fix and update
This commit is contained in:
@@ -14,6 +14,7 @@ import { SettingsService } from './settings.service';
|
||||
import { MessagingService } from '../infra/messaging.service';
|
||||
import { NotificationsService } from './notifications.service';
|
||||
import { canonicalPhoneE164, phoneLookupVariants } from '../infra/phone.util';
|
||||
import { resolveDeviceName } from '../infra/client-device.util';
|
||||
import { TotpService } from './totp.service';
|
||||
import { RbacService } from './rbac.service';
|
||||
import { DEFAULT_VERIFICATION_ICON, resolveVerificationIcon } from './verification.constants';
|
||||
@@ -289,6 +290,33 @@ export class AuthService {
|
||||
);
|
||||
}
|
||||
|
||||
private async publishLoginSuccessNotification(
|
||||
userId: string,
|
||||
deviceId: string,
|
||||
ipAddress?: string | null,
|
||||
userAgent?: string | null
|
||||
) {
|
||||
try {
|
||||
const device = await this.prisma.device.findUnique({ where: { id: deviceId } });
|
||||
const deviceLabel = device?.name ?? resolveDeviceName(undefined, userAgent);
|
||||
const ipLabel = ipAddress?.trim() || 'неизвестный IP';
|
||||
await this.notifications.create(
|
||||
userId,
|
||||
'login_success',
|
||||
'Выполнен вход',
|
||||
`Выполнен вход с устройства «${deviceLabel}» и IP ${ipLabel}`,
|
||||
{
|
||||
deviceId,
|
||||
deviceName: deviceLabel,
|
||||
ipAddress: ipAddress ?? null,
|
||||
userAgent: userAgent ?? null
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
// Уведомление о входе не должно блокировать авторизацию.
|
||||
}
|
||||
}
|
||||
|
||||
async verifyOtp(command: LoginCommand & { recipient: string; code: string }) {
|
||||
const existingUser = await this.findUserByRecipient(command.recipient);
|
||||
const targetVariants = this.recipientLookupTargets(command.recipient);
|
||||
@@ -431,7 +459,8 @@ export class AuthService {
|
||||
fingerprint: command.fingerprint,
|
||||
deviceName: command.deviceName,
|
||||
deviceType: command.deviceType,
|
||||
ipAddress: command.ipAddress
|
||||
ipAddress: command.ipAddress,
|
||||
userAgent: command.userAgent
|
||||
});
|
||||
return this.finalizeAuthentication(
|
||||
user,
|
||||
@@ -649,20 +678,21 @@ export class AuthService {
|
||||
return `totp:login:attempts:${challengeId}`;
|
||||
}
|
||||
|
||||
private async upsertDevice(userId: string, command: Pick<LoginCommand, 'fingerprint' | 'deviceName' | 'deviceType' | 'ipAddress'>) {
|
||||
private async upsertDevice(userId: string, command: Pick<LoginCommand, 'fingerprint' | 'deviceName' | 'deviceType' | 'ipAddress' | 'userAgent'>) {
|
||||
const resolvedName = resolveDeviceName(command.deviceName, command.userAgent);
|
||||
return this.prisma.device.upsert({
|
||||
where: { userId_fingerprint: { userId, fingerprint: command.fingerprint } },
|
||||
create: {
|
||||
userId,
|
||||
fingerprint: command.fingerprint,
|
||||
name: command.deviceName ?? 'Новое устройство',
|
||||
name: resolvedName,
|
||||
type: this.toDeviceType(command.deviceType),
|
||||
lastIp: command.ipAddress
|
||||
},
|
||||
update: {
|
||||
lastSeenAt: new Date(),
|
||||
lastIp: command.ipAddress,
|
||||
name: command.deviceName ?? undefined,
|
||||
name: resolvedName,
|
||||
type: this.toDeviceType(command.deviceType)
|
||||
}
|
||||
});
|
||||
@@ -688,6 +718,7 @@ export class AuthService {
|
||||
});
|
||||
|
||||
await this.notifications.dismissOtpCodeNotifications(user.id);
|
||||
await this.publishLoginSuccessNotification(user.id, deviceId, command.ipAddress, command.userAgent);
|
||||
|
||||
return {
|
||||
accessToken: await this.issueAccessToken(user, session.id, pinVerified),
|
||||
|
||||
Reference in New Issue
Block a user