From 658f59eb24b67c94c082cba41a3c12b952ad178e Mon Sep 17 00:00:00 2001 From: Jorrin <43169049+JorrinKievit@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:41:20 +0100 Subject: [PATCH] serialize body --- src/background/messages/makeRequest.ts | 55 +++++++++++- src/background/messages/prepareStream.ts | 103 +-------------------- src/utils/declarativeNetRequest.ts | 110 +++++++++++++++++++++++ 3 files changed, 166 insertions(+), 102 deletions(-) create mode 100644 src/utils/declarativeNetRequest.ts diff --git a/src/background/messages/makeRequest.ts b/src/background/messages/makeRequest.ts index 5c37429..4f221da 100644 --- a/src/background/messages/makeRequest.ts +++ b/src/background/messages/makeRequest.ts @@ -2,9 +2,20 @@ import type { PlasmoMessaging } from '@plasmohq/messaging'; import type { BaseRequest } from '~types/request'; import type { BaseResponse } from '~types/response'; +import { setDynamicRules } from '~utils/declarativeNetRequest'; import { makeFullUrl } from '~utils/fetcher'; import { assertDomainWhitelist } from '~utils/storage'; +type Body = + | { + bodyType: 'string'; + value: string; + } + | { + bodyType: 'FormData' | 'URLSearchParams' | 'Object'; + value: Record; + }; + export interface Request extends BaseRequest { baseUrl?: string; headers?: Record; @@ -12,7 +23,7 @@ export interface Request extends BaseRequest { query?: Record; readHeaders?: Record; url: string; - body?: string | FormData | URLSearchParams; + body?: Body; } type Response = BaseResponse<{ @@ -24,14 +35,52 @@ type Response = BaseResponse<{ }; }>; +const mapBodyToFetchBody = (body: Request['body']): BodyInit => { + if (body?.bodyType === 'FormData') { + const formData = new FormData(); + Object.entries(body.value).forEach(([key, value]) => { + formData.append(key, value); + }); + return formData; + } + if (body?.bodyType === 'URLSearchParams') { + const searchParams = new URLSearchParams(); + Object.entries(body.value).forEach(([key, value]) => { + searchParams.set(key, value); + }); + return searchParams; + } + if (body?.bodyType === 'Object') { + return JSON.stringify(body.value); + } + if (body?.bodyType === 'string') { + return body.value; + } + return undefined; +}; + const handler: PlasmoMessaging.MessageHandler> = async (req, res) => { try { await assertDomainWhitelist(req.sender.tab.url); + console.log(req.body.headers['User-Agent']); + if (req.body.headers['User-Agent']) { + console.log('preparing stream'); + await setDynamicRules({ + ruleId: 23498, + targetDomains: [req.body.url], + requestHeaders: { + 'User-Agent': req.body.headers['User-Agent'], + }, + }); + const rules = await chrome.declarativeNetRequest.getDynamicRules(); + console.log(rules); + } + const response = await fetch(makeFullUrl(req.body.url, req.body), { method: req.body.method, headers: req.body.headers, - body: req.body.body, + body: mapBodyToFetchBody(req.body.body), }); const contentType = response.headers.get('content-type'); const body = contentType?.includes('application/json') ? await response.json() : await response.text(); @@ -46,6 +95,8 @@ const handler: PlasmoMessaging.MessageHandler> = async (r }, }); } catch (err) { + console.log('error'); + console.log(err); res.send({ success: false, error: err.message, diff --git a/src/background/messages/prepareStream.ts b/src/background/messages/prepareStream.ts index d984c67..688285d 100644 --- a/src/background/messages/prepareStream.ts +++ b/src/background/messages/prepareStream.ts @@ -2,7 +2,7 @@ import type { PlasmoMessaging } from '@plasmohq/messaging'; import type { BaseRequest } from '~types/request'; import type { BaseResponse } from '~types/response'; -import { isChrome } from '~utils/extension'; +import { setDynamicRules } from '~utils/declarativeNetRequest'; import { assertDomainWhitelist } from '~utils/storage'; interface Request extends BaseRequest { @@ -13,112 +13,15 @@ interface Request extends BaseRequest { responseHeaders?: Record; } -const mapHeadersToDeclarativeNetRequestHeaders = ( - headers: Record, - op: string, -): { header: string; operation: any; value: string }[] => { - return Object.entries(headers).map(([name, value]) => ({ - header: name, - operation: op, - value, - })); -}; - const handler: PlasmoMessaging.MessageHandler = async (req, res) => { try { await assertDomainWhitelist(req.sender.tab.url); - if (isChrome()) { - await chrome.declarativeNetRequest.updateDynamicRules({ - removeRuleIds: [req.body.ruleId], - addRules: [ - { - id: req.body.ruleId, - condition: { - ...(req.body.targetDomains && { requestDomains: req.body.targetDomains }), - ...(req.body.targetRegex && { regexFilter: req.body.targetRegex }), - }, - action: { - type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, - ...(req.body.requestHeaders && Object.keys(req.body.requestHeaders).length > 0 - ? { - requestHeaders: mapHeadersToDeclarativeNetRequestHeaders( - req.body.requestHeaders, - chrome.declarativeNetRequest.HeaderOperation.SET, - ), - } - : {}), - responseHeaders: [ - { - header: 'Access-Control-Allow-Origin', - operation: chrome.declarativeNetRequest.HeaderOperation.SET, - value: '*', - }, - { - header: 'Access-Control-Allow-Methods', - operation: chrome.declarativeNetRequest.HeaderOperation.SET, - value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', - }, - { - header: 'Access-Control-Allow-Headers', - operation: chrome.declarativeNetRequest.HeaderOperation.SET, - value: '*', - }, - ...mapHeadersToDeclarativeNetRequestHeaders( - req.body.responseHeaders ?? {}, - chrome.declarativeNetRequest.HeaderOperation.SET, - ), - ], - }, - }, - ], - }); - if (chrome.runtime.lastError?.message) throw new Error(chrome.runtime.lastError.message); - } else { - await browser.declarativeNetRequest.updateDynamicRules({ - removeRuleIds: [req.body.ruleId], - addRules: [ - { - id: req.body.ruleId, - condition: { - ...(req.body.targetDomains && { requestDomains: req.body.targetDomains }), - ...(req.body.targetRegex && { regexFilter: req.body.targetRegex }), - }, - action: { - type: 'modifyHeaders', - ...(req.body.requestHeaders && Object.keys(req.body.requestHeaders).length > 0 - ? { - requestHeaders: mapHeadersToDeclarativeNetRequestHeaders(req.body.requestHeaders, 'set'), - } - : {}), - responseHeaders: [ - { - header: 'Access-Control-Allow-Origin', - operation: 'set', - value: '*', - }, - { - header: 'Access-Control-Allow-Methods', - operation: 'set', - value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', - }, - { - header: 'Access-Control-Allow-Headers', - operation: 'set', - value: '*', - }, - ...mapHeadersToDeclarativeNetRequestHeaders(req.body.responseHeaders ?? {}, 'set'), - ], - }, - }, - ], - }); - if (browser.runtime.lastError?.message) throw new Error(browser.runtime.lastError.message); - } - + await setDynamicRules(req.body); res.send({ success: true, }); } catch (err) { + console.log(err); res.send({ success: false, error: err.message, diff --git a/src/utils/declarativeNetRequest.ts b/src/utils/declarativeNetRequest.ts new file mode 100644 index 0000000..15be683 --- /dev/null +++ b/src/utils/declarativeNetRequest.ts @@ -0,0 +1,110 @@ +import { isChrome } from './extension'; + +interface DynamicRule { + ruleId: number; + targetDomains?: [string, ...string[]]; + targetRegex?: string; + requestHeaders?: Record; + responseHeaders?: Record; +} + +const mapHeadersToDeclarativeNetRequestHeaders = ( + headers: Record, + op: string, +): { header: string; operation: any; value: string }[] => { + return Object.entries(headers).map(([name, value]) => ({ + header: name, + operation: op, + value, + })); +}; + +export const setDynamicRules = async (body: DynamicRule) => { + if (isChrome()) { + await chrome.declarativeNetRequest.updateDynamicRules({ + removeRuleIds: [body.ruleId], + addRules: [ + { + id: body.ruleId, + condition: { + ...(body.targetDomains && { requestDomains: body.targetDomains }), + ...(body.targetRegex && { regexFilter: body.targetRegex }), + }, + action: { + type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, + ...(body.requestHeaders && Object.keys(body.requestHeaders).length > 0 + ? { + requestHeaders: mapHeadersToDeclarativeNetRequestHeaders( + body.requestHeaders, + chrome.declarativeNetRequest.HeaderOperation.SET, + ), + } + : {}), + responseHeaders: [ + { + header: 'Access-Control-Allow-Origin', + operation: chrome.declarativeNetRequest.HeaderOperation.SET, + value: '*', + }, + { + header: 'Access-Control-Allow-Methods', + operation: chrome.declarativeNetRequest.HeaderOperation.SET, + value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + }, + { + header: 'Access-Control-Allow-Headers', + operation: chrome.declarativeNetRequest.HeaderOperation.SET, + value: '*', + }, + ...mapHeadersToDeclarativeNetRequestHeaders( + body.responseHeaders ?? {}, + chrome.declarativeNetRequest.HeaderOperation.SET, + ), + ], + }, + }, + ], + }); + if (chrome.runtime.lastError?.message) throw new Error(chrome.runtime.lastError.message); + } else { + await browser.declarativeNetRequest.updateDynamicRules({ + removeRuleIds: [body.ruleId], + addRules: [ + { + id: body.ruleId, + condition: { + ...(body.targetDomains && { requestDomains: body.targetDomains }), + ...(body.targetRegex && { regexFilter: body.targetRegex }), + }, + action: { + type: 'modifyHeaders', + ...(body.requestHeaders && Object.keys(body.requestHeaders).length > 0 + ? { + requestHeaders: mapHeadersToDeclarativeNetRequestHeaders(body.requestHeaders, 'set'), + } + : {}), + responseHeaders: [ + { + header: 'Access-Control-Allow-Origin', + operation: 'set', + value: '*', + }, + { + header: 'Access-Control-Allow-Methods', + operation: 'set', + value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + }, + { + header: 'Access-Control-Allow-Headers', + operation: 'set', + value: '*', + }, + ...mapHeadersToDeclarativeNetRequestHeaders(body.responseHeaders ?? {}, 'set'), + ], + }, + }, + ], + }); + if (browser.runtime.lastError?.message) throw new Error(browser.runtime.lastError.message); + } +};