const crypto = require("crypto"); const fs = require("fs"); const path = require("path"); const keyPath = process.env.NODE_ENV === "development" ? path.resolve(__dirname, `../../../server/storage/comkey`) : path.resolve( process.env.STORAGE_DIR ?? path.resolve(__dirname, `../../../server/storage`), `comkey` ); class CommunicationKey { #pubKeyName = "ipc-pub.pem"; #storageLoc = keyPath; constructor() {} log(text, ...args) { console.log(`\x1b[36m[CommunicationKeyVerify]\x1b[0m ${text}`, ...args); } #readPublicKey() { return fs.readFileSync(path.resolve(this.#storageLoc, this.#pubKeyName)); } // Given a signed payload from private key from /app/server/ this signature should // decode to match the textData provided. This class does verification only in collector. // Note: The textData is typically the JSON stringified body sent to the document processor API. verify(signature = "", textData = "") { try { let data = textData; if (typeof textData !== "string") data = JSON.stringify(data); return crypto.verify( "RSA-SHA256", Buffer.from(data), this.#readPublicKey(), Buffer.from(signature, "hex") ); } catch {} return false; } // Use the rolling public-key to decrypt arbitrary data that was encrypted via the private key on the server side CommunicationKey class // that we know was done with the same key-pair and the given input is in base64 format already. // Returns plaintext string of the data that was encrypted. decrypt(base64String = "") { return crypto .publicDecrypt(this.#readPublicKey(), Buffer.from(base64String, "base64")) .toString(); } } module.exports = { CommunicationKey };