diff --git a/src/common/backend/services/dida365/service.ts b/src/common/backend/services/dida365/service.ts index 9d47b225..64a5dede 100644 --- a/src/common/backend/services/dida365/service.ts +++ b/src/common/backend/services/dida365/service.ts @@ -1,5 +1,7 @@ +import { Container } from 'typedi'; import { generateUuid } from '@web-clipper/shared/lib/uuid'; import localeService from '@/common/locales'; +import { IWebRequestService } from '@/service/common/webRequest'; import { CreateDocumentRequest, CompleteStatus, @@ -98,6 +100,18 @@ export default class Dida365DocumentService implements DocumentService { }; createDocument = async (request: CreateDocumentRequest): Promise => { + const webRequestService = Container.get(IWebRequestService); + + const header = await webRequestService.startChangeHeader({ + urls: ['https://api.dida365.com/*'], + requestHeaders: [ + { + name: 'origin', + value: 'https://dida365.com', + }, + ], + }); + const settings = await this.request.get<{ timeZone: string }>( 'user/preferences/settings?includeWeb=true' ); @@ -132,33 +146,14 @@ export default class Dida365DocumentService implements DocumentService { delete: [], }; - const handler = (request: chrome.webRequest.WebRequestHeadersDetails) => { - const headers = (request.requestHeaders ?? []) - .filter(header => { - return header.name !== 'Origin'; - }) - .concat([ - { - name: 'origin', - value: 'https://dida365.com', - }, - ]); - return { - requestHeaders: headers, - }; - }; - chrome.webRequest.onBeforeSendHeaders.addListener( - handler, - { urls: ['https://api.dida365.com/api/v2/batch/task'] }, - ['blocking', 'requestHeaders', 'extraHeaders'] - ); - await this.request.post('batch/task', { data: data, + headers: { + [header.name]: header.value, + }, }); - chrome.webRequest.onBeforeSendHeaders.removeListener(handler); - chrome.webRequest.handlerBehaviorChanged(); + await webRequestService.end(header); return { href: `https://dida365.com/#p/${request.repositoryId}/tasks/${id}`, diff --git a/src/main/background.main.chrome.ts b/src/main/background.main.chrome.ts index f23dff88..ee96cba1 100644 --- a/src/main/background.main.chrome.ts +++ b/src/main/background.main.chrome.ts @@ -1,3 +1,4 @@ import '@/main/background.main.common'; import '@/service/permissions/chrome/permissionsService'; +import '@/service/webRequest/browser/background/tabService'; import '@/main/background.main'; diff --git a/src/main/background.main.firefox.ts b/src/main/background.main.firefox.ts index 229ca885..e7908ef4 100644 --- a/src/main/background.main.firefox.ts +++ b/src/main/background.main.firefox.ts @@ -1,3 +1,4 @@ import '@/main/background.main.common'; import '@/service/permissions/firefox/firefoxPermissionsService'; +import '@/service/webRequest/firefox/background/tabService'; import '@/main/background.main'; diff --git a/src/main/background.main.ts b/src/main/background.main.ts index 26143db0..c0f79c8c 100644 --- a/src/main/background.main.ts +++ b/src/main/background.main.ts @@ -1,3 +1,5 @@ +import { IWebRequestService } from '@/service/common/webRequest'; +import { WebRequestChannel } from '@/service/webRequest/common/webRequestIPC'; import { IContentScriptService } from '@/service/common/contentScript'; import { ContentScriptChannelClient } from '@/service/contentScript/common/contentScriptIPC'; import { PopupContentScriptIPCClient } from '@/service/ipc/browser/popup/ipcClient'; @@ -22,6 +24,11 @@ backgroundIPCServer.registerChannel( new PermissionsChannel(Container.get(IPermissionsService)) ); +backgroundIPCServer.registerChannel( + 'webRequest', + new WebRequestChannel(Container.get(IWebRequestService)) +); + const contentScriptIPCClient = new PopupContentScriptIPCClient(Container.get(ITabService)); const contentScriptChannel = contentScriptIPCClient.getChannel('contentScript'); Container.set(IContentScriptService, new ContentScriptChannelClient(contentScriptChannel)); diff --git a/src/main/tool.main.ts b/src/main/tool.main.ts index 2a134e6f..a9936ac4 100644 --- a/src/main/tool.main.ts +++ b/src/main/tool.main.ts @@ -1,6 +1,8 @@ import 'regenerator-runtime/runtime'; import 'reflect-metadata'; import Container from 'typedi'; +import { IWebRequestService } from '@/service/common/webRequest'; +import { WebRequestChannelClient } from '@/service/webRequest/common/webRequestIPC'; import { IPermissionsService } from '@/service/common/permissions'; import { PermissionsChannelClient } from '@/service/permissions/common/permissionsIpc'; import { IContentScriptService } from '@/service/common/contentScript'; @@ -25,4 +27,7 @@ const contentScriptIPCClient = new PopupContentScriptIPCClient(Container.get(ITa const contentScriptChannel = contentScriptIPCClient.getChannel('contentScript'); Container.set(IContentScriptService, new ContentScriptChannelClient(contentScriptChannel)); +const webRequestChannel = ipcClient.getChannel('webRequest'); +Container.set(IWebRequestService, new WebRequestChannelClient(webRequestChannel)); + app(); diff --git a/src/service/common/webRequest.ts b/src/service/common/webRequest.ts new file mode 100644 index 00000000..02913d5b --- /dev/null +++ b/src/service/common/webRequest.ts @@ -0,0 +1,19 @@ +import { Token } from 'typedi'; + +export interface WebBlockHeader { + name: string; + value: string; +} + +export interface WebRequestBlockOption { + requestHeaders: chrome.webRequest.HttpHeader[]; + urls: string[]; +} + +export interface IWebRequestService { + startChangeHeader(option: WebRequestBlockOption): Promise; + + end(webBlockHeader: WebBlockHeader): Promise; +} + +export const IWebRequestService = new Token(); diff --git a/src/service/webRequest/browser/background/tabService.ts b/src/service/webRequest/browser/background/tabService.ts new file mode 100644 index 00000000..4e5f7009 --- /dev/null +++ b/src/service/webRequest/browser/background/tabService.ts @@ -0,0 +1,62 @@ +import { generateUuid } from '@web-clipper/shared/lib/uuid'; +import { + IWebRequestService, + WebRequestBlockOption, + WebBlockHeader, +} from '@/service/common/webRequest'; + +import { Service } from 'typedi'; + +export const WEB_REQUEST_BLOCK_HEADER = 'web_clipper_web_request'; + +class BackgroundWebRequestService implements IWebRequestService { + private handlerMap: Map; + + constructor() { + this.handlerMap = new Map(); + } + + async startChangeHeader(option: WebRequestBlockOption): Promise { + const uuid = generateUuid(); + const targetHeaders = option.requestHeaders.map(o => ({ + name: o.name.toLocaleLowerCase(), + value: o.value, + })); + + const handler = (request: chrome.webRequest.WebRequestHeadersDetails) => { + const originHeaders = request.requestHeaders ?? []; + if (originHeaders.findIndex(o => o.name === WEB_REQUEST_BLOCK_HEADER) === -1) { + return; + } + const headers = originHeaders + .filter(header => { + return !targetHeaders.find(o => o.name === header.name.toLocaleLowerCase()); + }) + .concat(targetHeaders); + + return { + requestHeaders: headers, + }; + }; + + this.handlerMap.set(uuid, handler); + chrome.webRequest.onBeforeSendHeaders.addListener(handler, { urls: option.urls }, [ + 'blocking', + 'requestHeaders', + 'extraHeaders', + ]); + return { + name: WEB_REQUEST_BLOCK_HEADER, + value: uuid, + }; + } + + async end(webBlockHeader: WebBlockHeader): Promise { + const handler = this.handlerMap.get(webBlockHeader.value); + this.handlerMap.delete(webBlockHeader.value); + chrome.webRequest.onBeforeSendHeaders.removeListener(handler); + chrome.webRequest.handlerBehaviorChanged(); + } +} + +Service(IWebRequestService)(BackgroundWebRequestService); diff --git a/src/service/webRequest/common/webRequestIPC.ts b/src/service/webRequest/common/webRequestIPC.ts new file mode 100644 index 00000000..66ccb49c --- /dev/null +++ b/src/service/webRequest/common/webRequestIPC.ts @@ -0,0 +1,38 @@ +import { + IWebRequestService, + WebRequestBlockOption, + WebBlockHeader, +} from '@/service/common/webRequest'; +import { IServerChannel, IChannel } from '@/service/common/ipc'; + +export class WebRequestChannel implements IServerChannel { + constructor(private service: IWebRequestService) {} + + call = async ( + _context: chrome.runtime.Port['sender'], + command: string, + arg: any + ): Promise => { + switch (command) { + case 'end': + return this.service.end(arg); + case 'startChangeHeader': + return this.service.startChangeHeader(arg); + default: { + throw new Error(`Call not found: ${command}`); + } + } + }; +} + +export class WebRequestChannelClient implements IWebRequestService { + constructor(private channel: IChannel) {} + + startChangeHeader = async (option: WebRequestBlockOption): Promise => { + return this.channel.call('startChangeHeader', option); + }; + + end = async (webBlockHeader: WebBlockHeader): Promise => { + return this.channel.call('end', webBlockHeader); + }; +} diff --git a/src/service/webRequest/firefox/background/tabService.ts b/src/service/webRequest/firefox/background/tabService.ts new file mode 100644 index 00000000..9efe2f8d --- /dev/null +++ b/src/service/webRequest/firefox/background/tabService.ts @@ -0,0 +1,61 @@ +import { generateUuid } from '@web-clipper/shared/lib/uuid'; +import { + IWebRequestService, + WebRequestBlockOption, + WebBlockHeader, +} from '@/service/common/webRequest'; + +import { Service } from 'typedi'; + +export const WEB_REQUEST_BLOCK_HEADER = 'web_clipper_web_request'; + +class BackgroundWebRequestService implements IWebRequestService { + private handlerMap: Map; + + constructor() { + this.handlerMap = new Map(); + } + + async startChangeHeader(option: WebRequestBlockOption): Promise { + const uuid = generateUuid(); + const targetHeaders = option.requestHeaders.map(o => ({ + name: o.name.toLocaleLowerCase(), + value: o.value, + })); + + const handler = (request: chrome.webRequest.WebRequestHeadersDetails) => { + const originHeaders = request.requestHeaders ?? []; + if (originHeaders.findIndex(o => o.name === WEB_REQUEST_BLOCK_HEADER) === -1) { + return; + } + const headers = originHeaders + .filter(header => { + return !targetHeaders.find(o => o.name === header.name.toLocaleLowerCase()); + }) + .concat(targetHeaders); + + return { + requestHeaders: headers, + }; + }; + + this.handlerMap.set(uuid, handler); + chrome.webRequest.onBeforeSendHeaders.addListener(handler, { urls: option.urls }, [ + 'blocking', + 'requestHeaders', + ]); + return { + name: WEB_REQUEST_BLOCK_HEADER, + value: uuid, + }; + } + + async end(webBlockHeader: WebBlockHeader): Promise { + const handler = this.handlerMap.get(webBlockHeader.value); + this.handlerMap.delete(webBlockHeader.value); + chrome.webRequest.onBeforeSendHeaders.removeListener(handler); + chrome.webRequest.handlerBehaviorChanged(); + } +} + +Service(IWebRequestService)(BackgroundWebRequestService);