Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .github/workflows/compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@ jobs:
sourcemaps: ./build
version_prefix: mask-
ignore_missing: true
- name: Upload `MaskNetwork.chromium-mv2.zip`
uses: actions/upload-artifact@v7
with:
name: MaskNetwork.chromium-mv2.zip
path: masknetwork.chromium-mv2.zip
if-no-files-found: error
- name: Upload `MaskNetwork.chromium-beta.zip`
uses: actions/upload-artifact@v7
with:
Expand All @@ -91,12 +85,6 @@ jobs:
name: MaskNetwork.chromium-mv3.zip
path: masknetwork.chromium-mv3.zip
if-no-files-found: error
- name: Upload `MaskNetwork.firefox-mv2.zip`
uses: actions/upload-artifact@v7
with:
name: MaskNetwork.firefox-mv2.zip
path: masknetwork.firefox-mv2.zip
if-no-files-found: error
- name: Upload `MaskNetwork.firefox-mv3.zip`
uses: actions/upload-artifact@v7
with:
Expand Down
1 change: 0 additions & 1 deletion knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const config: KnipConfig = {
ignore: ['public'],
entry: [
'.webpack/webpack.config.ts',
'background/initialization/mv2-entry.ts',
'background/initialization/mv3-entry.ts',
'dashboard/initialization/index.ts',
'popups/initialization/index.ts',
Expand Down
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
"scripts": {
"start": "dev",
"start-rspack": "dev-rspack",
"start:mv2": "dev --manifest 2",
"start:mv3": "dev --manifest 3",
"start:fx": "dev --manifest firefox-mv3",
"codegen": "gulp codegen-watch",
"build": "build",
Expand Down
2 changes: 1 addition & 1 deletion packages/mask/.webpack/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ export async function createConfiguration(
dashboard: withReactDevTools(join(import.meta.dirname, '../dashboard/initialization/index.ts')),
popups: withReactDevTools(join(import.meta.dirname, '../popups/initialization/index.ts')),
contentScript: withReactDevTools(join(import.meta.dirname, '../content-script/index.ts')),
background: normalizeEntryDescription(join(import.meta.dirname, '../background/initialization/mv2-entry.ts')),
background: normalizeEntryDescription(join(import.meta.dirname, '../background/initialization/mv3-entry.ts')),
backgroundWorker: normalizeEntryDescription(
join(import.meta.dirname, '../background/initialization/mv3-entry.ts'),
),
Expand Down
5 changes: 1 addition & 4 deletions packages/mask/.webpack/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import type { Configuration } from 'webpack'
import { join, isAbsolute } from 'node:path'

export const ManifestFile = {
ChromiumMV2: 'chromium-mv2',
ChromiumMV3: 'chromium-mv3',
ChromiumBetaMV3: 'chromium-beta-mv3',
FirefoxMV2: 'firefox-mv2',
FirefoxMV3: 'firefox-mv3',
SafariMV3: 'safari-mv3',
}
Expand Down Expand Up @@ -114,8 +112,7 @@ export function computedBuildFlags(
if (flags.sourceMapPreference) {
// React 19 requires a precise source map to make "Open in Editor" feature work
if (flags.devtools) sourceMapKind = 'source-map'
else if (flags.manifestFile.includes('3')) sourceMapKind = 'inline-cheap-source-map'
else sourceMapKind = 'eval-cheap-source-map'
else sourceMapKind = 'inline-cheap-source-map'

if (flags.mode === 'production') sourceMapKind = 'source-map'
if (typeof flags.sourceMapPreference === 'string') sourceMapKind = flags.sourceMapPreference
Expand Down
22 changes: 0 additions & 22 deletions packages/mask/.webpack/manifest/manifest.json

This file was deleted.

44 changes: 9 additions & 35 deletions packages/mask/.webpack/plugins/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ export function emitManifestFile(flags: NormalizedFlags, computedFlags: Computed
readFileSync(new URL('../../../../security/content-security-policy.json', import.meta.url), 'utf-8'),
)
const cspContent = {
mv2: Array.from(data['@mv2']).join('; ') + '; ',
mv2dev: Array.from(data['@mv2dev']).join('; ') + '; ',
mv3: Array.from(data['@mv3']).join('; ') + '; ',
}
if (flags.csp && flags.mode === 'development') {
Expand All @@ -41,12 +39,10 @@ export function emitManifestFile(flags: NormalizedFlags, computedFlags: Computed
csp += '; '
}
csp.trim()
cspContent.mv2 += csp
cspContent.mv2dev += csp
cspContent.mv3 += csp
}

const manifest = prepareAllManifest(flags, computedFlags, cspContent)
const manifest = prepareAllManifest(flags, cspContent)
const plugins = []
for (const [fileName, fileContent] of manifest) {
plugins.push(
Expand Down Expand Up @@ -77,29 +73,21 @@ export function emitManifestFile(flags: NormalizedFlags, computedFlags: Computed
return plugins
}

type ManifestV2 = Manifest.WebExtensionManifest & { manifest_version: 2; key?: string }
type ManifestV3 = Manifest.WebExtensionManifest & { manifest_version: 3; key?: string }
type ModifyAcceptFlags = Pick<NormalizedFlags, 'mode' | 'channel' | 'devtools' | 'hmr'>
type ModifyAcceptFlags = Pick<NormalizedFlags, 'mode' | 'channel' | 'devtools'>
type CSP = {
mv2: string
mv2dev: string
mv3: string
}
type ManifestPresets =
| [flags: ModifyAcceptFlags, base: ManifestV2, modify?: (manifest: ManifestV2) => void]
| [flags: ModifyAcceptFlags, base: ManifestV3, modify?: (manifest: ManifestV3) => void]
type ManifestPresets = [flags: ModifyAcceptFlags, base: ManifestV3, modify?: (manifest: ManifestV3) => void]

function prepareAllManifest(flags: NormalizedFlags, computedFlags: ComputedFlags, csp: CSP) {
const mv2Base: ManifestV2 = parseJSONc(readFileSync(new URL('../manifest/manifest.json', import.meta.url), 'utf-8'))
function prepareAllManifest(flags: NormalizedFlags, csp: CSP) {
const mv3Base: ManifestV3 = parseJSONc(
readFileSync(new URL('../manifest/manifest-mv3.json', import.meta.url), 'utf-8'),
)

const manifestFlags: Record<NormalizedFlags['manifestFile'], ManifestPresets> = {
'chromium-beta-mv3': [{ ...flags, channel: 'beta' }, mv3Base],
'chromium-mv2': [flags, mv2Base, (manifest: ManifestV2) => (manifest.browser_specific_settings = undefined)],
'chromium-mv3': [flags, mv3Base, (manifest: ManifestV3) => (manifest.browser_specific_settings = undefined)],
'firefox-mv2': [flags, mv2Base, (manifest: ManifestV2) => manifest.permissions!.push('tabs')],
'firefox-mv3': [
flags,
mv3Base,
Expand All @@ -123,24 +111,19 @@ function prepareAllManifest(flags: NormalizedFlags, computedFlags: ComputedFlags
},
],
}
const manifest = new Map<NormalizedFlags['manifestFile'], ManifestV2 | ManifestV3>()
const manifest = new Map<NormalizedFlags['manifestFile'], ManifestV3>()
for (const fileName in manifestFlags) {
if (!Object.hasOwn(manifestFlags, fileName)) continue
const [flags, base, modify]: ManifestPresets = (manifestFlags as any)[fileName]
const fileContent = cloneDeep(base)
editManifest(fileContent, cloneDeep(flags), cloneDeep(computedFlags), csp)
editManifest(fileContent, cloneDeep(flags), csp)
modify?.(fileContent as any)
manifest.set(fileName as any, fileContent)
}
return manifest
}

function editManifest(
manifest: ManifestV2 | ManifestV3,
flags: ModifyAcceptFlags,
computedFlags: ComputedFlags,
csp: CSP,
) {
function editManifest(manifest: ManifestV3, flags: ModifyAcceptFlags, csp: CSP) {
if (flags.mode === 'development') manifest.name += ' (dev)'
else if (flags.channel === 'beta') manifest.name += ' (beta)'
else if (flags.channel === 'insider') manifest.name += ' (insider)'
Expand All @@ -151,21 +134,12 @@ function editManifest(
const topPackageJSON = JSON.parse(readFileSync(new URL('../../../../package.json', import.meta.url), 'utf-8'))
manifest.version = topPackageJSON.version

if (manifest.manifest_version === 2) {
if (String(computedFlags.sourceMapKind).includes('eval')) manifest.content_security_policy = csp.mv2dev
else manifest.content_security_policy = csp.mv2

if (flags.hmr) {
;(manifest.web_accessible_resources as string[]).push('*.json', '*.js')
}
} else {
manifest.content_security_policy = { extension_pages: csp.mv3 }
}
manifest.content_security_policy = { extension_pages: csp.mv3 }
}

// cspell: disable-next-line
// Note: with this key you cannot upload it to the extension store
function fixTheExtensionID(manifest: ManifestV2 | ManifestV3) {
function fixTheExtensionID(manifest: ManifestV3) {
manifest.key =
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoz51rhO1w+wD' +
'0EKZJEFJaSMkIcIj0qRadfi0tqcl5nbpuJAsafvLe3MaTbW9LhbixTg9' +
Expand Down
1 change: 0 additions & 1 deletion packages/mask/background/initialization/mv2-entry.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/mask/background/services/helper/popup-opener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function openOrFocusPopupWindow(initialURL: string): Promise<void> {
// opened from the background chrome process for the extension that
// has no physical dimensions

// Note: DOM is only available in MV2 or MV3 page mode.
// Note: DOM is only available in page-based background contexts.
const { screenX, outerWidth, screenY } = globalThis as any
if (typeof screenX === 'number' && typeof screenY === 'number' && typeof outerWidth === 'number') {
top = Math.max(screenY, 0)
Expand Down
29 changes: 8 additions & 21 deletions packages/mask/background/services/site-adaptors/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import { Sniffings } from '@masknet/shared-base'
import { maskSDK_URL, injectUserScriptMV2, evaluateContentScript } from '../../utils/injectScript.js'
import { maskSDK_URL, evaluateContentScript } from '../../utils/injectScript.js'

export async function attachMaskSDKToCurrentActivePage(): Promise<boolean> {
if (browser.scripting) {
const [{ id }] = await browser.tabs.query({ active: true })
if (!id) return false
await Promise.all([attachMaskSDK3(id), evaluateContentScript(id)])
} else if (browser.tabs) {
await Promise.all([attachMaskSDK2(), evaluateContentScript(undefined)])
}
const [{ id }] = await browser.tabs.query({ active: true })
if (!id) return false
await Promise.all([attachMaskSDK(id), evaluateContentScript(id)])
return true
}

async function attachMaskSDK2() {
await browser.tabs.executeScript(undefined, {
code: await injectUserScriptMV2(maskSDK_URL),
})
}
async function attachMaskSDK3(id: number) {
async function attachMaskSDK(id: number) {
// TODO: Firefox MV3
const target = {
target: { tabId: id },
Expand All @@ -31,13 +22,9 @@ async function attachMaskSDK3(id: number) {
export async function developmentMaskSDKReload(): Promise<void> {
if (process.env.NODE_ENV !== 'development') return

if (browser.scripting) {
const [{ id }] = await browser.tabs.query({ active: true })
if (!id) return
await attachMaskSDK3(id)
} else if (browser.tabs) {
await attachMaskSDK2()
}
const [{ id }] = await browser.tabs.query({ active: true })
if (!id) return
await attachMaskSDK(id)
}

export async function shouldSuggestConnectInPopup(url?: string): Promise<boolean> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { hmr } from '../../../utils-pure/hmr.js'
import type { ExtensionTypes, WebNavigation } from 'webextension-polyfill'
import {
evaluateContentScript,
ignoreInjectError,
injectUserScriptMV2,
injectedScriptURL,
maskSDK_URL,
} from '../../utils/injectScript.js'
import type { WebNavigation } from 'webextension-polyfill'
import { evaluateContentScript, ignoreInjectError, injectedScriptURL, maskSDK_URL } from '../../utils/injectScript.js'
import { Sniffings } from '@masknet/shared-base'
import { matchesAnySiteAdaptor } from '../../../shared/site-adaptors/definitions.js'

Expand All @@ -18,22 +12,24 @@ async function onCommittedListener(arg: WebNavigation.OnCommittedDetailsType): P
const contains = await browser.permissions.contains({ origins: [arg.url] })
if (!contains) return

const detail: ExtensionTypes.InjectDetails = { runAt: 'document_start', frameId: arg.frameId }
const err = ignoreInjectError(arg)

const executeScript = (files: string[]) => {
const script = {
target: { tabId: arg.tabId, frameIds: [arg.frameId] },
files,
world: 'MAIN' as any,
injectImmediately: true,
}
if (Sniffings.is_firefox) delete script.world
return browser.scripting.executeScript(script)
}

if (matchesAnySiteAdaptor(arg.url)) {
// don't add await here. we don't want this to block the content script
if (Sniffings.is_firefox) {
browser.tabs.executeScript(arg.tabId, { ...detail, file: injectedScriptURL }).catch(err)
} else {
injectUserScriptMV2(injectedScriptURL)
.then(async (code) => browser.tabs.executeScript(arg.tabId, { ...detail, code }))
.catch(err)
}
executeScript([injectedScriptURL]).catch(err)
}
injectUserScriptMV2(maskSDK_URL)
.then(async (code) => browser.tabs.executeScript(arg.tabId, { ...detail, code }))
.catch(err)
executeScript([maskSDK_URL]).catch(err)

evaluateContentScript(arg.tabId, arg.frameId).catch(err)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/mask/background/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"rootDir": "./",
"outDir": "../dist/background/",
"tsBuildInfoFile": "../dist/background.tsbuildinfo",
// MV3 = WebWorker, MV2 = DOM
// Chrome MV3 = WebWorker, Firefox MV3 = DOM
// but we cannot build the same code in two env
"lib": ["ESNext", "WebWorker", "DOM.Iterable"]
},
Expand Down
51 changes: 12 additions & 39 deletions packages/mask/background/utils/injectScript.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,22 @@
import { Sniffings } from '@masknet/shared-base'
import { memoize } from 'lodash-es'

export const injectedScriptURL = '/js/injected-script.js'
export const maskSDK_URL = '/js/mask-sdk.js'

export async function evaluateContentScript(tabId: number | undefined, frameId?: number) {
if (browser.scripting) {
if (tabId === undefined) {
const activeTab = await browser.tabs.query({ active: true })
if (!activeTab.length) return
tabId = activeTab[0].id
}
if (!tabId) return
const script = {
target: { tabId, frameIds: frameId ? [frameId] : undefined },
files: contentScriptList,
world: 'ISOLATED' as any,
}
if (Sniffings.is_firefox) delete script.world
await browser.scripting.executeScript(script)
} else {
for (const script of contentScriptList) {
await browser.tabs.executeScript(tabId, {
file: script,
frameId,
runAt: 'document_idle',
})
}
if (tabId === undefined) {
const activeTab = await browser.tabs.query({ active: true })
if (!activeTab.length) return
tabId = activeTab[0].id
}
if (!tabId) return
const script = {
target: { tabId, frameIds: frameId ? [frameId] : undefined },
files: contentScriptList,
world: 'ISOLATED' as any,
}
if (Sniffings.is_firefox) delete script.world
await browser.scripting.executeScript(script)
}
export const contentScriptList = [
'/js/patches.js',
Expand All @@ -43,22 +32,6 @@ export const contentScriptList = [
'/cs.js',
]

async function injectUserScriptMV2_raw(url: string) {
try {
const code = await fetch(url).then((x) => x.text())
return `{
const script = document.createElement("script")
script.innerHTML = ${JSON.stringify(code)}
document.documentElement.appendChild(script)
}`
} catch (error) {
console.error(error)
return `console.log('[Mask] User script ${url} failed to load.')`
}
}
export const injectUserScriptMV2 =
process.env.NODE_ENV === 'development' ? injectUserScriptMV2_raw : memoize(injectUserScriptMV2_raw)

export function ignoreInjectError(arg: unknown): (reason: Error) => void {
return (error) => {
const ignoredErrorMessages = ['non-structured-clonable data', 'No tab with id']
Expand Down
Loading
Loading