Regular → Executable
+27
-12
@@ -1,8 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
/**
|
||||
* Generates a new extension ID and updates manifest.json and com.bridgeswarm.json.
|
||||
* Run on install so each copy of the template gets a unique ID (no overwrites).
|
||||
* Generates a new BridgeSwarm extension ID pair and updates:
|
||||
* - extension/manifest.json (Chrome key + gecko id)
|
||||
* - extension/manifest_firefox.json (gecko id only; no key)
|
||||
* - com.bridgeswarm.json (allowed_origins / allowed_extensions)
|
||||
*
|
||||
* Also prints the IDs so installers/docs can be synced.
|
||||
* Do NOT reuse holesail-browser's Chrome key/ID — they must stay unique.
|
||||
*/
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
@@ -10,29 +15,24 @@ const path = require('path');
|
||||
|
||||
const repoRoot = path.join(__dirname, '..');
|
||||
const manifestPath = path.join(repoRoot, 'extension', 'manifest.json');
|
||||
const manifestFirefoxPath = path.join(repoRoot, 'extension', 'manifest_firefox.json');
|
||||
const nativeManifestPath = path.join(repoRoot, 'com.bridgeswarm.json');
|
||||
|
||||
// Generate RSA 2048-bit key pair
|
||||
const { publicKey } = crypto.generateKeyPairSync('rsa', {
|
||||
modulusLength: 2048,
|
||||
publicKeyEncoding: { type: 'spki', format: 'der' },
|
||||
privateKeyEncoding: { type: 'pkcs8', format: 'der' }
|
||||
privateKeyEncoding: { type: 'pkcs8', format: 'der' },
|
||||
});
|
||||
|
||||
// Chrome extension ID: first 16 bytes of SHA256(publicKey), each byte -> 2 chars a-p
|
||||
// (Chromium crx_id.py: HexToMPDecimal)
|
||||
// Chrome extension ID: first 16 bytes of SHA256(publicKey), each nibble → a–p
|
||||
const hash = crypto.createHash('sha256').update(publicKey).digest();
|
||||
const chromeId = Array.from(hash.slice(0, 16))
|
||||
.map(b => String.fromCharCode(97 + (b >> 4)) + String.fromCharCode(97 + (b & 0x0f)))
|
||||
.map((b) => String.fromCharCode(97 + (b >> 4)) + String.fromCharCode(97 + (b & 0x0f)))
|
||||
.join('');
|
||||
|
||||
// Firefox ID: unique per install
|
||||
const firefoxId = 'bridgeswarm-' + crypto.randomBytes(8).toString('hex') + '@example.org';
|
||||
|
||||
// Base64-encode public key for manifest
|
||||
const keyBase64 = publicKey.toString('base64');
|
||||
|
||||
// Update extension manifest
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
||||
manifest.key = keyBase64;
|
||||
if (manifest.browser_specific_settings?.gecko) {
|
||||
@@ -40,10 +40,25 @@ if (manifest.browser_specific_settings?.gecko) {
|
||||
}
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
||||
|
||||
// Update native host manifest template
|
||||
// Firefox manifest: same as Chrome but without the Chrome-only "key"
|
||||
if (fs.existsSync(manifestFirefoxPath)) {
|
||||
const manifestFx = JSON.parse(fs.readFileSync(manifestFirefoxPath, 'utf8'));
|
||||
if (manifestFx.browser_specific_settings?.gecko) {
|
||||
manifestFx.browser_specific_settings.gecko.id = firefoxId;
|
||||
}
|
||||
delete manifestFx.key;
|
||||
fs.writeFileSync(manifestFirefoxPath, JSON.stringify(manifestFx, null, 2) + '\n');
|
||||
} else {
|
||||
const fx = { ...manifest };
|
||||
delete fx.key;
|
||||
fs.writeFileSync(manifestFirefoxPath, JSON.stringify(fx, null, 2) + '\n');
|
||||
}
|
||||
|
||||
const nativeManifest = JSON.parse(fs.readFileSync(nativeManifestPath, 'utf8'));
|
||||
nativeManifest.allowed_origins = ['chrome-extension://' + chromeId + '/'];
|
||||
nativeManifest.allowed_extensions = [firefoxId];
|
||||
fs.writeFileSync(nativeManifestPath, JSON.stringify(nativeManifest, null, 2) + '\n');
|
||||
|
||||
console.log('Generated extension ID:', chromeId, '(' + firefoxId + ')');
|
||||
console.log('CHROME_EXT_ID=' + chromeId);
|
||||
console.log('FIREFOX_EXT_ID=' + firefoxId);
|
||||
|
||||
+4
-2
@@ -10,8 +10,10 @@ $InstallDir = "$env:LOCALAPPDATA\bridgeswarm"
|
||||
$Downloads = "$env:USERPROFILE\Downloads"
|
||||
$ManifestName = "com.bridgeswarm"
|
||||
$ExtVersion = "1.0.0"
|
||||
$ChromeExtId = "fmcenppcipeikpnpopolicnllljclmmi"
|
||||
$FirefoxExtId = "bridgeswarm[email protected]"
|
||||
# Must match extension/manifest.json "key" / gecko.id and com.bridgeswarm.json
|
||||
# (unique to BridgeSwarm — do not share with holesail-browser)
|
||||
$ChromeExtId = "jhmbaojjfkkpoolhkoohklbjokdmbdpm"
|
||||
$FirefoxExtId = "[email protected]"
|
||||
|
||||
$HostZip = "bridge-swarm-host-win32-x64.zip"
|
||||
$ExtZip = "BridgeSwarm-$ExtVersion.zip"
|
||||
|
||||
+4
-2
@@ -13,8 +13,10 @@ INSTALL_DIR="$HOME/.bridgeswarm"
|
||||
MANIFEST_NAME="com.bridgeswarm"
|
||||
DOWNLOADS="$HOME/Downloads"
|
||||
EXT_VERSION="1.0.0"
|
||||
CHROME_EXT_ID="fmcenppcipeikpnpopolicnllljclmmi"
|
||||
FIREFOX_EXT_ID="bridgeswarm[email protected]"
|
||||
# Must match extension/manifest.json "key" / gecko.id and com.bridgeswarm.json
|
||||
# (unique to BridgeSwarm — do not share with holesail-browser)
|
||||
CHROME_EXT_ID="jhmbaojjfkkpoolhkoohklbjokdmbdpm"
|
||||
FIREFOX_EXT_ID="[email protected]"
|
||||
|
||||
# ── Detect platform ────────────────────────────────────────────────────────────
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
+39
-12
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Pack the browser extension into a zip (and .xpi) for distribution.
|
||||
* Pack the browser extension into a zip (Chrome) and .xpi (Firefox).
|
||||
* Zip contains manifest.json (Chrome, with "key").
|
||||
* XPI contains manifest_firefox.json as manifest.json (no "key").
|
||||
* Output: releases/BridgeSwarm-<version>.zip, releases/BridgeSwarm-<version>.xpi
|
||||
* Excludes: protomux-entry.cjs, *.map
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -13,10 +14,8 @@ const REPO_ROOT = path.resolve(__dirname, '..');
|
||||
const EXT_DIR = path.join(REPO_ROOT, 'extension');
|
||||
const RELEASES_DIR = path.join(REPO_ROOT, 'releases');
|
||||
|
||||
const EXCLUDE = new Set([
|
||||
'protomux-entry.cjs',
|
||||
'.map'
|
||||
]);
|
||||
const EXCLUDE_NAMES = new Set(['protomux-entry.cjs']);
|
||||
const EXCLUDE_EXTS = new Set(['.map']);
|
||||
|
||||
function getVersion() {
|
||||
const manifestPath = path.join(EXT_DIR, 'manifest.json');
|
||||
@@ -34,8 +33,9 @@ function listExtensionFiles(dir, base = dir) {
|
||||
if (e.isDirectory()) {
|
||||
files.push(...listExtensionFiles(full, base));
|
||||
} else {
|
||||
const skip = EXCLUDE.has(e.name) || [...EXCLUDE].some(x => x.startsWith('.') && rel.endsWith(x));
|
||||
if (!skip) files.push({ full, rel });
|
||||
const ext = path.extname(e.name);
|
||||
if (EXCLUDE_NAMES.has(e.name) || EXCLUDE_EXTS.has(ext)) continue;
|
||||
files.push({ full, rel });
|
||||
}
|
||||
}
|
||||
return files;
|
||||
@@ -51,7 +51,7 @@ function createZip(version) {
|
||||
archive.on('error', reject);
|
||||
archive.pipe(output);
|
||||
|
||||
const files = listExtensionFiles(EXT_DIR);
|
||||
const files = listExtensionFiles(EXT_DIR).filter(({ rel }) => rel !== 'manifest_firefox.json');
|
||||
for (const { full, rel } of files) {
|
||||
archive.file(full, { name: rel });
|
||||
}
|
||||
@@ -59,6 +59,32 @@ function createZip(version) {
|
||||
});
|
||||
}
|
||||
|
||||
function createXpi(version) {
|
||||
const firefoxManifestPath = path.join(EXT_DIR, 'manifest_firefox.json');
|
||||
if (!fs.existsSync(firefoxManifestPath)) {
|
||||
throw new Error('extension/manifest_firefox.json missing — run scripts/generate-extension-id.js');
|
||||
}
|
||||
|
||||
const xpiPath = path.join(RELEASES_DIR, `BridgeSwarm-${version}.xpi`);
|
||||
const output = fs.createWriteStream(xpiPath);
|
||||
const archive = archiver('zip', { zlib: { level: 9 } });
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
output.on('close', () => resolve(xpiPath));
|
||||
archive.on('error', reject);
|
||||
archive.pipe(output);
|
||||
|
||||
const files = listExtensionFiles(EXT_DIR).filter(
|
||||
({ rel }) => rel !== 'manifest.json' && rel !== 'manifest_firefox.json'
|
||||
);
|
||||
for (const { full, rel } of files) {
|
||||
archive.file(full, { name: rel });
|
||||
}
|
||||
archive.file(firefoxManifestPath, { name: 'manifest.json' });
|
||||
archive.finalize();
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const version = getVersion();
|
||||
console.log('BridgeSwarm version from manifest:', version);
|
||||
@@ -71,12 +97,13 @@ async function main() {
|
||||
console.log('Created releases/');
|
||||
}
|
||||
|
||||
console.log('Creating zip...');
|
||||
try {
|
||||
console.log('Creating Chrome zip...');
|
||||
const zipPath = await createZip(version);
|
||||
console.log('Written:', zipPath);
|
||||
const xpiPath = path.join(RELEASES_DIR, `BridgeSwarm-${version}.xpi`);
|
||||
fs.copyFileSync(zipPath, xpiPath);
|
||||
|
||||
console.log('Creating Firefox xpi...');
|
||||
const xpiPath = await createXpi(version);
|
||||
console.log('Written:', xpiPath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
# Update native host manifest with your Chrome extension ID (fix "Access forbidden").
|
||||
# Usage: .\scripts\update-native-manifest-extension-id.ps1 YOUR_EXTENSION_ID
|
||||
param([Parameter(Mandatory=$true)] [string] $ExtensionId)
|
||||
# Optionally pass a Firefox extension ID as the second argument.
|
||||
# Usage:
|
||||
# .\scripts\update-native-manifest-extension-id.ps1 CHROME_EXT_ID
|
||||
# .\scripts\update-native-manifest-extension-id.ps1 CHROME_EXT_ID FIREFOX_EXT_ID
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$ExtensionId,
|
||||
[Parameter(Mandatory = $false)][string]$FirefoxExtensionId
|
||||
)
|
||||
|
||||
$ExtensionId = $ExtensionId -replace '^chrome-extension://', '' -replace '/$', ''
|
||||
$Origin = "chrome-extension://$ExtensionId/"
|
||||
$manifestFile = (Get-ItemProperty -Path "HKCU:\Software\Google\Chrome\NativeMessagingHosts\com.bridgeswarm" -ErrorAction SilentlyContinue).'(Default)'
|
||||
if (-not $manifestFile -or -not (Test-Path $manifestFile)) { Write-Host "Run scripts/install.ps1 first."; exit 1 }
|
||||
$m = Get-Content $manifestFile -Raw | ConvertFrom-Json
|
||||
$m.allowed_origins = @($Origin)
|
||||
$m | ConvertTo-Json -Depth 4 | Set-Content $manifestFile -Encoding UTF8
|
||||
Write-Host "Updated $manifestFile. Restart Chrome."
|
||||
$updated = $false
|
||||
|
||||
$chromeKey = "HKCU:\Software\Google\Chrome\NativeMessagingHosts\com.bridgeswarm"
|
||||
$manifestFile = (Get-ItemProperty -Path $chromeKey -ErrorAction SilentlyContinue).'(Default)'
|
||||
if ($manifestFile -and (Test-Path $manifestFile)) {
|
||||
$m = Get-Content $manifestFile -Raw | ConvertFrom-Json
|
||||
$m.allowed_origins = @($Origin)
|
||||
$m | ConvertTo-Json -Depth 4 | Set-Content $manifestFile -Encoding UTF8
|
||||
Write-Host "Updated $manifestFile (allowed_origins)"
|
||||
$updated = $true
|
||||
}
|
||||
|
||||
if ($FirefoxExtensionId) {
|
||||
$ffKey = "HKCU:\Software\Mozilla\NativeMessagingHosts\com.bridgeswarm"
|
||||
$ffManifest = (Get-ItemProperty -Path $ffKey -ErrorAction SilentlyContinue).'(Default)'
|
||||
if ($ffManifest -and (Test-Path $ffManifest)) {
|
||||
$m = Get-Content $ffManifest -Raw | ConvertFrom-Json
|
||||
$m.allowed_extensions = @($FirefoxExtensionId)
|
||||
$m | ConvertTo-Json -Depth 4 | Set-Content $ffManifest -Encoding UTF8
|
||||
Write-Host "Updated $ffManifest (allowed_extensions)"
|
||||
$updated = $true
|
||||
} else {
|
||||
Write-Host "Note: Firefox manifest not found — skipping Firefox update"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $updated) {
|
||||
Write-Host "No manifest found. Run scripts/install.ps1 first."
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Done. Restart your browser."
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update native host manifest with your Chrome extension ID (fix "Access forbidden").
|
||||
# Usage: ./scripts/update-native-manifest-extension-id.sh YOUR_EXTENSION_ID
|
||||
# Also accepts a Firefox extension ID as a second argument to update allowed_extensions.
|
||||
# Usage: ./scripts/update-native-manifest-extension-id.sh CHROME_EXT_ID [FIREFOX_EXT_ID]
|
||||
set -e
|
||||
[[ -z "$1" ]] && echo "Usage: $0 YOUR_CHROME_EXTENSION_ID (from chrome://extensions)" && exit 1
|
||||
[[ -z "$1" ]] && echo "Usage: $0 CHROME_EXT_ID [FIREFOX_EXT_ID]" && exit 1
|
||||
EXT_ID="${1#chrome-extension://}"; EXT_ID="${EXT_ID%/}"
|
||||
ORIGIN="chrome-extension://${EXT_ID}/"
|
||||
CHROME_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
|
||||
CHROMIUM_DIR="$HOME/.config/chromium/NativeMessagingHosts"
|
||||
[[ "$OSTYPE" == "darwin"* ]] && CHROME_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts" && CHROMIUM_DIR="$HOME/Library/Application Support/Chromium/NativeMessagingHosts"
|
||||
FIREFOX_EXT_ID="${2:-}"
|
||||
|
||||
MANIFEST_NAME="com.bridgeswarm"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
CHROME_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
||||
CHROMIUM_DIR="$HOME/Library/Application Support/Chromium/NativeMessagingHosts"
|
||||
FIREFOX_DIR="$HOME/Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||
else
|
||||
CHROME_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
|
||||
CHROMIUM_DIR="$HOME/.config/chromium/NativeMessagingHosts"
|
||||
FIREFOX_DIR="$HOME/.mozilla/native-messaging-hosts"
|
||||
fi
|
||||
|
||||
updated=0
|
||||
|
||||
for dir in "$CHROME_DIR" "$CHROMIUM_DIR"; do
|
||||
f="$dir/${MANIFEST_NAME}.json"
|
||||
[[ ! -f "$f" ]] && continue
|
||||
@@ -18,8 +30,24 @@ for dir in "$CHROME_DIR" "$CHROMIUM_DIR"; do
|
||||
else
|
||||
sed -i.bak "s|\"chrome-extension://[^\"]*/\"|\"$ORIGIN\"|g" "$f" && rm -f "${f}.bak"
|
||||
fi
|
||||
echo "Updated $f"
|
||||
echo "Updated $f (allowed_origins)"
|
||||
updated=1
|
||||
done
|
||||
|
||||
if [[ -n "$FIREFOX_EXT_ID" ]]; then
|
||||
f="$FIREFOX_DIR/${MANIFEST_NAME}.json"
|
||||
if [[ -f "$f" ]]; then
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
node -e "const fs=require('fs');const j=JSON.parse(fs.readFileSync('$f','utf8'));j.allowed_extensions=['$FIREFOX_EXT_ID'];fs.writeFileSync('$f',JSON.stringify(j,null,2));"
|
||||
else
|
||||
sed -i.bak "s|\"bridgeswarm[^\"]*@[^\"]*\"|\"$FIREFOX_EXT_ID\"|g" "$f" && rm -f "${f}.bak"
|
||||
fi
|
||||
echo "Updated $f (allowed_extensions)"
|
||||
updated=1
|
||||
else
|
||||
echo "Note: Firefox manifest not found at $f — skipping Firefox update"
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ $updated -eq 0 ]] && echo "No manifest found. Run scripts/install.sh first." && exit 1
|
||||
echo "Done. Restart Chrome."
|
||||
echo "Done. Restart your browser."
|
||||
|
||||
Reference in New Issue
Block a user