@oneuptime/common 12.0.14 → 12.0.15
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/Models/DatabaseModels/GlobalOidc.ts +20 -0
- package/Models/DatabaseModels/GlobalSso.ts +20 -0
- package/Models/DatabaseModels/MarketingConversion.ts +19 -9
- package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +46 -0
- package/Models/DatabaseModels/StatusPage.ts +7 -4
- package/Server/API/StatusPageAPI.ts +29 -4
- package/Server/EnvironmentConfig.ts +7 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/SlackAuthorization.ts +43 -6
- package/Server/Middleware/UserAuthorization.ts +236 -26
- package/Server/Middleware/WhatsAppAuthorization.ts +43 -3
- package/Server/Services/GlobalOidcProjectService.ts +126 -1
- package/Server/Services/GlobalOidcService.ts +132 -0
- package/Server/Services/GlobalSsoProjectService.ts +126 -1
- package/Server/Services/GlobalSsoService.ts +132 -0
- package/Server/Services/UserEmailService.ts +4 -4
- package/Server/Utils/CronTab.ts +73 -0
- package/Server/Utils/GlobalSsoAuthorization.ts +175 -0
- package/Server/Utils/Marketing/ConversionUploadProvider.ts +35 -5
- package/Server/Utils/Marketing/Providers/GoogleAds.ts +1 -1
- package/Server/Utils/Marketing/Providers/LinkedIn.ts +1 -1
- package/Server/Utils/Marketing/Providers/Meta.ts +1 -1
- package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +1 -1
- package/Server/Utils/Marketing/Providers/Reddit.ts +1 -1
- package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +48 -33
- package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +35 -30
- package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +33 -28
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +475 -47
- package/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.ts +35 -30
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +34 -28
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +33 -28
- package/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.ts +69 -40
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +35 -29
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +8 -0
- package/Server/Utils/Monitor/MonitorResource.ts +161 -21
- package/Server/Utils/StatusPageContentSecurityPolicy.ts +56 -0
- package/Server/Utils/StatusPageCustomizationAccess.ts +117 -0
- package/Tests/Server/API/StatusPageCustomizationOrigin.test.ts +348 -0
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +9 -59
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +227 -0
- package/Tests/Server/Middleware/SlackAuthorization.test.ts +149 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +27 -13
- package/Tests/Server/Middleware/UserAuthorizationGlobalSsoGovernance.test.ts +1455 -0
- package/Tests/Server/Middleware/UserAuthorizationSSOProvider.test.ts +91 -2
- package/Tests/Server/Middleware/WhatsAppAuthorization.test.ts +233 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +21 -8
- package/Tests/Server/Services/GlobalSsoProviderAuthorization.test.ts +1242 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementHydration.test.ts +459 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +10 -0
- package/Tests/Server/Types/AnalyticsDatabase/AggregateUtilBucketTimestamp.test.ts +416 -0
- package/Tests/Server/Types/Database/QueryHelperManyToManyAndEmptyValues.test.ts +551 -0
- package/Tests/Server/Types/Database/SelectUtil.test.ts +348 -0
- package/Tests/Server/Utils/CronTab.test.ts +116 -0
- package/Tests/Server/Utils/GlobalSSOToken.test.ts +581 -0
- package/Tests/Server/Utils/GlobalSsoAuthorization.test.ts +1401 -0
- package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +254 -0
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +508 -0
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +30 -9
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +987 -0
- package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +916 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +382 -0
- package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +1219 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +86 -0
- package/Tests/Server/Utils/StatusPageContentSecurityPolicy.test.ts +136 -0
- package/Tests/Server/Utils/StatusPageCustomizationAccess.test.ts +223 -0
- package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +165 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceLinkRuleScope.test.ts +215 -0
- package/Tests/UI/Components/Forms/FormSubmitAnalytics.test.tsx +206 -0
- package/Tests/UI/Utils/AIChatExport/ConversationMarkdown.test.ts +774 -0
- package/Tests/UI/Utils/AIChatExport/MarkdownBlocks.test.ts +791 -0
- package/Tests/UI/Utils/AIChatExport/MarkdownSafety.test.ts +544 -0
- package/Tests/Utils/Analytics.test.ts +187 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +80 -0
- package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +1291 -0
- package/Tests/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.test.ts +214 -0
- package/Types/Marketing/MarketingConversion.ts +12 -0
- package/Types/Monitor/CriteriaFilter.ts +9 -0
- package/Types/NetworkDevice/NetworkDeviceLinkRuleScope.ts +51 -0
- package/UI/Components/FormModal/BasicFormModal.tsx +12 -0
- package/UI/Components/Forms/BasicForm.tsx +13 -1
- package/UI/Components/Forms/BasicModelForm.tsx +2 -1
- package/UI/Components/Forms/ModelForm.tsx +10 -1
- package/UI/Components/Forms/Utils/FormAnalyticsName.ts +39 -0
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +6 -1
- package/Utils/Analytics.ts +55 -2
- package/Utils/Monitor/MonitorMetricType.ts +40 -0
- package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +587 -37
- package/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.ts +115 -0
- package/build/dist/Models/DatabaseModels/GlobalOidc.js +21 -0
- package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSso.js +21 -0
- package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MarketingConversion.js +20 -10
- package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +47 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +25 -4
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +6 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/SlackAuthorization.js +28 -4
- package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +197 -22
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/WhatsAppAuthorization.js +32 -2
- package/build/dist/Server/Middleware/WhatsAppAuthorization.js.map +1 -1
- package/build/dist/Server/Services/GlobalOidcProjectService.js +105 -0
- package/build/dist/Server/Services/GlobalOidcProjectService.js.map +1 -1
- package/build/dist/Server/Services/GlobalOidcService.js +127 -0
- package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
- package/build/dist/Server/Services/GlobalSsoProjectService.js +105 -0
- package/build/dist/Server/Services/GlobalSsoProjectService.js.map +1 -1
- package/build/dist/Server/Services/GlobalSsoService.js +127 -0
- package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +4 -4
- package/build/dist/Server/Utils/CronTab.js +66 -0
- package/build/dist/Server/Utils/CronTab.js.map +1 -1
- package/build/dist/Server/Utils/GlobalSsoAuthorization.js +112 -0
- package/build/dist/Server/Utils/GlobalSsoAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +17 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +37 -35
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +20 -22
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +370 -42
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js +64 -52
- package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +25 -29
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +8 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +123 -23
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js +39 -0
- package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageCustomizationAccess.js +85 -0
- package/build/dist/Server/Utils/StatusPageCustomizationAccess.js.map +1 -0
- package/build/dist/Types/Marketing/MarketingConversion.js +10 -0
- package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js +46 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js.map +1 -0
- package/build/dist/UI/Components/FormModal/BasicFormModal.js +2 -1
- package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +10 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicModelForm.js +2 -1
- package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +4 -1
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js +33 -0
- package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js.map +1 -0
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +2 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/Utils/Analytics.js +50 -2
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +37 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +318 -37
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js +87 -0
- package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,9 +1,136 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
1
10
|
import DatabaseService from "./DatabaseService";
|
|
2
11
|
import Model from "../../Models/DatabaseModels/GlobalOidc";
|
|
12
|
+
import ObjectID from "../../Types/ObjectID";
|
|
13
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
|
+
import { GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS, clearGlobalSsoAuthorizationCaches, globalProviderCacheKey, globalSsoProviderTrustCache, loadTrustOnce, } from "../Utils/GlobalSsoAuthorization";
|
|
3
15
|
export class Service extends DatabaseService {
|
|
4
16
|
constructor() {
|
|
5
17
|
super(Model);
|
|
6
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* What the SSO-enforcement middleware needs to know about this provider:
|
|
21
|
+
* whether it is still usable at all, and whether the admin opted it into
|
|
22
|
+
* attachment-scoped access.
|
|
23
|
+
*
|
|
24
|
+
* Called on every authenticated request against an SSO-enforced project, so
|
|
25
|
+
* the answer is cached for 60s and concurrent misses share one query.
|
|
26
|
+
* Without this lookup, turning a provider off leaves every token it ever
|
|
27
|
+
* issued working until each one expires - up to thirty days.
|
|
28
|
+
*/
|
|
29
|
+
async getProviderTrust(providerId) {
|
|
30
|
+
const key = globalProviderCacheKey("oidc", providerId);
|
|
31
|
+
const cached = globalSsoProviderTrustCache.get(key);
|
|
32
|
+
if (cached !== undefined) {
|
|
33
|
+
return cached;
|
|
34
|
+
}
|
|
35
|
+
return loadTrustOnce(key, async () => {
|
|
36
|
+
const provider = await this.findOneBy({
|
|
37
|
+
query: { _id: providerId.toString() },
|
|
38
|
+
select: {
|
|
39
|
+
_id: true,
|
|
40
|
+
isEnabled: true,
|
|
41
|
+
restrictToAttachedProjects: true,
|
|
42
|
+
},
|
|
43
|
+
props: { isRoot: true },
|
|
44
|
+
});
|
|
45
|
+
/*
|
|
46
|
+
* A deleted provider and a disabled one are the same answer: no. Both
|
|
47
|
+
* are cached, so a revoked provider does not cost a query per request.
|
|
48
|
+
*/
|
|
49
|
+
const trust = {
|
|
50
|
+
isUsable: Boolean(provider && provider.isEnabled),
|
|
51
|
+
restrictToAttachedProjects: Boolean(provider && provider.restrictToAttachedProjects),
|
|
52
|
+
};
|
|
53
|
+
globalSsoProviderTrustCache.set(key, trust, GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS);
|
|
54
|
+
return trust;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/*
|
|
58
|
+
* Cache invalidation runs in the SUCCESS hooks, not the before-hooks: a
|
|
59
|
+
* clear that happens before the row is written can be immediately re-filled
|
|
60
|
+
* with the pre-change answer by a concurrent request, which would hand a
|
|
61
|
+
* disabled provider another full TTL of life on the very node that served
|
|
62
|
+
* the disable. Clearing in both is deliberate - the before-hook narrows the
|
|
63
|
+
* window, the success hook closes it.
|
|
64
|
+
*
|
|
65
|
+
* These caches are per-process, so the hooks make a change immediate on the
|
|
66
|
+
* node that served it and the TTL bounds every other node.
|
|
67
|
+
*/
|
|
68
|
+
async onBeforeUpdate(updateBy) {
|
|
69
|
+
clearGlobalSsoAuthorizationCaches();
|
|
70
|
+
return { updateBy, carryForward: null };
|
|
71
|
+
}
|
|
72
|
+
async onUpdateSuccess(onUpdate, _updatedItemIds) {
|
|
73
|
+
clearGlobalSsoAuthorizationCaches();
|
|
74
|
+
return onUpdate;
|
|
75
|
+
}
|
|
76
|
+
async onBeforeDelete(deleteBy) {
|
|
77
|
+
clearGlobalSsoAuthorizationCaches();
|
|
78
|
+
return { deleteBy, carryForward: null };
|
|
79
|
+
}
|
|
80
|
+
async onDeleteSuccess(onDelete, _itemIdsBeforeDelete) {
|
|
81
|
+
clearGlobalSsoAuthorizationCaches();
|
|
82
|
+
return onDelete;
|
|
83
|
+
}
|
|
84
|
+
async onBeforeCreate(createBy) {
|
|
85
|
+
clearGlobalSsoAuthorizationCaches();
|
|
86
|
+
return { createBy, carryForward: null };
|
|
87
|
+
}
|
|
88
|
+
async onCreateSuccess(_onCreate, createdItem) {
|
|
89
|
+
clearGlobalSsoAuthorizationCaches();
|
|
90
|
+
return createdItem;
|
|
91
|
+
}
|
|
7
92
|
}
|
|
93
|
+
__decorate([
|
|
94
|
+
CaptureSpan(),
|
|
95
|
+
__metadata("design:type", Function),
|
|
96
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
97
|
+
__metadata("design:returntype", Promise)
|
|
98
|
+
], Service.prototype, "getProviderTrust", null);
|
|
99
|
+
__decorate([
|
|
100
|
+
CaptureSpan(),
|
|
101
|
+
__metadata("design:type", Function),
|
|
102
|
+
__metadata("design:paramtypes", [Object]),
|
|
103
|
+
__metadata("design:returntype", Promise)
|
|
104
|
+
], Service.prototype, "onBeforeUpdate", null);
|
|
105
|
+
__decorate([
|
|
106
|
+
CaptureSpan(),
|
|
107
|
+
__metadata("design:type", Function),
|
|
108
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
109
|
+
__metadata("design:returntype", Promise)
|
|
110
|
+
], Service.prototype, "onUpdateSuccess", null);
|
|
111
|
+
__decorate([
|
|
112
|
+
CaptureSpan(),
|
|
113
|
+
__metadata("design:type", Function),
|
|
114
|
+
__metadata("design:paramtypes", [Object]),
|
|
115
|
+
__metadata("design:returntype", Promise)
|
|
116
|
+
], Service.prototype, "onBeforeDelete", null);
|
|
117
|
+
__decorate([
|
|
118
|
+
CaptureSpan(),
|
|
119
|
+
__metadata("design:type", Function),
|
|
120
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
121
|
+
__metadata("design:returntype", Promise)
|
|
122
|
+
], Service.prototype, "onDeleteSuccess", null);
|
|
123
|
+
__decorate([
|
|
124
|
+
CaptureSpan(),
|
|
125
|
+
__metadata("design:type", Function),
|
|
126
|
+
__metadata("design:paramtypes", [Object]),
|
|
127
|
+
__metadata("design:returntype", Promise)
|
|
128
|
+
], Service.prototype, "onBeforeCreate", null);
|
|
129
|
+
__decorate([
|
|
130
|
+
CaptureSpan(),
|
|
131
|
+
__metadata("design:type", Function),
|
|
132
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
133
|
+
__metadata("design:returntype", Promise)
|
|
134
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
8
135
|
export default new Service();
|
|
9
136
|
//# sourceMappingURL=GlobalOidcService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalOidcService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalOidcService.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"GlobalOidcService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalOidcService.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,10 +12,82 @@ import Model from "../../Models/DatabaseModels/GlobalSsoProject";
|
|
|
12
12
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
13
13
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
14
|
import validateGlobalProviderProjectTeams, { resolveAttachmentProjectId, } from "../Utils/ValidateGlobalProviderProjectTeams";
|
|
15
|
+
import { GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS, clearGlobalSsoAuthorizationCaches, doAttachmentsGovernProject, globalProviderCacheKey, globalSsoAttachmentsCache, loadAttachmentsOnce, } from "../Utils/GlobalSsoAuthorization";
|
|
15
16
|
export class Service extends DatabaseService {
|
|
16
17
|
constructor() {
|
|
17
18
|
super(Model);
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Whether this provider's attachments cover `projectId`.
|
|
22
|
+
*
|
|
23
|
+
* Only consulted when the provider has `restrictToAttachedProjects` on -
|
|
24
|
+
* attachments are the PROVISIONING allow-list by default, not an access
|
|
25
|
+
* boundary, and reading them as one without the admin asking would lock
|
|
26
|
+
* existing users out of projects they legitimately reach.
|
|
27
|
+
*
|
|
28
|
+
* "No attachment rows at all" means instance-wide, matching the login
|
|
29
|
+
* router's default-all mode. "Rows exist but none are enabled" is a
|
|
30
|
+
* different answer and denies - otherwise an admin disabling the last
|
|
31
|
+
* attachment would WIDEN the provider to every project.
|
|
32
|
+
*
|
|
33
|
+
* Cached for 60s, with concurrent misses sharing one query.
|
|
34
|
+
*/
|
|
35
|
+
async doesProviderGovernProject(data) {
|
|
36
|
+
const key = globalProviderCacheKey("sso", data.globalSsoId);
|
|
37
|
+
const cached = globalSsoAttachmentsCache.get(key);
|
|
38
|
+
if (cached !== undefined) {
|
|
39
|
+
return doAttachmentsGovernProject(cached, data.projectId);
|
|
40
|
+
}
|
|
41
|
+
const attachments = await loadAttachmentsOnce(key, async () => {
|
|
42
|
+
/*
|
|
43
|
+
* Fetched WITHOUT the isEnabled filter so a disabled row still counts
|
|
44
|
+
* as "this provider has attachments"; the enabled ones are selected
|
|
45
|
+
* out below.
|
|
46
|
+
*/
|
|
47
|
+
const rows = await this.findBy({
|
|
48
|
+
query: { globalSsoId: data.globalSsoId },
|
|
49
|
+
select: { _id: true, projectId: true, isEnabled: true },
|
|
50
|
+
limit: LIMIT_PER_PROJECT,
|
|
51
|
+
skip: 0,
|
|
52
|
+
props: { isRoot: true },
|
|
53
|
+
});
|
|
54
|
+
const loaded = {
|
|
55
|
+
hasAnyAttachmentRows: rows.length > 0,
|
|
56
|
+
enabledProjectIds: rows
|
|
57
|
+
.filter((row) => {
|
|
58
|
+
return Boolean(row.isEnabled) && Boolean(row.projectId);
|
|
59
|
+
})
|
|
60
|
+
.map((row) => {
|
|
61
|
+
return row.projectId.toString();
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
globalSsoAttachmentsCache.set(key, loaded, GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS);
|
|
65
|
+
return loaded;
|
|
66
|
+
});
|
|
67
|
+
return doAttachmentsGovernProject(attachments, data.projectId);
|
|
68
|
+
}
|
|
69
|
+
async onBeforeDelete(deleteBy) {
|
|
70
|
+
// Detaching a project has to take effect now, not in 60s, on this node.
|
|
71
|
+
clearGlobalSsoAuthorizationCaches();
|
|
72
|
+
return { deleteBy, carryForward: null };
|
|
73
|
+
}
|
|
74
|
+
/*
|
|
75
|
+
* Cleared again AFTER the write commits. A clear that runs before the row
|
|
76
|
+
* lands can be immediately re-filled with the pre-change answer by a
|
|
77
|
+
* concurrent request, handing the old attachment set another full TTL.
|
|
78
|
+
*/
|
|
79
|
+
async onDeleteSuccess(onDelete, _itemIdsBeforeDelete) {
|
|
80
|
+
clearGlobalSsoAuthorizationCaches();
|
|
81
|
+
return onDelete;
|
|
82
|
+
}
|
|
83
|
+
async onCreateSuccess(_onCreate, createdItem) {
|
|
84
|
+
clearGlobalSsoAuthorizationCaches();
|
|
85
|
+
return createdItem;
|
|
86
|
+
}
|
|
87
|
+
async onUpdateSuccess(onUpdate, _updatedItemIds) {
|
|
88
|
+
clearGlobalSsoAuthorizationCaches();
|
|
89
|
+
return onUpdate;
|
|
90
|
+
}
|
|
19
91
|
async onBeforeCreate(createBy) {
|
|
20
92
|
/*
|
|
21
93
|
* The attach form submits the project via the `project` relation, so the
|
|
@@ -30,6 +102,8 @@ export class Service extends DatabaseService {
|
|
|
30
102
|
teams: createBy.data.teams,
|
|
31
103
|
projectId,
|
|
32
104
|
});
|
|
105
|
+
// A new attachment narrows (or widens) which projects the provider governs.
|
|
106
|
+
clearGlobalSsoAuthorizationCaches();
|
|
33
107
|
return { createBy, carryForward: null };
|
|
34
108
|
}
|
|
35
109
|
async onBeforeUpdate(updateBy) {
|
|
@@ -61,9 +135,40 @@ export class Service extends DatabaseService {
|
|
|
61
135
|
}
|
|
62
136
|
}
|
|
63
137
|
}
|
|
138
|
+
clearGlobalSsoAuthorizationCaches();
|
|
64
139
|
return { updateBy, carryForward: null };
|
|
65
140
|
}
|
|
66
141
|
}
|
|
142
|
+
__decorate([
|
|
143
|
+
CaptureSpan(),
|
|
144
|
+
__metadata("design:type", Function),
|
|
145
|
+
__metadata("design:paramtypes", [Object]),
|
|
146
|
+
__metadata("design:returntype", Promise)
|
|
147
|
+
], Service.prototype, "doesProviderGovernProject", null);
|
|
148
|
+
__decorate([
|
|
149
|
+
CaptureSpan(),
|
|
150
|
+
__metadata("design:type", Function),
|
|
151
|
+
__metadata("design:paramtypes", [Object]),
|
|
152
|
+
__metadata("design:returntype", Promise)
|
|
153
|
+
], Service.prototype, "onBeforeDelete", null);
|
|
154
|
+
__decorate([
|
|
155
|
+
CaptureSpan(),
|
|
156
|
+
__metadata("design:type", Function),
|
|
157
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
158
|
+
__metadata("design:returntype", Promise)
|
|
159
|
+
], Service.prototype, "onDeleteSuccess", null);
|
|
160
|
+
__decorate([
|
|
161
|
+
CaptureSpan(),
|
|
162
|
+
__metadata("design:type", Function),
|
|
163
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
164
|
+
__metadata("design:returntype", Promise)
|
|
165
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
166
|
+
__decorate([
|
|
167
|
+
CaptureSpan(),
|
|
168
|
+
__metadata("design:type", Function),
|
|
169
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
170
|
+
__metadata("design:returntype", Promise)
|
|
171
|
+
], Service.prototype, "onUpdateSuccess", null);
|
|
67
172
|
__decorate([
|
|
68
173
|
CaptureSpan(),
|
|
69
174
|
__metadata("design:type", Function),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalSsoProjectService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalSsoProjectService.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,8CAA8C,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAKlE,OAAO,WAAW,MAAM,gCAAgC,CAAC;AACzD,OAAO,kCAAkC,EAAE,EACzC,0BAA0B,GAC3B,MAAM,6CAA6C,CAAC;
|
|
1
|
+
{"version":3,"file":"GlobalSsoProjectService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalSsoProjectService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,136 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
1
10
|
import DatabaseService from "./DatabaseService";
|
|
2
11
|
import Model from "../../Models/DatabaseModels/GlobalSso";
|
|
12
|
+
import ObjectID from "../../Types/ObjectID";
|
|
13
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
|
+
import { GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS, clearGlobalSsoAuthorizationCaches, globalProviderCacheKey, globalSsoProviderTrustCache, loadTrustOnce, } from "../Utils/GlobalSsoAuthorization";
|
|
3
15
|
export class Service extends DatabaseService {
|
|
4
16
|
constructor() {
|
|
5
17
|
super(Model);
|
|
6
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* What the SSO-enforcement middleware needs to know about this provider:
|
|
21
|
+
* whether it is still usable at all, and whether the admin opted it into
|
|
22
|
+
* attachment-scoped access.
|
|
23
|
+
*
|
|
24
|
+
* Called on every authenticated request against an SSO-enforced project, so
|
|
25
|
+
* the answer is cached for 60s and concurrent misses share one query.
|
|
26
|
+
* Without this lookup, turning a provider off leaves every token it ever
|
|
27
|
+
* issued working until each one expires - up to thirty days.
|
|
28
|
+
*/
|
|
29
|
+
async getProviderTrust(providerId) {
|
|
30
|
+
const key = globalProviderCacheKey("sso", providerId);
|
|
31
|
+
const cached = globalSsoProviderTrustCache.get(key);
|
|
32
|
+
if (cached !== undefined) {
|
|
33
|
+
return cached;
|
|
34
|
+
}
|
|
35
|
+
return loadTrustOnce(key, async () => {
|
|
36
|
+
const provider = await this.findOneBy({
|
|
37
|
+
query: { _id: providerId.toString() },
|
|
38
|
+
select: {
|
|
39
|
+
_id: true,
|
|
40
|
+
isEnabled: true,
|
|
41
|
+
restrictToAttachedProjects: true,
|
|
42
|
+
},
|
|
43
|
+
props: { isRoot: true },
|
|
44
|
+
});
|
|
45
|
+
/*
|
|
46
|
+
* A deleted provider and a disabled one are the same answer: no. Both
|
|
47
|
+
* are cached, so a revoked provider does not cost a query per request.
|
|
48
|
+
*/
|
|
49
|
+
const trust = {
|
|
50
|
+
isUsable: Boolean(provider && provider.isEnabled),
|
|
51
|
+
restrictToAttachedProjects: Boolean(provider && provider.restrictToAttachedProjects),
|
|
52
|
+
};
|
|
53
|
+
globalSsoProviderTrustCache.set(key, trust, GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS);
|
|
54
|
+
return trust;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/*
|
|
58
|
+
* Cache invalidation runs in the SUCCESS hooks, not the before-hooks: a
|
|
59
|
+
* clear that happens before the row is written can be immediately re-filled
|
|
60
|
+
* with the pre-change answer by a concurrent request, which would hand a
|
|
61
|
+
* disabled provider another full TTL of life on the very node that served
|
|
62
|
+
* the disable. Clearing in both is deliberate - the before-hook narrows the
|
|
63
|
+
* window, the success hook closes it.
|
|
64
|
+
*
|
|
65
|
+
* These caches are per-process, so the hooks make a change immediate on the
|
|
66
|
+
* node that served it and the TTL bounds every other node.
|
|
67
|
+
*/
|
|
68
|
+
async onBeforeUpdate(updateBy) {
|
|
69
|
+
clearGlobalSsoAuthorizationCaches();
|
|
70
|
+
return { updateBy, carryForward: null };
|
|
71
|
+
}
|
|
72
|
+
async onUpdateSuccess(onUpdate, _updatedItemIds) {
|
|
73
|
+
clearGlobalSsoAuthorizationCaches();
|
|
74
|
+
return onUpdate;
|
|
75
|
+
}
|
|
76
|
+
async onBeforeDelete(deleteBy) {
|
|
77
|
+
clearGlobalSsoAuthorizationCaches();
|
|
78
|
+
return { deleteBy, carryForward: null };
|
|
79
|
+
}
|
|
80
|
+
async onDeleteSuccess(onDelete, _itemIdsBeforeDelete) {
|
|
81
|
+
clearGlobalSsoAuthorizationCaches();
|
|
82
|
+
return onDelete;
|
|
83
|
+
}
|
|
84
|
+
async onBeforeCreate(createBy) {
|
|
85
|
+
clearGlobalSsoAuthorizationCaches();
|
|
86
|
+
return { createBy, carryForward: null };
|
|
87
|
+
}
|
|
88
|
+
async onCreateSuccess(_onCreate, createdItem) {
|
|
89
|
+
clearGlobalSsoAuthorizationCaches();
|
|
90
|
+
return createdItem;
|
|
91
|
+
}
|
|
7
92
|
}
|
|
93
|
+
__decorate([
|
|
94
|
+
CaptureSpan(),
|
|
95
|
+
__metadata("design:type", Function),
|
|
96
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
97
|
+
__metadata("design:returntype", Promise)
|
|
98
|
+
], Service.prototype, "getProviderTrust", null);
|
|
99
|
+
__decorate([
|
|
100
|
+
CaptureSpan(),
|
|
101
|
+
__metadata("design:type", Function),
|
|
102
|
+
__metadata("design:paramtypes", [Object]),
|
|
103
|
+
__metadata("design:returntype", Promise)
|
|
104
|
+
], Service.prototype, "onBeforeUpdate", null);
|
|
105
|
+
__decorate([
|
|
106
|
+
CaptureSpan(),
|
|
107
|
+
__metadata("design:type", Function),
|
|
108
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
109
|
+
__metadata("design:returntype", Promise)
|
|
110
|
+
], Service.prototype, "onUpdateSuccess", null);
|
|
111
|
+
__decorate([
|
|
112
|
+
CaptureSpan(),
|
|
113
|
+
__metadata("design:type", Function),
|
|
114
|
+
__metadata("design:paramtypes", [Object]),
|
|
115
|
+
__metadata("design:returntype", Promise)
|
|
116
|
+
], Service.prototype, "onBeforeDelete", null);
|
|
117
|
+
__decorate([
|
|
118
|
+
CaptureSpan(),
|
|
119
|
+
__metadata("design:type", Function),
|
|
120
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
121
|
+
__metadata("design:returntype", Promise)
|
|
122
|
+
], Service.prototype, "onDeleteSuccess", null);
|
|
123
|
+
__decorate([
|
|
124
|
+
CaptureSpan(),
|
|
125
|
+
__metadata("design:type", Function),
|
|
126
|
+
__metadata("design:paramtypes", [Object]),
|
|
127
|
+
__metadata("design:returntype", Promise)
|
|
128
|
+
], Service.prototype, "onBeforeCreate", null);
|
|
129
|
+
__decorate([
|
|
130
|
+
CaptureSpan(),
|
|
131
|
+
__metadata("design:type", Function),
|
|
132
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
133
|
+
__metadata("design:returntype", Promise)
|
|
134
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
8
135
|
export default new Service();
|
|
9
136
|
//# sourceMappingURL=GlobalSsoService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalSsoService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalSsoService.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"GlobalSsoService.js","sourceRoot":"","sources":["../../../../Server/Services/GlobalSsoService.ts"],"names":[],"mappings":"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"}
|
|
@@ -96,10 +96,10 @@ export class Service extends DatabaseService {
|
|
|
96
96
|
* create response for it to confirm the address the way a user would.
|
|
97
97
|
*
|
|
98
98
|
* It is gated on an environment variable that is unset in every shipped
|
|
99
|
-
* config and set true ONLY in the CI e2e
|
|
100
|
-
* through
|
|
101
|
-
* In production the flag is absent,
|
|
102
|
-
* never leaves the mail path.
|
|
99
|
+
* config and set true ONLY in the CI e2e jobs (docker-compose passes it
|
|
100
|
+
* through; both SaaS e2e jobs set it — test-release.yaml for master and
|
|
101
|
+
* release.yml for the release branch). In production the flag is absent,
|
|
102
|
+
* this branch never runs, and the code never leaves the mail path.
|
|
103
103
|
*/
|
|
104
104
|
if (process.env["EXPOSE_VERIFICATION_CODE_IN_API_RESPONSE_FOR_E2E"] ===
|
|
105
105
|
"true") {
|
|
@@ -23,6 +23,66 @@ export default class CronTab {
|
|
|
23
23
|
throw new BadDataException(`Invalid cron expression: ${crontab}`);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Longest gap (in seconds) between two consecutive runs of this cron.
|
|
28
|
+
*
|
|
29
|
+
* Used to reason about how much data an evaluation window can possibly
|
|
30
|
+
* contain: a monitor polled once every five minutes produces at most one
|
|
31
|
+
* sample per five minutes, so "all values over the last 5 minutes" can
|
|
32
|
+
* never be backed by more than one sample. Callers use this to decide
|
|
33
|
+
* whether a window is actually covered by data or is merely still
|
|
34
|
+
* filling up.
|
|
35
|
+
*
|
|
36
|
+
* The *longest* gap is deliberate. Irregular expressions (say
|
|
37
|
+
* `0,1,30 * * * *`) have both very short and very long gaps; taking the
|
|
38
|
+
* shortest would make callers demand data at a cadence the cron does not
|
|
39
|
+
* actually deliver, and they would wait forever.
|
|
40
|
+
*
|
|
41
|
+
* Returns null when the expression is missing or unparseable so callers
|
|
42
|
+
* can fall back to inferring the cadence from the data itself.
|
|
43
|
+
*/
|
|
44
|
+
static getIntervalInSeconds(crontab, referenceDate) {
|
|
45
|
+
if (!crontab) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const interval = CronParser.parseExpression(crontab, {
|
|
50
|
+
currentDate: referenceDate || new Date(),
|
|
51
|
+
});
|
|
52
|
+
/*
|
|
53
|
+
* Six executions -> five gaps. Enough to cover a full hour-wrap for
|
|
54
|
+
* every interval offered in the UI without walking the schedule far
|
|
55
|
+
* into the future.
|
|
56
|
+
*/
|
|
57
|
+
const executionTimes = [];
|
|
58
|
+
for (let i = 0; i < 6; i++) {
|
|
59
|
+
executionTimes.push(interval.next().toDate());
|
|
60
|
+
}
|
|
61
|
+
let longestGapInSeconds = 0;
|
|
62
|
+
for (let i = 1; i < executionTimes.length; i++) {
|
|
63
|
+
const gapInSeconds = (executionTimes[i].getTime() - executionTimes[i - 1].getTime()) /
|
|
64
|
+
1000;
|
|
65
|
+
if (gapInSeconds > longestGapInSeconds) {
|
|
66
|
+
longestGapInSeconds = gapInSeconds;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (longestGapInSeconds <= 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return longestGapInSeconds;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
/*
|
|
76
|
+
* Debug rather than error: this runs on the criteria-evaluation hot
|
|
77
|
+
* path, and monitors created before the interval was a cron (or
|
|
78
|
+
* through a Terraform example using the "Every 5 minutes" label) would
|
|
79
|
+
* otherwise log on every single check. Callers treat null as "cadence
|
|
80
|
+
* unknown" and fall back to inferring it from the data.
|
|
81
|
+
*/
|
|
82
|
+
logger.debug(error);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
26
86
|
}
|
|
27
87
|
__decorate([
|
|
28
88
|
CaptureSpan(),
|
|
@@ -30,4 +90,10 @@ __decorate([
|
|
|
30
90
|
__metadata("design:paramtypes", [String]),
|
|
31
91
|
__metadata("design:returntype", Date)
|
|
32
92
|
], CronTab, "getNextExecutionTime", null);
|
|
93
|
+
__decorate([
|
|
94
|
+
CaptureSpan(),
|
|
95
|
+
__metadata("design:type", Function),
|
|
96
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
97
|
+
__metadata("design:returntype", Object)
|
|
98
|
+
], CronTab, "getIntervalInSeconds", null);
|
|
33
99
|
//# sourceMappingURL=CronTab.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronTab.js","sourceRoot":"","sources":["../../../../Server/Utils/CronTab.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AACtE,OAAO,UAA8B,MAAM,aAAa,CAAC;AACzD,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAElD,MAAM,CAAC,OAAO,OAAO,OAAO;IAEZ,AAAP,MAAM,CAAC,oBAAoB,CAAC,OAAe;QAChD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAmB,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACrE,MAAM,iBAAiB,GAAS,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACzD,OAAO,iBAAiB,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,IAAI,gBAAgB,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"CronTab.js","sourceRoot":"","sources":["../../../../Server/Utils/CronTab.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AACtE,OAAO,UAA8B,MAAM,aAAa,CAAC;AACzD,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,WAAW,MAAM,yBAAyB,CAAC;AAElD,MAAM,CAAC,OAAO,OAAO,OAAO;IAEZ,AAAP,MAAM,CAAC,oBAAoB,CAAC,OAAe;QAChD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAmB,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACrE,MAAM,iBAAiB,GAAS,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACzD,OAAO,iBAAiB,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,IAAI,gBAAgB,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IAEW,AAAP,MAAM,CAAC,oBAAoB,CAChC,OAAkC,EAClC,aAAgC;QAEhC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAmB,UAAU,CAAC,eAAe,CAAC,OAAO,EAAE;gBACnE,WAAW,EAAE,aAAa,IAAI,IAAI,IAAI,EAAE;aACzC,CAAC,CAAC;YAEH;;;;eAIG;YACH,MAAM,cAAc,GAAgB,EAAE,CAAC;YAEvC,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YAChD,CAAC;YAED,IAAI,mBAAmB,GAAW,CAAC,CAAC;YAEpC,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvD,MAAM,YAAY,GAChB,CAAC,cAAc,CAAC,CAAC,CAAE,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,OAAO,EAAE,CAAC;oBACjE,IAAI,CAAC;gBAEP,IAAI,YAAY,GAAG,mBAAmB,EAAE,CAAC;oBACvC,mBAAmB,GAAG,YAAY,CAAC;gBACrC,CAAC;YACH,CAAC;YAED,IAAI,mBAAmB,IAAI,CAAC,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,mBAAmB,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf;;;;;;eAMG;YACH,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAnFe;IADb,WAAW,EAAE;;;oCACuC,IAAI;yCASxD;AAqBa;IADb,WAAW,EAAE;;;;yCAqDb"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
|
|
2
|
+
/*
|
|
3
|
+
* The stateful half of Global SSO enforcement.
|
|
4
|
+
*
|
|
5
|
+
* A Global SSO/OIDC token is a 30-day, self-contained JWT with no project
|
|
6
|
+
* binding, so on its own it answers only "this person authenticated against
|
|
7
|
+
* SOME instance-wide identity provider at some point in the last month". Two
|
|
8
|
+
* questions it cannot answer:
|
|
9
|
+
*
|
|
10
|
+
* 1. IS THE PROVIDER STILL TRUSTED? Turning a provider off, or deleting it,
|
|
11
|
+
* has to actually cut off access. Without a check at request time the
|
|
12
|
+
* "Enabled" toggle does nothing to anyone already signed in, for up to
|
|
13
|
+
* thirty days. This check is UNCONDITIONAL - "disabled" has only one
|
|
14
|
+
* possible meaning.
|
|
15
|
+
*
|
|
16
|
+
* 2. DOES THE PROVIDER GOVERN THIS PROJECT? Deliberately OPT-IN, per
|
|
17
|
+
* provider, via `restrictToAttachedProjects`. The attachment rows
|
|
18
|
+
* (GlobalSsoProject / GlobalOidcProject) were introduced as the
|
|
19
|
+
* PROVISIONING allow-list - "a SAML assertion can only ever provision a
|
|
20
|
+
* user into projects that a master admin has explicitly attached here",
|
|
21
|
+
* per the model's own docstring - and the login routers gate a session on
|
|
22
|
+
* membership of ANY project, not of an attached one. Reading attachments
|
|
23
|
+
* as an access boundary by default would therefore lock existing users
|
|
24
|
+
* out of projects they legitimately reach today, immediately on upgrade,
|
|
25
|
+
* with no way to recover from inside the product. So it stays off unless
|
|
26
|
+
* an admin asks for it.
|
|
27
|
+
*
|
|
28
|
+
* Both answers come from Postgres and run on every authenticated request
|
|
29
|
+
* against an SSO-enforced project, so both are cached in-process for 60
|
|
30
|
+
* seconds, and concurrent misses share one query.
|
|
31
|
+
*/
|
|
32
|
+
export const GLOBAL_SSO_AUTHORIZATION_CACHE_TTL_MS = 60000;
|
|
33
|
+
/*
|
|
34
|
+
* Absence of an entry means "not yet looked up", which is why these are read
|
|
35
|
+
* with an explicit `undefined` check rather than a truthiness test: a cached
|
|
36
|
+
* "this provider is disabled" must not be mistaken for a cache miss and
|
|
37
|
+
* re-queried on every single request.
|
|
38
|
+
*/
|
|
39
|
+
export const globalSsoProviderTrustCache = new InMemoryTTLCache(10000);
|
|
40
|
+
export const globalSsoAttachmentsCache = new InMemoryTTLCache(10000);
|
|
41
|
+
/*
|
|
42
|
+
* Namespaced by kind. A Global SSO provider and a Global OIDC provider are
|
|
43
|
+
* different rows in different tables and could in principle share an id;
|
|
44
|
+
* collapsing the keys would let one vouch for the other.
|
|
45
|
+
*/
|
|
46
|
+
export function globalProviderCacheKey(providerKind, providerId) {
|
|
47
|
+
return `${providerKind}:${providerId.toString()}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Decides whether a provider's attachments cover `projectId`, for a provider
|
|
51
|
+
* that has opted into attachment-scoped access.
|
|
52
|
+
*
|
|
53
|
+
* A provider with no attachment rows at all is instance-wide, matching the
|
|
54
|
+
* "default-all" reading the login routers use. A provider that HAS attachment
|
|
55
|
+
* rows governs exactly the enabled ones - so disabling them all denies rather
|
|
56
|
+
* than widens.
|
|
57
|
+
*/
|
|
58
|
+
export function doAttachmentsGovernProject(attachments, projectId) {
|
|
59
|
+
if (!attachments.hasAnyAttachmentRows) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return attachments.enabledProjectIds.includes(projectId.toString());
|
|
63
|
+
}
|
|
64
|
+
/** Drops every cached answer. Used by the write hooks and by tests. */
|
|
65
|
+
export function clearGlobalSsoAuthorizationCaches() {
|
|
66
|
+
globalSsoProviderTrustCache.clear();
|
|
67
|
+
globalSsoAttachmentsCache.clear();
|
|
68
|
+
inFlightTrustLookups.clear();
|
|
69
|
+
inFlightAttachmentLookups.clear();
|
|
70
|
+
}
|
|
71
|
+
/*
|
|
72
|
+
* In-flight de-duplication.
|
|
73
|
+
*
|
|
74
|
+
* The multi-tenant permission path fans out over every project the user
|
|
75
|
+
* belongs to CONCURRENTLY. Without this, a cold cache means N simultaneous
|
|
76
|
+
* copies of the same two queries - for a user in fifty projects, a hundred
|
|
77
|
+
* queries where two would do. Worse, failures are never cached, so a database
|
|
78
|
+
* that is already struggling gets the full fan-out again on every request.
|
|
79
|
+
*
|
|
80
|
+
* Sharing the promise collapses all of that to one query per provider, and a
|
|
81
|
+
* rejection is shared too rather than being retried N times in the same tick.
|
|
82
|
+
*/
|
|
83
|
+
const inFlightTrustLookups = new Map();
|
|
84
|
+
const inFlightAttachmentLookups = new Map();
|
|
85
|
+
async function loadOnce(inFlight, key, load) {
|
|
86
|
+
const existing = inFlight.get(key);
|
|
87
|
+
if (existing) {
|
|
88
|
+
return existing;
|
|
89
|
+
}
|
|
90
|
+
const pending = load().finally(() => {
|
|
91
|
+
/*
|
|
92
|
+
* Only clear the slot if it is still OURS. A cache clear between the two
|
|
93
|
+
* (every write to a Global SSO/OIDC service does exactly that, twice) lets
|
|
94
|
+
* a NEWER lookup take the key while this one is still on the wire; a blind
|
|
95
|
+
* delete would evict that newer entry when this one settles, and the fan-
|
|
96
|
+
* out that follows would stop de-duplicating - the one situation this
|
|
97
|
+
* exists for.
|
|
98
|
+
*/
|
|
99
|
+
if (inFlight.get(key) === pending) {
|
|
100
|
+
inFlight.delete(key);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
inFlight.set(key, pending);
|
|
104
|
+
return pending;
|
|
105
|
+
}
|
|
106
|
+
export function loadTrustOnce(key, load) {
|
|
107
|
+
return loadOnce(inFlightTrustLookups, key, load);
|
|
108
|
+
}
|
|
109
|
+
export function loadAttachmentsOnce(key, load) {
|
|
110
|
+
return loadOnce(inFlightAttachmentLookups, key, load);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=GlobalSsoAuthorization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalSsoAuthorization.js","sourceRoot":"","sources":["../../../../Server/Utils/GlobalSsoAuthorization.ts"],"names":[],"mappings":"AACA,OAAO,gBAAgB,MAAM,oCAAoC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,CAAC,MAAM,qCAAqC,GAAW,KAAM,CAAC;AAUpE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GACtC,IAAI,gBAAgB,CAAC,KAAM,CAAC,CAAC;AAe/B,MAAM,CAAC,MAAM,yBAAyB,GACpC,IAAI,gBAAgB,CAAC,KAAM,CAAC,CAAC;AAI/B;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,YAAgC,EAChC,UAAoB;IAEpB,OAAO,GAAG,YAAY,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,WAAsC,EACtC,SAAmB;IAEnB,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,iCAAiC;IAC/C,2BAA2B,CAAC,KAAK,EAAE,CAAC;IACpC,yBAAyB,CAAC,KAAK,EAAE,CAAC;IAClC,oBAAoB,CAAC,KAAK,EAAE,CAAC;IAC7B,yBAAyB,CAAC,KAAK,EAAE,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,oBAAoB,GAGtB,IAAI,GAAG,EAAE,CAAC;AACd,MAAM,yBAAyB,GAG3B,IAAI,GAAG,EAAE,CAAC;AAEd,KAAK,UAAU,QAAQ,CACrB,QAAiC,EACjC,GAAW,EACX,IAAsB;IAEtB,MAAM,QAAQ,GAA2B,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE3D,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAe,IAAI,EAAE,CAAC,OAAO,CAAC,GAAS,EAAE;QACpD;;;;;;;WAOG;QACH,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC;YAClC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAE3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,IAAwC;IAExC,OAAO,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,IAA8C;IAE9C,OAAO,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AACxD,CAAC"}
|