feat(server): add an embedded ACME directory server and certificate authority with challenge, order, and certificate endpoints
This commit is contained in:
36
ts_server/server.classes.nonce.ts
Normal file
36
ts_server/server.classes.nonce.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as crypto from 'node:crypto';
|
||||
|
||||
/**
|
||||
* Manages ACME replay nonces.
|
||||
* Each nonce is single-use: consumed on verification, fresh one issued with every response.
|
||||
*/
|
||||
export class NonceManager {
|
||||
private nonces = new Set<string>();
|
||||
private nonceQueue: string[] = [];
|
||||
private maxSize: number;
|
||||
|
||||
constructor(maxSize = 10000) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
generate(): string {
|
||||
const nonce = crypto.randomBytes(16).toString('base64url');
|
||||
if (this.nonces.size >= this.maxSize) {
|
||||
const oldest = this.nonceQueue.shift();
|
||||
if (oldest) {
|
||||
this.nonces.delete(oldest);
|
||||
}
|
||||
}
|
||||
this.nonces.add(nonce);
|
||||
this.nonceQueue.push(nonce);
|
||||
return nonce;
|
||||
}
|
||||
|
||||
consume(nonce: string): boolean {
|
||||
if (this.nonces.has(nonce)) {
|
||||
this.nonces.delete(nonce);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user