From 624b69c85a163cf7af283d732989c063d13ccfa1 Mon Sep 17 00:00:00 2001 From: signalhub Date: Sun, 5 May 2024 15:55:36 +0300 Subject: [PATCH] Add server side generation to publish --- .gitignore | 3 +- nx.json | 2 +- package.json | 3 +- project.json | 2 +- src/utils/generate-key.js | 67 +++++++++++++++++++++++++++++++++++++++ src/utils/generateKey.js | 21 ------------ 6 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 src/utils/generate-key.js delete mode 100644 src/utils/generateKey.js diff --git a/.gitignore b/.gitignore index 98a6e38..89cda51 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ testem.log .DS_Store Thumbs.db -.nx/cache \ No newline at end of file +.nx/cache +/src/.env diff --git a/nx.json b/nx.json index e075476..1643ec6 100644 --- a/nx.json +++ b/nx.json @@ -18,7 +18,7 @@ "inputs": ["production", "^production"] }, "@nx/vite:test": { - "cache": true, + "cache": false, "inputs": ["default", "^production"] } }, diff --git a/package.json b/package.json index 4ecca5c..dd5ac49 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "license": "MIT", "scripts": { "build": "nx build", - "test": "nx test" + "test": "nx test", + "generate-key": "cd src/utils && node generate-key.js --secret \"my-secret-key\" --output \"/Users/anton.zaloev/projects/signalhub/tokenized-auth/src/.env\"" }, "dependencies": { "tslib": "^2.3.0" diff --git a/project.json b/project.json index 94907e6..8eb4571 100644 --- a/project.json +++ b/project.json @@ -14,7 +14,7 @@ "outputPath": "dist/tokenized-auth", "main": "./src/index.ts", "tsConfig": "./tsconfig.lib.json", - "assets": ["*.md"] + "assets": ["*.md", "src/utils/generate-key.js"] } }, "lint": { diff --git a/src/utils/generate-key.js b/src/utils/generate-key.js new file mode 100644 index 0000000..f36309b --- /dev/null +++ b/src/utils/generate-key.js @@ -0,0 +1,67 @@ +const crypto = require('crypto').webcrypto; +const fs = require('fs'); +const path = require('path'); + +const generateEncryptionSecretKey = async (secret, salt) => { + const encoder = new TextEncoder(); + const secretKey = await crypto.subtle.importKey( + 'raw', + encoder.encode(secret), + { name: 'PBKDF2' }, + false, + ['deriveKey'] + ); + + return await crypto.subtle.deriveKey( + { + name: 'PBKDF2', + salt: salt, + iterations: 100000, + hash: 'SHA-256', + }, + secretKey, + { name: 'AES-GCM', length: 256 }, + true, + ['encrypt', 'decrypt'] + ); +}; + +const encryptSecretKey = async (secret, salt) => { + const key = await generateEncryptionSecretKey(secret, salt); + const exportedKey = await crypto.subtle.exportKey('raw', key); + const exportedKeyBuffer = Buffer.from(exportedKey); + return exportedKeyBuffer.toString('base64'); +}; + +const generateEnvFile = async (secret, envFilePath) => { + const salt = crypto.getRandomValues(new Uint8Array(16)); + + const encryptionKey = await encryptSecretKey(secret, salt); + + const envContent = `ENCRYPTION_KEY=${encryptionKey}\n`; + + fs.writeFileSync(envFilePath, envContent); + console.log(`Encryption key generated and saved to ${envFilePath}.`); +}; + +const getArgFromArgs = (argName) => { + const argIndex = process.argv.indexOf(argName); + if (argIndex !== -1 && argIndex + 1 < process.argv.length) { + return process.argv[argIndex + 1]; + } + return null; +}; + +const secret = getArgFromArgs('--secret'); +const envFilePath = getArgFromArgs('--output') || '.env'; + +if (secret) { + generateEnvFile(secret, path.resolve(envFilePath)).then(); +} else { + console.error('Please provide a secret key using the --secret argument.'); + process.exit(1); +} + +module.exports = { + generateEnvFile, +}; \ No newline at end of file diff --git a/src/utils/generateKey.js b/src/utils/generateKey.js deleted file mode 100644 index 9bbf3c3..0000000 --- a/src/utils/generateKey.js +++ /dev/null @@ -1,21 +0,0 @@ -const fs = require('fs'); -const crypto = require('crypto').webcrypto; - -async function generateEncryptionKey() { - const key = await crypto.subtle.generateKey( - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - const exportedKey = await crypto.subtle.exportKey('raw', key); - const exportedKeyBuffer = Buffer.from(exportedKey); - return exportedKeyBuffer.toString('base64'); -} - -async function generateEnv() { - const secretKey = await generateEncryptionKey(); - const envContent = `\nENCRYPTION_KEY=${secretKey}\n`; - fs.appendFileSync('.env', envContent); -} - -generateEnv().then(); \ No newline at end of file