@jmlq/auth 0.0.1-alpha.1
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/README.md +306 -0
- package/dist/examples/bcrypt-password-hasher.example.d.ts +3 -0
- package/dist/examples/bcrypt-password-hasher.example.js +78 -0
- package/dist/examples/entity-object.example.d.ts +39 -0
- package/dist/examples/entity-object.example.js +411 -0
- package/dist/examples/factory-auth-service-example.d.ts +3 -0
- package/dist/examples/factory-auth-service-example.js +84 -0
- package/dist/examples/index.example.d.ts +12 -0
- package/dist/examples/index.example.js +171 -0
- package/dist/examples/jwt-algoritm.example.d.ts +47 -0
- package/dist/examples/jwt-algoritm.example.js +447 -0
- package/dist/examples/jwt-token-generator.example.d.ts +6 -0
- package/dist/examples/jwt-token-generator.example.js +49 -0
- package/dist/examples/jwt-verifier.example.d.ts +3 -0
- package/dist/examples/jwt-verifier.example.js +80 -0
- package/dist/examples/password-policy.example.d.ts +7 -0
- package/dist/examples/password-policy.example.js +57 -0
- package/dist/examples/service-jwt-token.example.d.ts +3 -0
- package/dist/examples/service-jwt-token.example.js +154 -0
- package/dist/examples/service-token-session.example.d.ts +3 -0
- package/dist/examples/service-token-session.example.js +139 -0
- package/dist/examples/use-case-login-with-password.example.d.ts +6 -0
- package/dist/examples/use-case-login-with-password.example.js +105 -0
- package/dist/examples/use-case-logout.example.d.ts +7 -0
- package/dist/examples/use-case-logout.example.js +134 -0
- package/dist/examples/use-case-refresh-token.example.d.ts +11 -0
- package/dist/examples/use-case-refresh-token.example.js +164 -0
- package/dist/examples/use-case-register-user.example.d.ts +9 -0
- package/dist/examples/use-case-register-user.example.js +110 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -0
- package/dist/src/application/dtos/index.d.ts +4 -0
- package/dist/src/application/dtos/index.js +20 -0
- package/dist/src/application/dtos/login.dto.d.ts +9 -0
- package/dist/src/application/dtos/login.dto.js +2 -0
- package/dist/src/application/dtos/logout.dto.d.ts +7 -0
- package/dist/src/application/dtos/logout.dto.js +2 -0
- package/dist/src/application/dtos/refresh-token.dto.d.ts +7 -0
- package/dist/src/application/dtos/refresh-token.dto.js +2 -0
- package/dist/src/application/dtos/register-user.dto.d.ts +16 -0
- package/dist/src/application/dtos/register-user.dto.js +2 -0
- package/dist/src/application/factories/auth-service.factory.d.ts +5 -0
- package/dist/src/application/factories/auth-service.factory.js +51 -0
- package/dist/src/application/factories/index.d.ts +1 -0
- package/dist/src/application/factories/index.js +17 -0
- package/dist/src/application/index.d.ts +3 -0
- package/dist/src/application/index.js +19 -0
- package/dist/src/application/use-cases/index.d.ts +4 -0
- package/dist/src/application/use-cases/index.js +20 -0
- package/dist/src/application/use-cases/login-with-password.use-case.d.ts +9 -0
- package/dist/src/application/use-cases/login-with-password.use-case.js +36 -0
- package/dist/src/application/use-cases/logout.use-case.d.ts +7 -0
- package/dist/src/application/use-cases/logout.use-case.js +22 -0
- package/dist/src/application/use-cases/refresh-token.use-case.d.ts +7 -0
- package/dist/src/application/use-cases/refresh-token.use-case.js +23 -0
- package/dist/src/application/use-cases/register-user.use-case.d.ts +10 -0
- package/dist/src/application/use-cases/register-user.use-case.js +37 -0
- package/dist/src/domain/entities/credential.entity.d.ts +78 -0
- package/dist/src/domain/entities/credential.entity.js +92 -0
- package/dist/src/domain/entities/index.d.ts +2 -0
- package/dist/src/domain/entities/index.js +18 -0
- package/dist/src/domain/entities/user.entity.d.ts +97 -0
- package/dist/src/domain/entities/user.entity.js +116 -0
- package/dist/src/domain/errors/auth-domain-error.d.ts +82 -0
- package/dist/src/domain/errors/auth-domain-error.js +112 -0
- package/dist/src/domain/errors/auth.errors.d.ts +56 -0
- package/dist/src/domain/errors/auth.errors.js +76 -0
- package/dist/src/domain/errors/identity.errors.d.ts +34 -0
- package/dist/src/domain/errors/identity.errors.js +82 -0
- package/dist/src/domain/errors/index.d.ts +2 -0
- package/dist/src/domain/errors/index.js +18 -0
- package/dist/src/domain/index.d.ts +6 -0
- package/dist/src/domain/index.js +22 -0
- package/dist/src/domain/object-values/email.d.ts +37 -0
- package/dist/src/domain/object-values/email.js +56 -0
- package/dist/src/domain/object-values/hashed-password.d.ts +28 -0
- package/dist/src/domain/object-values/hashed-password.js +73 -0
- package/dist/src/domain/object-values/id.d.ts +8 -0
- package/dist/src/domain/object-values/id.js +28 -0
- package/dist/src/domain/object-values/index.d.ts +5 -0
- package/dist/src/domain/object-values/index.js +13 -0
- package/dist/src/domain/object-values/permission.d.ts +15 -0
- package/dist/src/domain/object-values/permission.js +57 -0
- package/dist/src/domain/object-values/role.d.ts +25 -0
- package/dist/src/domain/object-values/role.js +108 -0
- package/dist/src/domain/ports/auth/password-hasher.d.ts +7 -0
- package/dist/src/domain/ports/auth/password-hasher.js +2 -0
- package/dist/src/domain/ports/auth/password-policy-config.port.d.ts +0 -0
- package/dist/src/domain/ports/auth/password-policy-config.port.js +10 -0
- package/dist/src/domain/ports/auth/password-policy.port.d.ts +10 -0
- package/dist/src/domain/ports/auth/password-policy.port.js +2 -0
- package/dist/src/domain/ports/config/auth-config.port.d.ts +19 -0
- package/dist/src/domain/ports/config/auth-config.port.js +3 -0
- package/dist/src/domain/ports/index.d.ts +9 -0
- package/dist/src/domain/ports/index.js +25 -0
- package/dist/src/domain/ports/jwt/factory/signature-strategy-factory.port.d.ts +14 -0
- package/dist/src/domain/ports/jwt/factory/signature-strategy-factory.port.js +2 -0
- package/dist/src/domain/ports/jwt/payload/jwt-payload.port.d.ts +12 -0
- package/dist/src/domain/ports/jwt/payload/jwt-payload.port.js +2 -0
- package/dist/src/domain/ports/jwt/signature-strategy-factory.port.d.ts +14 -0
- package/dist/src/domain/ports/jwt/signature-strategy-factory.port.js +2 -0
- package/dist/src/domain/ports/jwt/signature-strategy.d.ts +30 -0
- package/dist/src/domain/ports/jwt/signature-strategy.js +4 -0
- package/dist/src/domain/ports/jwt/signature-strategy.port.d.ts +31 -0
- package/dist/src/domain/ports/jwt/signature-strategy.port.js +4 -0
- package/dist/src/domain/ports/jwt/strategy/signature-strategy.port.d.ts +31 -0
- package/dist/src/domain/ports/jwt/strategy/signature-strategy.port.js +4 -0
- package/dist/src/domain/ports/repository/credential.repository.d.ts +10 -0
- package/dist/src/domain/ports/repository/credential.repository.js +2 -0
- package/dist/src/domain/ports/repository/index.d.ts +2 -0
- package/dist/src/domain/ports/repository/index.js +18 -0
- package/dist/src/domain/ports/repository/user.repository.d.ts +13 -0
- package/dist/src/domain/ports/repository/user.repository.js +2 -0
- package/dist/src/domain/ports/token/token-session.port.d.ts +7 -0
- package/dist/src/domain/ports/token/token-session.port.js +2 -0
- package/dist/src/domain/ports/token/token.service.port.d.ts +9 -0
- package/dist/src/domain/ports/token/token.service.port.js +2 -0
- package/dist/src/domain/props/create-payload-props.port.d.ts +0 -0
- package/dist/src/domain/props/create-payload-props.port.js +8 -0
- package/dist/src/domain/props/entities/credential.props.d.ts +8 -0
- package/dist/src/domain/props/entities/credential.props.js +2 -0
- package/dist/src/domain/props/entities/index.d.ts +2 -0
- package/dist/src/domain/props/entities/index.js +18 -0
- package/dist/src/domain/props/entities/user.props.d.ts +10 -0
- package/dist/src/domain/props/entities/user.props.js +2 -0
- package/dist/src/domain/props/index.d.ts +2 -0
- package/dist/src/domain/props/index.js +18 -0
- package/dist/src/domain/props/jwt/create-payload.props.d.ts +9 -0
- package/dist/src/domain/props/jwt/create-payload.props.js +2 -0
- package/dist/src/domain/props/jwt/generate-access-token.props.d.ts +8 -0
- package/dist/src/domain/props/jwt/generate-access-token.props.js +2 -0
- package/dist/src/domain/props/jwt/generate-refresh-token.props.d.ts +8 -0
- package/dist/src/domain/props/jwt/generate-refresh-token.props.js +2 -0
- package/dist/src/domain/props/jwt/generate-token.props.d.ts +10 -0
- package/dist/src/domain/props/jwt/generate-token.props.js +2 -0
- package/dist/src/domain/props/jwt/index.d.ts +5 -0
- package/dist/src/domain/props/jwt/index.js +21 -0
- package/dist/src/domain/props/jwt/jwt-subject.d.ts +7 -0
- package/dist/src/domain/props/jwt/jwt-subject.js +2 -0
- package/dist/src/domain/props/jwt/jwt-user.d.ts +7 -0
- package/dist/src/domain/props/jwt/jwt-user.js +2 -0
- package/dist/src/domain/props/services/generate-access-token.props.d.ts +8 -0
- package/dist/src/domain/props/services/generate-access-token.props.js +2 -0
- package/dist/src/domain/props/services/generate-refresh-token.props.d.ts +8 -0
- package/dist/src/domain/props/services/generate-refresh-token.props.js +2 -0
- package/dist/src/domain/props/services/index.d.ts +2 -0
- package/dist/src/domain/props/services/index.js +18 -0
- package/dist/src/domain/services/index.d.ts +1 -0
- package/dist/src/domain/services/index.js +17 -0
- package/dist/src/domain/services/password-policy.service.d.ts +8 -0
- package/dist/src/domain/services/password-policy.service.js +29 -0
- package/dist/src/domain/services/token.service.port.d.ts +9 -0
- package/dist/src/domain/services/token.service.port.js +2 -0
- package/dist/src/index.d.ts +78 -0
- package/dist/src/index.js +94 -0
- package/dist/src/infrastructure/index.d.ts +5 -0
- package/dist/src/infrastructure/index.js +21 -0
- package/dist/src/infrastructure/jwt/factory/index.d.ts +1 -0
- package/dist/src/infrastructure/jwt/factory/index.js +17 -0
- package/dist/src/infrastructure/jwt/factory/signature-strategy.factory.d.ts +21 -0
- package/dist/src/infrastructure/jwt/factory/signature-strategy.factory.js +61 -0
- package/dist/src/infrastructure/jwt/index.d.ts +3 -0
- package/dist/src/infrastructure/jwt/index.js +19 -0
- package/dist/src/infrastructure/jwt/signature-strategy.factory.d.ts +21 -0
- package/dist/src/infrastructure/jwt/signature-strategy.factory.js +61 -0
- package/dist/src/infrastructure/jwt/strategies/ecdsa-signature-strategy.d.ts +47 -0
- package/dist/src/infrastructure/jwt/strategies/ecdsa-signature-strategy.js +124 -0
- package/dist/src/infrastructure/jwt/strategies/ecdsa-signature.strategy.d.ts +47 -0
- package/dist/src/infrastructure/jwt/strategies/ecdsa-signature.strategy.js +124 -0
- package/dist/src/infrastructure/jwt/strategies/hmac-signature-strategy.d.ts +54 -0
- package/dist/src/infrastructure/jwt/strategies/hmac-signature-strategy.js +129 -0
- package/dist/src/infrastructure/jwt/strategies/hmac-signature.strategy.d.ts +54 -0
- package/dist/src/infrastructure/jwt/strategies/hmac-signature.strategy.js +129 -0
- package/dist/src/infrastructure/jwt/strategies/index.d.ts +3 -0
- package/dist/src/infrastructure/jwt/strategies/index.js +19 -0
- package/dist/src/infrastructure/jwt/strategies/rsa-signature-strategy.d.ts +47 -0
- package/dist/src/infrastructure/jwt/strategies/rsa-signature-strategy.js +124 -0
- package/dist/src/infrastructure/jwt/strategies/rsa-signature.strategy.d.ts +47 -0
- package/dist/src/infrastructure/jwt/strategies/rsa-signature.strategy.js +124 -0
- package/dist/src/infrastructure/jwt/token/actions/jwt-token-generator.d.ts +57 -0
- package/dist/src/infrastructure/jwt/token/actions/jwt-token-generator.js +123 -0
- package/dist/src/infrastructure/jwt/token/actions/jwt-token-verifier.d.ts +59 -0
- package/dist/src/infrastructure/jwt/token/actions/jwt-token-verifier.js +100 -0
- package/dist/src/infrastructure/jwt/token/index.d.ts +5 -0
- package/dist/src/infrastructure/jwt/token/index.js +21 -0
- package/dist/src/infrastructure/jwt/token/jwt-signer.d.ts +33 -0
- package/dist/src/infrastructure/jwt/token/jwt-signer.js +46 -0
- package/dist/src/infrastructure/jwt/token/jwt-token-parser.d.ts +29 -0
- package/dist/src/infrastructure/jwt/token/jwt-token-parser.js +57 -0
- package/dist/src/infrastructure/jwt/token/jwt-token-validator.d.ts +32 -0
- package/dist/src/infrastructure/jwt/token/jwt-token-validator.js +77 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-signer.d.ts +33 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-signer.js +46 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-token-parser.d.ts +30 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-token-parser.js +57 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-token-validator.d.ts +32 -0
- package/dist/src/infrastructure/jwt/token/tools/jwt-token-validator.js +77 -0
- package/dist/src/infrastructure/repositories/index.d.ts +1 -0
- package/dist/src/infrastructure/repositories/index.js +17 -0
- package/dist/src/infrastructure/repositories/test/in-memory-credential.repository.d.ts +12 -0
- package/dist/src/infrastructure/repositories/test/in-memory-credential.repository.js +68 -0
- package/dist/src/infrastructure/repositories/test/in-memory-token-session.repository.d.ts +67 -0
- package/dist/src/infrastructure/repositories/test/in-memory-token-session.repository.js +128 -0
- package/dist/src/infrastructure/repositories/test/in-memory-user.repository.d.ts +11 -0
- package/dist/src/infrastructure/repositories/test/in-memory-user.repository.js +49 -0
- package/dist/src/infrastructure/repositories/test/index.d.ts +2 -0
- package/dist/src/infrastructure/repositories/test/index.js +18 -0
- package/dist/src/infrastructure/security/bcrypt-password-hasher.d.ts +6 -0
- package/dist/src/infrastructure/security/bcrypt-password-hasher.js +19 -0
- package/dist/src/infrastructure/security/index.d.ts +1 -0
- package/dist/src/infrastructure/security/index.js +17 -0
- package/dist/src/infrastructure/services/default-token-session.service.d.ts +18 -0
- package/dist/src/infrastructure/services/default-token-session.service.js +88 -0
- package/dist/src/infrastructure/services/index.d.ts +2 -0
- package/dist/src/infrastructure/services/index.js +18 -0
- package/dist/src/infrastructure/services/jwt-token.service.d.ts +15 -0
- package/dist/src/infrastructure/services/jwt-token.service.js +44 -0
- package/dist/src/infrastructure/services/simple-jwt-token.service.d.ts +15 -0
- package/dist/src/infrastructure/services/simple-jwt-token.service.js +46 -0
- package/dist/src/infrastructure/services/token-session.service.d.ts +24 -0
- package/dist/src/infrastructure/services/token-session.service.js +131 -0
- package/dist/src/infrastructure/types/auth-service-container.d.ts +14 -0
- package/dist/src/infrastructure/types/auth-service-container.js +2 -0
- package/dist/src/infrastructure/types/index.d.ts +1 -0
- package/dist/src/infrastructure/types/index.js +17 -0
- package/dist/src/shared/constants/index.d.ts +1 -0
- package/dist/src/shared/constants/index.js +17 -0
- package/dist/src/shared/constants/jwt-algorithms.d.ts +17 -0
- package/dist/src/shared/constants/jwt-algorithms.js +23 -0
- package/dist/src/shared/encoders/base64-url-encoder.d.ts +29 -0
- package/dist/src/shared/encoders/base64-url-encoder.js +45 -0
- package/dist/src/shared/encoders/index.d.ts +1 -0
- package/dist/src/shared/encoders/index.js +17 -0
- package/dist/src/shared/index.d.ts +4 -0
- package/dist/src/shared/index.js +20 -0
- package/dist/src/shared/types/index.d.ts +1 -0
- package/dist/src/shared/types/index.js +17 -0
- package/dist/src/shared/types/jwt.d.ts +25 -0
- package/dist/src/shared/types/jwt.js +2 -0
- package/dist/src/shared/types/jwt.types.d.ts +39 -0
- package/dist/src/shared/types/jwt.types.js +2 -0
- package/dist/src/shared/utils/index.d.ts +1 -0
- package/dist/src/shared/utils/index.js +17 -0
- package/dist/src/shared/utils/time-parser.d.ts +28 -0
- package/dist/src/shared/utils/time-parser.js +76 -0
- package/dist/tests/application/factory/auth-service-factory.spec.d.ts +1 -0
- package/dist/tests/application/factory/auth-service-factory.spec.js +97 -0
- package/dist/tests/application/use-cases/login-with-password.integration.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/login-with-password.integration.spec.js +140 -0
- package/dist/tests/application/use-cases/logout-use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/logout-use-case.spec.js +40 -0
- package/dist/tests/application/use-cases/refresh-token-use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/refresh-token-use-case.spec.js +116 -0
- package/dist/tests/application/use-cases/register-user.usecase.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/register-user.usecase.spec.js +151 -0
- package/dist/tests/domain/entities/credential.spec.d.ts +1 -0
- package/dist/tests/domain/entities/credential.spec.js +93 -0
- package/dist/tests/domain/entities/user.spec.d.ts +1 -0
- package/dist/tests/domain/entities/user.spec.js +93 -0
- package/dist/tests/domain/object-values/email.spec.d.ts +1 -0
- package/dist/tests/domain/object-values/email.spec.js +77 -0
- package/dist/tests/domain/object-values/hashed-password.spec.d.ts +1 -0
- package/dist/tests/domain/object-values/hashed-password.spec.js +54 -0
- package/dist/tests/domain/object-values/id.spec.d.ts +1 -0
- package/dist/tests/domain/object-values/id.spec.js +48 -0
- package/dist/tests/domain/object-values/permission.spec.d.ts +1 -0
- package/dist/tests/domain/object-values/permission.spec.js +75 -0
- package/dist/tests/domain/object-values/role.spec.d.ts +1 -0
- package/dist/tests/domain/object-values/role.spec.js +139 -0
- package/dist/tests/domain/services/default-password-policy.spec.d.ts +1 -0
- package/dist/tests/domain/services/default-password-policy.spec.js +69 -0
- package/dist/tests/doman/entities/credential.spec.d.ts +1 -0
- package/dist/tests/doman/entities/credential.spec.js +93 -0
- package/dist/tests/doman/entities/user.spec.d.ts +1 -0
- package/dist/tests/doman/entities/user.spec.js +93 -0
- package/dist/tests/doman/object-values/email.spec.d.ts +1 -0
- package/dist/tests/doman/object-values/email.spec.js +77 -0
- package/dist/tests/doman/object-values/hashed-password.spec.d.ts +1 -0
- package/dist/tests/doman/object-values/hashed-password.spec.js +54 -0
- package/dist/tests/doman/object-values/id.spec.d.ts +1 -0
- package/dist/tests/doman/object-values/id.spec.js +48 -0
- package/dist/tests/doman/object-values/permission.spec.d.ts +1 -0
- package/dist/tests/doman/object-values/permission.spec.js +75 -0
- package/dist/tests/doman/object-values/role.spec.d.ts +1 -0
- package/dist/tests/doman/object-values/role.spec.js +139 -0
- package/dist/tests/helpers/make-jwt-subject.d.ts +7 -0
- package/dist/tests/helpers/make-jwt-subject.js +16 -0
- package/dist/tests/helpers/make-jwt-user.d.ts +7 -0
- package/dist/tests/helpers/make-jwt-user.js +16 -0
- package/dist/tests/helpers/make-user.d.ts +2 -0
- package/dist/tests/helpers/make-user.js +15 -0
- package/dist/tests/infrastructure/jwt/signature-strategy-factory.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/signature-strategy-factory.spec.js +127 -0
- package/dist/tests/infrastructure/jwt/strategies/ecdsa-signature-strategy.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/strategies/ecdsa-signature-strategy.spec.js +157 -0
- package/dist/tests/infrastructure/jwt/strategies/hmac-signature-strategy.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/strategies/hmac-signature-strategy.spec.js +150 -0
- package/dist/tests/infrastructure/jwt/strategies/rsa-signature-strategy..spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/strategies/rsa-signature-strategy..spec.js +156 -0
- package/dist/tests/infrastructure/jwt/token/actions/jwt-token-generator.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/actions/jwt-token-generator.spec.js +179 -0
- package/dist/tests/infrastructure/jwt/token/actions/jwt-token-verifier.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/actions/jwt-token-verifier.spec.js +142 -0
- package/dist/tests/infrastructure/jwt/token/jwt-signer.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/jwt-signer.spec.js +125 -0
- package/dist/tests/infrastructure/jwt/token/jwt-token-parser.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/jwt-token-parser.spec.js +116 -0
- package/dist/tests/infrastructure/jwt/token/jwt-token-validator.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/jwt-token-validator.spec.js +88 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-signer.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-signer.spec.js +126 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-token-parser.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-token-parser.spec.js +116 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-token-validator.spec.d.ts +1 -0
- package/dist/tests/infrastructure/jwt/token/tools/jwt-token-validator.spec.js +88 -0
- package/dist/tests/infrastructure/security/security/bcrypt-password-hasher.spec.d.ts +1 -0
- package/dist/tests/infrastructure/security/security/bcrypt-password-hasher.spec.js +37 -0
- package/dist/tests/infrastructure/services/jwt-token-service.spec.d.ts +1 -0
- package/dist/tests/infrastructure/services/jwt-token-service.spec.js +145 -0
- package/dist/tests/infrastructure/services/token-session.service.spec.d.ts +1 -0
- package/dist/tests/infrastructure/services/token-session.service.spec.js +269 -0
- package/dist/tests/shared/constants/jwt-algorithms.spec.d.ts +1 -0
- package/dist/tests/shared/constants/jwt-algorithms.spec.js +27 -0
- package/dist/tests/shared/encoders/base64-url-encoder.spec.d.ts +1 -0
- package/dist/tests/shared/encoders/base64-url-encoder.spec.js +70 -0
- package/dist/tests/shared/utils/time-parser.spec.d.ts +1 -0
- package/dist/tests/shared/utils/time-parser.spec.js +80 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +17 -0
- package/dist/utils/time-parser.d.ts +28 -0
- package/dist/utils/time-parser.js +76 -0
- package/package.json +48 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare class TimeParser {
|
|
2
|
+
private static readonly TIME_UNITS;
|
|
3
|
+
private static readonly TIME_PATTERN;
|
|
4
|
+
/**
|
|
5
|
+
* Convierte una cadena de tiempo (ej: "15m", "1h", "7d") a milisegundos
|
|
6
|
+
* @param timeString - Cadena de tiempo en formato número + unidad
|
|
7
|
+
* @returns Tiempo en milisegundos
|
|
8
|
+
* @throws Error si el formato es inválido
|
|
9
|
+
*/
|
|
10
|
+
static parseToMilliseconds(timeString: string): number;
|
|
11
|
+
/**
|
|
12
|
+
* Valida si una cadena de tiempo tiene el formato correcto
|
|
13
|
+
* @param timeString - Cadena de tiempo a validar
|
|
14
|
+
* @returns true si es válida, false en caso contrario
|
|
15
|
+
*/
|
|
16
|
+
static isValidTimeString(timeString: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Obtiene las unidades de tiempo soportadas
|
|
19
|
+
* @returns Array con las unidades soportadas
|
|
20
|
+
*/
|
|
21
|
+
static getSupportedUnits(): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Convierte milisegundos a formato legible
|
|
24
|
+
* @param milliseconds - Tiempo en milisegundos
|
|
25
|
+
* @returns Cadena de tiempo legible
|
|
26
|
+
*/
|
|
27
|
+
static formatMilliseconds(milliseconds: number): string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeParser = void 0;
|
|
4
|
+
class TimeParser {
|
|
5
|
+
/**
|
|
6
|
+
* Convierte una cadena de tiempo (ej: "15m", "1h", "7d") a milisegundos
|
|
7
|
+
* @param timeString - Cadena de tiempo en formato número + unidad
|
|
8
|
+
* @returns Tiempo en milisegundos
|
|
9
|
+
* @throws Error si el formato es inválido
|
|
10
|
+
*/
|
|
11
|
+
static parseToMilliseconds(timeString) {
|
|
12
|
+
if (!timeString || typeof timeString !== "string") {
|
|
13
|
+
throw new Error("Time string is required and must be a string");
|
|
14
|
+
}
|
|
15
|
+
const trimmed = timeString.trim().toLowerCase();
|
|
16
|
+
const match = trimmed.match(this.TIME_PATTERN);
|
|
17
|
+
if (!match) {
|
|
18
|
+
throw new Error(`Invalid time format: "${timeString}". Expected format: number + unit (s, m, h, d). Examples: "15m", "1h", "7d"`);
|
|
19
|
+
}
|
|
20
|
+
const [, valueStr, unit] = match;
|
|
21
|
+
const value = parseInt(valueStr, 10);
|
|
22
|
+
if (isNaN(value) || value <= 0) {
|
|
23
|
+
throw new Error(`Invalid time value: "${valueStr}". Must be a positive number`);
|
|
24
|
+
}
|
|
25
|
+
const multiplier = this.TIME_UNITS[unit];
|
|
26
|
+
return value * multiplier;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Valida si una cadena de tiempo tiene el formato correcto
|
|
30
|
+
* @param timeString - Cadena de tiempo a validar
|
|
31
|
+
* @returns true si es válida, false en caso contrario
|
|
32
|
+
*/
|
|
33
|
+
static isValidTimeString(timeString) {
|
|
34
|
+
try {
|
|
35
|
+
this.parseToMilliseconds(timeString);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Obtiene las unidades de tiempo soportadas
|
|
44
|
+
* @returns Array con las unidades soportadas
|
|
45
|
+
*/
|
|
46
|
+
static getSupportedUnits() {
|
|
47
|
+
return Object.keys(this.TIME_UNITS);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Convierte milisegundos a formato legible
|
|
51
|
+
* @param milliseconds - Tiempo en milisegundos
|
|
52
|
+
* @returns Cadena de tiempo legible
|
|
53
|
+
*/
|
|
54
|
+
static formatMilliseconds(milliseconds) {
|
|
55
|
+
const units = [
|
|
56
|
+
{ unit: "d", value: 24 * 60 * 60 * 1000 },
|
|
57
|
+
{ unit: "h", value: 60 * 60 * 1000 },
|
|
58
|
+
{ unit: "m", value: 60 * 1000 },
|
|
59
|
+
{ unit: "s", value: 1000 },
|
|
60
|
+
];
|
|
61
|
+
for (const { unit, value } of units) {
|
|
62
|
+
if (milliseconds >= value && milliseconds % value === 0) {
|
|
63
|
+
return `${milliseconds / value}${unit}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return `${milliseconds}ms`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.TimeParser = TimeParser;
|
|
70
|
+
TimeParser.TIME_UNITS = {
|
|
71
|
+
s: 1000, // segundos
|
|
72
|
+
m: 60 * 1000, // minutos
|
|
73
|
+
h: 60 * 60 * 1000, // horas
|
|
74
|
+
d: 24 * 60 * 60 * 1000, // días
|
|
75
|
+
};
|
|
76
|
+
TimeParser.TIME_PATTERN = /^(\d+)([smhd])$/;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// tests/application/factory/auth-service-factory.spec.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const domain_1 = require("../../../src/domain");
|
|
5
|
+
const infrastructure_1 = require("../../../src/infrastructure");
|
|
6
|
+
const use_cases_1 = require("../../../src/application/use-cases");
|
|
7
|
+
const application_1 = require("src/application");
|
|
8
|
+
describe("AuthServiceFactory", () => {
|
|
9
|
+
let config;
|
|
10
|
+
let userRepository;
|
|
11
|
+
let credentialRepository;
|
|
12
|
+
// const algorithm: AnyAlgorithm = "HS256";
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
config = {
|
|
15
|
+
jwt: {
|
|
16
|
+
accessTokenSecret: "access-secret",
|
|
17
|
+
refreshTokenSecret: "refresh-secret",
|
|
18
|
+
accessTokenExpirationMs: 15 * 60 * 1000,
|
|
19
|
+
refreshTokenExpirationMs: 7 * 24 * 60 * 60 * 1000,
|
|
20
|
+
accessTokenExpiration: "15m",
|
|
21
|
+
refreshTokenExpiration: "7d",
|
|
22
|
+
},
|
|
23
|
+
info: {
|
|
24
|
+
issuer: "test-issuer",
|
|
25
|
+
audience: "test-audience",
|
|
26
|
+
},
|
|
27
|
+
bcrypt: {
|
|
28
|
+
saltRounds: 10,
|
|
29
|
+
},
|
|
30
|
+
algorithm: "HS256",
|
|
31
|
+
};
|
|
32
|
+
userRepository = new infrastructure_1.InMemoryUserRepository();
|
|
33
|
+
credentialRepository = new infrastructure_1.InMemoryCredentialRepository();
|
|
34
|
+
});
|
|
35
|
+
it("debería crear un contenedor con todas las dependencias correctamente instanciadas", () => {
|
|
36
|
+
const container = application_1.AuthServiceFactory.create(config, userRepository, credentialRepository);
|
|
37
|
+
// Repositorios: deben ser exactamente los mismos que pasamos
|
|
38
|
+
expect(container.userRepository).toBe(userRepository);
|
|
39
|
+
expect(container.credentialRepository).toBe(credentialRepository);
|
|
40
|
+
// Servicios de dominio / infraestructura
|
|
41
|
+
expect(container.passwordHasher).toBeInstanceOf(infrastructure_1.BcryptPasswordHasher);
|
|
42
|
+
expect(container.passwordPolicy).toBeInstanceOf(domain_1.DefaultPasswordPolicy);
|
|
43
|
+
expect(container.tokenService).toBeInstanceOf(infrastructure_1.JwtTokenService);
|
|
44
|
+
expect(container.tokenSession).toBeInstanceOf(infrastructure_1.TokenSessionService);
|
|
45
|
+
// Casos de uso
|
|
46
|
+
expect(container.registerUserUseCase).toBeInstanceOf(use_cases_1.RegisterUserUseCase);
|
|
47
|
+
expect(container.loginWithPasswordUseCase).toBeInstanceOf(use_cases_1.LoginWithPasswordUseCase);
|
|
48
|
+
expect(container.refreshTokenUseCase).toBeInstanceOf(use_cases_1.RefreshTokenUseCase);
|
|
49
|
+
expect(container.logoutUseCase).toBeInstanceOf(use_cases_1.LogoutUseCase);
|
|
50
|
+
});
|
|
51
|
+
it("debería inyectar correctamente JwtTokenService con la configuración JWT recibida", () => {
|
|
52
|
+
const container = application_1.AuthServiceFactory.create(config, userRepository, credentialRepository);
|
|
53
|
+
const tokenService = container.tokenService;
|
|
54
|
+
const jwtConfig = tokenService.config;
|
|
55
|
+
expect(jwtConfig.accessTokenSecret).toBe(config.jwt.accessTokenSecret);
|
|
56
|
+
expect(jwtConfig.refreshTokenSecret).toBe(config.jwt.refreshTokenSecret);
|
|
57
|
+
expect(jwtConfig.accessTokenExpirationMs).toBe(config.jwt.accessTokenExpirationMs);
|
|
58
|
+
expect(jwtConfig.refreshTokenExpirationMs).toBe(config.jwt.refreshTokenExpirationMs);
|
|
59
|
+
expect(tokenService.jwtGenerator).toBeInstanceOf(infrastructure_1.JwtTokenGenerator);
|
|
60
|
+
expect(tokenService.jwtVerifier).toBeInstanceOf(infrastructure_1.JwtTokenVerifier);
|
|
61
|
+
expect(tokenService.jwtValidator).toBeInstanceOf(infrastructure_1.JwtTokenValidator);
|
|
62
|
+
const jwtGenerator = tokenService.jwtGenerator;
|
|
63
|
+
expect(jwtGenerator.signer).toBeInstanceOf(infrastructure_1.JwtSigner);
|
|
64
|
+
expect(jwtGenerator.encoder).toBeDefined();
|
|
65
|
+
});
|
|
66
|
+
it("debería compartir las mismas instancias de repositorios y servicios entre los casos de uso", () => {
|
|
67
|
+
const container = application_1.AuthServiceFactory.create(config, userRepository, credentialRepository);
|
|
68
|
+
const { userRepository: ur, credentialRepository: cr, passwordHasher, passwordPolicy, tokenService, tokenSession, registerUserUseCase, loginWithPasswordUseCase, refreshTokenUseCase, logoutUseCase, } = container;
|
|
69
|
+
// RegisterUserUseCase
|
|
70
|
+
expect(registerUserUseCase.userRepository).toBe(ur);
|
|
71
|
+
expect(registerUserUseCase.passwordHasher).toBe(passwordHasher);
|
|
72
|
+
expect(registerUserUseCase.passwordPolicy).toBe(passwordPolicy);
|
|
73
|
+
// LoginWithPasswordUseCase
|
|
74
|
+
expect(loginWithPasswordUseCase.userRepository).toBe(ur);
|
|
75
|
+
expect(loginWithPasswordUseCase.passwordHasher).toBe(passwordHasher);
|
|
76
|
+
expect(loginWithPasswordUseCase.tokenSessionService).toBe(tokenSession);
|
|
77
|
+
// RefreshTokenUseCase
|
|
78
|
+
const refreshValues = Object.values(refreshTokenUseCase);
|
|
79
|
+
expect(refreshValues).toContain(tokenSession);
|
|
80
|
+
// LogoutUseCase
|
|
81
|
+
const logoutValues = Object.values(logoutUseCase);
|
|
82
|
+
expect(logoutValues).toContain(tokenSession);
|
|
83
|
+
// TokenSessionService wiring interno
|
|
84
|
+
expect(tokenSession.userRepository).toBe(ur);
|
|
85
|
+
expect(tokenSession.credentialRepository).toBe(cr);
|
|
86
|
+
expect(tokenSession.tokenService).toBe(tokenService);
|
|
87
|
+
});
|
|
88
|
+
it("debería respetar las instancias de repositorios entregadas por el llamador", () => {
|
|
89
|
+
const otherUserRepo = new infrastructure_1.InMemoryUserRepository();
|
|
90
|
+
const otherCredRepo = new infrastructure_1.InMemoryCredentialRepository();
|
|
91
|
+
const container = application_1.AuthServiceFactory.create(config, otherUserRepo, otherCredRepo);
|
|
92
|
+
expect(container.userRepository).toBe(otherUserRepo);
|
|
93
|
+
expect(container.credentialRepository).toBe(otherCredRepo);
|
|
94
|
+
expect(container.userRepository).not.toBe(userRepository);
|
|
95
|
+
expect(container.credentialRepository).not.toBe(credentialRepository);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const application_1 = require("src/application");
|
|
4
|
+
const domain_1 = require("src/domain");
|
|
5
|
+
const infrastructure_1 = require("src/infrastructure");
|
|
6
|
+
/**
|
|
7
|
+
* FakeTokenSession usa el repositorio de credenciales real,
|
|
8
|
+
* pero genera tokens simples sin firmar, sólo para pruebas.
|
|
9
|
+
*/
|
|
10
|
+
class FakeTokenSession {
|
|
11
|
+
constructor(credentialRepo) {
|
|
12
|
+
this.credentialRepo = credentialRepo;
|
|
13
|
+
}
|
|
14
|
+
async createSession(user) {
|
|
15
|
+
const credential = new domain_1.Credential({
|
|
16
|
+
userId: user.id,
|
|
17
|
+
accessToken: `access-${user.id.getValue()}`,
|
|
18
|
+
refreshToken: `refresh-${user.id.getValue()}`,
|
|
19
|
+
expiresAt: new Date(Date.now() + 60 * 60 * 1000),
|
|
20
|
+
createdAt: new Date(),
|
|
21
|
+
});
|
|
22
|
+
await this.credentialRepo.save(credential);
|
|
23
|
+
return credential;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Constantes comunes
|
|
27
|
+
const plainPassword = "MySecureP@ssw0rd";
|
|
28
|
+
const bcryptHash = "$2b$10$CwTycUXWue0Thq9StjUM0uJ8E9aG7vlYgSi0hd0eZBwbNG0Ax7Anm";
|
|
29
|
+
describe("LoginWithPasswordUseCase (integración con repositorios en memoria)", () => {
|
|
30
|
+
let userRepository;
|
|
31
|
+
let credentialRepository;
|
|
32
|
+
let passwordHasher;
|
|
33
|
+
let tokenSessionService;
|
|
34
|
+
let createSessionSpy;
|
|
35
|
+
let useCase;
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
userRepository = new infrastructure_1.InMemoryUserRepository();
|
|
38
|
+
credentialRepository = new infrastructure_1.InMemoryCredentialRepository();
|
|
39
|
+
passwordHasher = {
|
|
40
|
+
hash: jest.fn(),
|
|
41
|
+
compare: jest.fn(),
|
|
42
|
+
};
|
|
43
|
+
tokenSessionService = new FakeTokenSession(credentialRepository);
|
|
44
|
+
createSessionSpy = jest.spyOn(tokenSessionService, "createSession");
|
|
45
|
+
useCase = new application_1.LoginWithPasswordUseCase(userRepository, passwordHasher, tokenSessionService);
|
|
46
|
+
});
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
jest.clearAllMocks();
|
|
49
|
+
});
|
|
50
|
+
const createUser = (props) => new domain_1.User({
|
|
51
|
+
id: new domain_1.Id("user-123"),
|
|
52
|
+
email: new domain_1.Email("login@example.com"),
|
|
53
|
+
password: new domain_1.HashedPassword(bcryptHash),
|
|
54
|
+
isActive: true,
|
|
55
|
+
roles: [new domain_1.Role("user")],
|
|
56
|
+
createdAt: new Date(),
|
|
57
|
+
updatedAt: new Date(),
|
|
58
|
+
...props,
|
|
59
|
+
});
|
|
60
|
+
it("debe crear una sesión persistida al loguear correctamente", async () => {
|
|
61
|
+
const emailValue = "login@example.com";
|
|
62
|
+
const user = createUser({ email: new domain_1.Email(emailValue) });
|
|
63
|
+
await userRepository.save(user);
|
|
64
|
+
passwordHasher.compare.mockResolvedValue(true);
|
|
65
|
+
const request = {
|
|
66
|
+
email: emailValue,
|
|
67
|
+
password: plainPassword,
|
|
68
|
+
};
|
|
69
|
+
// Act
|
|
70
|
+
const response = await useCase.execute(request);
|
|
71
|
+
// Assert: respuesta
|
|
72
|
+
expect(response.accessToken).toBe("access-user-123");
|
|
73
|
+
expect(response.refreshToken).toBe("refresh-user-123");
|
|
74
|
+
// Assert: credencial persistida en el repositorio
|
|
75
|
+
const storedCredential = await credentialRepository.findByUserId(user.id);
|
|
76
|
+
expect(storedCredential).not.toBeNull();
|
|
77
|
+
expect(storedCredential?.accessToken).toBe("access-user-123");
|
|
78
|
+
expect(storedCredential?.refreshToken).toBe("refresh-user-123");
|
|
79
|
+
// Assert: se llamó a createSession
|
|
80
|
+
expect(createSessionSpy).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(createSessionSpy).toHaveBeenCalledWith(user);
|
|
82
|
+
});
|
|
83
|
+
it("debe loguear correctamente cuando las credenciales son válidas y el usuario está activo", async () => {
|
|
84
|
+
const emailValue = "user@example.com";
|
|
85
|
+
const user = createUser({ email: new domain_1.Email(emailValue) });
|
|
86
|
+
await userRepository.save(user);
|
|
87
|
+
passwordHasher.compare.mockResolvedValue(true);
|
|
88
|
+
const request = {
|
|
89
|
+
email: emailValue,
|
|
90
|
+
password: plainPassword,
|
|
91
|
+
};
|
|
92
|
+
// Act
|
|
93
|
+
const response = await useCase.execute(request);
|
|
94
|
+
// Assert
|
|
95
|
+
expect(passwordHasher.compare).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(passwordHasher.compare).toHaveBeenCalledWith(request.password, user.password.serialize());
|
|
97
|
+
expect(createSessionSpy).toHaveBeenCalledTimes(1);
|
|
98
|
+
expect(createSessionSpy).toHaveBeenCalledWith(user);
|
|
99
|
+
expect(response).toEqual({
|
|
100
|
+
accessToken: "access-user-123",
|
|
101
|
+
refreshToken: "refresh-user-123",
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it("debe lanzar UserNotFoundError cuando el usuario no existe", async () => {
|
|
105
|
+
const request = {
|
|
106
|
+
email: "unknown@example.com",
|
|
107
|
+
password: "whatever",
|
|
108
|
+
};
|
|
109
|
+
await expect(useCase.execute(request)).rejects.toBeInstanceOf(domain_1.UserNotFoundError);
|
|
110
|
+
expect(passwordHasher.compare).not.toHaveBeenCalled();
|
|
111
|
+
expect(createSessionSpy).not.toHaveBeenCalled();
|
|
112
|
+
});
|
|
113
|
+
it("debe lanzar UserDisabledError cuando el usuario está inactivo", async () => {
|
|
114
|
+
const emailValue = "disabled@example.com";
|
|
115
|
+
const user = createUser({ email: new domain_1.Email(emailValue) });
|
|
116
|
+
// Forzamos que canLogin() devuelva false
|
|
117
|
+
jest.spyOn(user, "canLogin").mockReturnValue(false);
|
|
118
|
+
await userRepository.save(user);
|
|
119
|
+
const request = {
|
|
120
|
+
email: emailValue,
|
|
121
|
+
password: "any-password",
|
|
122
|
+
};
|
|
123
|
+
await expect(useCase.execute(request)).rejects.toBeInstanceOf(domain_1.UserDisabledError);
|
|
124
|
+
expect(passwordHasher.compare).not.toHaveBeenCalled();
|
|
125
|
+
expect(createSessionSpy).not.toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
it("debe lanzar PasswordMismatchError cuando la contraseña es incorrecta", async () => {
|
|
128
|
+
const emailValue = "user@example.com";
|
|
129
|
+
const user = createUser({ email: new domain_1.Email(emailValue) });
|
|
130
|
+
await userRepository.save(user);
|
|
131
|
+
passwordHasher.compare.mockResolvedValue(false);
|
|
132
|
+
const request = {
|
|
133
|
+
email: emailValue,
|
|
134
|
+
password: "wrong-password",
|
|
135
|
+
};
|
|
136
|
+
await expect(useCase.execute(request)).rejects.toBeInstanceOf(domain_1.PasswordMismatchError);
|
|
137
|
+
expect(passwordHasher.compare).toHaveBeenCalledTimes(1);
|
|
138
|
+
expect(createSessionSpy).not.toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// tests/application/use-cases/logout.usecase.spec.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const application_1 = require("src/application");
|
|
5
|
+
const domain_1 = require("../../../src/domain");
|
|
6
|
+
describe("LogoutUseCase", () => {
|
|
7
|
+
let tokenSessionMock;
|
|
8
|
+
let useCase;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
tokenSessionMock = {
|
|
11
|
+
revokeSession: jest.fn(),
|
|
12
|
+
};
|
|
13
|
+
// Solo necesitamos revokeSession para este caso de uso,
|
|
14
|
+
// así que casteamos al tipo completo de ITokenSession.
|
|
15
|
+
useCase = new application_1.LogoutUseCase(tokenSessionMock);
|
|
16
|
+
});
|
|
17
|
+
it("debería cerrar sesión correctamente cuando revokeSession no lanza error", async () => {
|
|
18
|
+
// Arrange
|
|
19
|
+
const request = { refreshToken: "valid-refresh-token" };
|
|
20
|
+
tokenSessionMock.revokeSession.mockResolvedValueOnce(); // Promise<void>
|
|
21
|
+
// Act
|
|
22
|
+
const response = await useCase.execute(request);
|
|
23
|
+
// Assert
|
|
24
|
+
expect(tokenSessionMock.revokeSession).toHaveBeenCalledTimes(1);
|
|
25
|
+
expect(tokenSessionMock.revokeSession).toHaveBeenCalledWith("valid-refresh-token");
|
|
26
|
+
expect(response).toEqual({
|
|
27
|
+
success: true,
|
|
28
|
+
message: "Successfully logged out",
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
it("debería lanzar LogoutError cuando revokeSession lanza un error", async () => {
|
|
32
|
+
// Arrange
|
|
33
|
+
const request = { refreshToken: "invalid-refresh-token" };
|
|
34
|
+
tokenSessionMock.revokeSession.mockRejectedValueOnce(new Error("Some low-level error"));
|
|
35
|
+
// Act & Assert
|
|
36
|
+
await expect(useCase.execute(request)).rejects.toEqual(new domain_1.LogoutError("Failed to logout: invalid refresh token"));
|
|
37
|
+
expect(tokenSessionMock.revokeSession).toHaveBeenCalledTimes(1);
|
|
38
|
+
expect(tokenSessionMock.revokeSession).toHaveBeenCalledWith("invalid-refresh-token");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const application_1 = require("src/application");
|
|
4
|
+
const refresh_token_use_case_1 = require("src/application/use-cases/refresh-token.use-case");
|
|
5
|
+
const domain_1 = require("src/domain");
|
|
6
|
+
const infrastructure_1 = require("src/infrastructure");
|
|
7
|
+
const shared_1 = require("src/shared");
|
|
8
|
+
describe("RefreshTokenUseCase", () => {
|
|
9
|
+
let userRepo;
|
|
10
|
+
let credentialRepo;
|
|
11
|
+
let passwordHasher;
|
|
12
|
+
let jwtSigner;
|
|
13
|
+
let tokenGenerator;
|
|
14
|
+
let tokenSessionService;
|
|
15
|
+
const jwtConfig = {
|
|
16
|
+
accessTokenSecret: "access_secret_key_123",
|
|
17
|
+
refreshTokenSecret: "refresh_secret_key_123",
|
|
18
|
+
accessTokenExpirationMs: 1000 * 60 * 15, // 15 minutos
|
|
19
|
+
refreshTokenExpirationMs: 1000 * 60 * 60 * 24, // 1 día,
|
|
20
|
+
algorithm: "HS256",
|
|
21
|
+
};
|
|
22
|
+
// Hash válido de "Password123!" (cost 10)
|
|
23
|
+
const VALID_BCRYPT = "$2b$10$CwTycUXWue0Thq9StjUM0uJ8rS8o9VZqvE8G9W9C6q7CwTycUXWu2";
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
userRepo = new infrastructure_1.InMemoryUserRepository();
|
|
26
|
+
credentialRepo = new infrastructure_1.InMemoryCredentialRepository();
|
|
27
|
+
passwordHasher = new infrastructure_1.BcryptPasswordHasher();
|
|
28
|
+
jwtSigner = new infrastructure_1.JwtSigner(new shared_1.Base64UrlEncoder());
|
|
29
|
+
// 👇 Ajuste: orden típico (signer, encoder). Mantén tu firma real si difiere.
|
|
30
|
+
tokenGenerator = new infrastructure_1.JwtTokenGenerator(new shared_1.Base64UrlEncoder(), jwtSigner);
|
|
31
|
+
// TokenSessionJWT implementa ITokenSession
|
|
32
|
+
class TokenSessionJWT {
|
|
33
|
+
constructor(tokenGen, credentialRepo) {
|
|
34
|
+
this.tokenGen = tokenGen;
|
|
35
|
+
this.credentialRepo = credentialRepo;
|
|
36
|
+
}
|
|
37
|
+
validateSession(_accessToken) {
|
|
38
|
+
throw new Error("Method not implemented.");
|
|
39
|
+
}
|
|
40
|
+
async createSession(user) {
|
|
41
|
+
const accessToken = this.tokenGen.generateAccessToken({
|
|
42
|
+
user: {
|
|
43
|
+
id: user.id.getValue(),
|
|
44
|
+
email: user.email.toString(),
|
|
45
|
+
roles: user.roles.map((r) => ({ role: r.getValuePublic().role })),
|
|
46
|
+
},
|
|
47
|
+
config: jwtConfig,
|
|
48
|
+
});
|
|
49
|
+
const refreshToken = this.tokenGen.generateRefreshToken({
|
|
50
|
+
user: {
|
|
51
|
+
id: user.id.getValue(),
|
|
52
|
+
email: user.email.toString(),
|
|
53
|
+
roles: user.roles.map((r) => ({ role: r.getValuePublic().role })),
|
|
54
|
+
},
|
|
55
|
+
config: jwtConfig,
|
|
56
|
+
});
|
|
57
|
+
const credential = new domain_1.Credential({
|
|
58
|
+
userId: new domain_1.Id(user.id.getValue()),
|
|
59
|
+
accessToken,
|
|
60
|
+
refreshToken,
|
|
61
|
+
expiresAt: new Date(Date.now() + jwtConfig.accessTokenExpirationMs),
|
|
62
|
+
createdAt: new Date(),
|
|
63
|
+
});
|
|
64
|
+
await this.credentialRepo.save(credential);
|
|
65
|
+
return credential;
|
|
66
|
+
}
|
|
67
|
+
async refreshSession(refreshToken) {
|
|
68
|
+
const found = await this.credentialRepo.findByRefreshToken(refreshToken);
|
|
69
|
+
if (!found)
|
|
70
|
+
throw new domain_1.InvalidOrExpiredRefreshTokenError();
|
|
71
|
+
// ✅ (opcional) rotar: revocar el refresh anterior para evitar reutilización
|
|
72
|
+
await this.credentialRepo.deleteByRefreshToken(refreshToken);
|
|
73
|
+
const user = new domain_1.User({
|
|
74
|
+
id: new domain_1.Id(found.userId.getValue()),
|
|
75
|
+
email: new domain_1.Email("user@example.com"),
|
|
76
|
+
roles: [new domain_1.Role("USER")],
|
|
77
|
+
password: new domain_1.HashedPassword(VALID_BCRYPT),
|
|
78
|
+
isActive: true,
|
|
79
|
+
createdAt: new Date(),
|
|
80
|
+
updatedAt: new Date(),
|
|
81
|
+
});
|
|
82
|
+
return this.createSession(user);
|
|
83
|
+
}
|
|
84
|
+
async revokeSession(refreshToken) {
|
|
85
|
+
await this.credentialRepo.deleteByRefreshToken(refreshToken);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
tokenSessionService = new TokenSessionJWT(tokenGenerator, credentialRepo);
|
|
89
|
+
});
|
|
90
|
+
it("debería crear un usuario, loguearlo y refrescar su token", async () => {
|
|
91
|
+
// 1️⃣ Registrar usuario
|
|
92
|
+
const passwordPolicy = new domain_1.DefaultPasswordPolicy();
|
|
93
|
+
const registerUser = new application_1.RegisterUserUseCase(userRepo, passwordHasher, passwordPolicy);
|
|
94
|
+
const email = "user@example.com";
|
|
95
|
+
const password = "Password123!";
|
|
96
|
+
const roles = [{ role: "USER" }];
|
|
97
|
+
await registerUser.execute({ email, password, roles });
|
|
98
|
+
// 2️⃣ Loguear usuario
|
|
99
|
+
const login = new application_1.LoginWithPasswordUseCase(userRepo, passwordHasher, tokenSessionService);
|
|
100
|
+
const loginResponse = await login.execute({ email, password });
|
|
101
|
+
expect(loginResponse.accessToken).toBeDefined();
|
|
102
|
+
expect(loginResponse.refreshToken).toBeDefined();
|
|
103
|
+
// 3️⃣ Refrescar Token
|
|
104
|
+
const refreshTokenUseCase = new refresh_token_use_case_1.RefreshTokenUseCase(tokenSessionService);
|
|
105
|
+
const refreshed = await refreshTokenUseCase.execute({
|
|
106
|
+
refreshToken: loginResponse.refreshToken,
|
|
107
|
+
});
|
|
108
|
+
expect(refreshed.accessToken).toBeDefined();
|
|
109
|
+
expect(refreshed.refreshToken).toBeDefined();
|
|
110
|
+
expect(refreshed.refreshToken).not.toEqual(loginResponse.refreshToken);
|
|
111
|
+
});
|
|
112
|
+
it("debería lanzar InvalidOrExpiredRefreshTokenError si el token no existe", async () => {
|
|
113
|
+
const refreshTokenUseCase = new refresh_token_use_case_1.RefreshTokenUseCase(tokenSessionService);
|
|
114
|
+
await expect(refreshTokenUseCase.execute({ refreshToken: "invalid.token" })).rejects.toThrow(domain_1.InvalidOrExpiredRefreshTokenError);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const application_1 = require("src/application");
|
|
4
|
+
const domain_1 = require("src/domain");
|
|
5
|
+
describe("RegisterUserUseCase", () => {
|
|
6
|
+
let userRepository;
|
|
7
|
+
let passwordHasher;
|
|
8
|
+
let passwordPolicy;
|
|
9
|
+
let useCase;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
userRepository = {
|
|
12
|
+
findByEmail: jest.fn(),
|
|
13
|
+
save: jest.fn(),
|
|
14
|
+
// agrega otros métodos del repo si existen, con jest.fn()
|
|
15
|
+
};
|
|
16
|
+
passwordHasher = {
|
|
17
|
+
hash: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
passwordPolicy = {
|
|
20
|
+
validateStrength: jest.fn(),
|
|
21
|
+
getRequirements: jest.fn(),
|
|
22
|
+
};
|
|
23
|
+
useCase = new application_1.RegisterUserUseCase(userRepository, passwordHasher, passwordPolicy);
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
it("debería lanzar PasswordPolicyViolationError si la contraseña no cumple la política", async () => {
|
|
27
|
+
const weakPasswordErrors = ["Too short", "No number"];
|
|
28
|
+
passwordPolicy.validateStrength.mockReturnValue({
|
|
29
|
+
isValid: false,
|
|
30
|
+
errors: weakPasswordErrors,
|
|
31
|
+
});
|
|
32
|
+
const request = {
|
|
33
|
+
email: "test@example.com",
|
|
34
|
+
password: "weak",
|
|
35
|
+
roles: [],
|
|
36
|
+
};
|
|
37
|
+
await expect(useCase.execute(request)).rejects.toBeInstanceOf(domain_1.PasswordPolicyViolationError);
|
|
38
|
+
expect(passwordPolicy.validateStrength).toHaveBeenCalledWith(request.password);
|
|
39
|
+
expect(userRepository.findByEmail).not.toHaveBeenCalled();
|
|
40
|
+
expect(passwordHasher.hash).not.toHaveBeenCalled();
|
|
41
|
+
expect(userRepository.save).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
it("debería lanzar EmailAlreadyInUseError si el email ya existe", async () => {
|
|
44
|
+
passwordPolicy.validateStrength.mockReturnValue({
|
|
45
|
+
isValid: true,
|
|
46
|
+
errors: [],
|
|
47
|
+
});
|
|
48
|
+
// No necesitamos un User real, basta con algo truthy
|
|
49
|
+
const existingUser = {};
|
|
50
|
+
userRepository.findByEmail.mockResolvedValue(existingUser);
|
|
51
|
+
const request = {
|
|
52
|
+
email: "used@example.com",
|
|
53
|
+
password: "StrongP@ss1",
|
|
54
|
+
roles: [],
|
|
55
|
+
};
|
|
56
|
+
await expect(useCase.execute(request)).rejects.toBeInstanceOf(domain_1.EmailAlreadyInUseError);
|
|
57
|
+
expect(passwordPolicy.validateStrength).toHaveBeenCalledWith(request.password);
|
|
58
|
+
expect(userRepository.findByEmail).toHaveBeenCalledTimes(1);
|
|
59
|
+
expect(passwordHasher.hash).not.toHaveBeenCalled();
|
|
60
|
+
expect(userRepository.save).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
it("debería registrar un usuario, guardar en el repositorio y retornar la respuesta correcta", async () => {
|
|
63
|
+
passwordPolicy.validateStrength.mockReturnValue({
|
|
64
|
+
isValid: true,
|
|
65
|
+
errors: [],
|
|
66
|
+
});
|
|
67
|
+
userRepository.findByEmail.mockResolvedValue(null);
|
|
68
|
+
const hashedPassword = "hashed-password-123";
|
|
69
|
+
passwordHasher.hash.mockResolvedValue(hashedPassword);
|
|
70
|
+
const request = {
|
|
71
|
+
email: "newuser@example.com",
|
|
72
|
+
password: "StrongP@ss1",
|
|
73
|
+
roles: [
|
|
74
|
+
{
|
|
75
|
+
role: "ADMIN",
|
|
76
|
+
permissions: ["user.read", "user.write"],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
// Fake user que retornará User.create
|
|
81
|
+
const fakeUserIdValue = "generated-user-id";
|
|
82
|
+
const fakePublicRoles = [
|
|
83
|
+
{
|
|
84
|
+
role: "ADMIN",
|
|
85
|
+
permissions: ["user.read", "user.write"],
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
const fakeUser = {
|
|
89
|
+
id: {
|
|
90
|
+
getValue: jest.fn().mockReturnValue(fakeUserIdValue),
|
|
91
|
+
},
|
|
92
|
+
roles: [
|
|
93
|
+
{
|
|
94
|
+
getValuePublic: jest.fn().mockReturnValue(fakePublicRoles[0]),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
isActive: true,
|
|
98
|
+
};
|
|
99
|
+
const createSpy = jest
|
|
100
|
+
.spyOn(domain_1.User, "create")
|
|
101
|
+
.mockReturnValue(fakeUser);
|
|
102
|
+
const result = await useCase.execute(request);
|
|
103
|
+
// Validar interacción con passwordPolicy y repos
|
|
104
|
+
expect(passwordPolicy.validateStrength).toHaveBeenCalledWith(request.password);
|
|
105
|
+
expect(userRepository.findByEmail).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(passwordHasher.hash).toHaveBeenCalledWith(request.password);
|
|
107
|
+
// Validar que se llama User.create con los argumentos esperados
|
|
108
|
+
expect(createSpy).toHaveBeenCalledWith(request.email, expect.arrayContaining([
|
|
109
|
+
expect.objectContaining({}), // aquí solo validamos que se pasó al menos un Role
|
|
110
|
+
]), hashedPassword);
|
|
111
|
+
// Validar que se persiste el usuario
|
|
112
|
+
expect(userRepository.save).toHaveBeenCalledWith(fakeUser);
|
|
113
|
+
const expectedResponse = {
|
|
114
|
+
id: fakeUserIdValue,
|
|
115
|
+
roles: fakePublicRoles,
|
|
116
|
+
isActive: true,
|
|
117
|
+
};
|
|
118
|
+
expect(result).toEqual(expectedResponse);
|
|
119
|
+
});
|
|
120
|
+
it("debería permitir registrar usuario sin roles (array vacío por defecto)", async () => {
|
|
121
|
+
passwordPolicy.validateStrength.mockReturnValue({
|
|
122
|
+
isValid: true,
|
|
123
|
+
errors: [],
|
|
124
|
+
});
|
|
125
|
+
userRepository.findByEmail.mockResolvedValue(null);
|
|
126
|
+
const hashedPassword = "hashed-no-roles";
|
|
127
|
+
passwordHasher.hash.mockResolvedValue(hashedPassword);
|
|
128
|
+
const request = {
|
|
129
|
+
email: "noroles@example.com",
|
|
130
|
+
password: "StrongP@ss1",
|
|
131
|
+
// roles: undefined
|
|
132
|
+
};
|
|
133
|
+
const fakeUser = {
|
|
134
|
+
id: {
|
|
135
|
+
getValue: jest.fn().mockReturnValue("no-roles-id"),
|
|
136
|
+
},
|
|
137
|
+
roles: [],
|
|
138
|
+
isActive: true,
|
|
139
|
+
};
|
|
140
|
+
jest.spyOn(domain_1.User, "create").mockReturnValue(fakeUser);
|
|
141
|
+
const result = await useCase.execute(request);
|
|
142
|
+
expect(userRepository.findByEmail).toHaveBeenCalledTimes(1);
|
|
143
|
+
expect(passwordHasher.hash).toHaveBeenCalledWith(request.password);
|
|
144
|
+
expect(userRepository.save).toHaveBeenCalledWith(fakeUser);
|
|
145
|
+
expect(result).toEqual({
|
|
146
|
+
id: "no-roles-id",
|
|
147
|
+
roles: [],
|
|
148
|
+
isActive: true,
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|