MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / createTokenStore

Function createTokenStore

packages/server/src/services/auth/tokenStore.ts:24–83  ·  view source on GitHub ↗
(homeDir: string)

Source from the content-addressed store, hash-verified

22 * `dispose()` is intentionally a no-op: the token must survive shutdown.
23 */
24export async function createTokenStore(homeDir: string): Promise<TokenStore> {
25 const tokenPath = serverTokenPath(homeDir);
26 const initial = await loadOrCreateServerToken(homeDir);
27 const initialStat = statSync(tokenPath);
28 let cache: { token: string; mtimeMs: number; ino: number } = {
29 token: initial,
30 mtimeMs: initialStat.mtimeMs,
31 ino: initialStat.ino,
32 };
33
34 const currentToken = (): string => {
35 let st: ReturnType<typeof statSync>;
36 try {
37 st = statSync(tokenPath);
38 } catch {
39 // File temporarily unavailable — keep serving the last known token.
40 return cache.token;
41 }
42 // Detect a rewrite by mtime OR inode. `writePrivateFile` does an atomic
43 // rename, which always yields a new inode (POSIX) and a fresh mtime
44 // (Windows/NTFS, where `ino` is always 0). Checking both makes the reload
45 // robust even on filesystems with coarse (1s) mtime resolution.
46 if (st.mtimeMs === cache.mtimeMs && st.ino === cache.ino) {
47 return cache.token;
48 }
49 // Changed: re-read, but refuse a too-permissive file and never let an
50 // empty/partial read clobber the last good token.
51 // Skip the check on Windows: fs.stat mode is synthesised from the
52 // read-only attribute and does not reflect real ACLs, so it would always
53 // appear too permissive and prevent legitimate token reloads.
54 if (process.platform !== 'win32' && (st.mode & 0o077) !== 0) {
55 return cache.token;
56 }
57 try {
58 const token = readFileSync(tokenPath, 'utf8').trim();
59 if (token.length > 0) {
60 cache = { token, mtimeMs: st.mtimeMs, ino: st.ino };
61 }
62 } catch {
63 // keep last known token
64 }
65 return cache.token;
66 };
67
68 return {
69 tokenPath,
70 getToken: currentToken,
71 isValid(candidate: string): boolean {
72 const tokenBuf = Buffer.from(currentToken());
73 const candidateBuf = Buffer.from(candidate);
74 if (candidateBuf.length !== tokenBuf.length) {
75 return false;
76 }
77 return timingSafeEqual(candidateBuf, tokenBuf);
78 },
79 async dispose(): Promise<void> {
80 // Persistent token: intentionally left on disk so it survives restarts.
81 },

Callers 3

startServerFunction · 0.90

Calls 2

serverTokenPathFunction · 0.90
loadOrCreateServerTokenFunction · 0.90

Tested by

no test coverage detected