fix(audit): P1 心跳自启动 + refreshToken body + 类型修复
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
审计修复 Batch 2 (M4-03/M7-04/M11-01):
M4-03: 心跳引擎自动启动
- chat.rs auto-init 块: engine 创建后立即 start()
- 通过 engines.get() 获取引用避免 move 后使用
M7-04: refreshToken 发送 body 修复
- SaaSClient 新增 refreshTokenValue 存储 refresh_token
- refreshToken() 发送 { refresh_token } body
- SaaSRefreshResponse 新增 refresh_token 字段
- login/register 自动存储 refresh_token
- 添加 getRefreshToken/setRefreshToken 访问器
M11-01: blocking_lock 死锁修复 (已存在)
- 确认 try_lock + Result 匹配模式已正确
This commit is contained in:
@@ -20,15 +20,15 @@ export function installAuthMethods(ClientClass: { prototype: any }): void {
|
||||
* Login with username and password.
|
||||
* Auto-sets the client token on success.
|
||||
*/
|
||||
proto.login = async function (this: { token: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }, username: string, password: string, totpCode?: string): Promise<SaaSLoginResponse> {
|
||||
proto.login = async function (this: { token: string | null; refreshTokenValue: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }, username: string, password: string, totpCode?: string): Promise<SaaSLoginResponse> {
|
||||
const body: Record<string, string> = { username, password };
|
||||
if (totpCode) body.totp_code = totpCode;
|
||||
// Clear stale token before login — avoid sending expired token on auth endpoint
|
||||
if (totpCode) body.totp_code = totpCode; // Clear stale token before login — avoid sending expired token on auth endpoint
|
||||
this.token = null;
|
||||
const data = await this.request<SaaSLoginResponse>(
|
||||
'POST', '/api/v1/auth/login', body,
|
||||
);
|
||||
this.token = data.token;
|
||||
this.refreshTokenValue = data.refresh_token;
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ export function installAuthMethods(ClientClass: { prototype: any }): void {
|
||||
* Register a new account.
|
||||
* Auto-sets the client token on success.
|
||||
*/
|
||||
proto.register = async function (this: { token: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }, data: {
|
||||
proto.register = async function (this: { token: string | null; refreshTokenValue: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }, data: {
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
@@ -48,6 +48,7 @@ export function installAuthMethods(ClientClass: { prototype: any }): void {
|
||||
'POST', '/api/v1/auth/register', data,
|
||||
);
|
||||
this.token = result.token;
|
||||
this.refreshTokenValue = result.refresh_token;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -62,9 +63,17 @@ export function installAuthMethods(ClientClass: { prototype: any }): void {
|
||||
* Refresh the current token.
|
||||
* Auto-updates the client token on success.
|
||||
*/
|
||||
proto.refreshToken = async function (this: { token: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }): Promise<string> {
|
||||
const data = await this.request<SaaSRefreshResponse>('POST', '/api/v1/auth/refresh');
|
||||
proto.refreshToken = async function (this: { token: string | null; refreshTokenValue: string | null; request<T>(method: string, path: string, body?: unknown): Promise<T> }): Promise<string> {
|
||||
if (!this.refreshTokenValue) {
|
||||
throw new Error('No refresh token available');
|
||||
}
|
||||
const data = await this.request<SaaSRefreshResponse>('POST', '/api/v1/auth/refresh', {
|
||||
refresh_token: this.refreshTokenValue,
|
||||
});
|
||||
this.token = data.token;
|
||||
if (data.refresh_token) {
|
||||
this.refreshTokenValue = data.refresh_token;
|
||||
}
|
||||
return data.token;
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ export type {
|
||||
export class SaaSClient {
|
||||
private baseUrl: string;
|
||||
private token: string | null = null;
|
||||
private refreshTokenValue: string | null = null;
|
||||
|
||||
/**
|
||||
* Refresh mutex: shared Promise to prevent concurrent token refresh.
|
||||
@@ -172,6 +173,16 @@ export class SaaSClient {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/** Set or clear the refresh token (in-memory only, never persisted) */
|
||||
setRefreshToken(token: string | null): void {
|
||||
this.refreshTokenValue = token;
|
||||
}
|
||||
|
||||
/** Get the current refresh token */
|
||||
getRefreshToken(): string | null {
|
||||
return this.refreshTokenValue;
|
||||
}
|
||||
|
||||
/** Check if the client is authenticated (token in memory or cookie-based) */
|
||||
isAuthenticated(): boolean {
|
||||
return !!this.token || this._cookieAuth;
|
||||
|
||||
@@ -93,6 +93,7 @@ export interface SaaSLoginResponse {
|
||||
/** Refresh response from POST /api/v1/auth/refresh */
|
||||
export interface SaaSRefreshResponse {
|
||||
token: string;
|
||||
refresh_token: string;
|
||||
}
|
||||
|
||||
/** TOTP setup response from POST /api/v1/auth/totp/setup */
|
||||
|
||||
Reference in New Issue
Block a user