1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-21 16:18:28 +01:00

[PM-14485] Remove manifest and index.html logic from gulp (#11861)

Refactor the remaining logic from gulp.  Part of the browser build script
refactor effort.

Webpack is now responsible for performing most of the operations previously
done by gulp. This includes: - Setting browser specific class - Building the
manifest file  The `package.json` is modified to include browser specific
commands for `build`, `build:prod`, `build:watch` and `dist`.

# Manifests

Manifests now uses the `copy-webpack-plugin` `transform` feature. The logic is
located in `apps/browser/webpack/manifest.js`. It reads a template, which
supports some basic operations primarily overriding with browser specific
fields using `__browser__`.  The `manifest.json` for both regular and mv3
builds are identical to our existing manifests except:
- `applications` renamed to `browser_specific_settings`.
- `permissions` sorted alphabetically.

# Safari build

Safari requires additional packaging commands. This is implemented as a
powershell script due to the cross-platform nature, and since we generally
require powershell in our distribution pipelines. An alternative would be to
write it in bash, but bash is less powerful and would require some additional
commands like `jq`. Another alternative is to write it using js, but that would
require additional dependencies.
This commit is contained in:
Oscar Hinton 2024-11-18 11:50:24 +01:00 committed by GitHub
parent ea5f492fd1
commit c388697fdf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 376 additions and 5387 deletions

View File

@ -12,6 +12,7 @@ storybook-static
apps/browser/config/config.js
apps/browser/src/auth/scripts/duo.js
apps/browser/webpack/manifest.js
apps/desktop/desktop_native
apps/desktop/src/auth/scripts/duo.js

View File

@ -164,16 +164,74 @@ jobs:
zip -r browser-source.zip browser-source
- name: Upload browser source
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: browser-source-${{ env._BUILD_NUMBER }}.zip
path: browser-source.zip
if-no-files-found: error
- name: NPM setup
run: npm ci
working-directory: browser-source/
- name: Build
run: npm run dist
- name: Build Chrome
run: npm run dist:chrome
working-directory: browser-source/apps/browser
- name: Build Manifest v3
run: npm run dist:mv3
- name: Upload Chrome MV3 artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-chrome-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-chrome.zip
if-no-files-found: error
- name: Build Edge
run: npm run dist:edge
working-directory: browser-source/apps/browser
- name: Upload Edge artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-edge-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-edge.zip
if-no-files-found: error
- name: Build Edge (MV3)
run: npm run dist:edge:mv3
working-directory: browser-source/apps/browser
- name: Upload Edge MV3 artifact (DO NOT USE FOR PROD)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: DO-NOT-USE-FOR-PROD-dist-edge-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-edge.zip
if-no-files-found: error
- name: Build Firefox
run: npm run dist:firefox
working-directory: browser-source/apps/browser
- name: Upload Firefox artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-firefox.zip
if-no-files-found: error
- name: Build Firefox (MV3)
run: npm run dist:firefox:mv3
working-directory: browser-source/apps/browser
- name: Upload Firefox MV3 artifact (DO NOT USE FOR PROD)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: DO-NOT-USE-FOR-PROD-dist-firefox-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-firefox.zip
if-no-files-found: error
- name: Build Opera
run: npm run dist:opera
working-directory: browser-source/apps/browser
- name: Upload Opera artifact
@ -183,53 +241,15 @@ jobs:
path: browser-source/apps/browser/dist/dist-opera.zip
if-no-files-found: error
- name: Build Opera (MV3)
run: npm run dist:opera:mv3
working-directory: browser-source/apps/browser
- name: Upload Opera MV3 artifact (DO NOT USE FOR PROD)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: DO-NOT-USE-FOR-PROD-dist-opera-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-opera-mv3.zip
if-no-files-found: error
- name: Upload Chrome MV3 artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-chrome-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-chrome-mv3.zip
if-no-files-found: error
- name: Upload Firefox artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-firefox.zip
if-no-files-found: error
- name: Upload Firefox MV3 artifact (DO NOT USE FOR PROD)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: DO-NOT-USE-FOR-PROD-dist-firefox-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-firefox-mv3.zip
if-no-files-found: error
- name: Upload Edge artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist-edge-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-edge.zip
if-no-files-found: error
- name: Upload Edge MV3 artifact (DO NOT USE FOR PROD)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: DO-NOT-USE-FOR-PROD-dist-edge-MV3-${{ env._BUILD_NUMBER }}.zip
path: browser-source/apps/browser/dist/dist-edge-mv3.zip
if-no-files-found: error
- name: Upload browser source
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: browser-source-${{ env._BUILD_NUMBER }}.zip
path: browser-source.zip
path: browser-source/apps/browser/dist/dist-opera.zip
if-no-files-found: error
build-safari:

View File

@ -121,7 +121,7 @@ jobs:
PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }}
run: |
mv browser-source.zip browser-source-$PACKAGE_VERSION.zip
mv dist-chrome-mv3.zip dist-chrome-$PACKAGE_VERSION.zip
mv dist-chrome.zip dist-chrome-$PACKAGE_VERSION.zip
mv dist-opera.zip dist-opera-$PACKAGE_VERSION.zip
mv dist-firefox.zip dist-firefox-$PACKAGE_VERSION.zip
mv dist-edge.zip dist-edge-$PACKAGE_VERSION.zip

View File

@ -1,233 +0,0 @@
const child = require("child_process");
const fs = require("fs");
const { rimraf } = require("rimraf");
const gulp = require("gulp");
const gulpif = require("gulp-if");
const jeditor = require("gulp-json-editor");
const replace = require("gulp-replace");
const manifest = require("./src/manifest.json");
const manifestVersion = parseInt(process.env.MANIFEST_VERSION || manifest.version);
const paths = {
build: "./build/",
dist: "./dist/",
safari: "./src/safari/",
};
function buildString() {
var build = "";
if (process.env.MANIFEST_VERSION) {
build = `-mv${process.env.MANIFEST_VERSION}`;
}
if (process.env.BUILD_NUMBER && process.env.BUILD_NUMBER !== "") {
build = `-${process.env.BUILD_NUMBER}`;
}
return build;
}
function distFileName(browserName, ext) {
return `dist-${browserName}${buildString()}.${ext}`;
}
async function dist(browserName, manifest) {
const { default: zip } = await import("gulp-zip");
return gulp
.src(paths.build + "**/*")
.pipe(gulpif("popup/index.html", replace("__BROWSER__", "browser_" + browserName)))
.pipe(gulpif("manifest.json", jeditor(manifest)))
.pipe(zip(distFileName(browserName, "zip")))
.pipe(gulp.dest(paths.dist));
}
function distFirefox() {
return dist("firefox", (manifest) => {
if (manifestVersion === 3) {
const backgroundScript = manifest.background.service_worker;
delete manifest.background.service_worker;
manifest.background.scripts = [backgroundScript];
}
delete manifest.storage;
delete manifest.sandbox;
manifest.optional_permissions = manifest.optional_permissions.filter(
(permission) => permission !== "privacy",
);
return manifest;
});
}
function distOpera() {
return dist("opera", (manifest) => {
delete manifest.applications;
// Mv3 on Opera does seem to have sidebar support, however it is not working as expected.
// On install, the extension will crash the browser entirely if the sidebar_action key is set.
// We will remove the sidebar_action key for now until opera implements a fix.
if (manifestVersion === 3) {
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
}
return manifest;
});
}
function distChrome() {
return dist("chrome", (manifest) => {
delete manifest.applications;
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
return manifest;
});
}
function distEdge() {
return dist("edge", (manifest) => {
delete manifest.applications;
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
return manifest;
});
}
function distSafariMas(cb) {
return distSafariApp(cb, "mas");
}
function distSafariMasDev(cb) {
return distSafariApp(cb, "masdev");
}
function distSafariDmg(cb) {
return distSafariApp(cb, "dmg");
}
function distSafariApp(cb, subBuildPath) {
const buildPath = paths.dist + "Safari/" + subBuildPath + "/";
const builtAppexPath = buildPath + "build/Release/safari.appex";
const builtAppexFrameworkPath = buildPath + "build/Release/safari.appex/Contents/Frameworks/";
const entitlementsPath = paths.safari + "safari/safari.entitlements";
var args = [
"--verbose",
"--force",
"-o",
"runtime",
"--sign",
"Developer ID Application: 8bit Solutions LLC",
"--entitlements",
entitlementsPath,
];
if (subBuildPath !== "dmg") {
args = [
"--verbose",
"--force",
"--sign",
subBuildPath === "mas"
? "3rd Party Mac Developer Application: Bitwarden Inc"
: "E7C9978F6FBCE0553429185C405E61F5380BE8EB",
"--entitlements",
entitlementsPath,
];
}
return rimraf([buildPath + "**/*"], { glob: true })
.then(() => safariCopyAssets(paths.safari + "**/*", buildPath))
.then(() => safariCopyBuild(paths.build + "**/*", buildPath + "safari/app"))
.then(() => {
const proc = child.spawn("xcodebuild", [
"-project",
buildPath + "desktop.xcodeproj",
"-alltargets",
"-configuration",
"Release",
]);
stdOutProc(proc);
return new Promise((resolve) => proc.on("close", resolve));
})
.then(async () => {
const libs = fs
.readdirSync(builtAppexFrameworkPath)
.filter((p) => p.endsWith(".dylib"))
.map((p) => builtAppexFrameworkPath + p);
const libPromises = [];
libs.forEach((i) => {
const proc = child.spawn("codesign", args.concat([i]));
stdOutProc(proc);
libPromises.push(new Promise((resolve) => proc.on("close", resolve)));
});
return Promise.all(libPromises);
})
.then(() => {
const proc = child.spawn("codesign", args.concat([builtAppexPath]));
stdOutProc(proc);
return new Promise((resolve) => proc.on("close", resolve));
})
.then(
() => {
return cb;
},
() => {
return cb;
},
);
}
function safariCopyAssets(source, dest) {
return new Promise((resolve, reject) => {
gulp
.src(source)
.on("error", reject)
.pipe(gulpif("safari/Info.plist", replace("0.0.1", manifest.version)))
.pipe(
gulpif("safari/Info.plist", replace("0.0.2", process.env.BUILD_NUMBER || manifest.version)),
)
.pipe(gulpif("desktop.xcodeproj/project.pbxproj", replace("../../../build", "../safari/app")))
.pipe(gulp.dest(dest))
.on("end", resolve);
});
}
async function safariCopyBuild(source, dest) {
return new Promise((resolve, reject) => {
gulp
.src(source)
.on("error", reject)
.pipe(gulpif("popup/index.html", replace("__BROWSER__", "browser_safari")))
.pipe(
gulpif(
"manifest.json",
jeditor((manifest) => {
if (manifestVersion === 3) {
const backgroundScript = manifest.background.service_worker;
delete manifest.background.service_worker;
manifest.background.scripts = [backgroundScript];
}
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
delete manifest.optional_permissions;
manifest.permissions.push("nativeMessaging");
return manifest;
}),
),
)
.pipe(gulp.dest(dest))
.on("end", resolve);
});
}
function stdOutProc(proc) {
proc.stdout.on("data", (data) => console.log(data.toString()));
proc.stderr.on("data", (data) => console.error(data.toString()));
}
exports["dist:firefox"] = distFirefox;
exports["dist:chrome"] = distChrome;
exports["dist:opera"] = distOpera;
exports["dist:edge"] = distEdge;
exports["dist:safari"] = gulp.parallel(distSafariMas, distSafariMasDev, distSafariDmg);
exports["dist:safari:mas"] = distSafariMas;
exports["dist:safari:masdev"] = distSafariMasDev;
exports["dist:safari:dmg"] = distSafariDmg;
exports.dist = gulp.parallel(distFirefox, distChrome, distOpera, distEdge);

View File

@ -2,26 +2,32 @@
"name": "@bitwarden/browser",
"version": "2024.11.1",
"scripts": {
"build": "cross-env MANIFEST_VERSION=3 webpack",
"build:mv2": "webpack",
"build": "npm run build:chrome",
"build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 webpack",
"build:edge": "cross-env BROWSER=edge webpack",
"build:firefox": "cross-env BROWSER=firefox webpack",
"build:opera": "cross-env BROWSER=opera webpack",
"build:safari": "cross-env BROWSER=safari webpack",
"build:watch": "npm run build:watch:chrome",
"build:watch:chrome": "cross-env MANIFEST_VERSION=3 BROWSER=chrome webpack --watch",
"build:watch:firefox": "cross-env MANIFEST_VERSION=3 BROWSER=firefox webpack --watch",
"build:watch:safari": "cross-env MANIFEST_VERSION=3 BROWSER=safari webpack --watch",
"build:watch:mv2": "webpack --watch",
"build:prod": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" webpack",
"build:prod:watch": "cross-env NODE_ENV=production webpack --watch",
"dist": "npm run build:prod && gulp dist",
"dist:mv3": "cross-env MANIFEST_VERSION=3 npm run build:prod && cross-env MANIFEST_VERSION=3 gulp dist",
"dist:chrome": "npm run build:prod && gulp dist:chrome",
"dist:chrome:beta": "cross-env MANIFEST_VERSION=3 npm run build:prod:beta && cross-env MANIFEST_VERSION=3 BETA_BUILD=1 gulp dist:chrome",
"dist:firefox": "npm run build:prod && gulp dist:firefox",
"dist:opera": "npm run build:prod && gulp dist:opera",
"dist:safari": "cross-env BROWSER=safari npm run build:prod && gulp dist:safari",
"dist:safari:mv3": "cross-env MANIFEST_VERSION=3 BROWSER=safari run build:prod && cross-env MANIFEST_VERSION=3 BROWSER=safari gulp dist:safari",
"dist:safari:mas": "npm run build:prod && gulp dist:safari:mas",
"dist:safari:masdev": "npm run build:prod && gulp dist:safari:masdev",
"dist:safari:dmg": "npm run build:prod && gulp dist:safari:dmg",
"build:watch:chrome": "npm run build:chrome -- --watch",
"build:watch:edge": "npm run build:edge -- --watch",
"build:watch:firefox": "npm run build:firefox -- --watch",
"build:watch:opera": "npm run build:opera -- --watch",
"build:watch:safari": "npm run build:safari -- --watch",
"build:prod:chrome": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" npm run build:chrome",
"build:prod:edge": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" npm run build:edge",
"build:prod:firefox": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" npm run build:firefox",
"build:prod:opera": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" npm run build:opera",
"build:prod:safari": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" npm run build:safari",
"dist:chrome": "npm run build:prod:chrome && mkdir -p dist && tar -C ./build -acf dist/dist-chrome.zip ./",
"dist:edge": "npm run build:prod:edge && mkdir -p dist && tar -C ./build -acf dist/dist-edge.zip ./",
"dist:firefox": "npm run build:prod:firefox && mkdir -p dist && tar -C ./build -acf dist/dist-firefox.zip ./",
"dist:opera": "npm run build:prod:opera && mkdir -p dist && tar -C ./build -acf dist/dist-opera.zip ./",
"dist:safari": "npm run build:prod:safari && ./scripts/package-safari.ps1",
"dist:edge:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:edge",
"dist:firefox:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:firefox",
"dist:opera:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:opera",
"dist:safari:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:safari",
"test": "jest",
"test:watch": "jest --watch",
"test:watch:all": "jest --watchAll"

View File

@ -0,0 +1,112 @@
#!/usr/bin/env pwsh
####
# Builds the safari appex.
####
$buildDir = Join-Path $PSScriptRoot "../build"
$distDir = Join-Path $PSScriptRoot "../dist"
Write-Output $PSScriptRoot
if (-not (Test-Path $buildDir)) {
Write-Output "No build directory found. Exiting..."
exit
}
# Create dist directory if it doesn't exist
if (-not (Test-Path $distDir)) {
New-Item -ItemType Directory -Path $distDir
}
$subBuildPaths = @("mas", "masdev", "dmg")
$safariSrc = Join-Path $PSScriptRoot "../src/safari"
$safariDistPath = Join-Path -Path $distDir -ChildPath "Safari"
if (-not (Test-Path $safariDistPath)) {
New-Item -ItemType Directory -Path $safariDistPath
}
# Delete old safari dists
Remove-Item -LiteralPath $safariDistPath -Force -Recurse
foreach ($subBuildPath in $subBuildPaths) {
$safariBuildPath = Join-Path -Path $safariDistPath -ChildPath $subBuildPath
$builtAppexPath = Join-Path -Path $safariBuildPath -ChildPath "build/Release/safari.appex"
$builtAppexFrameworkPath = Join-Path -Path $safariBuildPath -ChildPath "build/Release/safari.appex/Contents/Frameworks/"
$entitlementsPath = Join-Path -Path $safariSrc -ChildPath "safari/safari.entitlements"
switch ($subBuildPath) {
"mas" {
$codesignArgs = @(
"--verbose",
"--force",
"--sign",
"3rd Party Mac Developer Application: Bitwarden Inc",
"--entitlements",
$entitlementsPath
)
}
"masdev" {
$codesignArgs = @(
"--verbose",
"--force",
"--sign",
"E7C9978F6FBCE0553429185C405E61F5380BE8EB",
"--entitlements",
$entitlementsPath
)
}
"dmg" {
$codesignArgs = @(
"--verbose",
"--force",
"-o",
"runtime",
"--sign",
"Developer ID Application: 8bit Solutions LLC",
"--entitlements",
$entitlementsPath
)
}
}
# Copy safari src
Copy-Item -Path $safariSrc -Destination $safariBuildPath -Recurse
# Copy build
$target = Join-Path -Path $safariBuildPath -ChildPath "safari/app"
Copy-Item -Path $buildDir -Destination $target -Recurse
# Update versions
$jsonFilePath = Join-Path $buildDir "manifest.json"
$jsonContent = Get-Content -Path $jsonFilePath -Raw
$jsonObject = $jsonContent | ConvertFrom-Json
$infoFile = Join-Path -Path $safariBuildPath -ChildPath "safari/Info.plist"
(Get-Content $infoFile).Replace('0.0.1', $jsonObject.version).Replace('0.0.2', $jsonObject.version) | Set-Content $infoFile
$projectFile = Join-Path -Path $safariBuildPath -ChildPath "desktop.xcodeproj/project.pbxproj"
(Get-Content $projectFile).Replace('../../../build', "../safari/app") | Set-Content $projectFile
# Build using xcode
$xcodeBuildArgs = @(
"-project",
(Join-Path $safariBuildPath "desktop.xcodeproj"),
"-alltargets",
"-configuration",
"Release"
)
$proc = Start-Process "xcodebuild" -ArgumentList $xcodeBuildArgs -NoNewWindow -PassThru
$proc.WaitForExit()
# Codesign
$libs = Get-ChildItem -Path $builtAppexFrameworkPath -Filter "*.dylib"
foreach ($lib in $libs) {
$proc = Start-Process "codesign" -ArgumentList ($codesignArgs + $lib.FullName) -NoNewWindow -PassThru
$proc.WaitForExit()
}
$proc = Start-Process "codesign" -ArgumentList ($codesignArgs + $builtAppexPath) -NoNewWindow -PassThru
$proc.WaitForExit()
}

View File

@ -52,19 +52,37 @@
"permissions": [
"<all_urls>",
"*://*/*",
"tabs",
"contextMenus",
"storage",
"unlimitedStorage",
"alarms",
"clipboardRead",
"clipboardWrite",
"contextMenus",
"idle",
"alarms",
"storage",
"tabs",
"unlimitedStorage",
"webNavigation",
"webRequest",
"webRequestBlocking",
"webNavigation"
"webRequestBlocking"
],
"__safari__permissions": [
"<all_urls>",
"*://*/*",
"alarms",
"clipboardRead",
"clipboardWrite",
"contextMenus",
"idle",
"nativeMessaging",
"storage",
"tabs",
"unlimitedStorage",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"optional_permissions": ["nativeMessaging", "privacy"],
"__firefox__optional_permissions": ["nativeMessaging"],
"__safari__optional_permissions": null,
"content_security_policy": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'",
"sandbox": {
"pages": [
@ -75,6 +93,7 @@
],
"content_security_policy": "sandbox allow-scripts; script-src 'self'"
},
"__firefox__sandbox": null,
"commands": {
"_execute_browser_action": {
"suggested_key": {
@ -83,7 +102,14 @@
},
"description": "__MSG_commandOpenPopup__"
},
"_execute_sidebar_action": {
"__firefox___execute_sidebar_action": {
"suggested_key": {
"default": "Alt+Shift+Y",
"linux": "Alt+Shift+U"
},
"description": "__MSG_commandOpenSidebar__"
},
"__opera___execute_sidebar_action": {
"suggested_key": {
"default": "Alt+Shift+Y",
"linux": "Alt+Shift+U"
@ -125,20 +151,26 @@
"overlay/list.html",
"popup/fonts/*"
],
"applications": {
"__firefox__browser_specific_settings": {
"gecko": {
"id": "{446900e4-71c2-419f-a6a7-df9c091e268b}",
"strict_min_version": "91.0"
}
},
"sidebar_action": {
"__firefox__sidebar_action": {
"default_title": "Bitwarden",
"default_panel": "popup/index.html?uilocation=sidebar",
"default_icon": "images/icon19.png",
"open_at_install": false,
"browser_style": false
},
"storage": {
"managed_schema": "managed_schema.json"
}
"__opera__sidebar_action": {
"default_title": "Bitwarden",
"default_panel": "popup/index.html?uilocation=sidebar",
"default_icon": "images/icon19.png",
"open_at_install": false,
"browser_style": false
},
"storage": { "managed_schema": "managed_schema.json" },
"__firefox__storage": null
}

View File

@ -41,6 +41,9 @@
"background": {
"service_worker": "background.js"
},
"__firefox__background": {
"scripts": ["background.js"]
},
"action": {
"default_icon": {
"19": "images/icon19.png",
@ -51,21 +54,40 @@
},
"permissions": [
"activeTab",
"tabs",
"contextMenus",
"storage",
"unlimitedStorage",
"alarms",
"clipboardRead",
"clipboardWrite",
"contextMenus",
"idle",
"alarms",
"scripting",
"offscreen",
"scripting",
"storage",
"tabs",
"unlimitedStorage",
"webNavigation",
"webRequest",
"webRequestAuthProvider",
"webNavigation"
"webRequestAuthProvider"
],
"__safari__permissions": [
"activeTab",
"alarms",
"clipboardRead",
"clipboardWrite",
"contextMenus",
"idle",
"nativeMessaging",
"offscreen",
"scripting",
"storage",
"tabs",
"unlimitedStorage",
"webNavigation",
"webRequest",
"webRequestAuthProvider"
],
"optional_permissions": ["nativeMessaging", "privacy"],
"__firefox__optional_permissions": ["nativeMessaging"],
"__safari__optional_permissions": null,
"host_permissions": ["https://*/*", "http://*/*"],
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'",
@ -79,6 +101,7 @@
"overlay/list.html"
]
},
"__firefox__sandbox": null,
"commands": {
"_execute_action": {
"suggested_key": {
@ -87,7 +110,7 @@
},
"description": "__MSG_commandOpenPopup__"
},
"_execute_sidebar_action": {
"__firefox___execute_sidebar_action": {
"suggested_key": {
"default": "Alt+Shift+Y",
"linux": "Alt+Shift+U"
@ -133,13 +156,13 @@
"matches": ["<all_urls>"]
}
],
"applications": {
"__firefox__browser_specific_settings": {
"gecko": {
"id": "{446900e4-71c2-419f-a6a7-df9c091e268b}",
"strict_min_version": "91.0"
}
},
"sidebar_action": {
"__firefox__sidebar_action": {
"default_title": "Bitwarden",
"default_panel": "popup/index.html?uilocation=sidebar",
"default_icon": "images/icon19.png",
@ -147,5 +170,6 @@
},
"storage": {
"managed_schema": "managed_schema.json"
}
},
"__firefox__storage": null
}

View File

@ -1,5 +1,5 @@
<!doctype html>
<html class="__BROWSER__">
<html class="browser_<%= htmlWebpackPlugin.options.browser %>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

View File

@ -7,58 +7,14 @@ const { AngularWebpackPlugin } = require("@ngtools/webpack");
const TerserPlugin = require("terser-webpack-plugin");
const { TsconfigPathsPlugin } = require("tsconfig-paths-webpack-plugin");
const configurator = require("./config/config");
const manifest = require("./webpack/manifest");
if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = "development";
}
const ENV = (process.env.ENV = process.env.NODE_ENV);
const manifestVersion = process.env.MANIFEST_VERSION == 3 ? 3 : 2;
const browser = process.env.BROWSER;
function modifyManifestV3(buffer) {
if (manifestVersion === 2 || !browser) {
return buffer;
}
const manifest = JSON.parse(buffer.toString());
if (browser === "chrome") {
// Remove unsupported properties
delete manifest.applications;
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
return JSON.stringify(manifest, null, 2);
}
// Update the background script reference to be an event page
const backgroundScript = manifest.background.service_worker;
delete manifest.background.service_worker;
manifest.background.scripts = [backgroundScript];
// Remove unsupported properties
delete manifest.content_security_policy.sandbox;
delete manifest.sandbox;
delete manifest.applications;
manifest.permissions = manifest.permissions.filter((permission) => permission !== "offscreen");
if (browser === "safari") {
delete manifest.sidebar_action;
delete manifest.commands._execute_sidebar_action;
delete manifest.optional_permissions;
manifest.permissions.push("nativeMessaging");
}
if (browser === "firefox") {
delete manifest.storage;
manifest.optional_permissions = manifest.optional_permissions.filter(
(permission) => permission !== "privacy",
);
}
return JSON.stringify(manifest, null, 2);
}
const browser = process.env.BROWSER ?? "chrome";
console.log(`Building Manifest Version ${manifestVersion} app`);
@ -142,9 +98,10 @@ const requiredPlugins = [
const plugins = [
new HtmlWebpackPlugin({
template: "./src/popup/index.html",
template: "./src/popup/index.ejs",
filename: "popup/index.html",
chunks: ["popup/polyfills", "popup/vendor-angular", "popup/vendor", "popup/main"],
browser: browser,
}),
new HtmlWebpackPlugin({
template: "./src/autofill/notification/bar.html",
@ -178,13 +135,11 @@ const plugins = [
}),
new CopyWebpackPlugin({
patterns: [
manifestVersion == 3
? {
from: "./src/manifest.v3.json",
to: "manifest.json",
transform: (content) => modifyManifestV3(content),
}
: "./src/manifest.json",
{
from: manifestVersion == 3 ? "./src/manifest.v3.json" : "./src/manifest.json",
to: "manifest.json",
transform: manifest.transform(browser),
},
{ from: "./src/managed_schema.json", to: "managed_schema.json" },
{ from: "./src/_locales", to: "_locales" },
{ from: "./src/images", to: "images" },

View File

@ -0,0 +1,72 @@
/**
* Transform the manifest template into a browser specific manifest.
*
* We support a simple browser prefix to the manifest keys. Example:
*
* ```json
* {
* "name": "Default name",
* "__chrome__name": "Chrome override"
* }
* ```
*
* Will result in the following manifest:
*
* ```json
* {
* "name": "Chrome override"
* }
* ```
*
* for Chrome.
*/
function transform(browser) {
return (buffer) => {
let manifest = JSON.parse(buffer.toString());
manifest = transformPrefixes(manifest, browser);
return JSON.stringify(manifest, null, 2);
};
}
const browsers = ["chrome", "edge", "firefox", "opera", "safari"];
/**
* Flatten the browser prefixes in the manifest.
*
* - Removes unrelated browser prefixes.
* - A null value deletes the non prefixed key.
*/
function transformPrefixes(manifest, browser) {
const prefix = `__${browser}__`;
function transformObject(obj) {
return Object.keys(obj).reduce((acc, key) => {
// Determine if we need to recurse into the object.
const nested = typeof obj[key] === "object" && obj[key] !== null && !Array.isArray(obj[key]);
if (key.startsWith(prefix)) {
const newKey = key.slice(prefix.length);
// Null values are used to remove keys.
if (obj[key] == null) {
delete acc[newKey];
return acc;
}
acc[newKey] = nested ? transformObject(obj[key]) : obj[key];
} else if (!browsers.some((b) => key.startsWith(`__${b}__`))) {
acc[key] = nested ? transformObject(obj[key]) : obj[key];
}
return acc;
}, {});
}
return transformObject(manifest);
}
module.exports = {
transform,
};

5009
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -107,11 +107,6 @@
"eslint-plugin-rxjs-angular": "2.0.1",
"eslint-plugin-storybook": "0.8.0",
"eslint-plugin-tailwindcss": "3.17.4",
"gulp": "4.0.2",
"gulp-if": "3.0.0",
"gulp-json-editor": "2.6.0",
"gulp-replace": "1.1.4",
"gulp-zip": "6.0.0",
"html-loader": "5.1.0",
"html-webpack-injector": "1.1.4",
"html-webpack-plugin": "5.6.3",