@oneuptime/common 12.0.12 → 12.0.13
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/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
- package/Models/DatabaseModels/NetworkDevice.ts +64 -0
- package/Models/DatabaseModels/StatusPage.ts +59 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
- package/Server/API/AIChatAPI.ts +55 -56
- package/Server/API/CommonAPI.ts +89 -0
- package/Server/API/MicrosoftTeamsAPI.ts +20 -9
- package/Server/API/SlackAPI.ts +13 -10
- package/Server/API/StatusPageAPI.ts +2197 -2128
- package/Server/API/TelemetryAPI.ts +72 -3
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/UserAuthorization.ts +11 -2
- package/Server/Services/ApiKeyPermissionService.ts +116 -2
- package/Server/Services/DatabaseService.ts +17 -6
- package/Server/Services/LogAggregationService.ts +34 -0
- package/Server/Services/LogService.ts +21 -0
- package/Server/Services/NetworkSiteService.ts +12 -0
- package/Server/Services/SpanService.ts +21 -0
- package/Server/Services/TraceAggregationService.ts +15 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
- package/Server/Utils/APIKey/AccessPermission.ts +16 -40
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
- package/Server/Utils/LogRedaction.ts +576 -0
- package/Server/Utils/Logger.ts +123 -46
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
- package/Server/Utils/Monitor/MonitorResource.ts +29 -9
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
- package/Server/Utils/StartServer.ts +30 -9
- package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
- package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
- package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
- package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
- package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
- package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
- package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
- package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
- package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
- package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
- package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
- package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
- package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
- package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
- package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
- package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
- package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
- package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
- package/Tests/UI/Components/MasterPage.test.tsx +36 -1
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
- package/Types/API/Hostname.ts +79 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
- package/Types/Database/DatabaseProperty.ts +38 -0
- package/Types/Database/TableColumn.ts +34 -7
- package/Types/Events/Recurring.ts +16 -1
- package/Types/Monitor/MonitorStep.ts +13 -1
- package/Types/Monitor/MonitorType.ts +345 -40
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
- package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
- package/UI/Components/CardSelect/CardSelect.tsx +714 -105
- package/UI/Components/EmptyState/EmptyState.tsx +8 -1
- package/UI/Components/Footer/Footer.tsx +32 -6
- package/UI/Components/Forms/Fields/FormField.tsx +3 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Loader/PageLoader.tsx +29 -8
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
- package/UI/Components/MasterPage/MasterPage.tsx +24 -11
- package/Utils/Monitor/MonitorMetricType.ts +16 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
- package/Utils/Telemetry/CrossSignalScope.ts +75 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +48 -35
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +59 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +13 -10
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +745 -673
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +34 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.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/UserAuthorization.js +6 -2
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +15 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +2 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogService.js +16 -0
- package/build/dist/Server/Services/LogService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +12 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +16 -0
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +449 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +98 -45
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -7
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +63 -0
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +38 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/TableColumn.js +24 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +13 -1
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +9 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +330 -31
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
- package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +7 -4
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
- package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/package.json +1 -1
package/Server/Utils/Logger.ts
CHANGED
|
@@ -5,6 +5,12 @@ import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
|
5
5
|
import Exception from "../../Types/Exception/Exception";
|
|
6
6
|
import { JSONObject } from "../../Types/JSON";
|
|
7
7
|
import ConfigLogLevel from "../Types/ConfigLogLevel";
|
|
8
|
+
import {
|
|
9
|
+
REDACTED,
|
|
10
|
+
isSensitiveLogKey,
|
|
11
|
+
redactLogString,
|
|
12
|
+
redactLogValue,
|
|
13
|
+
} from "./LogRedaction";
|
|
8
14
|
|
|
9
15
|
export type LogBody = string | JSONObject | Exception | Error | unknown;
|
|
10
16
|
|
|
@@ -68,9 +74,10 @@ export default class logger {
|
|
|
68
74
|
private static readonly recentLogTrimSlack: number = 256;
|
|
69
75
|
private static readonly maxRecentLogMessageLength: number = 4000;
|
|
70
76
|
|
|
77
|
+
// `body` has already been through redactBody -- see the level methods.
|
|
71
78
|
private static record(level: string, body: LogBody): void {
|
|
72
79
|
try {
|
|
73
|
-
const message: string = this.
|
|
80
|
+
const message: string = this.serializeRedactedBody(body);
|
|
74
81
|
|
|
75
82
|
this.recentLogs.push({
|
|
76
83
|
time: new Date().toISOString(),
|
|
@@ -114,13 +121,71 @@ export default class logger {
|
|
|
114
121
|
return LogLevel;
|
|
115
122
|
}
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
/*
|
|
125
|
+
* Turns a body into a redacted copy, once, before it is handed to any sink.
|
|
126
|
+
* Every level method calls this and then passes the RESULT to console, to
|
|
127
|
+
* the recent-log buffer and to telemetry, so a log record is redacted a
|
|
128
|
+
* single time no matter how many places it ends up in.
|
|
129
|
+
*
|
|
130
|
+
* Objects come back as plain redacted copies, so console keeps printing them
|
|
131
|
+
* as objects rather than as a JSON string.
|
|
132
|
+
*
|
|
133
|
+
* Errors are special-cased: when nothing in the message or the stack needed
|
|
134
|
+
* redacting -- the overwhelmingly common case -- the original Error is
|
|
135
|
+
* returned untouched, so console still renders a real stack trace.
|
|
136
|
+
*/
|
|
137
|
+
private static redactBody(body: LogBody): LogBody {
|
|
138
|
+
try {
|
|
139
|
+
if (typeof body === "string") {
|
|
140
|
+
return redactLogString(body);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (body instanceof Exception || body instanceof Error) {
|
|
144
|
+
const originalStack: string = body.stack || "";
|
|
145
|
+
const message: string = redactLogString(body.message);
|
|
146
|
+
const stack: string = redactLogString(originalStack);
|
|
147
|
+
|
|
148
|
+
if (message === body.message && stack === originalStack) {
|
|
149
|
+
return body;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return stack || `${body.name}: ${message}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return redactLogValue(body) as LogBody;
|
|
156
|
+
} catch {
|
|
157
|
+
// Never pass on a body we could not prove was redacted.
|
|
158
|
+
return REDACTED;
|
|
122
159
|
}
|
|
123
|
-
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Serialization only. The body must already have been through redactBody.
|
|
163
|
+
private static serializeRedactedBody(body: LogBody): string {
|
|
164
|
+
try {
|
|
165
|
+
if (typeof body === "string") {
|
|
166
|
+
return body;
|
|
167
|
+
} else if (body instanceof Exception || body instanceof Error) {
|
|
168
|
+
return body.message;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/*
|
|
172
|
+
* redactBody swept every string inside this copy already, so stringifying
|
|
173
|
+
* it needs no second textual pass.
|
|
174
|
+
*/
|
|
175
|
+
const serialized: string | undefined = JSON.stringify(body);
|
|
176
|
+
|
|
177
|
+
return serialized === undefined ? "" : serialized;
|
|
178
|
+
} catch {
|
|
179
|
+
return REDACTED;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* Redacts and serializes in one step, for callers outside the level methods
|
|
185
|
+
* that hold a raw body.
|
|
186
|
+
*/
|
|
187
|
+
public static serializeLogBody(body: LogBody): string {
|
|
188
|
+
return this.serializeRedactedBody(this.redactBody(body));
|
|
124
189
|
}
|
|
125
190
|
|
|
126
191
|
private static sanitizeAttributes(
|
|
@@ -136,7 +201,16 @@ export default class logger {
|
|
|
136
201
|
for (const key in attributes) {
|
|
137
202
|
const value: string | number | boolean | undefined = attributes[key];
|
|
138
203
|
|
|
139
|
-
if (value
|
|
204
|
+
if (value === undefined || value === null) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Attributes are a log sink too, and they travel to telemetry verbatim.
|
|
209
|
+
if (isSensitiveLogKey(key, value)) {
|
|
210
|
+
sanitized[key] = REDACTED;
|
|
211
|
+
} else if (typeof value === "string") {
|
|
212
|
+
sanitized[key] = redactLogString(value);
|
|
213
|
+
} else {
|
|
140
214
|
sanitized[key] = value;
|
|
141
215
|
}
|
|
142
216
|
}
|
|
@@ -151,16 +225,14 @@ export default class logger {
|
|
|
151
225
|
const logLevel: ConfigLogLevel = this.getLogLevel();
|
|
152
226
|
|
|
153
227
|
if (logLevel === ConfigLogLevel.DEBUG || logLevel === ConfigLogLevel.INFO) {
|
|
228
|
+
const body: LogBody = this.redactBody(message);
|
|
229
|
+
|
|
154
230
|
// eslint-disable-next-line no-console
|
|
155
|
-
console.info(
|
|
231
|
+
console.info(body);
|
|
156
232
|
|
|
157
|
-
this.record("INFO",
|
|
233
|
+
this.record("INFO", body);
|
|
158
234
|
|
|
159
|
-
this.
|
|
160
|
-
body: message,
|
|
161
|
-
severityNumber: SeverityNumber.INFO,
|
|
162
|
-
attributes,
|
|
163
|
-
});
|
|
235
|
+
this.emitRedacted(body, SeverityNumber.INFO, attributes);
|
|
164
236
|
}
|
|
165
237
|
}
|
|
166
238
|
|
|
@@ -173,16 +245,14 @@ export default class logger {
|
|
|
173
245
|
logLevel === ConfigLogLevel.WARN ||
|
|
174
246
|
logLevel === ConfigLogLevel.ERROR
|
|
175
247
|
) {
|
|
248
|
+
const body: LogBody = this.redactBody(message);
|
|
249
|
+
|
|
176
250
|
// eslint-disable-next-line no-console
|
|
177
|
-
console.error(
|
|
251
|
+
console.error(body);
|
|
178
252
|
|
|
179
|
-
this.record("ERROR",
|
|
253
|
+
this.record("ERROR", body);
|
|
180
254
|
|
|
181
|
-
this.
|
|
182
|
-
body: message,
|
|
183
|
-
severityNumber: SeverityNumber.ERROR,
|
|
184
|
-
attributes,
|
|
185
|
-
});
|
|
255
|
+
this.emitRedacted(body, SeverityNumber.ERROR, attributes);
|
|
186
256
|
}
|
|
187
257
|
}
|
|
188
258
|
|
|
@@ -194,16 +264,14 @@ export default class logger {
|
|
|
194
264
|
logLevel === ConfigLogLevel.INFO ||
|
|
195
265
|
logLevel === ConfigLogLevel.WARN
|
|
196
266
|
) {
|
|
267
|
+
const body: LogBody = this.redactBody(message);
|
|
268
|
+
|
|
197
269
|
// eslint-disable-next-line no-console
|
|
198
|
-
console.warn(
|
|
270
|
+
console.warn(body);
|
|
199
271
|
|
|
200
|
-
this.record("WARN",
|
|
272
|
+
this.record("WARN", body);
|
|
201
273
|
|
|
202
|
-
this.
|
|
203
|
-
body: message,
|
|
204
|
-
severityNumber: SeverityNumber.WARN,
|
|
205
|
-
attributes,
|
|
206
|
-
});
|
|
274
|
+
this.emitRedacted(body, SeverityNumber.WARN, attributes);
|
|
207
275
|
}
|
|
208
276
|
}
|
|
209
277
|
|
|
@@ -211,16 +279,14 @@ export default class logger {
|
|
|
211
279
|
const logLevel: ConfigLogLevel = this.getLogLevel();
|
|
212
280
|
|
|
213
281
|
if (logLevel === ConfigLogLevel.DEBUG) {
|
|
282
|
+
const body: LogBody = this.redactBody(message);
|
|
283
|
+
|
|
214
284
|
// eslint-disable-next-line no-console
|
|
215
|
-
console.debug(
|
|
285
|
+
console.debug(body);
|
|
216
286
|
|
|
217
|
-
this.record("DEBUG",
|
|
287
|
+
this.record("DEBUG", body);
|
|
218
288
|
|
|
219
|
-
this.
|
|
220
|
-
body: message,
|
|
221
|
-
severityNumber: SeverityNumber.DEBUG,
|
|
222
|
-
attributes,
|
|
223
|
-
});
|
|
289
|
+
this.emitRedacted(body, SeverityNumber.DEBUG, attributes);
|
|
224
290
|
}
|
|
225
291
|
}
|
|
226
292
|
|
|
@@ -229,6 +295,19 @@ export default class logger {
|
|
|
229
295
|
severityNumber: SeverityNumber;
|
|
230
296
|
attributes?: LogAttributes | undefined;
|
|
231
297
|
}): void {
|
|
298
|
+
this.emitRedacted(
|
|
299
|
+
this.redactBody(data.body),
|
|
300
|
+
data.severityNumber,
|
|
301
|
+
data.attributes,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// `body` must already have been through redactBody.
|
|
306
|
+
private static emitRedacted(
|
|
307
|
+
body: LogBody,
|
|
308
|
+
severityNumber: SeverityNumber,
|
|
309
|
+
attributes?: LogAttributes | undefined,
|
|
310
|
+
): void {
|
|
232
311
|
try {
|
|
233
312
|
const logger: TelemetryLogger | null = OneUptimeTelemetry.getLogger();
|
|
234
313
|
|
|
@@ -243,7 +322,7 @@ export default class logger {
|
|
|
243
322
|
*/
|
|
244
323
|
const mergedAttributes: LogAttributes = {
|
|
245
324
|
...TelemetryContext.getAttributes(),
|
|
246
|
-
...(
|
|
325
|
+
...(attributes || {}),
|
|
247
326
|
};
|
|
248
327
|
|
|
249
328
|
const sanitizedAttributes:
|
|
@@ -251,8 +330,8 @@ export default class logger {
|
|
|
251
330
|
| undefined = this.sanitizeAttributes(mergedAttributes);
|
|
252
331
|
|
|
253
332
|
logger.emit({
|
|
254
|
-
body: this.
|
|
255
|
-
severityNumber:
|
|
333
|
+
body: this.serializeRedactedBody(body),
|
|
334
|
+
severityNumber: severityNumber,
|
|
256
335
|
...(sanitizedAttributes ? { attributes: sanitizedAttributes } : {}),
|
|
257
336
|
});
|
|
258
337
|
} catch {
|
|
@@ -264,16 +343,14 @@ export default class logger {
|
|
|
264
343
|
const logLevel: ConfigLogLevel = this.getLogLevel();
|
|
265
344
|
|
|
266
345
|
if (logLevel === ConfigLogLevel.DEBUG) {
|
|
346
|
+
const body: LogBody = this.redactBody(message);
|
|
347
|
+
|
|
267
348
|
// eslint-disable-next-line no-console
|
|
268
|
-
console.trace(
|
|
349
|
+
console.trace(body);
|
|
269
350
|
|
|
270
|
-
this.record("TRACE",
|
|
351
|
+
this.record("TRACE", body);
|
|
271
352
|
|
|
272
|
-
this.
|
|
273
|
-
body: message,
|
|
274
|
-
severityNumber: SeverityNumber.DEBUG,
|
|
275
|
-
attributes,
|
|
276
|
-
});
|
|
353
|
+
this.emitRedacted(body, SeverityNumber.DEBUG, attributes);
|
|
277
354
|
}
|
|
278
355
|
}
|
|
279
356
|
}
|
|
@@ -78,16 +78,8 @@ export default class ServerMonitorCriteria {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (input.criteriaFilter.checkOn === CheckOn.IsValidCertificate) {
|
|
81
|
-
const isValidCertificate: boolean =
|
|
82
|
-
|
|
83
|
-
dataToProcess.isOnline &&
|
|
84
|
-
sslResponse.expiresAt &&
|
|
85
|
-
!sslResponse.isSelfSigned &&
|
|
86
|
-
OneUptimeDate.isAfter(
|
|
87
|
-
sslResponse.expiresAt,
|
|
88
|
-
OneUptimeDate.getCurrentDate(),
|
|
89
|
-
),
|
|
90
|
-
);
|
|
81
|
+
const isValidCertificate: boolean =
|
|
82
|
+
ServerMonitorCriteria.isValidCertificate(dataToProcess);
|
|
91
83
|
|
|
92
84
|
const isTrue: boolean =
|
|
93
85
|
input.criteriaFilter.filterType === FilterType.True;
|
|
@@ -100,7 +92,7 @@ export default class ServerMonitorCriteria {
|
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
if (!isValidCertificate && isFalse) {
|
|
103
|
-
return
|
|
95
|
+
return ServerMonitorCriteria.invalidCertificateReason(dataToProcess);
|
|
104
96
|
}
|
|
105
97
|
}
|
|
106
98
|
|
|
@@ -149,18 +141,19 @@ export default class ServerMonitorCriteria {
|
|
|
149
141
|
}
|
|
150
142
|
|
|
151
143
|
if (input.criteriaFilter.checkOn === CheckOn.IsNotAValidCertificate) {
|
|
144
|
+
/*
|
|
145
|
+
* The exact complement of IsValidCertificate, by construction.
|
|
146
|
+
*
|
|
147
|
+
* These two used to be computed independently, and both came out
|
|
148
|
+
* false whenever expiresAt was missing or unparseable - so a
|
|
149
|
+
* certificate the probe could not fully read satisfied NEITHER
|
|
150
|
+
* "valid" nor "not valid", every criterion went unmatched, and the
|
|
151
|
+
* monitor silently stayed at its default status. Deriving one from
|
|
152
|
+
* the other makes that state unreachable.
|
|
153
|
+
*/
|
|
152
154
|
const isNotValid: boolean =
|
|
153
|
-
!
|
|
154
|
-
|
|
155
|
-
Boolean(
|
|
156
|
-
sslResponse &&
|
|
157
|
-
sslResponse.expiresAt &&
|
|
158
|
-
(sslResponse.isSelfSigned ||
|
|
159
|
-
OneUptimeDate.isBefore(
|
|
160
|
-
sslResponse.expiresAt,
|
|
161
|
-
OneUptimeDate.getCurrentDate(),
|
|
162
|
-
)),
|
|
163
|
-
);
|
|
155
|
+
!ServerMonitorCriteria.isValidCertificate(dataToProcess);
|
|
156
|
+
|
|
164
157
|
const isTrue: boolean =
|
|
165
158
|
input.criteriaFilter.filterType === FilterType.True;
|
|
166
159
|
|
|
@@ -168,7 +161,7 @@ export default class ServerMonitorCriteria {
|
|
|
168
161
|
input.criteriaFilter.filterType === FilterType.False;
|
|
169
162
|
|
|
170
163
|
if (isNotValid && isTrue) {
|
|
171
|
-
return
|
|
164
|
+
return ServerMonitorCriteria.invalidCertificateReason(dataToProcess);
|
|
172
165
|
}
|
|
173
166
|
|
|
174
167
|
if (!isNotValid && isFalse) {
|
|
@@ -230,4 +223,82 @@ export default class ServerMonitorCriteria {
|
|
|
230
223
|
|
|
231
224
|
return null;
|
|
232
225
|
}
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* The single source of truth for "is this certificate trustworthy",
|
|
229
|
+
* shared by IsValidCertificate and IsNotAValidCertificate so the two can
|
|
230
|
+
* never both be false for the same response.
|
|
231
|
+
*
|
|
232
|
+
* The probe now records the strict-TLS verdict explicitly on
|
|
233
|
+
* sslResponse.isValidCertificate. Responses written before that field
|
|
234
|
+
* existed (rows already in MonitorProbe.lastMonitoringLog, and any probe
|
|
235
|
+
* still running an older build) do not carry it, so the pre-existing
|
|
236
|
+
* heuristic is kept as the fallback rather than treating those as
|
|
237
|
+
* invalid and flipping healthy monitors to Down on upgrade.
|
|
238
|
+
*/
|
|
239
|
+
private static isValidCertificate(
|
|
240
|
+
dataToProcess: ProbeMonitorResponse,
|
|
241
|
+
): boolean {
|
|
242
|
+
const sslResponse: SslMonitorResponse | undefined =
|
|
243
|
+
dataToProcess.sslResponse;
|
|
244
|
+
|
|
245
|
+
if (!sslResponse || !dataToProcess.isOnline) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (sslResponse.isValidCertificate !== undefined) {
|
|
250
|
+
return Boolean(sslResponse.isValidCertificate);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Legacy payload: fall back to what could be inferred before.
|
|
254
|
+
return Boolean(
|
|
255
|
+
sslResponse.expiresAt &&
|
|
256
|
+
!sslResponse.isSelfSigned &&
|
|
257
|
+
OneUptimeDate.isAfter(
|
|
258
|
+
sslResponse.expiresAt,
|
|
259
|
+
OneUptimeDate.getCurrentDate(),
|
|
260
|
+
),
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* Names WHY the certificate is not trustworthy. The root cause is what
|
|
266
|
+
* reaches the incident and the person paged by it, so "SSL certificate is
|
|
267
|
+
* not valid" on its own is not good enough when the probe knows it was a
|
|
268
|
+
* hostname mismatch.
|
|
269
|
+
*/
|
|
270
|
+
private static invalidCertificateReason(
|
|
271
|
+
dataToProcess: ProbeMonitorResponse,
|
|
272
|
+
): string {
|
|
273
|
+
const sslResponse: SslMonitorResponse | undefined =
|
|
274
|
+
dataToProcess.sslResponse;
|
|
275
|
+
|
|
276
|
+
if (!dataToProcess.isOnline) {
|
|
277
|
+
return "SSL certificate could not be checked because the endpoint is not reachable.";
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!sslResponse) {
|
|
281
|
+
return "SSL certificate is not valid.";
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (sslResponse.certificateValidationError) {
|
|
285
|
+
return `SSL certificate is not valid: ${sslResponse.certificateValidationError}`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (sslResponse.isSelfSigned) {
|
|
289
|
+
return "SSL certificate is not valid: the certificate is self signed.";
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (
|
|
293
|
+
sslResponse.expiresAt &&
|
|
294
|
+
OneUptimeDate.isBefore(
|
|
295
|
+
sslResponse.expiresAt,
|
|
296
|
+
OneUptimeDate.getCurrentDate(),
|
|
297
|
+
)
|
|
298
|
+
) {
|
|
299
|
+
return "SSL certificate is not valid: the certificate has expired.";
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return "SSL certificate is not valid.";
|
|
303
|
+
}
|
|
233
304
|
}
|
|
@@ -636,7 +636,16 @@ export default class MonitorResourceUtil {
|
|
|
636
636
|
}
|
|
637
637
|
}
|
|
638
638
|
|
|
639
|
-
|
|
639
|
+
/*
|
|
640
|
+
* The step this result was actually produced for. A probe result carries
|
|
641
|
+
* the monitorStepId it ran, and a monitor can have several steps whose
|
|
642
|
+
* criteria differ - so the step must be looked up, not assumed to be the
|
|
643
|
+
* first one. The lookup used to be performed and its result thrown away,
|
|
644
|
+
* which silently evaluated every result against step 0's criteria and fed
|
|
645
|
+
* step 0's id into checkProbeAgreement (so agreement compared this
|
|
646
|
+
* result against other probes' logs for the wrong step).
|
|
647
|
+
*/
|
|
648
|
+
let monitorStep: MonitorStep | undefined =
|
|
640
649
|
monitorSteps.data.monitorStepsInstanceArray[0];
|
|
641
650
|
|
|
642
651
|
logger.debug(
|
|
@@ -644,14 +653,25 @@ export default class MonitorResourceUtil {
|
|
|
644
653
|
);
|
|
645
654
|
|
|
646
655
|
if ((dataToProcess as ProbeMonitorResponse).monitorStepId) {
|
|
647
|
-
|
|
648
|
-
(
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
656
|
+
const ingestedMonitorStep: MonitorStep | undefined =
|
|
657
|
+
monitorSteps.data.monitorStepsInstanceArray.find(
|
|
658
|
+
(step: MonitorStep) => {
|
|
659
|
+
return (
|
|
660
|
+
step.id.toString() ===
|
|
661
|
+
(dataToProcess as ProbeMonitorResponse).monitorStepId.toString()
|
|
662
|
+
);
|
|
663
|
+
},
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
/*
|
|
667
|
+
* An id that matches no step is stale - the step was deleted after the
|
|
668
|
+
* probe was scheduled. Keep the existing behaviour there and fall back
|
|
669
|
+
* to the first step rather than dropping the result.
|
|
670
|
+
*/
|
|
671
|
+
if (ingestedMonitorStep) {
|
|
672
|
+
monitorStep = ingestedMonitorStep;
|
|
673
|
+
}
|
|
674
|
+
|
|
655
675
|
logger.debug(
|
|
656
676
|
`Found Monitor Step ID: ${(dataToProcess as ProbeMonitorResponse).monitorStepId}`,
|
|
657
677
|
);
|
|
@@ -83,12 +83,9 @@ export default class NetworkInventoryUtil {
|
|
|
83
83
|
const now: Date = OneUptimeDate.getCurrentDate();
|
|
84
84
|
|
|
85
85
|
/*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* would paint an unreachable device green. A poll where the probe could
|
|
90
|
-
* not reach the device reports isOnline === false; treat anything else
|
|
91
|
-
* (reachable, or a walk that reports no reachability) as seen.
|
|
86
|
+
* A poll where the probe could not reach the device reports
|
|
87
|
+
* isOnline === false; treat anything else (reachable, or a walk that
|
|
88
|
+
* reports no reachability at all) as answered.
|
|
92
89
|
*/
|
|
93
90
|
const isDeviceReachable: boolean = data.isOnline !== false;
|
|
94
91
|
|
|
@@ -96,6 +93,26 @@ export default class NetworkInventoryUtil {
|
|
|
96
93
|
// --- Device enrichment + cached counts ---
|
|
97
94
|
const deviceUpdate: Record<string, unknown> = {};
|
|
98
95
|
|
|
96
|
+
/*
|
|
97
|
+
* Three columns, three different questions, and the difference
|
|
98
|
+
* between them is the whole reason a reachable device used to show as
|
|
99
|
+
* down:
|
|
100
|
+
*
|
|
101
|
+
* lastPolledAt - when we last ASKED. Always stamped, success or
|
|
102
|
+
* failure. Without it there is no way to tell a
|
|
103
|
+
* device that did not answer from one nothing got
|
|
104
|
+
* round to polling, which is what made a fleet
|
|
105
|
+
* bigger than one probe's claim rate read as a
|
|
106
|
+
* fleet-wide outage.
|
|
107
|
+
* isReachable - what the answer WAS. This is what the device list,
|
|
108
|
+
* the topology graph and the site rollup read.
|
|
109
|
+
* lastSeenAt - when the device last ANSWERED. Only moves on a
|
|
110
|
+
* successful walk, so it stays honest as "last
|
|
111
|
+
* contact" and never paints a dead device green.
|
|
112
|
+
*/
|
|
113
|
+
deviceUpdate["lastPolledAt"] = now;
|
|
114
|
+
deviceUpdate["isReachable"] = isDeviceReachable;
|
|
115
|
+
|
|
99
116
|
if (isDeviceReachable) {
|
|
100
117
|
deviceUpdate["lastSeenAt"] = now;
|
|
101
118
|
}
|
|
@@ -181,7 +198,11 @@ export default class NetworkInventoryUtil {
|
|
|
181
198
|
).length;
|
|
182
199
|
}
|
|
183
200
|
|
|
184
|
-
|
|
201
|
+
/*
|
|
202
|
+
* Always non-empty now: even a walk that reached nothing has to
|
|
203
|
+
* record that we tried, or the staleness backstop cannot tell a
|
|
204
|
+
* failing device from an unpolled one.
|
|
205
|
+
*/
|
|
185
206
|
if (Object.keys(deviceUpdate).length > 0) {
|
|
186
207
|
await NetworkDeviceService.updateOneById({
|
|
187
208
|
id: deviceId,
|
|
@@ -24,6 +24,15 @@ import ObjectID from "../../../Types/ObjectID";
|
|
|
24
24
|
export const POLICY_CACHE_TTL_MS: number = 60 * 1000;
|
|
25
25
|
export const KILL_KEY_CACHE_TTL_MS: number = 5 * 1000;
|
|
26
26
|
|
|
27
|
+
/*
|
|
28
|
+
* The policy cache key includes a client-supplied appIdentifier, so without a
|
|
29
|
+
* bound anyone holding an ingestion key could grow this map forever. Caps
|
|
30
|
+
* match the InMemoryTTLCache house default; that class is not used directly
|
|
31
|
+
* because clearCache(projectId) needs the prefix key scan it lacks.
|
|
32
|
+
*/
|
|
33
|
+
export const MAX_POLICY_CACHE_ENTRIES: number = 10_000;
|
|
34
|
+
export const MAX_KILL_KEY_CACHE_ENTRIES: number = 10_000;
|
|
35
|
+
|
|
27
36
|
const KILL_KEY_PREFIX: string = "replay:gate:off:";
|
|
28
37
|
|
|
29
38
|
/*
|
|
@@ -52,6 +61,29 @@ interface KillKeyCacheEntry {
|
|
|
52
61
|
const policyCache: Map<string, PolicyCacheEntry<unknown>> = new Map();
|
|
53
62
|
const killKeyCache: Map<string, KillKeyCacheEntry> = new Map();
|
|
54
63
|
|
|
64
|
+
/*
|
|
65
|
+
* Coarse-LRU bounded write (mirrors InMemoryTTLCache): evict the oldest entry
|
|
66
|
+
* only when at capacity AND the key is new, so rewriting an existing key never
|
|
67
|
+
* evicts a different entry; delete-before-set refreshes insertion order. The
|
|
68
|
+
* entry being written always lands, which markProjectDisabled's local kill
|
|
69
|
+
* marker depends on.
|
|
70
|
+
*/
|
|
71
|
+
function boundedSet<TValue>(
|
|
72
|
+
map: Map<string, TValue>,
|
|
73
|
+
key: string,
|
|
74
|
+
value: TValue,
|
|
75
|
+
maxEntries: number,
|
|
76
|
+
): void {
|
|
77
|
+
if (map.size >= maxEntries && !map.has(key)) {
|
|
78
|
+
const oldest: string | undefined = map.keys().next().value;
|
|
79
|
+
if (oldest !== undefined) {
|
|
80
|
+
map.delete(oldest);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
map.delete(key);
|
|
84
|
+
map.set(key, value);
|
|
85
|
+
}
|
|
86
|
+
|
|
55
87
|
export default class SessionReplayGateCacheStore {
|
|
56
88
|
public static getPolicyEntry<TPolicy>(
|
|
57
89
|
cacheKey: string,
|
|
@@ -63,7 +95,12 @@ export default class SessionReplayGateCacheStore {
|
|
|
63
95
|
cacheKey: string,
|
|
64
96
|
policy: TPolicy | null,
|
|
65
97
|
): void {
|
|
66
|
-
|
|
98
|
+
boundedSet(
|
|
99
|
+
policyCache,
|
|
100
|
+
cacheKey,
|
|
101
|
+
{ policy: policy, loadedAt: Date.now() },
|
|
102
|
+
MAX_POLICY_CACHE_ENTRIES,
|
|
103
|
+
);
|
|
67
104
|
}
|
|
68
105
|
|
|
69
106
|
/*
|
|
@@ -93,10 +130,12 @@ export default class SessionReplayGateCacheStore {
|
|
|
93
130
|
}
|
|
94
131
|
}
|
|
95
132
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
133
|
+
boundedSet(
|
|
134
|
+
killKeyCache,
|
|
135
|
+
projectId.toString(),
|
|
136
|
+
{ isDisabled: true, loadedAt: Date.now() },
|
|
137
|
+
MAX_KILL_KEY_CACHE_ENTRIES,
|
|
138
|
+
);
|
|
100
139
|
}
|
|
101
140
|
|
|
102
141
|
/*
|
|
@@ -159,7 +198,12 @@ export default class SessionReplayGateCacheStore {
|
|
|
159
198
|
* Failing closed here would make a Redis blip stop replay ingest for
|
|
160
199
|
* every project that had correctly opted in.
|
|
161
200
|
*/
|
|
162
|
-
|
|
201
|
+
boundedSet(
|
|
202
|
+
killKeyCache,
|
|
203
|
+
cacheKey,
|
|
204
|
+
{ isDisabled: false, loadedAt: Date.now() },
|
|
205
|
+
MAX_KILL_KEY_CACHE_ENTRIES,
|
|
206
|
+
);
|
|
163
207
|
return false;
|
|
164
208
|
}
|
|
165
209
|
|
|
@@ -178,10 +222,12 @@ export default class SessionReplayGateCacheStore {
|
|
|
178
222
|
isDisabled = false;
|
|
179
223
|
}
|
|
180
224
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
225
|
+
boundedSet(
|
|
226
|
+
killKeyCache,
|
|
227
|
+
cacheKey,
|
|
228
|
+
{ isDisabled: isDisabled, loadedAt: Date.now() },
|
|
229
|
+
MAX_KILL_KEY_CACHE_ENTRIES,
|
|
230
|
+
);
|
|
185
231
|
|
|
186
232
|
return isDisabled;
|
|
187
233
|
}
|
|
@@ -76,30 +76,51 @@ app.set("view engine", "ejs");
|
|
|
76
76
|
app.set("trust proxy", TrustedProxyHops);
|
|
77
77
|
app.use(CookieParser());
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
export type BodyParserVerify = (
|
|
80
|
+
req: ExpressRequest,
|
|
81
|
+
res: ExpressResponse,
|
|
82
|
+
buf: Buffer,
|
|
83
|
+
) => void;
|
|
84
|
+
|
|
85
|
+
export interface BodyParserOptions {
|
|
86
|
+
limit: string;
|
|
87
|
+
extended: boolean;
|
|
88
|
+
verify: BodyParserVerify;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const jsonBodyParserOptions: BodyParserOptions = {
|
|
80
92
|
limit: "50mb",
|
|
81
93
|
extended: true,
|
|
82
|
-
verify: (req: ExpressRequest, _res: ExpressResponse, buf: Buffer) => {
|
|
94
|
+
verify: (req: ExpressRequest, _res: ExpressResponse, buf: Buffer): void => {
|
|
83
95
|
(req as OneUptimeRequest).rawBody = buf.toString();
|
|
84
96
|
logger.debug(
|
|
85
97
|
`Raw JSON Body for signature verification captured`,
|
|
86
98
|
getLogAttributesFromRequest(req as OneUptimeRequest),
|
|
87
99
|
);
|
|
88
100
|
},
|
|
89
|
-
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const jsonBodyParserMiddleware: RequestHandler = ExpressJson(
|
|
104
|
+
jsonBodyParserOptions,
|
|
105
|
+
); // 50 MB limit.
|
|
90
106
|
|
|
91
|
-
const
|
|
107
|
+
export const urlEncodedBodyParserOptions: BodyParserOptions = {
|
|
92
108
|
limit: "50mb",
|
|
93
109
|
extended: true,
|
|
94
|
-
verify: (req: ExpressRequest, _res: ExpressResponse, buf: Buffer) => {
|
|
95
|
-
|
|
96
|
-
(req as OneUptimeRequest).
|
|
110
|
+
verify: (req: ExpressRequest, _res: ExpressResponse, buf: Buffer): void => {
|
|
111
|
+
const raw: string = buf.toString();
|
|
112
|
+
(req as OneUptimeRequest).rawFormUrlEncodedBody = raw;
|
|
113
|
+
(req as OneUptimeRequest).rawBody = raw; // Also set rawBody for consistency
|
|
97
114
|
logger.debug(
|
|
98
|
-
`Raw Form Url Encoded Body
|
|
115
|
+
`Raw Form Url Encoded Body for signature verification captured`,
|
|
99
116
|
getLogAttributesFromRequest(req as OneUptimeRequest),
|
|
100
117
|
);
|
|
101
118
|
},
|
|
102
|
-
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const urlEncodedMiddleware: RequestHandler = ExpressUrlEncoded(
|
|
122
|
+
urlEncodedBodyParserOptions,
|
|
123
|
+
); // 50 MB limit.
|
|
103
124
|
|
|
104
125
|
const setDefaultHeaders: RequestHandler = (
|
|
105
126
|
req: ExpressRequest,
|