mirror of
https://github.com/movie-web/extension.git
synced 2025-09-13 14:33:26 +00:00
@@ -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": {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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<string, string>;
|
||||
@@ -12,7 +15,8 @@ export interface Request extends BaseRequest {
|
||||
query?: Record<string, string>;
|
||||
readHeaders?: Record<string, string>;
|
||||
url: string;
|
||||
body?: string | FormData | URLSearchParams;
|
||||
body?: any;
|
||||
bodyType?: 'string' | 'FormData' | 'URLSearchParams' | 'object';
|
||||
}
|
||||
|
||||
type Response<T> = BaseResponse<{
|
||||
@@ -24,15 +28,45 @@ type Response<T> = 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<Request, Response<any>> = 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();
|
||||
|
||||
|
@@ -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<string, string>;
|
||||
}
|
||||
|
||||
const mapHeadersToDeclarativeNetRequestHeaders = (
|
||||
headers: Record<string, string>,
|
||||
op: string,
|
||||
): { header: string; operation: any; value: string }[] => {
|
||||
return Object.entries(headers).map(([name, value]) => ({
|
||||
header: name,
|
||||
operation: op,
|
||||
value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = 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,
|
||||
});
|
||||
|
@@ -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%);
|
||||
}
|
||||
}
|
||||
|
@@ -7,9 +7,5 @@ export interface FrameProps {
|
||||
}
|
||||
|
||||
export function Frame(props: FrameProps) {
|
||||
return (
|
||||
<div className="frame" style={{ width: 300, height: 300 }}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
return <div className="frame">{props.children}</div>;
|
||||
}
|
||||
|
117
src/utils/declarativeNetRequest.ts
Normal file
117
src/utils/declarativeNetRequest.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { isChrome } from './extension';
|
||||
|
||||
interface DynamicRule {
|
||||
ruleId: number;
|
||||
targetDomains?: [string, ...string[]];
|
||||
targetRegex?: string;
|
||||
requestHeaders?: Record<string, string>;
|
||||
responseHeaders?: Record<string, string>;
|
||||
}
|
||||
|
||||
const mapHeadersToDeclarativeNetRequestHeaders = (
|
||||
headers: Record<string, string>,
|
||||
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);
|
||||
};
|
Reference in New Issue
Block a user