mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 21:50:15 +00:00
WIP: generate SPA checksum to validate web page
This commit is contained in:
5
apps/browser/src/platform/listeners/script-signature.ts
Normal file
5
apps/browser/src/platform/listeners/script-signature.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
|
||||
export class ScriptSignature {
|
||||
constructor(private readonly cryptoFunctionService: CryptoFunctionService) {}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { firstValueFrom } from "rxjs";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
@@ -22,6 +23,7 @@ export class UpdateBadge {
|
||||
private authService: AuthService;
|
||||
private badgeSettingsService: BadgeSettingsServiceAbstraction;
|
||||
private cipherService: CipherService;
|
||||
private environmentService: EnvironmentService;
|
||||
private badgeAction: typeof chrome.action | typeof chrome.browserAction;
|
||||
private sidebarAction: OperaSidebarAction | FirefoxSidebarAction;
|
||||
private win: Window & typeof globalThis;
|
||||
@@ -31,6 +33,7 @@ export class UpdateBadge {
|
||||
this.sidebarAction = BrowserApi.getSidebarAction(self);
|
||||
this.win = win;
|
||||
|
||||
this.environmentService = services.environmentService;
|
||||
this.badgeSettingsService = services.badgeSettingsService;
|
||||
this.authService = services.authService;
|
||||
this.cipherService = services.cipherService;
|
||||
@@ -38,9 +41,19 @@ export class UpdateBadge {
|
||||
|
||||
async run(opts?: { tabId?: number; windowId?: number }): Promise<void> {
|
||||
const authStatus = await this.authService.getAuthStatus();
|
||||
const environment = await firstValueFrom(this.environmentService.cloudWebVaultUrl$);
|
||||
|
||||
await this.setBadgeBackgroundColor();
|
||||
|
||||
const tab = await this.getTab(opts?.tabId, opts?.windowId);
|
||||
await this.setAuthStatusBadge(authStatus, tab);
|
||||
if (tab?.url?.startsWith(environment)) {
|
||||
await this.setValidWebVaultBadge(authStatus, tab);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async setAuthStatusBadge(authStatus: AuthenticationStatus, tab: chrome.tabs.Tab) {
|
||||
switch (authStatus) {
|
||||
case AuthenticationStatus.LoggedOut: {
|
||||
await this.setLoggedOut();
|
||||
@@ -51,13 +64,21 @@ export class UpdateBadge {
|
||||
break;
|
||||
}
|
||||
case AuthenticationStatus.Unlocked: {
|
||||
const tab = await this.getTab(opts?.tabId, opts?.windowId);
|
||||
await this.setUnlocked({ tab, windowId: tab?.windowId });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setValidWebVaultBadge(authStatus: AuthenticationStatus, tab: chrome.tabs.Tab) {
|
||||
if (authStatus === AuthenticationStatus.Unlocked) {
|
||||
await this.setUnlocked({ tab, windowId: tab?.windowId });
|
||||
} else {
|
||||
await this.setBadgeIcon("_gray", tab.windowId);
|
||||
await this.clearBadgeText();
|
||||
}
|
||||
}
|
||||
|
||||
async setLoggedOut(): Promise<void> {
|
||||
await this.setBadgeIcon("_gray");
|
||||
await this.clearBadgeText();
|
||||
|
||||
35
apps/web/scripts/generateChecksums.js
Normal file
35
apps/web/scripts/generateChecksums.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
|
||||
// Path to the built index.html file. The expectation is that this file contains <script> tags to generate checksums for.
|
||||
const indexFile = process.argv.slice(2);
|
||||
const indexFileDir = path.dirname(indexFile[0]);
|
||||
|
||||
// Read the index.html file.
|
||||
const index = fs.readFileSync(indexFile[0], "utf8");
|
||||
|
||||
// Extract all the script tags.
|
||||
// captures the src tag in the `src` group and any inline script in the `inline` group.
|
||||
const scripts = index.matchAll(
|
||||
/<script[^>]*?(?:src=(["\'])(?<src>(?:[\s\S](?!\1|>))*[\s\S]?)\1)?>(?<inline>[\s\S]*?)<\/script>/gm,
|
||||
);
|
||||
|
||||
const checksums = {
|
||||
inline: [],
|
||||
};
|
||||
|
||||
for (const match of scripts) {
|
||||
const src = match.groups.src;
|
||||
const inline = match.groups.inline;
|
||||
if (src) {
|
||||
const file = src;
|
||||
const fileContent = fs.readFileSync(path.join(indexFileDir, file), "utf8");
|
||||
checksums[file] = crypto.createHash("sha256").update(fileContent).digest("hex");
|
||||
}
|
||||
if (inline) {
|
||||
checksums.inline.push(crypto.createHash("sha256").update(inline).digest("hex"));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(checksums, null, 2));
|
||||
Reference in New Issue
Block a user