@shipfox/api-auth 10.1.0 → 11.0.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +30 -0
- package/README.md +42 -11
- package/dist/core/administration.d.ts +17 -1
- package/dist/core/administration.d.ts.map +1 -1
- package/dist/core/administration.js +107 -14
- package/dist/core/administration.js.map +1 -1
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +27 -10
- package/dist/core/auth.js.map +1 -1
- package/dist/core/jwt.d.ts +10 -0
- package/dist/core/jwt.d.ts.map +1 -1
- package/dist/core/jwt.js +3 -2
- package/dist/core/jwt.js.map +1 -1
- package/dist/db/admin-command.d.ts +18 -0
- package/dist/db/admin-command.d.ts.map +1 -0
- package/dist/db/admin-command.js +37 -0
- package/dist/db/admin-command.js.map +1 -0
- package/dist/db/admin-grants.d.ts +1 -1
- package/dist/db/admin-grants.d.ts.map +1 -1
- package/dist/db/admin-grants.js +12 -30
- package/dist/db/admin-grants.js.map +1 -1
- package/dist/db/admin-user-moderation.d.ts +29 -0
- package/dist/db/admin-user-moderation.d.ts.map +1 -0
- package/dist/db/admin-user-moderation.js +156 -0
- package/dist/db/admin-user-moderation.js.map +1 -0
- package/dist/db/admin-user-summary.d.ts +14 -0
- package/dist/db/admin-user-summary.d.ts.map +1 -0
- package/dist/db/admin-user-summary.js +31 -0
- package/dist/db/admin-user-summary.js.map +1 -0
- package/dist/db/admin-users.d.ts +2 -11
- package/dist/db/admin-users.d.ts.map +1 -1
- package/dist/db/admin-users.js +2 -27
- package/dist/db/admin-users.js.map +1 -1
- package/dist/db/refresh-tokens.d.ts +6 -4
- package/dist/db/refresh-tokens.d.ts.map +1 -1
- package/dist/db/refresh-tokens.js +31 -6
- package/dist/db/refresh-tokens.js.map +1 -1
- package/dist/db/schema/admin-command-results.d.ts +19 -2
- package/dist/db/schema/admin-command-results.d.ts.map +1 -1
- package/dist/db/schema/admin-command-results.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/presentation/auth/bearer-token-auth.d.ts +1 -0
- package/dist/presentation/auth/bearer-token-auth.d.ts.map +1 -1
- package/dist/presentation/auth/bearer-token-auth.js +4 -3
- package/dist/presentation/auth/bearer-token-auth.js.map +1 -1
- package/dist/presentation/auth/jwt-auth.d.ts +1 -4
- package/dist/presentation/auth/jwt-auth.d.ts.map +1 -1
- package/dist/presentation/auth/jwt-auth.js +23 -19
- package/dist/presentation/auth/jwt-auth.js.map +1 -1
- package/dist/presentation/routes/administration.d.ts.map +1 -1
- package/dist/presentation/routes/administration.js +94 -3
- package/dist/presentation/routes/administration.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/core/administration.ts +137 -15
- package/src/core/auth.test.ts +29 -10
- package/src/core/auth.ts +36 -14
- package/src/core/jwt.test.ts +20 -4
- package/src/core/jwt.ts +2 -1
- package/src/db/admin-command.ts +85 -0
- package/src/db/admin-grants.ts +19 -57
- package/src/db/admin-user-moderation.ts +230 -0
- package/src/db/admin-user-summary.ts +51 -0
- package/src/db/admin-users.ts +4 -49
- package/src/db/refresh-tokens.test.ts +0 -19
- package/src/db/refresh-tokens.ts +54 -23
- package/src/db/schema/admin-command-results.ts +23 -2
- package/src/index.ts +3 -0
- package/src/presentation/auth/bearer-token-auth.test.ts +17 -0
- package/src/presentation/auth/bearer-token-auth.ts +9 -2
- package/src/presentation/auth/jwt-auth.test.ts +34 -9
- package/src/presentation/auth/jwt-auth.ts +19 -13
- package/src/presentation/routes/administration.test.ts +253 -2
- package/src/presentation/routes/administration.ts +88 -1
- package/src/presentation/routes/password/change-password.test.ts +6 -0
- package/src/presentation/routes/password/password-reset-confirm.test.ts +14 -0
- package/src/presentation/routes/registration/signup.test.ts +2 -2
- package/src/presentation/routes/session/logout.test.ts +6 -0
- package/src/presentation/routes/session/refresh.test.ts +11 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n AUTH_PASSWORD_RESET_SEND_REQUESTED,\n type AuthEventMap,\n authEventSchemas,\n} from '@shipfox/api-auth-dto';\nimport {administrationActionEventSchemas} from '@shipfox/api-common-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {subscriberFactory} from '@shipfox/node-module';\nimport {config} from '#config.js';\nimport type {SignupPolicy} from '#core/ports.js';\nimport {createEnvironmentSignupPolicy} from '#core/signup-policy.js';\nimport {db} from '#db/db.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {authOutbox} from '#db/schema/outbox.js';\nimport {createJwtAuthMethod} from '#presentation/auth/jwt-auth.js';\nimport {createLeaseTokenAuthMethod} from '#presentation/auth/lease-token-auth.js';\nimport {createRunnerSessionAuthMethod} from '#presentation/auth/runner-session-auth.js';\nimport {createAuthE2eRoutes} from '#presentation/e2eRoutes/index.js';\nimport {createAuthInterModulePresentation} from '#presentation/inter-module.js';\nimport {\n administrationBootstrapRoutes,\n administrationRoutes,\n administrationUserRoutes,\n} from '#presentation/routes/administration.js';\nimport {buildAuthRoutes} from '#presentation/routes/index.js';\nimport {onPasswordResetSendRequested} from '#presentation/subscribers/index.js';\nimport {passwordLoginMethods} from './login-methods.js';\n\nconst authPublisherEventSchemas = {...authEventSchemas, ...administrationActionEventSchemas};\n\nexport type {AdminRole, JobLeaseTokenClaims, RunnerSessionTokenClaims} from '@shipfox/api-auth-dto';\nexport {\n ADMIN_ROLES,\n getCurrentAdminRole,\n hasMinimumAdminRole,\n highestAdminRole,\n requireAdminRole,\n revokeAdminGrant,\n} from '#core/admin-role.js';\nexport {\n bootstrapFirstAdminOwner,\n grantAdministratorRole,\n revokeAdministratorGrant,\n} from '#core/administration.js';\nexport type {\n CreateSessionForUserError,\n CreateSessionForUserParams,\n CreateSessionForUserResult,\n ProvisionUserParams,\n} from '#core/auth.js';\nexport {createSessionForUser, provisionUser} from '#core/auth.js';\nexport type {EmailOwner, FindUserByEmailParams} from '#core/email-owner.js';\nexport {findUserByEmail} from '#core/email-owner.js';\nexport type {AdminGrant} from '#core/entities/admin-grant.js';\nexport type {User, UserStatus} from '#core/entities/user.js';\nexport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n AdminRoleRequiredError,\n AuthDependencyUnavailableError,\n EmailNotVerifiedError,\n InvalidAdminBootstrapTokenError,\n InvalidCredentialsError,\n LastAdminOwnerError,\n SignupNotAllowedError,\n UserNotFoundError,\n} from '#core/errors.js';\nexport {\n issueJobLeaseToken,\n jobLeaseParamsFrom,\n verifyJobLeaseToken,\n} from '#core/job-lease-token.js';\nexport type {SignupPolicy} from '#core/ports.js';\nexport {\n issueRunnerSessionToken,\n verifyRunnerSessionToken,\n} from '#core/runner-session-token.js';\nexport {\n createEnvironmentSignupPolicy,\n DEFAULT_SIGNUP_NOT_ALLOWED_MESSAGE,\n} from '#core/signup-policy.js';\nexport {\n type AuthenticatedSessionContext,\n createJwtAuthMethod,\n getAuthenticatedSessionContext,\n type RefreshSessionId,\n type UserId,\n} from '#presentation/auth/jwt-auth.js';\nexport {createLeaseTokenAuthMethod} from '#presentation/auth/lease-token-auth.js';\nexport {\n authCookiePlugin,\n clearRefreshTokenCookie,\n getRefreshTokenCookie,\n setRefreshTokenCookie,\n} from '#presentation/auth/refresh-cookie.js';\nexport {createRunnerSessionAuthMethod} from '#presentation/auth/runner-session-auth.js';\n\nconst subscriber = subscriberFactory<AuthEventMap>();\n\nexport interface CreateAuthModuleOptions {\n workspaces: import('@shipfox/api-workspaces-dto/inter-module').WorkspacesInterModuleClient;\n signupPolicy?: SignupPolicy;\n}\n\nexport function createAuthModule({\n workspaces,\n signupPolicy = createEnvironmentSignupPolicy(),\n}: CreateAuthModuleOptions): ShipfoxModule {\n return {\n name: 'auth',\n database: {db, migrationsPath, databaseNamespace: 'auth'},\n auth: [createJwtAuthMethod(), createLeaseTokenAuthMethod(), createRunnerSessionAuthMethod()],\n loginMethods: passwordLoginMethods(config.AUTH_PASSWORD_ENABLED),\n routes: [\n buildAuthRoutes(config.AUTH_PASSWORD_ENABLED, workspaces, signupPolicy),\n administrationBootstrapRoutes,\n administrationRoutes,\n administrationUserRoutes,\n ],\n e2eRoutes: [createAuthE2eRoutes(workspaces)],\n publishers: [{name: 'auth', table: authOutbox, db, eventSchemas: authPublisherEventSchemas}],\n subscribers: [subscriber(AUTH_PASSWORD_RESET_SEND_REQUESTED, onPasswordResetSendRequested)],\n interModulePresentations: [createAuthInterModulePresentation()],\n };\n}\n"],"names":["AUTH_PASSWORD_RESET_SEND_REQUESTED","authEventSchemas","administrationActionEventSchemas","subscriberFactory","config","createEnvironmentSignupPolicy","db","migrationsPath","authOutbox","createJwtAuthMethod","createLeaseTokenAuthMethod","createRunnerSessionAuthMethod","createAuthE2eRoutes","createAuthInterModulePresentation","administrationBootstrapRoutes","administrationRoutes","administrationUserRoutes","buildAuthRoutes","onPasswordResetSendRequested","passwordLoginMethods","authPublisherEventSchemas","ADMIN_ROLES","getCurrentAdminRole","hasMinimumAdminRole","highestAdminRole","requireAdminRole","revokeAdminGrant","bootstrapFirstAdminOwner","grantAdministratorRole","revokeAdministratorGrant","createSessionForUser","provisionUser","findUserByEmail","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","AdminRoleRequiredError","AuthDependencyUnavailableError","EmailNotVerifiedError","InvalidAdminBootstrapTokenError","InvalidCredentialsError","LastAdminOwnerError","SignupNotAllowedError","UserNotFoundError","issueJobLeaseToken","jobLeaseParamsFrom","verifyJobLeaseToken","issueRunnerSessionToken","verifyRunnerSessionToken","DEFAULT_SIGNUP_NOT_ALLOWED_MESSAGE","getAuthenticatedSessionContext","authCookiePlugin","clearRefreshTokenCookie","getRefreshTokenCookie","setRefreshTokenCookie","subscriber","createAuthModule","workspaces","signupPolicy","name","database","databaseNamespace","auth","loginMethods","AUTH_PASSWORD_ENABLED","routes","e2eRoutes","publishers","table","eventSchemas","subscribers","interModulePresentations"],"mappings":"AAAA,SACEA,kCAAkC,EAElCC,gBAAgB,QACX,wBAAwB;AAC/B,SAAQC,gCAAgC,QAAO,0BAA0B;AAEzE,SAAQC,iBAAiB,QAAO,uBAAuB;AACvD,SAAQC,MAAM,QAAO,aAAa;AAElC,SAAQC,6BAA6B,QAAO,yBAAyB;AACrE,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAAQC,UAAU,QAAO,uBAAuB;AAChD,SAAQC,mBAAmB,QAAO,iCAAiC;AACnE,SAAQC,0BAA0B,QAAO,yCAAyC;AAClF,SAAQC,6BAA6B,QAAO,4CAA4C;AACxF,SAAQC,mBAAmB,QAAO,mCAAmC;AACrE,SAAQC,iCAAiC,QAAO,gCAAgC;AAChF,SACEC,6BAA6B,EAC7BC,oBAAoB,EACpBC,wBAAwB,QACnB,yCAAyC;AAChD,SAAQC,eAAe,QAAO,gCAAgC;AAC9D,SAAQC,4BAA4B,QAAO,qCAAqC;AAChF,SAAQC,oBAAoB,QAAO,qBAAqB;AAExD,MAAMC,4BAA4B;IAAC,GAAGnB,gBAAgB;IAAE,GAAGC,gCAAgC;AAAA;AAG3F,SACEmB,WAAW,EACXC,mBAAmB,EACnBC,mBAAmB,EACnBC,gBAAgB,EAChBC,gBAAgB,EAChBC,gBAAgB,QACX,sBAAsB;AAC7B,SACEC,wBAAwB,EACxBC,sBAAsB,EACtBC,wBAAwB,QACnB,0BAA0B;AAOjC,SAAQC,oBAAoB,EAAEC,aAAa,QAAO,gBAAgB;AAElE,SAAQC,eAAe,QAAO,uBAAuB;AAGrD,SACEC,yBAAyB,EACzBC,4BAA4B,EAC5BC,uBAAuB,EACvBC,6BAA6B,EAC7BC,sBAAsB,EACtBC,8BAA8B,EAC9BC,qBAAqB,EACrBC,+BAA+B,EAC/BC,uBAAuB,EACvBC,mBAAmB,EACnBC,qBAAqB,EACrBC,iBAAiB,QACZ,kBAAkB;AACzB,SACEC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,QACd,2BAA2B;AAElC,SACEC,uBAAuB,EACvBC,wBAAwB,QACnB,gCAAgC;AACvC,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n AUTH_PASSWORD_RESET_SEND_REQUESTED,\n type AuthEventMap,\n authEventSchemas,\n} from '@shipfox/api-auth-dto';\nimport {administrationActionEventSchemas} from '@shipfox/api-common-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {subscriberFactory} from '@shipfox/node-module';\nimport {config} from '#config.js';\nimport type {SignupPolicy} from '#core/ports.js';\nimport {createEnvironmentSignupPolicy} from '#core/signup-policy.js';\nimport {db} from '#db/db.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {authOutbox} from '#db/schema/outbox.js';\nimport {createJwtAuthMethod} from '#presentation/auth/jwt-auth.js';\nimport {createLeaseTokenAuthMethod} from '#presentation/auth/lease-token-auth.js';\nimport {createRunnerSessionAuthMethod} from '#presentation/auth/runner-session-auth.js';\nimport {createAuthE2eRoutes} from '#presentation/e2eRoutes/index.js';\nimport {createAuthInterModulePresentation} from '#presentation/inter-module.js';\nimport {\n administrationBootstrapRoutes,\n administrationRoutes,\n administrationUserRoutes,\n} from '#presentation/routes/administration.js';\nimport {buildAuthRoutes} from '#presentation/routes/index.js';\nimport {onPasswordResetSendRequested} from '#presentation/subscribers/index.js';\nimport {passwordLoginMethods} from './login-methods.js';\n\nconst authPublisherEventSchemas = {...authEventSchemas, ...administrationActionEventSchemas};\n\nexport type {AdminRole, JobLeaseTokenClaims, RunnerSessionTokenClaims} from '@shipfox/api-auth-dto';\nexport {\n ADMIN_ROLES,\n getCurrentAdminRole,\n hasMinimumAdminRole,\n highestAdminRole,\n requireAdminRole,\n revokeAdminGrant,\n} from '#core/admin-role.js';\nexport {\n bootstrapFirstAdminOwner,\n grantAdministratorRole,\n reactivateAdministratorUser,\n revokeAdministratorGrant,\n revokeAdministratorUserSessions,\n suspendAdministratorUser,\n} from '#core/administration.js';\nexport type {\n CreateSessionForUserError,\n CreateSessionForUserParams,\n CreateSessionForUserResult,\n ProvisionUserParams,\n} from '#core/auth.js';\nexport {createSessionForUser, provisionUser} from '#core/auth.js';\nexport type {EmailOwner, FindUserByEmailParams} from '#core/email-owner.js';\nexport {findUserByEmail} from '#core/email-owner.js';\nexport type {AdminGrant} from '#core/entities/admin-grant.js';\nexport type {User, UserStatus} from '#core/entities/user.js';\nexport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n AdminRoleRequiredError,\n AuthDependencyUnavailableError,\n EmailNotVerifiedError,\n InvalidAdminBootstrapTokenError,\n InvalidCredentialsError,\n LastAdminOwnerError,\n SignupNotAllowedError,\n UserNotFoundError,\n} from '#core/errors.js';\nexport {\n issueJobLeaseToken,\n jobLeaseParamsFrom,\n verifyJobLeaseToken,\n} from '#core/job-lease-token.js';\nexport type {SignupPolicy} from '#core/ports.js';\nexport {\n issueRunnerSessionToken,\n verifyRunnerSessionToken,\n} from '#core/runner-session-token.js';\nexport {\n createEnvironmentSignupPolicy,\n DEFAULT_SIGNUP_NOT_ALLOWED_MESSAGE,\n} from '#core/signup-policy.js';\nexport {\n type AuthenticatedSessionContext,\n createJwtAuthMethod,\n getAuthenticatedSessionContext,\n type RefreshSessionId,\n type UserId,\n} from '#presentation/auth/jwt-auth.js';\nexport {createLeaseTokenAuthMethod} from '#presentation/auth/lease-token-auth.js';\nexport {\n authCookiePlugin,\n clearRefreshTokenCookie,\n getRefreshTokenCookie,\n setRefreshTokenCookie,\n} from '#presentation/auth/refresh-cookie.js';\nexport {createRunnerSessionAuthMethod} from '#presentation/auth/runner-session-auth.js';\n\nconst subscriber = subscriberFactory<AuthEventMap>();\n\nexport interface CreateAuthModuleOptions {\n workspaces: import('@shipfox/api-workspaces-dto/inter-module').WorkspacesInterModuleClient;\n signupPolicy?: SignupPolicy;\n}\n\nexport function createAuthModule({\n workspaces,\n signupPolicy = createEnvironmentSignupPolicy(),\n}: CreateAuthModuleOptions): ShipfoxModule {\n return {\n name: 'auth',\n database: {db, migrationsPath, databaseNamespace: 'auth'},\n auth: [createJwtAuthMethod(), createLeaseTokenAuthMethod(), createRunnerSessionAuthMethod()],\n loginMethods: passwordLoginMethods(config.AUTH_PASSWORD_ENABLED),\n routes: [\n buildAuthRoutes(config.AUTH_PASSWORD_ENABLED, workspaces, signupPolicy),\n administrationBootstrapRoutes,\n administrationRoutes,\n administrationUserRoutes,\n ],\n e2eRoutes: [createAuthE2eRoutes(workspaces)],\n publishers: [{name: 'auth', table: authOutbox, db, eventSchemas: authPublisherEventSchemas}],\n subscribers: [subscriber(AUTH_PASSWORD_RESET_SEND_REQUESTED, onPasswordResetSendRequested)],\n interModulePresentations: [createAuthInterModulePresentation()],\n };\n}\n"],"names":["AUTH_PASSWORD_RESET_SEND_REQUESTED","authEventSchemas","administrationActionEventSchemas","subscriberFactory","config","createEnvironmentSignupPolicy","db","migrationsPath","authOutbox","createJwtAuthMethod","createLeaseTokenAuthMethod","createRunnerSessionAuthMethod","createAuthE2eRoutes","createAuthInterModulePresentation","administrationBootstrapRoutes","administrationRoutes","administrationUserRoutes","buildAuthRoutes","onPasswordResetSendRequested","passwordLoginMethods","authPublisherEventSchemas","ADMIN_ROLES","getCurrentAdminRole","hasMinimumAdminRole","highestAdminRole","requireAdminRole","revokeAdminGrant","bootstrapFirstAdminOwner","grantAdministratorRole","reactivateAdministratorUser","revokeAdministratorGrant","revokeAdministratorUserSessions","suspendAdministratorUser","createSessionForUser","provisionUser","findUserByEmail","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","AdminRoleRequiredError","AuthDependencyUnavailableError","EmailNotVerifiedError","InvalidAdminBootstrapTokenError","InvalidCredentialsError","LastAdminOwnerError","SignupNotAllowedError","UserNotFoundError","issueJobLeaseToken","jobLeaseParamsFrom","verifyJobLeaseToken","issueRunnerSessionToken","verifyRunnerSessionToken","DEFAULT_SIGNUP_NOT_ALLOWED_MESSAGE","getAuthenticatedSessionContext","authCookiePlugin","clearRefreshTokenCookie","getRefreshTokenCookie","setRefreshTokenCookie","subscriber","createAuthModule","workspaces","signupPolicy","name","database","databaseNamespace","auth","loginMethods","AUTH_PASSWORD_ENABLED","routes","e2eRoutes","publishers","table","eventSchemas","subscribers","interModulePresentations"],"mappings":"AAAA,SACEA,kCAAkC,EAElCC,gBAAgB,QACX,wBAAwB;AAC/B,SAAQC,gCAAgC,QAAO,0BAA0B;AAEzE,SAAQC,iBAAiB,QAAO,uBAAuB;AACvD,SAAQC,MAAM,QAAO,aAAa;AAElC,SAAQC,6BAA6B,QAAO,yBAAyB;AACrE,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAAQC,UAAU,QAAO,uBAAuB;AAChD,SAAQC,mBAAmB,QAAO,iCAAiC;AACnE,SAAQC,0BAA0B,QAAO,yCAAyC;AAClF,SAAQC,6BAA6B,QAAO,4CAA4C;AACxF,SAAQC,mBAAmB,QAAO,mCAAmC;AACrE,SAAQC,iCAAiC,QAAO,gCAAgC;AAChF,SACEC,6BAA6B,EAC7BC,oBAAoB,EACpBC,wBAAwB,QACnB,yCAAyC;AAChD,SAAQC,eAAe,QAAO,gCAAgC;AAC9D,SAAQC,4BAA4B,QAAO,qCAAqC;AAChF,SAAQC,oBAAoB,QAAO,qBAAqB;AAExD,MAAMC,4BAA4B;IAAC,GAAGnB,gBAAgB;IAAE,GAAGC,gCAAgC;AAAA;AAG3F,SACEmB,WAAW,EACXC,mBAAmB,EACnBC,mBAAmB,EACnBC,gBAAgB,EAChBC,gBAAgB,EAChBC,gBAAgB,QACX,sBAAsB;AAC7B,SACEC,wBAAwB,EACxBC,sBAAsB,EACtBC,2BAA2B,EAC3BC,wBAAwB,EACxBC,+BAA+B,EAC/BC,wBAAwB,QACnB,0BAA0B;AAOjC,SAAQC,oBAAoB,EAAEC,aAAa,QAAO,gBAAgB;AAElE,SAAQC,eAAe,QAAO,uBAAuB;AAGrD,SACEC,yBAAyB,EACzBC,4BAA4B,EAC5BC,uBAAuB,EACvBC,6BAA6B,EAC7BC,sBAAsB,EACtBC,8BAA8B,EAC9BC,qBAAqB,EACrBC,+BAA+B,EAC/BC,uBAAuB,EACvBC,mBAAmB,EACnBC,qBAAqB,EACrBC,iBAAiB,QACZ,kBAAkB;AACzB,SACEC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,QACd,2BAA2B;AAElC,SACEC,uBAAuB,EACvBC,wBAAwB,QACnB,gCAAgC;AACvC,SACE/C,6BAA6B,EAC7BgD,kCAAkC,QAC7B,yBAAyB;AAChC,SAEE5C,mBAAmB,EACnB6C,8BAA8B,QAGzB,iCAAiC;AACxC,SAAQ5C,0BAA0B,QAAO,yCAAyC;AAClF,SACE6C,gBAAgB,EAChBC,uBAAuB,EACvBC,qBAAqB,EACrBC,qBAAqB,QAChB,uCAAuC;AAC9C,SAAQ/C,6BAA6B,QAAO,4CAA4C;AAExF,MAAMgD,aAAaxD;AAOnB,OAAO,SAASyD,iBAAiB,EAC/BC,UAAU,EACVC,eAAezD,+BAA+B,EACtB;IACxB,OAAO;QACL0D,MAAM;QACNC,UAAU;YAAC1D;YAAIC;YAAgB0D,mBAAmB;QAAM;QACxDC,MAAM;YAACzD;YAAuBC;YAA8BC;SAAgC;QAC5FwD,cAAchD,qBAAqBf,OAAOgE,qBAAqB;QAC/DC,QAAQ;YACNpD,gBAAgBb,OAAOgE,qBAAqB,EAAEP,YAAYC;YAC1DhD;YACAC;YACAC;SACD;QACDsD,WAAW;YAAC1D,oBAAoBiD;SAAY;QAC5CU,YAAY;YAAC;gBAACR,MAAM;gBAAQS,OAAOhE;gBAAYF;gBAAImE,cAAcrD;YAAyB;SAAE;QAC5FsD,aAAa;YAACf,WAAW3D,oCAAoCkB;SAA8B;QAC3FyD,0BAA0B;YAAC9D;SAAoC;IACjE;AACF"}
|
|
@@ -7,6 +7,7 @@ interface UnauthorizedErrorParams {
|
|
|
7
7
|
interface BearerTokenAuthMethodOptions<TClaims> {
|
|
8
8
|
name: string;
|
|
9
9
|
verifyToken: (token: string) => Promise<TClaims | null>;
|
|
10
|
+
isInvalidTokenError?: (error: unknown) => boolean;
|
|
10
11
|
invalidTokenError: UnauthorizedErrorParams;
|
|
11
12
|
setContext: (request: FastifyRequest, claims: TClaims) => void;
|
|
12
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer-token-auth.d.ts","sourceRoot":"","sources":["../../../src/presentation/auth/bearer-token-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,UAAU,EAAkC,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAE5C,UAAU,uBAAuB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,4BAA4B,CAAC,OAAO;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACxD,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAChE;AAOD,wBAAgB,2BAA2B,CAAC,OAAO,EACjD,OAAO,EAAE,4BAA4B,CAAC,OAAO,CAAC,GAC7C,UAAU,
|
|
1
|
+
{"version":3,"file":"bearer-token-auth.d.ts","sourceRoot":"","sources":["../../../src/presentation/auth/bearer-token-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,UAAU,EAAkC,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAE5C,UAAU,uBAAuB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,4BAA4B,CAAC,OAAO;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACxD,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAClD,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CAChE;AAOD,wBAAgB,2BAA2B,CAAC,OAAO,EACjD,OAAO,EAAE,4BAA4B,CAAC,OAAO,CAAC,GAC7C,UAAU,CAiBZ"}
|
|
@@ -9,16 +9,17 @@ export function createBearerTokenAuthMethod(options) {
|
|
|
9
9
|
authenticate: async (request)=>{
|
|
10
10
|
const token = extractBearerToken(request.headers.authorization);
|
|
11
11
|
if (!token) throwUnauthorized(missingBearerError);
|
|
12
|
-
const claims = await verifyBearerToken(token, options.verifyToken);
|
|
12
|
+
const claims = await verifyBearerToken(token, options.verifyToken, options.isInvalidTokenError);
|
|
13
13
|
if (!claims) throwUnauthorized(options.invalidTokenError);
|
|
14
14
|
options.setContext(request, claims);
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
-
async function verifyBearerToken(token, verifyToken) {
|
|
18
|
+
async function verifyBearerToken(token, verifyToken, isInvalidTokenError) {
|
|
19
19
|
try {
|
|
20
20
|
return await verifyToken(token);
|
|
21
|
-
} catch
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (isInvalidTokenError && !isInvalidTokenError(error)) throw error;
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/auth/bearer-token-auth.ts"],"sourcesContent":["import {type AuthMethod, ClientError, extractBearerToken} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\n\ninterface UnauthorizedErrorParams {\n message: string;\n code: string;\n}\n\ninterface BearerTokenAuthMethodOptions<TClaims> {\n name: string;\n verifyToken: (token: string) => Promise<TClaims | null>;\n invalidTokenError: UnauthorizedErrorParams;\n setContext: (request: FastifyRequest, claims: TClaims) => void;\n}\n\nconst missingBearerError: UnauthorizedErrorParams = {\n message: 'Missing or invalid Authorization header',\n code: 'unauthorized',\n};\n\nexport function createBearerTokenAuthMethod<TClaims>(\n options: BearerTokenAuthMethodOptions<TClaims>,\n): AuthMethod {\n return {\n name: options.name,\n authenticate: async (request) => {\n const token = extractBearerToken(request.headers.authorization);\n if (!token) throwUnauthorized(missingBearerError);\n\n const claims = await verifyBearerToken(token
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/auth/bearer-token-auth.ts"],"sourcesContent":["import {type AuthMethod, ClientError, extractBearerToken} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\n\ninterface UnauthorizedErrorParams {\n message: string;\n code: string;\n}\n\ninterface BearerTokenAuthMethodOptions<TClaims> {\n name: string;\n verifyToken: (token: string) => Promise<TClaims | null>;\n isInvalidTokenError?: (error: unknown) => boolean;\n invalidTokenError: UnauthorizedErrorParams;\n setContext: (request: FastifyRequest, claims: TClaims) => void;\n}\n\nconst missingBearerError: UnauthorizedErrorParams = {\n message: 'Missing or invalid Authorization header',\n code: 'unauthorized',\n};\n\nexport function createBearerTokenAuthMethod<TClaims>(\n options: BearerTokenAuthMethodOptions<TClaims>,\n): AuthMethod {\n return {\n name: options.name,\n authenticate: async (request) => {\n const token = extractBearerToken(request.headers.authorization);\n if (!token) throwUnauthorized(missingBearerError);\n\n const claims = await verifyBearerToken(\n token,\n options.verifyToken,\n options.isInvalidTokenError,\n );\n if (!claims) throwUnauthorized(options.invalidTokenError);\n\n options.setContext(request, claims);\n },\n };\n}\n\nasync function verifyBearerToken<TClaims>(\n token: string,\n verifyToken: (token: string) => Promise<TClaims | null>,\n isInvalidTokenError: ((error: unknown) => boolean) | undefined,\n): Promise<TClaims | null> {\n try {\n return await verifyToken(token);\n } catch (error) {\n if (isInvalidTokenError && !isInvalidTokenError(error)) throw error;\n return null;\n }\n}\n\nfunction throwUnauthorized(error: UnauthorizedErrorParams): never {\n throw new ClientError(error.message, error.code, {status: 401});\n}\n"],"names":["ClientError","extractBearerToken","missingBearerError","message","code","createBearerTokenAuthMethod","options","name","authenticate","request","token","headers","authorization","throwUnauthorized","claims","verifyBearerToken","verifyToken","isInvalidTokenError","invalidTokenError","setContext","error","status"],"mappings":"AAAA,SAAyBA,WAAW,EAAEC,kBAAkB,QAAO,wBAAwB;AAgBvF,MAAMC,qBAA8C;IAClDC,SAAS;IACTC,MAAM;AACR;AAEA,OAAO,SAASC,4BACdC,OAA8C;IAE9C,OAAO;QACLC,MAAMD,QAAQC,IAAI;QAClBC,cAAc,OAAOC;YACnB,MAAMC,QAAQT,mBAAmBQ,QAAQE,OAAO,CAACC,aAAa;YAC9D,IAAI,CAACF,OAAOG,kBAAkBX;YAE9B,MAAMY,SAAS,MAAMC,kBACnBL,OACAJ,QAAQU,WAAW,EACnBV,QAAQW,mBAAmB;YAE7B,IAAI,CAACH,QAAQD,kBAAkBP,QAAQY,iBAAiB;YAExDZ,QAAQa,UAAU,CAACV,SAASK;QAC9B;IACF;AACF;AAEA,eAAeC,kBACbL,KAAa,EACbM,WAAuD,EACvDC,mBAA8D;IAE9D,IAAI;QACF,OAAO,MAAMD,YAAYN;IAC3B,EAAE,OAAOU,OAAO;QACd,IAAIH,uBAAuB,CAACA,oBAAoBG,QAAQ,MAAMA;QAC9D,OAAO;IACT;AACF;AAEA,SAASP,kBAAkBO,KAA8B;IACvD,MAAM,IAAIpB,YAAYoB,MAAMjB,OAAO,EAAEiB,MAAMhB,IAAI,EAAE;QAACiB,QAAQ;IAAG;AAC/D"}
|
|
@@ -14,10 +14,7 @@ export interface CreateJwtAuthMethodOptions {
|
|
|
14
14
|
secret: string;
|
|
15
15
|
}
|
|
16
16
|
export declare function getClientContext(request: FastifyRequest): ClientContext | null;
|
|
17
|
-
/**
|
|
18
|
-
* Resolves the active refresh session backing an authenticated user request.
|
|
19
|
-
* The session check intentionally happens only for consumers that need browser-session binding.
|
|
20
|
-
*/
|
|
17
|
+
/** Returns the refresh-session metadata carried by a verified access token. */
|
|
21
18
|
export declare function getAuthenticatedSessionContext(request: FastifyRequest): Promise<AuthenticatedSessionContext>;
|
|
22
19
|
export declare function createJwtAuthMethod(): AuthMethod;
|
|
23
20
|
//# sourceMappingURL=jwt-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-auth.d.ts","sourceRoot":"","sources":["../../../src/presentation/auth/jwt-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAC,KAAK,UAAU,EAAc,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"jwt-auth.d.ts","sourceRoot":"","sources":["../../../src/presentation/auth/jwt-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAC,KAAK,UAAU,EAAc,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAOjD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC;AAExC,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;AAChC,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;AAEzD,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AASD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,GAAG,IAAI,CAE9E;AAoBD,+EAA+E;AAC/E,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,2BAA2B,CAAC,CAOtC;AAED,wBAAgB,mBAAmB,IAAI,UAAU,CAyBhD"}
|
|
@@ -2,9 +2,14 @@ import { AUTH_USER, buildUserContext, getUserContext, setUserContext } from '@sh
|
|
|
2
2
|
import { userAccessTokenKey } from '@shipfox/node-auth-root-key';
|
|
3
3
|
import { ClientError } from '@shipfox/node-fastify';
|
|
4
4
|
import { verifyUserToken } from '#core/jwt.js';
|
|
5
|
-
import { findActiveRefreshSession } from '#db/refresh-tokens.js';
|
|
6
5
|
import { createBearerTokenAuthMethod } from './bearer-token-auth.js';
|
|
7
6
|
const AUTHENTICATED_SESSION_CONTEXT_KEY = Symbol.for('@shipfox/api-auth/session');
|
|
7
|
+
let InvalidJwtTokenError = class InvalidJwtTokenError extends Error {
|
|
8
|
+
constructor(){
|
|
9
|
+
super('Invalid JWT');
|
|
10
|
+
this.name = 'InvalidJwtTokenError';
|
|
11
|
+
}
|
|
12
|
+
};
|
|
8
13
|
export function getClientContext(request) {
|
|
9
14
|
return getUserContext(request);
|
|
10
15
|
}
|
|
@@ -17,34 +22,33 @@ function setAuthenticatedSessionContext(request, claims) {
|
|
|
17
22
|
function getAuthenticatedSessionTokenContext(request) {
|
|
18
23
|
return request[AUTHENTICATED_SESSION_CONTEXT_KEY] ?? null;
|
|
19
24
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Resolves the active refresh session backing an authenticated user request.
|
|
22
|
-
* The session check intentionally happens only for consumers that need browser-session binding.
|
|
23
|
-
*/ export async function getAuthenticatedSessionContext(request) {
|
|
25
|
+
/** Returns the refresh-session metadata carried by a verified access token. */ export async function getAuthenticatedSessionContext(request) {
|
|
24
26
|
const client = getClientContext(request);
|
|
25
27
|
const token = getAuthenticatedSessionTokenContext(request);
|
|
26
28
|
if (!client || !token || token.userId !== client.userId || !token.refreshSessionId) throw new ClientError('Invalid or expired token', 'unauthorized', {
|
|
27
29
|
status: 401
|
|
28
30
|
});
|
|
29
|
-
|
|
30
|
-
sessionId: token.refreshSessionId,
|
|
31
|
-
userId: client.userId
|
|
32
|
-
});
|
|
33
|
-
if (!session) throw new ClientError('Invalid or expired token', 'unauthorized', {
|
|
34
|
-
status: 401
|
|
35
|
-
});
|
|
36
|
-
return {
|
|
31
|
+
return await Promise.resolve({
|
|
37
32
|
userId: client.userId,
|
|
38
|
-
refreshSessionId:
|
|
39
|
-
};
|
|
33
|
+
refreshSessionId: token.refreshSessionId
|
|
34
|
+
});
|
|
40
35
|
}
|
|
41
36
|
export function createJwtAuthMethod() {
|
|
42
37
|
return createBearerTokenAuthMethod({
|
|
43
38
|
name: AUTH_USER,
|
|
44
|
-
verifyToken: (token)=>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
verifyToken: async (token)=>{
|
|
40
|
+
let claims;
|
|
41
|
+
try {
|
|
42
|
+
claims = await verifyUserToken({
|
|
43
|
+
token,
|
|
44
|
+
secret: userAccessTokenKey()
|
|
45
|
+
});
|
|
46
|
+
} catch {
|
|
47
|
+
throw new InvalidJwtTokenError();
|
|
48
|
+
}
|
|
49
|
+
return claims;
|
|
50
|
+
},
|
|
51
|
+
isInvalidTokenError: (error)=>error instanceof InvalidJwtTokenError,
|
|
48
52
|
invalidTokenError: {
|
|
49
53
|
message: 'Invalid or expired token',
|
|
50
54
|
code: 'unauthorized'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/auth/jwt-auth.ts"],"sourcesContent":["import {\n AUTH_USER,\n buildUserContext,\n getUserContext,\n setUserContext,\n type UserContext,\n} from '@shipfox/api-auth-context';\nimport {userAccessTokenKey} from '@shipfox/node-auth-root-key';\nimport {type AuthMethod, ClientError} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\nimport type {RefreshToken} from '#core/entities/refresh-token.js';\nimport type {User} from '#core/entities/user.js';\nimport type {UserTokenClaims} from '#core/jwt.js';\nimport {verifyUserToken} from '#core/jwt.js';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/auth/jwt-auth.ts"],"sourcesContent":["import {\n AUTH_USER,\n buildUserContext,\n getUserContext,\n setUserContext,\n type UserContext,\n} from '@shipfox/api-auth-context';\nimport {userAccessTokenKey} from '@shipfox/node-auth-root-key';\nimport {type AuthMethod, ClientError} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\nimport type {RefreshToken} from '#core/entities/refresh-token.js';\nimport type {User} from '#core/entities/user.js';\nimport type {UserTokenClaims} from '#core/jwt.js';\nimport {verifyUserToken} from '#core/jwt.js';\nimport {createBearerTokenAuthMethod} from './bearer-token-auth.js';\n\nconst AUTHENTICATED_SESSION_CONTEXT_KEY = Symbol.for('@shipfox/api-auth/session');\n\nexport type ClientContext = UserContext;\n\nexport type UserId = User['id'];\nexport type RefreshSessionId = RefreshToken['sessionId'];\n\nexport type AuthenticatedSessionContext = {\n userId: UserId;\n refreshSessionId: RefreshSessionId;\n};\n\nexport interface CreateJwtAuthMethodOptions {\n secret: string;\n}\n\nclass InvalidJwtTokenError extends Error {\n constructor() {\n super('Invalid JWT');\n this.name = 'InvalidJwtTokenError';\n }\n}\n\nexport function getClientContext(request: FastifyRequest): ClientContext | null {\n return getUserContext(request);\n}\n\nfunction setAuthenticatedSessionContext(request: FastifyRequest, claims: UserTokenClaims): void {\n (request as unknown as Record<symbol, unknown>)[AUTHENTICATED_SESSION_CONTEXT_KEY] = {\n userId: claims.sub,\n refreshSessionId: claims.refreshSessionId,\n };\n}\n\nfunction getAuthenticatedSessionTokenContext(request: FastifyRequest): {\n userId: UserId;\n refreshSessionId: RefreshSessionId | undefined;\n} | null {\n return (\n ((request as unknown as Record<symbol, unknown>)[AUTHENTICATED_SESSION_CONTEXT_KEY] as\n | {userId: UserId; refreshSessionId: RefreshSessionId | undefined}\n | undefined) ?? null\n );\n}\n\n/** Returns the refresh-session metadata carried by a verified access token. */\nexport async function getAuthenticatedSessionContext(\n request: FastifyRequest,\n): Promise<AuthenticatedSessionContext> {\n const client = getClientContext(request);\n const token = getAuthenticatedSessionTokenContext(request);\n if (!client || !token || token.userId !== client.userId || !token.refreshSessionId)\n throw new ClientError('Invalid or expired token', 'unauthorized', {status: 401});\n\n return await Promise.resolve({userId: client.userId, refreshSessionId: token.refreshSessionId});\n}\n\nexport function createJwtAuthMethod(): AuthMethod {\n return createBearerTokenAuthMethod({\n name: AUTH_USER,\n verifyToken: async (token) => {\n let claims: UserTokenClaims;\n try {\n claims = await verifyUserToken({token, secret: userAccessTokenKey()});\n } catch {\n throw new InvalidJwtTokenError();\n }\n return claims;\n },\n isInvalidTokenError: (error) => error instanceof InvalidJwtTokenError,\n invalidTokenError: {message: 'Invalid or expired token', code: 'unauthorized'},\n setContext: (request, claims) => {\n const clientContext: ClientContext = buildUserContext({\n userId: claims.sub,\n email: claims.email,\n name: claims.name ?? null,\n memberships: claims.memberships,\n });\n setUserContext(request, clientContext);\n setAuthenticatedSessionContext(request, claims);\n },\n });\n}\n"],"names":["AUTH_USER","buildUserContext","getUserContext","setUserContext","userAccessTokenKey","ClientError","verifyUserToken","createBearerTokenAuthMethod","AUTHENTICATED_SESSION_CONTEXT_KEY","Symbol","for","InvalidJwtTokenError","Error","name","getClientContext","request","setAuthenticatedSessionContext","claims","userId","sub","refreshSessionId","getAuthenticatedSessionTokenContext","getAuthenticatedSessionContext","client","token","status","Promise","resolve","createJwtAuthMethod","verifyToken","secret","isInvalidTokenError","error","invalidTokenError","message","code","setContext","clientContext","email","memberships"],"mappings":"AAAA,SACEA,SAAS,EACTC,gBAAgB,EAChBC,cAAc,EACdC,cAAc,QAET,4BAA4B;AACnC,SAAQC,kBAAkB,QAAO,8BAA8B;AAC/D,SAAyBC,WAAW,QAAO,wBAAwB;AAKnE,SAAQC,eAAe,QAAO,eAAe;AAC7C,SAAQC,2BAA2B,QAAO,yBAAyB;AAEnE,MAAMC,oCAAoCC,OAAOC,GAAG,CAAC;AAgBrD,IAAA,AAAMC,uBAAN,MAAMA,6BAA6BC;IACjC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,SAASC,iBAAiBC,OAAuB;IACtD,OAAOb,eAAea;AACxB;AAEA,SAASC,+BAA+BD,OAAuB,EAAEE,MAAuB;IACrFF,OAA8C,CAACP,kCAAkC,GAAG;QACnFU,QAAQD,OAAOE,GAAG;QAClBC,kBAAkBH,OAAOG,gBAAgB;IAC3C;AACF;AAEA,SAASC,oCAAoCN,OAAuB;IAIlE,OACE,AAAC,AAACA,OAA8C,CAACP,kCAAkC,IAEjE;AAEtB;AAEA,6EAA6E,GAC7E,OAAO,eAAec,+BACpBP,OAAuB;IAEvB,MAAMQ,SAAST,iBAAiBC;IAChC,MAAMS,QAAQH,oCAAoCN;IAClD,IAAI,CAACQ,UAAU,CAACC,SAASA,MAAMN,MAAM,KAAKK,OAAOL,MAAM,IAAI,CAACM,MAAMJ,gBAAgB,EAChF,MAAM,IAAIf,YAAY,4BAA4B,gBAAgB;QAACoB,QAAQ;IAAG;IAEhF,OAAO,MAAMC,QAAQC,OAAO,CAAC;QAACT,QAAQK,OAAOL,MAAM;QAAEE,kBAAkBI,MAAMJ,gBAAgB;IAAA;AAC/F;AAEA,OAAO,SAASQ;IACd,OAAOrB,4BAA4B;QACjCM,MAAMb;QACN6B,aAAa,OAAOL;YAClB,IAAIP;YACJ,IAAI;gBACFA,SAAS,MAAMX,gBAAgB;oBAACkB;oBAAOM,QAAQ1B;gBAAoB;YACrE,EAAE,OAAM;gBACN,MAAM,IAAIO;YACZ;YACA,OAAOM;QACT;QACAc,qBAAqB,CAACC,QAAUA,iBAAiBrB;QACjDsB,mBAAmB;YAACC,SAAS;YAA4BC,MAAM;QAAc;QAC7EC,YAAY,CAACrB,SAASE;YACpB,MAAMoB,gBAA+BpC,iBAAiB;gBACpDiB,QAAQD,OAAOE,GAAG;gBAClBmB,OAAOrB,OAAOqB,KAAK;gBACnBzB,MAAMI,OAAOJ,IAAI,IAAI;gBACrB0B,aAAatB,OAAOsB,WAAW;YACjC;YACApC,eAAeY,SAASsB;YACxBrB,+BAA+BD,SAASE;QAC1C;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"administration.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/administration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"administration.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/administration.ts"],"names":[],"mappings":"AAoBA,OAAO,EAA2B,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAwVhF,eAAO,MAAM,oBAAoB,EAAE,UAIlC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,UAI3C,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,UAItC,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AUTH_USER } from '@shipfox/api-auth-context';
|
|
2
|
-
import { adminBootstrapStateSchema, administratorUserLookupQuerySchema, administratorUserSummarySchema, bootstrapAdminOwnerBodySchema, bootstrapAdminOwnerResponseSchema, grantAdminRoleBodySchema, grantAdminRoleResponseSchema, listAdminGrantsQuerySchema, listAdminGrantsResponseSchema, revokeAdminGrantBodySchema, revokeAdminGrantResponseSchema } from '@shipfox/api-auth-dto';
|
|
2
|
+
import { adminBootstrapStateSchema, administratorUserLookupQuerySchema, administratorUserMutationResponseSchema, administratorUserSummarySchema, bootstrapAdminOwnerBodySchema, bootstrapAdminOwnerResponseSchema, grantAdminRoleBodySchema, grantAdminRoleResponseSchema, listAdminGrantsQuerySchema, listAdminGrantsResponseSchema, reactivateAdministratorUserBodySchema, revokeAdminGrantBodySchema, revokeAdminGrantResponseSchema, revokeAdministratorUserSessionsBodySchema, revokeAdministratorUserSessionsResponseSchema, suspendAdministratorUserBodySchema } from '@shipfox/api-auth-dto';
|
|
3
3
|
import { decodeTimestampIdCursor, encodeTimestampIdCursor } from '@shipfox/node-drizzle';
|
|
4
4
|
import { ClientError, defineRoute } from '@shipfox/node-fastify';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { requireAdminRole } from '#core/admin-role.js';
|
|
7
|
-
import { bootstrapFirstAdminOwner, findAdministratorUserSummary, getAdminBootstrapState, grantAdministratorRole, listAdministratorGrantSummaries, revokeAdministratorGrant } from '#core/administration.js';
|
|
7
|
+
import { bootstrapFirstAdminOwner, findAdministratorUserSummary, getAdminBootstrapState, grantAdministratorRole, listAdministratorGrantSummaries, reactivateAdministratorUser, revokeAdministratorGrant, revokeAdministratorUserSessions, suspendAdministratorUser } from '#core/administration.js';
|
|
8
8
|
import { AdminBootstrapClosedError, AdminGrantAlreadyExistsError, AdminGrantNotFoundError, AdminIdempotencyKeyReuseError, AdminRoleRequiredError, InvalidAdminBootstrapTokenError, LastAdminOwnerError, UserNotFoundError } from '#core/errors.js';
|
|
9
9
|
import { getClientContext } from '#presentation/auth/jwt-auth.js';
|
|
10
10
|
import { createAuthIpRateLimitPreHandler } from './rate-limit.js';
|
|
@@ -64,6 +64,12 @@ function toAdministratorGrantSummaryDto(grant) {
|
|
|
64
64
|
user: grant.user
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
+
function toAdministratorUserMutationDto(result) {
|
|
68
|
+
return {
|
|
69
|
+
...toAdministratorUserSummaryDto(result.user),
|
|
70
|
+
correlation_id: result.correlationId
|
|
71
|
+
};
|
|
72
|
+
}
|
|
67
73
|
function translateAdministrationError(error) {
|
|
68
74
|
if (error instanceof AdminRoleRequiredError) {
|
|
69
75
|
throw new ClientError('Administrator role required', 'forbidden', {
|
|
@@ -211,6 +217,88 @@ const userLookupRoute = defineRoute({
|
|
|
211
217
|
return toAdministratorUserSummaryDto(user);
|
|
212
218
|
}
|
|
213
219
|
});
|
|
220
|
+
const suspendUserRoute = defineRoute({
|
|
221
|
+
method: 'POST',
|
|
222
|
+
path: '/:userId/suspend',
|
|
223
|
+
description: 'Suspend a user and revoke all of its active sessions.',
|
|
224
|
+
schema: {
|
|
225
|
+
params: z.object({
|
|
226
|
+
userId: z.string().uuid()
|
|
227
|
+
}),
|
|
228
|
+
body: suspendAdministratorUserBodySchema,
|
|
229
|
+
response: {
|
|
230
|
+
200: administratorUserMutationResponseSchema
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
errorHandler: translateAdministrationError,
|
|
234
|
+
handler: async (request)=>{
|
|
235
|
+
const result = await suspendAdministratorUser({
|
|
236
|
+
actorId: requireActorId(request),
|
|
237
|
+
userId: request.params.userId,
|
|
238
|
+
reason: request.body.reason,
|
|
239
|
+
idempotencyKey: requireIdempotencyKey(request),
|
|
240
|
+
correlationId: request.id
|
|
241
|
+
});
|
|
242
|
+
return toAdministratorUserMutationDto(result);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
const reactivateUserRoute = defineRoute({
|
|
246
|
+
method: 'POST',
|
|
247
|
+
path: '/:userId/reactivate',
|
|
248
|
+
description: 'Reactivate a suspended user without restoring revoked sessions.',
|
|
249
|
+
schema: {
|
|
250
|
+
params: z.object({
|
|
251
|
+
userId: z.string().uuid()
|
|
252
|
+
}),
|
|
253
|
+
body: reactivateAdministratorUserBodySchema,
|
|
254
|
+
response: {
|
|
255
|
+
200: administratorUserMutationResponseSchema
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
errorHandler: translateAdministrationError,
|
|
259
|
+
handler: async (request)=>{
|
|
260
|
+
const result = await reactivateAdministratorUser({
|
|
261
|
+
actorId: requireActorId(request),
|
|
262
|
+
userId: request.params.userId,
|
|
263
|
+
...request.body.reason ? {
|
|
264
|
+
reason: request.body.reason
|
|
265
|
+
} : {},
|
|
266
|
+
idempotencyKey: requireIdempotencyKey(request),
|
|
267
|
+
correlationId: request.id
|
|
268
|
+
});
|
|
269
|
+
return toAdministratorUserMutationDto(result);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
const revokeUserSessionsRoute = defineRoute({
|
|
273
|
+
method: 'POST',
|
|
274
|
+
path: '/:userId/revoke-sessions',
|
|
275
|
+
description: 'Revoke all active sessions for a user without changing account status.',
|
|
276
|
+
schema: {
|
|
277
|
+
params: z.object({
|
|
278
|
+
userId: z.string().uuid()
|
|
279
|
+
}),
|
|
280
|
+
body: revokeAdministratorUserSessionsBodySchema,
|
|
281
|
+
response: {
|
|
282
|
+
200: revokeAdministratorUserSessionsResponseSchema
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
errorHandler: translateAdministrationError,
|
|
286
|
+
handler: async (request)=>{
|
|
287
|
+
const result = await revokeAdministratorUserSessions({
|
|
288
|
+
actorId: requireActorId(request),
|
|
289
|
+
userId: request.params.userId,
|
|
290
|
+
...request.body.reason ? {
|
|
291
|
+
reason: request.body.reason
|
|
292
|
+
} : {},
|
|
293
|
+
idempotencyKey: requireIdempotencyKey(request),
|
|
294
|
+
correlationId: request.id
|
|
295
|
+
});
|
|
296
|
+
return {
|
|
297
|
+
...toAdministratorUserMutationDto(result),
|
|
298
|
+
sessions_revoked: result.sessionsRevoked
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
});
|
|
214
302
|
const grantRoute = defineRoute({
|
|
215
303
|
method: 'POST',
|
|
216
304
|
path: '/',
|
|
@@ -282,7 +370,10 @@ export const administrationUserRoutes = {
|
|
|
282
370
|
prefix: '/admin/auth/users',
|
|
283
371
|
auth: AUTH_USER,
|
|
284
372
|
routes: [
|
|
285
|
-
userLookupRoute
|
|
373
|
+
userLookupRoute,
|
|
374
|
+
suspendUserRoute,
|
|
375
|
+
reactivateUserRoute,
|
|
376
|
+
revokeUserSessionsRoute
|
|
286
377
|
]
|
|
287
378
|
};
|
|
288
379
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/presentation/routes/administration.ts"],"sourcesContent":["import {AUTH_USER} from '@shipfox/api-auth-context';\nimport {\n adminBootstrapStateSchema,\n administratorUserLookupQuerySchema,\n administratorUserSummarySchema,\n bootstrapAdminOwnerBodySchema,\n bootstrapAdminOwnerResponseSchema,\n grantAdminRoleBodySchema,\n grantAdminRoleResponseSchema,\n listAdminGrantsQuerySchema,\n listAdminGrantsResponseSchema,\n revokeAdminGrantBodySchema,\n revokeAdminGrantResponseSchema,\n} from '@shipfox/api-auth-dto';\nimport {decodeTimestampIdCursor, encodeTimestampIdCursor} from '@shipfox/node-drizzle';\nimport {ClientError, defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\nimport {z} from 'zod';\nimport {requireAdminRole} from '#core/admin-role.js';\nimport {\n bootstrapFirstAdminOwner,\n findAdministratorUserSummary,\n getAdminBootstrapState,\n grantAdministratorRole,\n listAdministratorGrantSummaries,\n revokeAdministratorGrant,\n} from '#core/administration.js';\nimport type {AdminGrant} from '#core/entities/admin-grant.js';\nimport type {\n AdministratorGrantSummary,\n AdministratorUserSummary,\n} from '#core/entities/administrator-read-model.js';\nimport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n AdminRoleRequiredError,\n InvalidAdminBootstrapTokenError,\n LastAdminOwnerError,\n UserNotFoundError,\n} from '#core/errors.js';\nimport {getClientContext} from '#presentation/auth/jwt-auth.js';\nimport {createAuthIpRateLimitPreHandler} from './rate-limit.js';\n\nconst idempotencyKeyMaxLength = 256;\n\nfunction requireActorId(request: FastifyRequest): string {\n const client = getClientContext(request);\n if (!client) {\n throw new ClientError('Authentication required', 'unauthorized', {status: 401});\n }\n return client.userId;\n}\n\nfunction requireIdempotencyKey(request: FastifyRequest): string {\n const value = request.headers['idempotency-key'];\n const key = Array.isArray(value) ? value[0] : value;\n if (!key || key.trim().length === 0 || key.length > idempotencyKeyMaxLength) {\n throw new ClientError('Idempotency-Key header is required', 'idempotency-key-required', {\n status: 400,\n });\n }\n return key;\n}\n\nasync function requireAdministratorObserver(request: FastifyRequest): Promise<void> {\n await requireAdminRole({userId: requireActorId(request), minimumRole: 'admin-observer'});\n}\n\nfunction toAdminGrantDto(grant: AdminGrant) {\n return {\n id: grant.id,\n user_id: grant.userId,\n role: grant.role,\n revoked_at: grant.revokedAt?.toISOString() ?? null,\n created_at: grant.createdAt.toISOString(),\n updated_at: grant.updatedAt.toISOString(),\n };\n}\n\nfunction toAdministratorUserSummaryDto(user: AdministratorUserSummary) {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n status: user.status,\n email_verified_at: user.emailVerifiedAt?.toISOString() ?? null,\n created_at: user.createdAt.toISOString(),\n admin_role: user.adminRole,\n };\n}\n\nfunction toAdministratorGrantSummaryDto(grant: AdministratorGrantSummary) {\n return {\n grant_id: grant.grantId,\n role: grant.role,\n created_at: grant.createdAt.toISOString(),\n revoked_at: grant.revokedAt?.toISOString() ?? null,\n user: grant.user,\n };\n}\n\nfunction translateAdministrationError(error: unknown): never {\n if (error instanceof AdminRoleRequiredError) {\n throw new ClientError('Administrator role required', 'forbidden', {\n status: 403,\n details: {required_role: error.minimumRole},\n });\n }\n if (error instanceof InvalidAdminBootstrapTokenError) {\n throw new ClientError('Bootstrap token is invalid', 'bootstrap-token-invalid', {\n status: 403,\n });\n }\n if (error instanceof AdminBootstrapClosedError) {\n throw new ClientError('First administrator owner already exists', 'bootstrap-closed', {\n status: 409,\n });\n }\n if (error instanceof AdminGrantAlreadyExistsError) {\n throw new ClientError('Administrator grant already exists', 'grant-already-exists', {\n status: 409,\n });\n }\n if (error instanceof AdminGrantNotFoundError) {\n throw new ClientError('Administrator grant not found', 'not-found', {status: 404});\n }\n if (error instanceof UserNotFoundError) {\n throw new ClientError('User not found', 'not-found', {status: 404});\n }\n if (error instanceof LastAdminOwnerError) {\n throw new ClientError('Cannot remove the final active administrator owner', 'last-owner', {\n status: 409,\n });\n }\n if (error instanceof AdminIdempotencyKeyReuseError) {\n throw new ClientError(\n 'Idempotency-Key was already used for a different command',\n 'idempotency-key-reused',\n {status: 409},\n );\n }\n throw error;\n}\n\nconst bootstrapRoute = defineRoute({\n method: 'POST',\n path: '/bootstrap',\n description: 'Claim the first administrator owner role with the deployment bootstrap token.',\n schema: {\n body: bootstrapAdminOwnerBodySchema,\n response: {201: bootstrapAdminOwnerResponseSchema},\n },\n preHandler: createAuthIpRateLimitPreHandler('bootstrap'),\n errorHandler: translateAdministrationError,\n handler: async (request, reply) => {\n const actorId = requireActorId(request);\n const grant = await bootstrapFirstAdminOwner({\n actorId,\n bootstrapToken: request.body.bootstrap_token,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n reply.code(201);\n return toAdminGrantDto(grant);\n },\n});\n\nconst bootstrapStateRoute = defineRoute({\n method: 'GET',\n path: '/bootstrap-state',\n description: 'Read whether first administrator owner bootstrap is available.',\n schema: {response: {200: adminBootstrapStateSchema}},\n preHandler: createAuthIpRateLimitPreHandler('bootstrap-state'),\n errorHandler: translateAdministrationError,\n handler: async () => ({state: await getAdminBootstrapState()}),\n});\n\nconst listRoute = defineRoute({\n method: 'GET',\n path: '/',\n description: 'List bounded local administrator grant summaries.',\n schema: {\n querystring: listAdminGrantsQuerySchema,\n response: {200: listAdminGrantsResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const {limit, cursor} = request.query;\n const decodedCursor = decodeTimestampIdCursor(cursor);\n if (cursor && !decodedCursor) {\n throw new ClientError('Invalid cursor', 'invalid-cursor', {status: 400});\n }\n\n const result = await listAdministratorGrantSummaries({\n actorId: requireActorId(request),\n limit,\n ...(decodedCursor ? {cursor: decodedCursor} : {}),\n });\n return {\n grants: result.grants.map(toAdministratorGrantSummaryDto),\n next_cursor: result.nextCursor ? encodeTimestampIdCursor(result.nextCursor) : null,\n };\n },\n});\n\nconst userLookupRoute = defineRoute({\n method: 'GET',\n path: '/',\n description: 'Find one administrator-safe user summary by exact ID or email.',\n schema: {\n querystring: administratorUserLookupQuerySchema,\n response: {200: administratorUserSummarySchema},\n },\n preHandler: [requireAdministratorObserver, createAuthIpRateLimitPreHandler('lookup')],\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const {id, user_id: userId, email} = request.query;\n const lookupId = id ?? userId;\n const actorId = requireActorId(request);\n const user = lookupId\n ? await findAdministratorUserSummary({actorId, id: lookupId})\n : email\n ? await findAdministratorUserSummary({actorId, email})\n : undefined;\n if (!user) throw new UserNotFoundError(lookupId ?? email ?? 'unknown');\n return toAdministratorUserSummaryDto(user);\n },\n});\n\nconst grantRoute = defineRoute({\n method: 'POST',\n path: '/',\n description: 'Grant a local administrator role to an active user.',\n schema: {\n body: grantAdminRoleBodySchema,\n response: {201: grantAdminRoleResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request, reply) => {\n const actorId = requireActorId(request);\n const grant = await grantAdministratorRole({\n actorId,\n userId: request.body.user_id,\n role: request.body.role,\n reason: request.body.reason,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n reply.code(201);\n return toAdminGrantDto(grant);\n },\n});\n\nconst revokeRoute = defineRoute({\n method: 'DELETE',\n path: '/:grantId',\n description: 'Revoke a local administrator grant.',\n schema: {\n params: z.object({grantId: z.string().uuid()}),\n body: revokeAdminGrantBodySchema,\n response: {200: revokeAdminGrantResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const grant = await revokeAdministratorGrant({\n actorId: requireActorId(request),\n grantId: request.params.grantId,\n reason: request.body.reason,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n return toAdminGrantDto(grant);\n },\n});\n\nexport const administrationRoutes: RouteGroup = {\n prefix: '/admin/auth/admin-grants',\n auth: AUTH_USER,\n routes: [bootstrapRoute, listRoute, grantRoute, revokeRoute],\n};\n\nexport const administrationBootstrapRoutes: RouteGroup = {\n prefix: '/admin/auth',\n auth: AUTH_USER,\n routes: [bootstrapStateRoute],\n};\n\nexport const administrationUserRoutes: RouteGroup = {\n prefix: '/admin/auth/users',\n auth: AUTH_USER,\n routes: [userLookupRoute],\n};\n"],"names":["AUTH_USER","adminBootstrapStateSchema","administratorUserLookupQuerySchema","administratorUserSummarySchema","bootstrapAdminOwnerBodySchema","bootstrapAdminOwnerResponseSchema","grantAdminRoleBodySchema","grantAdminRoleResponseSchema","listAdminGrantsQuerySchema","listAdminGrantsResponseSchema","revokeAdminGrantBodySchema","revokeAdminGrantResponseSchema","decodeTimestampIdCursor","encodeTimestampIdCursor","ClientError","defineRoute","z","requireAdminRole","bootstrapFirstAdminOwner","findAdministratorUserSummary","getAdminBootstrapState","grantAdministratorRole","listAdministratorGrantSummaries","revokeAdministratorGrant","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","AdminRoleRequiredError","InvalidAdminBootstrapTokenError","LastAdminOwnerError","UserNotFoundError","getClientContext","createAuthIpRateLimitPreHandler","idempotencyKeyMaxLength","requireActorId","request","client","status","userId","requireIdempotencyKey","value","headers","key","Array","isArray","trim","length","requireAdministratorObserver","minimumRole","toAdminGrantDto","grant","id","user_id","role","revoked_at","revokedAt","toISOString","created_at","createdAt","updated_at","updatedAt","toAdministratorUserSummaryDto","user","email","name","email_verified_at","emailVerifiedAt","admin_role","adminRole","toAdministratorGrantSummaryDto","grant_id","grantId","translateAdministrationError","error","details","required_role","bootstrapRoute","method","path","description","schema","body","response","preHandler","errorHandler","handler","reply","actorId","bootstrapToken","bootstrap_token","idempotencyKey","correlationId","code","bootstrapStateRoute","state","listRoute","querystring","limit","cursor","query","decodedCursor","result","grants","map","next_cursor","nextCursor","userLookupRoute","lookupId","undefined","grantRoute","reason","revokeRoute","params","object","string","uuid","administrationRoutes","prefix","auth","routes","administrationBootstrapRoutes","administrationUserRoutes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/administration.ts"],"sourcesContent":["import {AUTH_USER} from '@shipfox/api-auth-context';\nimport {\n adminBootstrapStateSchema,\n administratorUserLookupQuerySchema,\n administratorUserMutationResponseSchema,\n administratorUserSummarySchema,\n bootstrapAdminOwnerBodySchema,\n bootstrapAdminOwnerResponseSchema,\n grantAdminRoleBodySchema,\n grantAdminRoleResponseSchema,\n listAdminGrantsQuerySchema,\n listAdminGrantsResponseSchema,\n reactivateAdministratorUserBodySchema,\n revokeAdminGrantBodySchema,\n revokeAdminGrantResponseSchema,\n revokeAdministratorUserSessionsBodySchema,\n revokeAdministratorUserSessionsResponseSchema,\n suspendAdministratorUserBodySchema,\n} from '@shipfox/api-auth-dto';\nimport {decodeTimestampIdCursor, encodeTimestampIdCursor} from '@shipfox/node-drizzle';\nimport {ClientError, defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {FastifyRequest} from 'fastify';\nimport {z} from 'zod';\nimport {requireAdminRole} from '#core/admin-role.js';\nimport {\n bootstrapFirstAdminOwner,\n findAdministratorUserSummary,\n getAdminBootstrapState,\n grantAdministratorRole,\n listAdministratorGrantSummaries,\n reactivateAdministratorUser,\n revokeAdministratorGrant,\n revokeAdministratorUserSessions,\n suspendAdministratorUser,\n} from '#core/administration.js';\nimport type {AdminGrant} from '#core/entities/admin-grant.js';\nimport type {\n AdministratorGrantSummary,\n AdministratorUserSummary,\n} from '#core/entities/administrator-read-model.js';\nimport {\n AdminBootstrapClosedError,\n AdminGrantAlreadyExistsError,\n AdminGrantNotFoundError,\n AdminIdempotencyKeyReuseError,\n AdminRoleRequiredError,\n InvalidAdminBootstrapTokenError,\n LastAdminOwnerError,\n UserNotFoundError,\n} from '#core/errors.js';\nimport {getClientContext} from '#presentation/auth/jwt-auth.js';\nimport {createAuthIpRateLimitPreHandler} from './rate-limit.js';\n\nconst idempotencyKeyMaxLength = 256;\n\nfunction requireActorId(request: FastifyRequest): string {\n const client = getClientContext(request);\n if (!client) {\n throw new ClientError('Authentication required', 'unauthorized', {status: 401});\n }\n return client.userId;\n}\n\nfunction requireIdempotencyKey(request: FastifyRequest): string {\n const value = request.headers['idempotency-key'];\n const key = Array.isArray(value) ? value[0] : value;\n if (!key || key.trim().length === 0 || key.length > idempotencyKeyMaxLength) {\n throw new ClientError('Idempotency-Key header is required', 'idempotency-key-required', {\n status: 400,\n });\n }\n return key;\n}\n\nasync function requireAdministratorObserver(request: FastifyRequest): Promise<void> {\n await requireAdminRole({userId: requireActorId(request), minimumRole: 'admin-observer'});\n}\n\nfunction toAdminGrantDto(grant: AdminGrant) {\n return {\n id: grant.id,\n user_id: grant.userId,\n role: grant.role,\n revoked_at: grant.revokedAt?.toISOString() ?? null,\n created_at: grant.createdAt.toISOString(),\n updated_at: grant.updatedAt.toISOString(),\n };\n}\n\nfunction toAdministratorUserSummaryDto(user: AdministratorUserSummary) {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n status: user.status,\n email_verified_at: user.emailVerifiedAt?.toISOString() ?? null,\n created_at: user.createdAt.toISOString(),\n admin_role: user.adminRole,\n };\n}\n\nfunction toAdministratorGrantSummaryDto(grant: AdministratorGrantSummary) {\n return {\n grant_id: grant.grantId,\n role: grant.role,\n created_at: grant.createdAt.toISOString(),\n revoked_at: grant.revokedAt?.toISOString() ?? null,\n user: grant.user,\n };\n}\n\nfunction toAdministratorUserMutationDto(result: {\n user: AdministratorUserSummary;\n correlationId: string;\n}) {\n return {\n ...toAdministratorUserSummaryDto(result.user),\n correlation_id: result.correlationId,\n };\n}\n\nfunction translateAdministrationError(error: unknown): never {\n if (error instanceof AdminRoleRequiredError) {\n throw new ClientError('Administrator role required', 'forbidden', {\n status: 403,\n details: {required_role: error.minimumRole},\n });\n }\n if (error instanceof InvalidAdminBootstrapTokenError) {\n throw new ClientError('Bootstrap token is invalid', 'bootstrap-token-invalid', {\n status: 403,\n });\n }\n if (error instanceof AdminBootstrapClosedError) {\n throw new ClientError('First administrator owner already exists', 'bootstrap-closed', {\n status: 409,\n });\n }\n if (error instanceof AdminGrantAlreadyExistsError) {\n throw new ClientError('Administrator grant already exists', 'grant-already-exists', {\n status: 409,\n });\n }\n if (error instanceof AdminGrantNotFoundError) {\n throw new ClientError('Administrator grant not found', 'not-found', {status: 404});\n }\n if (error instanceof UserNotFoundError) {\n throw new ClientError('User not found', 'not-found', {status: 404});\n }\n if (error instanceof LastAdminOwnerError) {\n throw new ClientError('Cannot remove the final active administrator owner', 'last-owner', {\n status: 409,\n });\n }\n if (error instanceof AdminIdempotencyKeyReuseError) {\n throw new ClientError(\n 'Idempotency-Key was already used for a different command',\n 'idempotency-key-reused',\n {status: 409},\n );\n }\n throw error;\n}\n\nconst bootstrapRoute = defineRoute({\n method: 'POST',\n path: '/bootstrap',\n description: 'Claim the first administrator owner role with the deployment bootstrap token.',\n schema: {\n body: bootstrapAdminOwnerBodySchema,\n response: {201: bootstrapAdminOwnerResponseSchema},\n },\n preHandler: createAuthIpRateLimitPreHandler('bootstrap'),\n errorHandler: translateAdministrationError,\n handler: async (request, reply) => {\n const actorId = requireActorId(request);\n const grant = await bootstrapFirstAdminOwner({\n actorId,\n bootstrapToken: request.body.bootstrap_token,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n reply.code(201);\n return toAdminGrantDto(grant);\n },\n});\n\nconst bootstrapStateRoute = defineRoute({\n method: 'GET',\n path: '/bootstrap-state',\n description: 'Read whether first administrator owner bootstrap is available.',\n schema: {response: {200: adminBootstrapStateSchema}},\n preHandler: createAuthIpRateLimitPreHandler('bootstrap-state'),\n errorHandler: translateAdministrationError,\n handler: async () => ({state: await getAdminBootstrapState()}),\n});\n\nconst listRoute = defineRoute({\n method: 'GET',\n path: '/',\n description: 'List bounded local administrator grant summaries.',\n schema: {\n querystring: listAdminGrantsQuerySchema,\n response: {200: listAdminGrantsResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const {limit, cursor} = request.query;\n const decodedCursor = decodeTimestampIdCursor(cursor);\n if (cursor && !decodedCursor) {\n throw new ClientError('Invalid cursor', 'invalid-cursor', {status: 400});\n }\n\n const result = await listAdministratorGrantSummaries({\n actorId: requireActorId(request),\n limit,\n ...(decodedCursor ? {cursor: decodedCursor} : {}),\n });\n return {\n grants: result.grants.map(toAdministratorGrantSummaryDto),\n next_cursor: result.nextCursor ? encodeTimestampIdCursor(result.nextCursor) : null,\n };\n },\n});\n\nconst userLookupRoute = defineRoute({\n method: 'GET',\n path: '/',\n description: 'Find one administrator-safe user summary by exact ID or email.',\n schema: {\n querystring: administratorUserLookupQuerySchema,\n response: {200: administratorUserSummarySchema},\n },\n preHandler: [requireAdministratorObserver, createAuthIpRateLimitPreHandler('lookup')],\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const {id, user_id: userId, email} = request.query;\n const lookupId = id ?? userId;\n const actorId = requireActorId(request);\n const user = lookupId\n ? await findAdministratorUserSummary({actorId, id: lookupId})\n : email\n ? await findAdministratorUserSummary({actorId, email})\n : undefined;\n if (!user) throw new UserNotFoundError(lookupId ?? email ?? 'unknown');\n return toAdministratorUserSummaryDto(user);\n },\n});\n\nconst suspendUserRoute = defineRoute({\n method: 'POST',\n path: '/:userId/suspend',\n description: 'Suspend a user and revoke all of its active sessions.',\n schema: {\n params: z.object({userId: z.string().uuid()}),\n body: suspendAdministratorUserBodySchema,\n response: {200: administratorUserMutationResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const result = await suspendAdministratorUser({\n actorId: requireActorId(request),\n userId: request.params.userId,\n reason: request.body.reason,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n return toAdministratorUserMutationDto(result);\n },\n});\n\nconst reactivateUserRoute = defineRoute({\n method: 'POST',\n path: '/:userId/reactivate',\n description: 'Reactivate a suspended user without restoring revoked sessions.',\n schema: {\n params: z.object({userId: z.string().uuid()}),\n body: reactivateAdministratorUserBodySchema,\n response: {200: administratorUserMutationResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const result = await reactivateAdministratorUser({\n actorId: requireActorId(request),\n userId: request.params.userId,\n ...(request.body.reason ? {reason: request.body.reason} : {}),\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n return toAdministratorUserMutationDto(result);\n },\n});\n\nconst revokeUserSessionsRoute = defineRoute({\n method: 'POST',\n path: '/:userId/revoke-sessions',\n description: 'Revoke all active sessions for a user without changing account status.',\n schema: {\n params: z.object({userId: z.string().uuid()}),\n body: revokeAdministratorUserSessionsBodySchema,\n response: {200: revokeAdministratorUserSessionsResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const result = await revokeAdministratorUserSessions({\n actorId: requireActorId(request),\n userId: request.params.userId,\n ...(request.body.reason ? {reason: request.body.reason} : {}),\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n return {\n ...toAdministratorUserMutationDto(result),\n sessions_revoked: result.sessionsRevoked,\n };\n },\n});\n\nconst grantRoute = defineRoute({\n method: 'POST',\n path: '/',\n description: 'Grant a local administrator role to an active user.',\n schema: {\n body: grantAdminRoleBodySchema,\n response: {201: grantAdminRoleResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request, reply) => {\n const actorId = requireActorId(request);\n const grant = await grantAdministratorRole({\n actorId,\n userId: request.body.user_id,\n role: request.body.role,\n reason: request.body.reason,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n reply.code(201);\n return toAdminGrantDto(grant);\n },\n});\n\nconst revokeRoute = defineRoute({\n method: 'DELETE',\n path: '/:grantId',\n description: 'Revoke a local administrator grant.',\n schema: {\n params: z.object({grantId: z.string().uuid()}),\n body: revokeAdminGrantBodySchema,\n response: {200: revokeAdminGrantResponseSchema},\n },\n errorHandler: translateAdministrationError,\n handler: async (request) => {\n const grant = await revokeAdministratorGrant({\n actorId: requireActorId(request),\n grantId: request.params.grantId,\n reason: request.body.reason,\n idempotencyKey: requireIdempotencyKey(request),\n correlationId: request.id,\n });\n return toAdminGrantDto(grant);\n },\n});\n\nexport const administrationRoutes: RouteGroup = {\n prefix: '/admin/auth/admin-grants',\n auth: AUTH_USER,\n routes: [bootstrapRoute, listRoute, grantRoute, revokeRoute],\n};\n\nexport const administrationBootstrapRoutes: RouteGroup = {\n prefix: '/admin/auth',\n auth: AUTH_USER,\n routes: [bootstrapStateRoute],\n};\n\nexport const administrationUserRoutes: RouteGroup = {\n prefix: '/admin/auth/users',\n auth: AUTH_USER,\n routes: [userLookupRoute, suspendUserRoute, reactivateUserRoute, revokeUserSessionsRoute],\n};\n"],"names":["AUTH_USER","adminBootstrapStateSchema","administratorUserLookupQuerySchema","administratorUserMutationResponseSchema","administratorUserSummarySchema","bootstrapAdminOwnerBodySchema","bootstrapAdminOwnerResponseSchema","grantAdminRoleBodySchema","grantAdminRoleResponseSchema","listAdminGrantsQuerySchema","listAdminGrantsResponseSchema","reactivateAdministratorUserBodySchema","revokeAdminGrantBodySchema","revokeAdminGrantResponseSchema","revokeAdministratorUserSessionsBodySchema","revokeAdministratorUserSessionsResponseSchema","suspendAdministratorUserBodySchema","decodeTimestampIdCursor","encodeTimestampIdCursor","ClientError","defineRoute","z","requireAdminRole","bootstrapFirstAdminOwner","findAdministratorUserSummary","getAdminBootstrapState","grantAdministratorRole","listAdministratorGrantSummaries","reactivateAdministratorUser","revokeAdministratorGrant","revokeAdministratorUserSessions","suspendAdministratorUser","AdminBootstrapClosedError","AdminGrantAlreadyExistsError","AdminGrantNotFoundError","AdminIdempotencyKeyReuseError","AdminRoleRequiredError","InvalidAdminBootstrapTokenError","LastAdminOwnerError","UserNotFoundError","getClientContext","createAuthIpRateLimitPreHandler","idempotencyKeyMaxLength","requireActorId","request","client","status","userId","requireIdempotencyKey","value","headers","key","Array","isArray","trim","length","requireAdministratorObserver","minimumRole","toAdminGrantDto","grant","id","user_id","role","revoked_at","revokedAt","toISOString","created_at","createdAt","updated_at","updatedAt","toAdministratorUserSummaryDto","user","email","name","email_verified_at","emailVerifiedAt","admin_role","adminRole","toAdministratorGrantSummaryDto","grant_id","grantId","toAdministratorUserMutationDto","result","correlation_id","correlationId","translateAdministrationError","error","details","required_role","bootstrapRoute","method","path","description","schema","body","response","preHandler","errorHandler","handler","reply","actorId","bootstrapToken","bootstrap_token","idempotencyKey","code","bootstrapStateRoute","state","listRoute","querystring","limit","cursor","query","decodedCursor","grants","map","next_cursor","nextCursor","userLookupRoute","lookupId","undefined","suspendUserRoute","params","object","string","uuid","reason","reactivateUserRoute","revokeUserSessionsRoute","sessions_revoked","sessionsRevoked","grantRoute","revokeRoute","administrationRoutes","prefix","auth","routes","administrationBootstrapRoutes","administrationUserRoutes"],"mappings":"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"}
|