dev/2026-04-08 #1
73
src/auth.ts
Normal file
73
src/auth.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import type { AuthRequestPayload } from "./types.js";
|
||||||
|
|
||||||
|
export const AUTH_NONCE_LENGTH = 24;
|
||||||
|
export const AUTH_MAX_TIMESTAMP_DRIFT_SECONDS = 10;
|
||||||
|
export const AUTH_MAX_ATTEMPTS_PER_WINDOW = 10;
|
||||||
|
export const AUTH_ATTEMPT_WINDOW_SECONDS = 10;
|
||||||
|
export const AUTH_RECENT_NONCE_WINDOW_SIZE = 10;
|
||||||
|
|
||||||
|
export interface AuthProofMaterial {
|
||||||
|
secret: string;
|
||||||
|
nonce: string;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAuthProofMaterial(input: AuthProofMaterial): AuthProofMaterial {
|
||||||
|
return {
|
||||||
|
secret: input.secret,
|
||||||
|
nonce: input.nonce,
|
||||||
|
timestamp: input.timestamp
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializeAuthProofMaterial(input: AuthProofMaterial): string {
|
||||||
|
const material = createAuthProofMaterial(input);
|
||||||
|
return JSON.stringify({
|
||||||
|
secret: material.secret,
|
||||||
|
nonce: material.nonce,
|
||||||
|
timestamp: material.timestamp
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidAuthNonce(nonce: string): boolean {
|
||||||
|
return /^[A-Za-z0-9_-]{24}$/.test(nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTimestampFresh(
|
||||||
|
proofTimestamp: number,
|
||||||
|
now: number,
|
||||||
|
maxDriftSeconds: number = AUTH_MAX_TIMESTAMP_DRIFT_SECONDS
|
||||||
|
): { ok: true } | { ok: false; reason: "stale_timestamp" | "future_timestamp" } {
|
||||||
|
const drift = proofTimestamp - now;
|
||||||
|
if (Math.abs(drift) < maxDriftSeconds) {
|
||||||
|
return { ok: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
reason: drift < 0 ? "stale_timestamp" : "future_timestamp"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAuthRequestSigningInput(input: {
|
||||||
|
secret: string;
|
||||||
|
nonce: string;
|
||||||
|
proofTimestamp: number;
|
||||||
|
}): string {
|
||||||
|
return serializeAuthProofMaterial({
|
||||||
|
secret: input.secret,
|
||||||
|
nonce: input.nonce,
|
||||||
|
timestamp: input.proofTimestamp
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractAuthRequestSigningInput(
|
||||||
|
payload: Pick<AuthRequestPayload, "nonce" | "proofTimestamp">,
|
||||||
|
secret: string
|
||||||
|
): string {
|
||||||
|
return createAuthRequestSigningInput({
|
||||||
|
secret,
|
||||||
|
nonce: payload.nonce,
|
||||||
|
proofTimestamp: payload.proofTimestamp
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
export * from "./codec.js";
|
export * from "./codec.js";
|
||||||
export * from "./errors.js";
|
export * from "./errors.js";
|
||||||
|
export * from "./auth.js";
|
||||||
|
|||||||
Reference in New Issue
Block a user