Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d5279acf | ||
|
|
e674607fce | ||
|
|
2e6239f637 | ||
|
|
bcb8ddc17b | ||
|
|
cd619582ec | ||
|
|
3b49562f64 | ||
|
|
674ed2cc72 | ||
|
|
5621fd8a06 | ||
|
|
af27e0b111 | ||
|
|
5a78e12f7d |
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>KeeWeb</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.opener.postMessage(
|
||||
{ storage: 'teams', search: location.search },
|
||||
window.location.origin
|
||||
);
|
||||
window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -37,4 +37,17 @@ const OneDriveApps = {
|
||||
}
|
||||
};
|
||||
|
||||
export { DropboxApps, GDriveApps, OneDriveApps };
|
||||
const MsTeamsApps = {
|
||||
Local: {
|
||||
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635'
|
||||
},
|
||||
Production: {
|
||||
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635'
|
||||
},
|
||||
Desktop: {
|
||||
id: '8fbe2245-13d5-446f-bedc-74c3b2e1f635',
|
||||
secret: 'F02~HYaWs-~7MndJcVRtv9~h-50Brk_9ho'
|
||||
}
|
||||
};
|
||||
|
||||
export { DropboxApps, GDriveApps, OneDriveApps, MsTeamsApps };
|
||||
|
||||
@@ -87,7 +87,13 @@ const DefaultAppSettings = {
|
||||
|
||||
onedrive: true, // enable OneDrive integration
|
||||
onedriveClientId: null, // custom OneDrive client id
|
||||
onedriveClientSecret: null // custom OneDrive client secret
|
||||
onedriveClientSecret: null, // custom OneDrive client secret
|
||||
onedriveTenantId: null, // custom OneDrive tenant id
|
||||
|
||||
msteams: false, // enable Microsoft Teams integration
|
||||
msteamsClientId: null, // custom Microsoft Teams client id
|
||||
msteamsClientSecret: null, // custom Microsoft Teams client secret
|
||||
msteamsTenantId: null // custom Microsoft Teams tenant id
|
||||
};
|
||||
|
||||
export { DefaultAppSettings };
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"dropbox": "Dropbox",
|
||||
"gdrive": "Google Drive",
|
||||
"onedrive": "OneDrive",
|
||||
"msteams": "Microsoft Teams",
|
||||
"menuAllItems": "All Items",
|
||||
"menuColors": "Colors",
|
||||
"menuTrash": "Trash",
|
||||
|
||||
@@ -221,22 +221,30 @@ class StorageOneDrive extends StorageBase {
|
||||
_getOAuthConfig() {
|
||||
let clientId = this.appSettings.onedriveClientId;
|
||||
let clientSecret = this.appSettings.onedriveClientSecret;
|
||||
let tenant = this.appSettings.onedriveTenantId;
|
||||
|
||||
if (!clientId) {
|
||||
if (Features.isDesktop) {
|
||||
({ id: clientId, secret: clientSecret } = OneDriveApps.Desktop);
|
||||
({ id: clientId, secret: clientSecret, tenantId: tenant } = OneDriveApps.Desktop);
|
||||
} else if (Features.isLocal) {
|
||||
({ id: clientId, secret: clientSecret } = OneDriveApps.Local);
|
||||
({ id: clientId, secret: clientSecret, tenantId: tenant } = OneDriveApps.Local);
|
||||
} else {
|
||||
({ id: clientId, secret: clientSecret } = OneDriveApps.Production);
|
||||
({
|
||||
id: clientId,
|
||||
secret: clientSecret,
|
||||
tenantId: tenant
|
||||
} = OneDriveApps.Production);
|
||||
}
|
||||
}
|
||||
tenant = tenant || 'common';
|
||||
|
||||
let scope = 'files.readwrite';
|
||||
if (!this.appSettings.shortLivedStorageToken) {
|
||||
scope += ' offline_access';
|
||||
}
|
||||
return {
|
||||
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
||||
tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
||||
url: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`,
|
||||
tokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
|
||||
scope,
|
||||
clientId,
|
||||
clientSecret,
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
import { StorageBase } from 'storage/storage-base';
|
||||
import { MsTeamsApps } from 'const/cloud-storage-apps';
|
||||
import { Features } from 'util/features';
|
||||
|
||||
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
|
||||
|
||||
// https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true
|
||||
// https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(c:c+eq+'Unified')
|
||||
// https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(c:c+eq+'Unified')&$orderby=displayName
|
||||
// https://graph.microsoft.com/v1.0/groups?$orderby=displayName
|
||||
// /me/joinedTeams
|
||||
// https://graph.microsoft.com/v1.0/groups/{group id}/drive/root/children
|
||||
|
||||
class StorageTeams extends StorageBase {
|
||||
name = 'msteams';
|
||||
enabled = true;
|
||||
uipos = 50;
|
||||
icon = 'user-friends';
|
||||
|
||||
_graphUrl = 'https://graph.microsoft.com/v1.0';
|
||||
_groupsUrl = `${this._graphUrl}/me/joinedTeams`;
|
||||
_baseUrl = `${this._graphUrl}/groups`;
|
||||
|
||||
getPathForName(fileName) {
|
||||
return '/drive/root:/' + fileName + '.kdbx';
|
||||
}
|
||||
|
||||
genUrlAddress(groupId, path) {
|
||||
if (groupId) {
|
||||
return this._baseUrl + '/' + groupId + (path ? '/' + path.replace(/^\/+/, '') : '');
|
||||
} else {
|
||||
return this._groupsUrl;
|
||||
}
|
||||
}
|
||||
|
||||
genUrl(path) {
|
||||
if (!path) {
|
||||
const groupId = null;
|
||||
const dir = null;
|
||||
const url = this.genUrlAddress(groupId, dir);
|
||||
return [groupId, dir, url];
|
||||
}
|
||||
|
||||
const parts = path.replace(/^\/+/, '').split('/');
|
||||
if (parts.length === 0) {
|
||||
const groupId = null;
|
||||
const dir = null;
|
||||
const url = this.genUrlAddress(groupId, dir);
|
||||
return [groupId, dir, url];
|
||||
} else if (parts.length === 1) {
|
||||
const groupId = parts[0];
|
||||
const dir = null;
|
||||
const url = this.genUrlAddress(groupId, dir);
|
||||
return [groupId, dir, url];
|
||||
} else {
|
||||
path = path.replace(/\/drive\/root\:/, '');
|
||||
const groupId = parts[0];
|
||||
const dir = ('/' + parts.slice(1).join('/')).replace(/^\/+/, '');
|
||||
const url = this.genUrlAddress(groupId, dir);
|
||||
return [groupId, dir, url];
|
||||
}
|
||||
}
|
||||
|
||||
load(path, opts, callback) {
|
||||
this._oauthAuthorize((err) => {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
}
|
||||
this.logger.debug('Load', path);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(path);
|
||||
const groupId = urlParts[0];
|
||||
path = urlParts[1];
|
||||
const url = urlParts[2];
|
||||
if (!groupId) {
|
||||
const err = 'no group id defined';
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
this._xhr({
|
||||
url,
|
||||
responseType: 'json',
|
||||
success: (response) => {
|
||||
const downloadUrl = response['@microsoft.graph.downloadUrl'];
|
||||
let rev = response.eTag;
|
||||
if (!downloadUrl || !response.eTag) {
|
||||
this.logger.debug(
|
||||
'Load error',
|
||||
path,
|
||||
'no download url',
|
||||
response,
|
||||
this.logger.ts(ts)
|
||||
);
|
||||
return callback && callback('no download url');
|
||||
}
|
||||
this._xhr({
|
||||
url: downloadUrl,
|
||||
responseType: 'arraybuffer',
|
||||
skipAuth: true,
|
||||
success: (response, xhr) => {
|
||||
rev = xhr.getResponseHeader('ETag') || rev;
|
||||
this.logger.debug('Loaded', path, rev, this.logger.ts(ts));
|
||||
return callback && callback(null, response, { rev });
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('Load error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('Load error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stat(path, opts, callback) {
|
||||
this._oauthAuthorize((err) => {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
}
|
||||
this.logger.debug('Stat', path);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(path);
|
||||
const groupId = urlParts[0];
|
||||
path = urlParts[1];
|
||||
const url = urlParts[2];
|
||||
if (!groupId) {
|
||||
const err = 'no group id defined';
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
this._xhr({
|
||||
url,
|
||||
responseType: 'json',
|
||||
success: (response) => {
|
||||
const rev = response.eTag;
|
||||
if (!rev) {
|
||||
this.logger.error('Stat error', path, 'no eTag', this.logger.ts(ts));
|
||||
return callback && callback('no eTag');
|
||||
}
|
||||
this.logger.debug('Stated', path, rev, this.logger.ts(ts));
|
||||
return callback && callback(null, { rev });
|
||||
},
|
||||
error: (err, xhr) => {
|
||||
if (xhr.status === 404) {
|
||||
this.logger.debug('Stated not found', path, this.logger.ts(ts));
|
||||
return callback && callback({ notFound: true });
|
||||
}
|
||||
this.logger.error('Stat error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
save(path, opts, data, callback, rev) {
|
||||
this._oauthAuthorize((err) => {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
}
|
||||
this.logger.debug('Save', path, rev);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(path);
|
||||
const groupId = urlParts[0];
|
||||
path = urlParts[1];
|
||||
const url = urlParts[2] + ':/content';
|
||||
if (!groupId) {
|
||||
const err = 'no group id defined';
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
this._xhr({
|
||||
url,
|
||||
method: 'PUT',
|
||||
responseType: 'json',
|
||||
headers: rev ? { 'If-Match': rev } : null,
|
||||
data,
|
||||
statuses: [200, 201, 412],
|
||||
success: (response, xhr) => {
|
||||
rev = response.eTag;
|
||||
if (!rev) {
|
||||
this.logger.error('Save error', path, 'no eTag', this.logger.ts(ts));
|
||||
return callback && callback('no eTag');
|
||||
}
|
||||
if (xhr.status === 412) {
|
||||
this.logger.debug('Save conflict', path, rev, this.logger.ts(ts));
|
||||
return callback && callback({ revConflict: true }, { rev });
|
||||
}
|
||||
this.logger.debug('Saved', path, rev, this.logger.ts(ts));
|
||||
return callback && callback(null, { rev });
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('Save error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
list(dir, callback) {
|
||||
this._oauthAuthorize((err) => {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
}
|
||||
this.logger.debug('List', dir);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(dir);
|
||||
const groupId = urlParts[0];
|
||||
dir = urlParts[1];
|
||||
const urlPath = groupId ? (dir ? ':/children' : '/drive/root/children') : '';
|
||||
const url = urlParts[2] + urlPath;
|
||||
|
||||
const self = this;
|
||||
self._groupId = groupId;
|
||||
|
||||
this._xhr({
|
||||
url,
|
||||
responseType: 'json',
|
||||
success: (response) => {
|
||||
if (!response || !response.value) {
|
||||
this.logger.error('List error', this.logger.ts(ts), response);
|
||||
return callback && callback('list error');
|
||||
}
|
||||
this.logger.debug('Listed', this.logger.ts(ts));
|
||||
let fileList;
|
||||
if (!self._groupId) {
|
||||
fileList = response.value
|
||||
.filter((f) => f.displayName)
|
||||
.map((f) => ({
|
||||
name: f.displayName,
|
||||
path: '/' + f.id,
|
||||
rev: f.id,
|
||||
dir: true
|
||||
}));
|
||||
} else {
|
||||
fileList = response.value
|
||||
.filter((f) => f.name)
|
||||
.map((f) => ({
|
||||
name: f.name,
|
||||
path: `/${self._groupId}${f.parentReference.path}/${f.name}`,
|
||||
rev: f.eTag,
|
||||
dir: !!f.folder
|
||||
}));
|
||||
}
|
||||
return callback && callback(null, fileList);
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('List error', this.logger.ts(ts), err);
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
remove(path, callback) {
|
||||
this.logger.debug('Remove', path);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(path);
|
||||
const groupId = urlParts[0];
|
||||
path = urlParts[1];
|
||||
const url = urlParts[2];
|
||||
if (!groupId) {
|
||||
const err = 'no group id defined';
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
this._xhr({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
responseType: 'json',
|
||||
statuses: [200, 204],
|
||||
success: () => {
|
||||
this.logger.debug('Removed', path, this.logger.ts(ts));
|
||||
return callback && callback();
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('Remove error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mkdir(path, callback) {
|
||||
this._oauthAuthorize((err) => {
|
||||
if (err) {
|
||||
return callback && callback(err);
|
||||
}
|
||||
this.logger.debug('Make dir', path);
|
||||
const ts = this.logger.ts();
|
||||
|
||||
const urlParts = this.genUrl(path);
|
||||
const groupId = urlParts[0];
|
||||
path = urlParts[1];
|
||||
const url = urlParts[2] + '/drive/root/children';
|
||||
if (!groupId) {
|
||||
const err = 'no group id defined';
|
||||
return callback && callback(err);
|
||||
}
|
||||
|
||||
const data = JSON.stringify({ name: path.replace('/drive/root:/', ''), folder: {} });
|
||||
this._xhr({
|
||||
url,
|
||||
method: 'POST',
|
||||
responseType: 'json',
|
||||
statuses: [200, 204],
|
||||
data,
|
||||
dataType: 'application/json',
|
||||
success: () => {
|
||||
this.logger.debug('Made dir', path, this.logger.ts(ts));
|
||||
return callback && callback();
|
||||
},
|
||||
error: (err) => {
|
||||
this.logger.error('Make dir error', path, err, this.logger.ts(ts));
|
||||
return callback && callback(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
logout(enabled) {
|
||||
this._oauthRevokeToken();
|
||||
}
|
||||
|
||||
_getOAuthConfig() {
|
||||
let clientId = this.appSettings.msteamsClientId;
|
||||
let clientSecret = this.appSettings.msteamsClientSecret;
|
||||
let tenant = this.appSettings.msteamsTenantId;
|
||||
|
||||
if (!clientId) {
|
||||
if (Features.isDesktop) {
|
||||
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Desktop);
|
||||
} else if (Features.isLocal) {
|
||||
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Local);
|
||||
} else {
|
||||
({ id: clientId, secret: clientSecret, tenantId: tenant } = MsTeamsApps.Production);
|
||||
}
|
||||
}
|
||||
tenant = tenant || 'common';
|
||||
|
||||
let scope = 'Sites.ReadWrite.All Team.ReadBasic.All';
|
||||
if (!this.appSettings.shortLivedStorageToken) {
|
||||
scope += ' offline_access';
|
||||
}
|
||||
return {
|
||||
url: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`,
|
||||
tokenUrl: `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
|
||||
scope,
|
||||
clientId,
|
||||
clientSecret,
|
||||
pkce: true,
|
||||
width: 600,
|
||||
height: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export { StorageTeams };
|
||||
@@ -5,6 +5,7 @@ import { StorageFile } from 'storage/impl/storage-file';
|
||||
import { StorageFileCache } from 'storage/impl/storage-file-cache';
|
||||
import { StorageGDrive } from 'storage/impl/storage-gdrive';
|
||||
import { StorageOneDrive } from 'storage/impl/storage-onedrive';
|
||||
import { StorageTeams } from 'storage/impl/storage-teams';
|
||||
import { StorageWebDav } from 'storage/impl/storage-webdav';
|
||||
import { createOAuthSession } from 'storage/pkce';
|
||||
|
||||
@@ -17,6 +18,7 @@ const ThirdPartyStorage = {
|
||||
dropbox: new StorageDropbox(),
|
||||
gdrive: new StorageGDrive(),
|
||||
onedrive: new StorageOneDrive(),
|
||||
msteams: new StorageTeams(),
|
||||
webdav: new StorageWebDav()
|
||||
};
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ $fa-var-file-image: next-fa-glyph();
|
||||
$fa-var-file-video: next-fa-glyph();
|
||||
$fa-var-file-audio: next-fa-glyph();
|
||||
$fa-var-onedrive: next-fa-glyph();
|
||||
$fa-var-user-friends: next-fa-glyph();
|
||||
$fa-var-question: next-fa-glyph();
|
||||
$fa-var-sign-out-alt: next-fa-glyph();
|
||||
$fa-var-sync-alt: next-fa-glyph();
|
||||
|
||||
@@ -5,42 +5,67 @@ const { isDev } = require('./app-info');
|
||||
const { app } = require('electron');
|
||||
const { ExtensionIds } = require('../const/extension-ids');
|
||||
|
||||
function getManifestDir(browser) {
|
||||
function getManifestDirs(browser) {
|
||||
const home = app.getPath('home');
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
switch (browser) {
|
||||
case 'Chrome':
|
||||
return `${home}/Library/Application Support/Google/Chrome/NativeMessagingHosts/`;
|
||||
return [
|
||||
`${home}/Library/Application Support/Google/Chrome/NativeMessagingHosts/`,
|
||||
`${home}/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts/`,
|
||||
`${home}/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts/`,
|
||||
`${home}/Library/Application Support/Chromium/NativeMessagingHosts/`,
|
||||
];
|
||||
case 'Firefox':
|
||||
return `${home}/Library/Application Support/Mozilla/NativeMessagingHosts/`;
|
||||
return [
|
||||
`${home}/Library/Application Support/Mozilla/NativeMessagingHosts/`,
|
||||
];
|
||||
case 'Edge':
|
||||
return `${home}/Library/Application Support/Microsoft Edge/NativeMessagingHosts/`;
|
||||
return [
|
||||
`${home}/Library/Application Support/Microsoft Edge/NativeMessagingHosts/`,
|
||||
];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
case 'linux':
|
||||
switch (browser) {
|
||||
case 'Chrome':
|
||||
return `${home}/.config/google-chrome/NativeMessagingHosts/`;
|
||||
return [
|
||||
`${home}/.config/google-chrome/NativeMessagingHosts/`,
|
||||
`${home}/.config/google-chrome-dev/NativeMessagingHosts/`,
|
||||
`${home}/.config/google-chrome-unstable/NativeMessagingHosts/`,
|
||||
`${home}/.config/chromium/NativeMessagingHosts/`,
|
||||
];
|
||||
case 'Firefox':
|
||||
return `${home}/.mozilla/native-messaging-hosts/`;
|
||||
return [
|
||||
`${home}/.mozilla/native-messaging-hosts/`,
|
||||
];
|
||||
case 'Edge':
|
||||
return `${home}/.config/microsoft-edge/NativeMessagingHosts/`;
|
||||
return [
|
||||
`${home}/.config/microsoft-edge/NativeMessagingHosts/`,
|
||||
];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getWindowsRegistryPath(browser) {
|
||||
function getWindowsRegistryPaths(browser) {
|
||||
switch (browser) {
|
||||
case 'Chrome':
|
||||
return 'HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\';
|
||||
return [
|
||||
'HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\',
|
||||
'HKCU\\Software\\Chromium\\NativeMessagingHosts\\',
|
||||
];
|
||||
case 'Firefox':
|
||||
return 'HKCU\\Software\\Mozilla\\NativeMessagingHosts\\';
|
||||
return [
|
||||
'HKCU\\Software\\Mozilla\\NativeMessagingHosts\\',
|
||||
];
|
||||
case 'Edge':
|
||||
return 'HKCU\\Software\\Microsoft\\Edge\\NativeMessagingHosts\\';
|
||||
return [
|
||||
'HKCU\\Software\\Microsoft\\Edge\\NativeMessagingHosts\\',
|
||||
];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
@@ -130,8 +155,8 @@ module.exports.install = async function (browser, extension) {
|
||||
manifest.path = getNativeMessagingHostPath();
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const registryPath = getWindowsRegistryPath(browser);
|
||||
if (!registryPath) {
|
||||
const registryPaths = getWindowsRegistryPaths(browser);
|
||||
if (!registryPaths) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,30 +168,34 @@ module.exports.install = async function (browser, extension) {
|
||||
const manifestFileName = getWindowsManifestFileName(browser, extension);
|
||||
await fs.promises.writeFile(manifestFileName, JSON.stringify(manifest, null, 4));
|
||||
|
||||
windowsRegistry.createKey(registryPath + registryKeyName, manifestFileName);
|
||||
for (const path of registryPaths) {
|
||||
windowsRegistry.createKey(path + registryKeyName, manifestFileName);
|
||||
}
|
||||
} else {
|
||||
const manifestDir = getManifestDir(browser);
|
||||
if (!manifestDir) {
|
||||
const manifestDirs = getManifestDirs(browser);
|
||||
if (!manifestDirs) {
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.promises.mkdir(manifestDir, { recursive: true });
|
||||
|
||||
const manifestFileName = getManifestFileName(extension);
|
||||
if (!manifestFileName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullPath = path.join(manifestDir, manifestFileName);
|
||||
for (const dir of manifestDirs) {
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
|
||||
await fs.promises.writeFile(fullPath, JSON.stringify(manifest, null, 4));
|
||||
const fullPath = path.join(dir, manifestFileName);
|
||||
|
||||
await fs.promises.writeFile(fullPath, JSON.stringify(manifest, null, 4));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.uninstall = async function (browser, extension) {
|
||||
if (process.platform === 'win32') {
|
||||
const registryPath = getWindowsRegistryPath(browser);
|
||||
if (!registryPath) {
|
||||
const registryPaths = getWindowsRegistryPaths(browser);
|
||||
if (!registryPaths) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,10 +204,12 @@ module.exports.uninstall = async function (browser, extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
windowsRegistry.deleteKey(registryPath + registryKeyName);
|
||||
for (const path of registryPaths) {
|
||||
windowsRegistry.deleteKey(path + registryKeyName);
|
||||
}
|
||||
} else {
|
||||
const manifestDir = getManifestDir(browser);
|
||||
if (!manifestDir) {
|
||||
const manifestDirs = getManifestDirs(browser);
|
||||
if (!manifestDirs) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,8 +217,11 @@ module.exports.uninstall = async function (browser, extension) {
|
||||
if (!manifestFileName) {
|
||||
return;
|
||||
}
|
||||
const fullPath = path.join(manifestDir, manifestFileName);
|
||||
|
||||
await fs.promises.unlink(fullPath);
|
||||
for (const dir of manifestDirs) {
|
||||
const fullPath = path.join(dir, manifestFileName);
|
||||
|
||||
await fs.promises.unlink(fullPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Generated
+434
-21420
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -32,7 +32,7 @@
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^5.2.4",
|
||||
"dompurify": "^2.2.8",
|
||||
"electron": "^12.0.7",
|
||||
"electron": "^12.2.2",
|
||||
"electron-builder": "^22.11.1",
|
||||
"electron-evil-feature-patcher": "^1.2.1",
|
||||
"electron-notarize": "^1.0.0",
|
||||
|
||||
Reference in New Issue
Block a user