feat(authz): add email-authorized GHDR dual signing
This commit is contained in:
parent
84f7c4c198
commit
bec7a3d7a0
10 changed files with 771 additions and 5 deletions
75
server-tools/lake-lamp-authz/ghdr-authorizer.js
Normal file
75
server-tools/lake-lamp-authz/ghdr-authorizer.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
"use strict";
|
||||
|
||||
const crypto = require("node:crypto");
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
class GhdrAuthorizer {
|
||||
constructor({
|
||||
privateKeyFile = "/var/lib/guanghu/lake-lamp-authz/ghdr-authorizer-private.pem",
|
||||
now = () => Math.floor(Date.now() / 1000),
|
||||
} = {}) {
|
||||
this.privateKeyFile = privateKeyFile;
|
||||
this.now = now;
|
||||
this.privateKey = this.loadOrCreate();
|
||||
this.publicKey = crypto.createPublicKey(this.privateKey);
|
||||
}
|
||||
|
||||
loadOrCreate() {
|
||||
if (fs.existsSync(this.privateKeyFile)) {
|
||||
const metadata = fs.lstatSync(this.privateKeyFile);
|
||||
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.mode & 0o077) {
|
||||
throw new Error("ghdr_authorizer_private_key_permissions_invalid");
|
||||
}
|
||||
return crypto.createPrivateKey(fs.readFileSync(this.privateKeyFile));
|
||||
}
|
||||
fs.mkdirSync(path.dirname(this.privateKeyFile), { recursive: true, mode: 0o700 });
|
||||
const { privateKey } = crypto.generateKeyPairSync("ed25519");
|
||||
const pem = privateKey.export({ type: "pkcs8", format: "pem" });
|
||||
const temporary = `${this.privateKeyFile}.${process.pid}.tmp`;
|
||||
fs.writeFileSync(temporary, pem, { mode: 0o600, flag: "wx" });
|
||||
fs.renameSync(temporary, this.privateKeyFile);
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
publicBinding() {
|
||||
const publicPem = this.publicKey.export({ type: "spki", format: "pem" });
|
||||
const fingerprint = crypto.createHash("sha256").update(publicPem).digest("hex");
|
||||
return {
|
||||
schema: "guanghu.ghdr-authorizer-public-binding/v1",
|
||||
authorizer_id: "JD-FD-PRIMARY-LAKE-LAMP",
|
||||
algorithm: "Ed25519",
|
||||
public_key_pem: publicPem,
|
||||
public_key_sha256: fingerprint,
|
||||
};
|
||||
}
|
||||
|
||||
issue({
|
||||
controllerNodeId,
|
||||
targetNodeId,
|
||||
layoutPayloadSha256,
|
||||
resource,
|
||||
workorderId,
|
||||
}) {
|
||||
const issued = this.now();
|
||||
const capability = {
|
||||
schema: "guanghu.ghdr-signing-capability/v1",
|
||||
authorizer_id: "JD-FD-PRIMARY-LAKE-LAMP",
|
||||
controller_node_id: controllerNodeId,
|
||||
target_node_id: targetNodeId,
|
||||
layout_payload_sha256: layoutPayloadSha256,
|
||||
resource,
|
||||
workorder_id: workorderId,
|
||||
issued_at_unix: issued,
|
||||
expires_at_unix: issued + 120,
|
||||
nonce: crypto.randomBytes(24).toString("base64url"),
|
||||
};
|
||||
const canonical = Buffer.from(JSON.stringify(capability));
|
||||
return {
|
||||
capability,
|
||||
capability_signature_base64url: crypto.sign(null, canonical, this.privateKey).toString("base64url"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { GhdrAuthorizer };
|
||||
Loading…
Reference in a new issue