@oneuptime/common 9.5.9 → 9.5.10
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/Server/API/OpenSourceDeploymentAPI.ts +8 -0
- package/Server/Middleware/UserAuthorization.ts +8 -3
- package/Server/Services/MonitorService.ts +8 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +11 -2
- package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +183 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +13 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +37 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +11 -7
- package/Server/Utils/Workspace/Slack/Slack.ts +15 -12
- package/Tests/Server/Middleware/UserAuthorization.test.ts +10 -2
- package/Types/Monitor/CriteriaFilter.ts +20 -3
- package/Types/Monitor/DnsMonitor/DnsMonitorResponse.ts +16 -0
- package/Types/Monitor/DnsMonitor/DnsRecordType.ts +14 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +30 -0
- package/Types/Monitor/MonitorStepDnsMonitor.ts +46 -0
- package/Types/Monitor/MonitorType.ts +15 -2
- package/Types/Probe/ProbeMonitorResponse.ts +2 -0
- package/Utils/Monitor/MonitorMetricType.ts +2 -1
- package/build/dist/Server/API/OpenSourceDeploymentAPI.js +5 -0
- package/build/dist/Server/API/OpenSourceDeploymentAPI.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +2 -3
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +8 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +10 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +138 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +10 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +24 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +10 -7
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +15 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js +4 -2
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +15 -3
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DnsMonitor/DnsMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsRecordType.js +15 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsRecordType.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +22 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js +34 -0
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +13 -2
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +2 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/package.json +1 -1
|
@@ -39,6 +39,14 @@ export default class OpenSourceDeploymentAPI extends BaseAPI<
|
|
|
39
39
|
(body["oneuptimeVersion"] as string) || "unknown";
|
|
40
40
|
deployment.instanceUrl = (body["instanceUrl"] as string) || "";
|
|
41
41
|
|
|
42
|
+
// Skip localhost instances - these are default/unconfigured deployments.
|
|
43
|
+
if (
|
|
44
|
+
deployment.instanceUrl === "http://localhost/" ||
|
|
45
|
+
deployment.instanceUrl === "http://localhost"
|
|
46
|
+
) {
|
|
47
|
+
return Response.sendEmptySuccessResponse(req, res);
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
await OpenSourceDeploymentService.create({
|
|
43
51
|
data: deployment,
|
|
44
52
|
props: {
|
|
@@ -177,10 +177,15 @@ export default class UserMiddleware {
|
|
|
177
177
|
try {
|
|
178
178
|
oneuptimeRequest.userAuthorization = JSONWebToken.decode(accessToken);
|
|
179
179
|
} catch (err) {
|
|
180
|
-
// if the token is invalid or expired,
|
|
180
|
+
// if the token is invalid or expired, return 401 so clients can refresh the token.
|
|
181
181
|
logger.error(err);
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
return Response.sendErrorResponse(
|
|
183
|
+
req,
|
|
184
|
+
res,
|
|
185
|
+
new NotAuthenticatedException(
|
|
186
|
+
"AccessToken is invalid or expired. Please refresh your token.",
|
|
187
|
+
),
|
|
188
|
+
);
|
|
184
189
|
}
|
|
185
190
|
|
|
186
191
|
if (oneuptimeRequest.userAuthorization.isMasterAdmin) {
|
|
@@ -127,6 +127,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
127
127
|
monitorDestination = `${monitorDestination}:${port}`;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
// For DNS monitors, use the queryName from dnsMonitor config
|
|
132
|
+
if (monitorType === MonitorType.DNS && firstStep?.data?.dnsMonitor) {
|
|
133
|
+
monitorDestination = firstStep.data.dnsMonitor.queryName || "";
|
|
134
|
+
if (firstStep.data.dnsMonitor.hostname) {
|
|
135
|
+
monitorDestination = `${monitorDestination} @${firstStep.data.dnsMonitor.hostname}`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -1805,9 +1805,18 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1805
1805
|
logger.debug("New channel template name:");
|
|
1806
1806
|
logger.debug(notificationChannels);
|
|
1807
1807
|
|
|
1808
|
+
/*
|
|
1809
|
+
* Sanitize the suffix for workspace channel names.
|
|
1810
|
+
* When no custom prefix is set, the default "#" prefix (e.g. "#42") produces
|
|
1811
|
+
* invalid Slack channel names (e.g. "oneuptime-alert-#42"). Strip characters
|
|
1812
|
+
* that are not valid in Slack/Teams channel names.
|
|
1813
|
+
*/
|
|
1814
|
+
const sanitizedSuffix: string = data.channelNameSiffix
|
|
1815
|
+
.toLowerCase()
|
|
1816
|
+
.replace(/[^a-z0-9\-_]/g, "");
|
|
1817
|
+
|
|
1808
1818
|
// add suffix and then check if it is already added or not.
|
|
1809
|
-
const channelName: string =
|
|
1810
|
-
notificationChannels + data.channelNameSiffix;
|
|
1819
|
+
const channelName: string = notificationChannels + sanitizedSuffix;
|
|
1811
1820
|
|
|
1812
1821
|
logger.debug("Final channel name with suffix:");
|
|
1813
1822
|
logger.debug(channelName);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import DataToProcess from "../DataToProcess";
|
|
2
|
+
import CompareCriteria from "./CompareCriteria";
|
|
3
|
+
import {
|
|
4
|
+
CheckOn,
|
|
5
|
+
CriteriaFilter,
|
|
6
|
+
FilterType,
|
|
7
|
+
} from "../../../../Types/Monitor/CriteriaFilter";
|
|
8
|
+
import DnsMonitorResponse from "../../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
|
9
|
+
import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
|
|
10
|
+
import EvaluateOverTime from "./EvaluateOverTime";
|
|
11
|
+
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
|
12
|
+
import logger from "../../Logger";
|
|
13
|
+
|
|
14
|
+
export default class DnsMonitorCriteria {
|
|
15
|
+
@CaptureSpan()
|
|
16
|
+
public static async isMonitorInstanceCriteriaFilterMet(input: {
|
|
17
|
+
dataToProcess: DataToProcess;
|
|
18
|
+
criteriaFilter: CriteriaFilter;
|
|
19
|
+
}): Promise<string | null> {
|
|
20
|
+
let threshold: number | string | undefined | null =
|
|
21
|
+
input.criteriaFilter.value;
|
|
22
|
+
|
|
23
|
+
const dataToProcess: ProbeMonitorResponse =
|
|
24
|
+
input.dataToProcess as ProbeMonitorResponse;
|
|
25
|
+
|
|
26
|
+
const dnsResponse: DnsMonitorResponse | undefined =
|
|
27
|
+
dataToProcess.dnsResponse;
|
|
28
|
+
|
|
29
|
+
let overTimeValue: Array<number | boolean> | number | boolean | undefined =
|
|
30
|
+
undefined;
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
input.criteriaFilter.evaluateOverTime &&
|
|
34
|
+
input.criteriaFilter.evaluateOverTimeOptions
|
|
35
|
+
) {
|
|
36
|
+
try {
|
|
37
|
+
overTimeValue = await EvaluateOverTime.getValueOverTime({
|
|
38
|
+
projectId: (input.dataToProcess as ProbeMonitorResponse).projectId,
|
|
39
|
+
monitorId: input.dataToProcess.monitorId!,
|
|
40
|
+
evaluateOverTimeOptions: input.criteriaFilter.evaluateOverTimeOptions,
|
|
41
|
+
metricType: input.criteriaFilter.checkOn,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(overTimeValue) && overTimeValue.length === 0) {
|
|
45
|
+
overTimeValue = undefined;
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`Error in getting over time value for ${input.criteriaFilter.checkOn}`,
|
|
50
|
+
);
|
|
51
|
+
logger.error(err);
|
|
52
|
+
overTimeValue = undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if DNS is online
|
|
57
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsIsOnline) {
|
|
58
|
+
const currentIsOnline: boolean | Array<boolean> =
|
|
59
|
+
(overTimeValue as Array<boolean>) ||
|
|
60
|
+
(input.dataToProcess as ProbeMonitorResponse).isOnline;
|
|
61
|
+
|
|
62
|
+
return CompareCriteria.compareCriteriaBoolean({
|
|
63
|
+
value: currentIsOnline,
|
|
64
|
+
criteriaFilter: input.criteriaFilter,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check DNS response time
|
|
69
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsResponseTime) {
|
|
70
|
+
threshold = CompareCriteria.convertToNumber(threshold);
|
|
71
|
+
|
|
72
|
+
if (threshold === null || threshold === undefined) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const currentResponseTime: number | Array<number> =
|
|
77
|
+
(overTimeValue as Array<number>) ||
|
|
78
|
+
dnsResponse?.responseTimeInMs ||
|
|
79
|
+
(input.dataToProcess as ProbeMonitorResponse).responseTimeInMs;
|
|
80
|
+
|
|
81
|
+
if (currentResponseTime === null || currentResponseTime === undefined) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return CompareCriteria.compareCriteriaNumbers({
|
|
86
|
+
value: currentResponseTime,
|
|
87
|
+
threshold: threshold as number,
|
|
88
|
+
criteriaFilter: input.criteriaFilter,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if DNS record exists
|
|
93
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordExists) {
|
|
94
|
+
const exists: boolean = Boolean(
|
|
95
|
+
dnsResponse?.records && dnsResponse.records.length > 0,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const isTrue: boolean =
|
|
99
|
+
input.criteriaFilter.filterType === FilterType.True;
|
|
100
|
+
const isFalse: boolean =
|
|
101
|
+
input.criteriaFilter.filterType === FilterType.False;
|
|
102
|
+
|
|
103
|
+
if (exists && isTrue) {
|
|
104
|
+
return `DNS records exist for the query.`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!exists && isFalse) {
|
|
108
|
+
return `No DNS records found for the query.`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check DNSSEC validity
|
|
115
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecIsValid) {
|
|
116
|
+
const isTrue: boolean =
|
|
117
|
+
input.criteriaFilter.filterType === FilterType.True;
|
|
118
|
+
const isFalse: boolean =
|
|
119
|
+
input.criteriaFilter.filterType === FilterType.False;
|
|
120
|
+
|
|
121
|
+
if (dnsResponse?.isDnssecValid === undefined) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (dnsResponse.isDnssecValid && isTrue) {
|
|
126
|
+
return `DNSSEC is valid.`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!dnsResponse.isDnssecValid && isFalse) {
|
|
130
|
+
return `DNSSEC is not valid.`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check DNS record value
|
|
137
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordValue) {
|
|
138
|
+
if (!dnsResponse?.records || dnsResponse.records.length === 0) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check if any record value matches the criteria
|
|
143
|
+
for (const record of dnsResponse.records) {
|
|
144
|
+
const recordValue: string = record.value;
|
|
145
|
+
|
|
146
|
+
// Try numeric comparison first
|
|
147
|
+
if (
|
|
148
|
+
typeof threshold === "number" ||
|
|
149
|
+
(typeof threshold === "string" && !isNaN(Number(threshold)))
|
|
150
|
+
) {
|
|
151
|
+
const numericThreshold: number | null =
|
|
152
|
+
CompareCriteria.convertToNumber(threshold);
|
|
153
|
+
|
|
154
|
+
if (numericThreshold !== null && !isNaN(Number(recordValue))) {
|
|
155
|
+
const result: string | null =
|
|
156
|
+
CompareCriteria.compareCriteriaNumbers({
|
|
157
|
+
value: Number(recordValue),
|
|
158
|
+
threshold: numericThreshold,
|
|
159
|
+
criteriaFilter: input.criteriaFilter,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (result) {
|
|
163
|
+
return `DNS record (${record.type}): ${result}`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// String comparison
|
|
169
|
+
const result: string | null = CompareCriteria.compareCriteriaStrings({
|
|
170
|
+
value: recordValue,
|
|
171
|
+
threshold: String(threshold),
|
|
172
|
+
criteriaFilter: input.criteriaFilter,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (result) {
|
|
176
|
+
return `DNS record (${record.type}): ${result}`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -12,6 +12,7 @@ import MetricMonitorCriteria from "./Criteria/MetricMonitorCriteria";
|
|
|
12
12
|
import TraceMonitorCriteria from "./Criteria/TraceMonitorCriteria";
|
|
13
13
|
import ExceptionMonitorCriteria from "./Criteria/ExceptionMonitorCriteria";
|
|
14
14
|
import SnmpMonitorCriteria from "./Criteria/SnmpMonitorCriteria";
|
|
15
|
+
import DnsMonitorCriteria from "./Criteria/DnsMonitorCriteria";
|
|
15
16
|
import MonitorCriteriaMessageBuilder from "./MonitorCriteriaMessageBuilder";
|
|
16
17
|
import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
|
|
17
18
|
import MonitorCriteriaMessageFormatter from "./MonitorCriteriaMessageFormatter";
|
|
@@ -493,6 +494,18 @@ ${contextBlock}
|
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
496
|
|
|
497
|
+
if (input.monitor.monitorType === MonitorType.DNS) {
|
|
498
|
+
const dnsMonitorResult: string | null =
|
|
499
|
+
await DnsMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
|
500
|
+
dataToProcess: input.dataToProcess,
|
|
501
|
+
criteriaFilter: input.criteriaFilter,
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
if (dnsMonitorResult) {
|
|
505
|
+
return dnsMonitorResult;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
496
509
|
return null;
|
|
497
510
|
}
|
|
498
511
|
|
|
@@ -14,6 +14,9 @@ import SyntheticMonitorResponse from "../../../Types/Monitor/SyntheticMonitors/S
|
|
|
14
14
|
import SnmpMonitorResponse, {
|
|
15
15
|
SnmpOidResponse,
|
|
16
16
|
} from "../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
|
|
17
|
+
import DnsMonitorResponse, {
|
|
18
|
+
DnsRecordResponse,
|
|
19
|
+
} from "../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
|
17
20
|
import Typeof from "../../../Types/Typeof";
|
|
18
21
|
import VMUtil from "../VM/VMAPI";
|
|
19
22
|
import DataToProcess from "./DataToProcess";
|
|
@@ -240,6 +243,40 @@ export default class MonitorTemplateUtil {
|
|
|
240
243
|
}
|
|
241
244
|
}
|
|
242
245
|
}
|
|
246
|
+
|
|
247
|
+
if (data.monitorType === MonitorType.DNS) {
|
|
248
|
+
const dnsResponse: DnsMonitorResponse | undefined = (
|
|
249
|
+
data.dataToProcess as ProbeMonitorResponse
|
|
250
|
+
).dnsResponse;
|
|
251
|
+
|
|
252
|
+
storageMap = {
|
|
253
|
+
isOnline: (data.dataToProcess as ProbeMonitorResponse).isOnline,
|
|
254
|
+
responseTimeInMs: dnsResponse?.responseTimeInMs,
|
|
255
|
+
failureCause: dnsResponse?.failureCause,
|
|
256
|
+
isTimeout: dnsResponse?.isTimeout,
|
|
257
|
+
isDnssecValid: dnsResponse?.isDnssecValid,
|
|
258
|
+
} as JSONObject;
|
|
259
|
+
|
|
260
|
+
// Add DNS records
|
|
261
|
+
if (dnsResponse?.records) {
|
|
262
|
+
storageMap["records"] = dnsResponse.records.map(
|
|
263
|
+
(record: DnsRecordResponse) => {
|
|
264
|
+
return {
|
|
265
|
+
type: record.type,
|
|
266
|
+
value: record.value,
|
|
267
|
+
ttl: record.ttl,
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// Add record values as a flat array for easier templating
|
|
273
|
+
storageMap["recordValues"] = dnsResponse.records.map(
|
|
274
|
+
(record: DnsRecordResponse) => {
|
|
275
|
+
return record.value;
|
|
276
|
+
},
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
243
280
|
} catch (err) {
|
|
244
281
|
logger.error(err);
|
|
245
282
|
}
|
|
@@ -780,13 +780,14 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
780
780
|
|
|
781
781
|
const workspaceChannels: Array<WorkspaceChannel> = [];
|
|
782
782
|
|
|
783
|
-
for (
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
783
|
+
for (const channelName of data.channelNames) {
|
|
784
|
+
/*
|
|
785
|
+
* Normalize channel name: replace spaces with hyphens, then strip
|
|
786
|
+
* characters not valid in Teams channel names (e.g. #, %, &, *, etc.).
|
|
787
|
+
*/
|
|
788
|
+
const normalizedChannelName: string = channelName
|
|
789
|
+
.replace(/\s+/g, "-")
|
|
790
|
+
.replace(/[^a-zA-Z0-9\-_]/g, "");
|
|
790
791
|
|
|
791
792
|
// Check if channel exists
|
|
792
793
|
const existingChannel: WorkspaceChannel | null =
|
|
@@ -839,6 +840,9 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
839
840
|
}): Promise<WorkspaceChannel> {
|
|
840
841
|
const teamId: string = data.teamId;
|
|
841
842
|
|
|
843
|
+
// Sanitize channel name: strip characters not valid in Teams channel names.
|
|
844
|
+
data.channelName = data.channelName.replace(/[^a-zA-Z0-9\-_\s]/g, "");
|
|
845
|
+
|
|
842
846
|
// Get valid access token
|
|
843
847
|
const accessToken: string = await this.getValidAccessToken({
|
|
844
848
|
authToken: data.authToken,
|
|
@@ -442,12 +442,14 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
442
442
|
const workspaceChannels: Array<WorkspaceChannel> = [];
|
|
443
443
|
|
|
444
444
|
for (let channelName of data.channelNames) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
channelName = channelName
|
|
450
|
-
|
|
445
|
+
/*
|
|
446
|
+
* Normalize channel name: replace spaces with hyphens, then strip
|
|
447
|
+
* any characters not valid in Slack channel names.
|
|
448
|
+
*/
|
|
449
|
+
channelName = channelName
|
|
450
|
+
.toLowerCase()
|
|
451
|
+
.replace(/\s+/g, "-")
|
|
452
|
+
.replace(/[^a-z0-9\-_]/g, "");
|
|
451
453
|
|
|
452
454
|
// Check if channel exists using optimized method
|
|
453
455
|
const existingChannel: WorkspaceChannel | null =
|
|
@@ -1345,12 +1347,13 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
1345
1347
|
channelName: string;
|
|
1346
1348
|
projectId: ObjectID;
|
|
1347
1349
|
}): Promise<WorkspaceChannel> {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1350
|
+
/*
|
|
1351
|
+
* Sanitize channel name: Slack only allows lowercase letters, numbers,
|
|
1352
|
+
* hyphens, and underscores. Remove all other characters (including #).
|
|
1353
|
+
*/
|
|
1354
|
+
data.channelName = data.channelName
|
|
1355
|
+
.toLowerCase()
|
|
1356
|
+
.replace(/[^a-z0-9\-_]/g, "");
|
|
1354
1357
|
|
|
1355
1358
|
logger.debug("Creating channel with data:");
|
|
1356
1359
|
logger.debug(data);
|
|
@@ -14,6 +14,7 @@ import Response from "../../../Server/Utils/Response";
|
|
|
14
14
|
import Dictionary from "../../../Types/Dictionary";
|
|
15
15
|
import Email from "../../../Types/Email";
|
|
16
16
|
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
17
|
+
import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
|
|
17
18
|
import SsoAuthorizationException from "../../../Types/Exception/SsoAuthorizationException";
|
|
18
19
|
import HashedString from "../../../Types/HashedString";
|
|
19
20
|
import JSONFunctions from "../../../Types/JSONFunctions";
|
|
@@ -330,7 +331,7 @@ describe("UserMiddleware", () => {
|
|
|
330
331
|
expect(JSONWebToken.decode).not.toHaveBeenCalled();
|
|
331
332
|
});
|
|
332
333
|
|
|
333
|
-
test("should call
|
|
334
|
+
test("should call Response.sendErrorResponse with NotAuthenticatedException, when accessToken can not be decoded", async () => {
|
|
334
335
|
const error: Error = new Error("Invalid access token");
|
|
335
336
|
|
|
336
337
|
const spyJWTDecode: jest.SpyInstance = getJestSpyOn(
|
|
@@ -342,7 +343,14 @@ describe("UserMiddleware", () => {
|
|
|
342
343
|
|
|
343
344
|
await UserMiddleware.getUserMiddleware(req, res, next);
|
|
344
345
|
|
|
345
|
-
expect(
|
|
346
|
+
expect(Response.sendErrorResponse).toHaveBeenCalledWith(
|
|
347
|
+
req,
|
|
348
|
+
res,
|
|
349
|
+
new NotAuthenticatedException(
|
|
350
|
+
"AccessToken is invalid or expired. Please refresh your token.",
|
|
351
|
+
),
|
|
352
|
+
);
|
|
353
|
+
expect(next).not.toHaveBeenCalled();
|
|
346
354
|
expect(spyJWTDecode).toHaveBeenCalledWith(mockedAccessToken);
|
|
347
355
|
expect(UserService.updateOneBy).not.toHaveBeenCalled();
|
|
348
356
|
});
|
|
@@ -60,6 +60,13 @@ export enum CheckOn {
|
|
|
60
60
|
SnmpOidExists = "SNMP OID Exists",
|
|
61
61
|
SnmpResponseTime = "SNMP Response Time (in ms)",
|
|
62
62
|
SnmpIsOnline = "SNMP Device Is Online",
|
|
63
|
+
|
|
64
|
+
// DNS monitors.
|
|
65
|
+
DnsResponseTime = "DNS Response Time (in ms)",
|
|
66
|
+
DnsIsOnline = "DNS Is Online",
|
|
67
|
+
DnsRecordValue = "DNS Record Value",
|
|
68
|
+
DnssecIsValid = "DNSSEC Is Valid",
|
|
69
|
+
DnsRecordExists = "DNS Record Exists",
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
export interface ServerMonitorOptions {
|
|
@@ -141,7 +148,11 @@ export class CriteriaFilterUtil {
|
|
|
141
148
|
}): boolean {
|
|
142
149
|
const { checkOn } = data;
|
|
143
150
|
|
|
144
|
-
if (
|
|
151
|
+
if (
|
|
152
|
+
checkOn === CheckOn.IsOnline ||
|
|
153
|
+
checkOn === CheckOn.SnmpIsOnline ||
|
|
154
|
+
checkOn === CheckOn.DnsIsOnline
|
|
155
|
+
) {
|
|
145
156
|
return false;
|
|
146
157
|
}
|
|
147
158
|
|
|
@@ -149,7 +160,11 @@ export class CriteriaFilterUtil {
|
|
|
149
160
|
return false;
|
|
150
161
|
}
|
|
151
162
|
|
|
152
|
-
if (
|
|
163
|
+
if (
|
|
164
|
+
checkOn === CheckOn.SnmpOidExists ||
|
|
165
|
+
checkOn === CheckOn.DnssecIsValid ||
|
|
166
|
+
checkOn === CheckOn.DnsRecordExists
|
|
167
|
+
) {
|
|
153
168
|
return false;
|
|
154
169
|
}
|
|
155
170
|
|
|
@@ -204,7 +219,9 @@ export class CriteriaFilterUtil {
|
|
|
204
219
|
checkOn === CheckOn.MemoryUsagePercent ||
|
|
205
220
|
checkOn === CheckOn.IsOnline ||
|
|
206
221
|
checkOn === CheckOn.SnmpResponseTime ||
|
|
207
|
-
checkOn === CheckOn.SnmpIsOnline
|
|
222
|
+
checkOn === CheckOn.SnmpIsOnline ||
|
|
223
|
+
checkOn === CheckOn.DnsResponseTime ||
|
|
224
|
+
checkOn === CheckOn.DnsIsOnline
|
|
208
225
|
);
|
|
209
226
|
}
|
|
210
227
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import DnsRecordType from "./DnsRecordType";
|
|
2
|
+
|
|
3
|
+
export interface DnsRecordResponse {
|
|
4
|
+
type: DnsRecordType;
|
|
5
|
+
value: string;
|
|
6
|
+
ttl?: number | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default interface DnsMonitorResponse {
|
|
10
|
+
isOnline: boolean;
|
|
11
|
+
responseTimeInMs: number;
|
|
12
|
+
failureCause: string;
|
|
13
|
+
records: Array<DnsRecordResponse>;
|
|
14
|
+
isDnssecValid?: boolean | undefined;
|
|
15
|
+
isTimeout?: boolean | undefined;
|
|
16
|
+
}
|
|
@@ -394,6 +394,33 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
394
394
|
return monitorCriteriaInstance;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
+
if (arg.monitorType === MonitorType.DNS) {
|
|
398
|
+
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
|
399
|
+
new MonitorCriteriaInstance();
|
|
400
|
+
|
|
401
|
+
monitorCriteriaInstance.data = {
|
|
402
|
+
id: ObjectID.generate().toString(),
|
|
403
|
+
monitorStatusId: arg.monitorStatusId,
|
|
404
|
+
filterCondition: FilterCondition.All,
|
|
405
|
+
filters: [
|
|
406
|
+
{
|
|
407
|
+
checkOn: CheckOn.DnsIsOnline,
|
|
408
|
+
filterType: FilterType.True,
|
|
409
|
+
value: undefined,
|
|
410
|
+
},
|
|
411
|
+
],
|
|
412
|
+
incidents: [],
|
|
413
|
+
alerts: [],
|
|
414
|
+
createAlerts: false,
|
|
415
|
+
changeMonitorStatus: true,
|
|
416
|
+
createIncidents: false,
|
|
417
|
+
name: `Check if ${arg.monitorName} is online`,
|
|
418
|
+
description: `This criteria checks if the ${arg.monitorName} DNS resolution is online`,
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
return monitorCriteriaInstance;
|
|
422
|
+
}
|
|
423
|
+
|
|
397
424
|
return null;
|
|
398
425
|
}
|
|
399
426
|
|
|
@@ -495,6 +522,46 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
495
522
|
};
|
|
496
523
|
}
|
|
497
524
|
|
|
525
|
+
if (arg.monitorType === MonitorType.DNS) {
|
|
526
|
+
monitorCriteriaInstance.data = {
|
|
527
|
+
id: ObjectID.generate().toString(),
|
|
528
|
+
monitorStatusId: arg.monitorStatusId,
|
|
529
|
+
filterCondition: FilterCondition.Any,
|
|
530
|
+
filters: [
|
|
531
|
+
{
|
|
532
|
+
checkOn: CheckOn.DnsIsOnline,
|
|
533
|
+
filterType: FilterType.False,
|
|
534
|
+
value: undefined,
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
incidents: [
|
|
538
|
+
{
|
|
539
|
+
title: `${arg.monitorName} is offline`,
|
|
540
|
+
description: `${arg.monitorName} DNS resolution is currently failing.`,
|
|
541
|
+
incidentSeverityId: arg.incidentSeverityId,
|
|
542
|
+
autoResolveIncident: true,
|
|
543
|
+
id: ObjectID.generate().toString(),
|
|
544
|
+
onCallPolicyIds: [],
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
changeMonitorStatus: true,
|
|
548
|
+
createIncidents: true,
|
|
549
|
+
createAlerts: false,
|
|
550
|
+
alerts: [
|
|
551
|
+
{
|
|
552
|
+
title: `${arg.monitorName} is offline`,
|
|
553
|
+
description: `${arg.monitorName} DNS resolution is currently failing.`,
|
|
554
|
+
alertSeverityId: arg.alertSeverityId,
|
|
555
|
+
autoResolveAlert: true,
|
|
556
|
+
id: ObjectID.generate().toString(),
|
|
557
|
+
onCallPolicyIds: [],
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
name: `Check if ${arg.monitorName} is offline`,
|
|
561
|
+
description: `This criteria checks if the ${arg.monitorName} DNS resolution is failing`,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
498
565
|
if (
|
|
499
566
|
arg.monitorType === MonitorType.API ||
|
|
500
567
|
arg.monitorType === MonitorType.Website
|