Table of contents
1 項目背景
我地想寫一個可以本地執行既 CLI(command line interface)小工具,要有以下功能:
功能 | 描述 |
---|
加密 | 以用戶提供既密碼,加密一個檔案(任何檔案格式),輸出一個純文字檔案。 |
解密 | 以用戶提供既密碼,解密一個由呢個工具既加密功能得出既純文字檔案,輸出原檔案。 |
而加密、解密功能都會用上 AES——最多人用既 symmetric key algorithm,而 CryptoJS 作為一個熱門既 JavaScript 加密 package 就可以提供到呢一個加密算法。
2 動手寫
2.1 NPM dependencies
package.json
:
1{
2 "name": "aes-encryptor-decryptor",
3 "version": "1.0.0",
4 "private": true,
5 "type": "module",
6 "dependencies": {
7 "crypto-js": "^4.1.1"
8 }
9}
2.2 寫 JavaScript code
2.2.1 通用既 utility
我地會用 AES(symmetric key)黎加密數據,再用 Base64 表達。
utils.js
:
1import CryptoJS from "crypto-js";
2
3const encrypt = (data, secret) => CryptoJS.AES.encrypt(data, secret).toString();
4
5const decrypt = (data, secret) => CryptoJS.AES.decrypt(data, secret).toString(CryptoJS.enc.Utf8);
6
7export default { encrypt, decrypt };
8export { encrypt, decrypt };
2.2.2 加密功能
加密功能需要用戶提供:
- 要加密既檔案既路徑
- 輸出檔案既路徑
- 密碼
enc.js
:
1import { readFile, writeFile } from "fs/promises";
2import { encrypt } from "./utils.js";
3
4const main = async () => {
5 const args = process.argv.slice(2); // 一定係 2
6
7 if (args.length < 3) {
8 console.log(
9 [
10 "Required 3 args:",
11 "",
12 " enc <I> <O> <P>",
13 "",
14 "I: Input file path",
15 "O: Output file path",
16 "P: Password",
17 ].join("\n")
18 );
19 return;
20 }
21
22 const inputFilePath = args.shift();
23 const outputFilePath = args.shift();
24 const secret = args.shift();
25
26 const data = await readFile(inputFilePath, { encoding: "base64" });
27 const encrypted = encrypt(data, secret);
28 await writeFile(outputFilePath, encrypted, { encoding: "utf8" });
29
30 console.log("Done encryption!");
31};
32
33main();
2.2.3 解密功能
解密功能需要用戶提供:
- 已加密既檔案既路徑
- 輸出檔案既路徑
- 密碼
dec.js
:
1import { readFile, writeFile } from "fs/promises";
2import { decrypt } from "./utils.js";
3
4const main = async () => {
5 const args = process.argv.slice(2); // 一定係 2
6
7 if (args.length < 3) {
8 console.log(
9 [
10 "Required 3 args:",
11 "",
12 " dec <I> <O> <P>",
13 "",
14 "I: Input file path",
15 "O: Output file path",
16 "P: Password",
17 ].join("\n")
18 );
19 return;
20 }
21
22 const inputFilePath = args.shift();
23 const outputFilePath = args.shift();
24 const secret = args.shift();
25
26 const data = await readFile(inputFilePath, { encoding: "utf8" });
27 const decrypted = decrypt(data.trim(), secret);
28 await writeFile(outputFilePath, decrypted, { encoding: "base64" });
29
30 console.log("Done decryption!");
31};
32
33main();
3 測試
3.1 測試加密功能
node enc "/path/to/raw.file" "/path/to/encrypted.file" "password"
3.2 測試解密功能
node dec "/path/to/encrypted.file" "/path/to/raw.file" "password"
4 筆記
4.1 用 import
而非 require
引用 modules
require
係 CommonJS 既寫法,可以喺 runtime 根據條件即時 load module;而 import
就係 ECMAScript 既寫法,喺 compile 既時候就會 load,亦冇得根據條件 load 或唔 load module。
NodeJS 默認係用 CommonJS,除非喺 package.json
度配置:
{
"type": "module"
}
4.2 process.argv
頭 2
個 values 係 NodeJS 個 binary 既 file path 以及我地個 JavaScript 程式既 file path,所以要去除頭 2
個 values:
const args = process.argv.slice(2); // 一定係 2
參考資料:
4.3 fs/promises
NodeJS 自帶既 fs
module 提供左讀寫檔案既功能,不過啲 API 就係 async callback 既寫法黎既。
如果我地想得到 Promise
,然後用 await
去令佢返回結果,可以用 NodeJS 自帶既 fs/promises
module。
參考資料:
4.4 將 config 放喺 .env
如果我地想用一個檔案黎 config password,我地可以喺 project root folder 建立一個 .env
檔,然後將 config 寫落去。不過我地需要安裝 NPM library dotenv
先可以將 .env
檔裡面既 key-value pairs 讀入 process.env
,然後喺 JavaScript code 裡面使用。
.env
:
password=1234
為 project 添加 dependency:
npm i dotenv
喺 JavaScript code 度讀取 .env
既 config:
import dotenv from "dotenv";
dotenv.config();
console.log(process.env.password); // 1234
參考資料: