Support uploading config files. #14

Merged
telackey merged 5 commits from telackey/configupload into main 2024-08-27 19:44:53 +00:00
Showing only changes of commit 2cce37ef1f - Show all commits

90
src/upload.ts Normal file
View File

@ -0,0 +1,90 @@
import crypto from 'crypto';
import fs from 'fs';
import assert from 'node:assert';
import openpgp from 'openpgp';
import YAML from 'yaml';
import { atob } from 'node:buffer';
import { Config } from './config.js';
let privateKey: openpgp.PrivateKey | null = null;
const loadPrivateKey = async () => {
if (null == privateKey) {
privateKey = await openpgp.decryptKey({
privateKey: await openpgp.readPrivateKey({
binaryKey: fs.readFileSync(Config.OPENPGP_PRIVATE_KEY_FILE)
}),
passphrase: Config.OPENPGP_PASSPHRASE,
});
}
return privateKey;
}
const randomId = (): string =>
crypto
.randomUUID({ disableEntropyCache: true })
.replaceAll('-', '')
.toUpperCase();
const validateConfig = (obj): undefined => {
assert(obj.authorized, "'authorized' is required");
assert(Array.isArray(obj.authorized), "'authorized' must be an array");
assert(obj.authorized.length >= 1, "'authorized' cannot be empty");
assert(obj.config, "'config' is required");
};
export const b64ToBytes = (base64): Uint8Array => {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
};
const decrypt = async (binaryMessage: Uint8Array): Promise<any> => {
const message = await openpgp.readMessage({
binaryMessage,
});
const { data } = await openpgp.decrypt({
message,
decryptionKeys: await loadPrivateKey(),
});
const config = data.toString();
return config.charAt(0) === '{' ? JSON.parse(config) : YAML.parse(config);
};
export class Uploader {
directory: string;
constructor(dir: string) {
this.directory = dir;
}
async upload(body: string | Uint8Array): Promise<string> {
let raw: any;
try {
raw = b64ToBytes(body);
} catch {
raw = body;
}
const obj = await decrypt(raw);
validateConfig(obj);
let id = randomId();
let destination: string;
do {
id = randomId();
destination = `${this.directory}/${id}`;
} while (fs.existsSync(destination));
fs.writeFileSync(destination, raw);
return id;
}
}