Files
drop/server/internal/clients/ca.ts
DecDuck 251ddb8ff8 Rearchitecture for v0.4.0 (#197)
* feat: database redist support

* feat: rearchitecture of database schemas, migration reset, and #180

* feat: import redists

* fix: giantbomb logging bug

* feat: partial user platform support + statusMessage -> message

* feat: add user platform filters to store view

* fix: sanitize svg uploads

... copilot suggested this

I feel dirty.

* feat: beginnings of platform & redist management

* feat: add server side redist patching

* fix: update drop-base commit

* feat: import of custom platforms & file extensions

* fix: redelete platform

* fix: remove platform

* feat: uninstall commands, new R UI

* checkpoint: before migrating to nuxt v4

* update to nuxt 4

* fix: fixes for Nuxt v4 update

* fix: remaining type issues

* feat: initial feedback to import other kinds of versions

* working commit

* fix: lint

* feat: redist import
2025-11-10 10:36:13 +11:00

75 lines
2.1 KiB
TypeScript

import droplet from "@drop-oss/droplet";
import type { CertificateStore } from "./ca-store";
export type CertificateBundle = {
priv: string;
cert: string;
};
/*
This is designed to handle client certificates, as described in the README.md
*/
export class CertificateAuthority {
private certificateStore: CertificateStore;
private root: CertificateBundle;
constructor(store: CertificateStore, root: CertificateBundle) {
this.certificateStore = store;
this.root = root;
}
static async new(store: CertificateStore) {
const root = await store.fetch("ca");
let ca;
if (root === undefined) {
const [cert, priv] = droplet.generateRootCa();
const bundle: CertificateBundle = { priv: priv!, cert: cert! };
await store.store("ca", bundle);
ca = new CertificateAuthority(store, bundle);
} else {
ca = new CertificateAuthority(store, root);
}
const serverCertificate = await ca.fetchClientCertificate("server");
if (!serverCertificate) {
await ca.generateClientCertificate("server", "Drop Server");
}
return ca;
}
async generateClientCertificate(clientId: string, clientName: string) {
const caCertificate = await this.certificateStore.fetch("ca");
if (!caCertificate)
throw new Error("Certificate authority not initialised");
const [cert, priv] = droplet.generateClientCertificate(
clientId,
clientName,
caCertificate.cert,
caCertificate.priv,
);
const certBundle: CertificateBundle = {
priv: priv!,
cert: cert!,
};
return certBundle;
}
async storeClientCertificate(clientId: string, bundle: CertificateBundle) {
await this.certificateStore.store(`client:${clientId}`, bundle);
}
async fetchClientCertificate(clientId: string) {
const isBlacklist = await this.certificateStore.checkBlacklistCertificate(
`client:${clientId}`,
);
if (isBlacklist) return undefined;
return await this.certificateStore.fetch(`client:${clientId}`);
}
async blacklistClient(clientId: string) {
await this.certificateStore.blacklistCertificate(`client:${clientId}`);
}
}