update
This commit is contained in:
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
@@ -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'
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<span class="text-xs text-text-tertiary ml-1">(ID: ...{{ typeof key.credentialID === 'string' && key.credentialID ? key.credentialID.slice(-8) : 'N/A' }})</span>
|
||||
</span>
|
||||
<div v-else class="flex items-center flex-grow">
|
||||
<input type="text" v-model="editingPasskeyName" @keyup.enter="savePasskeyName(key.credentialID)" @keyup.esc="cancelEditPasskeyName" class="flex-grow px-2 py-1 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary text-sm" :placeholder="$t('settings.passkey.enterNamePlaceholder', '输入 Passkey 名称')" />
|
||||
<input type="text" v-model="editingPasskeyName" @keyup.enter="savePasskeyName(key.credentialID)" @keyup.esc="cancelEditPasskeyName" class="flex-grow max-w-sm px-2 py-1 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary text-sm" :placeholder="$t('settings.passkey.enterNamePlaceholder', '输入 Passkey 名称')" />
|
||||
<button @click="savePasskeyName(key.credentialID)" :disabled="passkeyEditLoadingStates[key.credentialID]" class="ml-2 px-2 py-1 bg-success text-success-text rounded-md text-xs font-medium hover:bg-success/80 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-success disabled:opacity-50 disabled:cursor-not-allowed transition duration-150 ease-in-out">
|
||||
{{ passkeyEditLoadingStates[key.credentialID] ? $t('common.saving') : $t('common.save') }}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user