@oneuptime/common 7.0.4263 → 7.0.4295
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/StatusPage.ts +39 -0
- package/Server/API/OpenAPI.ts +29 -0
- package/Server/API/StatusPageAPI.ts +85 -114
- package/Server/EnvironmentConfig.ts +1 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.ts +15 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/BillingInvoiceService.ts +5 -3
- package/Server/Services/StatusPageDomainService.ts +31 -0
- package/Server/Services/StatusPageService.ts +89 -24
- package/Server/Types/ConfigLogLevel.ts +9 -0
- package/Server/Utils/Logger.ts +2 -1
- package/Server/Utils/OpenAPI.ts +370 -0
- package/Tests/Server/API/BaseAPI.test.ts +4 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +7 -6
- package/Types/Billing/SubscriptionStatus.ts +1 -0
- package/Types/Exception/ExceptionCode.ts +1 -0
- package/Types/Exception/ForbiddenException.ts +8 -0
- package/Types/IP/IP.ts +88 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +0 -2
- package/UI/Utils/API/API.ts +15 -5
- package/UI/Utils/Cookie.ts +9 -0
- package/UI/Utils/User.ts +1 -0
- package/Utils/DNSUtil.ts +24 -0
- package/Utils/Schema/ModelSchema.ts +247 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js +40 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Server/API/OpenAPI.js +14 -0
- package/build/dist/Server/API/OpenAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +78 -62
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +1 -8
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/BillingInvoiceService.js +3 -3
- package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +19 -0
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +66 -21
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Types/ConfigLogLevel.js +10 -0
- package/build/dist/Server/Types/ConfigLogLevel.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +2 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/OpenAPI.js +334 -0
- package/build/dist/Server/Utils/OpenAPI.js.map +1 -0
- package/build/dist/Tests/Server/API/BaseAPI.test.js +4 -0
- package/build/dist/Tests/Server/API/BaseAPI.test.js.map +1 -1
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +7 -6
- package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +1 -1
- package/build/dist/Types/Billing/SubscriptionStatus.js +1 -0
- package/build/dist/Types/Billing/SubscriptionStatus.js.map +1 -1
- package/build/dist/Types/Exception/ExceptionCode.js +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/ForbiddenException.js +8 -0
- package/build/dist/Types/Exception/ForbiddenException.js.map +1 -0
- package/build/dist/Types/IP/IP.js +66 -0
- package/build/dist/Types/IP/IP.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Utils/API/API.js +11 -5
- package/build/dist/UI/Utils/API/API.js.map +1 -1
- package/build/dist/UI/Utils/Cookie.js +8 -0
- package/build/dist/UI/Utils/Cookie.js.map +1 -1
- package/build/dist/UI/Utils/User.js +1 -0
- package/build/dist/UI/Utils/User.js.map +1 -1
- package/build/dist/Utils/DNSUtil.js +19 -0
- package/build/dist/Utils/DNSUtil.js.map +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js +181 -0
- package/build/dist/Utils/Schema/ModelSchema.js.map +1 -0
- package/package.json +4 -2
|
@@ -2158,4 +2158,43 @@ export default class StatusPage extends BaseModel {
|
|
|
2158
2158
|
create: PlanType.Free,
|
|
2159
2159
|
})
|
|
2160
2160
|
public showSubscriberPageOnStatusPage?: boolean = undefined;
|
|
2161
|
+
|
|
2162
|
+
@ColumnAccessControl({
|
|
2163
|
+
create: [
|
|
2164
|
+
Permission.ProjectOwner,
|
|
2165
|
+
Permission.ProjectAdmin,
|
|
2166
|
+
Permission.ProjectMember,
|
|
2167
|
+
Permission.CreateProjectStatusPage,
|
|
2168
|
+
],
|
|
2169
|
+
read: [
|
|
2170
|
+
Permission.ProjectOwner,
|
|
2171
|
+
Permission.ProjectAdmin,
|
|
2172
|
+
Permission.ProjectMember,
|
|
2173
|
+
Permission.ReadProjectStatusPage,
|
|
2174
|
+
],
|
|
2175
|
+
update: [
|
|
2176
|
+
Permission.ProjectOwner,
|
|
2177
|
+
Permission.ProjectAdmin,
|
|
2178
|
+
Permission.ProjectMember,
|
|
2179
|
+
Permission.EditProjectStatusPage,
|
|
2180
|
+
],
|
|
2181
|
+
})
|
|
2182
|
+
@TableColumn({
|
|
2183
|
+
isDefaultValueColumn: false,
|
|
2184
|
+
required: false,
|
|
2185
|
+
type: TableColumnType.VeryLongText,
|
|
2186
|
+
title: "IP Whitelist",
|
|
2187
|
+
description:
|
|
2188
|
+
"IP Whitelist for this Status Page. One IP per line. Only used if the status page is private.",
|
|
2189
|
+
})
|
|
2190
|
+
@Column({
|
|
2191
|
+
type: ColumnType.VeryLongText,
|
|
2192
|
+
nullable: true,
|
|
2193
|
+
})
|
|
2194
|
+
@ColumnBillingAccessControl({
|
|
2195
|
+
read: PlanType.Free,
|
|
2196
|
+
update: PlanType.Scale,
|
|
2197
|
+
create: PlanType.Free,
|
|
2198
|
+
})
|
|
2199
|
+
public ipWhitelist?: string = undefined;
|
|
2161
2200
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Express, {
|
|
2
|
+
ExpressRequest,
|
|
3
|
+
ExpressResponse,
|
|
4
|
+
ExpressRouter,
|
|
5
|
+
} from "../Utils/Express";
|
|
6
|
+
import Response from "../Utils/Response";
|
|
7
|
+
import { JSONObject } from "../../Types/JSON";
|
|
8
|
+
import OpenAPIUtil from "../Utils/OpenAPI";
|
|
9
|
+
|
|
10
|
+
export interface StatusAPIOptions {
|
|
11
|
+
readyCheck: () => Promise<void>;
|
|
12
|
+
liveCheck: () => Promise<void>;
|
|
13
|
+
globalCacheCheck?: (() => Promise<void>) | undefined;
|
|
14
|
+
analyticsDatabaseCheck?: (() => Promise<void>) | undefined;
|
|
15
|
+
databaseCheck?: (() => Promise<void>) | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default class OpenAPI {
|
|
19
|
+
public static getRouter(): ExpressRouter {
|
|
20
|
+
const router: ExpressRouter = Express.getRouter();
|
|
21
|
+
|
|
22
|
+
router.get("/openapi", (req: ExpressRequest, res: ExpressResponse) => {
|
|
23
|
+
const openAPISpec: JSONObject = OpenAPIUtil.generateOpenAPISpec();
|
|
24
|
+
return Response.sendJsonObjectResponse(req, res, openAPISpec);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return router;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -34,10 +34,8 @@ import {
|
|
|
34
34
|
import logger from "../Utils/Logger";
|
|
35
35
|
import Response from "../Utils/Response";
|
|
36
36
|
import BaseAPI from "./BaseAPI";
|
|
37
|
-
import CommonAPI from "./CommonAPI";
|
|
38
37
|
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
39
38
|
import ArrayUtil from "../../Utils/Array";
|
|
40
|
-
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
41
39
|
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
42
40
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
43
41
|
import OneUptimeDate from "../../Types/Date";
|
|
@@ -90,6 +88,7 @@ import Protocol from "../../Types/API/Protocol";
|
|
|
90
88
|
import DatabaseConfig from "../DatabaseConfig";
|
|
91
89
|
import { FileRoute } from "../../ServiceRoute";
|
|
92
90
|
import ProjectSmtpConfigService from "../Services/ProjectSmtpConfigService";
|
|
91
|
+
import ForbiddenException from "../../Types/Exception/ForbiddenException";
|
|
93
92
|
|
|
94
93
|
export default class StatusPageAPI extends BaseAPI<
|
|
95
94
|
StatusPage,
|
|
@@ -658,26 +657,19 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
658
657
|
UserMiddleware.getUserMiddleware,
|
|
659
658
|
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
660
659
|
try {
|
|
661
|
-
const
|
|
660
|
+
const statusPageId: ObjectID = new ObjectID(
|
|
662
661
|
req.params["statusPageId"] as string,
|
|
663
662
|
);
|
|
664
663
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
req,
|
|
670
|
-
))
|
|
671
|
-
) {
|
|
672
|
-
throw new NotAuthenticatedException(
|
|
673
|
-
"You are not authenticated to access this status page",
|
|
674
|
-
);
|
|
675
|
-
}
|
|
664
|
+
await this.checkHasReadAccess({
|
|
665
|
+
statusPageId: statusPageId,
|
|
666
|
+
req: req,
|
|
667
|
+
});
|
|
676
668
|
|
|
677
669
|
const resources: Array<StatusPageResource> =
|
|
678
670
|
await StatusPageResourceService.findBy({
|
|
679
671
|
query: {
|
|
680
|
-
statusPageId:
|
|
672
|
+
statusPageId: statusPageId,
|
|
681
673
|
},
|
|
682
674
|
select: {
|
|
683
675
|
_id: true,
|
|
@@ -729,17 +721,10 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
729
721
|
throw new BadDataException("Status Page or Resource not found");
|
|
730
722
|
}
|
|
731
723
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
req,
|
|
737
|
-
))
|
|
738
|
-
) {
|
|
739
|
-
throw new NotAuthenticatedException(
|
|
740
|
-
"You are not authenticated to access this status page",
|
|
741
|
-
);
|
|
742
|
-
}
|
|
724
|
+
await this.checkHasReadAccess({
|
|
725
|
+
statusPageId: statusPageId,
|
|
726
|
+
req: req,
|
|
727
|
+
});
|
|
743
728
|
|
|
744
729
|
// get start and end date from request body.
|
|
745
730
|
// if no end date is provided then it will be current date.
|
|
@@ -1022,21 +1007,14 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1022
1007
|
UserMiddleware.getUserMiddleware,
|
|
1023
1008
|
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
1024
1009
|
try {
|
|
1025
|
-
const
|
|
1010
|
+
const statusPageId: ObjectID = new ObjectID(
|
|
1026
1011
|
req.params["statusPageId"] as string,
|
|
1027
1012
|
);
|
|
1028
1013
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
req,
|
|
1034
|
-
))
|
|
1035
|
-
) {
|
|
1036
|
-
throw new NotAuthenticatedException(
|
|
1037
|
-
"You are not authenticated to access this status page",
|
|
1038
|
-
);
|
|
1039
|
-
}
|
|
1014
|
+
await this.checkHasReadAccess({
|
|
1015
|
+
statusPageId: statusPageId,
|
|
1016
|
+
req: req,
|
|
1017
|
+
});
|
|
1040
1018
|
|
|
1041
1019
|
const startDate: Date = OneUptimeDate.getSomeDaysAgo(90);
|
|
1042
1020
|
const endDate: Date = OneUptimeDate.getCurrentDate();
|
|
@@ -1051,7 +1029,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1051
1029
|
statusPageGroups,
|
|
1052
1030
|
monitorsInGroup,
|
|
1053
1031
|
} = await this.getStatusPageResourcesAndTimelines({
|
|
1054
|
-
statusPageId:
|
|
1032
|
+
statusPageId: statusPageId,
|
|
1055
1033
|
startDateForMonitorTimeline: startDate,
|
|
1056
1034
|
endDateForMonitorTimeline: endDate,
|
|
1057
1035
|
});
|
|
@@ -1198,7 +1176,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1198
1176
|
if (statusPage.showAnnouncementsOnStatusPage) {
|
|
1199
1177
|
activeAnnouncements = await StatusPageAnnouncementService.findBy({
|
|
1200
1178
|
query: {
|
|
1201
|
-
statusPages:
|
|
1179
|
+
statusPages: statusPageId as any,
|
|
1202
1180
|
showAnnouncementAt: QueryHelper.lessThan(today),
|
|
1203
1181
|
endAnnouncementAt: QueryHelper.greaterThanOrNull(today),
|
|
1204
1182
|
projectId: statusPage.projectId!,
|
|
@@ -1259,7 +1237,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1259
1237
|
currentScheduledMaintenanceState: {
|
|
1260
1238
|
isOngoingState: true,
|
|
1261
1239
|
} as any,
|
|
1262
|
-
statusPages:
|
|
1240
|
+
statusPages: statusPageId as any,
|
|
1263
1241
|
projectId: statusPage.projectId!,
|
|
1264
1242
|
isVisibleOnStatusPage: true,
|
|
1265
1243
|
},
|
|
@@ -1285,7 +1263,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1285
1263
|
currentScheduledMaintenanceState: {
|
|
1286
1264
|
isScheduledState: true,
|
|
1287
1265
|
} as any,
|
|
1288
|
-
statusPages:
|
|
1266
|
+
statusPages: statusPageId as any,
|
|
1289
1267
|
projectId: statusPage.projectId!,
|
|
1290
1268
|
isVisibleOnStatusPage: true,
|
|
1291
1269
|
},
|
|
@@ -1381,7 +1359,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1381
1359
|
const statusPageHistoryChartBarColorRules: Array<StatusPageHistoryChartBarColorRule> =
|
|
1382
1360
|
await StatusPageHistoryChartBarColorRuleService.findBy({
|
|
1383
1361
|
query: {
|
|
1384
|
-
statusPageId:
|
|
1362
|
+
statusPageId: statusPageId,
|
|
1385
1363
|
},
|
|
1386
1364
|
select: {
|
|
1387
1365
|
_id: true,
|
|
@@ -1557,7 +1535,6 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1557
1535
|
const response: JSONObject = await this.getIncidents(
|
|
1558
1536
|
objectId,
|
|
1559
1537
|
null,
|
|
1560
|
-
await CommonAPI.getDatabaseCommonInteractionProps(req),
|
|
1561
1538
|
req,
|
|
1562
1539
|
);
|
|
1563
1540
|
|
|
@@ -1582,7 +1559,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1582
1559
|
const response: JSONObject = await this.getScheduledMaintenanceEvents(
|
|
1583
1560
|
objectId,
|
|
1584
1561
|
null,
|
|
1585
|
-
|
|
1562
|
+
|
|
1586
1563
|
req,
|
|
1587
1564
|
);
|
|
1588
1565
|
|
|
@@ -1607,7 +1584,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1607
1584
|
const response: JSONObject = await this.getAnnouncements(
|
|
1608
1585
|
objectId,
|
|
1609
1586
|
null,
|
|
1610
|
-
|
|
1587
|
+
|
|
1611
1588
|
req,
|
|
1612
1589
|
);
|
|
1613
1590
|
|
|
@@ -1636,7 +1613,6 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1636
1613
|
const response: JSONObject = await this.getIncidents(
|
|
1637
1614
|
objectId,
|
|
1638
1615
|
incidentId,
|
|
1639
|
-
await CommonAPI.getDatabaseCommonInteractionProps(req),
|
|
1640
1616
|
req,
|
|
1641
1617
|
);
|
|
1642
1618
|
|
|
@@ -1665,7 +1641,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1665
1641
|
const response: JSONObject = await this.getScheduledMaintenanceEvents(
|
|
1666
1642
|
objectId,
|
|
1667
1643
|
scheduledMaintenanceId,
|
|
1668
|
-
|
|
1644
|
+
|
|
1669
1645
|
req,
|
|
1670
1646
|
);
|
|
1671
1647
|
|
|
@@ -1694,7 +1670,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1694
1670
|
const response: JSONObject = await this.getAnnouncements(
|
|
1695
1671
|
objectId,
|
|
1696
1672
|
announcementId,
|
|
1697
|
-
|
|
1673
|
+
|
|
1698
1674
|
req,
|
|
1699
1675
|
);
|
|
1700
1676
|
|
|
@@ -1710,14 +1686,12 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1710
1686
|
public async getScheduledMaintenanceEvents(
|
|
1711
1687
|
statusPageId: ObjectID,
|
|
1712
1688
|
scheduledMaintenanceId: ObjectID | null,
|
|
1713
|
-
props: DatabaseCommonInteractionProps,
|
|
1714
1689
|
req: ExpressRequest,
|
|
1715
1690
|
): Promise<JSONObject> {
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
}
|
|
1691
|
+
await this.checkHasReadAccess({
|
|
1692
|
+
statusPageId: statusPageId,
|
|
1693
|
+
req: req,
|
|
1694
|
+
});
|
|
1721
1695
|
|
|
1722
1696
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
1723
1697
|
query: {
|
|
@@ -2028,14 +2002,12 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2028
2002
|
public async getAnnouncements(
|
|
2029
2003
|
statusPageId: ObjectID,
|
|
2030
2004
|
announcementId: ObjectID | null,
|
|
2031
|
-
props: DatabaseCommonInteractionProps,
|
|
2032
2005
|
req: ExpressRequest,
|
|
2033
2006
|
): Promise<JSONObject> {
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
}
|
|
2007
|
+
await this.checkHasReadAccess({
|
|
2008
|
+
statusPageId: statusPageId,
|
|
2009
|
+
req: req,
|
|
2010
|
+
});
|
|
2039
2011
|
|
|
2040
2012
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
2041
2013
|
query: {
|
|
@@ -2142,28 +2114,22 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2142
2114
|
|
|
2143
2115
|
@CaptureSpan()
|
|
2144
2116
|
public async manageExistingSubscription(req: ExpressRequest): Promise<void> {
|
|
2145
|
-
const
|
|
2117
|
+
const statusPageId: ObjectID = new ObjectID(
|
|
2146
2118
|
req.params["statusPageId"] as string,
|
|
2147
2119
|
);
|
|
2148
2120
|
|
|
2149
|
-
logger.debug(
|
|
2121
|
+
logger.debug(
|
|
2122
|
+
`Managing Existing Subscription for Status Page: ${statusPageId}`,
|
|
2123
|
+
);
|
|
2150
2124
|
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
req,
|
|
2156
|
-
))
|
|
2157
|
-
) {
|
|
2158
|
-
logger.debug(`No read access to status page with ID: ${objectId}`);
|
|
2159
|
-
throw new NotAuthenticatedException(
|
|
2160
|
-
"You are not authenticated to access this status page",
|
|
2161
|
-
);
|
|
2162
|
-
}
|
|
2125
|
+
await this.checkHasReadAccess({
|
|
2126
|
+
statusPageId: statusPageId,
|
|
2127
|
+
req: req,
|
|
2128
|
+
});
|
|
2163
2129
|
|
|
2164
2130
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
2165
2131
|
query: {
|
|
2166
|
-
_id:
|
|
2132
|
+
_id: statusPageId.toString(),
|
|
2167
2133
|
},
|
|
2168
2134
|
select: {
|
|
2169
2135
|
_id: true,
|
|
@@ -2180,13 +2146,13 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2180
2146
|
});
|
|
2181
2147
|
|
|
2182
2148
|
if (!statusPage) {
|
|
2183
|
-
logger.debug(`Status page not found with ID: ${
|
|
2149
|
+
logger.debug(`Status page not found with ID: ${statusPageId}`);
|
|
2184
2150
|
throw new BadDataException("Status Page not found");
|
|
2185
2151
|
}
|
|
2186
2152
|
|
|
2187
2153
|
if (!statusPage.showSubscriberPageOnStatusPage) {
|
|
2188
2154
|
logger.debug(
|
|
2189
|
-
`Subscriber page not enabled for status page with ID: ${
|
|
2155
|
+
`Subscriber page not enabled for status page with ID: ${statusPageId}`,
|
|
2190
2156
|
);
|
|
2191
2157
|
throw new BadDataException(
|
|
2192
2158
|
"Subscribes not enabled for this status page.",
|
|
@@ -2200,7 +2166,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2200
2166
|
!statusPage.enableEmailSubscribers
|
|
2201
2167
|
) {
|
|
2202
2168
|
logger.debug(
|
|
2203
|
-
`Email subscribers not enabled for status page with ID: ${
|
|
2169
|
+
`Email subscribers not enabled for status page with ID: ${statusPageId}`,
|
|
2204
2170
|
);
|
|
2205
2171
|
throw new BadDataException(
|
|
2206
2172
|
"Email subscribers not enabled for this status page.",
|
|
@@ -2209,7 +2175,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2209
2175
|
|
|
2210
2176
|
if (req.body.data["subscriberPhone"] && !statusPage.enableSmsSubscribers) {
|
|
2211
2177
|
logger.debug(
|
|
2212
|
-
`SMS subscribers not enabled for status page with ID: ${
|
|
2178
|
+
`SMS subscribers not enabled for status page with ID: ${statusPageId}`,
|
|
2213
2179
|
);
|
|
2214
2180
|
throw new BadDataException(
|
|
2215
2181
|
"SMS subscribers not enabled for this status page.",
|
|
@@ -2223,7 +2189,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2223
2189
|
!req.body.data["subscriberPhone"]
|
|
2224
2190
|
) {
|
|
2225
2191
|
logger.debug(
|
|
2226
|
-
`No email or phone provided for subscription to status page with ID: ${
|
|
2192
|
+
`No email or phone provided for subscription to status page with ID: ${statusPageId}`,
|
|
2227
2193
|
);
|
|
2228
2194
|
throw new BadDataException(
|
|
2229
2195
|
"Email or phone is required to subscribe to this status page.",
|
|
@@ -2245,7 +2211,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2245
2211
|
statusPageSubscriber = await StatusPageSubscriberService.findOneBy({
|
|
2246
2212
|
query: {
|
|
2247
2213
|
subscriberEmail: email,
|
|
2248
|
-
statusPageId:
|
|
2214
|
+
statusPageId: statusPageId,
|
|
2249
2215
|
},
|
|
2250
2216
|
select: {
|
|
2251
2217
|
_id: true,
|
|
@@ -2262,7 +2228,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2262
2228
|
statusPageSubscriber = await StatusPageSubscriberService.findOneBy({
|
|
2263
2229
|
query: {
|
|
2264
2230
|
subscriberPhone: phone,
|
|
2265
|
-
statusPageId:
|
|
2231
|
+
statusPageId: statusPageId,
|
|
2266
2232
|
},
|
|
2267
2233
|
select: {
|
|
2268
2234
|
_id: true,
|
|
@@ -2291,7 +2257,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2291
2257
|
}
|
|
2292
2258
|
|
|
2293
2259
|
const statusPageURL: string =
|
|
2294
|
-
await StatusPageService.getStatusPageURL(
|
|
2260
|
+
await StatusPageService.getStatusPageURL(statusPageId);
|
|
2295
2261
|
|
|
2296
2262
|
const manageUrlink: string = StatusPageSubscriberService.getUnsubscribeLink(
|
|
2297
2263
|
URL.fromString(statusPageURL),
|
|
@@ -2300,7 +2266,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2300
2266
|
|
|
2301
2267
|
const statusPages: Array<StatusPage> =
|
|
2302
2268
|
await StatusPageSubscriberService.getStatusPagesToSendNotification([
|
|
2303
|
-
|
|
2269
|
+
statusPageId,
|
|
2304
2270
|
]);
|
|
2305
2271
|
|
|
2306
2272
|
for (const statusPage of statusPages) {
|
|
@@ -2375,18 +2341,10 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2375
2341
|
|
|
2376
2342
|
logger.debug(`Subscribing to status page with ID: ${objectId}`);
|
|
2377
2343
|
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
req,
|
|
2383
|
-
))
|
|
2384
|
-
) {
|
|
2385
|
-
logger.debug(`No read access to status page with ID: ${objectId}`);
|
|
2386
|
-
throw new NotAuthenticatedException(
|
|
2387
|
-
"You are not authenticated to access this status page",
|
|
2388
|
-
);
|
|
2389
|
-
}
|
|
2344
|
+
await this.checkHasReadAccess({
|
|
2345
|
+
statusPageId: objectId,
|
|
2346
|
+
req: req,
|
|
2347
|
+
});
|
|
2390
2348
|
|
|
2391
2349
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
2392
2350
|
query: {
|
|
@@ -2612,17 +2570,10 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2612
2570
|
req.params["statusPageId"] as string,
|
|
2613
2571
|
);
|
|
2614
2572
|
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
req,
|
|
2620
|
-
))
|
|
2621
|
-
) {
|
|
2622
|
-
throw new NotAuthenticatedException(
|
|
2623
|
-
"You are not authenticated to access this status page",
|
|
2624
|
-
);
|
|
2625
|
-
}
|
|
2573
|
+
await this.checkHasReadAccess({
|
|
2574
|
+
statusPageId: objectId,
|
|
2575
|
+
req: req,
|
|
2576
|
+
});
|
|
2626
2577
|
|
|
2627
2578
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
2628
2579
|
query: {
|
|
@@ -2675,14 +2626,12 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2675
2626
|
public async getIncidents(
|
|
2676
2627
|
statusPageId: ObjectID,
|
|
2677
2628
|
incidentId: ObjectID | null,
|
|
2678
|
-
props: DatabaseCommonInteractionProps,
|
|
2679
2629
|
req: ExpressRequest,
|
|
2680
2630
|
): Promise<JSONObject> {
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
}
|
|
2631
|
+
await this.checkHasReadAccess({
|
|
2632
|
+
statusPageId: statusPageId,
|
|
2633
|
+
req: req,
|
|
2634
|
+
});
|
|
2686
2635
|
|
|
2687
2636
|
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
2688
2637
|
query: {
|
|
@@ -3235,4 +3184,26 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3235
3184
|
monitorsInGroup,
|
|
3236
3185
|
};
|
|
3237
3186
|
}
|
|
3187
|
+
|
|
3188
|
+
public async checkHasReadAccess(data: {
|
|
3189
|
+
statusPageId: ObjectID;
|
|
3190
|
+
req: ExpressRequest;
|
|
3191
|
+
}): Promise<void> {
|
|
3192
|
+
const accessResult: {
|
|
3193
|
+
hasReadAccess: boolean;
|
|
3194
|
+
error?: NotAuthenticatedException | ForbiddenException;
|
|
3195
|
+
} = await this.service.hasReadAccess({
|
|
3196
|
+
statusPageId: data.statusPageId,
|
|
3197
|
+
req: data.req,
|
|
3198
|
+
});
|
|
3199
|
+
|
|
3200
|
+
if (!accessResult.hasReadAccess) {
|
|
3201
|
+
throw (
|
|
3202
|
+
accessResult.error ||
|
|
3203
|
+
new NotAuthenticatedException(
|
|
3204
|
+
"You are not authenticated to access this status page",
|
|
3205
|
+
)
|
|
3206
|
+
);
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3238
3209
|
}
|
|
@@ -14,14 +14,7 @@ import { JSONObject } from "../Types/JSON";
|
|
|
14
14
|
import ObjectID from "../Types/ObjectID";
|
|
15
15
|
import Port from "../Types/Port";
|
|
16
16
|
import Hostname from "../Types/API/Hostname";
|
|
17
|
-
|
|
18
|
-
export enum ConfigLogLevel {
|
|
19
|
-
INFO = "INFO",
|
|
20
|
-
WARN = "WARN",
|
|
21
|
-
ERROR = "ERROR",
|
|
22
|
-
DEBUG = "DEBUG",
|
|
23
|
-
OFF = "OFF",
|
|
24
|
-
}
|
|
17
|
+
import ConfigLogLevel from "./Types/ConfigLogLevel";
|
|
25
18
|
|
|
26
19
|
export const getAllEnvVars: () => JSONObject = (): JSONObject => {
|
|
27
20
|
return process.env;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1748456937826 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1748456937826";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "StatusPage" ADD "ipWhitelist" text`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
+
await queryRunner.query(
|
|
12
|
+
`ALTER TABLE "StatusPage" DROP COLUMN "ipWhitelist"`,
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -133,6 +133,7 @@ import { MigrationName1744804990712 } from "./1744804990712-MigrationName";
|
|
|
133
133
|
import { MigrationName1744809770336 } from "./1744809770336-MigrationName";
|
|
134
134
|
import { MigrationName1747305098533 } from "./1747305098533-MigrationName";
|
|
135
135
|
import { MigrationName1747674762672 } from "./1747674762672-MigrationName";
|
|
136
|
+
import { MigrationName1748456937826 } from "./1748456937826-MigrationName";
|
|
136
137
|
|
|
137
138
|
export default [
|
|
138
139
|
InitialMigration,
|
|
@@ -270,4 +271,5 @@ export default [
|
|
|
270
271
|
MigrationName1744809770336,
|
|
271
272
|
MigrationName1747305098533,
|
|
272
273
|
MigrationName1747674762672,
|
|
274
|
+
MigrationName1748456937826,
|
|
273
275
|
];
|
|
@@ -10,7 +10,9 @@ import Model, {
|
|
|
10
10
|
InvoiceStatus,
|
|
11
11
|
} from "../../Models/DatabaseModels/BillingInvoice";
|
|
12
12
|
import Project from "../../Models/DatabaseModels/Project";
|
|
13
|
-
import SubscriptionStatus
|
|
13
|
+
import SubscriptionStatus, {
|
|
14
|
+
SubscriptionStatusUtil,
|
|
15
|
+
} from "../../Types/Billing/SubscriptionStatus";
|
|
14
16
|
import ObjectID from "../../Types/ObjectID";
|
|
15
17
|
import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
|
|
16
18
|
import logger from "../Utils/Logger";
|
|
@@ -101,8 +103,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
if (
|
|
104
|
-
meteredSubscriptionState
|
|
105
|
-
subscriptionState
|
|
106
|
+
SubscriptionStatusUtil.isSubscriptionInactive(meteredSubscriptionState) ||
|
|
107
|
+
SubscriptionStatusUtil.isSubscriptionInactive(subscriptionState)
|
|
106
108
|
) {
|
|
107
109
|
// check if all invoices are paid. If yes, then reactivate the subscription.
|
|
108
110
|
|
|
@@ -19,6 +19,8 @@ import StatusPageDomain from "../../Models/DatabaseModels/StatusPageDomain";
|
|
|
19
19
|
import AcmeCertificateService from "./AcmeCertificateService";
|
|
20
20
|
import Telemetry, { Span } from "../Utils/Telemetry";
|
|
21
21
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
22
|
+
import { StatusPageCNameRecord } from "../EnvironmentConfig";
|
|
23
|
+
import DNSUtil from "../../Utils/DNSUtil";
|
|
22
24
|
|
|
23
25
|
export class Service extends DatabaseService<StatusPageDomain> {
|
|
24
26
|
public constructor() {
|
|
@@ -336,6 +338,35 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
336
338
|
return true;
|
|
337
339
|
}
|
|
338
340
|
|
|
341
|
+
if (StatusPageCNameRecord) {
|
|
342
|
+
// check if cname record is set and if it matches StatusPageCNameRecord
|
|
343
|
+
|
|
344
|
+
const cnameRecord: string | undefined = await DNSUtil.getCnameRecord({
|
|
345
|
+
domain: fullDomain,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (
|
|
349
|
+
cnameRecord &&
|
|
350
|
+
cnameRecord.trim().toLocaleLowerCase() ===
|
|
351
|
+
StatusPageCNameRecord.trim().toLocaleLowerCase()
|
|
352
|
+
) {
|
|
353
|
+
logger.debug(
|
|
354
|
+
`CNAME record for ${fullDomain} matches the expected record: ${StatusPageCNameRecord}`,
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
await this.updateCnameStatusForStatusPageDomain({
|
|
358
|
+
domain: fullDomain,
|
|
359
|
+
cnameStatus: true,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
logger.debug(
|
|
366
|
+
`CNAME record for ${fullDomain} does not match the expected record: ${StatusPageCNameRecord}`,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
339
370
|
await this.updateCnameStatusForStatusPageDomain({
|
|
340
371
|
domain: fullDomain,
|
|
341
372
|
cnameStatus: false,
|