@mudrichenkoevgeny/web-platform-sdk-core-security 0.0.1 → 0.1.2

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.
Files changed (106) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +110 -110
  3. package/dist/di/security-component.d.ts +56 -0
  4. package/dist/di/security-component.d.ts.map +1 -0
  5. package/dist/di/security-component.test.d.ts +2 -0
  6. package/dist/di/security-component.test.d.ts.map +1 -0
  7. package/dist/error/model/security-error.d.ts +117 -0
  8. package/dist/error/model/security-error.d.ts.map +1 -0
  9. package/dist/error/model/security-error.test.d.ts +2 -0
  10. package/dist/error/model/security-error.test.d.ts.map +1 -0
  11. package/dist/error/parser/security-error-parser.d.ts +37 -0
  12. package/dist/error/parser/security-error-parser.d.ts.map +1 -0
  13. package/dist/error/parser/security-error-parser.test.d.ts +2 -0
  14. package/dist/error/parser/security-error-parser.test.d.ts.map +1 -0
  15. package/dist/index.d.ts +20 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +11946 -4898
  18. package/dist/integration/SecuritySettingsIntegration.test.d.ts +2 -0
  19. package/dist/integration/SecuritySettingsIntegration.test.d.ts.map +1 -0
  20. package/dist/mock/di/security-component-mock.d.ts +9 -0
  21. package/dist/mock/di/security-component-mock.d.ts.map +1 -0
  22. package/dist/mock/network/open-security-settings-api-mock.d.ts +25 -0
  23. package/dist/mock/network/open-security-settings-api-mock.d.ts.map +1 -0
  24. package/dist/mock/repository/open-security-settings-repository-mock.d.ts +28 -0
  25. package/dist/mock/repository/open-security-settings-repository-mock.d.ts.map +1 -0
  26. package/dist/mock/storage/open-security-settings-storage-mock.d.ts +31 -0
  27. package/dist/mock/storage/open-security-settings-storage-mock.d.ts.map +1 -0
  28. package/dist/mock/usecase/validate-password-use-case-mock.d.ts +22 -0
  29. package/dist/mock/usecase/validate-password-use-case-mock.d.ts.map +1 -0
  30. package/dist/network/api/security-settings/fetch-open-security-settings-api.d.ts +22 -0
  31. package/dist/network/api/security-settings/fetch-open-security-settings-api.d.ts.map +1 -0
  32. package/dist/network/api/security-settings/fetch-open-security-settings-api.test.d.ts +2 -0
  33. package/dist/network/api/security-settings/fetch-open-security-settings-api.test.d.ts.map +1 -0
  34. package/dist/network/api/security-settings/open-security-settings-api.d.ts +14 -0
  35. package/dist/network/api/security-settings/open-security-settings-api.d.ts.map +1 -0
  36. package/dist/network/api/security-settings/security-settings-dto-mapping.test.d.ts +2 -0
  37. package/dist/network/api/security-settings/security-settings-dto-mapping.test.d.ts.map +1 -0
  38. package/dist/network/contract/security-web-socket-event-types.d.ts +2 -0
  39. package/dist/network/contract/security-web-socket-event-types.d.ts.map +1 -0
  40. package/dist/network/websocket/message-handler/security-web-socket-message-handler.d.ts +15 -0
  41. package/dist/network/websocket/message-handler/security-web-socket-message-handler.d.ts.map +1 -0
  42. package/dist/network/websocket/message-handler/security-web-socket-message-handler.test.d.ts +2 -0
  43. package/dist/network/websocket/message-handler/security-web-socket-message-handler.test.d.ts.map +1 -0
  44. package/dist/repository/open-security-settings-repository-impl.d.ts +57 -0
  45. package/dist/repository/open-security-settings-repository-impl.d.ts.map +1 -0
  46. package/dist/repository/open-security-settings-repository-impl.test.d.ts +2 -0
  47. package/dist/repository/open-security-settings-repository-impl.test.d.ts.map +1 -0
  48. package/dist/repository/open-security-settings-repository.d.ts +35 -0
  49. package/dist/repository/open-security-settings-repository.d.ts.map +1 -0
  50. package/dist/storage/security-settings/encrypted-open-security-settings-storage.d.ts +32 -0
  51. package/dist/storage/security-settings/encrypted-open-security-settings-storage.d.ts.map +1 -0
  52. package/dist/storage/security-settings/encrypted-open-security-settings-storage.test.d.ts +2 -0
  53. package/dist/storage/security-settings/encrypted-open-security-settings-storage.test.d.ts.map +1 -0
  54. package/dist/storage/security-settings/open-security-settings-storage.d.ts +23 -0
  55. package/dist/storage/security-settings/open-security-settings-storage.d.ts.map +1 -0
  56. package/dist/usecase/observe-open-security-settings-use-case.d.ts +19 -0
  57. package/dist/usecase/observe-open-security-settings-use-case.d.ts.map +1 -0
  58. package/dist/usecase/observe-open-security-settings-use-case.test.d.ts +2 -0
  59. package/dist/usecase/observe-open-security-settings-use-case.test.d.ts.map +1 -0
  60. package/dist/usecase/refresh-open-security-settings-use-case.d.ts +22 -0
  61. package/dist/usecase/refresh-open-security-settings-use-case.d.ts.map +1 -0
  62. package/dist/usecase/refresh-open-security-settings-use-case.test.d.ts +2 -0
  63. package/dist/usecase/refresh-open-security-settings-use-case.test.d.ts.map +1 -0
  64. package/dist/usecase/validate-password-use-case.d.ts +26 -0
  65. package/dist/usecase/validate-password-use-case.d.ts.map +1 -0
  66. package/dist/usecase/validate-password-use-case.test.d.ts +2 -0
  67. package/dist/usecase/validate-password-use-case.test.d.ts.map +1 -0
  68. package/package.json +16 -7
  69. package/src/di/security-component.test.ts +0 -33
  70. package/src/di/security-component.ts +0 -86
  71. package/src/domain/model/open-security-settings.ts +0 -79
  72. package/src/domain/model/password-policy-validator.test.ts +0 -96
  73. package/src/domain/model/password-policy-validator.ts +0 -63
  74. package/src/error/model/security-error.test.ts +0 -65
  75. package/src/error/model/security-error.ts +0 -182
  76. package/src/error/naming/client-security-error-codes.ts +0 -21
  77. package/src/error/parser/security-error-parser.test.ts +0 -87
  78. package/src/error/parser/security-error-parser.ts +0 -138
  79. package/src/index.ts +0 -24
  80. package/src/locales/en/strings.ts +0 -67
  81. package/src/locales/index.ts +0 -2
  82. package/src/locales/ru/strings.ts +0 -35
  83. package/src/mock/di/security-component-mock.ts +0 -35
  84. package/src/mock/domain/model/open-security-settings-mock.ts +0 -52
  85. package/src/mock/network/model/open-security-settings-payload-mock.ts +0 -28
  86. package/src/mock/network/open-security-settings-api-mock.ts +0 -38
  87. package/src/mock/repository/open-security-settings-repository-mock.ts +0 -62
  88. package/src/mock/storage/open-security-settings-storage-mock.ts +0 -45
  89. package/src/mock/usecase/validate-password-use-case-mock.ts +0 -31
  90. package/src/network/contract/security-web-socket-event-types.ts +0 -7
  91. package/src/network/security-settings/fetch-open-security-settings-api.test.ts +0 -51
  92. package/src/network/security-settings/fetch-open-security-settings-api.ts +0 -30
  93. package/src/network/security-settings/open-security-settings-api.ts +0 -15
  94. package/src/network/websocket/message-handler/security-web-socket-message-handler.test.ts +0 -19
  95. package/src/network/websocket/message-handler/security-web-socket-message-handler.ts +0 -19
  96. package/src/repository/open-security-settings-repository-impl.test.ts +0 -112
  97. package/src/repository/open-security-settings-repository-impl.ts +0 -151
  98. package/src/repository/open-security-settings-repository.ts +0 -39
  99. package/src/storage/security-settings/encrypted-open-security-settings-storage.test.ts +0 -71
  100. package/src/storage/security-settings/encrypted-open-security-settings-storage.ts +0 -65
  101. package/src/storage/security-settings/open-security-settings-storage.ts +0 -25
  102. package/src/usecase/refresh-open-security-settings-use-case.ts +0 -26
  103. package/src/usecase/security-use-cases.test.ts +0 -67
  104. package/src/usecase/validate-password-use-case.ts +0 -76
  105. package/tsconfig.json +0 -16
  106. package/vite.config.ts +0 -50
@@ -1,33 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import {
3
- WebSocketServiceMock,
4
- HttpClient,
5
- EncryptedSettingsMock,
6
- DeviceInfoProviderMock
7
- } from '@mudrichenkoevgeny/web-platform-sdk-core-common'
8
- import { SecurityComponent } from '@/di/security-component'
9
-
10
- describe('SecurityComponent', () => {
11
- it('initializes all modules and exposes dependencies', () => {
12
- const ws = new WebSocketServiceMock()
13
- const httpClient = new HttpClient({
14
- baseUrl: 'https://api.example.com',
15
- deviceInfoProvider: new DeviceInfoProviderMock()
16
- })
17
- const encryptedSettings = new EncryptedSettingsMock()
18
-
19
- const component = new SecurityComponent({
20
- webSocketService: ws,
21
- httpClient,
22
- encryptedSettings
23
- })
24
-
25
- expect(component.securitySettingsStorage).toBeDefined()
26
- expect(component.openSecuritySettingsApi).toBeDefined()
27
- expect(component.securitySettingsRepository).toBeDefined()
28
- expect(component.passwordPolicyValidator).toBeDefined()
29
- expect(component.refreshSecuritySettingsUseCase).toBeDefined()
30
- expect(component.validatePasswordUseCase).toBeDefined()
31
- expect(component.securityWebSocketMessageHandler).toBeDefined()
32
- })
33
- })
@@ -1,86 +0,0 @@
1
- import type { EncryptedSettings, HttpClient, WebSocketService } from '@mudrichenkoevgeny/web-platform-sdk-core-common'
2
- import type { OpenSecuritySettingsStorage } from '@/storage/security-settings/open-security-settings-storage'
3
- import { EncryptedOpenSecuritySettingsStorage } from '@/storage/security-settings/encrypted-open-security-settings-storage'
4
- import type { OpenSecuritySettingsApi } from '@/network/security-settings/open-security-settings-api'
5
- import { FetchOpenSecuritySettingsApi } from '@/network/security-settings/fetch-open-security-settings-api'
6
- import type { OpenSecuritySettingsRepository } from '@/repository/open-security-settings-repository'
7
- import { OpenSecuritySettingsRepositoryImpl } from '@/repository/open-security-settings-repository-impl'
8
- import { PasswordPolicyValidator } from '@/domain/model/password-policy-validator'
9
- import { RefreshOpenSecuritySettingsUseCase } from '@/usecase/refresh-open-security-settings-use-case'
10
- import { ValidatePasswordUseCase } from '@/usecase/validate-password-use-case'
11
- import { SecurityWebSocketMessageHandler } from '@/network/websocket/message-handler/security-web-socket-message-handler'
12
-
13
- /**
14
- * Configuration options required to instantiate {@link SecurityComponent}.
15
- */
16
- export interface SecurityComponentConfig {
17
- /** Global WebSocket service. */
18
- webSocketService: WebSocketService
19
- /** Pre-configured HTTP client for REST calls. */
20
- httpClient: HttpClient
21
- /** Encrypted storage backend. */
22
- encryptedSettings: EncryptedSettings
23
- /** Optional mock overrides for tests. */
24
- openSecuritySettingsApi?: OpenSecuritySettingsApi
25
- /** Optional mock overrides for tests. */
26
- openSecuritySettingsStorage?: OpenSecuritySettingsStorage
27
- /** Optional mock overrides for tests. */
28
- passwordPolicyValidator?: PasswordPolicyValidator
29
- }
30
-
31
- /**
32
- * Root dependency injection container for `core-security` module.
33
- *
34
- * Assembles storage, networking, repositories, and password policy validation.
35
- */
36
- export class SecurityComponent {
37
- /** Core persistence interface for open security settings. */
38
- public readonly securitySettingsStorage: OpenSecuritySettingsStorage
39
- /** HTTP REST client API for open security settings. */
40
- public readonly openSecuritySettingsApi: OpenSecuritySettingsApi
41
- /** Central repository for open security settings. */
42
- public readonly securitySettingsRepository: OpenSecuritySettingsRepository
43
- /** Pure domain logic password policy validator. */
44
- public readonly passwordPolicyValidator: PasswordPolicyValidator
45
- /** Use case for forcing a network refresh of settings. */
46
- public readonly refreshSecuritySettingsUseCase: RefreshOpenSecuritySettingsUseCase
47
- /** Use case for validating password candidate strings against active policy. */
48
- public readonly validatePasswordUseCase: ValidatePasswordUseCase
49
- /** Handler offered to the shared WebSocket pipeline. */
50
- public readonly securityWebSocketMessageHandler: SecurityWebSocketMessageHandler
51
-
52
- /**
53
- * Constructs a new {@link SecurityComponent}.
54
- *
55
- * @param config - Container configuration holding global SDK dependencies
56
- */
57
- public constructor(config: SecurityComponentConfig) {
58
- this.securitySettingsStorage =
59
- config.openSecuritySettingsStorage ??
60
- new EncryptedOpenSecuritySettingsStorage(config.encryptedSettings)
61
-
62
- this.passwordPolicyValidator =
63
- config.passwordPolicyValidator ?? new PasswordPolicyValidator()
64
-
65
- this.openSecuritySettingsApi =
66
- config.openSecuritySettingsApi ??
67
- new FetchOpenSecuritySettingsApi(config.httpClient)
68
-
69
- this.securitySettingsRepository = new OpenSecuritySettingsRepositoryImpl(
70
- this.openSecuritySettingsApi,
71
- this.securitySettingsStorage,
72
- config.webSocketService
73
- )
74
-
75
- this.refreshSecuritySettingsUseCase = new RefreshOpenSecuritySettingsUseCase(
76
- this.securitySettingsRepository
77
- )
78
-
79
- this.validatePasswordUseCase = new ValidatePasswordUseCase(
80
- this.securitySettingsRepository,
81
- this.passwordPolicyValidator
82
- )
83
-
84
- this.securityWebSocketMessageHandler = new SecurityWebSocketMessageHandler()
85
- }
86
- }
@@ -1,79 +0,0 @@
1
- import type { OpenSecuritySettingsPayload } from '@mudrichenkoevgeny/shared-foundation'
2
-
3
- /** Password policy requirement constraints. */
4
- export interface OpenPasswordPolicy {
5
- /** Minimum required password character length. */
6
- readonly minLength: number
7
- /** Whether password must contain at least one letter. */
8
- readonly requireLetter: boolean
9
- /** Whether password must contain at least one uppercase letter. */
10
- readonly requireUpperCase: boolean
11
- /** Whether password must contain at least one lowercase letter. */
12
- readonly requireLowerCase: boolean
13
- /** Whether password must contain at least one digit character. */
14
- readonly requireDigit: boolean
15
- /** Whether password must contain at least one special character. */
16
- readonly requireSpecialChar: boolean
17
- }
18
-
19
- /** One-time password confirmation constraints. */
20
- export interface OtpConfirmation {
21
- /** Delay duration in seconds before requesting OTP resend. */
22
- readonly retryAfterSeconds: number
23
- /** Number of digit/symbol characters in OTP code. */
24
- readonly numberOfSymbols: number
25
- /** Validity duration in seconds before OTP code expires. */
26
- readonly expirationSeconds: number
27
- }
28
-
29
- /** Active open security settings domain model. */
30
- export interface OpenSecuritySettings {
31
- /** Password policy validation configuration. */
32
- readonly openPasswordPolicy: OpenPasswordPolicy
33
- /** OTP code confirmation parameters. */
34
- readonly otpConfirmation: OtpConfirmation
35
- }
36
-
37
- /**
38
- * Maps an {@link OpenSecuritySettingsPayload} server response object into an {@link OpenSecuritySettings} domain model.
39
- *
40
- * @param payload - Raw API response payload
41
- * @returns Mapped domain model
42
- */
43
- export const toOpenSecuritySettings = (payload: OpenSecuritySettingsPayload): OpenSecuritySettings => ({
44
- openPasswordPolicy: {
45
- minLength: payload.open_password_policy.min_length,
46
- requireLetter: payload.open_password_policy.require_letter,
47
- requireUpperCase: payload.open_password_policy.require_upper_case,
48
- requireLowerCase: payload.open_password_policy.require_lower_case,
49
- requireDigit: payload.open_password_policy.require_digit,
50
- requireSpecialChar: payload.open_password_policy.require_special_char
51
- },
52
- otpConfirmation: {
53
- retryAfterSeconds: payload.otp_confirmation.retry_after_seconds,
54
- numberOfSymbols: payload.otp_confirmation.number_of_symbols,
55
- expirationSeconds: payload.otp_confirmation.expiration_seconds
56
- }
57
- })
58
-
59
- /**
60
- * Maps an {@link OpenSecuritySettings} domain model into an {@link OpenSecuritySettingsPayload} server payload.
61
- *
62
- * @param settings - Security settings domain model
63
- * @returns Serialized API payload
64
- */
65
- export const toOpenSecuritySettingsPayload = (settings: OpenSecuritySettings): OpenSecuritySettingsPayload => ({
66
- open_password_policy: {
67
- min_length: settings.openPasswordPolicy.minLength,
68
- require_letter: settings.openPasswordPolicy.requireLetter,
69
- require_upper_case: settings.openPasswordPolicy.requireUpperCase,
70
- require_lower_case: settings.openPasswordPolicy.requireLowerCase,
71
- require_digit: settings.openPasswordPolicy.requireDigit,
72
- require_special_char: settings.openPasswordPolicy.requireSpecialChar
73
- },
74
- otp_confirmation: {
75
- retry_after_seconds: settings.otpConfirmation.retryAfterSeconds,
76
- number_of_symbols: settings.otpConfirmation.numberOfSymbols,
77
- expiration_seconds: settings.otpConfirmation.expirationSeconds
78
- }
79
- })
@@ -1,96 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { PasswordPolicyValidator } from '@/domain/model/password-policy-validator'
3
- import type { OpenPasswordPolicy } from '@/domain/model/open-security-settings'
4
-
5
- describe('PasswordPolicyValidator', () => {
6
- const validator = new PasswordPolicyValidator()
7
-
8
- const strictPolicy: OpenPasswordPolicy = {
9
- minLength: 8,
10
- requireLetter: true,
11
- requireUpperCase: true,
12
- requireLowerCase: true,
13
- requireDigit: true,
14
- requireSpecialChar: true
15
- }
16
-
17
- const relaxedPolicy: OpenPasswordPolicy = {
18
- minLength: 6,
19
- requireLetter: false,
20
- requireUpperCase: false,
21
- requireLowerCase: false,
22
- requireDigit: false,
23
- requireSpecialChar: false
24
- }
25
-
26
- it('validates successful password', () => {
27
- const result = validator.validate(strictPolicy, 'Valid123!')
28
- expect(result.success).toBe(true)
29
- })
30
-
31
- it('fails TOO_SHORT', () => {
32
- const result = validator.validate(strictPolicy, 'Val1!')
33
- expect(result.success).toBe(false)
34
- if (!result.success) {
35
- expect(result.reasons).toContain('TOO_SHORT')
36
- }
37
- })
38
-
39
- it('fails NO_LETTER', () => {
40
- const result = validator.validate(strictPolicy, '12345678!')
41
- expect(result.success).toBe(false)
42
- if (!result.success) {
43
- expect(result.reasons).toContain('NO_LETTER')
44
- expect(result.reasons).toContain('NO_UPPERCASE')
45
- expect(result.reasons).toContain('NO_LOWERCASE')
46
- }
47
- })
48
-
49
- it('fails NO_UPPERCASE', () => {
50
- const result = validator.validate(strictPolicy, 'valid123!')
51
- expect(result.success).toBe(false)
52
- if (!result.success) {
53
- expect(result.reasons).toContain('NO_UPPERCASE')
54
- }
55
- })
56
-
57
- it('fails NO_LOWERCASE', () => {
58
- const result = validator.validate(strictPolicy, 'VALID123!')
59
- expect(result.success).toBe(false)
60
- if (!result.success) {
61
- expect(result.reasons).toContain('NO_LOWERCASE')
62
- }
63
- })
64
-
65
- it('fails NO_DIGIT', () => {
66
- const result = validator.validate(strictPolicy, 'ValidPassword!')
67
- expect(result.success).toBe(false)
68
- if (!result.success) {
69
- expect(result.reasons).toContain('NO_DIGIT')
70
- }
71
- })
72
-
73
- it('fails NO_SPECIAL_CHAR', () => {
74
- const result = validator.validate(strictPolicy, 'Valid123')
75
- expect(result.success).toBe(false)
76
- if (!result.success) {
77
- expect(result.reasons).toContain('NO_SPECIAL_CHAR')
78
- }
79
- })
80
-
81
- it('passes relaxed policy with weak password', () => {
82
- const result = validator.validate(relaxedPolicy, '123456')
83
- expect(result.success).toBe(true)
84
- })
85
-
86
- it('returns multiple failure reasons simultaneously', () => {
87
- const result = validator.validate(strictPolicy, 'abc')
88
- expect(result.success).toBe(false)
89
- if (!result.success) {
90
- expect(result.reasons).toContain('TOO_SHORT')
91
- expect(result.reasons).toContain('NO_UPPERCASE')
92
- expect(result.reasons).toContain('NO_DIGIT')
93
- expect(result.reasons).toContain('NO_SPECIAL_CHAR')
94
- }
95
- })
96
- })
@@ -1,63 +0,0 @@
1
- import type { OpenPasswordPolicy } from '@/domain/model/open-security-settings'
2
-
3
- /** Represents individual reasons why a password might fail policy validation. */
4
- export type PasswordPolicyFailReason =
5
- | 'TOO_SHORT'
6
- | 'NO_LETTER'
7
- | 'NO_UPPERCASE'
8
- | 'NO_LOWERCASE'
9
- | 'NO_DIGIT'
10
- | 'NO_SPECIAL_CHAR'
11
- | 'TOO_COMMON'
12
-
13
- /** Result of a password policy validation check. */
14
- export type PasswordPolicyValidatorResult =
15
- | { readonly success: true }
16
- | { readonly success: false; readonly reasons: PasswordPolicyFailReason[] }
17
-
18
- /**
19
- * Validates a candidate password string against an {@link OpenPasswordPolicy}.
20
- */
21
- export class PasswordPolicyValidator {
22
- /**
23
- * Evaluates a password string against the rules defined in a policy.
24
- *
25
- * @param policy - Target password policy
26
- * @param password - Candidate string
27
- * @returns Validation result indicating success or failure reasons
28
- */
29
- public validate(policy: OpenPasswordPolicy, password: string): PasswordPolicyValidatorResult {
30
- const reasons: PasswordPolicyFailReason[] = []
31
-
32
- if (password.length < policy.minLength) {
33
- reasons.push('TOO_SHORT')
34
- }
35
-
36
- if (policy.requireLetter && !/[a-zA-Z]/.test(password)) {
37
- reasons.push('NO_LETTER')
38
- }
39
-
40
- if (policy.requireUpperCase && !/[A-Z]/.test(password)) {
41
- reasons.push('NO_UPPERCASE')
42
- }
43
-
44
- if (policy.requireLowerCase && !/[a-z]/.test(password)) {
45
- reasons.push('NO_LOWERCASE')
46
- }
47
-
48
- if (policy.requireDigit && !/[0-9]/.test(password)) {
49
- reasons.push('NO_DIGIT')
50
- }
51
-
52
- // Special characters include standard symbols; adjust regex based on backend constraints if needed.
53
- if (policy.requireSpecialChar && !/[^a-zA-Z0-9]/.test(password)) {
54
- reasons.push('NO_SPECIAL_CHAR')
55
- }
56
-
57
- if (reasons.length > 0) {
58
- return { success: false, reasons }
59
- }
60
-
61
- return { success: true }
62
- }
63
- }
@@ -1,65 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { SecurityError } from '@/error/model/security-error'
3
- import { ClientSecurityErrorCodes } from '@/error/naming/client-security-error-codes'
4
-
5
- describe('SecurityError', () => {
6
- it('creates passwordPolicyUnavailable error as a plain object', () => {
7
- const error = SecurityError.passwordPolicyUnavailable()
8
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_POLICY_UNAVAILABLE)
9
- expect(error.isRetryable).toBe(true)
10
- expect(error.args).toBeNull()
11
- expect(error.id).toBeDefined()
12
- })
13
-
14
- it('creates passwordTooShort error with arguments', () => {
15
- const error = SecurityError.passwordTooShort(8)
16
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_TOO_SHORT)
17
- expect(error.isRetryable).toBe(false)
18
- expect(error.args).toEqual({ passwordMinLength: '8' })
19
- })
20
-
21
- it('creates passwordTooShort error without minLength', () => {
22
- const error = SecurityError.passwordTooShort()
23
- expect(error.args).toBeNull()
24
- })
25
-
26
- it('creates passwordNoLetter error', () => {
27
- const error = SecurityError.passwordNoLetter()
28
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_NO_LETTER)
29
- })
30
-
31
- it('creates passwordNoUpperCase error', () => {
32
- const error = SecurityError.passwordNoUpperCase()
33
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_NO_UPPERCASE)
34
- })
35
-
36
- it('creates passwordNoLowerCase error', () => {
37
- const error = SecurityError.passwordNoLowerCase()
38
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_NO_LOWERCASE)
39
- })
40
-
41
- it('creates passwordNoDigit error', () => {
42
- const error = SecurityError.passwordNoDigit()
43
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_NO_DIGIT)
44
- })
45
-
46
- it('creates passwordNoSpecialChar error', () => {
47
- const error = SecurityError.passwordNoSpecialChar()
48
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_NO_SPECIAL_CHAR)
49
- })
50
-
51
- it('creates passwordTooCommon error', () => {
52
- const error = SecurityError.passwordTooCommon()
53
- expect(error.code).toBe(ClientSecurityErrorCodes.PASSWORD_TOO_COMMON)
54
- })
55
-
56
- it('supports JSON serialization / deserialization without losing structure', () => {
57
- const original = SecurityError.passwordTooShort(12)
58
- const serialized = JSON.stringify(original)
59
- const deserialized = JSON.parse(serialized) as typeof original
60
-
61
- expect(deserialized).toEqual(original)
62
- expect(deserialized.code).toBe('PASSWORD_TOO_SHORT')
63
- expect(deserialized.args).toEqual({ passwordMinLength: '12' })
64
- })
65
- })
@@ -1,182 +0,0 @@
1
- import { SecurityErrorArgs } from '@mudrichenkoevgeny/shared-foundation'
2
- import { generateErrorId } from '@mudrichenkoevgeny/web-platform-sdk-core-common'
3
- import type { ErrorId } from "@mudrichenkoevgeny/web-platform-sdk-core-common";
4
- import { ClientSecurityErrorCodes } from '@/error/naming/client-security-error-codes'
5
- /** Error indicating security/password policy settings could not be fetched. */
6
- export type SecurityErrorPasswordPolicyUnavailable = {
7
- readonly id: ErrorId
8
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_POLICY_UNAVAILABLE
9
- readonly args: null
10
- readonly isRetryable: true
11
- }
12
-
13
- /** Error indicating candidate password is shorter than minimum required length. */
14
- export type SecurityErrorPasswordTooShort = {
15
- readonly id: ErrorId
16
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_TOO_SHORT
17
- readonly args: Record<string, string> | null
18
- readonly isRetryable: false
19
- }
20
-
21
- /** Error indicating candidate password contains no letter character. */
22
- export type SecurityErrorPasswordNoLetter = {
23
- readonly id: ErrorId
24
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_NO_LETTER
25
- readonly args: null
26
- readonly isRetryable: false
27
- }
28
-
29
- /** Error indicating candidate password contains no uppercase letter. */
30
- export type SecurityErrorPasswordNoUpperCase = {
31
- readonly id: ErrorId
32
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_NO_UPPERCASE
33
- readonly args: null
34
- readonly isRetryable: false
35
- }
36
-
37
- /** Error indicating candidate password contains no lowercase letter. */
38
- export type SecurityErrorPasswordNoLowerCase = {
39
- readonly id: ErrorId
40
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_NO_LOWERCASE
41
- readonly args: null
42
- readonly isRetryable: false
43
- }
44
-
45
- /** Error indicating candidate password contains no digit character. */
46
- export type SecurityErrorPasswordNoDigit = {
47
- readonly id: ErrorId
48
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_NO_DIGIT
49
- readonly args: null
50
- readonly isRetryable: false
51
- }
52
-
53
- /** Error indicating candidate password contains no special character. */
54
- export type SecurityErrorPasswordNoSpecialChar = {
55
- readonly id: ErrorId
56
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_NO_SPECIAL_CHAR
57
- readonly args: null
58
- readonly isRetryable: false
59
- }
60
-
61
- /** Error indicating candidate password is on the forbidden common passwords list. */
62
- export type SecurityErrorPasswordTooCommon = {
63
- readonly id: ErrorId
64
- readonly code: typeof ClientSecurityErrorCodes.PASSWORD_TOO_COMMON
65
- readonly args: null
66
- readonly isRetryable: false
67
- }
68
-
69
- /**
70
- * Discriminated union type representing security domain errors.
71
- */
72
- export type SecurityError =
73
- | SecurityErrorPasswordPolicyUnavailable
74
- | SecurityErrorPasswordTooShort
75
- | SecurityErrorPasswordNoLetter
76
- | SecurityErrorPasswordNoUpperCase
77
- | SecurityErrorPasswordNoLowerCase
78
- | SecurityErrorPasswordNoDigit
79
- | SecurityErrorPasswordNoSpecialChar
80
- | SecurityErrorPasswordTooCommon
81
-
82
- /**
83
- * Factory helper object for constructing {@link SecurityError} plain objects.
84
- */
85
- export const SecurityError = {
86
- /**
87
- * Creates a password policy unavailable error.
88
- *
89
- * @returns {@link SecurityErrorPasswordPolicyUnavailable}
90
- */
91
- passwordPolicyUnavailable: (): SecurityErrorPasswordPolicyUnavailable => ({
92
- id: generateErrorId(),
93
- code: ClientSecurityErrorCodes.PASSWORD_POLICY_UNAVAILABLE,
94
- args: null,
95
- isRetryable: true
96
- }),
97
-
98
- /**
99
- * Creates a password too short validation error.
100
- *
101
- * @param minLength - Optional minimum length requirement
102
- * @returns {@link SecurityErrorPasswordTooShort}
103
- */
104
- passwordTooShort: (minLength?: number | null): SecurityErrorPasswordTooShort => ({
105
- id: generateErrorId(),
106
- code: ClientSecurityErrorCodes.PASSWORD_TOO_SHORT,
107
- args: minLength != null ? { [SecurityErrorArgs.PASSWORD_MIN_LENGTH]: String(minLength) } : null,
108
- isRetryable: false
109
- }),
110
-
111
- /**
112
- * Creates a password missing letter validation error.
113
- *
114
- * @returns {@link SecurityErrorPasswordNoLetter}
115
- */
116
- passwordNoLetter: (): SecurityErrorPasswordNoLetter => ({
117
- id: generateErrorId(),
118
- code: ClientSecurityErrorCodes.PASSWORD_NO_LETTER,
119
- args: null,
120
- isRetryable: false
121
- }),
122
-
123
- /**
124
- * Creates a password missing uppercase letter validation error.
125
- *
126
- * @returns {@link SecurityErrorPasswordNoUpperCase}
127
- */
128
- passwordNoUpperCase: (): SecurityErrorPasswordNoUpperCase => ({
129
- id: generateErrorId(),
130
- code: ClientSecurityErrorCodes.PASSWORD_NO_UPPERCASE,
131
- args: null,
132
- isRetryable: false
133
- }),
134
-
135
- /**
136
- * Creates a password missing lowercase letter validation error.
137
- *
138
- * @returns {@link SecurityErrorPasswordNoLowerCase}
139
- */
140
- passwordNoLowerCase: (): SecurityErrorPasswordNoLowerCase => ({
141
- id: generateErrorId(),
142
- code: ClientSecurityErrorCodes.PASSWORD_NO_LOWERCASE,
143
- args: null,
144
- isRetryable: false
145
- }),
146
-
147
- /**
148
- * Creates a password missing digit validation error.
149
- *
150
- * @returns {@link SecurityErrorPasswordNoDigit}
151
- */
152
- passwordNoDigit: (): SecurityErrorPasswordNoDigit => ({
153
- id: generateErrorId(),
154
- code: ClientSecurityErrorCodes.PASSWORD_NO_DIGIT,
155
- args: null,
156
- isRetryable: false
157
- }),
158
-
159
- /**
160
- * Creates a password missing special character validation error.
161
- *
162
- * @returns {@link SecurityErrorPasswordNoSpecialChar}
163
- */
164
- passwordNoSpecialChar: (): SecurityErrorPasswordNoSpecialChar => ({
165
- id: generateErrorId(),
166
- code: ClientSecurityErrorCodes.PASSWORD_NO_SPECIAL_CHAR,
167
- args: null,
168
- isRetryable: false
169
- }),
170
-
171
- /**
172
- * Creates a password too common validation error.
173
- *
174
- * @returns {@link SecurityErrorPasswordTooCommon}
175
- */
176
- passwordTooCommon: (): SecurityErrorPasswordTooCommon => ({
177
- id: generateErrorId(),
178
- code: ClientSecurityErrorCodes.PASSWORD_TOO_COMMON,
179
- args: null,
180
- isRetryable: false
181
- })
182
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Machine-readable error codes for security client errors and password policy validation.
3
- */
4
- export const ClientSecurityErrorCodes = {
5
- /** Password policy is missing and cannot be fetched. */
6
- PASSWORD_POLICY_UNAVAILABLE: 'PASSWORD_POLICY_UNAVAILABLE',
7
- /** Password does not meet the minimum length requirement. */
8
- PASSWORD_TOO_SHORT: 'PASSWORD_TOO_SHORT',
9
- /** Password must contain at least one letter. */
10
- PASSWORD_NO_LETTER: 'PASSWORD_NO_LETTER',
11
- /** Password must contain at least one uppercase letter. */
12
- PASSWORD_NO_UPPERCASE: 'PASSWORD_NO_UPPERCASE',
13
- /** Password must contain at least one lowercase letter. */
14
- PASSWORD_NO_LOWERCASE: 'PASSWORD_NO_LOWERCASE',
15
- /** Password must contain at least one digit. */
16
- PASSWORD_NO_DIGIT: 'PASSWORD_NO_DIGIT',
17
- /** Password must contain at least one special character. */
18
- PASSWORD_NO_SPECIAL_CHAR: 'PASSWORD_NO_SPECIAL_CHAR',
19
- /** Password is in the list of forbidden common passwords. */
20
- PASSWORD_TOO_COMMON: 'PASSWORD_TOO_COMMON'
21
- } as const