@nauth-toolkit/core 0.1.0 → 0.1.3
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/LICENSE +90 -0
- package/README.md +30 -0
- package/package.json +7 -2
- package/jest.config.js +0 -15
- package/jest.setup.ts +0 -6
- package/src/adapters/database-columns.ts +0 -165
- package/src/adapters/express.adapter.ts +0 -385
- package/src/adapters/fastify.adapter.ts +0 -416
- package/src/adapters/index.ts +0 -16
- package/src/adapters/storage.factory.ts +0 -143
- package/src/bootstrap.ts +0 -374
- package/src/dto/auth-challenge.dto.ts +0 -231
- package/src/dto/auth-response.dto.ts +0 -253
- package/src/dto/challenge-response.dto.ts +0 -234
- package/src/dto/change-password-request.dto.ts +0 -50
- package/src/dto/change-password-response.dto.ts +0 -29
- package/src/dto/change-password.dto.ts +0 -57
- package/src/dto/error-response.dto.ts +0 -136
- package/src/dto/get-available-methods.dto.ts +0 -55
- package/src/dto/get-challenge-data-response.dto.ts +0 -28
- package/src/dto/get-challenge-data.dto.ts +0 -69
- package/src/dto/get-client-info.dto.ts +0 -104
- package/src/dto/get-device-token-response.dto.ts +0 -25
- package/src/dto/get-events-by-type.dto.ts +0 -76
- package/src/dto/get-ip-address-response.dto.ts +0 -24
- package/src/dto/get-mfa-status.dto.ts +0 -94
- package/src/dto/get-risk-assessment-history.dto.ts +0 -39
- package/src/dto/get-session-id-response.dto.ts +0 -25
- package/src/dto/get-setup-data-response.dto.ts +0 -31
- package/src/dto/get-setup-data.dto.ts +0 -75
- package/src/dto/get-suspicious-activity.dto.ts +0 -42
- package/src/dto/get-user-agent-response.dto.ts +0 -23
- package/src/dto/get-user-auth-history.dto.ts +0 -95
- package/src/dto/get-user-by-email.dto.ts +0 -61
- package/src/dto/get-user-by-id.dto.ts +0 -46
- package/src/dto/get-user-devices.dto.ts +0 -53
- package/src/dto/get-user-response.dto.ts +0 -17
- package/src/dto/has-provider.dto.ts +0 -56
- package/src/dto/index.ts +0 -57
- package/src/dto/is-trusted-device-response.dto.ts +0 -34
- package/src/dto/list-providers-response.dto.ts +0 -23
- package/src/dto/login.dto.ts +0 -95
- package/src/dto/logout-all-response.dto.ts +0 -24
- package/src/dto/logout-all.dto.ts +0 -65
- package/src/dto/logout-response.dto.ts +0 -25
- package/src/dto/logout.dto.ts +0 -64
- package/src/dto/refresh-token.dto.ts +0 -36
- package/src/dto/remove-devices.dto.ts +0 -85
- package/src/dto/resend-code-response.dto.ts +0 -32
- package/src/dto/resend-code.dto.ts +0 -51
- package/src/dto/reset-password.dto.ts +0 -115
- package/src/dto/respond-challenge.dto.ts +0 -272
- package/src/dto/set-mfa-exemption.dto.ts +0 -112
- package/src/dto/set-must-change-password-response.dto.ts +0 -27
- package/src/dto/set-must-change-password.dto.ts +0 -46
- package/src/dto/set-preferred-method.dto.ts +0 -80
- package/src/dto/setup-mfa.dto.ts +0 -98
- package/src/dto/signup.dto.ts +0 -174
- package/src/dto/social-auth.dto.ts +0 -422
- package/src/dto/trust-device-response.dto.ts +0 -30
- package/src/dto/trust-device.dto.ts +0 -9
- package/src/dto/update-user-attributes-request.dto.ts +0 -51
- package/src/dto/user-response.dto.ts +0 -138
- package/src/dto/user-update.dto.ts +0 -222
- package/src/dto/verify-email.dto.ts +0 -313
- package/src/dto/verify-mfa-code.dto.ts +0 -103
- package/src/dto/verify-phone-by-sub.dto.ts +0 -78
- package/src/dto/verify-phone.dto.ts +0 -245
- package/src/entities/auth-audit.entity.ts +0 -232
- package/src/entities/challenge-session.entity.ts +0 -116
- package/src/entities/index.ts +0 -29
- package/src/entities/login-attempt.entity.ts +0 -64
- package/src/entities/mfa-device.entity.ts +0 -151
- package/src/entities/rate-limit.entity.ts +0 -44
- package/src/entities/session.entity.ts +0 -180
- package/src/entities/social-account.entity.ts +0 -96
- package/src/entities/storage-lock.entity.ts +0 -39
- package/src/entities/trusted-device.entity.ts +0 -112
- package/src/entities/user.entity.ts +0 -243
- package/src/entities/verification-token.entity.ts +0 -141
- package/src/enums/auth-audit-event-type.enum.ts +0 -360
- package/src/enums/error-codes.enum.ts +0 -420
- package/src/enums/mfa-method.enum.ts +0 -97
- package/src/enums/risk-factor.enum.ts +0 -111
- package/src/exceptions/nauth.exception.ts +0 -231
- package/src/handlers/auth.handler.ts +0 -260
- package/src/handlers/client-info.handler.ts +0 -101
- package/src/handlers/csrf.handler.ts +0 -156
- package/src/handlers/token-delivery.handler.ts +0 -118
- package/src/index.ts +0 -118
- package/src/interfaces/client-info.interface.ts +0 -85
- package/src/interfaces/config.interface.ts +0 -2135
- package/src/interfaces/entities.interface.ts +0 -226
- package/src/interfaces/index.ts +0 -15
- package/src/interfaces/logger.interface.ts +0 -283
- package/src/interfaces/mfa-provider.interface.ts +0 -154
- package/src/interfaces/oauth.interface.ts +0 -148
- package/src/interfaces/provider.interface.ts +0 -47
- package/src/interfaces/social-auth-provider.interface.ts +0 -131
- package/src/interfaces/storage-adapter.interface.ts +0 -82
- package/src/interfaces/template.interface.ts +0 -510
- package/src/interfaces/token-verifier.interface.ts +0 -110
- package/src/internal.ts +0 -178
- package/src/platform/interfaces.ts +0 -299
- package/src/schemas/auth-config.schema.ts +0 -646
- package/src/services/adaptive-mfa-decision.service.spec.ts +0 -1058
- package/src/services/adaptive-mfa-decision.service.ts +0 -457
- package/src/services/auth-audit.service.spec.ts +0 -675
- package/src/services/auth-audit.service.ts +0 -558
- package/src/services/auth-challenge-helper.service.spec.ts +0 -3227
- package/src/services/auth-challenge-helper.service.ts +0 -825
- package/src/services/auth-flow-context-builder.service.ts +0 -520
- package/src/services/auth-flow-rules.ts +0 -202
- package/src/services/auth-flow-state-definitions.ts +0 -190
- package/src/services/auth-flow-state-machine.service.ts +0 -207
- package/src/services/auth-flow-state-machine.types.ts +0 -316
- package/src/services/auth.service.spec.ts +0 -4195
- package/src/services/auth.service.ts +0 -3727
- package/src/services/challenge.service.spec.ts +0 -1363
- package/src/services/challenge.service.ts +0 -696
- package/src/services/client-info.service.spec.ts +0 -572
- package/src/services/client-info.service.ts +0 -374
- package/src/services/csrf.service.ts +0 -54
- package/src/services/email-verification.service.spec.ts +0 -1229
- package/src/services/email-verification.service.ts +0 -578
- package/src/services/geo-location.service.spec.ts +0 -603
- package/src/services/geo-location.service.ts +0 -599
- package/src/services/index.ts +0 -13
- package/src/services/jwt.service.spec.ts +0 -882
- package/src/services/jwt.service.ts +0 -621
- package/src/services/mfa-base.service.spec.ts +0 -246
- package/src/services/mfa-base.service.ts +0 -611
- package/src/services/mfa.service.spec.ts +0 -693
- package/src/services/mfa.service.ts +0 -960
- package/src/services/password.service.spec.ts +0 -166
- package/src/services/password.service.ts +0 -309
- package/src/services/phone-verification.service.spec.ts +0 -1120
- package/src/services/phone-verification.service.ts +0 -751
- package/src/services/risk-detection.service.spec.ts +0 -1292
- package/src/services/risk-detection.service.ts +0 -1012
- package/src/services/risk-scoring.service.spec.ts +0 -204
- package/src/services/risk-scoring.service.ts +0 -131
- package/src/services/session.service.spec.ts +0 -1293
- package/src/services/session.service.ts +0 -803
- package/src/services/social-account.service.spec.ts +0 -725
- package/src/services/social-auth-base.service.spec.ts +0 -418
- package/src/services/social-auth-base.service.ts +0 -581
- package/src/services/social-auth.service.spec.ts +0 -238
- package/src/services/social-auth.service.ts +0 -436
- package/src/services/social-provider-registry.service.spec.ts +0 -238
- package/src/services/social-provider-registry.service.ts +0 -122
- package/src/services/trusted-device.service.spec.ts +0 -505
- package/src/services/trusted-device.service.ts +0 -339
- package/src/storage/account-lockout-storage.service.spec.ts +0 -310
- package/src/storage/account-lockout-storage.service.ts +0 -89
- package/src/storage/index.ts +0 -3
- package/src/storage/memory-storage.adapter.ts +0 -443
- package/src/storage/rate-limit-storage.service.spec.ts +0 -247
- package/src/storage/rate-limit-storage.service.ts +0 -38
- package/src/templates/html-template.engine.spec.ts +0 -161
- package/src/templates/html-template.engine.ts +0 -688
- package/src/templates/index.ts +0 -7
- package/src/utils/common-passwords.spec.ts +0 -230
- package/src/utils/common-passwords.ts +0 -170
- package/src/utils/context-storage.ts +0 -188
- package/src/utils/cookie-names.util.ts +0 -67
- package/src/utils/cookies.util.ts +0 -94
- package/src/utils/index.ts +0 -12
- package/src/utils/ip-extractor.spec.ts +0 -330
- package/src/utils/ip-extractor.ts +0 -220
- package/src/utils/nauth-logger.spec.ts +0 -388
- package/src/utils/nauth-logger.ts +0 -215
- package/src/utils/pii-redactor.spec.ts +0 -130
- package/src/utils/pii-redactor.ts +0 -288
- package/src/utils/setup/get-repositories.ts +0 -140
- package/src/utils/setup/init-services.ts +0 -422
- package/src/utils/setup/init-social.ts +0 -189
- package/src/utils/setup/init-storage.ts +0 -94
- package/src/utils/setup/register-mfa.ts +0 -165
- package/src/utils/setup/run-nauth-migrations.ts +0 -61
- package/src/utils/token-delivery-policy.ts +0 -38
- package/src/validators/template.validator.ts +0 -219
- package/tsconfig.json +0 -37
- package/tsconfig.lint.json +0 -6
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
import { BaseSocialAuthProviderService } from './social-auth-base.service';
|
|
2
|
-
import { AuthService } from './auth.service';
|
|
3
|
-
import { SocialAuthService } from './social-auth.service';
|
|
4
|
-
import { JwtService } from './jwt.service';
|
|
5
|
-
import { SessionService } from './session.service';
|
|
6
|
-
import { AuthChallengeHelperService } from './auth-challenge-helper.service';
|
|
7
|
-
import { ClientInfoService } from './client-info.service';
|
|
8
|
-
import { PhoneVerificationService } from './phone-verification.service';
|
|
9
|
-
import { AuthAuditService } from './auth-audit.service';
|
|
10
|
-
import { NAuthConfig } from '../interfaces/config.interface';
|
|
11
|
-
import { NAuthLogger } from '../utils/nauth-logger';
|
|
12
|
-
import { OAuthUserProfile } from '../interfaces/oauth.interface';
|
|
13
|
-
import { NAuthException } from '../exceptions/nauth.exception';
|
|
14
|
-
import { AuthErrorCode } from '../enums/error-codes.enum';
|
|
15
|
-
import { IUser } from '../interfaces/entities.interface';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Test implementation of BaseSocialAuthProviderService
|
|
19
|
-
*/
|
|
20
|
-
class TestSocialAuthProviderService extends BaseSocialAuthProviderService {
|
|
21
|
-
readonly providerName = 'test';
|
|
22
|
-
|
|
23
|
-
async getAuthUrl(state?: string): Promise<string> {
|
|
24
|
-
return `https://test.com/auth?state=${state || 'generated-state'}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
protected async getOAuthProfile(code: string, _state: string): Promise<OAuthUserProfile> {
|
|
28
|
-
return {
|
|
29
|
-
id: 'test-user-id',
|
|
30
|
-
email: 'user@example.com',
|
|
31
|
-
firstName: 'John',
|
|
32
|
-
lastName: 'Doe',
|
|
33
|
-
picture: null,
|
|
34
|
-
verified: true,
|
|
35
|
-
raw: {},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
protected async verifyNativeToken(
|
|
40
|
-
idToken: string,
|
|
41
|
-
_accessToken?: string,
|
|
42
|
-
_profileData?: unknown,
|
|
43
|
-
): Promise<OAuthUserProfile> {
|
|
44
|
-
return {
|
|
45
|
-
id: 'test-user-id',
|
|
46
|
-
email: 'user@example.com',
|
|
47
|
-
firstName: 'John',
|
|
48
|
-
lastName: 'Doe',
|
|
49
|
-
picture: null,
|
|
50
|
-
verified: true,
|
|
51
|
-
raw: {},
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Base Social Auth Provider Service Unit Tests
|
|
58
|
-
*
|
|
59
|
-
* Tests shared functionality in BaseSocialAuthProviderService including
|
|
60
|
-
* OAuth callback handling, token verification, and account linking.
|
|
61
|
-
* Uses direct instantiation, no NestJS dependencies.
|
|
62
|
-
*/
|
|
63
|
-
describe('BaseSocialAuthProviderService', () => {
|
|
64
|
-
let service: TestSocialAuthProviderService;
|
|
65
|
-
let mockConfig: NAuthConfig;
|
|
66
|
-
let mockLogger: NAuthLogger;
|
|
67
|
-
let mockAuthService: jest.Mocked<AuthService>;
|
|
68
|
-
let mockSocialAuthService: jest.Mocked<SocialAuthService>;
|
|
69
|
-
let mockJwtService: jest.Mocked<JwtService>;
|
|
70
|
-
let mockSessionService: jest.Mocked<SessionService>;
|
|
71
|
-
let mockChallengeHelper: jest.Mocked<AuthChallengeHelperService>;
|
|
72
|
-
let mockClientInfoService: jest.Mocked<ClientInfoService>;
|
|
73
|
-
let mockStateStore: Map<string, { timestamp: number; provider: string }>;
|
|
74
|
-
let mockPhoneVerificationService: jest.Mocked<PhoneVerificationService>;
|
|
75
|
-
let mockAuditService: jest.Mocked<AuthAuditService>;
|
|
76
|
-
let mockUser: IUser;
|
|
77
|
-
|
|
78
|
-
beforeEach(() => {
|
|
79
|
-
mockLogger = {
|
|
80
|
-
log: jest.fn(),
|
|
81
|
-
error: jest.fn(),
|
|
82
|
-
warn: jest.fn(),
|
|
83
|
-
debug: jest.fn(),
|
|
84
|
-
} as any;
|
|
85
|
-
|
|
86
|
-
mockConfig = {
|
|
87
|
-
jwt: {
|
|
88
|
-
accessToken: {
|
|
89
|
-
secret: 'test-secret',
|
|
90
|
-
expiresIn: 3600,
|
|
91
|
-
},
|
|
92
|
-
refreshToken: {
|
|
93
|
-
secret: 'test-refresh-secret',
|
|
94
|
-
expiresIn: 2592000,
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
social: {
|
|
98
|
-
test: {
|
|
99
|
-
enabled: true,
|
|
100
|
-
allowSignup: true,
|
|
101
|
-
autoLink: false,
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
} as NAuthConfig;
|
|
105
|
-
|
|
106
|
-
mockAuthService = {
|
|
107
|
-
getUserById: jest.fn(),
|
|
108
|
-
getUserByEmail: jest.fn(),
|
|
109
|
-
createSocialUser: jest.fn(),
|
|
110
|
-
} as any;
|
|
111
|
-
|
|
112
|
-
mockSocialAuthService = {
|
|
113
|
-
findSocialAccountByProvider: jest.fn(),
|
|
114
|
-
createOrUpdateSocialAccount: jest.fn(),
|
|
115
|
-
} as any;
|
|
116
|
-
|
|
117
|
-
mockJwtService = {
|
|
118
|
-
generateTokens: jest.fn().mockResolvedValue({
|
|
119
|
-
accessToken: 'access-token',
|
|
120
|
-
refreshToken: 'refresh-token',
|
|
121
|
-
}),
|
|
122
|
-
generateTokenPair: jest.fn().mockResolvedValue({
|
|
123
|
-
accessToken: 'access-token',
|
|
124
|
-
refreshToken: 'refresh-token',
|
|
125
|
-
}),
|
|
126
|
-
hashToken: jest.fn((token: string) => `hashed-${token}`),
|
|
127
|
-
decodeToken: jest.fn((token: string) => ({
|
|
128
|
-
payload: { exp: Math.floor(Date.now() / 1000) + 3600 },
|
|
129
|
-
})),
|
|
130
|
-
} as any;
|
|
131
|
-
|
|
132
|
-
mockSessionService = {
|
|
133
|
-
createSession: jest.fn().mockResolvedValue({ id: 'session-id' }),
|
|
134
|
-
revokeAllUserSessions: jest.fn().mockResolvedValue(0),
|
|
135
|
-
updateTokens: jest.fn().mockResolvedValue(undefined),
|
|
136
|
-
} as any;
|
|
137
|
-
|
|
138
|
-
mockChallengeHelper = {
|
|
139
|
-
determineAuthResponse: jest.fn().mockResolvedValue({
|
|
140
|
-
user: {
|
|
141
|
-
sub: 'user-123',
|
|
142
|
-
email: 'user@example.com',
|
|
143
|
-
},
|
|
144
|
-
accessToken: 'access-token',
|
|
145
|
-
refreshToken: 'refresh-token',
|
|
146
|
-
accessTokenExpiresAt: Date.now() + 3600000,
|
|
147
|
-
refreshTokenExpiresAt: Date.now() + 2592000000,
|
|
148
|
-
}),
|
|
149
|
-
} as any;
|
|
150
|
-
mockClientInfoService = {
|
|
151
|
-
getClientInfo: jest.fn().mockResolvedValue({
|
|
152
|
-
ipAddress: '192.168.1.1',
|
|
153
|
-
userAgent: 'test-agent',
|
|
154
|
-
}),
|
|
155
|
-
get: jest.fn().mockReturnValue({
|
|
156
|
-
ipAddress: '192.168.1.1',
|
|
157
|
-
userAgent: 'test-agent',
|
|
158
|
-
}),
|
|
159
|
-
} as any;
|
|
160
|
-
|
|
161
|
-
mockStateStore = new Map();
|
|
162
|
-
mockPhoneVerificationService = {} as any;
|
|
163
|
-
mockAuditService = {
|
|
164
|
-
recordEvent: jest.fn(),
|
|
165
|
-
} as any;
|
|
166
|
-
|
|
167
|
-
mockUser = {
|
|
168
|
-
id: 1,
|
|
169
|
-
sub: 'user-123',
|
|
170
|
-
email: 'user@example.com',
|
|
171
|
-
isEmailVerified: true,
|
|
172
|
-
} as IUser;
|
|
173
|
-
|
|
174
|
-
service = new TestSocialAuthProviderService(
|
|
175
|
-
mockConfig,
|
|
176
|
-
mockLogger,
|
|
177
|
-
mockAuthService,
|
|
178
|
-
mockSocialAuthService,
|
|
179
|
-
mockJwtService,
|
|
180
|
-
mockSessionService,
|
|
181
|
-
mockChallengeHelper,
|
|
182
|
-
mockClientInfoService,
|
|
183
|
-
mockStateStore,
|
|
184
|
-
mockPhoneVerificationService,
|
|
185
|
-
mockAuditService,
|
|
186
|
-
);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
afterEach(() => {
|
|
190
|
-
jest.clearAllMocks();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
describe('getProviderConfig', () => {
|
|
194
|
-
it('should return provider config', () => {
|
|
195
|
-
const config = (service as any).getProviderConfig();
|
|
196
|
-
|
|
197
|
-
expect(config).toEqual({
|
|
198
|
-
enabled: true,
|
|
199
|
-
allowSignup: true,
|
|
200
|
-
autoLink: false,
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('should return null when social config is missing', () => {
|
|
205
|
-
mockConfig.social = undefined;
|
|
206
|
-
const newService = new TestSocialAuthProviderService(
|
|
207
|
-
mockConfig,
|
|
208
|
-
mockLogger,
|
|
209
|
-
mockAuthService,
|
|
210
|
-
mockSocialAuthService,
|
|
211
|
-
mockJwtService,
|
|
212
|
-
mockSessionService,
|
|
213
|
-
mockChallengeHelper,
|
|
214
|
-
mockClientInfoService,
|
|
215
|
-
mockStateStore,
|
|
216
|
-
mockPhoneVerificationService,
|
|
217
|
-
mockAuditService,
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
const config = (newService as any).getProviderConfig();
|
|
221
|
-
|
|
222
|
-
expect(config).toBeNull();
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
describe('validateState', () => {
|
|
227
|
-
it('should validate state parameter', () => {
|
|
228
|
-
const state = 'valid-state';
|
|
229
|
-
mockStateStore.set(state, {
|
|
230
|
-
timestamp: Date.now(),
|
|
231
|
-
provider: 'test',
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
(service as any).validateState(state);
|
|
235
|
-
|
|
236
|
-
expect(mockStateStore.has(state)).toBe(false); // Should be deleted after validation
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('should throw error when state is not found', () => {
|
|
240
|
-
try {
|
|
241
|
-
(service as any).validateState('invalid-state');
|
|
242
|
-
fail('Should have thrown NAuthException');
|
|
243
|
-
} catch (error) {
|
|
244
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
245
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.VALIDATION_FAILED);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('should throw error when state provider mismatch', () => {
|
|
250
|
-
const state = 'valid-state';
|
|
251
|
-
mockStateStore.set(state, {
|
|
252
|
-
timestamp: Date.now(),
|
|
253
|
-
provider: 'different-provider',
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
(service as any).validateState(state);
|
|
258
|
-
fail('Should have thrown NAuthException');
|
|
259
|
-
} catch (error) {
|
|
260
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
261
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.VALIDATION_FAILED);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should throw error when state is expired', () => {
|
|
266
|
-
const state = 'expired-state';
|
|
267
|
-
mockStateStore.set(state, {
|
|
268
|
-
timestamp: Date.now() - 6 * 60 * 1000, // 6 minutes ago
|
|
269
|
-
provider: 'test',
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
try {
|
|
273
|
-
(service as any).validateState(state);
|
|
274
|
-
fail('Should have thrown NAuthException');
|
|
275
|
-
} catch (error) {
|
|
276
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
277
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.CHALLENGE_EXPIRED);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe('generateState', () => {
|
|
283
|
-
it('should generate state and store it', () => {
|
|
284
|
-
const state = (service as any).generateState();
|
|
285
|
-
|
|
286
|
-
expect(state).toBeDefined();
|
|
287
|
-
expect(typeof state).toBe('string');
|
|
288
|
-
expect(mockStateStore.has(state)).toBe(true);
|
|
289
|
-
expect(mockStateStore.get(state)?.provider).toBe('test');
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
describe('handleCallback', () => {
|
|
294
|
-
it('should handle OAuth callback and return auth response', async () => {
|
|
295
|
-
const state = 'valid-state';
|
|
296
|
-
mockStateStore.set(state, {
|
|
297
|
-
timestamp: Date.now(),
|
|
298
|
-
provider: 'test',
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
mockSocialAuthService.findSocialAccountByProvider.mockResolvedValue(null);
|
|
302
|
-
mockAuthService.getUserByEmail.mockResolvedValue(null);
|
|
303
|
-
mockAuthService.createSocialUser.mockResolvedValue(mockUser);
|
|
304
|
-
mockSocialAuthService.createOrUpdateSocialAccount.mockResolvedValue(undefined);
|
|
305
|
-
|
|
306
|
-
const result = await service.handleCallback('code', state);
|
|
307
|
-
|
|
308
|
-
expect(result).toBeDefined();
|
|
309
|
-
expect(mockAuthService.createSocialUser).toHaveBeenCalled();
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('should throw error when provider config is missing', async () => {
|
|
313
|
-
mockConfig.social = undefined;
|
|
314
|
-
const newService = new TestSocialAuthProviderService(
|
|
315
|
-
mockConfig,
|
|
316
|
-
mockLogger,
|
|
317
|
-
mockAuthService,
|
|
318
|
-
mockSocialAuthService,
|
|
319
|
-
mockJwtService,
|
|
320
|
-
mockSessionService,
|
|
321
|
-
mockChallengeHelper,
|
|
322
|
-
mockClientInfoService,
|
|
323
|
-
mockStateStore,
|
|
324
|
-
mockPhoneVerificationService,
|
|
325
|
-
mockAuditService,
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
try {
|
|
329
|
-
await newService.handleCallback('code', 'state');
|
|
330
|
-
fail('Should have thrown NAuthException');
|
|
331
|
-
} catch (error) {
|
|
332
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
333
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.SOCIAL_CONFIG_MISSING);
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe('verifyToken', () => {
|
|
339
|
-
it('should verify native token and return auth response', async () => {
|
|
340
|
-
mockSocialAuthService.findSocialAccountByProvider.mockResolvedValue(null);
|
|
341
|
-
mockAuthService.getUserByEmail.mockResolvedValue(null);
|
|
342
|
-
mockAuthService.createSocialUser.mockResolvedValue(mockUser);
|
|
343
|
-
mockSocialAuthService.createOrUpdateSocialAccount.mockResolvedValue(undefined);
|
|
344
|
-
|
|
345
|
-
const result = await service.verifyToken('id-token');
|
|
346
|
-
|
|
347
|
-
expect(result).toBeDefined();
|
|
348
|
-
expect(mockAuthService.createSocialUser).toHaveBeenCalled();
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('should throw error when provider is not enabled', async () => {
|
|
352
|
-
(mockConfig.social as any).test.enabled = false;
|
|
353
|
-
const newService = new TestSocialAuthProviderService(
|
|
354
|
-
mockConfig,
|
|
355
|
-
mockLogger,
|
|
356
|
-
mockAuthService,
|
|
357
|
-
mockSocialAuthService,
|
|
358
|
-
mockJwtService,
|
|
359
|
-
mockSessionService,
|
|
360
|
-
mockChallengeHelper,
|
|
361
|
-
mockClientInfoService,
|
|
362
|
-
mockStateStore,
|
|
363
|
-
mockPhoneVerificationService,
|
|
364
|
-
mockAuditService,
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
try {
|
|
368
|
-
await newService.verifyToken('id-token');
|
|
369
|
-
fail('Should have thrown NAuthException');
|
|
370
|
-
} catch (error) {
|
|
371
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
372
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.SOCIAL_CONFIG_MISSING);
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
describe('linkAccount', () => {
|
|
378
|
-
it('should link social account to existing user', async () => {
|
|
379
|
-
const state = 'valid-state';
|
|
380
|
-
mockStateStore.set(state, {
|
|
381
|
-
timestamp: Date.now(),
|
|
382
|
-
provider: 'test',
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
mockAuthService.getUserById.mockResolvedValue(mockUser);
|
|
386
|
-
mockSocialAuthService.findSocialAccountByProvider.mockResolvedValue(null);
|
|
387
|
-
mockSocialAuthService.createOrUpdateSocialAccount.mockResolvedValue(undefined);
|
|
388
|
-
|
|
389
|
-
const result = await service.linkAccount('user-123', 'code', state);
|
|
390
|
-
|
|
391
|
-
expect(result.message).toContain('account linked successfully');
|
|
392
|
-
expect(mockSocialAuthService.createOrUpdateSocialAccount).toHaveBeenCalled();
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
it('should throw error when account is already linked', async () => {
|
|
396
|
-
const state = 'valid-state';
|
|
397
|
-
mockStateStore.set(state, {
|
|
398
|
-
timestamp: Date.now(),
|
|
399
|
-
provider: 'test',
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
mockAuthService.getUserById.mockResolvedValue(mockUser);
|
|
403
|
-
mockSocialAuthService.findSocialAccountByProvider.mockResolvedValue({
|
|
404
|
-
id: 1,
|
|
405
|
-
provider: 'test',
|
|
406
|
-
providerUserId: 'test-user-id',
|
|
407
|
-
} as any);
|
|
408
|
-
|
|
409
|
-
try {
|
|
410
|
-
await service.linkAccount('user-123', 'code', state);
|
|
411
|
-
fail('Should have thrown NAuthException');
|
|
412
|
-
} catch (error) {
|
|
413
|
-
expect(error).toBeInstanceOf(NAuthException);
|
|
414
|
-
expect((error as NAuthException).code).toBe(AuthErrorCode.SOCIAL_ACCOUNT_LINKED);
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
});
|
|
418
|
-
});
|