@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
|
@@ -24,6 +24,7 @@ import MonitorType, {
|
|
|
24
24
|
} from "../../../Types/Monitor/MonitorType";
|
|
25
25
|
import ServerMonitorResponse from "../../../Types/Monitor/ServerMonitor/ServerMonitorResponse";
|
|
26
26
|
import ObjectID from "../../../Types/ObjectID";
|
|
27
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
27
28
|
import ProbeApiIngestResponse from "../../../Types/Probe/ProbeApiIngestResponse";
|
|
28
29
|
import ProbeMonitorResponse from "../../../Types/Probe/ProbeMonitorResponse";
|
|
29
30
|
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
@@ -141,6 +142,13 @@ export default class MonitorResourceUtil {
|
|
|
141
142
|
_id: true,
|
|
142
143
|
name: true,
|
|
143
144
|
minimumProbeAgreement: true,
|
|
145
|
+
/*
|
|
146
|
+
* How often this monitor is checked. Over-time criteria filters need
|
|
147
|
+
* it to work out how many samples a fully covered evaluation window
|
|
148
|
+
* should hold - without it a monitor that has only just started
|
|
149
|
+
* looks the same as one whose whole window is breaching.
|
|
150
|
+
*/
|
|
151
|
+
monitoringInterval: true,
|
|
144
152
|
/*
|
|
145
153
|
* Recorded as oneuptime.label.* / oneuptime.customField.* attributes on
|
|
146
154
|
* every monitor metric this result produces, so response time and
|
|
@@ -737,6 +745,7 @@ export default class MonitorResourceUtil {
|
|
|
737
745
|
monitorStep: monitorStep,
|
|
738
746
|
currentCriteriaMetId: response.criteriaMetId || null,
|
|
739
747
|
currentRootCause: response.rootCause || null,
|
|
748
|
+
currentProbeId: (dataToProcess as ProbeMonitorResponse).probeId,
|
|
740
749
|
monitorProbes: monitorProbesForMonitor || undefined,
|
|
741
750
|
});
|
|
742
751
|
|
|
@@ -1238,12 +1247,115 @@ export default class MonitorResourceUtil {
|
|
|
1238
1247
|
}
|
|
1239
1248
|
}
|
|
1240
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* Turn a probe response read back out of MonitorProbe.lastMonitoringLog
|
|
1252
|
+
* into one the criteria evaluators can actually use.
|
|
1253
|
+
*
|
|
1254
|
+
* The column stores `JSON.parse(JSON.stringify(response))`, which turns
|
|
1255
|
+
* every ObjectID into a plain `{ _type: "ObjectID", value: "..." }` object
|
|
1256
|
+
* and every Date into a string. Those plain objects are not `instanceof
|
|
1257
|
+
* ObjectID`, so the analytics query builder binds them as-is and the
|
|
1258
|
+
* "evaluate over time" lookup silently matches zero rows - which used to
|
|
1259
|
+
* be indistinguishable from "this monitor has no history" and sent the
|
|
1260
|
+
* evaluator down its instantaneous-value fallback. The result was a
|
|
1261
|
+
* decision that disagreed with the evaluation summary shown beside it.
|
|
1262
|
+
*/
|
|
1263
|
+
public static hydrateStoredProbeResponse(
|
|
1264
|
+
probeResponse: ProbeMonitorResponse,
|
|
1265
|
+
): ProbeMonitorResponse {
|
|
1266
|
+
const hydrated: ProbeMonitorResponse = {
|
|
1267
|
+
...probeResponse,
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
const toObjectID: (value: unknown) => ObjectID | undefined = (
|
|
1271
|
+
value: unknown,
|
|
1272
|
+
): ObjectID | undefined => {
|
|
1273
|
+
if (!value) {
|
|
1274
|
+
return undefined;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
if (value instanceof ObjectID) {
|
|
1278
|
+
return value;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if (typeof value === "string") {
|
|
1282
|
+
return new ObjectID(value);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
if (typeof value === "object") {
|
|
1286
|
+
const asJson: JSONObject = value as JSONObject;
|
|
1287
|
+
|
|
1288
|
+
if (asJson["value"]) {
|
|
1289
|
+
return new ObjectID(asJson["value"].toString());
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
return undefined;
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
const toDate: (value: unknown) => Date | undefined = (
|
|
1297
|
+
value: unknown,
|
|
1298
|
+
): Date | undefined => {
|
|
1299
|
+
if (!value) {
|
|
1300
|
+
return undefined;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
if (value instanceof Date) {
|
|
1304
|
+
return value;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
const parsed: Date = new Date(value as string);
|
|
1308
|
+
|
|
1309
|
+
return isNaN(parsed.getTime()) ? undefined : parsed;
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
const projectId: ObjectID | undefined = toObjectID(probeResponse.projectId);
|
|
1313
|
+
if (projectId) {
|
|
1314
|
+
hydrated.projectId = projectId;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
const monitorId: ObjectID | undefined = toObjectID(probeResponse.monitorId);
|
|
1318
|
+
if (monitorId) {
|
|
1319
|
+
hydrated.monitorId = monitorId;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
const monitorStepId: ObjectID | undefined = toObjectID(
|
|
1323
|
+
probeResponse.monitorStepId,
|
|
1324
|
+
);
|
|
1325
|
+
if (monitorStepId) {
|
|
1326
|
+
hydrated.monitorStepId = monitorStepId;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
const probeId: ObjectID | undefined = toObjectID(probeResponse.probeId);
|
|
1330
|
+
if (probeId) {
|
|
1331
|
+
hydrated.probeId = probeId;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
const monitoredAt: Date | undefined = toDate(probeResponse.monitoredAt);
|
|
1335
|
+
if (monitoredAt) {
|
|
1336
|
+
hydrated.monitoredAt = monitoredAt;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
const ingestedAt: Date | undefined = toDate(probeResponse.ingestedAt);
|
|
1340
|
+
if (ingestedAt) {
|
|
1341
|
+
hydrated.ingestedAt = ingestedAt;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
return hydrated;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1241
1347
|
@CaptureSpan()
|
|
1242
1348
|
private static async checkProbeAgreement(input: {
|
|
1243
1349
|
monitor: Monitor;
|
|
1244
1350
|
monitorStep: MonitorStep;
|
|
1245
1351
|
currentCriteriaMetId: string | null;
|
|
1246
1352
|
currentRootCause: string | null;
|
|
1353
|
+
/*
|
|
1354
|
+
* Probe that produced the result being handled right now. Its verdict is
|
|
1355
|
+
* already in currentCriteriaMetId / currentRootCause, so it is reused
|
|
1356
|
+
* rather than recomputed - see the loop below.
|
|
1357
|
+
*/
|
|
1358
|
+
currentProbeId?: ObjectID | undefined;
|
|
1247
1359
|
/*
|
|
1248
1360
|
* Pre-fetched MonitorProbe rows for this monitor (probeId, isEnabled,
|
|
1249
1361
|
* lastMonitoringLog, probe.name/connectionStatus). The probe-result hot
|
|
@@ -1342,30 +1454,58 @@ export default class MonitorResourceUtil {
|
|
|
1342
1454
|
continue;
|
|
1343
1455
|
}
|
|
1344
1456
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
monitorId: monitor.id!,
|
|
1348
|
-
criteriaMetId: undefined,
|
|
1349
|
-
rootCause: null,
|
|
1350
|
-
};
|
|
1457
|
+
let evaluatedCriteriaMetId: string | undefined = undefined;
|
|
1458
|
+
let evaluatedRootCause: string | null = null;
|
|
1351
1459
|
|
|
1352
|
-
const
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
};
|
|
1460
|
+
const isCurrentProbe: boolean = Boolean(
|
|
1461
|
+
input.currentProbeId &&
|
|
1462
|
+
monitorProbe.probeId?.toString() === input.currentProbeId.toString(),
|
|
1463
|
+
);
|
|
1357
1464
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1465
|
+
if (isCurrentProbe) {
|
|
1466
|
+
/*
|
|
1467
|
+
* The probe whose result we are handling right now was already
|
|
1468
|
+
* evaluated by the caller, and that evaluation is the one the user
|
|
1469
|
+
* sees in the evaluation summary. Re-running it here would evaluate
|
|
1470
|
+
* a *different* window for any "evaluate over time" filter - seconds
|
|
1471
|
+
* have passed, and this pass reads the payload back out of
|
|
1472
|
+
* lastMonitoringLog rather than using the live object. That is how
|
|
1473
|
+
* an incident could be created citing a criteria the summary right
|
|
1474
|
+
* next to it reported as not met.
|
|
1475
|
+
*/
|
|
1476
|
+
evaluatedCriteriaMetId = currentCriteriaMetId || undefined;
|
|
1477
|
+
evaluatedRootCause = currentRootCause;
|
|
1478
|
+
} else {
|
|
1479
|
+
// Evaluate this probe's response against criteria
|
|
1480
|
+
const tempResponse: ProbeApiIngestResponse = {
|
|
1481
|
+
monitorId: monitor.id!,
|
|
1482
|
+
criteriaMetId: undefined,
|
|
1483
|
+
rootCause: null,
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
const tempEvaluationSummary: MonitorEvaluationSummary = {
|
|
1487
|
+
evaluatedAt: OneUptimeDate.getCurrentDate(),
|
|
1488
|
+
criteriaResults: [],
|
|
1489
|
+
events: [],
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
const evaluatedResponse: ProbeApiIngestResponse =
|
|
1493
|
+
await MonitorCriteriaEvaluator.processMonitorStep({
|
|
1494
|
+
dataToProcess: MonitorResourceUtil.hydrateStoredProbeResponse(
|
|
1495
|
+
probeResponse,
|
|
1496
|
+
) as DataToProcess,
|
|
1497
|
+
monitorStep: monitorStep,
|
|
1498
|
+
monitor: monitor,
|
|
1499
|
+
probeApiIngestResponse: tempResponse,
|
|
1500
|
+
evaluationSummary: tempEvaluationSummary,
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1503
|
+
evaluatedCriteriaMetId = evaluatedResponse.criteriaMetId;
|
|
1504
|
+
evaluatedRootCause = evaluatedResponse.rootCause;
|
|
1505
|
+
}
|
|
1366
1506
|
|
|
1367
1507
|
// Record the result
|
|
1368
|
-
const criteriaKey: string =
|
|
1508
|
+
const criteriaKey: string = evaluatedCriteriaMetId || "none";
|
|
1369
1509
|
const existing:
|
|
1370
1510
|
| { count: number; rootCause: string | null; probeNames: Array<string> }
|
|
1371
1511
|
| undefined = criteriaAgreements.get(criteriaKey);
|
|
@@ -1379,7 +1519,7 @@ export default class MonitorResourceUtil {
|
|
|
1379
1519
|
} else {
|
|
1380
1520
|
criteriaAgreements.set(criteriaKey, {
|
|
1381
1521
|
count: 1,
|
|
1382
|
-
rootCause:
|
|
1522
|
+
rootCause: evaluatedRootCause,
|
|
1383
1523
|
probeNames: [probeName],
|
|
1384
1524
|
});
|
|
1385
1525
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ExpressRequest, ExpressResponse } from "./Express";
|
|
2
|
+
|
|
3
|
+
export const STATUS_PAGE_CONTENT_SECURITY_POLICY_HEADER_NAME: string =
|
|
4
|
+
"Content-Security-Policy";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Fallback status pages share the authenticated application's origin. Custom
|
|
8
|
+
* domains do not, so this policy is deliberately limited to documents served
|
|
9
|
+
* below /status-page on the application host/path.
|
|
10
|
+
*
|
|
11
|
+
* The status-page template currently contains inline script elements for its
|
|
12
|
+
* Tailwind configuration and optional Google Tag Manager bootstrap. Keeping
|
|
13
|
+
* 'unsafe-inline' in script-src lets those elements continue to run, while
|
|
14
|
+
* script-src-attr 'none' uses CSP3's more-specific directive to block inline
|
|
15
|
+
* event handlers such as <img onerror>. Omitting 'unsafe-eval' separately
|
|
16
|
+
* blocks eval/new Function, which is the custom-JavaScript execution sink.
|
|
17
|
+
* HTTPS script sources remain available for Tag Manager and the tags it loads.
|
|
18
|
+
*/
|
|
19
|
+
export const STATUS_PAGE_FALLBACK_CONTENT_SECURITY_POLICY: string = [
|
|
20
|
+
"script-src 'self' 'unsafe-inline' https:",
|
|
21
|
+
"script-src-attr 'none'",
|
|
22
|
+
"object-src 'none'",
|
|
23
|
+
"base-uri 'none'",
|
|
24
|
+
].join("; ");
|
|
25
|
+
|
|
26
|
+
export const isStatusPageFallbackDocumentPath: (path: string) => boolean = (
|
|
27
|
+
path: string,
|
|
28
|
+
): boolean => {
|
|
29
|
+
const normalizedPath: string = (path || "").split("?")[0] || "";
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
normalizedPath === "/status-page" ||
|
|
33
|
+
normalizedPath === "/status-page/" ||
|
|
34
|
+
normalizedPath.startsWith("/status-page/")
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Adds the fallback status page's CSP before its HTML document is rendered.
|
|
40
|
+
* Custom-domain documents (normally served from "/") are intentionally left
|
|
41
|
+
* alone because arbitrary customization remains a supported isolated-origin
|
|
42
|
+
* feature there.
|
|
43
|
+
*/
|
|
44
|
+
export default function applyStatusPageContentSecurityPolicy(
|
|
45
|
+
req: ExpressRequest,
|
|
46
|
+
res: ExpressResponse,
|
|
47
|
+
): void {
|
|
48
|
+
if (!isStatusPageFallbackDocumentPath(req.path || "") || res.headersSent) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
res.set(
|
|
53
|
+
STATUS_PAGE_CONTENT_SECURITY_POLICY_HEADER_NAME,
|
|
54
|
+
STATUS_PAGE_FALLBACK_CONTENT_SECURITY_POLICY,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import Domain from "../../Models/DatabaseModels/Domain";
|
|
2
|
+
import StatusPageDomain from "../../Models/DatabaseModels/StatusPageDomain";
|
|
3
|
+
import Hostname from "../../Types/API/Hostname";
|
|
4
|
+
import ObjectID from "../../Types/ObjectID";
|
|
5
|
+
import StatusPageDomainService from "../Services/StatusPageDomainService";
|
|
6
|
+
import { ExpressRequest } from "./Express";
|
|
7
|
+
|
|
8
|
+
const BUILT_IN_PRIMARY_HOSTS: Set<string> = new Set<string>([
|
|
9
|
+
"localhost",
|
|
10
|
+
"ingress",
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
const INVALID_HOST_AUTHORITY_CHARACTER: RegExp = /[\s/?#]/;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse the HTTP Host authority without consulting Express' `req.hostname`.
|
|
17
|
+
*
|
|
18
|
+
* Express may derive `req.hostname` from X-Forwarded-Host when `trust proxy`
|
|
19
|
+
* is enabled. That header is caller-controlled on several of the Nginx routes
|
|
20
|
+
* in this repository, so it cannot decide whether tenant-controlled code is
|
|
21
|
+
* returned. Nginx overwrites the actual Host header with `$host`, which makes
|
|
22
|
+
* the raw Host the appropriate input to this security boundary.
|
|
23
|
+
*/
|
|
24
|
+
export const normalizeStatusPageRequestHost: (
|
|
25
|
+
rawHost: string | undefined,
|
|
26
|
+
) => string | null = (rawHost: string | undefined): string | null => {
|
|
27
|
+
const authority: string = rawHost?.trim() || "";
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
!authority ||
|
|
31
|
+
authority.includes("@") ||
|
|
32
|
+
authority.includes(",") ||
|
|
33
|
+
INVALID_HOST_AUTHORITY_CHARACTER.test(authority) ||
|
|
34
|
+
!Hostname.isValid(authority)
|
|
35
|
+
) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
let hostname: string = Hostname.fromAuthority(authority)
|
|
41
|
+
.hostname.trim()
|
|
42
|
+
.toLowerCase();
|
|
43
|
+
|
|
44
|
+
// Treat the fully-qualified spelling of a DNS name as the same host.
|
|
45
|
+
if (hostname.endsWith(".")) {
|
|
46
|
+
hostname = hostname.slice(0, -1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return hostname || null;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const isPrimaryStatusPageHost: (hostname: string) => boolean = (
|
|
56
|
+
hostname: string,
|
|
57
|
+
): boolean => {
|
|
58
|
+
if (BUILT_IN_PRIMARY_HOSTS.has(hostname)) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const configuredHostValue: string = process.env["HOST"] || "localhost";
|
|
63
|
+
const configuredHost: string | null =
|
|
64
|
+
normalizeStatusPageRequestHost(configuredHostValue);
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* A malformed deployment HOST means we cannot prove that any incoming host
|
|
68
|
+
* is isolated from the authenticated application. Disable customizations
|
|
69
|
+
* globally until the configuration is corrected.
|
|
70
|
+
*/
|
|
71
|
+
if (!configuredHost) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return hostname === configuredHost;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const canServeStatusPageCustomizations: (data: {
|
|
79
|
+
req: ExpressRequest;
|
|
80
|
+
statusPageId: ObjectID;
|
|
81
|
+
}) => Promise<boolean> = async (data: {
|
|
82
|
+
req: ExpressRequest;
|
|
83
|
+
statusPageId: ObjectID;
|
|
84
|
+
}): Promise<boolean> => {
|
|
85
|
+
const requestHost: string | null = normalizeStatusPageRequestHost(
|
|
86
|
+
data.req.get("host"),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (!requestHost || isPrimaryStatusPageHost(requestHost)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const statusPageDomain: StatusPageDomain | null =
|
|
95
|
+
await StatusPageDomainService.findOneBy({
|
|
96
|
+
query: {
|
|
97
|
+
fullDomain: requestHost,
|
|
98
|
+
statusPageId: data.statusPageId,
|
|
99
|
+
isCnameVerified: true,
|
|
100
|
+
domain: {
|
|
101
|
+
isVerified: true,
|
|
102
|
+
} as Domain,
|
|
103
|
+
},
|
|
104
|
+
select: {
|
|
105
|
+
_id: true,
|
|
106
|
+
},
|
|
107
|
+
props: {
|
|
108
|
+
isRoot: true,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return Boolean(statusPageDomain);
|
|
113
|
+
} catch {
|
|
114
|
+
// A lookup failure must never fall back to serving tenant-controlled code.
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
};
|