feat(pairing): add PairingStore interface for persistence injection
This commit is contained in:
+25
-5
@@ -14,7 +14,7 @@ interface PendingCode {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
interface ApprovedSender {
|
||||
export interface ApprovedSender {
|
||||
channel: string;
|
||||
senderId: string;
|
||||
approvedAt: number;
|
||||
@@ -22,6 +22,12 @@ interface ApprovedSender {
|
||||
codeUsed: string;
|
||||
}
|
||||
|
||||
export interface PairingStore {
|
||||
loadApproved(): ApprovedSender[];
|
||||
saveApproved(sender: ApprovedSender): void;
|
||||
removeApproved(channel: string, senderId: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages DM pairing codes for authenticating unknown senders.
|
||||
*
|
||||
@@ -35,9 +41,17 @@ export class PairingManager {
|
||||
private config: PairingConfig;
|
||||
private pendingCodes: Map<string, PendingCode> = new Map();
|
||||
private approvedSenders: Map<string, ApprovedSender> = new Map();
|
||||
private store?: PairingStore;
|
||||
|
||||
constructor(config: PairingConfig) {
|
||||
constructor(config: PairingConfig, store?: PairingStore) {
|
||||
this.config = config;
|
||||
this.store = store;
|
||||
if (store) {
|
||||
for (const sender of store.loadApproved()) {
|
||||
const key = `${sender.channel}:${sender.senderId}`;
|
||||
this.approvedSenders.set(key, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate a new pairing code. Returns the code string. */
|
||||
@@ -77,12 +91,14 @@ export class PairingManager {
|
||||
|
||||
// Code is valid — approve the sender
|
||||
const key = `${channel}:${senderId}`;
|
||||
this.approvedSenders.set(key, {
|
||||
const approved: ApprovedSender = {
|
||||
channel,
|
||||
senderId,
|
||||
approvedAt: Date.now(),
|
||||
codeUsed: normalizedCode,
|
||||
});
|
||||
};
|
||||
this.approvedSenders.set(key, approved);
|
||||
this.store?.saveApproved(approved);
|
||||
|
||||
// Remove the used code
|
||||
this.pendingCodes.delete(normalizedCode);
|
||||
@@ -98,7 +114,11 @@ export class PairingManager {
|
||||
/** Revoke approval for a sender. Returns true if the sender was found and removed. */
|
||||
revokeApproval(channel: string, senderId: string): boolean {
|
||||
const key = `${channel}:${senderId}`;
|
||||
return this.approvedSenders.delete(key);
|
||||
const deleted = this.approvedSenders.delete(key);
|
||||
if (deleted) {
|
||||
this.store?.removeApproved(channel, senderId);
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/** List all currently approved senders. */
|
||||
|
||||
Reference in New Issue
Block a user