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
22 changes: 22 additions & 0 deletions extension/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ Only add a copy of a library here if it's not published as a npm module.

Both `forge.js` and `forge.mjs` need to be rebuilt when updating node-forge to a new version.

### Automated Method (Recommended)

Use the automated update script:

```bash
npm run update-forge -- v1.3.3
```

This script will automatically:
1. Clone the forge repository at the specified version
2. Modify webpack.config.js to add source maps
3. Build forge.js with source maps
4. Convert forge.js to forge.mjs
5. Copy both files to `extension/lib/`
6. Clean up temporary files

The version can be specified with or without the 'v' prefix (e.g., `v1.3.3` or `1.3.3`).

### Manual Method

If you prefer to update manually, follow these steps:

### 1) Clone the forge repository at the desired version

```bash
Expand Down
1 change: 1 addition & 0 deletions extension/lib/forge.js
Original file line number Diff line number Diff line change
Expand Up @@ -10749,6 +10749,7 @@ var pfxValidator = {
capture: 'macAlgorithm'
}, {
name: 'PFX.macData.mac.digestAlgorithm.parameters',
optional: true,
tagClass: asn1.Class.UNIVERSAL,
captureAsn1: 'macAlgorithmParameters'
}]
Expand Down
1 change: 1 addition & 0 deletions extension/lib/forge.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10743,6 +10743,7 @@ var pfxValidator = {
capture: 'macAlgorithm'
}, {
name: 'PFX.macData.mac.digestAlgorithm.parameters',
optional: true,
tagClass: asn1.Class.UNIVERSAL,
captureAsn1: 'macAlgorithmParameters'
}]
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"run_firefox": "npm run build-incremental && npx web-ext run --source-dir ./build/firefox-consumer/ --firefox-profile ~/.mozilla/firefox/flowcrypt-dev --keep-profile-changes",
"run_firefox_windows": "npm run build-incremental && npx web-ext run --source-dir ./build/firefox-consumer/ --firefox-profile %userprofile%/AppData/Local/Mozilla/Firefox/Profiles/flowcrypt-dev --keep-profile-changes",
"find_unused": "ts-prune -p tsconfig.json | grep -v extension/types | grep -v extension/js/common/core",
"update-forge": "node ./scripts/update-forge.js",
"release-step-1": "npm run build && ./tooling/release-step-1-pack-and-sign",
"release-step-2": "./tooling/release-step-2-upload",
"prepare": "husky"
Expand Down
191 changes: 191 additions & 0 deletions scripts/update-forge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */

const fs = require('fs-extra');
const path = require('path');
const { execSync, execFileSync } = require('child_process');

const FORGE_REPO_URL = 'https://github.com/digitalbazaar/forge';
const TEMP_DIR = path.join(__dirname, '../.tmp-forge-build');
const EXTENSION_LIB_DIR = path.join(__dirname, '../extension/lib');

const updateForge = async (version) => {
if (!version) {
console.error('Error: Version parameter is required');
console.error('Usage: npm run update-forge -- v1.3.3');
process.exit(1);
}

// Ensure version starts with 'v'
if (!version.startsWith('v')) {
version = 'v' + version;
}

console.log(`Starting Forge update process for version ${version}...`);

try {
// Clean up any existing temp directory
await fs.remove(TEMP_DIR);

// Step 1: Clone the forge repository at the desired version
console.log('\n1. Cloning forge repository...');
execFileSync('git', ['clone', '-b', version, FORGE_REPO_URL, TEMP_DIR], { stdio: 'inherit' });

// Step 2: Install dependencies
console.log('\n2. Installing dependencies...');
execSync('npm install', { cwd: TEMP_DIR, stdio: 'inherit' });

// Step 3: Modify webpack.config.js to add source maps
console.log('\n3. Modifying webpack.config.js to add source maps...');
const webpackConfigPath = path.join(TEMP_DIR, 'webpack.config.js');
let webpackConfig = fs.readFileSync(webpackConfigPath, 'utf8');

// According to the readme, we need to add devtool to the plain unoptimized bundle
// This is the bundle object created around line 78
// Look for "// plain unoptimized unminified bundle" comment and the bundle object after it

const bundlePattern = /(\/\/ plain unoptimized unminified bundle\s*\n\s*const bundle = Object\.assign\(\{}, common, \{[\s\S]*?\n\s*}\);)/;
const match = webpackConfig.match(bundlePattern);

if (match) {
const bundleBlock = match[1];

// Check if devtool already exists in this bundle configuration
if (!bundleBlock.includes('devtool:')) {
// Find the right place to insert devtool (after mode: 'development')
const modifiedBundle = bundleBlock.replace(
/(mode:\s*'development',)/,
"$1\n devtool: 'cheap-module-source-map',"
);

webpackConfig = webpackConfig.replace(bundleBlock, modifiedBundle);
await fs.writeFile(webpackConfigPath, webpackConfig, 'utf8');
console.log(' Added source map configuration to webpack.config.js');
} else {
console.log(' Source map configuration already present');
}
} else {
console.warn(' Warning: Could not find the bundle configuration in webpack.config.js');
console.warn(' The webpack.config.js structure may have changed');
console.warn(' You may need to manually add devtool: \'cheap-module-source-map\' to the plain unoptimized bundle configuration');
}

// Step 4: Build forge.js
console.log('\n4. Building forge.js...');
execSync('npm run build', { cwd: TEMP_DIR, stdio: 'inherit' });

// Step 5: Create conversion script for forge.mjs
console.log('\n5. Creating conversion script for forge.mjs...');
const conversionScriptPath = path.join(TEMP_DIR, 'convert-forge-to-mjs.js');
const conversionScript = `const fs = require('fs');
const path = require('path');

const sourceFile = path.join(__dirname, 'dist', 'forge.js');
const targetFile = path.join(__dirname, 'dist', 'forge.mjs');

console.log('Reading forge.js...');
let content = fs.readFileSync(sourceFile, 'utf8');

// Split content into lines
const lines = content.split('\\n');

// Find where the webpack bundle starts
// It starts with the webpack bootstrap function
let startLine = lines.findIndex(line => line.includes('/******/ (function(modules) { // webpackBootstrap'));

if (startLine === -1) {
throw new Error('Could not find webpack bundle start');
}

// Find the end - the webpack bundle ends with "/******/ });"
// This closes the modules object passed to the bootstrap function
let endLine = -1;
for (let i = lines.length - 1; i >= 0; i--) {
if (lines[i].trim() === '/******/ });') {
endLine = i + 1; // Include this line
break;
}
}

if (endLine === -1) {
throw new Error('Could not find bundle end');
}

console.log(\`Extracting lines \${startLine} to \${endLine}\`);

// Extract just the webpack bundle
const bundleLines = lines.slice(startLine, endLine);

// Remove 'return ' from the first line if present (from UMD wrapper)
// The line looks like: return /******/ (function(modules) { // webpackBootstrap
bundleLines[0] = bundleLines[0].replace(/^\\s*return\\s+/, '');

// Prepend 'var forge = ' to capture the return value
bundleLines[0] = 'var forge = ' + bundleLines[0];

const bundle = bundleLines.join('\\n');

// Create ES module wrapper
const esModule = \`const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

\${bundle}

var lib = forge;

export { lib as default };
\`;

console.log('Writing forge.mjs...');
fs.writeFileSync(targetFile, esModule, 'utf8');
console.log('forge.mjs generated successfully!');
`;

await fs.writeFile(conversionScriptPath, conversionScript, 'utf8');

// Step 6: Run the conversion script
console.log('\n6. Converting forge.js to forge.mjs...');
execSync('node convert-forge-to-mjs.js', { cwd: TEMP_DIR, stdio: 'inherit' });

// Step 7: Copy files to extension/lib
console.log('\n7. Copying files to extension/lib...');

// Ensure the destination directory exists
await fs.ensureDir(EXTENSION_LIB_DIR);

// Copy forge.js
const sourceForgeJs = path.join(TEMP_DIR, 'dist', 'forge.js');
const destForgeJs = path.join(EXTENSION_LIB_DIR, 'forge.js');
await fs.copy(sourceForgeJs, destForgeJs);
console.log(` Copied forge.js to ${destForgeJs}`);

// Copy forge.mjs
const sourceForgeMjs = path.join(TEMP_DIR, 'dist', 'forge.mjs');
const destForgeMjs = path.join(EXTENSION_LIB_DIR, 'forge.mjs');
await fs.copy(sourceForgeMjs, destForgeMjs);
console.log(` Copied forge.mjs to ${destForgeMjs}`);

// Step 8: Clean up
console.log('\n8. Cleaning up temporary files...');
await fs.remove(TEMP_DIR);

console.log(`\n✅ Successfully updated Forge to version ${version}!`);
console.log('Files have been copied to extension/lib/');

} catch (error) {
console.error('\n❌ Error during Forge update:', error.message);

// Clean up on error
try {
await fs.remove(TEMP_DIR);
} catch {
// Ignore cleanup errors
}

process.exit(1);
}
}

// Get version from command line arguments
const version = process.argv[2];
void updateForge(version);
Loading