Support uploading config files. #14
90
src/upload.ts
Normal file
90
src/upload.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user