couchloop-eq-mcp 1.0.4 → 1.1.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/README.md +24 -11
- package/dist/developer/analyzers/bloat-detector.d.ts +89 -0
- package/dist/developer/analyzers/bloat-detector.d.ts.map +1 -0
- package/dist/developer/analyzers/bloat-detector.js +483 -0
- package/dist/developer/analyzers/bloat-detector.js.map +1 -0
- package/dist/developer/backup/auto-backup.d.ts +96 -0
- package/dist/developer/backup/auto-backup.d.ts.map +1 -0
- package/dist/developer/backup/auto-backup.js +346 -0
- package/dist/developer/backup/auto-backup.js.map +1 -0
- package/dist/developer/blockers/package-blocker.d.ts +33 -0
- package/dist/developer/blockers/package-blocker.d.ts.map +1 -0
- package/dist/developer/blockers/package-blocker.js +224 -0
- package/dist/developer/blockers/package-blocker.js.map +1 -0
- package/dist/developer/evaluators/ai-error-preventer.d.ts +54 -0
- package/dist/developer/evaluators/ai-error-preventer.d.ts.map +1 -0
- package/dist/developer/evaluators/ai-error-preventer.js +270 -0
- package/dist/developer/evaluators/ai-error-preventer.js.map +1 -0
- package/dist/developer/evaluators/build-context-detector.d.ts +44 -0
- package/dist/developer/evaluators/build-context-detector.d.ts.map +1 -0
- package/dist/developer/evaluators/build-context-detector.js +258 -0
- package/dist/developer/evaluators/build-context-detector.js.map +1 -0
- package/dist/developer/evaluators/package-evaluator.d.ts +37 -0
- package/dist/developer/evaluators/package-evaluator.d.ts.map +1 -0
- package/dist/developer/evaluators/package-evaluator.js +278 -0
- package/dist/developer/evaluators/package-evaluator.js.map +1 -0
- package/dist/developer/guards/file-guardian.d.ts +79 -0
- package/dist/developer/guards/file-guardian.d.ts.map +1 -0
- package/dist/developer/guards/file-guardian.js +309 -0
- package/dist/developer/guards/file-guardian.js.map +1 -0
- package/dist/developer/managers/context-manager.d.ts +61 -0
- package/dist/developer/managers/context-manager.d.ts.map +1 -0
- package/dist/developer/managers/context-manager.js +302 -0
- package/dist/developer/managers/context-manager.js.map +1 -0
- package/dist/developer/metrics/complexity-calculator.d.ts +52 -0
- package/dist/developer/metrics/complexity-calculator.d.ts.map +1 -0
- package/dist/developer/metrics/complexity-calculator.js +259 -0
- package/dist/developer/metrics/complexity-calculator.js.map +1 -0
- package/dist/developer/reports/review-summary.d.ts +49 -0
- package/dist/developer/reports/review-summary.d.ts.map +1 -0
- package/dist/developer/reports/review-summary.js +249 -0
- package/dist/developer/reports/review-summary.js.map +1 -0
- package/dist/developer/scanners/review-assistant.d.ts +41 -0
- package/dist/developer/scanners/review-assistant.d.ts.map +1 -0
- package/dist/developer/scanners/review-assistant.js +374 -0
- package/dist/developer/scanners/review-assistant.js.map +1 -0
- package/dist/developer/scanners/secret-scanner.d.ts +66 -0
- package/dist/developer/scanners/secret-scanner.d.ts.map +1 -0
- package/dist/developer/scanners/secret-scanner.js +287 -0
- package/dist/developer/scanners/secret-scanner.js.map +1 -0
- package/dist/developer/scanners/sql-injection-detector.d.ts +54 -0
- package/dist/developer/scanners/sql-injection-detector.d.ts.map +1 -0
- package/dist/developer/scanners/sql-injection-detector.js +174 -0
- package/dist/developer/scanners/sql-injection-detector.js.map +1 -0
- package/dist/developer/scanners/xss-detector.d.ts +60 -0
- package/dist/developer/scanners/xss-detector.d.ts.map +1 -0
- package/dist/developer/scanners/xss-detector.js +229 -0
- package/dist/developer/scanners/xss-detector.js.map +1 -0
- package/dist/developer/types/ai-errors.d.ts +34 -0
- package/dist/developer/types/ai-errors.d.ts.map +1 -0
- package/dist/developer/types/ai-errors.js +271 -0
- package/dist/developer/types/ai-errors.js.map +1 -0
- package/dist/developer/types/package.d.ts +32 -0
- package/dist/developer/types/package.d.ts.map +1 -0
- package/dist/developer/types/package.js +5 -0
- package/dist/developer/types/package.js.map +1 -0
- package/dist/developer/updaters/dependency-updater.d.ts +102 -0
- package/dist/developer/updaters/dependency-updater.d.ts.map +1 -0
- package/dist/developer/updaters/dependency-updater.js +472 -0
- package/dist/developer/updaters/dependency-updater.js.map +1 -0
- package/dist/developer/validators/cargo.d.ts +14 -0
- package/dist/developer/validators/cargo.d.ts.map +1 -0
- package/dist/developer/validators/cargo.js +132 -0
- package/dist/developer/validators/cargo.js.map +1 -0
- package/dist/developer/validators/gem.d.ts +14 -0
- package/dist/developer/validators/gem.d.ts.map +1 -0
- package/dist/developer/validators/gem.js +85 -0
- package/dist/developer/validators/gem.js.map +1 -0
- package/dist/developer/validators/go.d.ts +14 -0
- package/dist/developer/validators/go.d.ts.map +1 -0
- package/dist/developer/validators/go.js +138 -0
- package/dist/developer/validators/go.js.map +1 -0
- package/dist/developer/validators/maven.d.ts +14 -0
- package/dist/developer/validators/maven.d.ts.map +1 -0
- package/dist/developer/validators/maven.js +99 -0
- package/dist/developer/validators/maven.js.map +1 -0
- package/dist/developer/validators/npm.d.ts +14 -0
- package/dist/developer/validators/npm.d.ts.map +1 -0
- package/dist/developer/validators/npm.js +96 -0
- package/dist/developer/validators/npm.js.map +1 -0
- package/dist/developer/validators/nuget.d.ts +15 -0
- package/dist/developer/validators/nuget.d.ts.map +1 -0
- package/dist/developer/validators/nuget.js +107 -0
- package/dist/developer/validators/nuget.js.map +1 -0
- package/dist/developer/validators/pypi.d.ts +14 -0
- package/dist/developer/validators/pypi.d.ts.map +1 -0
- package/dist/developer/validators/pypi.js +118 -0
- package/dist/developer/validators/pypi.js.map +1 -0
- package/dist/developer/validators/registry-manager.d.ts +37 -0
- package/dist/developer/validators/registry-manager.d.ts.map +1 -0
- package/dist/developer/validators/registry-manager.js +89 -0
- package/dist/developer/validators/registry-manager.js.map +1 -0
- package/dist/developer/validators/version-checker.d.ts +145 -0
- package/dist/developer/validators/version-checker.d.ts.map +1 -0
- package/dist/developer/validators/version-checker.js +529 -0
- package/dist/developer/validators/version-checker.js.map +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/middleware/auth.d.ts +7 -9
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/middleware/auth.js.map +1 -1
- package/dist/tools/check-versions.d.ts +100 -0
- package/dist/tools/check-versions.d.ts.map +1 -0
- package/dist/tools/check-versions.js +328 -0
- package/dist/tools/check-versions.js.map +1 -0
- package/dist/tools/detect-code-smell.d.ts +9 -0
- package/dist/tools/detect-code-smell.d.ts.map +1 -0
- package/dist/tools/detect-code-smell.js +231 -0
- package/dist/tools/detect-code-smell.js.map +1 -0
- package/dist/tools/index.d.ts +471 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +178 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/journey.js +1 -1
- package/dist/tools/journey.js.map +1 -1
- package/dist/tools/pre-review-code.d.ts +71 -0
- package/dist/tools/pre-review-code.d.ts.map +1 -0
- package/dist/tools/pre-review-code.js +159 -0
- package/dist/tools/pre-review-code.js.map +1 -0
- package/dist/tools/preserve-context.d.ts +27 -0
- package/dist/tools/preserve-context.d.ts.map +1 -0
- package/dist/tools/preserve-context.js +98 -0
- package/dist/tools/preserve-context.js.map +1 -0
- package/dist/tools/protect-files.d.ts +224 -0
- package/dist/tools/protect-files.d.ts.map +1 -0
- package/dist/tools/protect-files.js +286 -0
- package/dist/tools/protect-files.js.map +1 -0
- package/dist/tools/scan-security.d.ts +38 -0
- package/dist/tools/scan-security.d.ts.map +1 -0
- package/dist/tools/scan-security.js +237 -0
- package/dist/tools/scan-security.js.map +1 -0
- package/dist/tools/validate_packages.d.ts +8 -0
- package/dist/tools/validate_packages.d.ts.map +1 -0
- package/dist/tools/validate_packages.js +159 -0
- package/dist/tools/validate_packages.js.map +1 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +1 -2
- package/dist/types/auth.js.map +1 -1
- package/dist/types/context.d.ts +46 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +17 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/file-protection.d.ts +50 -0
- package/dist/types/file-protection.d.ts.map +1 -0
- package/dist/types/file-protection.js +9 -0
- package/dist/types/file-protection.js.map +1 -0
- package/dist/utils/errorHandler.d.ts.map +1 -1
- package/dist/utils/errorHandler.js +2 -1
- package/dist/utils/errorHandler.js.map +1 -1
- package/package.json +30 -4
- package/dist/db/migrate.d.ts +0 -4
- package/dist/db/migrate.d.ts.map +0 -1
- package/dist/db/migrate.js +0 -34
- package/dist/db/migrate.js.map +0 -1
- package/dist/db/migrations/schema.d.ts +0 -1074
- package/dist/db/migrations/schema.d.ts.map +0 -1
- package/dist/db/migrations/schema.js +0 -160
- package/dist/db/migrations/schema.js.map +0 -1
- package/dist/db/schema.d.ts +0 -1576
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/db/schema.js +0 -204
- package/dist/db/schema.js.map +0 -1
- package/dist/db/seed.d.ts +0 -4
- package/dist/db/seed.d.ts.map +0 -1
- package/dist/db/seed.js +0 -57
- package/dist/db/seed.js.map +0 -1
- package/dist/db/seedOAuth.d.ts +0 -4
- package/dist/db/seedOAuth.d.ts.map +0 -1
- package/dist/db/seedOAuth.js +0 -76
- package/dist/db/seedOAuth.js.map +0 -1
- package/dist/governance/config.d.ts +0 -66
- package/dist/governance/config.d.ts.map +0 -1
- package/dist/governance/config.js +0 -238
- package/dist/governance/config.js.map +0 -1
- package/dist/governance/detectors/hallucination.d.ts +0 -61
- package/dist/governance/detectors/hallucination.d.ts.map +0 -1
- package/dist/governance/detectors/hallucination.js +0 -338
- package/dist/governance/detectors/hallucination.js.map +0 -1
- package/dist/governance/detectors/inconsistency.d.ts +0 -99
- package/dist/governance/detectors/inconsistency.d.ts.map +0 -1
- package/dist/governance/detectors/inconsistency.js +0 -548
- package/dist/governance/detectors/inconsistency.js.map +0 -1
- package/dist/governance/detectors/toneDrift.d.ts +0 -63
- package/dist/governance/detectors/toneDrift.d.ts.map +0 -1
- package/dist/governance/detectors/toneDrift.js +0 -421
- package/dist/governance/detectors/toneDrift.js.map +0 -1
- package/dist/governance/detectors/unsafeReasoning.d.ts +0 -54
- package/dist/governance/detectors/unsafeReasoning.d.ts.map +0 -1
- package/dist/governance/detectors/unsafeReasoning.js +0 -473
- package/dist/governance/detectors/unsafeReasoning.js.map +0 -1
- package/dist/governance/evaluationEngine.d.ts +0 -112
- package/dist/governance/evaluationEngine.d.ts.map +0 -1
- package/dist/governance/evaluationEngine.js +0 -265
- package/dist/governance/evaluationEngine.js.map +0 -1
- package/dist/governance/intervention.d.ts +0 -81
- package/dist/governance/intervention.d.ts.map +0 -1
- package/dist/governance/intervention.js +0 -405
- package/dist/governance/intervention.js.map +0 -1
- package/dist/server/oauth/anomalyDetection.d.ts +0 -146
- package/dist/server/oauth/anomalyDetection.d.ts.map +0 -1
- package/dist/server/oauth/anomalyDetection.js +0 -405
- package/dist/server/oauth/anomalyDetection.js.map +0 -1
- package/dist/server/oauth/authServer.d.ts +0 -61
- package/dist/server/oauth/authServer.d.ts.map +0 -1
- package/dist/server/oauth/authServer.js +0 -283
- package/dist/server/oauth/authServer.js.map +0 -1
- package/dist/server/oauth/dpop.d.ts +0 -135
- package/dist/server/oauth/dpop.d.ts.map +0 -1
- package/dist/server/oauth/dpop.js +0 -338
- package/dist/server/oauth/dpop.js.map +0 -1
- package/dist/server/oauth/gdpr/consent.d.ts +0 -173
- package/dist/server/oauth/gdpr/consent.d.ts.map +0 -1
- package/dist/server/oauth/gdpr/consent.js +0 -388
- package/dist/server/oauth/gdpr/consent.js.map +0 -1
- package/dist/server/oauth/gdpr/dataPortability.d.ts +0 -214
- package/dist/server/oauth/gdpr/dataPortability.d.ts.map +0 -1
- package/dist/server/oauth/gdpr/dataPortability.js +0 -486
- package/dist/server/oauth/gdpr/dataPortability.js.map +0 -1
- package/dist/server/oauth/gdpr/index.d.ts +0 -103
- package/dist/server/oauth/gdpr/index.d.ts.map +0 -1
- package/dist/server/oauth/gdpr/index.js +0 -273
- package/dist/server/oauth/gdpr/index.js.map +0 -1
- package/dist/server/oauth/gdpr/rightToErasure.d.ts +0 -184
- package/dist/server/oauth/gdpr/rightToErasure.d.ts.map +0 -1
- package/dist/server/oauth/gdpr/rightToErasure.js +0 -527
- package/dist/server/oauth/gdpr/rightToErasure.js.map +0 -1
- package/dist/server/oauth/monitoring/securityMonitor.d.ts +0 -218
- package/dist/server/oauth/monitoring/securityMonitor.d.ts.map +0 -1
- package/dist/server/oauth/monitoring/securityMonitor.js +0 -615
- package/dist/server/oauth/monitoring/securityMonitor.js.map +0 -1
- package/dist/server/oauth/pkce.d.ts +0 -61
- package/dist/server/oauth/pkce.d.ts.map +0 -1
- package/dist/server/oauth/pkce.js +0 -157
- package/dist/server/oauth/pkce.js.map +0 -1
- package/dist/server/oauth/providers/base.d.ts +0 -147
- package/dist/server/oauth/providers/base.d.ts.map +0 -1
- package/dist/server/oauth/providers/base.js +0 -312
- package/dist/server/oauth/providers/base.js.map +0 -1
- package/dist/server/oauth/providers/github.d.ts +0 -55
- package/dist/server/oauth/providers/github.d.ts.map +0 -1
- package/dist/server/oauth/providers/github.js +0 -225
- package/dist/server/oauth/providers/github.js.map +0 -1
- package/dist/server/oauth/providers/google.d.ts +0 -49
- package/dist/server/oauth/providers/google.d.ts.map +0 -1
- package/dist/server/oauth/providers/google.js +0 -153
- package/dist/server/oauth/providers/google.js.map +0 -1
- package/dist/server/oauth/providers/index.d.ts +0 -9
- package/dist/server/oauth/providers/index.d.ts.map +0 -1
- package/dist/server/oauth/providers/index.js +0 -24
- package/dist/server/oauth/providers/index.js.map +0 -1
- package/dist/server/oauth/refreshTokenRotation.d.ts +0 -114
- package/dist/server/oauth/refreshTokenRotation.d.ts.map +0 -1
- package/dist/server/oauth/refreshTokenRotation.js +0 -344
- package/dist/server/oauth/refreshTokenRotation.js.map +0 -1
- package/dist/server/oauth/security.d.ts +0 -101
- package/dist/server/oauth/security.d.ts.map +0 -1
- package/dist/server/oauth/security.js +0 -268
- package/dist/server/oauth/security.js.map +0 -1
- package/dist/server/oauth/tokenEncryption.d.ts +0 -80
- package/dist/server/oauth/tokenEncryption.d.ts.map +0 -1
- package/dist/server/oauth/tokenEncryption.js +0 -218
- package/dist/server/oauth/tokenEncryption.js.map +0 -1
- package/dist/tools/sendMessage-complex-backup.d.ts +0 -6
- package/dist/tools/sendMessage-complex-backup.d.ts.map +0 -1
- package/dist/tools/sendMessage-complex-backup.js +0 -545
- package/dist/tools/sendMessage-complex-backup.js.map +0 -1
- package/dist/tools/sendMessage-revised.d.ts +0 -11
- package/dist/tools/sendMessage-revised.d.ts.map +0 -1
- package/dist/tools/sendMessage-revised.js +0 -429
- package/dist/tools/sendMessage-revised.js.map +0 -1
- package/dist/tools/sendMessage-truly-simple.d.ts +0 -8
- package/dist/tools/sendMessage-truly-simple.d.ts.map +0 -1
- package/dist/tools/sendMessage-truly-simple.js +0 -299
- package/dist/tools/sendMessage-truly-simple.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../../src/server/oauth/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGnF;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;IACpD,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,gBAAgB,kDAAkD;IAC3E,QAAQ,CAAC,QAAQ,yCAAyC;IAC1D,QAAQ,CAAC,WAAW,mDAAmD;IACvE,QAAQ,CAAC,SAAS,0CAA0C;IAC5D,QAAQ,CAAC,OAAO,gDAAgD;gBAEpD,MAAM,EAAE,cAAc;IAsBlC;;OAEG;IACH,SAAS,CAAC,gBAAgB,IAAI,MAAM,EAAE;IAWtC;;OAEG;IACH,SAAS,CAAC,iBAAiB,IAAI,MAAM;IAIrC;;OAEG;IACH,SAAS,CAAC,iBAAiB,CAAC,IAAI,EAAE,GAAG,GAAG,QAAQ;IAahD;;OAEG;IACH,SAAS,CAAC,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAe5D;;;OAGG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IASjE;;OAEG;IACG,kBAAkB,CACtB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,GACtC,OAAO,CAAC,OAAO,CAAC;IAoBnB;;;OAGG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,cAAc,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB7F;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK;CAYjD"}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { OAuthProvider } from './base.js';
|
|
2
|
-
import { logger } from '../../../utils/logger.js';
|
|
3
|
-
/**
|
|
4
|
-
* Google OAuth 2.0 Provider
|
|
5
|
-
* Implements Google Sign-In with OpenID Connect
|
|
6
|
-
*/
|
|
7
|
-
export class GoogleOAuthProvider extends OAuthProvider {
|
|
8
|
-
name = 'google';
|
|
9
|
-
authorizationUrl = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
10
|
-
tokenUrl = 'https://oauth2.googleapis.com/token';
|
|
11
|
-
userInfoUrl = 'https://www.googleapis.com/oauth2/v2/userinfo';
|
|
12
|
-
revokeUrl = 'https://oauth2.googleapis.com/revoke';
|
|
13
|
-
jwksUrl = 'https://www.googleapis.com/oauth2/v3/certs';
|
|
14
|
-
constructor(config) {
|
|
15
|
-
super(config);
|
|
16
|
-
// Set Google-specific defaults
|
|
17
|
-
if (!this.config.scopes || this.config.scopes.length === 0) {
|
|
18
|
-
this.config.scopes = this.getDefaultScopes();
|
|
19
|
-
}
|
|
20
|
-
// Google-specific additional parameters
|
|
21
|
-
if (!this.config.additionalParams) {
|
|
22
|
-
this.config.additionalParams = {};
|
|
23
|
-
}
|
|
24
|
-
// Request refresh token
|
|
25
|
-
this.config.additionalParams.access_type = 'offline';
|
|
26
|
-
// Force approval prompt for refresh token on first auth
|
|
27
|
-
if (process.env.GOOGLE_FORCE_APPROVAL === 'true') {
|
|
28
|
-
this.config.additionalParams.prompt = 'consent';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Get default scopes for Google
|
|
33
|
-
*/
|
|
34
|
-
getDefaultScopes() {
|
|
35
|
-
return [
|
|
36
|
-
'openid',
|
|
37
|
-
'email',
|
|
38
|
-
'profile',
|
|
39
|
-
// Add additional scopes as needed
|
|
40
|
-
// 'https://www.googleapis.com/auth/calendar.readonly',
|
|
41
|
-
// 'https://www.googleapis.com/auth/drive.file',
|
|
42
|
-
];
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Get expected issuer for Google
|
|
46
|
-
*/
|
|
47
|
-
getExpectedIssuer() {
|
|
48
|
-
return 'https://accounts.google.com';
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Normalize Google user info to common format
|
|
52
|
-
*/
|
|
53
|
-
normalizeUserInfo(data) {
|
|
54
|
-
return {
|
|
55
|
-
id: data.id || data.sub,
|
|
56
|
-
email: data.email,
|
|
57
|
-
email_verified: data.email_verified || data.verified_email,
|
|
58
|
-
name: data.name,
|
|
59
|
-
picture: data.picture,
|
|
60
|
-
locale: data.locale,
|
|
61
|
-
provider: this.name,
|
|
62
|
-
raw: data,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Additional Google-specific ID token validation
|
|
67
|
-
*/
|
|
68
|
-
validateIdTokenClaims(claims) {
|
|
69
|
-
super.validateIdTokenClaims(claims);
|
|
70
|
-
// Google-specific: Check HD claim for G Suite domains
|
|
71
|
-
const allowedDomain = process.env.GOOGLE_ALLOWED_DOMAIN;
|
|
72
|
-
if (allowedDomain && claims.hd !== allowedDomain) {
|
|
73
|
-
throw new Error(`User not from allowed domain: ${allowedDomain}`);
|
|
74
|
-
}
|
|
75
|
-
// Verify email is verified for Google accounts
|
|
76
|
-
if (claims.email && !claims.email_verified) {
|
|
77
|
-
throw new Error('Email not verified');
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Google-specific user info enrichment
|
|
82
|
-
* Can fetch additional profile data if needed
|
|
83
|
-
*/
|
|
84
|
-
async getEnrichedUserInfo(accessToken) {
|
|
85
|
-
const baseInfo = await this.getUserInfo(accessToken);
|
|
86
|
-
// Could fetch additional Google APIs data here
|
|
87
|
-
// For example: Google+ profile, Calendar info, etc.
|
|
88
|
-
return baseInfo;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Check if user has specific Google service access
|
|
92
|
-
*/
|
|
93
|
-
async checkServiceAccess(accessToken, service) {
|
|
94
|
-
const serviceUrls = {
|
|
95
|
-
calendar: 'https://www.googleapis.com/calendar/v3/users/me/settings',
|
|
96
|
-
drive: 'https://www.googleapis.com/drive/v3/about',
|
|
97
|
-
gmail: 'https://www.googleapis.com/gmail/v1/users/me/profile',
|
|
98
|
-
};
|
|
99
|
-
try {
|
|
100
|
-
const response = await fetch(serviceUrls[service], {
|
|
101
|
-
headers: {
|
|
102
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
return response.ok;
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Revoke Google tokens
|
|
113
|
-
* Google supports revoking both access and refresh tokens
|
|
114
|
-
*/
|
|
115
|
-
async revokeToken(token, tokenType) {
|
|
116
|
-
// Google revokes all tokens associated with the grant
|
|
117
|
-
const params = new URLSearchParams({ token });
|
|
118
|
-
try {
|
|
119
|
-
const response = await fetch(this.revokeUrl, {
|
|
120
|
-
method: 'POST',
|
|
121
|
-
headers: {
|
|
122
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
123
|
-
},
|
|
124
|
-
body: params.toString(),
|
|
125
|
-
});
|
|
126
|
-
if (response.ok) {
|
|
127
|
-
logger.info('Successfully revoked Google tokens');
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
const error = await response.text();
|
|
131
|
-
logger.error(`Failed to revoke Google token: ${error}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
logger.error('Error revoking Google token:', error);
|
|
136
|
-
throw error;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Handle Google-specific errors
|
|
141
|
-
*/
|
|
142
|
-
handleProviderError(error) {
|
|
143
|
-
// Handle Google-specific error codes
|
|
144
|
-
if (error.error === 'invalid_grant') {
|
|
145
|
-
throw new Error('Authorization code has been used or is invalid');
|
|
146
|
-
}
|
|
147
|
-
if (error.error === 'access_denied') {
|
|
148
|
-
throw new Error('User denied access to Google account');
|
|
149
|
-
}
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
//# sourceMappingURL=google.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../../../src/server/oauth/providers/google.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Register all available OAuth providers
|
|
3
|
-
*/
|
|
4
|
-
export declare function registerProviders(): void;
|
|
5
|
-
export { ProviderFactory } from './base.js';
|
|
6
|
-
export { GoogleOAuthProvider } from './google.js';
|
|
7
|
-
export { GitHubOAuthProvider } from './github.js';
|
|
8
|
-
export type { OAuthProvider, TokenResponse, UserInfo, IdTokenClaims, ProviderConfig, } from './base.js';
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/oauth/providers/index.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAYxC;AAMD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EACV,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,EACb,cAAc,GACf,MAAM,WAAW,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { ProviderFactory } from './base.js';
|
|
2
|
-
import { GoogleOAuthProvider } from './google.js';
|
|
3
|
-
import { GitHubOAuthProvider } from './github.js';
|
|
4
|
-
import { logger } from '../../../utils/logger.js';
|
|
5
|
-
/**
|
|
6
|
-
* Register all available OAuth providers
|
|
7
|
-
*/
|
|
8
|
-
export function registerProviders() {
|
|
9
|
-
// Register Google
|
|
10
|
-
ProviderFactory.register('google', GoogleOAuthProvider);
|
|
11
|
-
// Register GitHub
|
|
12
|
-
ProviderFactory.register('github', GitHubOAuthProvider);
|
|
13
|
-
// Additional providers can be registered here
|
|
14
|
-
// ProviderFactory.register('microsoft', MicrosoftOAuthProvider);
|
|
15
|
-
// ProviderFactory.register('apple', AppleOAuthProvider);
|
|
16
|
-
logger.info(`Registered ${ProviderFactory.getProviders().length} OAuth providers`);
|
|
17
|
-
}
|
|
18
|
-
// Auto-register on module load
|
|
19
|
-
registerProviders();
|
|
20
|
-
// Export all providers and factory
|
|
21
|
-
export { ProviderFactory } from './base.js';
|
|
22
|
-
export { GoogleOAuthProvider } from './google.js';
|
|
23
|
-
export { GitHubOAuthProvider } from './github.js';
|
|
24
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/oauth/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,kBAAkB;IAClB,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAExD,kBAAkB;IAClB,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAExD,8CAA8C;IAC9C,iEAAiE;IACjE,yDAAyD;IAEzD,MAAM,CAAC,IAAI,CAAC,cAAc,eAAe,CAAC,YAAY,EAAE,CAAC,MAAM,kBAAkB,CAAC,CAAC;AACrF,CAAC;AAED,+BAA+B;AAC/B,iBAAiB,EAAE,CAAC;AAEpB,mCAAmC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token family for tracking refresh token lineage
|
|
3
|
-
*/
|
|
4
|
-
export interface TokenFamily {
|
|
5
|
-
familyId: string;
|
|
6
|
-
currentTokenHash: string;
|
|
7
|
-
previousTokenHashes: string[];
|
|
8
|
-
userId: string;
|
|
9
|
-
clientId: string;
|
|
10
|
-
createdAt: Date;
|
|
11
|
-
lastRotated: Date;
|
|
12
|
-
rotationCount: number;
|
|
13
|
-
metadata?: {
|
|
14
|
-
ipAddress?: string;
|
|
15
|
-
userAgent?: string;
|
|
16
|
-
deviceId?: string;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Token rotation result
|
|
21
|
-
*/
|
|
22
|
-
export interface TokenRotationResult {
|
|
23
|
-
accessToken: string;
|
|
24
|
-
refreshToken: string;
|
|
25
|
-
expiresIn: number;
|
|
26
|
-
tokenType: 'Bearer';
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Security event types for monitoring
|
|
30
|
-
*/
|
|
31
|
-
export declare enum SecurityEvent {
|
|
32
|
-
TOKEN_ROTATED = "token_rotated",
|
|
33
|
-
TOKEN_REUSE_DETECTED = "token_reuse_detected",
|
|
34
|
-
TOKEN_FAMILY_REVOKED = "family_revoked",
|
|
35
|
-
SUSPICIOUS_ROTATION = "suspicious_rotation"
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Refresh Token Manager with rotation support
|
|
39
|
-
* Implements automatic token rotation and reuse detection
|
|
40
|
-
*/
|
|
41
|
-
export declare class RefreshTokenManager {
|
|
42
|
-
private tokenFamilies;
|
|
43
|
-
private readonly ACCESS_TOKEN_TTL;
|
|
44
|
-
private readonly REFRESH_TOKEN_TTL;
|
|
45
|
-
private readonly MAX_ROTATION_COUNT;
|
|
46
|
-
private readonly REUSE_DETECTION_WINDOW;
|
|
47
|
-
/**
|
|
48
|
-
* Generate a new token family for initial authentication
|
|
49
|
-
*/
|
|
50
|
-
createTokenFamily(userId: string, clientId: string, metadata?: TokenFamily['metadata']): Promise<TokenRotationResult>;
|
|
51
|
-
/**
|
|
52
|
-
* Rotate refresh token
|
|
53
|
-
* Detects and prevents token reuse attacks
|
|
54
|
-
*/
|
|
55
|
-
rotateRefreshToken(oldRefreshToken: string, metadata?: TokenFamily['metadata']): Promise<TokenRotationResult>;
|
|
56
|
-
/**
|
|
57
|
-
* Check if token has been reused
|
|
58
|
-
* Allows small grace period for legitimate retries
|
|
59
|
-
*/
|
|
60
|
-
private isTokenReused;
|
|
61
|
-
/**
|
|
62
|
-
* Handle token reuse detection
|
|
63
|
-
* Revokes entire token family as a security measure
|
|
64
|
-
*/
|
|
65
|
-
private handleTokenReuse;
|
|
66
|
-
/**
|
|
67
|
-
* Revoke an entire token family
|
|
68
|
-
* Used when token reuse or other attacks are detected
|
|
69
|
-
*/
|
|
70
|
-
revokeTokenFamily(familyId: string): Promise<void>;
|
|
71
|
-
/**
|
|
72
|
-
* Revoke all tokens for a user
|
|
73
|
-
* Used in case of account compromise
|
|
74
|
-
*/
|
|
75
|
-
revokeAllUserTokens(userId: string): Promise<void>;
|
|
76
|
-
/**
|
|
77
|
-
* Find token family by refresh token hash
|
|
78
|
-
*/
|
|
79
|
-
private findTokenFamily;
|
|
80
|
-
/**
|
|
81
|
-
* Detect suspicious rotation patterns
|
|
82
|
-
*/
|
|
83
|
-
private detectSuspiciousRotation;
|
|
84
|
-
/**
|
|
85
|
-
* Generate new refresh token
|
|
86
|
-
*/
|
|
87
|
-
private generateRefreshToken;
|
|
88
|
-
/**
|
|
89
|
-
* Generate new access token (JWT)
|
|
90
|
-
*/
|
|
91
|
-
private generateAccessToken;
|
|
92
|
-
/**
|
|
93
|
-
* Persist token family to database
|
|
94
|
-
*/
|
|
95
|
-
private persistTokenFamily;
|
|
96
|
-
/**
|
|
97
|
-
* Update token family in database
|
|
98
|
-
*/
|
|
99
|
-
private updateTokenFamily;
|
|
100
|
-
/**
|
|
101
|
-
* Log security event
|
|
102
|
-
*/
|
|
103
|
-
private logSecurityEvent;
|
|
104
|
-
/**
|
|
105
|
-
* Notify security team of critical events
|
|
106
|
-
*/
|
|
107
|
-
private notifySecurityTeam;
|
|
108
|
-
/**
|
|
109
|
-
* Clean up expired token families
|
|
110
|
-
*/
|
|
111
|
-
cleanupExpiredFamilies(): Promise<void>;
|
|
112
|
-
}
|
|
113
|
-
export declare const refreshTokenManager: RefreshTokenManager;
|
|
114
|
-
//# sourceMappingURL=refreshTokenRotation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refreshTokenRotation.d.ts","sourceRoot":"","sources":["../../../src/server/oauth/refreshTokenRotation.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE;QACT,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,CAAC;CACrB;AAED;;GAEG;AACH,oBAAY,aAAa;IACvB,aAAa,kBAAkB;IAC/B,oBAAoB,yBAAyB;IAC7C,oBAAoB,mBAAmB;IACvC,mBAAmB,wBAAwB;CAC5C;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmD;IACpF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwD;IAC1F,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IAC1C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAE/C;;OAEG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,GACjC,OAAO,CAAC,mBAAmB,CAAC;IAkC/B;;;OAGG;IACG,kBAAkB,CACtB,eAAe,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,GACjC,OAAO,CAAC,mBAAmB,CAAC;IAiE/B;;;OAGG;YACW,aAAa;IAoB3B;;;OAGG;YACW,gBAAgB;IAM9B;;;OAGG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBxD;;;OAGG;IACG,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxD;;OAEG;YACW,eAAe;IAsD7B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2BhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;YACW,mBAAmB;IAajC;;OAEG;YACW,kBAAkB;IAuBhC;;OAEG;YACW,iBAAiB;IAqB/B;;OAEG;YACW,gBAAgB;IAQ9B;;OAEG;YACW,kBAAkB;IAKhC;;OAEG;IACG,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;CAkB9C;AAGD,eAAO,MAAM,mBAAmB,qBAA4B,CAAC"}
|
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from 'crypto';
|
|
2
|
-
import { logger } from '../../utils/logger.js';
|
|
3
|
-
import { getDb } from '../../db/client.js';
|
|
4
|
-
import { oauthTokens } from '../../db/schema.js';
|
|
5
|
-
import { eq, and, isNull } from 'drizzle-orm';
|
|
6
|
-
import { tokenEncryption } from './tokenEncryption.js';
|
|
7
|
-
import jwt from 'jsonwebtoken';
|
|
8
|
-
/**
|
|
9
|
-
* Security event types for monitoring
|
|
10
|
-
*/
|
|
11
|
-
export var SecurityEvent;
|
|
12
|
-
(function (SecurityEvent) {
|
|
13
|
-
SecurityEvent["TOKEN_ROTATED"] = "token_rotated";
|
|
14
|
-
SecurityEvent["TOKEN_REUSE_DETECTED"] = "token_reuse_detected";
|
|
15
|
-
SecurityEvent["TOKEN_FAMILY_REVOKED"] = "family_revoked";
|
|
16
|
-
SecurityEvent["SUSPICIOUS_ROTATION"] = "suspicious_rotation";
|
|
17
|
-
})(SecurityEvent || (SecurityEvent = {}));
|
|
18
|
-
/**
|
|
19
|
-
* Refresh Token Manager with rotation support
|
|
20
|
-
* Implements automatic token rotation and reuse detection
|
|
21
|
-
*/
|
|
22
|
-
export class RefreshTokenManager {
|
|
23
|
-
tokenFamilies = new Map();
|
|
24
|
-
ACCESS_TOKEN_TTL = parseInt(process.env.ACCESS_TOKEN_TTL || '900'); // 15 minutes
|
|
25
|
-
REFRESH_TOKEN_TTL = parseInt(process.env.REFRESH_TOKEN_TTL || '2592000'); // 30 days
|
|
26
|
-
MAX_ROTATION_COUNT = 100; // Prevent infinite rotation
|
|
27
|
-
REUSE_DETECTION_WINDOW = 2000; // 2 seconds grace period
|
|
28
|
-
/**
|
|
29
|
-
* Generate a new token family for initial authentication
|
|
30
|
-
*/
|
|
31
|
-
async createTokenFamily(userId, clientId, metadata) {
|
|
32
|
-
const familyId = randomBytes(16).toString('base64url');
|
|
33
|
-
const refreshToken = this.generateRefreshToken();
|
|
34
|
-
const refreshTokenHash = tokenEncryption.hashToken(refreshToken);
|
|
35
|
-
const family = {
|
|
36
|
-
familyId,
|
|
37
|
-
currentTokenHash: refreshTokenHash,
|
|
38
|
-
previousTokenHashes: [],
|
|
39
|
-
userId,
|
|
40
|
-
clientId,
|
|
41
|
-
createdAt: new Date(),
|
|
42
|
-
lastRotated: new Date(),
|
|
43
|
-
rotationCount: 0,
|
|
44
|
-
metadata,
|
|
45
|
-
};
|
|
46
|
-
// Store family in memory and database
|
|
47
|
-
this.tokenFamilies.set(familyId, family);
|
|
48
|
-
await this.persistTokenFamily(family, refreshToken);
|
|
49
|
-
// Generate access token
|
|
50
|
-
const accessToken = await this.generateAccessToken(userId, clientId);
|
|
51
|
-
logger.info(`Created new token family ${familyId} for user ${userId}`);
|
|
52
|
-
return {
|
|
53
|
-
accessToken,
|
|
54
|
-
refreshToken,
|
|
55
|
-
expiresIn: this.ACCESS_TOKEN_TTL,
|
|
56
|
-
tokenType: 'Bearer',
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Rotate refresh token
|
|
61
|
-
* Detects and prevents token reuse attacks
|
|
62
|
-
*/
|
|
63
|
-
async rotateRefreshToken(oldRefreshToken, metadata) {
|
|
64
|
-
const oldTokenHash = tokenEncryption.hashToken(oldRefreshToken);
|
|
65
|
-
// Find token family
|
|
66
|
-
const family = await this.findTokenFamily(oldTokenHash);
|
|
67
|
-
if (!family) {
|
|
68
|
-
logger.error('Refresh token not found - possible attack');
|
|
69
|
-
throw new Error('Invalid refresh token');
|
|
70
|
-
}
|
|
71
|
-
// Check for token reuse (replay attack)
|
|
72
|
-
if (await this.isTokenReused(family, oldTokenHash)) {
|
|
73
|
-
logger.error(`Token reuse detected for family ${family.familyId}`);
|
|
74
|
-
await this.handleTokenReuse(family);
|
|
75
|
-
throw new Error('Token reuse detected - all tokens revoked');
|
|
76
|
-
}
|
|
77
|
-
// Check rotation count to prevent infinite rotation
|
|
78
|
-
if (family.rotationCount >= this.MAX_ROTATION_COUNT) {
|
|
79
|
-
logger.warn(`Max rotation count reached for family ${family.familyId}`);
|
|
80
|
-
await this.revokeTokenFamily(family.familyId);
|
|
81
|
-
throw new Error('Maximum token rotations exceeded');
|
|
82
|
-
}
|
|
83
|
-
// Check for suspicious rotation patterns
|
|
84
|
-
if (this.detectSuspiciousRotation(family, metadata)) {
|
|
85
|
-
logger.warn(`Suspicious rotation pattern detected for family ${family.familyId}`);
|
|
86
|
-
await this.logSecurityEvent(SecurityEvent.SUSPICIOUS_ROTATION, family);
|
|
87
|
-
}
|
|
88
|
-
// Generate new tokens
|
|
89
|
-
const newRefreshToken = this.generateRefreshToken();
|
|
90
|
-
const newRefreshTokenHash = tokenEncryption.hashToken(newRefreshToken);
|
|
91
|
-
const newAccessToken = await this.generateAccessToken(family.userId, family.clientId);
|
|
92
|
-
// Update token family
|
|
93
|
-
family.previousTokenHashes.push(family.currentTokenHash);
|
|
94
|
-
family.currentTokenHash = newRefreshTokenHash;
|
|
95
|
-
family.lastRotated = new Date();
|
|
96
|
-
family.rotationCount++;
|
|
97
|
-
// Limit history to prevent memory bloat (keep last 10)
|
|
98
|
-
if (family.previousTokenHashes.length > 10) {
|
|
99
|
-
family.previousTokenHashes = family.previousTokenHashes.slice(-10);
|
|
100
|
-
}
|
|
101
|
-
// Update metadata if provided
|
|
102
|
-
if (metadata) {
|
|
103
|
-
family.metadata = { ...family.metadata, ...metadata };
|
|
104
|
-
}
|
|
105
|
-
// Persist changes
|
|
106
|
-
await this.updateTokenFamily(family, newRefreshToken, oldRefreshToken);
|
|
107
|
-
logger.info(`Rotated refresh token for family ${family.familyId}, rotation #${family.rotationCount}`);
|
|
108
|
-
return {
|
|
109
|
-
accessToken: newAccessToken,
|
|
110
|
-
refreshToken: newRefreshToken,
|
|
111
|
-
expiresIn: this.ACCESS_TOKEN_TTL,
|
|
112
|
-
tokenType: 'Bearer',
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Check if token has been reused
|
|
117
|
-
* Allows small grace period for legitimate retries
|
|
118
|
-
*/
|
|
119
|
-
async isTokenReused(family, tokenHash) {
|
|
120
|
-
// Current token is valid
|
|
121
|
-
if (tokenHash === family.currentTokenHash) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
// Check if it's a recently rotated token (within grace period)
|
|
125
|
-
const timeSinceRotation = Date.now() - family.lastRotated.getTime();
|
|
126
|
-
if (timeSinceRotation < this.REUSE_DETECTION_WINDOW) {
|
|
127
|
-
const lastPrevious = family.previousTokenHashes[family.previousTokenHashes.length - 1];
|
|
128
|
-
if (tokenHash === lastPrevious) {
|
|
129
|
-
logger.debug('Token use within grace period, allowing');
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// Check if it's an old token (definite reuse)
|
|
134
|
-
return family.previousTokenHashes.includes(tokenHash);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Handle token reuse detection
|
|
138
|
-
* Revokes entire token family as a security measure
|
|
139
|
-
*/
|
|
140
|
-
async handleTokenReuse(family) {
|
|
141
|
-
await this.logSecurityEvent(SecurityEvent.TOKEN_REUSE_DETECTED, family);
|
|
142
|
-
await this.revokeTokenFamily(family.familyId);
|
|
143
|
-
await this.notifySecurityTeam(family);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Revoke an entire token family
|
|
147
|
-
* Used when token reuse or other attacks are detected
|
|
148
|
-
*/
|
|
149
|
-
async revokeTokenFamily(familyId) {
|
|
150
|
-
const family = this.tokenFamilies.get(familyId);
|
|
151
|
-
if (!family) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
const db = getDb();
|
|
155
|
-
// Mark all tokens in family as revoked
|
|
156
|
-
await db.update(oauthTokens)
|
|
157
|
-
.set({
|
|
158
|
-
revokedAt: new Date(),
|
|
159
|
-
revocationReason: 'family_revoked',
|
|
160
|
-
})
|
|
161
|
-
.where(eq(oauthTokens.tokenFamilyId, familyId));
|
|
162
|
-
// Remove from memory
|
|
163
|
-
this.tokenFamilies.delete(familyId);
|
|
164
|
-
logger.info(`Revoked token family ${familyId} for user ${family.userId}`);
|
|
165
|
-
await this.logSecurityEvent(SecurityEvent.TOKEN_FAMILY_REVOKED, family);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Revoke all tokens for a user
|
|
169
|
-
* Used in case of account compromise
|
|
170
|
-
*/
|
|
171
|
-
async revokeAllUserTokens(userId) {
|
|
172
|
-
const db = getDb();
|
|
173
|
-
// Revoke all tokens
|
|
174
|
-
await db.update(oauthTokens)
|
|
175
|
-
.set({
|
|
176
|
-
revokedAt: new Date(),
|
|
177
|
-
revocationReason: 'user_revoked_all',
|
|
178
|
-
})
|
|
179
|
-
.where(eq(oauthTokens.userId, userId));
|
|
180
|
-
// Remove from memory
|
|
181
|
-
for (const [familyId, family] of this.tokenFamilies.entries()) {
|
|
182
|
-
if (family.userId === userId) {
|
|
183
|
-
this.tokenFamilies.delete(familyId);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
logger.info(`Revoked all tokens for user ${userId}`);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Find token family by refresh token hash
|
|
190
|
-
*/
|
|
191
|
-
async findTokenFamily(tokenHash) {
|
|
192
|
-
// Check memory cache first
|
|
193
|
-
for (const family of this.tokenFamilies.values()) {
|
|
194
|
-
if (family.currentTokenHash === tokenHash ||
|
|
195
|
-
family.previousTokenHashes.includes(tokenHash)) {
|
|
196
|
-
return family;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// Check database
|
|
200
|
-
const db = getDb();
|
|
201
|
-
const result = await db.select()
|
|
202
|
-
.from(oauthTokens)
|
|
203
|
-
.where(and(eq(oauthTokens.refreshTokenHash, tokenHash), isNull(oauthTokens.revokedAt)))
|
|
204
|
-
.limit(1);
|
|
205
|
-
if (result.length === 0) {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
// Reconstruct family from database
|
|
209
|
-
const token = result[0];
|
|
210
|
-
// Handle nullable fields
|
|
211
|
-
if (!token || !token.tokenFamilyId || !token.refreshTokenHash || !token.clientId) {
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
const family = {
|
|
215
|
-
familyId: token.tokenFamilyId,
|
|
216
|
-
currentTokenHash: token.refreshTokenHash,
|
|
217
|
-
previousTokenHashes: [], // Would need separate table for full history
|
|
218
|
-
userId: token.userId,
|
|
219
|
-
clientId: token.clientId,
|
|
220
|
-
createdAt: token.createdAt,
|
|
221
|
-
lastRotated: token.createdAt,
|
|
222
|
-
rotationCount: 0,
|
|
223
|
-
metadata: {
|
|
224
|
-
ipAddress: token.ipAddress || undefined,
|
|
225
|
-
userAgent: token.userAgent || undefined,
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
// Cache in memory
|
|
229
|
-
this.tokenFamilies.set(family.familyId, family);
|
|
230
|
-
return family;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Detect suspicious rotation patterns
|
|
234
|
-
*/
|
|
235
|
-
detectSuspiciousRotation(family, newMetadata) {
|
|
236
|
-
// Rapid rotation (more than once per minute)
|
|
237
|
-
const timeSinceLastRotation = Date.now() - family.lastRotated.getTime();
|
|
238
|
-
if (timeSinceLastRotation < 60000) {
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
// Different IP address
|
|
242
|
-
if (newMetadata?.ipAddress &&
|
|
243
|
-
family.metadata?.ipAddress &&
|
|
244
|
-
newMetadata.ipAddress !== family.metadata.ipAddress) {
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
// Different device
|
|
248
|
-
if (newMetadata?.deviceId &&
|
|
249
|
-
family.metadata?.deviceId &&
|
|
250
|
-
newMetadata.deviceId !== family.metadata.deviceId) {
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Generate new refresh token
|
|
257
|
-
*/
|
|
258
|
-
generateRefreshToken() {
|
|
259
|
-
return randomBytes(32).toString('base64url');
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Generate new access token (JWT)
|
|
263
|
-
*/
|
|
264
|
-
async generateAccessToken(userId, clientId) {
|
|
265
|
-
const payload = {
|
|
266
|
-
sub: userId,
|
|
267
|
-
client_id: clientId,
|
|
268
|
-
token_type: 'access',
|
|
269
|
-
iat: Math.floor(Date.now() / 1000),
|
|
270
|
-
exp: Math.floor(Date.now() / 1000) + this.ACCESS_TOKEN_TTL,
|
|
271
|
-
};
|
|
272
|
-
const secret = process.env.JWT_SECRET || 'dev-secret-change-in-production';
|
|
273
|
-
return jwt.sign(payload, secret, { algorithm: 'HS256' });
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Persist token family to database
|
|
277
|
-
*/
|
|
278
|
-
async persistTokenFamily(family, refreshToken) {
|
|
279
|
-
const db = getDb();
|
|
280
|
-
const encryptedToken = await tokenEncryption.encryptToken(refreshToken);
|
|
281
|
-
await db.insert(oauthTokens)
|
|
282
|
-
.values({
|
|
283
|
-
userId: family.userId,
|
|
284
|
-
clientId: family.clientId,
|
|
285
|
-
tokenFamilyId: family.familyId,
|
|
286
|
-
refreshTokenHash: family.currentTokenHash,
|
|
287
|
-
refreshTokenEncrypted: encryptedToken.encrypted,
|
|
288
|
-
accessTokenHash: '', // Will be set separately
|
|
289
|
-
accessTokenEncrypted: '', // Will be set separately
|
|
290
|
-
scope: 'default',
|
|
291
|
-
expiresAt: new Date(Date.now() + this.REFRESH_TOKEN_TTL * 1000),
|
|
292
|
-
ipAddress: family.metadata?.ipAddress,
|
|
293
|
-
userAgent: family.metadata?.userAgent,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Update token family in database
|
|
298
|
-
*/
|
|
299
|
-
async updateTokenFamily(family, newRefreshToken, oldRefreshToken) {
|
|
300
|
-
const db = getDb();
|
|
301
|
-
const encryptedToken = await tokenEncryption.encryptToken(newRefreshToken);
|
|
302
|
-
const oldTokenHash = tokenEncryption.hashToken(oldRefreshToken);
|
|
303
|
-
// Mark old token as rotated
|
|
304
|
-
await db.update(oauthTokens)
|
|
305
|
-
.set({
|
|
306
|
-
revokedAt: new Date(),
|
|
307
|
-
revocationReason: 'rotated',
|
|
308
|
-
})
|
|
309
|
-
.where(eq(oauthTokens.refreshTokenHash, oldTokenHash));
|
|
310
|
-
// Insert new token
|
|
311
|
-
await this.persistTokenFamily(family, newRefreshToken);
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Log security event
|
|
315
|
-
*/
|
|
316
|
-
async logSecurityEvent(event, family) {
|
|
317
|
-
logger.warn(`Security event: ${event} for family ${family.familyId}, user ${family.userId}`);
|
|
318
|
-
// TODO: Log to audit table
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Notify security team of critical events
|
|
322
|
-
*/
|
|
323
|
-
async notifySecurityTeam(family) {
|
|
324
|
-
// TODO: Send alert to security team
|
|
325
|
-
logger.error(`SECURITY ALERT: Token reuse detected for user ${family.userId}`);
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Clean up expired token families
|
|
329
|
-
*/
|
|
330
|
-
async cleanupExpiredFamilies() {
|
|
331
|
-
const db = getDb();
|
|
332
|
-
const expiredDate = new Date(Date.now() - this.REFRESH_TOKEN_TTL * 1000);
|
|
333
|
-
await db.update(oauthTokens)
|
|
334
|
-
.set({
|
|
335
|
-
revokedAt: new Date(),
|
|
336
|
-
revocationReason: 'expired',
|
|
337
|
-
})
|
|
338
|
-
.where(and(eq(oauthTokens.revokedAt, null), eq(oauthTokens.expiresAt, expiredDate)));
|
|
339
|
-
logger.debug('Cleaned up expired token families');
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
// Export singleton instance
|
|
343
|
-
export const refreshTokenManager = new RefreshTokenManager();
|
|
344
|
-
//# sourceMappingURL=refreshTokenRotation.js.map
|