@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.
Files changed (72) hide show
  1. package/Models/DatabaseModels/StatusPage.ts +39 -0
  2. package/Server/API/OpenAPI.ts +29 -0
  3. package/Server/API/StatusPageAPI.ts +85 -114
  4. package/Server/EnvironmentConfig.ts +1 -8
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.ts +15 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/BillingInvoiceService.ts +5 -3
  8. package/Server/Services/StatusPageDomainService.ts +31 -0
  9. package/Server/Services/StatusPageService.ts +89 -24
  10. package/Server/Types/ConfigLogLevel.ts +9 -0
  11. package/Server/Utils/Logger.ts +2 -1
  12. package/Server/Utils/OpenAPI.ts +370 -0
  13. package/Tests/Server/API/BaseAPI.test.ts +4 -0
  14. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +7 -6
  15. package/Types/Billing/SubscriptionStatus.ts +1 -0
  16. package/Types/Exception/ExceptionCode.ts +1 -0
  17. package/Types/Exception/ForbiddenException.ts +8 -0
  18. package/Types/IP/IP.ts +88 -0
  19. package/UI/Components/ModelTable/BaseModelTable.tsx +0 -2
  20. package/UI/Utils/API/API.ts +15 -5
  21. package/UI/Utils/Cookie.ts +9 -0
  22. package/UI/Utils/User.ts +1 -0
  23. package/Utils/DNSUtil.ts +24 -0
  24. package/Utils/Schema/ModelSchema.ts +247 -0
  25. package/build/dist/Models/DatabaseModels/StatusPage.js +40 -0
  26. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  27. package/build/dist/Server/API/OpenAPI.js +14 -0
  28. package/build/dist/Server/API/OpenAPI.js.map +1 -0
  29. package/build/dist/Server/API/StatusPageAPI.js +78 -62
  30. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  31. package/build/dist/Server/EnvironmentConfig.js +1 -8
  32. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  33. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.js +12 -0
  34. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1748456937826-MigrationName.js.map +1 -0
  35. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  36. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  37. package/build/dist/Server/Services/BillingInvoiceService.js +3 -3
  38. package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
  39. package/build/dist/Server/Services/StatusPageDomainService.js +19 -0
  40. package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
  41. package/build/dist/Server/Services/StatusPageService.js +66 -21
  42. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  43. package/build/dist/Server/Types/ConfigLogLevel.js +10 -0
  44. package/build/dist/Server/Types/ConfigLogLevel.js.map +1 -0
  45. package/build/dist/Server/Utils/Logger.js +2 -1
  46. package/build/dist/Server/Utils/Logger.js.map +1 -1
  47. package/build/dist/Server/Utils/OpenAPI.js +334 -0
  48. package/build/dist/Server/Utils/OpenAPI.js.map +1 -0
  49. package/build/dist/Tests/Server/API/BaseAPI.test.js +4 -0
  50. package/build/dist/Tests/Server/API/BaseAPI.test.js.map +1 -1
  51. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js +7 -6
  52. package/build/dist/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.js.map +1 -1
  53. package/build/dist/Types/Billing/SubscriptionStatus.js +1 -0
  54. package/build/dist/Types/Billing/SubscriptionStatus.js.map +1 -1
  55. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  56. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  57. package/build/dist/Types/Exception/ForbiddenException.js +8 -0
  58. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -0
  59. package/build/dist/Types/IP/IP.js +66 -0
  60. package/build/dist/Types/IP/IP.js.map +1 -1
  61. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  62. package/build/dist/UI/Utils/API/API.js +11 -5
  63. package/build/dist/UI/Utils/API/API.js.map +1 -1
  64. package/build/dist/UI/Utils/Cookie.js +8 -0
  65. package/build/dist/UI/Utils/Cookie.js.map +1 -1
  66. package/build/dist/UI/Utils/User.js +1 -0
  67. package/build/dist/UI/Utils/User.js.map +1 -1
  68. package/build/dist/Utils/DNSUtil.js +19 -0
  69. package/build/dist/Utils/DNSUtil.js.map +1 -0
  70. package/build/dist/Utils/Schema/ModelSchema.js +181 -0
  71. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -0
  72. 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 objectId: ObjectID = new ObjectID(
660
+ const statusPageId: ObjectID = new ObjectID(
662
661
  req.params["statusPageId"] as string,
663
662
  );
664
663
 
665
- if (
666
- !(await this.service.hasReadAccess(
667
- objectId,
668
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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: objectId,
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
- if (
733
- !(await this.service.hasReadAccess(
734
- statusPageId,
735
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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 objectId: ObjectID = new ObjectID(
1010
+ const statusPageId: ObjectID = new ObjectID(
1026
1011
  req.params["statusPageId"] as string,
1027
1012
  );
1028
1013
 
1029
- if (
1030
- !(await this.service.hasReadAccess(
1031
- objectId,
1032
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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: objectId,
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: objectId as any,
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: objectId as any,
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: objectId as any,
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: objectId,
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
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- if (!(await this.service.hasReadAccess(statusPageId, props, req))) {
1717
- throw new NotAuthenticatedException(
1718
- "You are not authenticated to access this status page",
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
- if (!(await this.service.hasReadAccess(statusPageId, props, req))) {
2035
- throw new NotAuthenticatedException(
2036
- "You are not authenticated to access this status page",
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 objectId: ObjectID = new ObjectID(
2117
+ const statusPageId: ObjectID = new ObjectID(
2146
2118
  req.params["statusPageId"] as string,
2147
2119
  );
2148
2120
 
2149
- logger.debug(`Managing Existing Subscription for Status Page: ${objectId}`);
2121
+ logger.debug(
2122
+ `Managing Existing Subscription for Status Page: ${statusPageId}`,
2123
+ );
2150
2124
 
2151
- if (
2152
- !(await this.service.hasReadAccess(
2153
- objectId,
2154
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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: objectId.toString(),
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: ${objectId}`);
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: ${objectId}`,
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: ${objectId}`,
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: ${objectId}`,
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: ${objectId}`,
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: objectId,
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: objectId,
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(objectId);
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
- objectId,
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
- if (
2379
- !(await this.service.hasReadAccess(
2380
- objectId,
2381
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- if (
2616
- !(await this.service.hasReadAccess(
2617
- objectId,
2618
- await CommonAPI.getDatabaseCommonInteractionProps(req),
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
- if (!(await this.service.hasReadAccess(statusPageId, props, req))) {
2682
- throw new NotAuthenticatedException(
2683
- "You are not authenticated to access this status page",
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 from "../../Types/Billing/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 === SubscriptionStatus.Canceled ||
105
- subscriptionState === SubscriptionStatus.Canceled
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,