diff --git a/package.json b/package.json index 2b6a476..14f0747 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@movie-web/extension", "displayName": "movie-web extension", - "version": "1.0.1", + "version": "1.0.2", "description": "Enhance your movie-web experience with just one click", "author": "movie-web", "scripts": { diff --git a/src/Popup.css b/src/Popup.css index 87fe58a..ee5b928 100644 --- a/src/Popup.css +++ b/src/Popup.css @@ -1,6 +1,13 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@500;800&display=swap'); +html { + min-height: 300px; + min-width: 300px; +} + body { + min-height: 300px; + min-width: 300px; margin: 0; font-family: 'Inter', sans-serif; } @@ -11,4 +18,4 @@ body { display: flex; justify-content: center; align-items: center; -} \ No newline at end of file +} diff --git a/src/background/messages/makeRequest.ts b/src/background/messages/makeRequest.ts index 5c37429..cd778a8 100644 --- a/src/background/messages/makeRequest.ts +++ b/src/background/messages/makeRequest.ts @@ -2,9 +2,12 @@ import type { PlasmoMessaging } from '@plasmohq/messaging'; import type { BaseRequest } from '~types/request'; import type { BaseResponse } from '~types/response'; +import { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest'; import { makeFullUrl } from '~utils/fetcher'; import { assertDomainWhitelist } from '~utils/storage'; +const MAKE_REQUEST_DYNAMIC_RULE = 23498; + export interface Request extends BaseRequest { baseUrl?: string; headers?: Record; @@ -12,7 +15,8 @@ export interface Request extends BaseRequest { query?: Record; readHeaders?: Record; url: string; - body?: string | FormData | URLSearchParams; + body?: any; + bodyType?: 'string' | 'FormData' | 'URLSearchParams' | 'object'; } type Response = BaseResponse<{ @@ -24,15 +28,45 @@ type Response = BaseResponse<{ }; }>; +const mapBodyToFetchBody = (body: Request['body'], bodyType: Request['bodyType']): BodyInit => { + if (bodyType === 'FormData') { + const formData = new FormData(); + body.forEach(([key, value]) => { + formData.append(key, value.toString()); + }); + } + if (bodyType === 'URLSearchParams') { + return new URLSearchParams(body); + } + if (bodyType === 'object') { + return JSON.stringify(body); + } + if (bodyType === 'string') { + return body; + } + return body; +}; + const handler: PlasmoMessaging.MessageHandler> = async (req, res) => { try { await assertDomainWhitelist(req.sender.tab.url); + if (req.body.headers['User-Agent']) { + await setDynamicRules({ + ruleId: MAKE_REQUEST_DYNAMIC_RULE, + targetDomains: [new URL(req.body.url).hostname], + requestHeaders: { + 'User-Agent': req.body.headers['User-Agent'], + }, + }); + } + 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, req.body.bodyType), }); + await removeDynamicRules([MAKE_REQUEST_DYNAMIC_RULE]); const contentType = response.headers.get('content-type'); const body = contentType?.includes('application/json') ? await response.json() : await response.text(); diff --git a/src/background/messages/prepareStream.ts b/src/background/messages/prepareStream.ts index d984c67..2833433 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,108 +13,10 @@ 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, }); diff --git a/src/components/Frame.css b/src/components/Frame.css index 100be9b..25b93b0 100644 --- a/src/components/Frame.css +++ b/src/components/Frame.css @@ -1,4 +1,6 @@ .frame { + height: 100%; + width: 100%; background-color: #0a080e; background-image: radial-gradient(271.48% 132.05% at 136.13% 65.62%, #271945b3 0%, #1c1c2c00 100%), radial-gradient(671.15% 123.02% at 76.68% -34.38%, #272753 0%, #17172000 100%); -} \ No newline at end of file +} diff --git a/src/components/Frame.tsx b/src/components/Frame.tsx index efa84e7..18f607f 100644 --- a/src/components/Frame.tsx +++ b/src/components/Frame.tsx @@ -7,9 +7,5 @@ export interface FrameProps { } export function Frame(props: FrameProps) { - return ( -
- {props.children} -
- ); + return
{props.children}
; } diff --git a/src/utils/declarativeNetRequest.ts b/src/utils/declarativeNetRequest.ts new file mode 100644 index 0000000..5dac227 --- /dev/null +++ b/src/utils/declarativeNetRequest.ts @@ -0,0 +1,117 @@ +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); + } +}; + +export const removeDynamicRules = async (ruleIds: number[]) => { + await (chrome || browser).declarativeNetRequest.updateDynamicRules({ + removeRuleIds: ruleIds, + }); + if ((chrome || browser).runtime.lastError?.message) throw new Error((chrome || browser).runtime.lastError.message); +};