This commit is contained in:
Baobhan Sith
2025-05-08 16:22:44 +08:00
parent c586d4b671
commit c9519c5271
5 changed files with 70 additions and 5 deletions
@@ -286,7 +286,54 @@ export const deleteUserPasskeyHandler = async (req: Request, res: Response): Pro
}
};
/**
* 更新当前认证用户指定的 Passkey 名称 (PUT /api/v1/user/passkeys/:credentialID/name)
*/
export const updateUserPasskeyNameHandler = async (req: Request, res: Response): Promise<void> => {
const userId = req.session.userId;
const username = req.session.username;
const { credentialID } = req.params;
const { name } = req.body;
if (!userId || !username) {
res.status(401).json({ message: '用户未认证。' });
return;
}
if (!credentialID) {
res.status(400).json({ message: '必须提供 Passkey 的 CredentialID。' });
return;
}
if (typeof name !== 'string' || name.trim() === '') {
res.status(400).json({ message: 'Passkey 名称不能为空。' });
return;
}
const trimmedName = name.trim();
try {
await passkeyService.updatePasskeyName(userId, credentialID, trimmedName);
console.log(`[AuthController] 用户 ${username} (ID: ${userId}) 成功更新了 Passkey (CredentialID: ${credentialID}) 的名称为 "${trimmedName}"。`);
auditLogService.logAction('PASSKEY_NAME_UPDATED', { userId, username, credentialId: credentialID, newName: trimmedName });
// Optionally send a notification if desired
// notificationService.sendNotification('PASSKEY_NAME_UPDATED', { userId, username, credentialId: credentialID, newName: trimmedName });
res.status(200).json({ message: 'Passkey 名称更新成功。' });
} catch (error: any) {
console.error(`[AuthController] 用户 ${username} (ID: ${userId}) 更新 Passkey (CredentialID: ${credentialID}) 名称时出错:`, error.message, error.stack);
if (error.message === 'Passkey not found.') {
res.status(404).json({ message: '指定的 Passkey 未找到。' });
} else if (error.message === 'Unauthorized to update this passkey name.') {
auditLogService.logAction('PASSKEY_NAME_UPDATE_UNAUTHORIZED', { userId, username, credentialIdAttempted: credentialID });
res.status(403).json({ message: '无权更新此 Passkey 名称。' });
} else {
res.status(500).json({ message: '更新 Passkey 名称失败。', error: error.message });
}
}
};
/**
* 处理用户登录请求 (POST /api/v1/auth/login)
*/
+6 -2
View File
@@ -18,7 +18,8 @@ import {
verifyPasskeyAuthenticationHandler,
// 新的 Passkey 管理处理器
listUserPasskeysHandler,
deleteUserPasskeyHandler
deleteUserPasskeyHandler,
updateUserPasskeyNameHandler // 新增:更新 Passkey 名称的处理器
} from './auth.controller';
import { isAuthenticated } from './auth.middleware';
import { ipBlacklistCheckMiddleware } from './ipBlacklistCheck.middleware';
@@ -79,7 +80,10 @@ router.get('/user/passkeys', isAuthenticated, listUserPasskeysHandler);
// DELETE /api/v1/auth/user/passkeys/:credentialID - 删除当前用户指定的 Passkey (需要认证)
router.delete('/user/passkeys/:credentialID', isAuthenticated, deleteUserPasskeyHandler);
// PUT /api/v1/auth/user/passkeys/:credentialID/name - 更新当前用户指定的 Passkey 名称 (需要认证)
router.put('/user/passkeys/:credentialID/name', isAuthenticated, updateUserPasskeyNameHandler);
// POST /api/v1/auth/logout - 用户登出接口 (公开访问)
router.post('/logout', logout);
@@ -289,6 +289,18 @@ export class PasskeyService {
const wasDeleted = await this.passkeyRepo.deletePasskey(credentialID);
return wasDeleted;
}
}
async updatePasskeyName(userId: number, credentialID: string, newName: string): Promise<void> {
const passkey = await this.passkeyRepo.getPasskeyByCredentialId(credentialID);
if (!passkey) {
throw new Error('Passkey not found.');
}
if (passkey.user_id !== userId) {
// Security measure: User can only update their own passkey names
throw new Error('Unauthorized to update this passkey name.');
}
await this.passkeyRepo.updatePasskeyName(credentialID, newName);
}
}
export const passkeyService = new PasskeyService(passkeyRepository, userRepository);
+3 -1
View File
@@ -13,7 +13,9 @@ export type AuditLogActionType =
| 'PASSKEY_AUTH_FAILURE'
| 'PASSKEY_DELETED'
| 'PASSKEY_DELETE_UNAUTHORIZED'
| 'PASSKEY_NAME_UPDATED'
| 'PASSKEY_NAME_UPDATE_UNAUTHORIZED'
// Connections
| 'CONNECTION_CREATED'
| 'CONNECTION_UPDATED'