Skip to content
This repository was archived by the owner on Jun 4, 2023. It is now read-only.

Commit dfa8a80

Browse files
authored
feat: add a way to uninstall extensions (#561)
1 parent d34d277 commit dfa8a80

File tree

8 files changed

+81
-4
lines changed

8 files changed

+81
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"@types/node-fetch": "^2.5.8",
5151
"@types/react": "17.0.2",
5252
"@types/react-dom": "17.0.1",
53+
"@types/rimraf": "^3.0.0",
5354
"@types/styled-components": "5.1.7",
5455
"@typescript-eslint/eslint-plugin": "^4.15.1",
5556
"@typescript-eslint/parser": "^4.15.1",

src/common/rpc/extensions.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { RendererToMainChannel } from '@wexond/rpc-electron';
2+
3+
export interface ExtensionMainService {
4+
uninstall(id: string): void;
5+
}
6+
7+
export const extensionMainChannel = new RendererToMainChannel<ExtensionMainService>(
8+
'ExtensionMainService',
9+
);

src/main/application.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { runAutoUpdaterService } from './services';
1212
import { DialogsService } from './services/dialogs-service';
1313
import { requestAuth } from './dialogs/auth';
1414
import { NetworkServiceHandler } from './network/network-service-handler';
15+
import { ExtensionServiceHandler } from './extension-service-handler';
1516

1617
export class Application {
1718
public static instance = new Application();
@@ -88,6 +89,8 @@ export class Application {
8889
private async onReady() {
8990
await app.whenReady();
9091

92+
new ExtensionServiceHandler();
93+
9194
NetworkServiceHandler.get();
9295

9396
checkFiles();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { RpcMainEvent, RpcMainHandler } from '@wexond/rpc-electron';
2+
import {
3+
extensionMainChannel,
4+
ExtensionMainService,
5+
} from '~/common/rpc/extensions';
6+
import { Application } from './application';
7+
8+
export class ExtensionServiceHandler
9+
implements RpcMainHandler<ExtensionMainService> {
10+
constructor() {
11+
extensionMainChannel.getReceiver().handler = this;
12+
}
13+
14+
uninstall(e: RpcMainEvent, id: string): void {
15+
Application.instance.sessions.uninstallExtension(id);
16+
}
17+
}

src/main/sessions-service.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import { pathExists } from '~/utils/files';
1111
import { extractZip } from '~/utils/zip';
1212
import { extensions, _setFallbackSession } from 'electron-extensions';
1313
import { requestPermission } from './dialogs/permissions';
14+
import * as rimraf from 'rimraf';
15+
import { promisify } from 'util';
16+
17+
const rf = promisify(rimraf);
1418

1519
// TODO: sessions should be separate. This structure actually doesn't make sense.
1620
export class SessionsService {
@@ -29,9 +33,6 @@ export class SessionsService {
2933
this.clearCache('incognito');
3034

3135
if (process.env.ENABLE_EXTENSIONS) {
32-
// TODO: remove this after fix for e.sender.session
33-
_setFallbackSession(this.view);
34-
3536
extensions.initializeSession(
3637
this.view,
3738
`${app.getAppPath()}/build/extensions-preload.bundle.js`,
@@ -331,6 +332,17 @@ export class SessionsService {
331332
this.extensionsLoaded = true;
332333
}
333334

335+
async uninstallExtension(id: string) {
336+
if (!process.env.ENABLE_EXTENSIONS) return;
337+
338+
const extension = this.view.getExtension(id);
339+
if (!extension) return;
340+
341+
await this.view.removeExtension(id);
342+
343+
await rf(extension.path);
344+
}
345+
334346
public onCreateTab = async (details: chrome.tabs.CreateProperties) => {
335347
const view = Application.instance.windows.list
336348
.find((x) => x.win.id === details.windowId)

src/renderer/views/app/components/BrowserAction/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ const onContextMenu = (data: IBrowserAction) => (
4646
) => {
4747
const { target } = e;
4848
const menu = remote.Menu.buildFromTemplate([
49+
{
50+
label: 'Uninstall',
51+
click: () => {
52+
store.extensions.uninstallExtension(data.extensionId);
53+
},
54+
},
4955
{
5056
label: 'Inspect popup',
5157
click: () => {

src/renderer/views/app/store/extensions.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/* eslint @typescript-eslint/camelcase: 0 */
22

3-
import { makeObservable, observable } from 'mobx';
3+
import { action, makeObservable, observable } from 'mobx';
44
import { join } from 'path';
55

66
import { IBrowserAction } from '../models';
77
import { promises } from 'fs';
88
import { ipcRenderer } from 'electron';
99
import store from '.';
10+
import { extensionMainChannel } from '~/common/rpc/extensions';
1011

1112
export class ExtensionsStore {
1213
public browserActions: IBrowserAction[] = [];
@@ -20,6 +21,7 @@ export class ExtensionsStore {
2021
browserActions: observable,
2122
defaultBrowserActions: observable,
2223
currentlyToggledPopup: observable,
24+
uninstallExtension: action,
2325
});
2426

2527
this.load();
@@ -87,4 +89,15 @@ export class ExtensionsStore {
8789

8890
await Promise.all(extensions.map((x) => this.loadExtension(x)));
8991
}
92+
93+
uninstallExtension(id: string) {
94+
this.browserActions = this.browserActions.filter(
95+
(x) => x.extensionId !== id,
96+
);
97+
this.defaultBrowserActions = this.defaultBrowserActions.filter(
98+
(x) => x.extensionId !== id,
99+
);
100+
101+
extensionMainChannel.getInvoker().uninstall(id);
102+
}
90103
}

yarn.lock

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,14 @@
592592
dependencies:
593593
"@types/node" "*"
594594

595+
"@types/glob@*":
596+
version "7.1.3"
597+
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
598+
integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
599+
dependencies:
600+
"@types/minimatch" "*"
601+
"@types/node" "*"
602+
595603
"@types/glob@^7.1.1":
596604
version "7.1.2"
597605
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.2.tgz#06ca26521353a545d94a0adc74f38a59d232c987"
@@ -716,6 +724,14 @@
716724
"@types/node" "*"
717725
safe-buffer "*"
718726

727+
"@types/rimraf@^3.0.0":
728+
version "3.0.0"
729+
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.0.tgz#b9d03f090ece263671898d57bb7bb007023ac19f"
730+
integrity sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==
731+
dependencies:
732+
"@types/glob" "*"
733+
"@types/node" "*"
734+
719735
"@types/semver@^7.3.1":
720736
version "7.3.4"
721737
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"

0 commit comments

Comments
 (0)