mirror of
https://github.com/movie-web/extension.git
synced 2025-09-13 14:53:24 +00:00
Compare commits
3 Commits
fix-androi
...
1.1.0
Author | SHA1 | Date | |
---|---|---|---|
|
d989fd1ee8 | ||
|
2ea2208dea | ||
|
6a3d32dcc3 |
10
.github/SECURITY.md
vendored
10
.github/SECURITY.md
vendored
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
The latest version of movie-web is the only version that is supported, as it is the only version that is being actively developed.
|
The movie-web maintainers only support the latest version of movie-web published at https://movie-web.app.
|
||||||
|
This published version is equivalent to the master branch.
|
||||||
|
|
||||||
|
Support is not provided for any forks or mirrors of movie-web.
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
You can contact the movie-web maintainers to report a vulnerability:
|
There are two ways you can contact the movie-web maintainers to report a vulnerability:
|
||||||
- Report the vulnerability in the [movie-web Discord server](https://movie-web.github.io/links/discord)
|
- Email [security@movie-web.app](mailto:security@movie-web.app)
|
||||||
|
- Report the vulnerability in the [movie-web Discord server](https://discord.movie-web.app)
|
||||||
|
4
.github/workflows/deploying.yml
vendored
4
.github/workflows/deploying.yml
vendored
@@ -94,8 +94,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: ./chrome/chrome-mv3-prod.zip
|
asset_path: ./chrome/chrome-mv3-prod.zip
|
||||||
asset_name: extension-mw.chrome.zip
|
asset_name: extension-mw.chrome.crx
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/x-chrome-extension
|
||||||
|
|
||||||
- name: Upload Firefox release
|
- name: Upload Firefox release
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB |
18
package.json
18
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@movie-web/extension",
|
"name": "@movie-web/extension",
|
||||||
"displayName": "movie-web extension",
|
"displayName": "movie-web extension",
|
||||||
"version": "1.1.4",
|
"version": "1.1.0",
|
||||||
"description": "Enhance your movie-web experience with just one click",
|
"description": "Enhance your movie-web experience with just one click",
|
||||||
"author": "movie-web",
|
"author": "movie-web",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -53,21 +53,7 @@
|
|||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "{3fd86354-c73f-4395-9e26-2c5c984579bf}"
|
"id": "{3fd86354-c73f-4395-9e26-2c5c984579bf}"
|
||||||
},
|
|
||||||
"gecko_android": {
|
|
||||||
"id": "{3fd86354-c73f-4395-9e26-2c5c984579bf}"
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"web_accessible_resources": [
|
|
||||||
{
|
|
||||||
"resources": [
|
|
||||||
"assets/active.png",
|
|
||||||
"assets/inactive.png"
|
|
||||||
],
|
|
||||||
"matches": [
|
|
||||||
"<all_urls>"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,6 @@ type Response = BaseResponse<{
|
|||||||
|
|
||||||
const handler: PlasmoMessaging.MessageHandler<BaseRequest, Response> = async (req, res) => {
|
const handler: PlasmoMessaging.MessageHandler<BaseRequest, Response> = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.sender?.tab?.url) throw new Error('No tab URL found in the request.');
|
|
||||||
|
|
||||||
const version = getVersion();
|
const version = getVersion();
|
||||||
res.send({
|
res.send({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -26,7 +24,7 @@ const handler: PlasmoMessaging.MessageHandler<BaseRequest, Response> = async (re
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.send({
|
res.send({
|
||||||
success: false,
|
success: false,
|
||||||
error: err instanceof Error ? err.message : String(err),
|
error: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -3,7 +3,6 @@ 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 { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest';
|
import { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest';
|
||||||
import { isFirefox } from '~utils/extension';
|
|
||||||
import { makeFullUrl } from '~utils/fetcher';
|
import { makeFullUrl } from '~utils/fetcher';
|
||||||
import { assertDomainWhitelist } from '~utils/storage';
|
import { assertDomainWhitelist } from '~utils/storage';
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ type Response<T> = BaseResponse<{
|
|||||||
const mapBodyToFetchBody = (body: Request['body'], bodyType: Request['bodyType']): BodyInit => {
|
const mapBodyToFetchBody = (body: Request['body'], bodyType: Request['bodyType']): BodyInit => {
|
||||||
if (bodyType === 'FormData') {
|
if (bodyType === 'FormData') {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
body.forEach(([key, value]: [any, any]) => {
|
body.forEach(([key, value]) => {
|
||||||
formData.append(key, value.toString());
|
formData.append(key, value.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -50,17 +49,16 @@ const mapBodyToFetchBody = (body: Request['body'], bodyType: Request['bodyType']
|
|||||||
|
|
||||||
const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (req, res) => {
|
const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
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.');
|
|
||||||
|
|
||||||
const url = makeFullUrl(req.body.url, req.body);
|
const url = makeFullUrl(req.body.url, req.body);
|
||||||
await assertDomainWhitelist(req.sender.tab.url);
|
await assertDomainWhitelist(req.sender.tab.url);
|
||||||
|
|
||||||
await setDynamicRules({
|
if (Object.keys(req.body.headers).length > 0) {
|
||||||
ruleId: MAKE_REQUEST_DYNAMIC_RULE,
|
await setDynamicRules({
|
||||||
targetDomains: [new URL(url).hostname],
|
ruleId: MAKE_REQUEST_DYNAMIC_RULE,
|
||||||
requestHeaders: req.body.headers,
|
targetDomains: [new URL(url).hostname],
|
||||||
});
|
requestHeaders: req.body.headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: req.body.method,
|
method: req.body.method,
|
||||||
@@ -73,9 +71,6 @@ const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (r
|
|||||||
|
|
||||||
const cookies = await (chrome || browser).cookies.getAll({
|
const cookies = await (chrome || browser).cookies.getAll({
|
||||||
url: response.url,
|
url: response.url,
|
||||||
...(isFirefox() && {
|
|
||||||
firstPartyDomain: new URL(response.url).hostname,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
@@ -94,7 +89,7 @@ const handler: PlasmoMessaging.MessageHandler<Request, Response<any>> = async (r
|
|||||||
console.error('failed request', err);
|
console.error('failed request', err);
|
||||||
res.send({
|
res.send({
|
||||||
success: false,
|
success: false,
|
||||||
error: err instanceof Error ? err.message : String(err),
|
error: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -11,9 +11,6 @@ type Request = BaseRequest & {
|
|||||||
|
|
||||||
const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (req, res) => {
|
const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.sender?.tab?.id) throw new Error('No tab ID found in the request.');
|
|
||||||
if (!req.body) throw new Error('No body found in the request.');
|
|
||||||
|
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
searchParams.set('redirectUrl', req.body.redirectUrl);
|
searchParams.set('redirectUrl', req.body.redirectUrl);
|
||||||
const url = (chrome || browser).runtime.getURL(`/tabs/${req.body.page}.html?${searchParams.toString()}`);
|
const url = (chrome || browser).runtime.getURL(`/tabs/${req.body.page}.html?${searchParams.toString()}`);
|
||||||
@@ -32,7 +29,7 @@ const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (re
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.send({
|
res.send({
|
||||||
success: false,
|
success: false,
|
||||||
error: err instanceof Error ? err.message : String(err),
|
error: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -15,9 +15,6 @@ interface Request extends BaseRequest {
|
|||||||
|
|
||||||
const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (req, res) => {
|
const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
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.');
|
|
||||||
|
|
||||||
await assertDomainWhitelist(req.sender.tab.url);
|
await assertDomainWhitelist(req.sender.tab.url);
|
||||||
await setDynamicRules(req.body);
|
await setDynamicRules(req.body);
|
||||||
res.send({
|
res.send({
|
||||||
@@ -26,7 +23,7 @@ const handler: PlasmoMessaging.MessageHandler<Request, BaseResponse> = async (re
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.send({
|
res.send({
|
||||||
success: false,
|
success: false,
|
||||||
error: err instanceof Error ? err.message : String(err),
|
error: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -9,7 +9,6 @@ export function SetupScreen() {
|
|||||||
const open = useCallback(() => {
|
const open = useCallback(() => {
|
||||||
const url = (chrome || browser).runtime.getURL(`/tabs/PermissionRequest.html`);
|
const url = (chrome || browser).runtime.getURL(`/tabs/PermissionRequest.html`);
|
||||||
(chrome || browser).tabs.create({ url });
|
(chrome || browser).tabs.create({ url });
|
||||||
window.close();
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -36,7 +36,7 @@ export function ToggleButton(props: ToggleButtonProps) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Extension <strong>{props.active ? 'enabled' : 'disabled'}</strong> <br /> on <strong>{props.domain}</strong>
|
Extension {props.active ? 'enabled' : 'disabled'} <br /> on <strong>{props.domain}</strong>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -15,5 +15,5 @@ export function useDomain(): null | string {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return domain ? makeUrlIntoDomain(domain) : null;
|
return makeUrlIntoDomain(domain);
|
||||||
}
|
}
|
||||||
|
@@ -8,12 +8,12 @@ export function useDomainWhitelist() {
|
|||||||
|
|
||||||
const removeDomain = useCallback((domain: string | null) => {
|
const removeDomain = useCallback((domain: string | null) => {
|
||||||
if (!domain) return;
|
if (!domain) return;
|
||||||
setDomainWhitelist((s) => [...(s ?? []).filter((v) => v !== domain)]);
|
setDomainWhitelist((s) => [...s.filter((v) => v !== domain)]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const addDomain = useCallback((domain: string | null) => {
|
const addDomain = useCallback((domain: string | null) => {
|
||||||
if (!domain) return;
|
if (!domain) return;
|
||||||
setDomainWhitelist((s) => [...(s ?? []).filter((v) => v !== domain), domain]);
|
setDomainWhitelist((s) => [...s.filter((v) => v !== domain), domain]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -23,15 +23,10 @@ export function useDomainWhitelist() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useToggleWhitelistDomain(domain: string | null) {
|
export function useToggleWhitelistDomain(domain: string) {
|
||||||
const { domainWhitelist, addDomain, removeDomain } = useDomainWhitelist();
|
const { domainWhitelist, addDomain, removeDomain } = useDomainWhitelist();
|
||||||
const isWhitelisted = domainWhitelist.includes(domain ?? '');
|
const isWhitelisted = domainWhitelist.includes(domain);
|
||||||
const { grantPermission } = usePermission();
|
const { grantPermission } = usePermission();
|
||||||
const iconPath = (chrome || browser).runtime.getURL(isWhitelisted ? 'assets/active.png' : 'assets/inactive.png');
|
|
||||||
|
|
||||||
(chrome || browser).action.setIcon({
|
|
||||||
path: iconPath,
|
|
||||||
});
|
|
||||||
|
|
||||||
const toggle = useCallback(() => {
|
const toggle = useCallback(() => {
|
||||||
if (!isWhitelisted) {
|
if (!isWhitelisted) {
|
||||||
|
@@ -28,7 +28,7 @@ function IndexPopup() {
|
|||||||
) : (
|
) : (
|
||||||
<Frame>
|
<Frame>
|
||||||
<div className="popup">
|
<div className="popup">
|
||||||
{page === 'toggle' && domain ? <ToggleButton active={isWhitelisted} onClick={toggle} domain={domain} /> : null}
|
{page === 'toggle' ? <ToggleButton active={isWhitelisted} onClick={toggle} domain={domain} /> : null}
|
||||||
{page === 'disabled' ? <DisabledScreen /> : null}
|
{page === 'disabled' ? <DisabledScreen /> : null}
|
||||||
<BottomLabel />
|
<BottomLabel />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -13,7 +13,7 @@ body {
|
|||||||
#__plasmo {
|
#__plasmo {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
min-height: 100%;
|
||||||
background-color: #0A0A10;
|
background-color: #0A0A10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,27 +8,11 @@ export default function PermissionGrant() {
|
|||||||
const { grantPermission } = usePermission();
|
const { grantPermission } = usePermission();
|
||||||
|
|
||||||
const queryParams = new URLSearchParams(window.location.search);
|
const queryParams = new URLSearchParams(window.location.search);
|
||||||
const redirectUrl = queryParams.get('redirectUrl') ?? undefined;
|
const redirectUrl = queryParams.get('redirectUrl') ?? 'https://movie-web.app';
|
||||||
const domain = redirectUrl ? makeUrlIntoDomain(redirectUrl) : undefined;
|
const domain = makeUrlIntoDomain(redirectUrl);
|
||||||
|
|
||||||
if (!domain) {
|
|
||||||
return (
|
|
||||||
<div className="permission-grant container">
|
|
||||||
<div className="inner-container">
|
|
||||||
<div className="permission-card">
|
|
||||||
<h1 className="color-white">Permission</h1>
|
|
||||||
<p className="text-color" style={{ textAlign: 'center' }}>
|
|
||||||
No domain found to grant permission to.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectBack = () => {
|
const redirectBack = () => {
|
||||||
chrome.tabs.getCurrent((tab) => {
|
chrome.tabs.getCurrent((tab) => {
|
||||||
if (!tab?.id) return;
|
|
||||||
chrome.tabs.update(tab.id, { url: redirectUrl });
|
chrome.tabs.update(tab.id, { url: redirectUrl });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -10,10 +10,6 @@ body {
|
|||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#__plasmo {
|
|
||||||
height: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.permission-request.container {
|
.permission-request.container {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: 100px auto;
|
margin: 100px auto;
|
||||||
|
@@ -123,6 +123,5 @@ export const removeDynamicRules = async (ruleIds: number[]) => {
|
|||||||
await (chrome || browser).declarativeNetRequest.updateDynamicRules({
|
await (chrome || browser).declarativeNetRequest.updateDynamicRules({
|
||||||
removeRuleIds: ruleIds,
|
removeRuleIds: ruleIds,
|
||||||
});
|
});
|
||||||
if ((chrome || browser).runtime.lastError?.message)
|
if ((chrome || browser).runtime.lastError?.message) throw new Error((chrome || browser).runtime.lastError.message);
|
||||||
throw new Error((chrome || browser).runtime.lastError?.message ?? 'Unknown error');
|
|
||||||
};
|
};
|
||||||
|
@@ -1,11 +1,3 @@
|
|||||||
export const isChrome = () => {
|
export const isChrome = () => {
|
||||||
return chrome.runtime.getURL('').startsWith('chrome-extension://');
|
return chrome.runtime.getURL('').startsWith('chrome-extension://');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isFirefox = () => {
|
|
||||||
try {
|
|
||||||
return browser.runtime.getURL('').startsWith('moz-extension://');
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@@ -3,14 +3,7 @@ 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 = ['movie-web.app', 'dev.movie-web.app'];
|
||||||
'mw.lonelil.ru',
|
|
||||||
'watch.qtchaos.de',
|
|
||||||
'bmov.vercel.app',
|
|
||||||
'stream.thehairy.me',
|
|
||||||
'scootydooter.vercel.app',
|
|
||||||
'movie-web-me.vercel.app',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const storage = new Storage();
|
export const storage = new Storage();
|
||||||
|
|
||||||
@@ -38,9 +31,5 @@ export const isDomainWhitelisted = async (url: string | undefined) => {
|
|||||||
|
|
||||||
export const assertDomainWhitelist = async (url: string) => {
|
export const assertDomainWhitelist = async (url: string) => {
|
||||||
const isWhiteListed = await isDomainWhitelisted(url);
|
const isWhiteListed = await isDomainWhitelisted(url);
|
||||||
const currentDomain = makeUrlIntoDomain(url);
|
if (!isWhiteListed) throw new Error('Domain is not whitelisted');
|
||||||
if (!isWhiteListed)
|
|
||||||
throw new Error(
|
|
||||||
`${currentDomain} is not whitelisted. Open the extension and click on the power button to whitelist the site.`,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { isChrome } from './extension';
|
import { isChrome } from './extension';
|
||||||
|
|
||||||
export function queryCurrentDomain(cb: (domain: string | null) => void) {
|
export function queryCurrentDomain(cb: (domain: string | null) => void) {
|
||||||
const handle = (tabUrl: string | undefined) => {
|
const handle = (tabUrl: string | null) => {
|
||||||
if (!tabUrl) cb(null);
|
if (!tabUrl) cb(null);
|
||||||
else cb(tabUrl);
|
else cb(tabUrl);
|
||||||
};
|
};
|
||||||
|
@@ -1,13 +1,18 @@
|
|||||||
{
|
{
|
||||||
"extends": "plasmo/templates/tsconfig.base",
|
"extends": "plasmo/templates/tsconfig.base",
|
||||||
"exclude": ["node_modules"],
|
"exclude": [
|
||||||
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"],
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
".plasmo/index.d.ts",
|
||||||
|
"./**/*.ts",
|
||||||
|
"./**/*.tsx"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
|
||||||
"strict": true,
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"~*": ["./src/*"]
|
"~*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"baseUrl": "."
|
"baseUrl": "."
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user