@nauth-toolkit/core 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dto/index.d.ts +1 -0
- package/dist/dto/index.d.ts.map +1 -1
- package/dist/dto/index.js +1 -0
- package/dist/dto/index.js.map +1 -1
- package/dist/dto/update-verified-status-request.dto.d.ts +70 -0
- package/dist/dto/update-verified-status-request.dto.d.ts.map +1 -0
- package/dist/dto/update-verified-status-request.dto.js +107 -0
- package/dist/dto/update-verified-status-request.dto.js.map +1 -0
- package/dist/interfaces/hooks.interface.d.ts +129 -0
- package/dist/interfaces/hooks.interface.d.ts.map +1 -1
- package/dist/services/auth.service.d.ts +37 -0
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +221 -0
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/email-verification.service.d.ts +3 -1
- package/dist/services/email-verification.service.d.ts.map +1 -1
- package/dist/services/email-verification.service.js +77 -1
- package/dist/services/email-verification.service.js.map +1 -1
- package/dist/services/hook-registry.service.d.ts +23 -1
- package/dist/services/hook-registry.service.d.ts.map +1 -1
- package/dist/services/hook-registry.service.js +39 -0
- package/dist/services/hook-registry.service.js.map +1 -1
- package/dist/services/phone-verification.service.d.ts +3 -1
- package/dist/services/phone-verification.service.d.ts.map +1 -1
- package/dist/services/phone-verification.service.js +80 -1
- package/dist/services/phone-verification.service.js.map +1 -1
- package/dist/services/social-auth-base.service.d.ts +2 -1
- package/dist/services/social-auth-base.service.d.ts.map +1 -1
- package/dist/services/social-auth-base.service.js +5 -2
- package/dist/services/social-auth-base.service.js.map +1 -1
- package/dist/utils/setup/init-services.d.ts.map +1 -1
- package/dist/utils/setup/init-services.js +2 -2
- package/dist/utils/setup/init-services.js.map +1 -1
- package/package.json +1 -1
|
@@ -47,6 +47,7 @@ const enable_user_dto_1 = require("../dto/enable-user.dto");
|
|
|
47
47
|
const login_dto_1 = require("../dto/login.dto");
|
|
48
48
|
const change_password_request_dto_1 = require("../dto/change-password-request.dto");
|
|
49
49
|
const update_user_attributes_request_dto_1 = require("../dto/update-user-attributes-request.dto");
|
|
50
|
+
const update_verified_status_request_dto_1 = require("../dto/update-verified-status-request.dto");
|
|
50
51
|
const user_response_dto_1 = require("../dto/user-response.dto");
|
|
51
52
|
const auth_response_dto_1 = require("../dto/auth-response.dto");
|
|
52
53
|
const auth_challenge_dto_1 = require("../dto/auth-challenge.dto");
|
|
@@ -735,10 +736,16 @@ class AuthService {
|
|
|
735
736
|
// Lifecycle Hook: afterSignup
|
|
736
737
|
// ============================================================================
|
|
737
738
|
// Execute afterSignup hook immediately after account creation (non-blocking)
|
|
739
|
+
// Extract profile picture from social metadata if available
|
|
740
|
+
const profilePicture = dto.socialMetadata && typeof dto.socialMetadata === 'object' && 'picture' in dto.socialMetadata
|
|
741
|
+
? dto.socialMetadata.picture
|
|
742
|
+
: null;
|
|
738
743
|
await this.hookRegistry.executePostSignup(savedUser, {
|
|
739
744
|
signupType: 'social',
|
|
740
745
|
provider: dto.provider,
|
|
741
746
|
adminSignup: true,
|
|
747
|
+
socialMetadata: dto.socialMetadata || null,
|
|
748
|
+
profilePicture,
|
|
742
749
|
});
|
|
743
750
|
// ============================================================================
|
|
744
751
|
// Audit: Record account creation by admin (social import)
|
|
@@ -3967,6 +3974,220 @@ class AuthService {
|
|
|
3967
3974
|
userId: user.id,
|
|
3968
3975
|
});
|
|
3969
3976
|
}
|
|
3977
|
+
// ============================================================================
|
|
3978
|
+
// Hook: Execute user profile updated hooks
|
|
3979
|
+
// ============================================================================
|
|
3980
|
+
try {
|
|
3981
|
+
// Build changed fields array with old/new values
|
|
3982
|
+
const changedFields = [];
|
|
3983
|
+
// Track all fields that were in updateFields
|
|
3984
|
+
for (const fieldName of Object.keys(updateFields)) {
|
|
3985
|
+
changedFields.push({
|
|
3986
|
+
fieldName,
|
|
3987
|
+
oldValue: user[fieldName],
|
|
3988
|
+
newValue: updateFields[fieldName],
|
|
3989
|
+
});
|
|
3990
|
+
}
|
|
3991
|
+
// Get client info from ClientInfoService
|
|
3992
|
+
const clientInfo = this.clientInfoService.get();
|
|
3993
|
+
// Execute hooks (non-blocking)
|
|
3994
|
+
await this.hookRegistry.executeUserProfileUpdated({
|
|
3995
|
+
user: updatedUser,
|
|
3996
|
+
changedFields,
|
|
3997
|
+
updateSource: 'user_request',
|
|
3998
|
+
clientInfo: {
|
|
3999
|
+
ipAddress: clientInfo.ipAddress,
|
|
4000
|
+
userAgent: clientInfo.userAgent,
|
|
4001
|
+
ipCountry: clientInfo.ipCountry,
|
|
4002
|
+
ipCity: clientInfo.ipCity,
|
|
4003
|
+
},
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
catch (hookError) {
|
|
4007
|
+
// Non-blocking: Log but continue
|
|
4008
|
+
const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
|
|
4009
|
+
this.logger?.error?.(`Failed to execute userProfileUpdated hooks: ${errorMessage}`, {
|
|
4010
|
+
error: hookError,
|
|
4011
|
+
userId: user.id,
|
|
4012
|
+
});
|
|
4013
|
+
}
|
|
4014
|
+
// Return user response DTO
|
|
4015
|
+
return user_response_dto_1.UserResponseDto.fromEntity(updatedUser);
|
|
4016
|
+
}
|
|
4017
|
+
/**
|
|
4018
|
+
* Update email and/or phone verification status.
|
|
4019
|
+
*
|
|
4020
|
+
* Intended for admin use cases such as migration or offline validation.
|
|
4021
|
+
* Updates verification status without requiring actual verification codes.
|
|
4022
|
+
*
|
|
4023
|
+
* Validation:
|
|
4024
|
+
* - Cannot set verified=true if email/phone doesn't exist
|
|
4025
|
+
* - Can set verified=false even if email/phone doesn't exist (default state)
|
|
4026
|
+
* - Only updates provided fields (partial update)
|
|
4027
|
+
*
|
|
4028
|
+
* Audit:
|
|
4029
|
+
* - Records EMAIL_VERIFIED or PHONE_VERIFIED audit events
|
|
4030
|
+
* - Includes performedBy from authenticated admin context
|
|
4031
|
+
*
|
|
4032
|
+
* @param dto - Request DTO containing sub and verification status flags
|
|
4033
|
+
* @returns Updated user object
|
|
4034
|
+
* @throws {NAuthException} If user not found or trying to verify non-existent email/phone
|
|
4035
|
+
*
|
|
4036
|
+
* @example
|
|
4037
|
+
* ```typescript
|
|
4038
|
+
* // Update email verification only
|
|
4039
|
+
* await authService.updateVerifiedStatus({
|
|
4040
|
+
* sub: 'user-uuid',
|
|
4041
|
+
* isEmailVerified: true
|
|
4042
|
+
* });
|
|
4043
|
+
*
|
|
4044
|
+
* // Update both email and phone verification
|
|
4045
|
+
* await authService.updateVerifiedStatus({
|
|
4046
|
+
* sub: 'user-uuid',
|
|
4047
|
+
* isEmailVerified: true,
|
|
4048
|
+
* isPhoneVerified: false
|
|
4049
|
+
* });
|
|
4050
|
+
* ```
|
|
4051
|
+
*/
|
|
4052
|
+
async updateVerifiedStatus(dto) {
|
|
4053
|
+
// Ensure DTO is validated (supports direct usage without framework validation)
|
|
4054
|
+
dto = await (0, dto_validator_1.ensureValidatedDto)(update_verified_status_request_dto_1.UpdateVerifiedStatusRequestDTO, dto);
|
|
4055
|
+
// Find user by sub (external identifier)
|
|
4056
|
+
const user = (await this.userRepository.findOne({ where: { sub: dto.sub } }));
|
|
4057
|
+
if (!user) {
|
|
4058
|
+
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
|
|
4059
|
+
}
|
|
4060
|
+
// Validate that email exists if trying to set isEmailVerified to true
|
|
4061
|
+
if (dto.isEmailVerified === true && !user.email) {
|
|
4062
|
+
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.VALIDATION_FAILED, 'Cannot set email verification to true: user does not have an email address');
|
|
4063
|
+
}
|
|
4064
|
+
// Validate that phone exists if trying to set isPhoneVerified to true
|
|
4065
|
+
if (dto.isPhoneVerified === true && !user.phone) {
|
|
4066
|
+
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.VALIDATION_FAILED, 'Cannot set phone verification to true: user does not have a phone number');
|
|
4067
|
+
}
|
|
4068
|
+
// Prepare update object - only include fields that were provided
|
|
4069
|
+
const updateFields = {};
|
|
4070
|
+
if (dto.isEmailVerified !== undefined) {
|
|
4071
|
+
updateFields.isEmailVerified = dto.isEmailVerified;
|
|
4072
|
+
}
|
|
4073
|
+
if (dto.isPhoneVerified !== undefined) {
|
|
4074
|
+
updateFields.isPhoneVerified = dto.isPhoneVerified;
|
|
4075
|
+
}
|
|
4076
|
+
// If no fields to update, return current user
|
|
4077
|
+
if (Object.keys(updateFields).length === 0) {
|
|
4078
|
+
return user_response_dto_1.UserResponseDto.fromEntity(user);
|
|
4079
|
+
}
|
|
4080
|
+
// Update user - use internal id for database update
|
|
4081
|
+
await this.userRepository.update(user.id, updateFields);
|
|
4082
|
+
// Reload user to get updated values
|
|
4083
|
+
const updatedUser = (await this.userRepository.findOne({ where: { id: user.id } }));
|
|
4084
|
+
if (!updatedUser) {
|
|
4085
|
+
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.INTERNAL_ERROR, 'Failed to reload user after update');
|
|
4086
|
+
}
|
|
4087
|
+
// ============================================================================
|
|
4088
|
+
// Audit: Record verification status changes
|
|
4089
|
+
// ============================================================================
|
|
4090
|
+
if (this.auditService) {
|
|
4091
|
+
// Record email verification change if provided
|
|
4092
|
+
if (dto.isEmailVerified !== undefined) {
|
|
4093
|
+
try {
|
|
4094
|
+
await this.auditService.recordEvent({
|
|
4095
|
+
userId: user.id,
|
|
4096
|
+
eventType: auth_audit_event_type_enum_1.AuthAuditEventType.EMAIL_VERIFIED,
|
|
4097
|
+
eventStatus: dto.isEmailVerified ? 'SUCCESS' : 'INFO',
|
|
4098
|
+
description: dto.isEmailVerified
|
|
4099
|
+
? 'Email verification status set to verified (admin action)'
|
|
4100
|
+
: 'Email verification status set to unverified (admin action)',
|
|
4101
|
+
reason: 'admin_verification_update',
|
|
4102
|
+
metadata: {
|
|
4103
|
+
previousStatus: user.isEmailVerified,
|
|
4104
|
+
newStatus: dto.isEmailVerified,
|
|
4105
|
+
updateMethod: 'admin_direct',
|
|
4106
|
+
// Client info automatically included from context (performedBy auto-populated)
|
|
4107
|
+
},
|
|
4108
|
+
});
|
|
4109
|
+
}
|
|
4110
|
+
catch (auditError) {
|
|
4111
|
+
// Non-blocking: Log but continue
|
|
4112
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
4113
|
+
this.logger?.error?.(`Failed to record EMAIL_VERIFIED audit event: ${errorMessage}`, {
|
|
4114
|
+
error: auditError,
|
|
4115
|
+
userId: user.id,
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
// Record phone verification change if provided
|
|
4120
|
+
if (dto.isPhoneVerified !== undefined) {
|
|
4121
|
+
try {
|
|
4122
|
+
await this.auditService.recordEvent({
|
|
4123
|
+
userId: user.id,
|
|
4124
|
+
eventType: auth_audit_event_type_enum_1.AuthAuditEventType.PHONE_VERIFIED,
|
|
4125
|
+
eventStatus: dto.isPhoneVerified ? 'SUCCESS' : 'INFO',
|
|
4126
|
+
description: dto.isPhoneVerified
|
|
4127
|
+
? 'Phone verification status set to verified (admin action)'
|
|
4128
|
+
: 'Phone verification status set to unverified (admin action)',
|
|
4129
|
+
reason: 'admin_verification_update',
|
|
4130
|
+
metadata: {
|
|
4131
|
+
previousStatus: user.isPhoneVerified,
|
|
4132
|
+
newStatus: dto.isPhoneVerified,
|
|
4133
|
+
updateMethod: 'admin_direct',
|
|
4134
|
+
// Client info automatically included from context (performedBy auto-populated)
|
|
4135
|
+
},
|
|
4136
|
+
});
|
|
4137
|
+
}
|
|
4138
|
+
catch (auditError) {
|
|
4139
|
+
// Non-blocking: Log but continue
|
|
4140
|
+
const errorMessage = auditError instanceof Error ? auditError.message : 'Unknown error';
|
|
4141
|
+
this.logger?.error?.(`Failed to record PHONE_VERIFIED audit event: ${errorMessage}`, {
|
|
4142
|
+
error: auditError,
|
|
4143
|
+
userId: user.id,
|
|
4144
|
+
});
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
}
|
|
4148
|
+
// ============================================================================
|
|
4149
|
+
// Hook: Execute user profile updated hooks
|
|
4150
|
+
// ============================================================================
|
|
4151
|
+
try {
|
|
4152
|
+
// Build changed fields array with old/new values
|
|
4153
|
+
const changedFields = [];
|
|
4154
|
+
if (dto.isEmailVerified !== undefined) {
|
|
4155
|
+
changedFields.push({
|
|
4156
|
+
fieldName: 'isEmailVerified',
|
|
4157
|
+
oldValue: user.isEmailVerified,
|
|
4158
|
+
newValue: dto.isEmailVerified,
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
if (dto.isPhoneVerified !== undefined) {
|
|
4162
|
+
changedFields.push({
|
|
4163
|
+
fieldName: 'isPhoneVerified',
|
|
4164
|
+
oldValue: user.isPhoneVerified,
|
|
4165
|
+
newValue: dto.isPhoneVerified,
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
// Get client info from ClientInfoService
|
|
4169
|
+
const clientInfo = this.clientInfoService.get();
|
|
4170
|
+
// Execute hooks (non-blocking)
|
|
4171
|
+
await this.hookRegistry.executeUserProfileUpdated({
|
|
4172
|
+
user: updatedUser,
|
|
4173
|
+
changedFields,
|
|
4174
|
+
updateSource: 'admin_action',
|
|
4175
|
+
clientInfo: {
|
|
4176
|
+
ipAddress: clientInfo.ipAddress,
|
|
4177
|
+
userAgent: clientInfo.userAgent,
|
|
4178
|
+
ipCountry: clientInfo.ipCountry,
|
|
4179
|
+
ipCity: clientInfo.ipCity,
|
|
4180
|
+
},
|
|
4181
|
+
});
|
|
4182
|
+
}
|
|
4183
|
+
catch (hookError) {
|
|
4184
|
+
// Non-blocking: Log but continue
|
|
4185
|
+
const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
|
|
4186
|
+
this.logger?.error?.(`Failed to execute userProfileUpdated hooks: ${errorMessage}`, {
|
|
4187
|
+
error: hookError,
|
|
4188
|
+
userId: user.id,
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
3970
4191
|
// Return user response DTO
|
|
3971
4192
|
return user_response_dto_1.UserResponseDto.fromEntity(updatedUser);
|
|
3972
4193
|
}
|