Add TKMind platform extensions, H5/MindSpace stack, and deployment tooling.
Deploy Documentation / deploy (push) Has been cancelled
Canary / Prepare Version (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-intel (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / bundle-desktop-windows-cuda (push) Has been cancelled
Canary / Release (push) Has been cancelled
Unused Dependencies / machete (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / Check Rust Code Format (push) Has been cancelled
CI / Build and Test Rust Project (push) Has been cancelled
CI / Build Rust Project on Windows (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Lint Rust Code (push) Has been cancelled
CI / Check Generated Schemas are Up-to-Date (push) Has been cancelled
CI / Test and Lint Electron Desktop App (push) Has been cancelled
CI / H5 Plaza Tests and Build (push) Has been cancelled
Live Provider Tests / check-fork (push) Has been cancelled
Live Provider Tests / changes (push) Has been cancelled
Live Provider Tests / Build Binary (push) Has been cancelled
Live Provider Tests / Smoke Tests (push) Has been cancelled
Live Provider Tests / Smoke Tests (Code Execution) (push) Has been cancelled
Live Provider Tests / Compaction Tests (push) Has been cancelled
Live Provider Tests / goose server HTTP integration tests (push) Has been cancelled
Publish Ask AI Bot Docker Image / docker (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Deploy Documentation / deploy (push) Has been cancelled
Canary / Prepare Version (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-intel (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / bundle-desktop-windows-cuda (push) Has been cancelled
Canary / Release (push) Has been cancelled
Unused Dependencies / machete (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / Check Rust Code Format (push) Has been cancelled
CI / Build and Test Rust Project (push) Has been cancelled
CI / Build Rust Project on Windows (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Lint Rust Code (push) Has been cancelled
CI / Check Generated Schemas are Up-to-Date (push) Has been cancelled
CI / Test and Lint Electron Desktop App (push) Has been cancelled
CI / H5 Plaza Tests and Build (push) Has been cancelled
Live Provider Tests / check-fork (push) Has been cancelled
Live Provider Tests / changes (push) Has been cancelled
Live Provider Tests / Build Binary (push) Has been cancelled
Live Provider Tests / Smoke Tests (push) Has been cancelled
Live Provider Tests / Smoke Tests (Code Execution) (push) Has been cancelled
Live Provider Tests / Compaction Tests (push) Has been cancelled
Live Provider Tests / goose server HTTP integration tests (push) Has been cancelled
Publish Ask AI Bot Docker Image / docker (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Fork goose with custom MCP widgets, platform extensions (aider, git, web, search), MindSpace H5 backend/frontend, Plaza/Ops UIs, and deploy scripts for tkmind.cn. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+117
@@ -0,0 +1,117 @@
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
export const AUTH_COOKIE = 'tkmind_h5_session';
|
||||
|
||||
export function parseCookies(header = '') {
|
||||
return Object.fromEntries(
|
||||
header
|
||||
.split(';')
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const separator = part.indexOf('=');
|
||||
if (separator < 0) return [part, ''];
|
||||
return [
|
||||
decodeURIComponent(part.slice(0, separator)),
|
||||
decodeURIComponent(part.slice(separator + 1)),
|
||||
];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function safeEqual(left, right) {
|
||||
const leftBuffer = Buffer.from(left);
|
||||
const rightBuffer = Buffer.from(right);
|
||||
return (
|
||||
leftBuffer.length === rightBuffer.length &&
|
||||
crypto.timingSafeEqual(leftBuffer, rightBuffer)
|
||||
);
|
||||
}
|
||||
|
||||
export function createAuthManager({
|
||||
password,
|
||||
ttlMs = 7 * 24 * 60 * 60 * 1000,
|
||||
maxFailures = 5,
|
||||
failureWindowMs = 5 * 60 * 1000,
|
||||
}) {
|
||||
if (!password) {
|
||||
throw new Error('H5_ACCESS_PASSWORD is required');
|
||||
}
|
||||
|
||||
const sessions = new Map();
|
||||
const failures = new Map();
|
||||
|
||||
const prune = (now = Date.now()) => {
|
||||
for (const [token, expiresAt] of sessions) {
|
||||
if (expiresAt <= now) sessions.delete(token);
|
||||
}
|
||||
for (const [ip, state] of failures) {
|
||||
if (state.resetAt <= now) failures.delete(ip);
|
||||
}
|
||||
};
|
||||
|
||||
const login = (candidate, ip = 'unknown', now = Date.now()) => {
|
||||
prune(now);
|
||||
const failure = failures.get(ip);
|
||||
if (failure && failure.count >= maxFailures && failure.resetAt > now) {
|
||||
return { ok: false, retryAfterMs: failure.resetAt - now };
|
||||
}
|
||||
|
||||
if (!safeEqual(candidate, password)) {
|
||||
const current =
|
||||
failure && failure.resetAt > now
|
||||
? failure
|
||||
: { count: 0, resetAt: now + failureWindowMs };
|
||||
current.count += 1;
|
||||
failures.set(ip, current);
|
||||
return { ok: false, retryAfterMs: 0 };
|
||||
}
|
||||
|
||||
failures.delete(ip);
|
||||
const token = crypto.randomBytes(32).toString('base64url');
|
||||
sessions.set(token, now + ttlMs);
|
||||
return { ok: true, token };
|
||||
};
|
||||
|
||||
const verify = (token, now = Date.now()) => {
|
||||
if (!token) return false;
|
||||
prune(now);
|
||||
const expiresAt = sessions.get(token);
|
||||
if (!expiresAt || expiresAt <= now) {
|
||||
sessions.delete(token);
|
||||
return false;
|
||||
}
|
||||
sessions.set(token, now + ttlMs);
|
||||
return true;
|
||||
};
|
||||
|
||||
const revoke = (token) => {
|
||||
if (token) sessions.delete(token);
|
||||
};
|
||||
|
||||
return { login, verify, revoke };
|
||||
}
|
||||
|
||||
export function sessionCookie(token, secure) {
|
||||
const parts = [
|
||||
`${AUTH_COOKIE}=${encodeURIComponent(token)}`,
|
||||
'Path=/',
|
||||
'HttpOnly',
|
||||
'SameSite=Lax',
|
||||
'Max-Age=604800',
|
||||
];
|
||||
if (secure) parts.push('Secure');
|
||||
return parts.join('; ');
|
||||
}
|
||||
|
||||
export function clearSessionCookie(secure) {
|
||||
const parts = [
|
||||
`${AUTH_COOKIE}=`,
|
||||
'Path=/',
|
||||
'HttpOnly',
|
||||
'SameSite=Lax',
|
||||
'Max-Age=0',
|
||||
];
|
||||
if (secure) parts.push('Secure');
|
||||
return parts.join('; ');
|
||||
}
|
||||
Reference in New Issue
Block a user