@oneuptime/common 14.0.0 → 14.0.1
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/Index.ts +4 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorService.ts +3 -2
- package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
- package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
- package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Markdown.test.ts +2 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
- package/Tests/Types/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
- package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/UI/Components/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/Utils/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.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/Services/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +3 -2
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
- package/build/dist/Types/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/Utils/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import Hostname from "../../../Types/API/Hostname";
|
|
2
|
+
import Protocol from "../../../Types/API/Protocol";
|
|
3
|
+
import Route from "../../../Types/API/Route";
|
|
4
|
+
import URL from "../../../Types/API/URL";
|
|
5
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
6
|
+
import { describe, expect, test } from "@jest/globals";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Route refuses any value that starts with a scheme ("javascript:...", but
|
|
10
|
+
* equally "bot123:ABC/sendMessage"), so a scheme can never reach a navigation
|
|
11
|
+
* sink. URL.fromString stores a parsed path WITHOUT the "/" that separates it
|
|
12
|
+
* from the authority, and handed that bare path to Route. So any URL whose
|
|
13
|
+
* first path segment contains a ":" stopped parsing:
|
|
14
|
+
*
|
|
15
|
+
* URL.fromString("https://api.telegram.org/bot123:ABC/sendMessage")
|
|
16
|
+
* => BadDataException "Invalid route: bot123:ABC/sendMessage"
|
|
17
|
+
*
|
|
18
|
+
* Telegram puts the bot token - always "<id>:<secret>" - in exactly that
|
|
19
|
+
* segment. That broke the Telegram workflow component (and put the token in
|
|
20
|
+
* the run log), every API component call to Telegram, and every sandboxed
|
|
21
|
+
* axios call to Telegram, where the SSRF guard's parse failure surfaced as
|
|
22
|
+
* "Request URL is not a valid URL".
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Same shape as a real token: 10-digit bot id, 35-character secret.
|
|
26
|
+
const BOT_TOKEN: string = "8000000001:AAFakeFakeFakeFakeFakeFakeFake_-12345";
|
|
27
|
+
const TELEGRAM_URL: string = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
|
|
28
|
+
|
|
29
|
+
describe("URL.fromString - Telegram Bot API URLs", () => {
|
|
30
|
+
test("parses the sendMessage URL instead of throwing Invalid route", () => {
|
|
31
|
+
expect(() => {
|
|
32
|
+
return URL.fromString(TELEGRAM_URL);
|
|
33
|
+
}).not.toThrow();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("round-trips to exactly the string that was parsed", () => {
|
|
37
|
+
expect(URL.fromString(TELEGRAM_URL).toString()).toBe(TELEGRAM_URL);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("puts the whole bot token in the path, not in the host or port", () => {
|
|
41
|
+
const url: URL = URL.fromString(TELEGRAM_URL);
|
|
42
|
+
|
|
43
|
+
expect(url.protocol).toBe(Protocol.HTTPS);
|
|
44
|
+
expect(url.hostname.hostname).toBe("api.telegram.org");
|
|
45
|
+
expect(url.hostname.port).toBeUndefined();
|
|
46
|
+
expect(url.route.toString()).toBe(`/bot${BOT_TOKEN}/sendMessage`);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("agrees with the WHATWG parser the HTTP client uses", () => {
|
|
50
|
+
const whatwg: globalThis.URL = new globalThis.URL(TELEGRAM_URL);
|
|
51
|
+
const url: URL = URL.fromString(TELEGRAM_URL);
|
|
52
|
+
|
|
53
|
+
expect(url.hostname.hostname).toBe(whatwg.hostname);
|
|
54
|
+
expect(url.route.toString()).toBe(whatwg.pathname);
|
|
55
|
+
expect(url.toString()).toBe(whatwg.href);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test.each([
|
|
59
|
+
"getMe",
|
|
60
|
+
"sendMessage",
|
|
61
|
+
"sendPhoto",
|
|
62
|
+
"getUpdates",
|
|
63
|
+
"setWebhook",
|
|
64
|
+
"getWebhookInfo",
|
|
65
|
+
])("parses the %s method URL", (method: string) => {
|
|
66
|
+
const raw: string = `https://api.telegram.org/bot${BOT_TOKEN}/${method}`;
|
|
67
|
+
|
|
68
|
+
expect(URL.fromString(raw).toString()).toBe(raw);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("keeps query parameters on a Telegram URL", () => {
|
|
72
|
+
const raw: string = `${TELEGRAM_URL}?chat_id=@mychannel&text=hello`;
|
|
73
|
+
const url: URL = URL.fromString(raw);
|
|
74
|
+
|
|
75
|
+
expect(url.route.toString()).toBe(`/bot${BOT_TOKEN}/sendMessage`);
|
|
76
|
+
expect(url.getQueryParam("chat_id")).toBe("@mychannel");
|
|
77
|
+
expect(url.getQueryParam("text")).toBe("hello");
|
|
78
|
+
expect(url.toString()).toBe(raw);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("keeps the file download path, whose token is not the first segment", () => {
|
|
82
|
+
const raw: string = `https://api.telegram.org/file/bot${BOT_TOKEN}/photos/file_1.jpg`;
|
|
83
|
+
|
|
84
|
+
expect(URL.fromString(raw).toString()).toBe(raw);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("fromStringLenient returns a real URL, not a malformed placeholder", () => {
|
|
88
|
+
const url: URL = URL.fromStringLenient(TELEGRAM_URL);
|
|
89
|
+
|
|
90
|
+
expect(url.isMalformed()).toBe(false);
|
|
91
|
+
expect(url.hostname.hostname).toBe("api.telegram.org");
|
|
92
|
+
expect(url.toString()).toBe(TELEGRAM_URL);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("survives fromURL, toJSON and fromJSON", () => {
|
|
96
|
+
const url: URL = URL.fromString(TELEGRAM_URL);
|
|
97
|
+
|
|
98
|
+
expect(URL.fromURL(url).toString()).toBe(TELEGRAM_URL);
|
|
99
|
+
|
|
100
|
+
const revived: URL = URL.fromJSON(url.toJSON());
|
|
101
|
+
expect(revived.isMalformed()).toBe(false);
|
|
102
|
+
expect(revived.toString()).toBe(TELEGRAM_URL);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("removeQueryString keeps the token path", () => {
|
|
106
|
+
const url: URL = URL.fromString(`${TELEGRAM_URL}?chat_id=1`);
|
|
107
|
+
|
|
108
|
+
expect(url.removeQueryString().toString()).toBe(TELEGRAM_URL);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("addQueryParam appends to a Telegram URL", () => {
|
|
112
|
+
const url: URL = URL.fromString(TELEGRAM_URL).addQueryParam(
|
|
113
|
+
"chat_id",
|
|
114
|
+
"@my channel",
|
|
115
|
+
true,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(url.toString()).toBe(`${TELEGRAM_URL}?chat_id=%40my%20channel`);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("getLastRoute reads the method and the token segment", () => {
|
|
122
|
+
const url: URL = URL.fromString(TELEGRAM_URL);
|
|
123
|
+
|
|
124
|
+
expect(url.getLastRoute()?.toString()).toBe("/sendMessage");
|
|
125
|
+
expect(url.getLastRoute(1)?.toString()).toBe(`/bot${BOT_TOKEN}`);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("URL.fromString - any first path segment containing a ':'", () => {
|
|
130
|
+
test.each([
|
|
131
|
+
["an id:secret pair", "https://example.com/abc:def"],
|
|
132
|
+
["a URN", "https://example.com/urn:uuid:6e8bc430-9c3a-11d9-9669"],
|
|
133
|
+
["a trailing slash", "https://example.com/bot1:abc/"],
|
|
134
|
+
["a single segment", "https://example.com/bot1:abc"],
|
|
135
|
+
["a port", "https://example.com:8443/bot1:abc/sendMessage"],
|
|
136
|
+
["userinfo", "https://user:pw@example.com/bot1:abc/sendMessage"],
|
|
137
|
+
["plain http", "http://example.com/bot1:abc/sendMessage"],
|
|
138
|
+
["a fragment", "https://example.com/bot1:abc/sendMessage#top"],
|
|
139
|
+
["a query", "https://example.com/bot1:abc/sendMessage?a=1&b=2"],
|
|
140
|
+
["a dotted scheme-like name", "https://example.com/a.b+c-d:e/f"],
|
|
141
|
+
])("parses and round-trips a path with %s", (_label: string, raw: string) => {
|
|
142
|
+
const url: URL = URL.fromString(raw);
|
|
143
|
+
|
|
144
|
+
expect(url.toString()).toBe(raw);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("an uppercase scheme on the URL is normalised, the path is kept", () => {
|
|
148
|
+
const url: URL = URL.fromString(
|
|
149
|
+
"HTTPS://api.telegram.org/bot1:abc/sendMessage",
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(url.toString()).toBe(
|
|
153
|
+
"https://api.telegram.org/bot1:abc/sendMessage",
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("a path that merely looks like a dangerous scheme stays a path", () => {
|
|
158
|
+
/*
|
|
159
|
+
* Before Route refused scheme-like values this parsed to a route of
|
|
160
|
+
* "javascript:alert(1)" - a value that is a live href on its own. It now
|
|
161
|
+
* keeps its "/", so the Route is a same-origin path and can never be
|
|
162
|
+
* mistaken for a scheme by anything that renders it.
|
|
163
|
+
*/
|
|
164
|
+
const url: URL = URL.fromString("https://example.com/javascript:alert(1)");
|
|
165
|
+
const route: string = url.route.toString();
|
|
166
|
+
|
|
167
|
+
expect(url.hostname.hostname).toBe("example.com");
|
|
168
|
+
expect(route).toBe("/javascript:alert(1)");
|
|
169
|
+
expect(route.startsWith("/")).toBe(true);
|
|
170
|
+
expect(Route.hasSchemePrefix(route)).toBe(false);
|
|
171
|
+
expect(url.toString()).toBe("https://example.com/javascript:alert(1)");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test.each([
|
|
175
|
+
"https://example.com/bot1:abc/sendMessage",
|
|
176
|
+
"https://example.com/mailto:someone@example.com",
|
|
177
|
+
"https://example.com/data:text/plain,hi",
|
|
178
|
+
"https://example.com/urn:isbn:0451450523",
|
|
179
|
+
])("the route of %s is never itself scheme-like", (raw: string) => {
|
|
180
|
+
expect(Route.hasSchemePrefix(URL.fromString(raw).route.toString())).toBe(
|
|
181
|
+
false,
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("the host is still read off the authority, never off the path", () => {
|
|
186
|
+
// The ":" in the path must not be mistaken for a host:port separator.
|
|
187
|
+
const url: URL = URL.fromString("https://10.0.0.5/bot1:80/sendMessage");
|
|
188
|
+
|
|
189
|
+
expect(url.hostname.hostname).toBe("10.0.0.5");
|
|
190
|
+
expect(url.hostname.port).toBeUndefined();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("URL.fromString - paths that already parsed are unchanged", () => {
|
|
195
|
+
/*
|
|
196
|
+
* The leading "/" is only kept when dropping it would make the path read as
|
|
197
|
+
* a scheme. Every other path keeps the bare representation it always had,
|
|
198
|
+
* so nothing that read url.route before this change sees a different value.
|
|
199
|
+
*/
|
|
200
|
+
test.each([
|
|
201
|
+
["https://example.com/api/v1/items", "api/v1/items"],
|
|
202
|
+
["https://example.com/docs#section", "docs#section"],
|
|
203
|
+
["https://example.com#section", "#section"],
|
|
204
|
+
["https://example.com/p/", "p/"],
|
|
205
|
+
["https://vision.googleapis.com/v1/images:annotate", "v1/images:annotate"],
|
|
206
|
+
["https://example.com/api/:resourceId", "api/:resourceId"],
|
|
207
|
+
["https://example.com/1:2/x", "1:2/x"],
|
|
208
|
+
[
|
|
209
|
+
"https://example.com/_matrix/client/v3/rooms/!r:m.org",
|
|
210
|
+
"_matrix/client/v3/rooms/!r:m.org",
|
|
211
|
+
],
|
|
212
|
+
["https://example.com/:leading-colon", ":leading-colon"],
|
|
213
|
+
["https://example.com/events?at=12:30", "events"],
|
|
214
|
+
["https://example.com", ""],
|
|
215
|
+
["https://example.com/", ""],
|
|
216
|
+
])("%s keeps route %s", (raw: string, expectedRoute: string) => {
|
|
217
|
+
expect(URL.fromString(raw).route.toString()).toBe(expectedRoute);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe("URL.fromString - '~' in a path", () => {
|
|
222
|
+
/*
|
|
223
|
+
* "~" is an RFC 3986 unreserved character, but Route's character allowlist
|
|
224
|
+
* left it out, so "https://example.com/~user" could not be parsed - and the
|
|
225
|
+
* sandboxed axios bridge refused it as "Request URL is not a valid URL".
|
|
226
|
+
*/
|
|
227
|
+
test.each([
|
|
228
|
+
"https://example.com/~user/hook",
|
|
229
|
+
"https://example.com/files/~backup",
|
|
230
|
+
"https://example.com/a~b/c",
|
|
231
|
+
"https://example.com/path?x=~y",
|
|
232
|
+
])("parses and round-trips %s", (raw: string) => {
|
|
233
|
+
expect(URL.fromString(raw).toString()).toBe(raw);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe("URL.addRoute with a scheme-like segment", () => {
|
|
238
|
+
test("appends a string segment that starts with a token", () => {
|
|
239
|
+
const url: URL = URL.fromString("https://api.telegram.org").addRoute(
|
|
240
|
+
`bot${BOT_TOKEN}/sendMessage`,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
expect(url.toString()).toBe(TELEGRAM_URL);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("appends the same segment given with its leading slash", () => {
|
|
247
|
+
const url: URL = URL.fromString("https://api.telegram.org").addRoute(
|
|
248
|
+
`/bot${BOT_TOKEN}/sendMessage`,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
expect(url.toString()).toBe(TELEGRAM_URL);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("appends a method to a URL that already ends in the token", () => {
|
|
255
|
+
const url: URL = URL.fromString(
|
|
256
|
+
`https://api.telegram.org/bot${BOT_TOKEN}`,
|
|
257
|
+
).addRoute("sendMessage");
|
|
258
|
+
|
|
259
|
+
expect(url.toString()).toBe(TELEGRAM_URL);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("appends to a URL built from the constructor", () => {
|
|
263
|
+
const url: URL = new URL(
|
|
264
|
+
Protocol.HTTPS,
|
|
265
|
+
new Hostname("api.telegram.org"),
|
|
266
|
+
).addRoute(`bot${BOT_TOKEN}/sendMessage`);
|
|
267
|
+
|
|
268
|
+
expect(url.toString()).toBe(TELEGRAM_URL);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test("still behaves as before for an ordinary segment", () => {
|
|
272
|
+
expect(
|
|
273
|
+
URL.fromString("https://example.com/api").addRoute("v1/items").toString(),
|
|
274
|
+
).toBe("https://example.com/api/v1/items");
|
|
275
|
+
expect(
|
|
276
|
+
URL.fromString("https://example.com/api").addRoute("/v1").toString(),
|
|
277
|
+
).toBe("https://example.com/api/v1");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("still refuses characters no route may contain", () => {
|
|
281
|
+
expect(() => {
|
|
282
|
+
URL.fromString("https://example.com").addRoute("a b");
|
|
283
|
+
}).toThrowError(BadDataException);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe("URL.fromString - the scheme checks are not loosened", () => {
|
|
288
|
+
test.each([
|
|
289
|
+
"javascript:alert(1)",
|
|
290
|
+
"data:text/html,<script>alert(1)</script>",
|
|
291
|
+
"file:///etc/passwd",
|
|
292
|
+
"ftp://example.com/bot1:abc/sendMessage",
|
|
293
|
+
])("still refuses %s", (raw: string) => {
|
|
294
|
+
expect(() => {
|
|
295
|
+
return URL.fromString(raw);
|
|
296
|
+
}).toThrowError(BadDataException);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test("a bare scheme-like Route is still refused on its own", () => {
|
|
300
|
+
expect(() => {
|
|
301
|
+
return new Route(`bot${BOT_TOKEN}/sendMessage`);
|
|
302
|
+
}).toThrowError(BadDataException);
|
|
303
|
+
});
|
|
304
|
+
});
|