@etcsec-com/etc-collector 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +60 -0
- package/.env.test.example +33 -0
- package/.github/workflows/ci.yml +83 -0
- package/.github/workflows/release.yml +246 -0
- package/.prettierrc.json +10 -0
- package/CHANGELOG.md +15 -0
- package/Dockerfile +57 -0
- package/LICENSE +190 -0
- package/README.md +194 -0
- package/dist/api/controllers/audit.controller.d.ts +21 -0
- package/dist/api/controllers/audit.controller.d.ts.map +1 -0
- package/dist/api/controllers/audit.controller.js +179 -0
- package/dist/api/controllers/audit.controller.js.map +1 -0
- package/dist/api/controllers/auth.controller.d.ts +16 -0
- package/dist/api/controllers/auth.controller.d.ts.map +1 -0
- package/dist/api/controllers/auth.controller.js +146 -0
- package/dist/api/controllers/auth.controller.js.map +1 -0
- package/dist/api/controllers/export.controller.d.ts +27 -0
- package/dist/api/controllers/export.controller.d.ts.map +1 -0
- package/dist/api/controllers/export.controller.js +80 -0
- package/dist/api/controllers/export.controller.js.map +1 -0
- package/dist/api/controllers/health.controller.d.ts +5 -0
- package/dist/api/controllers/health.controller.d.ts.map +1 -0
- package/dist/api/controllers/health.controller.js +16 -0
- package/dist/api/controllers/health.controller.js.map +1 -0
- package/dist/api/controllers/jobs.controller.d.ts +13 -0
- package/dist/api/controllers/jobs.controller.d.ts.map +1 -0
- package/dist/api/controllers/jobs.controller.js +125 -0
- package/dist/api/controllers/jobs.controller.js.map +1 -0
- package/dist/api/controllers/providers.controller.d.ts +15 -0
- package/dist/api/controllers/providers.controller.d.ts.map +1 -0
- package/dist/api/controllers/providers.controller.js +112 -0
- package/dist/api/controllers/providers.controller.js.map +1 -0
- package/dist/api/dto/AuditRequest.dto.d.ts +6 -0
- package/dist/api/dto/AuditRequest.dto.d.ts.map +1 -0
- package/dist/api/dto/AuditRequest.dto.js +3 -0
- package/dist/api/dto/AuditRequest.dto.js.map +1 -0
- package/dist/api/dto/AuditResponse.dto.d.ts +17 -0
- package/dist/api/dto/AuditResponse.dto.d.ts.map +1 -0
- package/dist/api/dto/AuditResponse.dto.js +3 -0
- package/dist/api/dto/AuditResponse.dto.js.map +1 -0
- package/dist/api/dto/TokenRequest.dto.d.ts +6 -0
- package/dist/api/dto/TokenRequest.dto.d.ts.map +1 -0
- package/dist/api/dto/TokenRequest.dto.js +3 -0
- package/dist/api/dto/TokenRequest.dto.js.map +1 -0
- package/dist/api/dto/TokenResponse.dto.d.ts +12 -0
- package/dist/api/dto/TokenResponse.dto.d.ts.map +1 -0
- package/dist/api/dto/TokenResponse.dto.js +3 -0
- package/dist/api/dto/TokenResponse.dto.js.map +1 -0
- package/dist/api/middlewares/authenticate.d.ts +12 -0
- package/dist/api/middlewares/authenticate.d.ts.map +1 -0
- package/dist/api/middlewares/authenticate.js +141 -0
- package/dist/api/middlewares/authenticate.js.map +1 -0
- package/dist/api/middlewares/errorHandler.d.ts +3 -0
- package/dist/api/middlewares/errorHandler.d.ts.map +1 -0
- package/dist/api/middlewares/errorHandler.js +30 -0
- package/dist/api/middlewares/errorHandler.js.map +1 -0
- package/dist/api/middlewares/rateLimit.d.ts +3 -0
- package/dist/api/middlewares/rateLimit.d.ts.map +1 -0
- package/dist/api/middlewares/rateLimit.js +34 -0
- package/dist/api/middlewares/rateLimit.js.map +1 -0
- package/dist/api/middlewares/validate.d.ts +4 -0
- package/dist/api/middlewares/validate.d.ts.map +1 -0
- package/dist/api/middlewares/validate.js +31 -0
- package/dist/api/middlewares/validate.js.map +1 -0
- package/dist/api/routes/audit.routes.d.ts +5 -0
- package/dist/api/routes/audit.routes.d.ts.map +1 -0
- package/dist/api/routes/audit.routes.js +24 -0
- package/dist/api/routes/audit.routes.js.map +1 -0
- package/dist/api/routes/auth.routes.d.ts +6 -0
- package/dist/api/routes/auth.routes.d.ts.map +1 -0
- package/dist/api/routes/auth.routes.js +22 -0
- package/dist/api/routes/auth.routes.js.map +1 -0
- package/dist/api/routes/export.routes.d.ts +5 -0
- package/dist/api/routes/export.routes.d.ts.map +1 -0
- package/dist/api/routes/export.routes.js +16 -0
- package/dist/api/routes/export.routes.js.map +1 -0
- package/dist/api/routes/health.routes.d.ts +4 -0
- package/dist/api/routes/health.routes.d.ts.map +1 -0
- package/dist/api/routes/health.routes.js +11 -0
- package/dist/api/routes/health.routes.js.map +1 -0
- package/dist/api/routes/index.d.ts +10 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/index.js +20 -0
- package/dist/api/routes/index.js.map +1 -0
- package/dist/api/routes/providers.routes.d.ts +5 -0
- package/dist/api/routes/providers.routes.d.ts.map +1 -0
- package/dist/api/routes/providers.routes.js +13 -0
- package/dist/api/routes/providers.routes.js.map +1 -0
- package/dist/api/validators/audit.schemas.d.ts +60 -0
- package/dist/api/validators/audit.schemas.d.ts.map +1 -0
- package/dist/api/validators/audit.schemas.js +55 -0
- package/dist/api/validators/audit.schemas.js.map +1 -0
- package/dist/api/validators/auth.schemas.d.ts +17 -0
- package/dist/api/validators/auth.schemas.d.ts.map +1 -0
- package/dist/api/validators/auth.schemas.js +21 -0
- package/dist/api/validators/auth.schemas.js.map +1 -0
- package/dist/app.d.ts +3 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +62 -0
- package/dist/app.js.map +1 -0
- package/dist/config/config.schema.d.ts +65 -0
- package/dist/config/config.schema.d.ts.map +1 -0
- package/dist/config/config.schema.js +95 -0
- package/dist/config/config.schema.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +75 -0
- package/dist/config/index.js.map +1 -0
- package/dist/container.d.ts +47 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +137 -0
- package/dist/container.js.map +1 -0
- package/dist/data/database.d.ts +13 -0
- package/dist/data/database.d.ts.map +1 -0
- package/dist/data/database.js +68 -0
- package/dist/data/database.js.map +1 -0
- package/dist/data/jobs/token-cleanup.job.d.ts +23 -0
- package/dist/data/jobs/token-cleanup.job.d.ts.map +1 -0
- package/dist/data/jobs/token-cleanup.job.js +96 -0
- package/dist/data/jobs/token-cleanup.job.js.map +1 -0
- package/dist/data/migrations/migration.runner.d.ts +13 -0
- package/dist/data/migrations/migration.runner.d.ts.map +1 -0
- package/dist/data/migrations/migration.runner.js +136 -0
- package/dist/data/migrations/migration.runner.js.map +1 -0
- package/dist/data/models/Token.model.d.ts +30 -0
- package/dist/data/models/Token.model.d.ts.map +1 -0
- package/dist/data/models/Token.model.js +3 -0
- package/dist/data/models/Token.model.js.map +1 -0
- package/dist/data/repositories/token.repository.d.ts +16 -0
- package/dist/data/repositories/token.repository.d.ts.map +1 -0
- package/dist/data/repositories/token.repository.js +97 -0
- package/dist/data/repositories/token.repository.js.map +1 -0
- package/dist/providers/azure/auth.provider.d.ts +5 -0
- package/dist/providers/azure/auth.provider.d.ts.map +1 -0
- package/dist/providers/azure/auth.provider.js +13 -0
- package/dist/providers/azure/auth.provider.js.map +1 -0
- package/dist/providers/azure/azure-errors.d.ts +40 -0
- package/dist/providers/azure/azure-errors.d.ts.map +1 -0
- package/dist/providers/azure/azure-errors.js +121 -0
- package/dist/providers/azure/azure-errors.js.map +1 -0
- package/dist/providers/azure/azure-retry.d.ts +41 -0
- package/dist/providers/azure/azure-retry.d.ts.map +1 -0
- package/dist/providers/azure/azure-retry.js +85 -0
- package/dist/providers/azure/azure-retry.js.map +1 -0
- package/dist/providers/azure/graph-client.d.ts +26 -0
- package/dist/providers/azure/graph-client.d.ts.map +1 -0
- package/dist/providers/azure/graph-client.js +146 -0
- package/dist/providers/azure/graph-client.js.map +1 -0
- package/dist/providers/azure/graph.provider.d.ts +23 -0
- package/dist/providers/azure/graph.provider.d.ts.map +1 -0
- package/dist/providers/azure/graph.provider.js +161 -0
- package/dist/providers/azure/graph.provider.js.map +1 -0
- package/dist/providers/azure/queries/app.queries.d.ts +6 -0
- package/dist/providers/azure/queries/app.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/app.queries.js +9 -0
- package/dist/providers/azure/queries/app.queries.js.map +1 -0
- package/dist/providers/azure/queries/policy.queries.d.ts +6 -0
- package/dist/providers/azure/queries/policy.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/policy.queries.js +9 -0
- package/dist/providers/azure/queries/policy.queries.js.map +1 -0
- package/dist/providers/azure/queries/user.queries.d.ts +7 -0
- package/dist/providers/azure/queries/user.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/user.queries.js +10 -0
- package/dist/providers/azure/queries/user.queries.js.map +1 -0
- package/dist/providers/interfaces/IGraphProvider.d.ts +31 -0
- package/dist/providers/interfaces/IGraphProvider.d.ts.map +1 -0
- package/dist/providers/interfaces/IGraphProvider.js +3 -0
- package/dist/providers/interfaces/IGraphProvider.js.map +1 -0
- package/dist/providers/interfaces/ILDAPProvider.d.ts +37 -0
- package/dist/providers/interfaces/ILDAPProvider.d.ts.map +1 -0
- package/dist/providers/interfaces/ILDAPProvider.js +3 -0
- package/dist/providers/interfaces/ILDAPProvider.js.map +1 -0
- package/dist/providers/ldap/acl-parser.d.ts +8 -0
- package/dist/providers/ldap/acl-parser.d.ts.map +1 -0
- package/dist/providers/ldap/acl-parser.js +157 -0
- package/dist/providers/ldap/acl-parser.js.map +1 -0
- package/dist/providers/ldap/ad-mappers.d.ts +8 -0
- package/dist/providers/ldap/ad-mappers.d.ts.map +1 -0
- package/dist/providers/ldap/ad-mappers.js +162 -0
- package/dist/providers/ldap/ad-mappers.js.map +1 -0
- package/dist/providers/ldap/ldap-client.d.ts +33 -0
- package/dist/providers/ldap/ldap-client.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-client.js +195 -0
- package/dist/providers/ldap/ldap-client.js.map +1 -0
- package/dist/providers/ldap/ldap-errors.d.ts +48 -0
- package/dist/providers/ldap/ldap-errors.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-errors.js +120 -0
- package/dist/providers/ldap/ldap-errors.js.map +1 -0
- package/dist/providers/ldap/ldap-retry.d.ts +14 -0
- package/dist/providers/ldap/ldap-retry.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-retry.js +102 -0
- package/dist/providers/ldap/ldap-retry.js.map +1 -0
- package/dist/providers/ldap/ldap-sanitizer.d.ts +12 -0
- package/dist/providers/ldap/ldap-sanitizer.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-sanitizer.js +104 -0
- package/dist/providers/ldap/ldap-sanitizer.js.map +1 -0
- package/dist/providers/ldap/ldap.provider.d.ts +21 -0
- package/dist/providers/ldap/ldap.provider.d.ts.map +1 -0
- package/dist/providers/ldap/ldap.provider.js +165 -0
- package/dist/providers/ldap/ldap.provider.js.map +1 -0
- package/dist/providers/ldap/queries/computer.queries.d.ts +6 -0
- package/dist/providers/ldap/queries/computer.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/computer.queries.js +9 -0
- package/dist/providers/ldap/queries/computer.queries.js.map +1 -0
- package/dist/providers/ldap/queries/group.queries.d.ts +6 -0
- package/dist/providers/ldap/queries/group.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/group.queries.js +9 -0
- package/dist/providers/ldap/queries/group.queries.js.map +1 -0
- package/dist/providers/ldap/queries/user.queries.d.ts +7 -0
- package/dist/providers/ldap/queries/user.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/user.queries.js +10 -0
- package/dist/providers/ldap/queries/user.queries.js.map +1 -0
- package/dist/providers/smb/smb.provider.d.ts +68 -0
- package/dist/providers/smb/smb.provider.d.ts.map +1 -0
- package/dist/providers/smb/smb.provider.js +382 -0
- package/dist/providers/smb/smb.provider.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +44 -0
- package/dist/server.js.map +1 -0
- package/dist/services/audit/ad-audit.service.d.ts +70 -0
- package/dist/services/audit/ad-audit.service.d.ts.map +1 -0
- package/dist/services/audit/ad-audit.service.js +1019 -0
- package/dist/services/audit/ad-audit.service.js.map +1 -0
- package/dist/services/audit/attack-graph.service.d.ts +62 -0
- package/dist/services/audit/attack-graph.service.d.ts.map +1 -0
- package/dist/services/audit/attack-graph.service.js +702 -0
- package/dist/services/audit/attack-graph.service.js.map +1 -0
- package/dist/services/audit/audit.service.d.ts +4 -0
- package/dist/services/audit/audit.service.d.ts.map +1 -0
- package/dist/services/audit/audit.service.js +10 -0
- package/dist/services/audit/audit.service.js.map +1 -0
- package/dist/services/audit/azure-audit.service.d.ts +37 -0
- package/dist/services/audit/azure-audit.service.d.ts.map +1 -0
- package/dist/services/audit/azure-audit.service.js +153 -0
- package/dist/services/audit/azure-audit.service.js.map +1 -0
- package/dist/services/audit/detectors/ad/accounts.detector.d.ts +37 -0
- package/dist/services/audit/detectors/ad/accounts.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/accounts.detector.js +881 -0
- package/dist/services/audit/detectors/ad/accounts.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/adcs.detector.d.ts +21 -0
- package/dist/services/audit/detectors/ad/adcs.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/adcs.detector.js +227 -0
- package/dist/services/audit/detectors/ad/adcs.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/advanced.detector.d.ts +63 -0
- package/dist/services/audit/detectors/ad/advanced.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/advanced.detector.js +867 -0
- package/dist/services/audit/detectors/ad/advanced.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts +16 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.js +369 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/compliance.detector.d.ts +28 -0
- package/dist/services/audit/detectors/ad/compliance.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/compliance.detector.js +896 -0
- package/dist/services/audit/detectors/ad/compliance.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/computers.detector.d.ts +30 -0
- package/dist/services/audit/detectors/ad/computers.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/computers.detector.js +799 -0
- package/dist/services/audit/detectors/ad/computers.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/gpo.detector.d.ts +17 -0
- package/dist/services/audit/detectors/ad/gpo.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/gpo.detector.js +257 -0
- package/dist/services/audit/detectors/ad/gpo.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/groups.detector.d.ts +19 -0
- package/dist/services/audit/detectors/ad/groups.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/groups.detector.js +488 -0
- package/dist/services/audit/detectors/ad/groups.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/index.d.ts +15 -0
- package/dist/services/audit/detectors/ad/index.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/index.js +51 -0
- package/dist/services/audit/detectors/ad/index.js.map +1 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.d.ts +17 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.js +293 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.d.ts +23 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.js +328 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/network.detector.d.ts +39 -0
- package/dist/services/audit/detectors/ad/network.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/network.detector.js +257 -0
- package/dist/services/audit/detectors/ad/network.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/password.detector.d.ts +14 -0
- package/dist/services/audit/detectors/ad/password.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/password.detector.js +235 -0
- package/dist/services/audit/detectors/ad/password.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/permissions.detector.d.ts +20 -0
- package/dist/services/audit/detectors/ad/permissions.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/permissions.detector.js +392 -0
- package/dist/services/audit/detectors/ad/permissions.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/trusts.detector.d.ts +11 -0
- package/dist/services/audit/detectors/ad/trusts.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/trusts.detector.js +186 -0
- package/dist/services/audit/detectors/ad/trusts.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/app-security.detector.d.ts +11 -0
- package/dist/services/audit/detectors/azure/app-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/app-security.detector.js +184 -0
- package/dist/services/audit/detectors/azure/app-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts +10 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.js +130 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts +8 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.js +113 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/user-security.detector.d.ts +14 -0
- package/dist/services/audit/detectors/azure/user-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/user-security.detector.js +198 -0
- package/dist/services/audit/detectors/azure/user-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/index.d.ts +2 -0
- package/dist/services/audit/detectors/index.d.ts.map +1 -0
- package/dist/services/audit/detectors/index.js +38 -0
- package/dist/services/audit/detectors/index.js.map +1 -0
- package/dist/services/audit/response-formatter.d.ts +176 -0
- package/dist/services/audit/response-formatter.d.ts.map +1 -0
- package/dist/services/audit/response-formatter.js +240 -0
- package/dist/services/audit/response-formatter.js.map +1 -0
- package/dist/services/audit/scoring.service.d.ts +15 -0
- package/dist/services/audit/scoring.service.d.ts.map +1 -0
- package/dist/services/audit/scoring.service.js +139 -0
- package/dist/services/audit/scoring.service.js.map +1 -0
- package/dist/services/auth/crypto.service.d.ts +19 -0
- package/dist/services/auth/crypto.service.d.ts.map +1 -0
- package/dist/services/auth/crypto.service.js +135 -0
- package/dist/services/auth/crypto.service.js.map +1 -0
- package/dist/services/auth/errors.d.ts +19 -0
- package/dist/services/auth/errors.d.ts.map +1 -0
- package/dist/services/auth/errors.js +46 -0
- package/dist/services/auth/errors.js.map +1 -0
- package/dist/services/auth/token.service.d.ts +41 -0
- package/dist/services/auth/token.service.d.ts.map +1 -0
- package/dist/services/auth/token.service.js +208 -0
- package/dist/services/auth/token.service.js.map +1 -0
- package/dist/services/config/config.service.d.ts +6 -0
- package/dist/services/config/config.service.d.ts.map +1 -0
- package/dist/services/config/config.service.js +64 -0
- package/dist/services/config/config.service.js.map +1 -0
- package/dist/services/export/export.service.d.ts +28 -0
- package/dist/services/export/export.service.d.ts.map +1 -0
- package/dist/services/export/export.service.js +28 -0
- package/dist/services/export/export.service.js.map +1 -0
- package/dist/services/export/formatters/csv.formatter.d.ts +8 -0
- package/dist/services/export/formatters/csv.formatter.d.ts.map +1 -0
- package/dist/services/export/formatters/csv.formatter.js +46 -0
- package/dist/services/export/formatters/csv.formatter.js.map +1 -0
- package/dist/services/export/formatters/json.formatter.d.ts +40 -0
- package/dist/services/export/formatters/json.formatter.d.ts.map +1 -0
- package/dist/services/export/formatters/json.formatter.js +58 -0
- package/dist/services/export/formatters/json.formatter.js.map +1 -0
- package/dist/services/jobs/azure-job-runner.d.ts +38 -0
- package/dist/services/jobs/azure-job-runner.d.ts.map +1 -0
- package/dist/services/jobs/azure-job-runner.js +199 -0
- package/dist/services/jobs/azure-job-runner.js.map +1 -0
- package/dist/services/jobs/index.d.ts +4 -0
- package/dist/services/jobs/index.d.ts.map +1 -0
- package/dist/services/jobs/index.js +20 -0
- package/dist/services/jobs/index.js.map +1 -0
- package/dist/services/jobs/job-runner.d.ts +64 -0
- package/dist/services/jobs/job-runner.d.ts.map +1 -0
- package/dist/services/jobs/job-runner.js +952 -0
- package/dist/services/jobs/job-runner.js.map +1 -0
- package/dist/services/jobs/job-store.d.ts +27 -0
- package/dist/services/jobs/job-store.d.ts.map +1 -0
- package/dist/services/jobs/job-store.js +261 -0
- package/dist/services/jobs/job-store.js.map +1 -0
- package/dist/services/jobs/job.types.d.ts +67 -0
- package/dist/services/jobs/job.types.d.ts.map +1 -0
- package/dist/services/jobs/job.types.js +36 -0
- package/dist/services/jobs/job.types.js.map +1 -0
- package/dist/types/ad.types.d.ts +74 -0
- package/dist/types/ad.types.d.ts.map +1 -0
- package/dist/types/ad.types.js +3 -0
- package/dist/types/ad.types.js.map +1 -0
- package/dist/types/adcs.types.d.ts +58 -0
- package/dist/types/adcs.types.d.ts.map +1 -0
- package/dist/types/adcs.types.js +38 -0
- package/dist/types/adcs.types.js.map +1 -0
- package/dist/types/attack-graph.types.d.ts +135 -0
- package/dist/types/attack-graph.types.d.ts.map +1 -0
- package/dist/types/attack-graph.types.js +58 -0
- package/dist/types/attack-graph.types.js.map +1 -0
- package/dist/types/audit.types.d.ts +34 -0
- package/dist/types/audit.types.d.ts.map +1 -0
- package/dist/types/audit.types.js +3 -0
- package/dist/types/audit.types.js.map +1 -0
- package/dist/types/azure.types.d.ts +61 -0
- package/dist/types/azure.types.d.ts.map +1 -0
- package/dist/types/azure.types.js +3 -0
- package/dist/types/azure.types.js.map +1 -0
- package/dist/types/config.types.d.ts +63 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +3 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/error.types.d.ts +33 -0
- package/dist/types/error.types.d.ts.map +1 -0
- package/dist/types/error.types.js +70 -0
- package/dist/types/error.types.js.map +1 -0
- package/dist/types/finding.types.d.ts +133 -0
- package/dist/types/finding.types.d.ts.map +1 -0
- package/dist/types/finding.types.js +3 -0
- package/dist/types/finding.types.js.map +1 -0
- package/dist/types/gpo.types.d.ts +39 -0
- package/dist/types/gpo.types.d.ts.map +1 -0
- package/dist/types/gpo.types.js +15 -0
- package/dist/types/gpo.types.js.map +1 -0
- package/dist/types/token.types.d.ts +26 -0
- package/dist/types/token.types.d.ts.map +1 -0
- package/dist/types/token.types.js +3 -0
- package/dist/types/token.types.js.map +1 -0
- package/dist/types/trust.types.d.ts +45 -0
- package/dist/types/trust.types.d.ts.map +1 -0
- package/dist/types/trust.types.js +71 -0
- package/dist/types/trust.types.js.map +1 -0
- package/dist/utils/entity-converter.d.ts +17 -0
- package/dist/utils/entity-converter.d.ts.map +1 -0
- package/dist/utils/entity-converter.js +285 -0
- package/dist/utils/entity-converter.js.map +1 -0
- package/dist/utils/graph.util.d.ts +66 -0
- package/dist/utils/graph.util.d.ts.map +1 -0
- package/dist/utils/graph.util.js +382 -0
- package/dist/utils/graph.util.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/type-name-normalizer.d.ts +5 -0
- package/dist/utils/type-name-normalizer.d.ts.map +1 -0
- package/dist/utils/type-name-normalizer.js +218 -0
- package/dist/utils/type-name-normalizer.js.map +1 -0
- package/docker-compose.yml +26 -0
- package/docs/api/README.md +178 -0
- package/docs/api/openapi.yaml +1524 -0
- package/eslint.config.js +54 -0
- package/jest.config.js +38 -0
- package/package.json +97 -0
- package/scripts/fetch-ad-cert.sh +142 -0
- package/src/.gitkeep +0 -0
- package/src/api/.gitkeep +0 -0
- package/src/api/controllers/.gitkeep +0 -0
- package/src/api/controllers/audit.controller.ts +313 -0
- package/src/api/controllers/auth.controller.ts +258 -0
- package/src/api/controllers/export.controller.ts +153 -0
- package/src/api/controllers/health.controller.ts +16 -0
- package/src/api/controllers/jobs.controller.ts +187 -0
- package/src/api/controllers/providers.controller.ts +165 -0
- package/src/api/dto/.gitkeep +0 -0
- package/src/api/dto/AuditRequest.dto.ts +8 -0
- package/src/api/dto/AuditResponse.dto.ts +19 -0
- package/src/api/dto/TokenRequest.dto.ts +8 -0
- package/src/api/dto/TokenResponse.dto.ts +14 -0
- package/src/api/middlewares/.gitkeep +0 -0
- package/src/api/middlewares/authenticate.ts +203 -0
- package/src/api/middlewares/errorHandler.ts +54 -0
- package/src/api/middlewares/rateLimit.ts +35 -0
- package/src/api/middlewares/validate.ts +32 -0
- package/src/api/routes/.gitkeep +0 -0
- package/src/api/routes/audit.routes.ts +77 -0
- package/src/api/routes/auth.routes.ts +71 -0
- package/src/api/routes/export.routes.ts +34 -0
- package/src/api/routes/health.routes.ts +14 -0
- package/src/api/routes/index.ts +40 -0
- package/src/api/routes/providers.routes.ts +24 -0
- package/src/api/validators/.gitkeep +0 -0
- package/src/api/validators/audit.schemas.ts +59 -0
- package/src/api/validators/auth.schemas.ts +59 -0
- package/src/app.ts +87 -0
- package/src/config/.gitkeep +0 -0
- package/src/config/config.schema.ts +108 -0
- package/src/config/index.ts +82 -0
- package/src/container.ts +221 -0
- package/src/data/.gitkeep +0 -0
- package/src/data/database.ts +78 -0
- package/src/data/jobs/token-cleanup.job.ts +166 -0
- package/src/data/migrations/.gitkeep +0 -0
- package/src/data/migrations/001_initial_schema.sql +47 -0
- package/src/data/migrations/migration.runner.ts +125 -0
- package/src/data/models/.gitkeep +0 -0
- package/src/data/models/Token.model.ts +35 -0
- package/src/data/repositories/.gitkeep +0 -0
- package/src/data/repositories/token.repository.ts +160 -0
- package/src/providers/.gitkeep +0 -0
- package/src/providers/azure/.gitkeep +0 -0
- package/src/providers/azure/auth.provider.ts +14 -0
- package/src/providers/azure/azure-errors.ts +189 -0
- package/src/providers/azure/azure-retry.ts +168 -0
- package/src/providers/azure/graph-client.ts +315 -0
- package/src/providers/azure/graph.provider.ts +294 -0
- package/src/providers/azure/queries/app.queries.ts +9 -0
- package/src/providers/azure/queries/policy.queries.ts +9 -0
- package/src/providers/azure/queries/user.queries.ts +10 -0
- package/src/providers/interfaces/.gitkeep +0 -0
- package/src/providers/interfaces/IGraphProvider.ts +117 -0
- package/src/providers/interfaces/ILDAPProvider.ts +142 -0
- package/src/providers/ldap/.gitkeep +0 -0
- package/src/providers/ldap/acl-parser.ts +231 -0
- package/src/providers/ldap/ad-mappers.ts +280 -0
- package/src/providers/ldap/ldap-client.ts +259 -0
- package/src/providers/ldap/ldap-errors.ts +188 -0
- package/src/providers/ldap/ldap-retry.ts +267 -0
- package/src/providers/ldap/ldap-sanitizer.ts +273 -0
- package/src/providers/ldap/ldap.provider.ts +293 -0
- package/src/providers/ldap/queries/computer.queries.ts +9 -0
- package/src/providers/ldap/queries/group.queries.ts +9 -0
- package/src/providers/ldap/queries/user.queries.ts +10 -0
- package/src/providers/smb/smb.provider.ts +653 -0
- package/src/server.ts +60 -0
- package/src/services/.gitkeep +0 -0
- package/src/services/audit/.gitkeep +0 -0
- package/src/services/audit/ad-audit.service.ts +1481 -0
- package/src/services/audit/attack-graph.service.ts +1104 -0
- package/src/services/audit/audit.service.ts +12 -0
- package/src/services/audit/azure-audit.service.ts +286 -0
- package/src/services/audit/detectors/ad/accounts.detector.ts +1232 -0
- package/src/services/audit/detectors/ad/adcs.detector.ts +449 -0
- package/src/services/audit/detectors/ad/advanced.detector.ts +1270 -0
- package/src/services/audit/detectors/ad/attack-paths.detector.ts +600 -0
- package/src/services/audit/detectors/ad/compliance.detector.ts +1421 -0
- package/src/services/audit/detectors/ad/computers.detector.ts +1188 -0
- package/src/services/audit/detectors/ad/gpo.detector.ts +485 -0
- package/src/services/audit/detectors/ad/groups.detector.ts +685 -0
- package/src/services/audit/detectors/ad/index.ts +84 -0
- package/src/services/audit/detectors/ad/kerberos.detector.ts +424 -0
- package/src/services/audit/detectors/ad/monitoring.detector.ts +501 -0
- package/src/services/audit/detectors/ad/network.detector.ts +538 -0
- package/src/services/audit/detectors/ad/password.detector.ts +324 -0
- package/src/services/audit/detectors/ad/permissions.detector.ts +637 -0
- package/src/services/audit/detectors/ad/trusts.detector.ts +315 -0
- package/src/services/audit/detectors/azure/app-security.detector.ts +246 -0
- package/src/services/audit/detectors/azure/conditional-access.detector.ts +186 -0
- package/src/services/audit/detectors/azure/privilege-security.detector.ts +176 -0
- package/src/services/audit/detectors/azure/user-security.detector.ts +280 -0
- package/src/services/audit/detectors/index.ts +18 -0
- package/src/services/audit/response-formatter.ts +604 -0
- package/src/services/audit/scoring.service.ts +234 -0
- package/src/services/auth/.gitkeep +0 -0
- package/src/services/auth/crypto.service.ts +230 -0
- package/src/services/auth/errors.ts +47 -0
- package/src/services/auth/token.service.ts +420 -0
- package/src/services/config/.gitkeep +0 -0
- package/src/services/config/config.service.ts +75 -0
- package/src/services/export/.gitkeep +0 -0
- package/src/services/export/export.service.ts +99 -0
- package/src/services/export/formatters/csv.formatter.ts +124 -0
- package/src/services/export/formatters/json.formatter.ts +160 -0
- package/src/services/jobs/azure-job-runner.ts +312 -0
- package/src/services/jobs/index.ts +9 -0
- package/src/services/jobs/job-runner.ts +1280 -0
- package/src/services/jobs/job-store.ts +384 -0
- package/src/services/jobs/job.types.ts +182 -0
- package/src/types/.gitkeep +0 -0
- package/src/types/ad.types.ts +91 -0
- package/src/types/adcs.types.ts +107 -0
- package/src/types/attack-graph.types.ts +260 -0
- package/src/types/audit.types.ts +42 -0
- package/src/types/azure.types.ts +68 -0
- package/src/types/config.types.ts +79 -0
- package/src/types/error.types.ts +69 -0
- package/src/types/finding.types.ts +284 -0
- package/src/types/gpo.types.ts +72 -0
- package/src/types/smb2.d.ts +73 -0
- package/src/types/token.types.ts +32 -0
- package/src/types/trust.types.ts +140 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/entity-converter.ts +453 -0
- package/src/utils/graph.util.ts +609 -0
- package/src/utils/logger.ts +111 -0
- package/src/utils/type-name-normalizer.ts +302 -0
- package/tests/.gitkeep +0 -0
- package/tests/e2e/.gitkeep +0 -0
- package/tests/fixtures/.gitkeep +0 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/integration/README.md +156 -0
- package/tests/integration/ad-audit.integration.test.ts +216 -0
- package/tests/integration/api/.gitkeep +0 -0
- package/tests/integration/api/endpoints.integration.test.ts +431 -0
- package/tests/integration/auth/jwt-authentication.integration.test.ts +358 -0
- package/tests/integration/providers/.gitkeep +0 -0
- package/tests/integration/providers/azure-basic.integration.test.ts +167 -0
- package/tests/integration/providers/ldap-basic.integration.test.ts +152 -0
- package/tests/integration/providers/ldap-connectivity.test.ts +44 -0
- package/tests/integration/providers/ldap-provider.integration.test.ts +347 -0
- package/tests/mocks/.gitkeep +0 -0
- package/tests/setup.ts +16 -0
- package/tests/unit/.gitkeep +0 -0
- package/tests/unit/api/middlewares/authenticate.test.ts +446 -0
- package/tests/unit/providers/.gitkeep +0 -0
- package/tests/unit/providers/azure/azure-errors.test.ts +193 -0
- package/tests/unit/providers/azure/azure-retry.test.ts +254 -0
- package/tests/unit/providers/azure/graph-provider.test.ts +313 -0
- package/tests/unit/providers/ldap/ad-mappers.test.ts +392 -0
- package/tests/unit/providers/ldap/ldap-provider.test.ts +376 -0
- package/tests/unit/providers/ldap/ldap-retry.test.ts +377 -0
- package/tests/unit/providers/ldap/ldap-sanitizer.test.ts +301 -0
- package/tests/unit/sample.test.ts +19 -0
- package/tests/unit/services/.gitkeep +0 -0
- package/tests/unit/services/audit/detectors/ad/accounts.detector.test.ts +393 -0
- package/tests/unit/services/audit/detectors/ad/advanced.detector.test.ts +380 -0
- package/tests/unit/services/audit/detectors/ad/computers.detector.test.ts +440 -0
- package/tests/unit/services/audit/detectors/ad/groups.detector.test.ts +276 -0
- package/tests/unit/services/audit/detectors/ad/kerberos.detector.test.ts +215 -0
- package/tests/unit/services/audit/detectors/ad/password.detector.test.ts +226 -0
- package/tests/unit/services/audit/detectors/ad/permissions.detector.test.ts +244 -0
- package/tests/unit/services/audit/detectors/azure/app-security.detector.test.ts +349 -0
- package/tests/unit/services/audit/detectors/azure/conditional-access.detector.test.ts +374 -0
- package/tests/unit/services/audit/detectors/azure/privilege-security.detector.test.ts +374 -0
- package/tests/unit/services/audit/detectors/azure/user-security.detector.test.ts +297 -0
- package/tests/unit/services/auth/crypto.service.test.ts +296 -0
- package/tests/unit/services/auth/token.service.test.ts +579 -0
- package/tests/unit/services/export/export.service.test.ts +241 -0
- package/tests/unit/services/export/formatters/csv.formatter.test.ts +270 -0
- package/tests/unit/services/export/formatters/json.formatter.test.ts +258 -0
- package/tests/unit/utils/.gitkeep +0 -0
- package/tsconfig.json +50 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { Token, TokenCreateInput, ActiveToken } from '../models/Token.model';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Token Repository
|
|
6
|
+
* Handles CRUD operations for JWT tokens in SQLite database
|
|
7
|
+
* Uses synchronous better-sqlite3 for thread-safe operations
|
|
8
|
+
*/
|
|
9
|
+
export class TokenRepository {
|
|
10
|
+
constructor(private db: Database.Database) {}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a new token record
|
|
14
|
+
* @param input - Token creation data
|
|
15
|
+
* @returns The created token with generated ID
|
|
16
|
+
*/
|
|
17
|
+
create(input: TokenCreateInput): Token {
|
|
18
|
+
const stmt = this.db.prepare(`
|
|
19
|
+
INSERT INTO tokens (jti, public_key, expires_at, max_uses, metadata)
|
|
20
|
+
VALUES (@jti, @public_key, @expires_at, @max_uses, @metadata)
|
|
21
|
+
`);
|
|
22
|
+
|
|
23
|
+
stmt.run({
|
|
24
|
+
jti: input.jti,
|
|
25
|
+
public_key: input.public_key,
|
|
26
|
+
expires_at: input.expires_at,
|
|
27
|
+
max_uses: input.max_uses ?? 0,
|
|
28
|
+
metadata: input.metadata ?? null,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return this.findByJti(input.jti)!;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Find a token by its JTI (JWT ID)
|
|
36
|
+
* @param jti - The JWT ID to search for
|
|
37
|
+
* @returns The token if found, null otherwise
|
|
38
|
+
*/
|
|
39
|
+
findByJti(jti: string): Token | null {
|
|
40
|
+
const stmt = this.db.prepare(`
|
|
41
|
+
SELECT id, jti, public_key, created_at, expires_at, max_uses, used_count,
|
|
42
|
+
revoked_at, revoked_by, revoked_reason, metadata
|
|
43
|
+
FROM tokens
|
|
44
|
+
WHERE jti = ?
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
return (stmt.get(jti) as Token | undefined) ?? null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get all tokens (including expired and revoked)
|
|
52
|
+
* @returns Array of all tokens
|
|
53
|
+
*/
|
|
54
|
+
findAll(): Token[] {
|
|
55
|
+
const stmt = this.db.prepare(`
|
|
56
|
+
SELECT id, jti, public_key, created_at, expires_at, max_uses, used_count,
|
|
57
|
+
revoked_at, revoked_by, revoked_reason, metadata
|
|
58
|
+
FROM tokens
|
|
59
|
+
ORDER BY created_at DESC
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
return stmt.all() as Token[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get all active tokens (not expired, not revoked, within usage limits)
|
|
67
|
+
* Uses the v_active_tokens view for optimized query
|
|
68
|
+
* @returns Array of active tokens with remaining_uses calculated
|
|
69
|
+
*/
|
|
70
|
+
findActive(): ActiveToken[] {
|
|
71
|
+
const stmt = this.db.prepare(`
|
|
72
|
+
SELECT id, jti, created_at, expires_at, max_uses, used_count, remaining_uses
|
|
73
|
+
FROM v_active_tokens
|
|
74
|
+
ORDER BY created_at DESC
|
|
75
|
+
`);
|
|
76
|
+
|
|
77
|
+
return stmt.all() as ActiveToken[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Increment the usage count for a token
|
|
82
|
+
* @param jti - The JWT ID of the token to increment
|
|
83
|
+
* @throws Error if token not found or usage limit exceeded
|
|
84
|
+
*/
|
|
85
|
+
incrementUsage(jti: string): void {
|
|
86
|
+
const stmt = this.db.prepare(`
|
|
87
|
+
UPDATE tokens
|
|
88
|
+
SET used_count = used_count + 1
|
|
89
|
+
WHERE jti = ?
|
|
90
|
+
AND (max_uses = 0 OR used_count < max_uses)
|
|
91
|
+
AND revoked_at IS NULL
|
|
92
|
+
AND datetime(expires_at) > datetime('now')
|
|
93
|
+
`);
|
|
94
|
+
|
|
95
|
+
const result = stmt.run(jti);
|
|
96
|
+
|
|
97
|
+
if (result.changes === 0) {
|
|
98
|
+
throw new Error(`Token not found, expired, revoked, or usage limit exceeded: ${jti}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Revoke a token, making it unusable
|
|
104
|
+
* @param jti - The JWT ID to revoke
|
|
105
|
+
* @param revokedBy - Identifier of who revoked the token
|
|
106
|
+
* @param reason - Reason for revocation
|
|
107
|
+
* @throws Error if token not found or already revoked
|
|
108
|
+
*/
|
|
109
|
+
revoke(jti: string, revokedBy: string, reason: string): void {
|
|
110
|
+
const stmt = this.db.prepare(`
|
|
111
|
+
UPDATE tokens
|
|
112
|
+
SET revoked_at = datetime('now'),
|
|
113
|
+
revoked_by = ?,
|
|
114
|
+
revoked_reason = ?
|
|
115
|
+
WHERE jti = ?
|
|
116
|
+
AND revoked_at IS NULL
|
|
117
|
+
`);
|
|
118
|
+
|
|
119
|
+
const result = stmt.run(revokedBy, reason, jti);
|
|
120
|
+
|
|
121
|
+
if (result.changes === 0) {
|
|
122
|
+
throw new Error(`Token not found or already revoked: ${jti}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Delete all expired tokens from the database
|
|
128
|
+
* Used for cleanup operations
|
|
129
|
+
* @returns Number of tokens deleted
|
|
130
|
+
*/
|
|
131
|
+
deleteExpired(): number {
|
|
132
|
+
const stmt = this.db.prepare(`
|
|
133
|
+
DELETE FROM tokens
|
|
134
|
+
WHERE datetime(expires_at) <= datetime('now')
|
|
135
|
+
`);
|
|
136
|
+
|
|
137
|
+
const result = stmt.run();
|
|
138
|
+
return result.changes;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Count total number of tokens
|
|
143
|
+
* @returns Total token count
|
|
144
|
+
*/
|
|
145
|
+
count(): number {
|
|
146
|
+
const stmt = this.db.prepare('SELECT COUNT(*) as count FROM tokens');
|
|
147
|
+
const result = stmt.get() as { count: number };
|
|
148
|
+
return result.count;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Count number of active tokens
|
|
153
|
+
* @returns Active token count
|
|
154
|
+
*/
|
|
155
|
+
countActive(): number {
|
|
156
|
+
const stmt = this.db.prepare('SELECT COUNT(*) as count FROM v_active_tokens');
|
|
157
|
+
const result = stmt.get() as { count: number };
|
|
158
|
+
return result.count;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure OAuth 2.0 Authentication Provider
|
|
3
|
+
* Handles client credentials flow
|
|
4
|
+
* TODO: Full implementation in Story 1.6
|
|
5
|
+
*/
|
|
6
|
+
export class AzureAuthProvider {
|
|
7
|
+
async getAccessToken(): Promise<string> {
|
|
8
|
+
throw new Error('Azure auth token not implemented yet');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async refreshToken(): Promise<string> {
|
|
12
|
+
throw new Error('Azure token refresh not implemented yet');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure Error Types
|
|
3
|
+
*
|
|
4
|
+
* Custom error classes for Microsoft Graph / Azure AD operations.
|
|
5
|
+
* Provides specific error types for different failure scenarios.
|
|
6
|
+
*
|
|
7
|
+
* Task 2: Create Error Types for Azure Operations (Story 1.6)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base Azure Error
|
|
12
|
+
*
|
|
13
|
+
* Base class for all Azure/Microsoft Graph-related errors.
|
|
14
|
+
*/
|
|
15
|
+
export class AzureError extends Error {
|
|
16
|
+
constructor(message: string) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'AzureError';
|
|
19
|
+
Object.setPrototypeOf(this, AzureError.prototype);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Azure Authentication Error
|
|
25
|
+
*
|
|
26
|
+
* Thrown when OAuth 2.0 authentication fails.
|
|
27
|
+
*/
|
|
28
|
+
export class AzureAuthenticationError extends AzureError {
|
|
29
|
+
public readonly tenantId: string;
|
|
30
|
+
public readonly clientId: string;
|
|
31
|
+
public override readonly cause?: Error;
|
|
32
|
+
|
|
33
|
+
constructor(message: string, tenantId: string, clientId: string, cause?: Error) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = 'AzureAuthenticationError';
|
|
36
|
+
this.tenantId = tenantId;
|
|
37
|
+
this.clientId = clientId;
|
|
38
|
+
this.cause = cause;
|
|
39
|
+
Object.setPrototypeOf(this, AzureAuthenticationError.prototype);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Azure API Error
|
|
45
|
+
*
|
|
46
|
+
* Thrown when Microsoft Graph API request fails.
|
|
47
|
+
*/
|
|
48
|
+
export class AzureAPIError extends AzureError {
|
|
49
|
+
public readonly statusCode?: number;
|
|
50
|
+
public readonly endpoint: string;
|
|
51
|
+
public override readonly cause?: Error;
|
|
52
|
+
|
|
53
|
+
constructor(message: string, endpoint: string, statusCode?: number, cause?: Error) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = 'AzureAPIError';
|
|
56
|
+
this.endpoint = endpoint;
|
|
57
|
+
this.statusCode = statusCode;
|
|
58
|
+
this.cause = cause;
|
|
59
|
+
Object.setPrototypeOf(this, AzureAPIError.prototype);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Azure Rate Limit Error
|
|
65
|
+
*
|
|
66
|
+
* Thrown when Graph API rate limit (429) is exceeded.
|
|
67
|
+
*/
|
|
68
|
+
export class AzureRateLimitError extends AzureError {
|
|
69
|
+
public readonly retryAfter: number; // seconds
|
|
70
|
+
public readonly endpoint: string;
|
|
71
|
+
|
|
72
|
+
constructor(message: string, endpoint: string, retryAfter: number) {
|
|
73
|
+
super(message);
|
|
74
|
+
this.name = 'AzureRateLimitError';
|
|
75
|
+
this.endpoint = endpoint;
|
|
76
|
+
this.retryAfter = retryAfter;
|
|
77
|
+
Object.setPrototypeOf(this, AzureRateLimitError.prototype);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Azure Timeout Error
|
|
83
|
+
*
|
|
84
|
+
* Thrown when Graph API request times out.
|
|
85
|
+
*/
|
|
86
|
+
export class AzureTimeoutError extends AzureError {
|
|
87
|
+
public readonly operation: string;
|
|
88
|
+
public readonly timeoutMs: number;
|
|
89
|
+
|
|
90
|
+
constructor(message: string, operation: string, timeoutMs: number) {
|
|
91
|
+
super(message);
|
|
92
|
+
this.name = 'AzureTimeoutError';
|
|
93
|
+
this.operation = operation;
|
|
94
|
+
this.timeoutMs = timeoutMs;
|
|
95
|
+
Object.setPrototypeOf(this, AzureTimeoutError.prototype);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Azure Permission Error
|
|
101
|
+
*
|
|
102
|
+
* Thrown when application doesn't have required permissions.
|
|
103
|
+
*/
|
|
104
|
+
export class AzurePermissionError extends AzureError {
|
|
105
|
+
public readonly requiredPermissions: string[];
|
|
106
|
+
public readonly endpoint: string;
|
|
107
|
+
|
|
108
|
+
constructor(message: string, endpoint: string, requiredPermissions: string[]) {
|
|
109
|
+
super(message);
|
|
110
|
+
this.name = 'AzurePermissionError';
|
|
111
|
+
this.endpoint = endpoint;
|
|
112
|
+
this.requiredPermissions = requiredPermissions;
|
|
113
|
+
Object.setPrototypeOf(this, AzurePermissionError.prototype);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Azure Configuration Error
|
|
119
|
+
*
|
|
120
|
+
* Thrown when Azure configuration is invalid or missing.
|
|
121
|
+
*/
|
|
122
|
+
export class AzureConfigurationError extends AzureError {
|
|
123
|
+
public readonly configKey: string;
|
|
124
|
+
|
|
125
|
+
constructor(message: string, configKey: string) {
|
|
126
|
+
super(message);
|
|
127
|
+
this.name = 'AzureConfigurationError';
|
|
128
|
+
this.configKey = configKey;
|
|
129
|
+
Object.setPrototypeOf(this, AzureConfigurationError.prototype);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Azure Token Expired Error
|
|
135
|
+
*
|
|
136
|
+
* Thrown when access token has expired and needs refresh.
|
|
137
|
+
*/
|
|
138
|
+
export class AzureTokenExpiredError extends AzureError {
|
|
139
|
+
public readonly expiresAt: Date;
|
|
140
|
+
|
|
141
|
+
constructor(message: string, expiresAt: Date) {
|
|
142
|
+
super(message);
|
|
143
|
+
this.name = 'AzureTokenExpiredError';
|
|
144
|
+
this.expiresAt = expiresAt;
|
|
145
|
+
Object.setPrototypeOf(this, AzureTokenExpiredError.prototype);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Check if an error is retryable
|
|
151
|
+
*
|
|
152
|
+
* Determines if an Azure operation should be retried based on error type.
|
|
153
|
+
* Rate limit errors (429) and transient network errors are retryable.
|
|
154
|
+
*
|
|
155
|
+
* @param error - The error to check
|
|
156
|
+
* @returns True if the error is retryable
|
|
157
|
+
*/
|
|
158
|
+
export function isRetryableError(error: Error): boolean {
|
|
159
|
+
// Rate limit errors are retryable with delay
|
|
160
|
+
if (error instanceof AzureRateLimitError) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Timeout errors are retryable
|
|
165
|
+
if (error instanceof AzureTimeoutError) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// API errors with certain status codes are retryable
|
|
170
|
+
if (error instanceof AzureAPIError) {
|
|
171
|
+
const retryableStatusCodes = [429, 500, 502, 503, 504];
|
|
172
|
+
return error.statusCode ? retryableStatusCodes.includes(error.statusCode) : false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Network errors (ECONNREFUSED, ETIMEDOUT, etc.) are retryable
|
|
176
|
+
if ('code' in error) {
|
|
177
|
+
const networkErrorCodes = [
|
|
178
|
+
'ECONNREFUSED',
|
|
179
|
+
'ECONNRESET',
|
|
180
|
+
'ETIMEDOUT',
|
|
181
|
+
'ENOTFOUND',
|
|
182
|
+
'ENETUNREACH',
|
|
183
|
+
'EHOSTUNREACH',
|
|
184
|
+
];
|
|
185
|
+
return networkErrorCodes.includes((error as { code: string }).code);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure Retry Logic
|
|
3
|
+
*
|
|
4
|
+
* Provides retry functionality for Azure/Microsoft Graph API operations.
|
|
5
|
+
* Implements exponential backoff with jitter and special handling for rate limits (429).
|
|
6
|
+
*
|
|
7
|
+
* Task 5: Add retry logic with exponential backoff (Story 1.6)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { AzureRateLimitError, isRetryableError } from './azure-errors';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Retry options
|
|
14
|
+
*/
|
|
15
|
+
export interface RetryOptions {
|
|
16
|
+
maxAttempts?: number; // default: 3
|
|
17
|
+
initialDelay?: number; // milliseconds, default: 1000
|
|
18
|
+
maxDelay?: number; // milliseconds, default: 30000
|
|
19
|
+
backoffMultiplier?: number; // default: 2
|
|
20
|
+
jitterPercent?: number; // 0-100, default: 10
|
|
21
|
+
onRetry?: (error: Error, attempt: number, delay: number) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Sleep for specified milliseconds
|
|
26
|
+
*
|
|
27
|
+
* @param ms - Milliseconds to sleep
|
|
28
|
+
*/
|
|
29
|
+
function sleep(ms: number): Promise<void> {
|
|
30
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Calculate delay with exponential backoff and jitter
|
|
35
|
+
*
|
|
36
|
+
* @param attempt - Current attempt number (0-based)
|
|
37
|
+
* @param options - Retry options
|
|
38
|
+
* @returns Delay in milliseconds
|
|
39
|
+
*/
|
|
40
|
+
export function calculateDelay(attempt: number, options: Required<RetryOptions>): number {
|
|
41
|
+
// Exponential backoff: initialDelay * (multiplier ^ attempt)
|
|
42
|
+
const exponentialDelay = options.initialDelay * Math.pow(options.backoffMultiplier, attempt);
|
|
43
|
+
|
|
44
|
+
// Cap at maxDelay
|
|
45
|
+
const cappedDelay = Math.min(exponentialDelay, options.maxDelay);
|
|
46
|
+
|
|
47
|
+
// Add jitter to prevent thundering herd
|
|
48
|
+
// Jitter is random value between [0, jitterPercent% of delay]
|
|
49
|
+
const jitterAmount = cappedDelay * (options.jitterPercent / 100);
|
|
50
|
+
const jitter = Math.random() * jitterAmount;
|
|
51
|
+
|
|
52
|
+
return Math.round(cappedDelay + jitter);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Retry an async operation with exponential backoff
|
|
57
|
+
*
|
|
58
|
+
* @param operation - Async operation to retry
|
|
59
|
+
* @param options - Retry options
|
|
60
|
+
* @returns Result of the operation
|
|
61
|
+
* @throws Last error if all retries fail
|
|
62
|
+
*/
|
|
63
|
+
export async function retryWithBackoff<T>(
|
|
64
|
+
operation: () => Promise<T>,
|
|
65
|
+
options: RetryOptions = {}
|
|
66
|
+
): Promise<T> {
|
|
67
|
+
const opts: Required<RetryOptions> = {
|
|
68
|
+
maxAttempts: options.maxAttempts ?? 3,
|
|
69
|
+
initialDelay: options.initialDelay ?? 1000,
|
|
70
|
+
maxDelay: options.maxDelay ?? 30000,
|
|
71
|
+
backoffMultiplier: options.backoffMultiplier ?? 2,
|
|
72
|
+
jitterPercent: options.jitterPercent ?? 10,
|
|
73
|
+
onRetry: options.onRetry ?? (() => {}),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
let attempt = 0;
|
|
77
|
+
let lastError: Error | undefined;
|
|
78
|
+
|
|
79
|
+
while (attempt < opts.maxAttempts) {
|
|
80
|
+
try {
|
|
81
|
+
return await operation();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
84
|
+
|
|
85
|
+
const isLastAttempt = attempt === opts.maxAttempts - 1;
|
|
86
|
+
|
|
87
|
+
// Don't retry if it's the last attempt
|
|
88
|
+
if (isLastAttempt) {
|
|
89
|
+
throw lastError;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if error is retryable
|
|
93
|
+
if (!isRetryableError(lastError)) {
|
|
94
|
+
throw lastError;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// For rate limit errors, use the retry-after value
|
|
98
|
+
let delay: number;
|
|
99
|
+
if (lastError instanceof AzureRateLimitError) {
|
|
100
|
+
// Use the retry-after value from the error (in seconds)
|
|
101
|
+
delay = lastError.retryAfter * 1000; // convert to ms
|
|
102
|
+
} else {
|
|
103
|
+
// Calculate delay with exponential backoff
|
|
104
|
+
delay = calculateDelay(attempt, opts);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Call retry callback
|
|
108
|
+
opts.onRetry(lastError, attempt, delay);
|
|
109
|
+
|
|
110
|
+
// Wait before retrying
|
|
111
|
+
await sleep(delay);
|
|
112
|
+
|
|
113
|
+
attempt++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// This should never happen, but TypeScript doesn't know that
|
|
118
|
+
throw lastError || new Error('Retry failed with unknown error');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Retry configuration for different scenarios
|
|
123
|
+
*/
|
|
124
|
+
export const AZURE_RETRY_CONFIGS = {
|
|
125
|
+
/**
|
|
126
|
+
* Default retry config for most operations
|
|
127
|
+
*/
|
|
128
|
+
default: {
|
|
129
|
+
maxAttempts: 3,
|
|
130
|
+
initialDelay: 1000, // 1 second
|
|
131
|
+
maxDelay: 30000, // 30 seconds
|
|
132
|
+
backoffMultiplier: 2,
|
|
133
|
+
jitterPercent: 10,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Aggressive retry config for operations that are likely to succeed quickly
|
|
138
|
+
*/
|
|
139
|
+
aggressive: {
|
|
140
|
+
maxAttempts: 5,
|
|
141
|
+
initialDelay: 500, // 0.5 seconds
|
|
142
|
+
maxDelay: 15000, // 15 seconds
|
|
143
|
+
backoffMultiplier: 1.5,
|
|
144
|
+
jitterPercent: 15,
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Conservative retry config for expensive operations
|
|
149
|
+
*/
|
|
150
|
+
conservative: {
|
|
151
|
+
maxAttempts: 2,
|
|
152
|
+
initialDelay: 2000, // 2 seconds
|
|
153
|
+
maxDelay: 60000, // 60 seconds
|
|
154
|
+
backoffMultiplier: 3,
|
|
155
|
+
jitterPercent: 5,
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Rate limit retry config - respects rate limit headers
|
|
160
|
+
*/
|
|
161
|
+
rateLimit: {
|
|
162
|
+
maxAttempts: 3,
|
|
163
|
+
initialDelay: 60000, // 60 seconds (default if no retry-after header)
|
|
164
|
+
maxDelay: 300000, // 5 minutes
|
|
165
|
+
backoffMultiplier: 1, // Don't use exponential backoff for rate limits
|
|
166
|
+
jitterPercent: 0, // No jitter for rate limits (use exact retry-after)
|
|
167
|
+
},
|
|
168
|
+
} as const;
|