@authduo/authduo
Version:
Free User-sovereign Authentication for the World
81 lines • 2.85 kB
JavaScript
import { Base64, Text } from "@benev/slate";
import { Passport } from "./passport.js";
import { ensure } from "./utils/ensure.js";
import { crushUsername } from "./utils/crush-username.js";
export class PassportsFile {
static format = "authduo.org passports";
static extension = "passport";
static version = 3;
static #ingestData(raw) {
let data = null;
if (!("format" in raw) ||
!("version" in raw) ||
raw.format !== PassportsFile.format)
throw new Error(`invalid format`);
switch (raw.version) {
case 0:
case 1:
case 2: throw new Error(`invalid version ${raw.version}`);
case 3: data = raw;
}
if (!data)
throw new Error(`unknown version ${raw.version}`);
return {
format: ensure.string("format", data.format),
version: ensure.number("version", data.version),
passports: ensure.array("array", data.passports.map((p) => ({
name: ensure.string("name", p.name),
created: ensure.number("created", p.created),
keypair: {
thumbprint: ensure.string("thumbprint", p.keypair.thumbprint),
publicKey: ensure.string("public", p.keypair.publicKey),
privateKey: ensure.string("private", p.keypair.privateKey),
},
})))
};
}
static fromData(raw) {
const data = PassportsFile.#ingestData(raw);
const passports = new this();
passports.add(...data.passports.map(d => Passport.fromData(d)));
return passports;
}
#map = new Map();
list() {
return [...this.#map.values()];
}
add(...additions) {
for (const passport of additions)
this.#map.set(passport.thumbprint, passport);
return this;
}
delete(...deletions) {
for (const passport of deletions)
this.#map.delete(passport.thumbprint);
return this;
}
deleteAll() {
this.#map.clear();
return this;
}
toData() {
return {
format: PassportsFile.format,
version: PassportsFile.version,
passports: [...this.#map.values()]
.map(passport => passport.toData()),
};
}
filename() {
const passports = this.list();
return passports.length === 1
? `${crushUsername(passports.at(0).name)}.${PassportsFile.extension}`
: `passports.${PassportsFile.extension}`;
}
href() {
const text = JSON.stringify(this.toData(), undefined, "\t");
const encoded = Base64.string(Text.bytes(text));
return `data:application/octet-stream;base64,${encoded}`;
}
}
//# sourceMappingURL=passports-file.js.map