Merge pull request #2 from ztpn/main

This commit is contained in:
TPN 2024-08-19 18:45:42 +01:00 committed by GitHub
commit cd2ecdb6b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1410 additions and 1109 deletions

View File

@ -16,28 +16,28 @@
"preinstall": "npx -y only-allow pnpm" "preinstall": "npx -y only-allow pnpm"
}, },
"dependencies": { "dependencies": {
"@plasmohq/messaging": "^0.6.1", "@plasmohq/messaging": "^0.6.2",
"@plasmohq/storage": "^1.9.0", "@plasmohq/storage": "^1.11.0",
"plasmo": "0.84.0", "plasmo": "0.84.0",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0" "react-dom": "18.2.0"
}, },
"devDependencies": { "devDependencies": {
"@types/chrome": "0.0.251", "@types/chrome": "0.0.251",
"@types/firefox-webext-browser": "^120.0.0", "@types/firefox-webext-browser": "^120.0.4",
"@types/node": "20.9.0", "@types/node": "20.9.0",
"@types/react": "18.2.37", "@types/react": "18.2.37",
"@types/react-dom": "18.2.15", "@types/react-dom": "18.2.15",
"@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.15.0", "@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.1", "eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.2",
"prettier": "3.0.3", "prettier": "3.0.3",
"typescript": "5.2.2" "typescript": "5.2.2"
}, },

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ import type { BaseResponse } from '~types/response';
import { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest'; import { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest';
import { isFirefox } from '~utils/extension'; import { isFirefox } from '~utils/extension';
import { makeFullUrl } from '~utils/fetcher'; import { makeFullUrl } from '~utils/fetcher';
import { assertDomainWhitelist } from '~utils/storage'; import { assertDomainWhitelist, canAccessCookies } from '~utils/storage';
const MAKE_REQUEST_DYNAMIC_RULE = 23498; const MAKE_REQUEST_DYNAMIC_RULE = 23498;
@ -60,6 +60,12 @@ const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (r
ruleId: MAKE_REQUEST_DYNAMIC_RULE, ruleId: MAKE_REQUEST_DYNAMIC_RULE,
targetDomains: [new URL(url).hostname], targetDomains: [new URL(url).hostname],
requestHeaders: req.body.headers, requestHeaders: req.body.headers,
// set Access-Control-Allow-Credentials if the reqested host has access to cookies
responseHeaders: {
...(canAccessCookies(new URL(url).hostname) && {
'Access-Control-Allow-Credentials': 'true',
}),
},
}); });
const response = await fetch(url, { const response = await fetch(url, {
@ -84,7 +90,10 @@ const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (r
statusCode: response.status, statusCode: response.status,
headers: { headers: {
...Object.fromEntries(response.headers.entries()), ...Object.fromEntries(response.headers.entries()),
// include cookies if allowed for the reqested host
...(canAccessCookies(new URL(url).hostname) && {
'Set-Cookie': cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join(', '), 'Set-Cookie': cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join(', '),
}),
}, },
body, body,
finalUrl: response.url, finalUrl: response.url,

View File

@ -3,7 +3,7 @@ import type { PlasmoMessaging } from '@plasmohq/messaging';
import type { BaseRequest } from '~types/request'; import type { BaseRequest } from '~types/request';
import type { BaseResponse } from '~types/response'; import type { BaseResponse } from '~types/response';
import { setDynamicRules } from '~utils/declarativeNetRequest'; import { setDynamicRules } from '~utils/declarativeNetRequest';
import { assertDomainWhitelist } from '~utils/storage'; import { assertDomainWhitelist, modifiableResponseHeaders } from '~utils/storage';
interface Request extends BaseRequest { interface Request extends BaseRequest {
ruleId: number; ruleId: number;
@ -18,6 +18,17 @@ const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (re
if (!req.sender?.tab?.url) throw new Error('No tab URL found in the request.'); if (!req.sender?.tab?.url) throw new Error('No tab URL found in the request.');
if (!req.body) throw new Error('No request body found in the request.'); if (!req.body) throw new Error('No request body found in the request.');
// restrict what response headers can be modified
req.body.responseHeaders = Object.keys(req.body.responseHeaders ?? {})
.filter((key) => modifiableResponseHeaders.includes(key.toLowerCase()))
.reduce(
(obj, key) => {
obj[key] = (req.body?.responseHeaders ?? {})[key];
return obj;
},
{} as Record<string, string>,
);
await assertDomainWhitelist(req.sender.tab.url); await assertDomainWhitelist(req.sender.tab.url);
await setDynamicRules(req.body); await setDynamicRules(req.body);
res.send({ res.send({

View File

@ -76,7 +76,8 @@ export default function PermissionRequest() {
<Card icon={<Icon name="cookie" />}> <Card icon={<Icon name="cookie" />}>
<h3>Read and write cookies</h3> <h3>Read and write cookies</h3>
<p className="text-color paragraph"> <p className="text-color paragraph">
Some sources use cookies for authentication. We need to be able to read and set those cookies. Some sources use cookies for authentication. We need to be able to read and set those cookies. The
extension will only be able to accees the cookies for a few sites we scrape.
</p> </p>
<p className="text-color paragraph"> <p className="text-color paragraph">
You won&apos;t be prompted for this permission, it&apos;s included in Read & change data from all sites. You won&apos;t be prompted for this permission, it&apos;s included in Read & change data from all sites.

View File

@ -1,4 +1,5 @@
import { isChrome } from './extension'; import { isChrome } from './extension';
import { modifiableResponseHeaders } from './storage';
interface DynamicRule { interface DynamicRule {
ruleId: number; ruleId: number;
@ -56,11 +57,6 @@ export const setDynamicRules = async (body: DynamicRule) => {
operation: chrome.declarativeNetRequest.HeaderOperation.SET, operation: chrome.declarativeNetRequest.HeaderOperation.SET,
value: '*', value: '*',
}, },
{
header: 'Access-Control-Allow-Credentials',
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
value: 'true',
},
...mapHeadersToDeclarativeNetRequestHeaders( ...mapHeadersToDeclarativeNetRequestHeaders(
body.responseHeaders ?? {}, body.responseHeaders ?? {},
chrome.declarativeNetRequest.HeaderOperation.SET, chrome.declarativeNetRequest.HeaderOperation.SET,
@ -104,11 +100,6 @@ export const setDynamicRules = async (body: DynamicRule) => {
operation: 'set', operation: 'set',
value: '*', value: '*',
}, },
{
header: 'Access-Control-Allow-Credentials',
operation: 'set',
value: 'true',
},
...mapHeadersToDeclarativeNetRequestHeaders(body.responseHeaders ?? {}, 'set'), ...mapHeadersToDeclarativeNetRequestHeaders(body.responseHeaders ?? {}, 'set'),
], ],
}, },

View File

@ -3,17 +3,32 @@ import { useStorage } from '@plasmohq/storage/hook';
import { makeUrlIntoDomain } from '~utils/domains'; import { makeUrlIntoDomain } from '~utils/domains';
export const DEFAULT_DOMAIN_WHITELIST = [ export const DEFAULT_DOMAIN_WHITELIST = [];
'mw.lonelil.ru',
'watch.qtchaos.de', export const modifiableResponseHeaders = [
'bmov.app', 'access-control-allow-origin',
'bmov.vercel.app', 'access-control-allow-methods',
'stream.thehairy.me', 'access-control-allow-headers',
'scootydooter.vercel.app', 'content-security-policy',
'movie-web-me.vercel.app', 'content-security-policy-report-only',
'sudo-flix.lol', 'content-disposition',
]; ];
const hostsWithCookiesAccess: RegExp[] = [
/^(?:.*\.)?ee3\.me$/,
/^(?:.*\.)?rips\.cc$/,
/^(?:.*\.)?m4ufree\.(?:tv|to|pw)$/,
/^(?:.*\.)?goojara\.to$/,
/^(?:.*\.)?levidia\.ch$/,
/^(?:.*\.)?wootly\.ch$/,
/^(?:.*\.)?multimovies\.(?:sbs|online|cloud)$/,
];
export function canAccessCookies(host: string): boolean {
if (hostsWithCookiesAccess.some((regex) => regex.test(host))) return true;
return false;
}
export const storage = new Storage(); export const storage = new Storage();
const getDomainWhiteList = async () => { const getDomainWhiteList = async () => {