@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.
Files changed (195) hide show
  1. package/Models/DatabaseModels/GlobalOidc.ts +20 -0
  2. package/Models/DatabaseModels/GlobalSso.ts +20 -0
  3. package/Models/DatabaseModels/MarketingConversion.ts +19 -9
  4. package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +46 -0
  5. package/Models/DatabaseModels/StatusPage.ts +7 -4
  6. package/Server/API/StatusPageAPI.ts +29 -4
  7. package/Server/EnvironmentConfig.ts +7 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.ts +19 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.ts +40 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  11. package/Server/Middleware/SlackAuthorization.ts +43 -6
  12. package/Server/Middleware/UserAuthorization.ts +236 -26
  13. package/Server/Middleware/WhatsAppAuthorization.ts +43 -3
  14. package/Server/Services/GlobalOidcProjectService.ts +126 -1
  15. package/Server/Services/GlobalOidcService.ts +132 -0
  16. package/Server/Services/GlobalSsoProjectService.ts +126 -1
  17. package/Server/Services/GlobalSsoService.ts +132 -0
  18. package/Server/Services/UserEmailService.ts +4 -4
  19. package/Server/Utils/CronTab.ts +73 -0
  20. package/Server/Utils/GlobalSsoAuthorization.ts +175 -0
  21. package/Server/Utils/Marketing/ConversionUploadProvider.ts +35 -5
  22. package/Server/Utils/Marketing/Providers/GoogleAds.ts +1 -1
  23. package/Server/Utils/Marketing/Providers/LinkedIn.ts +1 -1
  24. package/Server/Utils/Marketing/Providers/Meta.ts +1 -1
  25. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +1 -1
  26. package/Server/Utils/Marketing/Providers/Reddit.ts +1 -1
  27. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +48 -33
  28. package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +35 -30
  29. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +33 -28
  30. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +475 -47
  31. package/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.ts +35 -30
  32. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +34 -28
  33. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +33 -28
  34. package/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.ts +69 -40
  35. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +35 -29
  36. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +8 -0
  37. package/Server/Utils/Monitor/MonitorResource.ts +161 -21
  38. package/Server/Utils/StatusPageContentSecurityPolicy.ts +56 -0
  39. package/Server/Utils/StatusPageCustomizationAccess.ts +117 -0
  40. package/Tests/Server/API/StatusPageCustomizationOrigin.test.ts +348 -0
  41. package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +9 -59
  42. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +227 -0
  43. package/Tests/Server/Middleware/SlackAuthorization.test.ts +149 -0
  44. package/Tests/Server/Middleware/UserAuthorization.test.ts +27 -13
  45. package/Tests/Server/Middleware/UserAuthorizationGlobalSsoGovernance.test.ts +1455 -0
  46. package/Tests/Server/Middleware/UserAuthorizationSSOProvider.test.ts +91 -2
  47. package/Tests/Server/Middleware/WhatsAppAuthorization.test.ts +233 -0
  48. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +21 -8
  49. package/Tests/Server/Services/GlobalSsoProviderAuthorization.test.ts +1242 -0
  50. package/Tests/Server/Services/MonitorResourceProbeAgreementHydration.test.ts +459 -0
  51. package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +10 -0
  52. package/Tests/Server/Types/AnalyticsDatabase/AggregateUtilBucketTimestamp.test.ts +416 -0
  53. package/Tests/Server/Types/Database/QueryHelperManyToManyAndEmptyValues.test.ts +551 -0
  54. package/Tests/Server/Types/Database/SelectUtil.test.ts +348 -0
  55. package/Tests/Server/Utils/CronTab.test.ts +116 -0
  56. package/Tests/Server/Utils/GlobalSSOToken.test.ts +581 -0
  57. package/Tests/Server/Utils/GlobalSsoAuthorization.test.ts +1401 -0
  58. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +254 -0
  59. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +1 -1
  60. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +508 -0
  61. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +30 -9
  62. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +987 -0
  63. package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +916 -0
  64. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +382 -0
  65. package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +1219 -0
  66. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +86 -0
  67. package/Tests/Server/Utils/StatusPageContentSecurityPolicy.test.ts +136 -0
  68. package/Tests/Server/Utils/StatusPageCustomizationAccess.test.ts +223 -0
  69. package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +165 -0
  70. package/Tests/Types/NetworkDevice/NetworkDeviceLinkRuleScope.test.ts +215 -0
  71. package/Tests/UI/Components/Forms/FormSubmitAnalytics.test.tsx +206 -0
  72. package/Tests/UI/Utils/AIChatExport/ConversationMarkdown.test.ts +774 -0
  73. package/Tests/UI/Utils/AIChatExport/MarkdownBlocks.test.ts +791 -0
  74. package/Tests/UI/Utils/AIChatExport/MarkdownSafety.test.ts +544 -0
  75. package/Tests/Utils/Analytics.test.ts +187 -0
  76. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +80 -0
  77. package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +1291 -0
  78. package/Tests/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.test.ts +214 -0
  79. package/Types/Marketing/MarketingConversion.ts +12 -0
  80. package/Types/Monitor/CriteriaFilter.ts +9 -0
  81. package/Types/NetworkDevice/NetworkDeviceLinkRuleScope.ts +51 -0
  82. package/UI/Components/FormModal/BasicFormModal.tsx +12 -0
  83. package/UI/Components/Forms/BasicForm.tsx +13 -1
  84. package/UI/Components/Forms/BasicModelForm.tsx +2 -1
  85. package/UI/Components/Forms/ModelForm.tsx +10 -1
  86. package/UI/Components/Forms/Utils/FormAnalyticsName.ts +39 -0
  87. package/UI/Components/ModelFormModal/ModelFormModal.tsx +6 -1
  88. package/Utils/Analytics.ts +55 -2
  89. package/Utils/Monitor/MonitorMetricType.ts +40 -0
  90. package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +587 -37
  91. package/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.ts +115 -0
  92. package/build/dist/Models/DatabaseModels/GlobalOidc.js +21 -0
  93. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  94. package/build/dist/Models/DatabaseModels/GlobalSso.js +21 -0
  95. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  96. package/build/dist/Models/DatabaseModels/MarketingConversion.js +20 -10
  97. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -1
  98. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +47 -0
  99. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -1
  100. package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
  101. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  102. package/build/dist/Server/API/StatusPageAPI.js +25 -4
  103. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  104. package/build/dist/Server/EnvironmentConfig.js +6 -0
  105. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  106. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js +12 -0
  107. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js.map +1 -0
  108. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js +29 -0
  109. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js.map +1 -0
  110. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  111. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  112. package/build/dist/Server/Middleware/SlackAuthorization.js +28 -4
  113. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  114. package/build/dist/Server/Middleware/UserAuthorization.js +197 -22
  115. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  116. package/build/dist/Server/Middleware/WhatsAppAuthorization.js +32 -2
  117. package/build/dist/Server/Middleware/WhatsAppAuthorization.js.map +1 -1
  118. package/build/dist/Server/Services/GlobalOidcProjectService.js +105 -0
  119. package/build/dist/Server/Services/GlobalOidcProjectService.js.map +1 -1
  120. package/build/dist/Server/Services/GlobalOidcService.js +127 -0
  121. package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
  122. package/build/dist/Server/Services/GlobalSsoProjectService.js +105 -0
  123. package/build/dist/Server/Services/GlobalSsoProjectService.js.map +1 -1
  124. package/build/dist/Server/Services/GlobalSsoService.js +127 -0
  125. package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
  126. package/build/dist/Server/Services/UserEmailService.js +4 -4
  127. package/build/dist/Server/Utils/CronTab.js +66 -0
  128. package/build/dist/Server/Utils/CronTab.js.map +1 -1
  129. package/build/dist/Server/Utils/GlobalSsoAuthorization.js +112 -0
  130. package/build/dist/Server/Utils/GlobalSsoAuthorization.js.map +1 -0
  131. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +17 -1
  132. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -1
  133. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +1 -1
  134. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -1
  135. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +1 -1
  136. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -1
  137. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +1 -1
  138. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -1
  139. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +1 -1
  140. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -1
  141. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +1 -1
  142. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -1
  143. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +37 -35
  144. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  145. package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +21 -25
  146. package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -1
  147. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +20 -22
  148. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  149. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +370 -42
  150. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  151. package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js +21 -25
  152. package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js.map +1 -1
  153. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +21 -25
  154. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  155. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +21 -25
  156. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  157. package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js +64 -52
  158. package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js.map +1 -1
  159. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +25 -29
  160. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  161. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +8 -0
  162. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  163. package/build/dist/Server/Utils/Monitor/MonitorResource.js +123 -23
  164. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  165. package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js +39 -0
  166. package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js.map +1 -0
  167. package/build/dist/Server/Utils/StatusPageCustomizationAccess.js +85 -0
  168. package/build/dist/Server/Utils/StatusPageCustomizationAccess.js.map +1 -0
  169. package/build/dist/Types/Marketing/MarketingConversion.js +10 -0
  170. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -1
  171. package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
  172. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  173. package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js +46 -0
  174. package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js.map +1 -0
  175. package/build/dist/UI/Components/FormModal/BasicFormModal.js +2 -1
  176. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  177. package/build/dist/UI/Components/Forms/BasicForm.js +10 -1
  178. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  179. package/build/dist/UI/Components/Forms/BasicModelForm.js +2 -1
  180. package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
  181. package/build/dist/UI/Components/Forms/ModelForm.js +4 -1
  182. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  183. package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js +33 -0
  184. package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js.map +1 -0
  185. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +2 -1
  186. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  187. package/build/dist/Utils/Analytics.js +50 -2
  188. package/build/dist/Utils/Analytics.js.map +1 -1
  189. package/build/dist/Utils/Monitor/MonitorMetricType.js +37 -0
  190. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  191. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +318 -37
  192. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -1
  193. package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js +87 -0
  194. package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js.map +1 -0
  195. 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;AAE3D,MAAM,OAAO,OAAQ,SAAQ,eAAsB;IACjD;QACE,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;CACF;AAED,eAAe,IAAI,OAAO,EAAE,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;AAErD,MAAM,OAAO,OAAQ,SAAQ,eAAsB;IACjD;QACE,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAGwB,AAAN,KAAK,CAAC,cAAc,CACrC,QAAyB;QAEzB;;;;WAIG;QACH,MAAM,SAAS,GAAyB,0BAA0B,CAChE,QAAQ,CAAC,IAAI,CACd,CAAC;QAEF,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QACtC,CAAC;QAED,MAAM,kCAAkC,CAAC;YACvC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK;YAC1B,SAAS;SACV,CAAC,CAAC;QAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IAGwB,AAAN,KAAK,CAAC,cAAc,CACrC,QAAyB;QAEzB,0EAA0E;QAC1E,MAAM,KAAK,GAA4B,QAAQ,CAAC,IAAI,CAAC,KAExC,CAAC;QAEd,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,iBAAiB,GAAyB,QAAQ,CAAC,IAAI;iBAC1D,SAA4C,CAAC;YAEhD,IAAI,iBAAiB,EAAE,CAAC;gBACtB,MAAM,kCAAkC,CAAC;oBACvC,KAAK;oBACL,SAAS,EAAE,iBAAiB;iBAC7B,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,yEAAyE;gBACzE,MAAM,IAAI,GAAiB,MAAM,IAAI,CAAC,MAAM,CAAC;oBAC3C,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;oBACtC,KAAK,EAAE,iBAAiB;oBACxB,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;iBACxB,CAAC,CAAC;gBAEH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,kCAAkC,CAAC;wBACvC,KAAK;wBACL,SAAS,EAAE,GAAG,CAAC,SAAS;qBACzB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;CACF;AA/D0B;IADxB,WAAW,EAAE;;;;6CAuBb;AAGwB;IADxB,WAAW,EAAE;;;;6CAsCb;AAGH,eAAe,IAAI,OAAO,EAAE,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;AAE1D,MAAM,OAAO,OAAQ,SAAQ,eAAsB;IACjD;QACE,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;CACF;AAED,eAAe,IAAI,OAAO,EAAE,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 job (docker-compose passes it
100
- * through, .github/workflows/test-release.yaml sets it for the SaaS run).
101
- * In production the flag is absent, this branch never runs, and the code
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;AAVe;IADb,WAAW,EAAE;;;oCACuC,IAAI;yCASxD"}
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"}