emilsoftware-utilities 2.0.0-dev.3 → 2.0.0-dev.30
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 +185 -38
- package/dist/ContractGenerator.d.ts +4 -3
- package/dist/ContractGenerator.js +15 -5
- package/dist/ContractGenerator.js.map +1 -1
- package/dist/DailyFileTransport.d.ts +21 -0
- package/dist/DailyFileTransport.js +74 -0
- package/dist/DailyFileTransport.js.map +1 -0
- package/dist/DatabaseUpdater.d.ts +1 -1
- package/dist/DatabaseUpdater.js +32 -29
- package/dist/DatabaseUpdater.js.map +1 -1
- package/dist/EmilsoftwareModule.js.map +1 -1
- package/dist/ExecutionTimeLogger.d.ts +2 -2
- package/dist/ExecutionTimeLogger.js +5 -4
- package/dist/ExecutionTimeLogger.js.map +1 -1
- package/dist/Logger.d.ts +22 -11
- package/dist/Logger.js +132 -119
- package/dist/Logger.js.map +1 -1
- package/dist/Orm.d.ts +28 -7
- package/dist/Orm.js +196 -90
- package/dist/Orm.js.map +1 -1
- package/dist/RoutesLoggerMiddleware.js.map +1 -1
- package/dist/Utilities.d.ts +18 -8
- package/dist/Utilities.js +117 -38
- package/dist/Utilities.js.map +1 -1
- package/dist/accessi-module/AccessiModule.d.ts +70 -1
- package/dist/accessi-module/AccessiModule.js +32 -5
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/accessiFetch.d.ts +7 -0
- package/dist/accessi-module/Console/accessiFetch.js +59 -0
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -0
- package/dist/accessi-module/Console/console.css +618 -0
- package/dist/accessi-module/Console/console.d.ts +1 -0
- package/dist/accessi-module/Console/console.js +3101 -0
- package/dist/accessi-module/Console/console.js.map +1 -0
- package/dist/accessi-module/Console/generated/accessiApi.d.ts +562 -0
- package/dist/accessi-module/Console/generated/accessiApi.js +533 -0
- package/dist/accessi-module/Console/generated/accessiApi.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenu.d.ts +39 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenu.js +3 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenu.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenuTipoAbilitazione.d.ts +16 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenuTipoAbilitazione.js +17 -0
- package/dist/accessi-module/Console/generated/model/abilitazioneMenuTipoAbilitazione.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/actionResponse.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/actionResponse.js +9 -0
- package/dist/accessi-module/Console/generated/model/actionResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/assignPermissionsToUserRequest.d.ts +11 -0
- package/dist/accessi-module/Console/generated/model/assignPermissionsToUserRequest.js +3 -0
- package/dist/accessi-module/Console/generated/model/assignPermissionsToUserRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/assignRolesToUserRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/assignRolesToUserRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/assignRolesToUserRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/authenticatedTokenPayloadDto.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/authenticatedTokenPayloadDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/authenticatedTokenPayloadDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/authenticatedUserPayloadDto.d.ts +19 -0
- package/dist/accessi-module/Console/generated/model/authenticatedUserPayloadDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/authenticatedUserPayloadDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/confirmResetPasswordRequest.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/confirmResetPasswordRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/confirmResetPasswordRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createFederatedIdentityRequest.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/createFederatedIdentityRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createFederatedIdentityRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createFederatedProviderRequest.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/createFederatedProviderRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createFederatedProviderRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createFederatedUserRequest.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/createFederatedUserRequest.js +3 -0
- package/dist/accessi-module/Console/generated/model/createFederatedUserRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequest.d.ts +23 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequest.js +3 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequestFlgEnabled.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequestFlgEnabled.js +15 -0
- package/dist/accessi-module/Console/generated/model/createFilterTypeRequestFlgEnabled.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createMenuGroupRequest.d.ts +27 -0
- package/dist/accessi-module/Console/generated/model/createMenuGroupRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createMenuGroupRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createMenuRequest.d.ts +52 -0
- package/dist/accessi-module/Console/generated/model/createMenuRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createMenuRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createMenuTypeRequest.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/createMenuTypeRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createMenuTypeRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenRequest.d.ts +16 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/createServiceTokenResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/errorResponse.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/errorResponse.js +9 -0
- package/dist/accessi-module/Console/generated/model/errorResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityListResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityListResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityListResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponseDto.d.ts +23 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponseDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/federatedIdentityResponseDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderListResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderListResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderListResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponseDto.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponseDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/federatedProviderResponseDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/filtriUtente.d.ts +32 -0
- package/dist/accessi-module/Console/generated/model/filtriUtente.js +9 -0
- package/dist/accessi-module/Console/generated/model/filtriUtente.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getFiltriResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getFiltriResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getFiltriResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteParams.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteParams.js +9 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getFiltriUtenteResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusParams.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusParams.js +9 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getGroupsWithMenusResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getMenuTypesResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getMenuTypesResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getMenuTypesResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getMenusResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getMenusResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getMenusResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getRolesResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getRolesResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getRolesResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensParams.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensParams.js +9 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getServiceTokensResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getUserByTokenResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUsersParams.d.ts +32 -0
- package/dist/accessi-module/Console/generated/model/getUsersParams.js +9 -0
- package/dist/accessi-module/Console/generated/model/getUsersParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUsersResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getUsersResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getUsersResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUsersResult.d.ts +17 -0
- package/dist/accessi-module/Console/generated/model/getUsersResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/getUsersResult.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/getUsersResultExtensionFields.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/getUsersResultExtensionFields.js +9 -0
- package/dist/accessi-module/Console/generated/model/getUsersResultExtensionFields.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/groupWithMenusEntity.d.ts +19 -0
- package/dist/accessi-module/Console/generated/model/groupWithMenusEntity.js +3 -0
- package/dist/accessi-module/Console/generated/model/groupWithMenusEntity.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +93 -0
- package/dist/accessi-module/Console/generated/model/index.js +110 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/issuedServiceTokenDto.d.ts +30 -0
- package/dist/accessi-module/Console/generated/model/issuedServiceTokenDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/issuedServiceTokenDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/loginRequest.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/loginRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/loginRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/loginResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/loginResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/loginResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/loginResult.d.ts +32 -0
- package/dist/accessi-module/Console/generated/model/loginResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/loginResult.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/loginResultExtensionFields.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/loginResultExtensionFields.js +9 -0
- package/dist/accessi-module/Console/generated/model/loginResultExtensionFields.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/loginResultPasswordRequired.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/loginResultPasswordRequired.js +14 -0
- package/dist/accessi-module/Console/generated/model/loginResultPasswordRequired.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/menuEntity.d.ts +32 -0
- package/dist/accessi-module/Console/generated/model/menuEntity.js +9 -0
- package/dist/accessi-module/Console/generated/model/menuEntity.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/menuTypeEntity.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/menuTypeEntity.js +9 -0
- package/dist/accessi-module/Console/generated/model/menuTypeEntity.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/passwordExpiredResponse.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/passwordExpiredResponse.js +9 -0
- package/dist/accessi-module/Console/generated/model/passwordExpiredResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/permission.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/permission.js +9 -0
- package/dist/accessi-module/Console/generated/model/permission.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/publicRegisterRequest.d.ts +51 -0
- package/dist/accessi-module/Console/generated/model/publicRegisterRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/publicRegisterRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/registerRequest.d.ts +62 -0
- package/dist/accessi-module/Console/generated/model/registerRequest.js +3 -0
- package/dist/accessi-module/Console/generated/model/registerRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/registerResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/registerResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/registerResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/resendTwoFactorRequest.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/resendTwoFactorRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/resendTwoFactorRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/role.d.ts +15 -0
- package/dist/accessi-module/Console/generated/model/role.js +3 -0
- package/dist/accessi-module/Console/generated/model/role.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenu.d.ts +15 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenu.js +3 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenu.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenuTipoAbilitazione.d.ts +16 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenuTipoAbilitazione.js +17 -0
- package/dist/accessi-module/Console/generated/model/ruoliMenuTipoAbilitazione.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/sendResetPasswordEmailRequest.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/sendResetPasswordEmailRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/sendResetPasswordEmailRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/serveResetPasswordPageParams.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/serveResetPasswordPageParams.js +9 -0
- package/dist/accessi-module/Console/generated/model/serveResetPasswordPageParams.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/serviceTokenDto.d.ts +28 -0
- package/dist/accessi-module/Console/generated/model/serviceTokenDto.js +9 -0
- package/dist/accessi-module/Console/generated/model/serviceTokenDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/setPasswordLoginPolicyRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/setPasswordLoginPolicyRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/setPasswordLoginPolicyRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDto.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDtoStatoRegistrazione.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDtoStatoRegistrazione.js +19 -0
- package/dist/accessi-module/Console/generated/model/setStatoRegistrazioneDtoStatoRegistrazione.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/status.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/status.js +9 -0
- package/dist/accessi-module/Console/generated/model/status.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltro.d.ts +23 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltro.js +3 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltro.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltroFlgEnabled.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltroFlgEnabled.js +15 -0
- package/dist/accessi-module/Console/generated/model/tipoFiltroFlgEnabled.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/tokenResult.d.ts +15 -0
- package/dist/accessi-module/Console/generated/model/tokenResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/tokenResult.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/tokenResultType.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/tokenResultType.js +15 -0
- package/dist/accessi-module/Console/generated/model/tokenResultType.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDto.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoMethod.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoMethod.js +14 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoMethod.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoTwoFactorRequired.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoTwoFactorRequired.js +14 -0
- package/dist/accessi-module/Console/generated/model/twoFactorChallengeDtoTwoFactorRequired.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateEnabledStatusRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/updateEnabledStatusRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateEnabledStatusRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedIdentityRequest.d.ts +11 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedIdentityRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedIdentityRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedProviderRequest.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedProviderRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateFederatedProviderRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequest.d.ts +21 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequest.js +3 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequestFlgEnabled.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequestFlgEnabled.js +15 -0
- package/dist/accessi-module/Console/generated/model/updateFilterTypeRequestFlgEnabled.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateMenuGroupRequest.d.ts +22 -0
- package/dist/accessi-module/Console/generated/model/updateMenuGroupRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateMenuGroupRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateMenuRequest.d.ts +47 -0
- package/dist/accessi-module/Console/generated/model/updateMenuRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateMenuRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/updateMenuTypeRequest.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/updateMenuTypeRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/updateMenuTypeRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/userDto.d.ts +88 -0
- package/dist/accessi-module/Console/generated/model/userDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/userDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/userDtoStatoRegistrazione.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/userDtoStatoRegistrazione.js +19 -0
- package/dist/accessi-module/Console/generated/model/userDtoStatoRegistrazione.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/userGrantsDto.d.ts +16 -0
- package/dist/accessi-module/Console/generated/model/userGrantsDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/userGrantsDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/userGrantsResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/userGrantsResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/userGrantsResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/verifyTwoFactorRequest.d.ts +18 -0
- package/dist/accessi-module/Console/generated/model/verifyTwoFactorRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/verifyTwoFactorRequest.js.map +1 -0
- package/dist/accessi-module/Console/help.d.ts +13 -0
- package/dist/accessi-module/Console/help.js +348 -0
- package/dist/accessi-module/Console/help.js.map +1 -0
- package/dist/accessi-module/Console/index.html +127 -0
- package/dist/accessi-module/Console/wiki.d.ts +52 -0
- package/dist/accessi-module/Console/wiki.js +689 -0
- package/dist/accessi-module/Console/wiki.js.map +1 -0
- package/dist/accessi-module/Controllers/AccessiConsoleController.d.ts +18 -0
- package/dist/accessi-module/Controllers/AccessiConsoleController.js +111 -0
- package/dist/accessi-module/Controllers/AccessiConsoleController.js.map +1 -0
- package/dist/accessi-module/Controllers/AuthController.d.ts +8 -5
- package/dist/accessi-module/Controllers/AuthController.js +128 -79
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Controllers/ConfiguratorController.d.ts +1 -3
- package/dist/accessi-module/Controllers/ConfiguratorController.js +30 -35
- package/dist/accessi-module/Controllers/ConfiguratorController.js.map +1 -1
- package/dist/accessi-module/Controllers/EmailController.d.ts +4 -6
- package/dist/accessi-module/Controllers/EmailController.js +12 -14
- package/dist/accessi-module/Controllers/EmailController.js.map +1 -1
- package/dist/accessi-module/Controllers/FiltriController.d.ts +5 -4
- package/dist/accessi-module/Controllers/FiltriController.js +124 -5
- package/dist/accessi-module/Controllers/FiltriController.js.map +1 -1
- package/dist/accessi-module/Controllers/PermissionController.d.ts +12 -1
- package/dist/accessi-module/Controllers/PermissionController.js +317 -46
- package/dist/accessi-module/Controllers/PermissionController.js.map +1 -1
- package/dist/accessi-module/Controllers/ServiceTokenController.d.ts +23 -0
- package/dist/accessi-module/Controllers/ServiceTokenController.js +176 -0
- package/dist/accessi-module/Controllers/ServiceTokenController.js.map +1 -0
- package/dist/accessi-module/Controllers/UserController.d.ts +8 -4
- package/dist/accessi-module/Controllers/UserController.js +156 -23
- package/dist/accessi-module/Controllers/UserController.js.map +1 -1
- package/dist/accessi-module/Dtos/Abilitazione.js.map +1 -1
- package/dist/accessi-module/Dtos/AbilitazioneMenu.js +16 -8
- package/dist/accessi-module/Dtos/AbilitazioneMenu.js.map +1 -1
- package/dist/accessi-module/Dtos/AssignPermissionsToUserRequest.js +0 -1
- package/dist/accessi-module/Dtos/AssignPermissionsToUserRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/AssignRolesToUserRequest.js +1 -2
- package/dist/accessi-module/Dtos/AssignRolesToUserRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.d.ts +13 -0
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.js +70 -0
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.js.map +1 -0
- package/dist/accessi-module/Dtos/BaseResponse.d.ts +22 -0
- package/dist/accessi-module/Dtos/BaseResponse.js +106 -1
- package/dist/accessi-module/Dtos/BaseResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/CatalogDtos.d.ts +66 -0
- package/dist/accessi-module/Dtos/CatalogDtos.js +336 -0
- package/dist/accessi-module/Dtos/CatalogDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/ConfirmResetPasswordRequest.d.ts +3 -0
- package/dist/accessi-module/Dtos/ConfirmResetPasswordRequest.js +31 -0
- package/dist/accessi-module/Dtos/ConfirmResetPasswordRequest.js.map +1 -0
- package/dist/accessi-module/Dtos/FederatedIdentityDtos.d.ts +69 -0
- package/dist/accessi-module/Dtos/FederatedIdentityDtos.js +236 -0
- package/dist/accessi-module/Dtos/FederatedIdentityDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/FiltriUtente.js +5 -1
- package/dist/accessi-module/Dtos/FiltriUtente.js.map +1 -1
- package/dist/accessi-module/Dtos/GetGroupsWithMenusResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/GetMenusResponse.js +1 -1
- package/dist/accessi-module/Dtos/GetMenusResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/GetRolesResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/GetUserByTokenRequest.d.ts +3 -0
- package/dist/accessi-module/Dtos/GetUserByTokenRequest.js +26 -0
- package/dist/accessi-module/Dtos/GetUserByTokenRequest.js.map +1 -0
- package/dist/accessi-module/Dtos/GetUserByTokenResponse.d.ts +5 -0
- package/dist/accessi-module/Dtos/GetUserByTokenResponse.js +27 -0
- package/dist/accessi-module/Dtos/GetUserByTokenResponse.js.map +1 -0
- package/dist/accessi-module/Dtos/GetUsersResponse.d.ts +1 -1
- package/dist/accessi-module/Dtos/GetUsersResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/LoginRequest.d.ts +1 -1
- package/dist/accessi-module/Dtos/LoginRequest.js +3 -2
- package/dist/accessi-module/Dtos/LoginRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/LoginResponse.d.ts +6 -2
- package/dist/accessi-module/Dtos/LoginResponse.js +20 -7
- package/dist/accessi-module/Dtos/LoginResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/MenuItem.js +1 -0
- package/dist/accessi-module/Dtos/Permission.d.ts +1 -0
- package/dist/accessi-module/Dtos/Permission.js +1 -0
- package/dist/accessi-module/Dtos/Permission.js.map +1 -1
- package/dist/accessi-module/Dtos/PublicRegisterRequest.d.ts +5 -0
- package/dist/accessi-module/Dtos/PublicRegisterRequest.js +15 -0
- package/dist/accessi-module/Dtos/PublicRegisterRequest.js.map +1 -0
- package/dist/accessi-module/Dtos/RegisterRequest.js +7 -1
- package/dist/accessi-module/Dtos/RegisterRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/RegisterResponse.d.ts +1 -1
- package/dist/accessi-module/Dtos/RegisterResponse.js +3 -3
- package/dist/accessi-module/Dtos/RegisterResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/Role.d.ts +4 -0
- package/dist/accessi-module/Dtos/Role.js +4 -0
- package/dist/accessi-module/Dtos/Role.js.map +1 -1
- package/dist/accessi-module/Dtos/RuoliMenu.js.map +1 -1
- package/dist/accessi-module/Dtos/SendResetPasswordEmailRequest.d.ts +4 -0
- package/dist/accessi-module/Dtos/SendResetPasswordEmailRequest.js +36 -0
- package/dist/accessi-module/Dtos/SendResetPasswordEmailRequest.js.map +1 -0
- package/dist/accessi-module/Dtos/ServiceToken.d.ts +34 -0
- package/dist/accessi-module/Dtos/ServiceToken.js +128 -0
- package/dist/accessi-module/Dtos/ServiceToken.js.map +1 -0
- package/dist/accessi-module/Dtos/SetStatoRegistrazione.js.map +1 -1
- package/dist/accessi-module/Dtos/StatoRegistrazione.js.map +1 -1
- package/dist/accessi-module/Dtos/TipoAbilitazione.d.ts +4 -0
- package/dist/accessi-module/Dtos/TipoAbilitazione.js +4 -0
- package/dist/accessi-module/Dtos/TipoAbilitazione.js.map +1 -1
- package/dist/accessi-module/Dtos/TipoFiltro.js.map +1 -1
- package/dist/accessi-module/Dtos/TokenResult.js.map +1 -1
- package/dist/accessi-module/Dtos/TwoFactorDtos.d.ts +13 -0
- package/dist/accessi-module/Dtos/TwoFactorDtos.js +60 -0
- package/dist/accessi-module/Dtos/TwoFactorDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/UpdateEnabledStatusRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/UserDto.d.ts +7 -0
- package/dist/accessi-module/Dtos/UserDto.js +31 -3
- package/dist/accessi-module/Dtos/UserDto.js.map +1 -1
- package/dist/accessi-module/Dtos/UserGrantsDto.js.map +1 -1
- package/dist/accessi-module/Dtos/UserGrantsResponse.d.ts +5 -0
- package/dist/accessi-module/Dtos/UserGrantsResponse.js +27 -0
- package/dist/accessi-module/Dtos/UserGrantsResponse.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +11 -0
- package/dist/accessi-module/Dtos/index.js +11 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/AuthService/AuthService.d.ts +40 -5
- package/dist/accessi-module/Services/AuthService/AuthService.js +192 -40
- package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
- package/dist/accessi-module/Services/ConfiguratorService/ConfiguratorService.d.ts +3 -1
- package/dist/accessi-module/Services/ConfiguratorService/ConfiguratorService.js +5 -1
- package/dist/accessi-module/Services/ConfiguratorService/ConfiguratorService.js.map +1 -1
- package/dist/accessi-module/Services/EmailService/EmailService.d.ts +9 -2
- package/dist/accessi-module/Services/EmailService/EmailService.js +47 -22
- package/dist/accessi-module/Services/EmailService/EmailService.js.map +1 -1
- package/dist/accessi-module/Services/FiltriService/FiltriService.d.ts +18 -3
- package/dist/accessi-module/Services/FiltriService/FiltriService.js +92 -16
- package/dist/accessi-module/Services/FiltriService/FiltriService.js.map +1 -1
- package/dist/accessi-module/Services/PermissionService/PermissionService.d.ts +77 -2
- package/dist/accessi-module/Services/PermissionService/PermissionService.js +608 -206
- package/dist/accessi-module/Services/PermissionService/PermissionService.js.map +1 -1
- package/dist/accessi-module/Services/ServiceTokenService/ServiceTokenService.d.ts +75 -0
- package/dist/accessi-module/Services/ServiceTokenService/ServiceTokenService.js +265 -0
- package/dist/accessi-module/Services/ServiceTokenService/ServiceTokenService.js.map +1 -0
- package/dist/accessi-module/Services/TwoFactorService/TwoFactorService.d.ts +27 -0
- package/dist/accessi-module/Services/TwoFactorService/TwoFactorService.js +175 -0
- package/dist/accessi-module/Services/TwoFactorService/TwoFactorService.js.map +1 -0
- package/dist/accessi-module/Services/UserService/UserService.d.ts +54 -4
- package/dist/accessi-module/Services/UserService/UserService.js +434 -269
- package/dist/accessi-module/Services/UserService/UserService.js.map +1 -1
- package/dist/accessi-module/Views/reset-password.html +213 -213
- package/dist/accessi-module/accessiRuntime.d.ts +45 -0
- package/dist/accessi-module/accessiRuntime.js +39 -0
- package/dist/accessi-module/accessiRuntime.js.map +1 -0
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.d.ts +51 -10
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js +435 -181
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiSchema.d.ts +45 -0
- package/dist/accessi-module/database-updates/accessiSchema.js +87 -0
- package/dist/accessi-module/database-updates/accessiSchema.js.map +1 -0
- package/dist/accessi-module/database-updates/optionalColumns.d.ts +7 -0
- package/dist/accessi-module/database-updates/optionalColumns.js +58 -0
- package/dist/accessi-module/database-updates/optionalColumns.js.map +1 -0
- package/dist/accessi-module/database-updates/runAccessiDbUpdate.js +26 -8
- package/dist/accessi-module/database-updates/runAccessiDbUpdate.js.map +1 -1
- package/dist/accessi-module/federated-auth/FederatedAuthController.d.ts +24 -0
- package/dist/accessi-module/federated-auth/FederatedAuthController.js +333 -0
- package/dist/accessi-module/federated-auth/FederatedAuthController.js.map +1 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.d.ts +100 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.js +451 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.js.map +1 -0
- package/dist/accessi-module/federated-auth/FederatedAuthTypes.d.ts +53 -0
- package/dist/accessi-module/federated-auth/FederatedAuthTypes.js +3 -0
- package/dist/accessi-module/federated-auth/FederatedAuthTypes.js.map +1 -0
- package/dist/accessi-module/index.d.ts +21 -0
- package/dist/accessi-module/index.js +69 -19
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/jwt/jwt.strategy.d.ts +1 -1
- package/dist/accessi-module/jwt/jwt.strategy.js +16 -7
- package/dist/accessi-module/jwt/jwt.strategy.js.map +1 -1
- package/dist/accessi-module/middleware/accessiRequirements.d.ts +23 -1
- package/dist/accessi-module/middleware/accessiRequirements.js +7 -0
- package/dist/accessi-module/middleware/accessiRequirements.js.map +1 -1
- package/dist/accessi-module/middleware/authenticateGen.d.ts +16 -1
- package/dist/accessi-module/middleware/authenticateGen.js +63 -25
- package/dist/accessi-module/middleware/authenticateGen.js.map +1 -1
- package/dist/accessi-module/security/AccessiHttpExceptionFilter.d.ts +12 -0
- package/dist/accessi-module/security/AccessiHttpExceptionFilter.js +74 -0
- package/dist/accessi-module/security/AccessiHttpExceptionFilter.js.map +1 -0
- package/dist/accessi-module/security/accessControl.d.ts +11 -0
- package/dist/accessi-module/security/accessControl.js +19 -4
- package/dist/accessi-module/security/accessControl.js.map +1 -1
- package/dist/accessi-module/security/accessiValidation.d.ts +9 -0
- package/dist/accessi-module/security/accessiValidation.js +41 -0
- package/dist/accessi-module/security/accessiValidation.js.map +1 -0
- package/dist/accessi-module/security/authenticatedToken.d.ts +15 -1
- package/dist/accessi-module/security/authenticatedToken.js +31 -4
- package/dist/accessi-module/security/authenticatedToken.js.map +1 -1
- package/dist/accessi-module/security/emailConfiguration.d.ts +20 -0
- package/dist/accessi-module/security/emailConfiguration.js +41 -0
- package/dist/accessi-module/security/emailConfiguration.js.map +1 -0
- package/dist/accessi-module/security/passwordResetToken.d.ts +13 -3
- package/dist/accessi-module/security/passwordResetToken.js +13 -5
- package/dist/accessi-module/security/passwordResetToken.js.map +1 -1
- package/dist/accessi-module/security/publicAuthRateLimit.d.ts +3 -3
- package/dist/accessi-module/security/publicAuthRateLimit.js +30 -8
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/security/serviceTokenGuard.d.ts +25 -0
- package/dist/accessi-module/security/serviceTokenGuard.js +85 -0
- package/dist/accessi-module/security/serviceTokenGuard.js.map +1 -0
- package/dist/accessi-module/security/serviceTokenRateLimit.d.ts +8 -0
- package/dist/accessi-module/security/serviceTokenRateLimit.js +49 -0
- package/dist/accessi-module/security/serviceTokenRateLimit.js.map +1 -0
- package/dist/allegati-module/AllegatiModule.d.ts +12 -1
- package/dist/allegati-module/AllegatiModule.js +11 -1
- package/dist/allegati-module/AllegatiModule.js.map +1 -1
- package/dist/allegati-module/Controllers/AllegatiController.d.ts +2 -1
- package/dist/allegati-module/Controllers/AllegatiController.js +23 -15
- package/dist/allegati-module/Controllers/AllegatiController.js.map +1 -1
- package/dist/allegati-module/Dtos/AllegatoDto.js.map +1 -1
- package/dist/allegati-module/Dtos/BaseResponse.js.map +1 -1
- package/dist/allegati-module/Dtos/UploadSingleFileRequest.js.map +1 -1
- package/dist/allegati-module/Dtos/index.js.map +1 -1
- package/dist/allegati-module/Dtos/responses/DownloadAllegatoResponseDto.js.map +1 -1
- package/dist/allegati-module/Dtos/responses/GetListResponse.js.map +1 -1
- package/dist/allegati-module/Dtos/responses/UploadAllegatoResponseDto.js.map +1 -1
- package/dist/allegati-module/Services/AllegatiService/AllegatiService.d.ts +10 -3
- package/dist/allegati-module/Services/AllegatiService/AllegatiService.js +150 -101
- package/dist/allegati-module/Services/AllegatiService/AllegatiService.js.map +1 -1
- package/dist/allegati-module/index.js.map +1 -1
- package/dist/allegati-module/security/allegatiAuthorizationGuard.d.ts +14 -0
- package/dist/allegati-module/security/allegatiAuthorizationGuard.js +70 -0
- package/dist/allegati-module/security/allegatiAuthorizationGuard.js.map +1 -0
- package/dist/autobind.d.ts +10 -3
- package/dist/autobind.js +24 -9
- package/dist/autobind.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.30.tgz +0 -0
- package/dist/firebird-compat.d.ts +29 -6
- package/dist/firebird-compat.js +150 -129
- package/dist/firebird-compat.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/initEmilsoftwareModule.js +11 -3
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/dist/scripts/generateAccessiOpenApi.d.ts +1 -0
- package/dist/scripts/generateAccessiOpenApi.js +57 -0
- package/dist/scripts/generateAccessiOpenApi.js.map +1 -0
- package/dist/scripts/generateAccessiWiki.d.ts +1 -0
- package/dist/scripts/generateAccessiWiki.js +131 -0
- package/dist/scripts/generateAccessiWiki.js.map +1 -0
- package/dist/swagger/SwaggerConfig.d.ts +7 -1
- package/dist/swagger/SwaggerConfig.js +22 -8
- package/dist/swagger/SwaggerConfig.js.map +1 -1
- package/package.json +103 -83
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractAccessiBearerToken = extractAccessiBearerToken;
|
|
3
4
|
exports.resolveCodiceUtenteFromTokenPayload = resolveCodiceUtenteFromTokenPayload;
|
|
4
5
|
exports.buildAuthenticatedTokenPayload = buildAuthenticatedTokenPayload;
|
|
6
|
+
exports.isAccessiTokenAllowedForUser = isAccessiTokenAllowedForUser;
|
|
5
7
|
exports.isAuthenticatedUserEnabledForJwt = isAuthenticatedUserEnabledForJwt;
|
|
6
8
|
const StatoRegistrazione_1 = require("../Dtos/StatoRegistrazione");
|
|
7
9
|
function normalizeBooleanFlag(value) {
|
|
@@ -10,9 +12,18 @@ function normalizeBooleanFlag(value) {
|
|
|
10
12
|
function isRecord(value) {
|
|
11
13
|
return typeof value === 'object' && value !== null;
|
|
12
14
|
}
|
|
15
|
+
/** Shared, strict Bearer parsing for the Nest guard and Express middleware. */
|
|
16
|
+
function extractAccessiBearerToken(header) {
|
|
17
|
+
var _a;
|
|
18
|
+
if (typeof header !== 'string')
|
|
19
|
+
return undefined;
|
|
20
|
+
return (_a = /^Bearer[ \t]+([^\s]+)$/i.exec(header.trim())) === null || _a === void 0 ? void 0 : _a[1];
|
|
21
|
+
}
|
|
22
|
+
/** Estrae il codice utente sia dai JWT Accessi moderni sia dai payload legacy compatibili. */
|
|
13
23
|
function resolveCodiceUtenteFromTokenPayload(decoded) {
|
|
14
24
|
var _a;
|
|
15
|
-
|
|
25
|
+
// `typ` obbligatorio: un token senza tipo non e un access token Accessi.
|
|
26
|
+
if (!isRecord(decoded) || decoded.typ !== 'access') {
|
|
16
27
|
return undefined;
|
|
17
28
|
}
|
|
18
29
|
const userData = isRecord(decoded.userData) ? decoded.userData : undefined;
|
|
@@ -22,17 +33,33 @@ function resolveCodiceUtenteFromTokenPayload(decoded) {
|
|
|
22
33
|
? userData.utente
|
|
23
34
|
: undefined;
|
|
24
35
|
const codiceUtente = Number((_a = utente === null || utente === void 0 ? void 0 : utente.codiceUtente) !== null && _a !== void 0 ? _a : decoded.codiceUtente);
|
|
25
|
-
if (!Number.
|
|
36
|
+
if (!Number.isSafeInteger(codiceUtente) || codiceUtente <= 0) {
|
|
26
37
|
return undefined;
|
|
27
38
|
}
|
|
28
39
|
return codiceUtente;
|
|
29
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Mantiene le claim estranee al modulo ma sovrascrive il profilo con valori correnti e autorevoli dal database.
|
|
43
|
+
* `tokenPayload` conserva il payload verificato originale per audit o integrazioni che ne abbiano necessita.
|
|
44
|
+
*/
|
|
30
45
|
function buildAuthenticatedTokenPayload(decoded, utente) {
|
|
31
46
|
const basePayload = isRecord(decoded) ? Object.assign({}, decoded) : {};
|
|
32
47
|
const userData = isRecord(basePayload.userData) ? Object.assign({}, basePayload.userData) : {};
|
|
33
|
-
const normalizedUser = Object.assign(Object.assign({}, utente), { flagSuper: normalizeBooleanFlag(utente.flagSuper), flagAdminConfigurator: normalizeBooleanFlag(utente.flagAdminConfigurator) });
|
|
34
|
-
return Object.assign(Object.assign({}, basePayload), { utente: normalizedUser, userData: Object.assign(Object.assign({}, userData), { utente: normalizedUser }), tokenPayload: decoded });
|
|
48
|
+
const normalizedUser = Object.assign(Object.assign({}, utente), { flagSuper: normalizeBooleanFlag(utente.flagSuper), flagAdminConfigurator: normalizeBooleanFlag(utente.flagAdminConfigurator), flagDueFattori: normalizeBooleanFlag(utente.flagDueFattori), passwordlessLoginEnabled: normalizeBooleanFlag(utente.passwordlessLoginEnabled) });
|
|
49
|
+
return Object.assign(Object.assign({}, basePayload), { codiceUtente: normalizedUser.codiceUtente, email: normalizedUser.email, statoRegistrazione: normalizedUser.statoRegistrazione, flagSuper: normalizedUser.flagSuper, flagAdminConfigurator: normalizedUser.flagAdminConfigurator, flagDueFattori: normalizedUser.flagDueFattori, passwordlessLoginEnabled: normalizedUser.passwordlessLoginEnabled, passwordLoginEnabled: normalizedUser.passwordLoginEnabled, utente: normalizedUser, userData: Object.assign(Object.assign({}, userData), { utente: normalizedUser }), tokenPayload: decoded });
|
|
50
|
+
}
|
|
51
|
+
/** Enabling 2FA invalidates sessions which have not completed the required verification. */
|
|
52
|
+
function isAccessiTokenAllowedForUser(decoded, user) {
|
|
53
|
+
if (!isRecord(decoded))
|
|
54
|
+
return false;
|
|
55
|
+
const methods = Array.isArray(decoded.amr) ? decoded.amr : [];
|
|
56
|
+
if (user.flagDueFattori && !methods.includes('otp'))
|
|
57
|
+
return false;
|
|
58
|
+
if (methods.includes('passwordless') && (!user.flagDueFattori || !user.passwordlessLoginEnabled))
|
|
59
|
+
return false;
|
|
60
|
+
return true;
|
|
35
61
|
}
|
|
62
|
+
/** Un JWT puo essere usato soltanto da utenti nello stato confermato, indipendentemente dalla sua scadenza. */
|
|
36
63
|
function isAuthenticatedUserEnabledForJwt(utente) {
|
|
37
64
|
return (utente === null || utente === void 0 ? void 0 : utente.statoRegistrazione) === StatoRegistrazione_1.StatoRegistrazione.CONF;
|
|
38
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticatedToken.js","sourceRoot":"","sources":["../../../src/accessi-module/security/authenticatedToken.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"authenticatedToken.js","sourceRoot":"","sources":["../../../src/accessi-module/security/authenticatedToken.ts"],"names":[],"mappings":"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","sourcesContent":["import { StatoRegistrazione } from '../Dtos/StatoRegistrazione';\n\n/** Stato autorevole minimo riletto dal database per ogni verifica JWT. */\nexport interface AccessiAuthenticatedUserSnapshot {\n codiceUtente: number;\n email?: string;\n statoRegistrazione: StatoRegistrazione;\n flagSuper: boolean;\n flagAdminConfigurator: boolean;\n flagDueFattori?: boolean;\n passwordlessLoginEnabled?: boolean;\n passwordLoginEnabled?: boolean;\n}\n\nfunction normalizeBooleanFlag(value: unknown): boolean {\n return value === true || value === 1 || value === '1';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/** Shared, strict Bearer parsing for the Nest guard and Express middleware. */\nexport function extractAccessiBearerToken(header: unknown): string | undefined {\n if (typeof header !== 'string') return undefined;\n return /^Bearer[ \\t]+([^\\s]+)$/i.exec(header.trim())?.[1];\n}\n\n/** Estrae il codice utente sia dai JWT Accessi moderni sia dai payload legacy compatibili. */\nexport function resolveCodiceUtenteFromTokenPayload(decoded: unknown): number | undefined {\n // `typ` obbligatorio: un token senza tipo non e un access token Accessi.\n if (!isRecord(decoded) || decoded.typ !== 'access') {\n return undefined;\n }\n\n const userData = isRecord(decoded.userData) ? decoded.userData : undefined;\n const utente = isRecord(decoded.utente)\n ? decoded.utente\n : isRecord(userData?.utente)\n ? userData.utente\n : undefined;\n\n const codiceUtente = Number(utente?.codiceUtente ?? decoded.codiceUtente);\n if (!Number.isSafeInteger(codiceUtente) || codiceUtente <= 0) {\n return undefined;\n }\n\n return codiceUtente;\n}\n\n/**\n * Mantiene le claim estranee al modulo ma sovrascrive il profilo con valori correnti e autorevoli dal database.\n * `tokenPayload` conserva il payload verificato originale per audit o integrazioni che ne abbiano necessita.\n */\nexport function buildAuthenticatedTokenPayload(\n decoded: unknown,\n utente: AccessiAuthenticatedUserSnapshot,\n): Record<string, unknown> {\n const basePayload = isRecord(decoded) ? { ...decoded } : {};\n const userData = isRecord(basePayload.userData) ? { ...basePayload.userData } : {};\n\n const normalizedUser = {\n ...utente,\n flagSuper: normalizeBooleanFlag(utente.flagSuper),\n flagAdminConfigurator: normalizeBooleanFlag(utente.flagAdminConfigurator),\n flagDueFattori: normalizeBooleanFlag(utente.flagDueFattori),\n passwordlessLoginEnabled: normalizeBooleanFlag(utente.passwordlessLoginEnabled),\n };\n\n return {\n ...basePayload,\n codiceUtente: normalizedUser.codiceUtente,\n email: normalizedUser.email,\n statoRegistrazione: normalizedUser.statoRegistrazione,\n flagSuper: normalizedUser.flagSuper,\n flagAdminConfigurator: normalizedUser.flagAdminConfigurator,\n flagDueFattori: normalizedUser.flagDueFattori,\n passwordlessLoginEnabled: normalizedUser.passwordlessLoginEnabled,\n passwordLoginEnabled: normalizedUser.passwordLoginEnabled,\n utente: normalizedUser,\n userData: {\n ...userData,\n utente: normalizedUser,\n },\n tokenPayload: decoded,\n };\n}\n\n/** Enabling 2FA invalidates sessions which have not completed the required verification. */\nexport function isAccessiTokenAllowedForUser(decoded: unknown, user: AccessiAuthenticatedUserSnapshot): boolean {\n if (!isRecord(decoded)) return false;\n const methods = Array.isArray(decoded.amr) ? decoded.amr : [];\n if (user.flagDueFattori && !methods.includes('otp')) return false;\n if (methods.includes('passwordless') && (!user.flagDueFattori || !user.passwordlessLoginEnabled)) return false;\n return true;\n}\n\n/** Un JWT puo essere usato soltanto da utenti nello stato confermato, indipendentemente dalla sua scadenza. */\nexport function isAuthenticatedUserEnabledForJwt(\n utente: AccessiAuthenticatedUserSnapshot | null | undefined,\n): utente is AccessiAuthenticatedUserSnapshot {\n return utente?.statoRegistrazione === StatoRegistrazione.CONF;\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BadRequestException } from '@nestjs/common';
|
|
2
|
+
import type { AccessiOptions } from '../AccessiModule';
|
|
3
|
+
/** Codice stabile usato nel contratto errore quando manca la configurazione email. */
|
|
4
|
+
export declare const ACCESSI_EMAIL_NOT_CONFIGURED = "ACCESSI_EMAIL_NOT_CONFIGURED";
|
|
5
|
+
/**
|
|
6
|
+
* Errore sollevato quando un'operazione richiede l'invio di email (reset password, 2FA,
|
|
7
|
+
* creazione utente) ma `AccessiOptions.emailOptions` non e configurato. E' una BadRequestException
|
|
8
|
+
* con un `code` stabile, cosi il contratto HTTP risponde 400 con ACCESSI_EMAIL_NOT_CONFIGURED.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AccessiEmailNotConfiguredError extends BadRequestException {
|
|
11
|
+
get code(): string;
|
|
12
|
+
constructor(message?: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* True se `emailOptions` contiene i campi minimi per inviare posta (host SMTP e mittente).
|
|
16
|
+
* Non verifica la raggiungibilita del server: quella si scopre all'invio.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isEmailConfigured(options: AccessiOptions): boolean;
|
|
19
|
+
/** Fail-fast utilizzato dal bootstrap e dalle operazioni che dipendono dalla posta. */
|
|
20
|
+
export declare function assertEmailConfigured(options: AccessiOptions): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccessiEmailNotConfiguredError = exports.ACCESSI_EMAIL_NOT_CONFIGURED = void 0;
|
|
4
|
+
exports.isEmailConfigured = isEmailConfigured;
|
|
5
|
+
exports.assertEmailConfigured = assertEmailConfigured;
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
/** Codice stabile usato nel contratto errore quando manca la configurazione email. */
|
|
8
|
+
exports.ACCESSI_EMAIL_NOT_CONFIGURED = 'ACCESSI_EMAIL_NOT_CONFIGURED';
|
|
9
|
+
/**
|
|
10
|
+
* Errore sollevato quando un'operazione richiede l'invio di email (reset password, 2FA,
|
|
11
|
+
* creazione utente) ma `AccessiOptions.emailOptions` non e configurato. E' una BadRequestException
|
|
12
|
+
* con un `code` stabile, cosi il contratto HTTP risponde 400 con ACCESSI_EMAIL_NOT_CONFIGURED.
|
|
13
|
+
*/
|
|
14
|
+
class AccessiEmailNotConfiguredError extends common_1.BadRequestException {
|
|
15
|
+
get code() {
|
|
16
|
+
return exports.ACCESSI_EMAIL_NOT_CONFIGURED;
|
|
17
|
+
}
|
|
18
|
+
constructor(message = 'Nessun servizio email configurato (AccessiOptions.emailOptions): impossibile inviare email di reset password o 2FA.') {
|
|
19
|
+
super({ code: exports.ACCESSI_EMAIL_NOT_CONFIGURED, message });
|
|
20
|
+
this.name = 'AccessiEmailNotConfiguredError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.AccessiEmailNotConfiguredError = AccessiEmailNotConfiguredError;
|
|
24
|
+
/**
|
|
25
|
+
* True se `emailOptions` contiene i campi minimi per inviare posta (host SMTP e mittente).
|
|
26
|
+
* Non verifica la raggiungibilita del server: quella si scopre all'invio.
|
|
27
|
+
*/
|
|
28
|
+
function isEmailConfigured(options) {
|
|
29
|
+
const email = options === null || options === void 0 ? void 0 : options.emailOptions;
|
|
30
|
+
if (!email)
|
|
31
|
+
return false;
|
|
32
|
+
return typeof email.host === 'string' && email.host.trim() !== ''
|
|
33
|
+
&& typeof email.from === 'string' && email.from.trim() !== '';
|
|
34
|
+
}
|
|
35
|
+
/** Fail-fast utilizzato dal bootstrap e dalle operazioni che dipendono dalla posta. */
|
|
36
|
+
function assertEmailConfigured(options) {
|
|
37
|
+
if (!isEmailConfigured(options)) {
|
|
38
|
+
throw new AccessiEmailNotConfiguredError();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=emailConfiguration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailConfiguration.js","sourceRoot":"","sources":["../../../src/accessi-module/security/emailConfiguration.ts"],"names":[],"mappings":";;;AA0BA,8CAKC;AAGD,sDAIC;AAtCD,2CAAqD;AAGrD,sFAAsF;AACzE,QAAA,4BAA4B,GAAG,8BAA8B,CAAC;AAE3E;;;;GAIG;AACH,MAAa,8BAA+B,SAAQ,4BAAmB;IACrE,IAAW,IAAI;QACb,OAAO,oCAA4B,CAAC;IACtC,CAAC;IAED,YAAY,OAAO,GAAG,qHAAqH;QACzI,KAAK,CAAC,EAAE,IAAI,EAAE,oCAA4B,EAAE,OAAO,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;IAC/C,CAAC;CACF;AATD,wEASC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,OAAuB;IACvD,MAAM,KAAK,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAA8D,CAAC;IACtF,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;WAC5D,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAClE,CAAC;AAED,uFAAuF;AACvF,SAAgB,qBAAqB,CAAC,OAAuB;IAC3D,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,8BAA8B,EAAE,CAAC;IAC7C,CAAC;AACH,CAAC","sourcesContent":["import { BadRequestException } from '@nestjs/common';\nimport type { AccessiOptions } from '../AccessiModule';\n\n/** Codice stabile usato nel contratto errore quando manca la configurazione email. */\nexport const ACCESSI_EMAIL_NOT_CONFIGURED = 'ACCESSI_EMAIL_NOT_CONFIGURED';\n\n/**\n * Errore sollevato quando un'operazione richiede l'invio di email (reset password, 2FA,\n * creazione utente) ma `AccessiOptions.emailOptions` non e configurato. E' una BadRequestException\n * con un `code` stabile, cosi il contratto HTTP risponde 400 con ACCESSI_EMAIL_NOT_CONFIGURED.\n */\nexport class AccessiEmailNotConfiguredError extends BadRequestException {\n public get code(): string {\n return ACCESSI_EMAIL_NOT_CONFIGURED;\n }\n\n constructor(message = 'Nessun servizio email configurato (AccessiOptions.emailOptions): impossibile inviare email di reset password o 2FA.') {\n super({ code: ACCESSI_EMAIL_NOT_CONFIGURED, message });\n this.name = 'AccessiEmailNotConfiguredError';\n }\n}\n\n/**\n * True se `emailOptions` contiene i campi minimi per inviare posta (host SMTP e mittente).\n * Non verifica la raggiungibilita del server: quella si scopre all'invio.\n */\nexport function isEmailConfigured(options: AccessiOptions): boolean {\n const email = options?.emailOptions as { host?: unknown; from?: unknown } | undefined;\n if (!email) return false;\n return typeof email.host === 'string' && email.host.trim() !== ''\n && typeof email.from === 'string' && email.from.trim() !== '';\n}\n\n/** Fail-fast utilizzato dal bootstrap e dalle operazioni che dipendono dalla posta. */\nexport function assertEmailConfigured(options: AccessiOptions): void {\n if (!isEmailConfigured(options)) {\n throw new AccessiEmailNotConfiguredError();\n }\n}\n"]}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as jwt from 'jsonwebtoken';
|
|
2
|
+
import type { AccessiOptions } from '../AccessiModule';
|
|
3
|
+
/** Durata predefinita del token di reset. La monouso e garantita anche dal nonce persistito in `UTENTI.KEYREG`. */
|
|
2
4
|
export declare const DEFAULT_PASSWORD_RESET_EXPIRES_IN = "1h";
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
+
/** Scopo della chiave derivata: separa le chiavi di access token, reset password e 2FA. */
|
|
6
|
+
export type AccessiJwtPurpose = 'access' | 'reset' | '2fa';
|
|
7
|
+
/**
|
|
8
|
+
* Deriva una chiave JWT per scopo dal segreto configurato (key separation senza nuova configurazione).
|
|
9
|
+
* Un leak della chiave di reset non compromette gli access token e viceversa.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getAccessiJwtSecret(options: AccessiOptions, purpose?: AccessiJwtPurpose): string;
|
|
12
|
+
/** Crea un token firmato contenente solo codice utente e nonce; non inserire email o dati personali nelle claim. */
|
|
13
|
+
export declare function createPasswordResetToken(codiceUtente: number, nonce: string, secret: string, expiresIn?: jwt.SignOptions['expiresIn']): string;
|
|
14
|
+
/** Verifica firma e scadenza, quindi restituisce i dati minimi necessari al reset. */
|
|
5
15
|
export declare function verifyPasswordResetToken(token: string, secret: string): {
|
|
6
16
|
codiceUtente: number;
|
|
7
17
|
nonce: string;
|
|
@@ -38,15 +38,22 @@ exports.getAccessiJwtSecret = getAccessiJwtSecret;
|
|
|
38
38
|
exports.createPasswordResetToken = createPasswordResetToken;
|
|
39
39
|
exports.verifyPasswordResetToken = verifyPasswordResetToken;
|
|
40
40
|
const jwt = __importStar(require("jsonwebtoken"));
|
|
41
|
+
const crypto_1 = require("crypto");
|
|
42
|
+
/** Durata predefinita del token di reset. La monouso e garantita anche dal nonce persistito in `UTENTI.KEYREG`. */
|
|
41
43
|
exports.DEFAULT_PASSWORD_RESET_EXPIRES_IN = '1h';
|
|
42
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Deriva una chiave JWT per scopo dal segreto configurato (key separation senza nuova configurazione).
|
|
46
|
+
* Un leak della chiave di reset non compromette gli access token e viceversa.
|
|
47
|
+
*/
|
|
48
|
+
function getAccessiJwtSecret(options, purpose = 'access') {
|
|
43
49
|
var _a;
|
|
44
50
|
const secret = ((_a = options === null || options === void 0 ? void 0 : options.jwtOptions) === null || _a === void 0 ? void 0 : _a.secret) || process.env.ACC_JWT_SECRET;
|
|
45
51
|
if (!secret) {
|
|
46
52
|
throw new Error('JWT secret non configurato.');
|
|
47
53
|
}
|
|
48
|
-
return secret;
|
|
54
|
+
return (0, crypto_1.createHmac)('sha256', secret).update(`accessi:jwt:${purpose}:v1`).digest('hex');
|
|
49
55
|
}
|
|
56
|
+
/** Crea un token firmato contenente solo codice utente e nonce; non inserire email o dati personali nelle claim. */
|
|
50
57
|
function createPasswordResetToken(codiceUtente, nonce, secret, expiresIn = exports.DEFAULT_PASSWORD_RESET_EXPIRES_IN) {
|
|
51
58
|
if (!codiceUtente || !nonce) {
|
|
52
59
|
throw new Error('Dati insufficienti per generare il reset token.');
|
|
@@ -56,13 +63,14 @@ function createPasswordResetToken(codiceUtente, nonce, secret, expiresIn = expor
|
|
|
56
63
|
typ: 'password-reset',
|
|
57
64
|
}, secret, {
|
|
58
65
|
subject: `${codiceUtente}`,
|
|
59
|
-
expiresIn
|
|
66
|
+
expiresIn,
|
|
60
67
|
});
|
|
61
68
|
}
|
|
69
|
+
/** Verifica firma e scadenza, quindi restituisce i dati minimi necessari al reset. */
|
|
62
70
|
function verifyPasswordResetToken(token, secret) {
|
|
63
|
-
const decoded = jwt.verify(token, secret);
|
|
71
|
+
const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
|
|
64
72
|
const codiceUtente = Number(decoded === null || decoded === void 0 ? void 0 : decoded.sub);
|
|
65
|
-
if ((decoded === null || decoded === void 0 ? void 0 : decoded.typ) !== 'password-reset' || !codiceUtente || typeof (decoded === null || decoded === void 0 ? void 0 : decoded.nonce) !== 'string') {
|
|
73
|
+
if ((decoded === null || decoded === void 0 ? void 0 : decoded.typ) !== 'password-reset' || !Number.isSafeInteger(codiceUtente) || codiceUtente <= 0 || typeof (decoded === null || decoded === void 0 ? void 0 : decoded.nonce) !== 'string' || !decoded.nonce) {
|
|
66
74
|
throw new Error('Token di reset non valido.');
|
|
67
75
|
}
|
|
68
76
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passwordResetToken.js","sourceRoot":"","sources":["../../../src/accessi-module/security/passwordResetToken.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"passwordResetToken.js","sourceRoot":"","sources":["../../../src/accessi-module/security/passwordResetToken.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,kDAOC;AAGD,4DAqBC;AAGD,4DAeC;AApED,kDAAoC;AACpC,mCAAoC;AAGpC,mHAAmH;AACtG,QAAA,iCAAiC,GAAG,IAAI,CAAC;AAUtD;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,OAAuB,EAAE,UAA6B,QAAQ;;IAChG,MAAM,MAAM,GAAG,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,UAAU,0CAAE,MAAM,KAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACzE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,eAAe,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxF,CAAC;AAED,oHAAoH;AACpH,SAAgB,wBAAwB,CACtC,YAAoB,EACpB,KAAa,EACb,MAAc,EACd,YAA0C,yCAAiC;IAE3E,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CACb;QACE,KAAK;QACL,GAAG,EAAE,gBAAgB;KACtB,EACD,MAAM,EACN;QACE,OAAO,EAAE,GAAG,YAAY,EAAE;QAC1B,SAAS;KACV,CACF,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,SAAgB,wBAAwB,CACtC,KAAa,EACb,MAAc;IAEd,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAA8B,CAAC;IAClG,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAC,CAAC;IAE1C,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,MAAK,gBAAgB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,IAAI,CAAC,IAAI,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,CAAA,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC1J,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACL,YAAY;QACZ,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC;AACJ,CAAC","sourcesContent":["import * as jwt from 'jsonwebtoken';\nimport { createHmac } from 'crypto';\nimport type { AccessiOptions } from '../AccessiModule';\n\n/** Durata predefinita del token di reset. La monouso e garantita anche dal nonce persistito in `UTENTI.KEYREG`. */\nexport const DEFAULT_PASSWORD_RESET_EXPIRES_IN = '1h';\n\ninterface PasswordResetTokenPayload extends jwt.JwtPayload {\n nonce: string;\n typ: 'password-reset';\n}\n\n/** Scopo della chiave derivata: separa le chiavi di access token, reset password e 2FA. */\nexport type AccessiJwtPurpose = 'access' | 'reset' | '2fa';\n\n/**\n * Deriva una chiave JWT per scopo dal segreto configurato (key separation senza nuova configurazione).\n * Un leak della chiave di reset non compromette gli access token e viceversa.\n */\nexport function getAccessiJwtSecret(options: AccessiOptions, purpose: AccessiJwtPurpose = 'access'): string {\n const secret = options?.jwtOptions?.secret || process.env.ACC_JWT_SECRET;\n if (!secret) {\n throw new Error('JWT secret non configurato.');\n }\n\n return createHmac('sha256', secret).update(`accessi:jwt:${purpose}:v1`).digest('hex');\n}\n\n/** Crea un token firmato contenente solo codice utente e nonce; non inserire email o dati personali nelle claim. */\nexport function createPasswordResetToken(\n codiceUtente: number,\n nonce: string,\n secret: string,\n expiresIn: jwt.SignOptions['expiresIn'] = DEFAULT_PASSWORD_RESET_EXPIRES_IN,\n): string {\n if (!codiceUtente || !nonce) {\n throw new Error('Dati insufficienti per generare il reset token.');\n }\n\n return jwt.sign(\n {\n nonce,\n typ: 'password-reset',\n },\n secret,\n {\n subject: `${codiceUtente}`,\n expiresIn,\n },\n );\n}\n\n/** Verifica firma e scadenza, quindi restituisce i dati minimi necessari al reset. */\nexport function verifyPasswordResetToken(\n token: string,\n secret: string,\n): { codiceUtente: number; nonce: string } {\n const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] }) as PasswordResetTokenPayload;\n const codiceUtente = Number(decoded?.sub);\n\n if (decoded?.typ !== 'password-reset' || !Number.isSafeInteger(codiceUtente) || codiceUtente <= 0 || typeof decoded?.nonce !== 'string' || !decoded.nonce) {\n throw new Error('Token di reset non valido.');\n }\n\n return {\n codiceUtente,\n nonce: decoded.nonce,\n };\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Request, Response } from 'express';
|
|
2
|
-
import { AccessiOptions } from '../AccessiModule';
|
|
3
|
-
export type PublicAuthRateLimitScope = 'login' | 'register' | 'passwordResetEmail' | 'passwordResetConfirm' | 'getUserByToken';
|
|
2
|
+
import type { AccessiOptions } from '../AccessiModule';
|
|
3
|
+
export type PublicAuthRateLimitScope = 'login' | 'twoFactorVerify' | 'twoFactorResend' | 'register' | 'passwordResetEmail' | 'passwordResetConfirm' | 'getUserByToken';
|
|
4
4
|
type RateLimitDecision = {
|
|
5
5
|
allowed: boolean;
|
|
6
|
-
retryAfterSeconds
|
|
6
|
+
retryAfterSeconds: number;
|
|
7
7
|
};
|
|
8
8
|
export declare function checkPublicAuthRateLimit(options: AccessiOptions, scope: PublicAuthRateLimitScope, req: Request, identifiers?: string[]): RateLimitDecision;
|
|
9
9
|
export declare function sendPublicAuthRateLimitExceeded(res: Response, retryAfterSeconds: number): Response;
|
|
@@ -6,6 +6,8 @@ const common_1 = require("@nestjs/common");
|
|
|
6
6
|
const Utilities_1 = require("../../Utilities");
|
|
7
7
|
const DEFAULT_PUBLIC_AUTH_RATE_LIMITS = {
|
|
8
8
|
login: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },
|
|
9
|
+
twoFactorVerify: { windowMs: 15 * 60 * 1000, maxAttempts: 20 },
|
|
10
|
+
twoFactorResend: { windowMs: 15 * 60 * 1000, maxAttempts: 5 },
|
|
9
11
|
register: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },
|
|
10
12
|
passwordResetEmail: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },
|
|
11
13
|
passwordResetConfirm: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },
|
|
@@ -49,9 +51,27 @@ function pruneRateLimitBuckets(now) {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
}
|
|
54
|
+
/** Mantiene il numero di bucket sotto la soglia, scartando i meno recenti. */
|
|
55
|
+
function enforceBucketCap() {
|
|
56
|
+
while (RATE_LIMIT_BUCKETS.size >= MAX_TRACKED_BUCKETS) {
|
|
57
|
+
let oldestKey;
|
|
58
|
+
let oldestSeen = Number.POSITIVE_INFINITY;
|
|
59
|
+
for (const [key, bucket] of RATE_LIMIT_BUCKETS.entries()) {
|
|
60
|
+
if (bucket.lastSeenAt < oldestSeen) {
|
|
61
|
+
oldestSeen = bucket.lastSeenAt;
|
|
62
|
+
oldestKey = key;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (oldestKey === undefined) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
RATE_LIMIT_BUCKETS.delete(oldestKey);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
52
71
|
function consumeBucket(bucketKey, rule, now) {
|
|
53
72
|
const existingBucket = RATE_LIMIT_BUCKETS.get(bucketKey);
|
|
54
73
|
if (!existingBucket || existingBucket.resetAt <= now) {
|
|
74
|
+
enforceBucketCap();
|
|
55
75
|
RATE_LIMIT_BUCKETS.set(bucketKey, {
|
|
56
76
|
count: 1,
|
|
57
77
|
resetAt: now + rule.windowMs,
|
|
@@ -69,23 +89,25 @@ function consumeBucket(bucketKey, rule, now) {
|
|
|
69
89
|
function checkPublicAuthRateLimit(options, scope, req, identifiers = []) {
|
|
70
90
|
var _a, _b, _c, _d, _e;
|
|
71
91
|
if (((_a = options.publicAuthRateLimit) === null || _a === void 0 ? void 0 : _a.enabled) === false) {
|
|
72
|
-
return { allowed: true };
|
|
92
|
+
return { allowed: true, retryAfterSeconds: 0 };
|
|
73
93
|
}
|
|
74
94
|
const rule = getRule(options, scope);
|
|
75
95
|
const now = Date.now();
|
|
76
96
|
pruneRateLimitBuckets(now);
|
|
77
97
|
const ipAddress = (_e = normalizeIdentifier((_d = (_b = req.ip) !== null && _b !== void 0 ? _b : (_c = req.socket) === null || _c === void 0 ? void 0 : _c.remoteAddress) !== null && _d !== void 0 ? _d : 'unknown')) !== null && _e !== void 0 ? _e : 'unknown';
|
|
78
|
-
|
|
98
|
+
// Consuma prima il bucket per IP: se gia bloccato non crea bucket per soggetto,
|
|
99
|
+
// evitando crescita di memoria con identificatori sempre diversi.
|
|
100
|
+
const ipRetryAfterSeconds = consumeBucket(`${scope}|ip|${ipAddress}`, rule, now);
|
|
101
|
+
if (ipRetryAfterSeconds) {
|
|
102
|
+
return { allowed: false, retryAfterSeconds: ipRetryAfterSeconds };
|
|
103
|
+
}
|
|
104
|
+
let retryAfterSeconds = 0;
|
|
79
105
|
for (const identifier of identifiers) {
|
|
80
106
|
const normalizedIdentifier = normalizeIdentifier(identifier);
|
|
81
107
|
if (!normalizedIdentifier) {
|
|
82
108
|
continue;
|
|
83
109
|
}
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
let retryAfterSeconds = 0;
|
|
87
|
-
for (const bucketKey of bucketKeys) {
|
|
88
|
-
const bucketRetryAfterSeconds = consumeBucket(bucketKey, rule, now);
|
|
110
|
+
const bucketRetryAfterSeconds = consumeBucket(`${scope}|ip-subject|${ipAddress}|${normalizedIdentifier}`, rule, now);
|
|
89
111
|
if (bucketRetryAfterSeconds) {
|
|
90
112
|
retryAfterSeconds = Math.max(retryAfterSeconds, bucketRetryAfterSeconds);
|
|
91
113
|
}
|
|
@@ -96,7 +118,7 @@ function checkPublicAuthRateLimit(options, scope, req, identifiers = []) {
|
|
|
96
118
|
retryAfterSeconds,
|
|
97
119
|
};
|
|
98
120
|
}
|
|
99
|
-
return { allowed: true };
|
|
121
|
+
return { allowed: true, retryAfterSeconds: 0 };
|
|
100
122
|
}
|
|
101
123
|
function sendPublicAuthRateLimitExceeded(res, retryAfterSeconds) {
|
|
102
124
|
res.setHeader('Retry-After', String(retryAfterSeconds));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publicAuthRateLimit.js","sourceRoot":"","sources":["../../../src/accessi-module/security/publicAuthRateLimit.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpStatus } from '@nestjs/common';\r\nimport { Request, Response } from 'express';\r\nimport { RestUtilities } from '../../Utilities';\r\nimport { AccessiOptions, PublicAuthRateLimitRuleOptions } from '../AccessiModule';\r\n\r\nexport type PublicAuthRateLimitScope =\r\n | 'login'\r\n | 'register'\r\n | 'passwordResetEmail'\r\n | 'passwordResetConfirm'\r\n | 'getUserByToken';\r\n\r\ntype RateLimitBucket = {\r\n count: number;\r\n resetAt: number;\r\n lastSeenAt: number;\r\n};\r\n\r\ntype RateLimitDecision = {\r\n allowed: boolean;\r\n retryAfterSeconds?: number;\r\n};\r\n\r\nconst DEFAULT_PUBLIC_AUTH_RATE_LIMITS: Record<\r\n PublicAuthRateLimitScope,\r\n PublicAuthRateLimitRuleOptions\r\n> = {\r\n login: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },\r\n register: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },\r\n passwordResetEmail: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },\r\n passwordResetConfirm: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },\r\n getUserByToken: { windowMs: 5 * 60 * 1000, maxAttempts: 30 },\r\n};\r\n\r\nconst RATE_LIMIT_BUCKETS = new Map<string, RateLimitBucket>();\r\nconst MAX_TRACKED_BUCKETS = 20000;\r\nconst MAX_WINDOW_MS = Math.max(\r\n ...Object.values(DEFAULT_PUBLIC_AUTH_RATE_LIMITS).map((rule) => rule.windowMs),\r\n);\r\n\r\nfunction getRule(\r\n options: AccessiOptions,\r\n scope: PublicAuthRateLimitScope,\r\n): PublicAuthRateLimitRuleOptions {\r\n const configuredRule = options.publicAuthRateLimit?.[scope];\r\n\r\n if (\r\n configuredRule &&\r\n Number.isFinite(configuredRule.windowMs) &&\r\n configuredRule.windowMs > 0 &&\r\n Number.isFinite(configuredRule.maxAttempts) &&\r\n configuredRule.maxAttempts > 0\r\n ) {\r\n return {\r\n windowMs: Math.trunc(configuredRule.windowMs),\r\n maxAttempts: Math.trunc(configuredRule.maxAttempts),\r\n };\r\n }\r\n\r\n return DEFAULT_PUBLIC_AUTH_RATE_LIMITS[scope];\r\n}\r\n\r\nfunction normalizeIdentifier(identifier: string): string | null {\r\n if (typeof identifier !== 'string') {\r\n return null;\r\n }\r\n\r\n const normalized = identifier.trim().toLowerCase();\r\n return normalized === '' ? null : normalized;\r\n}\r\n\r\nfunction pruneRateLimitBuckets(now: number): void {\r\n if (RATE_LIMIT_BUCKETS.size < MAX_TRACKED_BUCKETS) {\r\n return;\r\n }\r\n\r\n for (const [key, bucket] of RATE_LIMIT_BUCKETS.entries()) {\r\n if (bucket.resetAt <= now || bucket.lastSeenAt <= now - MAX_WINDOW_MS * 2) {\r\n RATE_LIMIT_BUCKETS.delete(key);\r\n }\r\n\r\n if (RATE_LIMIT_BUCKETS.size < MAX_TRACKED_BUCKETS) {\r\n return;\r\n }\r\n }\r\n}\r\n\r\nfunction consumeBucket(\r\n bucketKey: string,\r\n rule: PublicAuthRateLimitRuleOptions,\r\n now: number,\r\n): number | null {\r\n const existingBucket = RATE_LIMIT_BUCKETS.get(bucketKey);\r\n if (!existingBucket || existingBucket.resetAt <= now) {\r\n RATE_LIMIT_BUCKETS.set(bucketKey, {\r\n count: 1,\r\n resetAt: now + rule.windowMs,\r\n lastSeenAt: now,\r\n });\r\n return null;\r\n }\r\n\r\n existingBucket.lastSeenAt = now;\r\n if (existingBucket.count >= rule.maxAttempts) {\r\n return Math.max(1, Math.ceil((existingBucket.resetAt - now) / 1000));\r\n }\r\n\r\n existingBucket.count += 1;\r\n return null;\r\n}\r\n\r\nexport function checkPublicAuthRateLimit(\r\n options: AccessiOptions,\r\n scope: PublicAuthRateLimitScope,\r\n req: Request,\r\n identifiers: string[] = [],\r\n): RateLimitDecision {\r\n if (options.publicAuthRateLimit?.enabled === false) {\r\n return { allowed: true };\r\n }\r\n\r\n const rule = getRule(options, scope);\r\n const now = Date.now();\r\n pruneRateLimitBuckets(now);\r\n\r\n const ipAddress =\r\n normalizeIdentifier(req.ip ?? req.socket?.remoteAddress ?? 'unknown') ?? 'unknown';\r\n const bucketKeys = new Set<string>([`${scope}|ip|${ipAddress}`]);\r\n\r\n for (const identifier of identifiers) {\r\n const normalizedIdentifier = normalizeIdentifier(identifier);\r\n if (!normalizedIdentifier) {\r\n continue;\r\n }\r\n\r\n bucketKeys.add(`${scope}|ip-subject|${ipAddress}|${normalizedIdentifier}`);\r\n }\r\n\r\n let retryAfterSeconds = 0;\r\n for (const bucketKey of bucketKeys) {\r\n const bucketRetryAfterSeconds = consumeBucket(bucketKey, rule, now);\r\n if (bucketRetryAfterSeconds) {\r\n retryAfterSeconds = Math.max(retryAfterSeconds, bucketRetryAfterSeconds);\r\n }\r\n }\r\n\r\n if (retryAfterSeconds > 0) {\r\n return {\r\n allowed: false,\r\n retryAfterSeconds,\r\n };\r\n }\r\n\r\n return { allowed: true };\r\n}\r\n\r\nexport function sendPublicAuthRateLimitExceeded(\r\n res: Response,\r\n retryAfterSeconds: number,\r\n): Response {\r\n res.setHeader('Retry-After', String(retryAfterSeconds));\r\n return RestUtilities.sendErrorMessage(\r\n res,\r\n 'Troppi tentativi. Riprova piu tardi.',\r\n 'PublicAuthRateLimit',\r\n HttpStatus.TOO_MANY_REQUESTS,\r\n );\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"publicAuthRateLimit.js","sourceRoot":"","sources":["../../../src/accessi-module/security/publicAuthRateLimit.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpStatus } from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { RestUtilities } from '../../Utilities';\nimport type { AccessiOptions, PublicAuthRateLimitRuleOptions } from '../AccessiModule';\n\nexport type PublicAuthRateLimitScope =\n | 'login'\n | 'twoFactorVerify'\n | 'twoFactorResend'\n | 'register'\n | 'passwordResetEmail'\n | 'passwordResetConfirm'\n | 'getUserByToken';\n\ntype RateLimitBucket = {\n count: number;\n resetAt: number;\n lastSeenAt: number;\n};\n\ntype RateLimitDecision = {\n allowed: boolean;\n retryAfterSeconds: number;\n};\n\nconst DEFAULT_PUBLIC_AUTH_RATE_LIMITS: Record<\n PublicAuthRateLimitScope,\n PublicAuthRateLimitRuleOptions\n> = {\n login: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },\n twoFactorVerify: { windowMs: 15 * 60 * 1000, maxAttempts: 20 },\n twoFactorResend: { windowMs: 15 * 60 * 1000, maxAttempts: 5 },\n register: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },\n passwordResetEmail: { windowMs: 60 * 60 * 1000, maxAttempts: 5 },\n passwordResetConfirm: { windowMs: 15 * 60 * 1000, maxAttempts: 10 },\n getUserByToken: { windowMs: 5 * 60 * 1000, maxAttempts: 30 },\n};\n\nconst RATE_LIMIT_BUCKETS = new Map<string, RateLimitBucket>();\nconst MAX_TRACKED_BUCKETS = 20000;\nconst MAX_WINDOW_MS = Math.max(\n ...Object.values(DEFAULT_PUBLIC_AUTH_RATE_LIMITS).map((rule) => rule.windowMs),\n);\n\nfunction getRule(\n options: AccessiOptions,\n scope: PublicAuthRateLimitScope,\n): PublicAuthRateLimitRuleOptions {\n const configuredRule = options.publicAuthRateLimit?.[scope];\n\n if (\n configuredRule &&\n Number.isFinite(configuredRule.windowMs) &&\n configuredRule.windowMs > 0 &&\n Number.isFinite(configuredRule.maxAttempts) &&\n configuredRule.maxAttempts > 0\n ) {\n return {\n windowMs: Math.trunc(configuredRule.windowMs),\n maxAttempts: Math.trunc(configuredRule.maxAttempts),\n };\n }\n\n return DEFAULT_PUBLIC_AUTH_RATE_LIMITS[scope];\n}\n\nfunction normalizeIdentifier(identifier: string): string | null {\n if (typeof identifier !== 'string') {\n return null;\n }\n\n const normalized = identifier.trim().toLowerCase();\n return normalized === '' ? null : normalized;\n}\n\nfunction pruneRateLimitBuckets(now: number): void {\n if (RATE_LIMIT_BUCKETS.size < MAX_TRACKED_BUCKETS) {\n return;\n }\n\n for (const [key, bucket] of RATE_LIMIT_BUCKETS.entries()) {\n if (bucket.resetAt <= now || bucket.lastSeenAt <= now - MAX_WINDOW_MS * 2) {\n RATE_LIMIT_BUCKETS.delete(key);\n }\n\n if (RATE_LIMIT_BUCKETS.size < MAX_TRACKED_BUCKETS) {\n return;\n }\n }\n}\n\n/** Mantiene il numero di bucket sotto la soglia, scartando i meno recenti. */\nfunction enforceBucketCap(): void {\n while (RATE_LIMIT_BUCKETS.size >= MAX_TRACKED_BUCKETS) {\n let oldestKey: string | undefined;\n let oldestSeen = Number.POSITIVE_INFINITY;\n\n for (const [key, bucket] of RATE_LIMIT_BUCKETS.entries()) {\n if (bucket.lastSeenAt < oldestSeen) {\n oldestSeen = bucket.lastSeenAt;\n oldestKey = key;\n }\n }\n\n if (oldestKey === undefined) {\n return;\n }\n\n RATE_LIMIT_BUCKETS.delete(oldestKey);\n }\n}\n\nfunction consumeBucket(\n bucketKey: string,\n rule: PublicAuthRateLimitRuleOptions,\n now: number,\n): number | null {\n const existingBucket = RATE_LIMIT_BUCKETS.get(bucketKey);\n if (!existingBucket || existingBucket.resetAt <= now) {\n enforceBucketCap();\n RATE_LIMIT_BUCKETS.set(bucketKey, {\n count: 1,\n resetAt: now + rule.windowMs,\n lastSeenAt: now,\n });\n return null;\n }\n\n existingBucket.lastSeenAt = now;\n if (existingBucket.count >= rule.maxAttempts) {\n return Math.max(1, Math.ceil((existingBucket.resetAt - now) / 1000));\n }\n\n existingBucket.count += 1;\n return null;\n}\n\nexport function checkPublicAuthRateLimit(\n options: AccessiOptions,\n scope: PublicAuthRateLimitScope,\n req: Request,\n identifiers: string[] = [],\n): RateLimitDecision {\n if (options.publicAuthRateLimit?.enabled === false) {\n return { allowed: true, retryAfterSeconds: 0 };\n }\n\n const rule = getRule(options, scope);\n const now = Date.now();\n pruneRateLimitBuckets(now);\n\n const ipAddress =\n normalizeIdentifier(req.ip ?? req.socket?.remoteAddress ?? 'unknown') ?? 'unknown';\n\n // Consuma prima il bucket per IP: se gia bloccato non crea bucket per soggetto,\n // evitando crescita di memoria con identificatori sempre diversi.\n const ipRetryAfterSeconds = consumeBucket(`${scope}|ip|${ipAddress}`, rule, now);\n if (ipRetryAfterSeconds) {\n return { allowed: false, retryAfterSeconds: ipRetryAfterSeconds };\n }\n\n let retryAfterSeconds = 0;\n for (const identifier of identifiers) {\n const normalizedIdentifier = normalizeIdentifier(identifier);\n if (!normalizedIdentifier) {\n continue;\n }\n\n const bucketRetryAfterSeconds = consumeBucket(\n `${scope}|ip-subject|${ipAddress}|${normalizedIdentifier}`,\n rule,\n now,\n );\n if (bucketRetryAfterSeconds) {\n retryAfterSeconds = Math.max(retryAfterSeconds, bucketRetryAfterSeconds);\n }\n }\n\n if (retryAfterSeconds > 0) {\n return {\n allowed: false,\n retryAfterSeconds,\n };\n }\n\n return { allowed: true, retryAfterSeconds: 0 };\n}\n\nexport function sendPublicAuthRateLimitExceeded(\n res: Response,\n retryAfterSeconds: number,\n): Response {\n res.setHeader('Retry-After', String(retryAfterSeconds));\n return RestUtilities.sendErrorMessage(\n res,\n 'Troppi tentativi. Riprova piu tardi.',\n 'PublicAuthRateLimit',\n HttpStatus.TOO_MANY_REQUESTS,\n );\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
2
|
+
import { Reflector } from '@nestjs/core';
|
|
3
|
+
import type { Request } from 'express';
|
|
4
|
+
import { ServiceTokenService, VerifiedServiceToken } from '../Services/ServiceTokenService/ServiceTokenService';
|
|
5
|
+
/** Chiave dei metadata usata da `@RequireServiceTokenScopes`. */
|
|
6
|
+
export declare const SERVICE_TOKEN_SCOPES_METADATA = "accessi:service-token-scopes";
|
|
7
|
+
/** Richiede che il token di servizio presenti tutti gli scope indicati. */
|
|
8
|
+
export declare const RequireServiceTokenScopes: (...scopes: string[]) => import("@nestjs/common").CustomDecorator<string>;
|
|
9
|
+
export type AccessiServiceTokenRequest = Request & {
|
|
10
|
+
accessiServiceToken?: VerifiedServiceToken;
|
|
11
|
+
};
|
|
12
|
+
/** Restituisce il token di servizio verificato da `ServiceTokenGuard`; lancia 401 se assente. */
|
|
13
|
+
export declare function getAccessiServiceToken(req: Request): VerifiedServiceToken;
|
|
14
|
+
/**
|
|
15
|
+
* Autentica le chiamate tecniche macchina-a-macchina tramite `Authorization: Bearer <token>`.
|
|
16
|
+
*
|
|
17
|
+
* Il token e per installazione/servizio, non legato a un utente. Gli scope richiesti si dichiarano
|
|
18
|
+
* con `@RequireServiceTokenScopes('ia')`.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ServiceTokenGuard implements CanActivate {
|
|
21
|
+
private readonly serviceTokenService;
|
|
22
|
+
private readonly reflector;
|
|
23
|
+
constructor(serviceTokenService: ServiceTokenService, reflector: Reflector);
|
|
24
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ServiceTokenGuard = exports.RequireServiceTokenScopes = exports.SERVICE_TOKEN_SCOPES_METADATA = void 0;
|
|
22
|
+
exports.getAccessiServiceToken = getAccessiServiceToken;
|
|
23
|
+
const common_1 = require("@nestjs/common");
|
|
24
|
+
const core_1 = require("@nestjs/core");
|
|
25
|
+
const ServiceTokenService_1 = require("../Services/ServiceTokenService/ServiceTokenService");
|
|
26
|
+
const authenticatedToken_1 = require("./authenticatedToken");
|
|
27
|
+
const serviceTokenRateLimit_1 = require("./serviceTokenRateLimit");
|
|
28
|
+
/** Chiave dei metadata usata da `@RequireServiceTokenScopes`. */
|
|
29
|
+
exports.SERVICE_TOKEN_SCOPES_METADATA = 'accessi:service-token-scopes';
|
|
30
|
+
/** Richiede che il token di servizio presenti tutti gli scope indicati. */
|
|
31
|
+
const RequireServiceTokenScopes = (...scopes) => (0, common_1.SetMetadata)(exports.SERVICE_TOKEN_SCOPES_METADATA, scopes);
|
|
32
|
+
exports.RequireServiceTokenScopes = RequireServiceTokenScopes;
|
|
33
|
+
/** Restituisce il token di servizio verificato da `ServiceTokenGuard`; lancia 401 se assente. */
|
|
34
|
+
function getAccessiServiceToken(req) {
|
|
35
|
+
const verified = req.accessiServiceToken;
|
|
36
|
+
if (!verified) {
|
|
37
|
+
throw new common_1.UnauthorizedException('Token di servizio non verificato.');
|
|
38
|
+
}
|
|
39
|
+
return verified;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Autentica le chiamate tecniche macchina-a-macchina tramite `Authorization: Bearer <token>`.
|
|
43
|
+
*
|
|
44
|
+
* Il token e per installazione/servizio, non legato a un utente. Gli scope richiesti si dichiarano
|
|
45
|
+
* con `@RequireServiceTokenScopes('ia')`.
|
|
46
|
+
*/
|
|
47
|
+
let ServiceTokenGuard = class ServiceTokenGuard {
|
|
48
|
+
constructor(serviceTokenService, reflector) {
|
|
49
|
+
this.serviceTokenService = serviceTokenService;
|
|
50
|
+
this.reflector = reflector;
|
|
51
|
+
}
|
|
52
|
+
canActivate(context) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
var _a, _b, _c, _d;
|
|
55
|
+
const request = context.switchToHttp().getRequest();
|
|
56
|
+
const ip = (_c = (_a = request.ip) !== null && _a !== void 0 ? _a : (_b = request.socket) === null || _b === void 0 ? void 0 : _b.remoteAddress) !== null && _c !== void 0 ? _c : 'unknown';
|
|
57
|
+
(0, serviceTokenRateLimit_1.assertServiceTokenRateLimit)(ip);
|
|
58
|
+
const token = (0, authenticatedToken_1.extractAccessiBearerToken)(request.headers['authorization']);
|
|
59
|
+
if (!token) {
|
|
60
|
+
throw new common_1.UnauthorizedException('Token di servizio mancante.');
|
|
61
|
+
}
|
|
62
|
+
const verified = yield this.serviceTokenService.verify(token, { ip });
|
|
63
|
+
if (!verified) {
|
|
64
|
+
throw new common_1.UnauthorizedException('Token di servizio non valido, scaduto o revocato.');
|
|
65
|
+
}
|
|
66
|
+
request.accessiServiceToken = verified;
|
|
67
|
+
const requiredScopes = (_d = this.reflector.getAllAndOverride(exports.SERVICE_TOKEN_SCOPES_METADATA, [
|
|
68
|
+
context.getHandler(),
|
|
69
|
+
context.getClass(),
|
|
70
|
+
])) !== null && _d !== void 0 ? _d : [];
|
|
71
|
+
const missingScope = requiredScopes.find((scope) => !(0, ServiceTokenService_1.serviceTokenHasScope)(verified.scopes, scope));
|
|
72
|
+
if (missingScope) {
|
|
73
|
+
throw new common_1.ForbiddenException(`Scope '${missingScope}' non autorizzato per questo token.`);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
exports.ServiceTokenGuard = ServiceTokenGuard;
|
|
80
|
+
exports.ServiceTokenGuard = ServiceTokenGuard = __decorate([
|
|
81
|
+
(0, common_1.Injectable)(),
|
|
82
|
+
__metadata("design:paramtypes", [ServiceTokenService_1.ServiceTokenService,
|
|
83
|
+
core_1.Reflector])
|
|
84
|
+
], ServiceTokenGuard);
|
|
85
|
+
//# sourceMappingURL=serviceTokenGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serviceTokenGuard.js","sourceRoot":"","sources":["../../../src/accessi-module/security/serviceTokenGuard.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,wDAMC;AA7BD,2CAOwB;AACxB,uCAAyC;AAEzC,6FAAsI;AACtI,6DAAiE;AACjE,mEAAsE;AAEtE,iEAAiE;AACpD,QAAA,6BAA6B,GAAG,8BAA8B,CAAC;AAE5E,2EAA2E;AACpE,MAAM,yBAAyB,GAAG,CAAC,GAAG,MAAgB,EAAE,EAAE,CAAC,IAAA,oBAAW,EAAC,qCAA6B,EAAE,MAAM,CAAC,CAAC;AAAxG,QAAA,yBAAyB,6BAA+E;AAIrH,iGAAiG;AACjG,SAAgB,sBAAsB,CAAC,GAAY;IACjD,MAAM,QAAQ,GAAI,GAAkC,CAAC,mBAAmB,CAAC;IACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,8BAAqB,CAAC,mCAAmC,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B,YACmB,mBAAwC,EACxC,SAAoB;QADpB,wBAAmB,GAAnB,mBAAmB,CAAqB;QACxC,cAAS,GAAT,SAAS,CAAW;IACpC,CAAC;IAEE,WAAW,CAAC,OAAyB;;;YACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;YAC7D,MAAM,EAAE,GAAG,MAAA,MAAA,OAAO,CAAC,EAAE,mCAAI,MAAA,OAAO,CAAC,MAAM,0CAAE,aAAa,mCAAI,SAAS,CAAC;YACpE,IAAA,mDAA2B,EAAC,EAAE,CAAC,CAAC;YAEhC,MAAM,KAAK,GAAG,IAAA,8CAAyB,EAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;YAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,8BAAqB,CAAC,6BAA6B,CAAC,CAAC;YACjE,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACtE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,8BAAqB,CAAC,mDAAmD,CAAC,CAAC;YACvF,CAAC;YAEA,OAAsC,CAAC,mBAAmB,GAAG,QAAQ,CAAC;YAEvE,MAAM,cAAc,GAAG,MAAA,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAW,qCAA6B,EAAE;gBAC/F,OAAO,CAAC,UAAU,EAAE;gBACpB,OAAO,CAAC,QAAQ,EAAE;aACnB,CAAC,mCAAI,EAAE,CAAC;YACT,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAA,0CAAoB,EAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YACnG,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,IAAI,2BAAkB,CAAC,UAAU,YAAY,qCAAqC,CAAC,CAAC;YAC5F,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;KAAA;CACF,CAAA;AAlCY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAG6B,yCAAmB;QAC7B,gBAAS;GAH5B,iBAAiB,CAkC7B","sourcesContent":["import {\n CanActivate,\n ExecutionContext,\n ForbiddenException,\n Injectable,\n SetMetadata,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport type { Request } from 'express';\nimport { ServiceTokenService, serviceTokenHasScope, VerifiedServiceToken } from '../Services/ServiceTokenService/ServiceTokenService';\nimport { extractAccessiBearerToken } from './authenticatedToken';\nimport { assertServiceTokenRateLimit } from './serviceTokenRateLimit';\n\n/** Chiave dei metadata usata da `@RequireServiceTokenScopes`. */\nexport const SERVICE_TOKEN_SCOPES_METADATA = 'accessi:service-token-scopes';\n\n/** Richiede che il token di servizio presenti tutti gli scope indicati. */\nexport const RequireServiceTokenScopes = (...scopes: string[]) => SetMetadata(SERVICE_TOKEN_SCOPES_METADATA, scopes);\n\nexport type AccessiServiceTokenRequest = Request & { accessiServiceToken?: VerifiedServiceToken };\n\n/** Restituisce il token di servizio verificato da `ServiceTokenGuard`; lancia 401 se assente. */\nexport function getAccessiServiceToken(req: Request): VerifiedServiceToken {\n const verified = (req as AccessiServiceTokenRequest).accessiServiceToken;\n if (!verified) {\n throw new UnauthorizedException('Token di servizio non verificato.');\n }\n return verified;\n}\n\n/**\n * Autentica le chiamate tecniche macchina-a-macchina tramite `Authorization: Bearer <token>`.\n *\n * Il token e per installazione/servizio, non legato a un utente. Gli scope richiesti si dichiarano\n * con `@RequireServiceTokenScopes('ia')`.\n */\n@Injectable()\nexport class ServiceTokenGuard implements CanActivate {\n constructor(\n private readonly serviceTokenService: ServiceTokenService,\n private readonly reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<Request>();\n const ip = request.ip ?? request.socket?.remoteAddress ?? 'unknown';\n assertServiceTokenRateLimit(ip);\n\n const token = extractAccessiBearerToken(request.headers['authorization']);\n if (!token) {\n throw new UnauthorizedException('Token di servizio mancante.');\n }\n\n const verified = await this.serviceTokenService.verify(token, { ip });\n if (!verified) {\n throw new UnauthorizedException('Token di servizio non valido, scaduto o revocato.');\n }\n\n (request as AccessiServiceTokenRequest).accessiServiceToken = verified;\n\n const requiredScopes = this.reflector.getAllAndOverride<string[]>(SERVICE_TOKEN_SCOPES_METADATA, [\n context.getHandler(),\n context.getClass(),\n ]) ?? [];\n const missingScope = requiredScopes.find((scope) => !serviceTokenHasScope(verified.scopes, scope));\n if (missingScope) {\n throw new ForbiddenException(`Scope '${missingScope}' non autorizzato per questo token.`);\n }\n\n return true;\n }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function checkServiceTokenRateLimit(identifier: string): {
|
|
2
|
+
allowed: boolean;
|
|
3
|
+
retryAfterSeconds: number;
|
|
4
|
+
};
|
|
5
|
+
/** Svuota i bucket (usato nei test). */
|
|
6
|
+
export declare function resetServiceTokenRateLimit(): void;
|
|
7
|
+
/** Lancia 429 con `Retry-After` quando il limite e superato. */
|
|
8
|
+
export declare function assertServiceTokenRateLimit(identifier: string): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkServiceTokenRateLimit = checkServiceTokenRateLimit;
|
|
4
|
+
exports.resetServiceTokenRateLimit = resetServiceTokenRateLimit;
|
|
5
|
+
exports.assertServiceTokenRateLimit = assertServiceTokenRateLimit;
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
/**
|
|
8
|
+
* Limite anti-abuso per la verifica dei token di servizio.
|
|
9
|
+
*
|
|
10
|
+
* Il segreto ha 256 bit di entropia (brute force non praticabile), ma il limite evita
|
|
11
|
+
* che un client difettoso o malevolo martelli l'endpoint. In-memory: in cluster va
|
|
12
|
+
* aggiunto un limite anche al gateway.
|
|
13
|
+
*/
|
|
14
|
+
const WINDOW_MS = 60000;
|
|
15
|
+
const MAX_ATTEMPTS = 120;
|
|
16
|
+
const MAX_BUCKETS = 20000;
|
|
17
|
+
const buckets = new Map();
|
|
18
|
+
function checkServiceTokenRateLimit(identifier) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
const key = identifier && identifier.trim() !== '' ? identifier : 'unknown';
|
|
21
|
+
const bucket = buckets.get(key);
|
|
22
|
+
if (!bucket || bucket.resetAt <= now) {
|
|
23
|
+
if (buckets.size >= MAX_BUCKETS) {
|
|
24
|
+
const oldestKey = buckets.keys().next().value;
|
|
25
|
+
if (oldestKey !== undefined) {
|
|
26
|
+
buckets.delete(oldestKey);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
buckets.set(key, { count: 1, resetAt: now + WINDOW_MS });
|
|
30
|
+
return { allowed: true, retryAfterSeconds: 0 };
|
|
31
|
+
}
|
|
32
|
+
if (bucket.count >= MAX_ATTEMPTS) {
|
|
33
|
+
return { allowed: false, retryAfterSeconds: Math.max(1, Math.ceil((bucket.resetAt - now) / 1000)) };
|
|
34
|
+
}
|
|
35
|
+
bucket.count += 1;
|
|
36
|
+
return { allowed: true, retryAfterSeconds: 0 };
|
|
37
|
+
}
|
|
38
|
+
/** Svuota i bucket (usato nei test). */
|
|
39
|
+
function resetServiceTokenRateLimit() {
|
|
40
|
+
buckets.clear();
|
|
41
|
+
}
|
|
42
|
+
/** Lancia 429 con `Retry-After` quando il limite e superato. */
|
|
43
|
+
function assertServiceTokenRateLimit(identifier) {
|
|
44
|
+
const decision = checkServiceTokenRateLimit(identifier);
|
|
45
|
+
if (!decision.allowed) {
|
|
46
|
+
throw new common_1.HttpException({ code: 'ACCESSI_SERVICE_TOKEN_RATE_LIMITED', message: 'Troppi tentativi. Riprova piu tardi.' }, common_1.HttpStatus.TOO_MANY_REQUESTS);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=serviceTokenRateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serviceTokenRateLimit.js","sourceRoot":"","sources":["../../../src/accessi-module/security/serviceTokenRateLimit.ts"],"names":[],"mappings":";;AAgBA,gEAsBC;AAGD,gEAEC;AAGD,kEAQC;AAtDD,2CAA2D;AAI3D;;;;;;GAMG;AACH,MAAM,SAAS,GAAG,KAAM,CAAC;AACzB,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,WAAW,GAAG,KAAM,CAAC;AAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEnD,SAAgB,0BAA0B,CAAC,UAAkB;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,UAAU,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEhC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;YAChC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,SAAS,EAAE,CAAC,CAAC;QACzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;IACtG,CAAC;IAED,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAClB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,wCAAwC;AACxC,SAAgB,0BAA0B;IACxC,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,gEAAgE;AAChE,SAAgB,2BAA2B,CAAC,UAAkB;IAC5D,MAAM,QAAQ,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QACtB,MAAM,IAAI,sBAAa,CACrB,EAAE,IAAI,EAAE,oCAAoC,EAAE,OAAO,EAAE,sCAAsC,EAAE,EAC/F,mBAAU,CAAC,iBAAiB,CAC7B,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { HttpException, HttpStatus } from '@nestjs/common';\n\ntype RateLimitBucket = { count: number; resetAt: number };\n\n/**\n * Limite anti-abuso per la verifica dei token di servizio.\n *\n * Il segreto ha 256 bit di entropia (brute force non praticabile), ma il limite evita\n * che un client difettoso o malevolo martelli l'endpoint. In-memory: in cluster va\n * aggiunto un limite anche al gateway.\n */\nconst WINDOW_MS = 60_000;\nconst MAX_ATTEMPTS = 120;\nconst MAX_BUCKETS = 20_000;\nconst buckets = new Map<string, RateLimitBucket>();\n\nexport function checkServiceTokenRateLimit(identifier: string): { allowed: boolean; retryAfterSeconds: number } {\n const now = Date.now();\n const key = identifier && identifier.trim() !== '' ? identifier : 'unknown';\n const bucket = buckets.get(key);\n\n if (!bucket || bucket.resetAt <= now) {\n if (buckets.size >= MAX_BUCKETS) {\n const oldestKey = buckets.keys().next().value;\n if (oldestKey !== undefined) {\n buckets.delete(oldestKey);\n }\n }\n buckets.set(key, { count: 1, resetAt: now + WINDOW_MS });\n return { allowed: true, retryAfterSeconds: 0 };\n }\n\n if (bucket.count >= MAX_ATTEMPTS) {\n return { allowed: false, retryAfterSeconds: Math.max(1, Math.ceil((bucket.resetAt - now) / 1000)) };\n }\n\n bucket.count += 1;\n return { allowed: true, retryAfterSeconds: 0 };\n}\n\n/** Svuota i bucket (usato nei test). */\nexport function resetServiceTokenRateLimit(): void {\n buckets.clear();\n}\n\n/** Lancia 429 con `Retry-After` quando il limite e superato. */\nexport function assertServiceTokenRateLimit(identifier: string): void {\n const decision = checkServiceTokenRateLimit(identifier);\n if (!decision.allowed) {\n throw new HttpException(\n { code: 'ACCESSI_SERVICE_TOKEN_RATE_LIMITED', message: 'Troppi tentativi. Riprova piu tardi.' },\n HttpStatus.TOO_MANY_REQUESTS,\n );\n }\n}\n"]}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { DynamicModule } from "@nestjs/common";
|
|
2
|
-
import {
|
|
2
|
+
import { Request } from "express";
|
|
3
|
+
import { Options } from "node-firebird";
|
|
3
4
|
export interface AllegatiOptions {
|
|
4
5
|
databaseOptions: Options;
|
|
6
|
+
/**
|
|
7
|
+
* Guard applicato a ogni richiesta dei controller Allegati.
|
|
8
|
+
* Se definito e restituisce `false`, la richiesta viene rifiutata con 403.
|
|
9
|
+
*/
|
|
10
|
+
authorize?: (request: Request) => boolean | Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Sicurezza by default: se `authorize` non e configurato, le richieste vengono rifiutate con 403.
|
|
13
|
+
* Impostare `false` per ripristinare il comportamento storico (endpoint aperti) durante la migrazione.
|
|
14
|
+
*/
|
|
15
|
+
requireAuthorization?: boolean;
|
|
5
16
|
}
|
|
6
17
|
export declare class AllegatiModule {
|
|
7
18
|
static forRoot(options: AllegatiOptions): DynamicModule;
|