mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-07 22:09:57 +00:00
70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import { generateSecureToken } from "../../infra/secure-random.js";
|
|
|
|
const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18;
|
|
const SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH = Math.ceil(
|
|
(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES * 8) / 6,
|
|
);
|
|
const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(
|
|
`^[A-Za-z0-9_-]{${SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH}}$`,
|
|
);
|
|
const SLACK_EXTERNAL_ARG_MENU_TTL_MS = 10 * 60 * 1000;
|
|
|
|
export const SLACK_EXTERNAL_ARG_MENU_PREFIX = "openclaw_cmdarg_ext:";
|
|
|
|
export type SlackExternalArgMenuChoice = { label: string; value: string };
|
|
export type SlackExternalArgMenuEntry = {
|
|
choices: SlackExternalArgMenuChoice[];
|
|
userId: string;
|
|
expiresAt: number;
|
|
};
|
|
|
|
function pruneSlackExternalArgMenuStore(
|
|
store: Map<string, SlackExternalArgMenuEntry>,
|
|
now: number,
|
|
): void {
|
|
for (const [token, entry] of store.entries()) {
|
|
if (entry.expiresAt <= now) {
|
|
store.delete(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
function createSlackExternalArgMenuToken(store: Map<string, SlackExternalArgMenuEntry>): string {
|
|
let token = "";
|
|
do {
|
|
token = generateSecureToken(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES);
|
|
} while (store.has(token));
|
|
return token;
|
|
}
|
|
|
|
export function createSlackExternalArgMenuStore() {
|
|
const store = new Map<string, SlackExternalArgMenuEntry>();
|
|
|
|
return {
|
|
create(
|
|
params: { choices: SlackExternalArgMenuChoice[]; userId: string },
|
|
now = Date.now(),
|
|
): string {
|
|
pruneSlackExternalArgMenuStore(store, now);
|
|
const token = createSlackExternalArgMenuToken(store);
|
|
store.set(token, {
|
|
choices: params.choices,
|
|
userId: params.userId,
|
|
expiresAt: now + SLACK_EXTERNAL_ARG_MENU_TTL_MS,
|
|
});
|
|
return token;
|
|
},
|
|
readToken(raw: unknown): string | undefined {
|
|
if (typeof raw !== "string" || !raw.startsWith(SLACK_EXTERNAL_ARG_MENU_PREFIX)) {
|
|
return undefined;
|
|
}
|
|
const token = raw.slice(SLACK_EXTERNAL_ARG_MENU_PREFIX.length).trim();
|
|
return SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN.test(token) ? token : undefined;
|
|
},
|
|
get(token: string, now = Date.now()): SlackExternalArgMenuEntry | undefined {
|
|
pruneSlackExternalArgMenuStore(store, now);
|
|
return store.get(token);
|
|
},
|
|
};
|
|
}
|