@oneuptime/common 9.1.0 → 9.1.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/BillingPaymentMethod.ts +45 -9
- package/Models/DatabaseModels/StatusPageDomain.ts +3 -2
- package/Models/DatabaseModels/User.ts +1 -1
- package/Server/API/BillingPaymentMethodAPI.ts +6 -7
- package/Server/API/StatusPageAPI.ts +1 -1
- package/Server/EnvironmentConfig.ts +11 -0
- package/Server/Services/StatusPageDomainService.ts +17 -10
- package/Server/Types/Workflow/Components/Email.ts +10 -1
- package/Server/Utils/Captcha.ts +98 -0
- package/Server/Utils/Greenlock/Greenlock.ts +10 -3
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +16 -7
- package/UI/Components/Captcha/Captcha.tsx +75 -0
- package/UI/Config.ts +3 -0
- package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js +45 -9
- package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js +2 -2
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +1 -1
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +6 -5
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +1 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +6 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +12 -9
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +8 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/Captcha.js +58 -0
- package/build/dist/Server/Utils/Captcha.js.map +1 -0
- package/build/dist/Server/Utils/Greenlock/Greenlock.js +7 -2
- package/build/dist/Server/Utils/Greenlock/Greenlock.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +13 -8
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/UI/Components/Captcha/Captcha.js +37 -0
- package/build/dist/UI/Components/Captcha/Captcha.js.map +1 -0
- package/build/dist/UI/Config.js +2 -0
- package/build/dist/UI/Config.js.map +1 -1
- package/package.json +2 -1
|
@@ -20,7 +20,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
20
20
|
@AllowAccessIfSubscriptionIsUnpaid()
|
|
21
21
|
@TenantColumn("projectId")
|
|
22
22
|
@TableAccessControl({
|
|
23
|
-
create: [
|
|
23
|
+
create: [
|
|
24
|
+
Permission.ProjectOwner,
|
|
25
|
+
Permission.ManageProjectBilling,
|
|
26
|
+
Permission.CreateBillingPaymentMethod,
|
|
27
|
+
],
|
|
24
28
|
read: [
|
|
25
29
|
Permission.ProjectOwner,
|
|
26
30
|
Permission.ProjectUser,
|
|
@@ -28,7 +32,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
28
32
|
Permission.ProjectMember,
|
|
29
33
|
Permission.ReadBillingPaymentMethod,
|
|
30
34
|
],
|
|
31
|
-
delete: [
|
|
35
|
+
delete: [
|
|
36
|
+
Permission.ProjectOwner,
|
|
37
|
+
Permission.ManageProjectBilling,
|
|
38
|
+
Permission.DeleteBillingPaymentMethod,
|
|
39
|
+
],
|
|
32
40
|
update: [],
|
|
33
41
|
})
|
|
34
42
|
@CrudApiEndpoint(new Route("/billing-payment-methods"))
|
|
@@ -45,7 +53,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
45
53
|
})
|
|
46
54
|
export default class BillingPaymentMethod extends BaseModel {
|
|
47
55
|
@ColumnAccessControl({
|
|
48
|
-
create: [
|
|
56
|
+
create: [
|
|
57
|
+
Permission.ProjectOwner,
|
|
58
|
+
Permission.ManageProjectBilling,
|
|
59
|
+
Permission.CreateBillingPaymentMethod,
|
|
60
|
+
],
|
|
49
61
|
read: [
|
|
50
62
|
Permission.ProjectOwner,
|
|
51
63
|
Permission.ProjectUser,
|
|
@@ -77,7 +89,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
77
89
|
public project?: Project = undefined;
|
|
78
90
|
|
|
79
91
|
@ColumnAccessControl({
|
|
80
|
-
create: [
|
|
92
|
+
create: [
|
|
93
|
+
Permission.ProjectOwner,
|
|
94
|
+
Permission.ManageProjectBilling,
|
|
95
|
+
Permission.CreateBillingPaymentMethod,
|
|
96
|
+
],
|
|
81
97
|
read: [
|
|
82
98
|
Permission.ProjectOwner,
|
|
83
99
|
Permission.ProjectAdmin,
|
|
@@ -103,7 +119,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
103
119
|
public projectId?: ObjectID = undefined;
|
|
104
120
|
|
|
105
121
|
@ColumnAccessControl({
|
|
106
|
-
create: [
|
|
122
|
+
create: [
|
|
123
|
+
Permission.ProjectOwner,
|
|
124
|
+
Permission.ManageProjectBilling,
|
|
125
|
+
Permission.CreateBillingPaymentMethod,
|
|
126
|
+
],
|
|
107
127
|
read: [
|
|
108
128
|
Permission.ProjectOwner,
|
|
109
129
|
Permission.ProjectAdmin,
|
|
@@ -136,7 +156,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
136
156
|
public createdByUser?: User = undefined;
|
|
137
157
|
|
|
138
158
|
@ColumnAccessControl({
|
|
139
|
-
create: [
|
|
159
|
+
create: [
|
|
160
|
+
Permission.ProjectOwner,
|
|
161
|
+
Permission.ManageProjectBilling,
|
|
162
|
+
Permission.CreateBillingPaymentMethod,
|
|
163
|
+
],
|
|
140
164
|
read: [
|
|
141
165
|
Permission.ProjectOwner,
|
|
142
166
|
Permission.ProjectAdmin,
|
|
@@ -218,7 +242,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
218
242
|
public deletedByUserId?: ObjectID = undefined;
|
|
219
243
|
|
|
220
244
|
@ColumnAccessControl({
|
|
221
|
-
create: [
|
|
245
|
+
create: [
|
|
246
|
+
Permission.ProjectOwner,
|
|
247
|
+
Permission.ManageProjectBilling,
|
|
248
|
+
Permission.CreateBillingPaymentMethod,
|
|
249
|
+
],
|
|
222
250
|
read: [
|
|
223
251
|
Permission.ProjectOwner,
|
|
224
252
|
Permission.ProjectAdmin,
|
|
@@ -278,7 +306,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
278
306
|
public paymentProviderCustomerId?: string = undefined;
|
|
279
307
|
|
|
280
308
|
@ColumnAccessControl({
|
|
281
|
-
create: [
|
|
309
|
+
create: [
|
|
310
|
+
Permission.ProjectOwner,
|
|
311
|
+
Permission.ManageProjectBilling,
|
|
312
|
+
Permission.CreateBillingPaymentMethod,
|
|
313
|
+
],
|
|
282
314
|
read: [
|
|
283
315
|
Permission.ProjectOwner,
|
|
284
316
|
Permission.ProjectAdmin,
|
|
@@ -298,7 +330,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
298
330
|
public last4Digits?: string = undefined;
|
|
299
331
|
|
|
300
332
|
@ColumnAccessControl({
|
|
301
|
-
create: [
|
|
333
|
+
create: [
|
|
334
|
+
Permission.ProjectOwner,
|
|
335
|
+
Permission.ManageProjectBilling,
|
|
336
|
+
Permission.CreateBillingPaymentMethod,
|
|
337
|
+
],
|
|
302
338
|
read: [
|
|
303
339
|
Permission.ProjectOwner,
|
|
304
340
|
Permission.ProjectAdmin,
|
|
@@ -282,8 +282,9 @@ export default class StatusPageDomain extends BaseModel {
|
|
|
282
282
|
@TableColumn({
|
|
283
283
|
required: true,
|
|
284
284
|
type: TableColumnType.ShortText,
|
|
285
|
-
title: "
|
|
286
|
-
description:
|
|
285
|
+
title: "Subdomain",
|
|
286
|
+
description:
|
|
287
|
+
"Subdomain label for your status page such as 'status'. Leave blank or enter @ to use the root domain.",
|
|
287
288
|
})
|
|
288
289
|
@Column({
|
|
289
290
|
nullable: false,
|
|
@@ -30,7 +30,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
30
30
|
})
|
|
31
31
|
@AllowAccessIfSubscriptionIsUnpaid()
|
|
32
32
|
@TableAccessControl({
|
|
33
|
-
create: [
|
|
33
|
+
create: [],
|
|
34
34
|
read: [Permission.CurrentUser],
|
|
35
35
|
delete: [Permission.CurrentUser],
|
|
36
36
|
update: [Permission.CurrentUser],
|
|
@@ -42,17 +42,16 @@ export default class UserAPI extends BaseAPI<
|
|
|
42
42
|
const userPermissions: Array<UserPermission> = (
|
|
43
43
|
await this.getPermissionsForTenant(req)
|
|
44
44
|
).filter((permission: UserPermission) => {
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
45
|
+
return [
|
|
46
|
+
Permission.ProjectOwner,
|
|
47
|
+
Permission.ManageProjectBilling,
|
|
48
|
+
Permission.CreateBillingPaymentMethod,
|
|
49
|
+
].includes(permission.permission);
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
if (userPermissions.length === 0) {
|
|
54
53
|
throw new BadDataException(
|
|
55
|
-
"Only
|
|
54
|
+
"Only project owners or members with Manage Billing access can add payment methods.",
|
|
56
55
|
);
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -2809,7 +2809,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2809
2809
|
manageSubscriptionUrl: manageUrlink,
|
|
2810
2810
|
},
|
|
2811
2811
|
subject:
|
|
2812
|
-
"Manage your Subscription for" +
|
|
2812
|
+
"Manage your Subscription for " +
|
|
2813
2813
|
(statusPage.name || "Status Page"),
|
|
2814
2814
|
},
|
|
2815
2815
|
{
|
|
@@ -44,6 +44,8 @@ const FRONTEND_ENV_ALLOW_LIST: Array<string> = [
|
|
|
44
44
|
"DISABLE_TELEMETRY",
|
|
45
45
|
"SLACK_APP_CLIENT_ID",
|
|
46
46
|
"MICROSOFT_TEAMS_APP_CLIENT_ID",
|
|
47
|
+
"CAPTCHA_ENABLED",
|
|
48
|
+
"CAPTCHA_SITE_KEY",
|
|
47
49
|
];
|
|
48
50
|
|
|
49
51
|
const FRONTEND_ENV_ALLOW_PREFIXES: Array<string> = [
|
|
@@ -324,6 +326,13 @@ export const Host: string = process.env["HOST"] || "";
|
|
|
324
326
|
|
|
325
327
|
export const ProvisionSsl: boolean = process.env["PROVISION_SSL"] === "true";
|
|
326
328
|
|
|
329
|
+
export const CaptchaEnabled: boolean =
|
|
330
|
+
process.env["CAPTCHA_ENABLED"] === "true";
|
|
331
|
+
|
|
332
|
+
export const CaptchaSecretKey: string = process.env["CAPTCHA_SECRET_KEY"] || "";
|
|
333
|
+
|
|
334
|
+
export const CaptchaSiteKey: string = process.env["CAPTCHA_SITE_KEY"] || "";
|
|
335
|
+
|
|
327
336
|
export const WorkflowScriptTimeoutInMS: number = process.env[
|
|
328
337
|
"WORKFLOW_SCRIPT_TIMEOUT_IN_MS"
|
|
329
338
|
]
|
|
@@ -446,6 +455,8 @@ export const MicrosoftTeamsAppClientId: string | null =
|
|
|
446
455
|
process.env["MICROSOFT_TEAMS_APP_CLIENT_ID"] || null;
|
|
447
456
|
export const MicrosoftTeamsAppClientSecret: string | null =
|
|
448
457
|
process.env["MICROSOFT_TEAMS_APP_CLIENT_SECRET"] || null;
|
|
458
|
+
export const MicrosoftTeamsAppTenantId: string | null =
|
|
459
|
+
process.env["MICROSOFT_TEAMS_APP_TENANT_ID"] || null;
|
|
449
460
|
|
|
450
461
|
// VAPID Configuration for Web Push Notifications
|
|
451
462
|
export const VapidPublicKey: string | undefined =
|
|
@@ -48,19 +48,26 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
let normalizedSubdomain: string =
|
|
52
|
+
createBy.data.subdomain?.trim().toLowerCase() || "";
|
|
53
|
+
|
|
54
|
+
if (normalizedSubdomain === "@") {
|
|
55
|
+
normalizedSubdomain = "";
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
createBy.data.subdomain = normalizedSubdomain;
|
|
59
|
+
|
|
56
60
|
if (domain) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const baseDomain: string =
|
|
62
|
+
domain.domain?.toString().toLowerCase().trim() || "";
|
|
63
|
+
|
|
64
|
+
if (!baseDomain) {
|
|
65
|
+
throw new BadDataException("Please select a valid domain.");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
createBy.data.fullDomain = normalizedSubdomain
|
|
69
|
+
? `${normalizedSubdomain}.${baseDomain}`
|
|
70
|
+
: baseDomain;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
createBy.data.cnameVerificationToken = ObjectID.generate().toString();
|
|
@@ -115,9 +115,18 @@ export default class Email extends ComponentCode {
|
|
|
115
115
|
const smtpTransport: SMTPTransport.Options = {
|
|
116
116
|
host: args["smtp-host"]?.toString(),
|
|
117
117
|
port: args["smtp-port"] as number,
|
|
118
|
-
secure: Boolean(args["secure"]),
|
|
119
118
|
};
|
|
120
119
|
|
|
120
|
+
if (
|
|
121
|
+
args["secure"] === true ||
|
|
122
|
+
args["secure"] === "true" ||
|
|
123
|
+
args["secure"] === 1
|
|
124
|
+
) {
|
|
125
|
+
smtpTransport.secure = true;
|
|
126
|
+
} else {
|
|
127
|
+
smtpTransport.secure = false;
|
|
128
|
+
}
|
|
129
|
+
|
|
121
130
|
if (username && password) {
|
|
122
131
|
smtpTransport.auth = {
|
|
123
132
|
user: username,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import axios, { AxiosError, AxiosResponse } from "axios";
|
|
2
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
3
|
+
import logger from "./Logger";
|
|
4
|
+
import { CaptchaEnabled, CaptchaSecretKey } from "../EnvironmentConfig";
|
|
5
|
+
|
|
6
|
+
export interface VerifyCaptchaOptions {
|
|
7
|
+
token: string | null | undefined;
|
|
8
|
+
remoteIp?: string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const REQUEST_TIMEOUT_MS: number = 5000;
|
|
12
|
+
const GENERIC_ERROR_MESSAGE: string =
|
|
13
|
+
"Captcha verification failed. Please try again.";
|
|
14
|
+
|
|
15
|
+
type HCaptchaResponse = {
|
|
16
|
+
success?: boolean;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
class CaptchaUtil {
|
|
21
|
+
public static isCaptchaEnabled(): boolean {
|
|
22
|
+
return CaptchaEnabled && Boolean(CaptchaSecretKey);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static async verifyCaptcha(
|
|
26
|
+
options: VerifyCaptchaOptions,
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
if (!CaptchaEnabled) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!CaptchaSecretKey) {
|
|
33
|
+
logger.error(
|
|
34
|
+
"Captcha is enabled but CAPTCHA_SECRET_KEY is not configured.",
|
|
35
|
+
);
|
|
36
|
+
throw new BadDataException(GENERIC_ERROR_MESSAGE);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const token: string = (options.token || "").trim();
|
|
40
|
+
|
|
41
|
+
if (!token) {
|
|
42
|
+
throw new BadDataException(
|
|
43
|
+
"Captcha token is missing. Please complete the verification challenge.",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await this.verifyHCaptcha(token, options.remoteIp || undefined);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
if (axios.isAxiosError(err)) {
|
|
51
|
+
const axiosError: AxiosError = err as AxiosError;
|
|
52
|
+
logger.error(
|
|
53
|
+
`Captcha provider verification failure: ${axiosError.message}`,
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
logger.error(
|
|
57
|
+
`Captcha provider verification failure: ${(err as Error).message}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new BadDataException(GENERIC_ERROR_MESSAGE);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private static async verifyHCaptcha(
|
|
66
|
+
token: string,
|
|
67
|
+
remoteIp?: string,
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
const params: URLSearchParams = new URLSearchParams();
|
|
70
|
+
params.append("secret", CaptchaSecretKey);
|
|
71
|
+
params.append("response", token);
|
|
72
|
+
|
|
73
|
+
if (remoteIp) {
|
|
74
|
+
params.append("remoteip", remoteIp);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const response: AxiosResponse<HCaptchaResponse> =
|
|
78
|
+
await axios.post<HCaptchaResponse>(
|
|
79
|
+
"https://hcaptcha.com/siteverify",
|
|
80
|
+
params.toString(),
|
|
81
|
+
{
|
|
82
|
+
headers: {
|
|
83
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
84
|
+
},
|
|
85
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (!response.data?.success) {
|
|
90
|
+
logger.warn(
|
|
91
|
+
`hCaptcha verification failed: ${JSON.stringify(response.data || {})}`,
|
|
92
|
+
);
|
|
93
|
+
throw new BadDataException(GENERIC_ERROR_MESSAGE);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default CaptchaUtil;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
IsBillingEnabled,
|
|
2
3
|
LetsEncryptAccountKey,
|
|
3
4
|
LetsEncryptNotificationEmail,
|
|
4
5
|
} from "../../../Server/EnvironmentConfig";
|
|
@@ -325,9 +326,15 @@ export default class GreenlockUtil {
|
|
|
325
326
|
throw e;
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
if (IsBillingEnabled) {
|
|
330
|
+
throw new ServerException(
|
|
331
|
+
`Unable to order certificate for ${data.domain}. Please contact support at support@oneuptime.com for more information.`,
|
|
332
|
+
);
|
|
333
|
+
} else {
|
|
334
|
+
throw new ServerException(
|
|
335
|
+
`Unable to order certificate for ${data.domain}. Please make sure that your server can be accessed publicly over port 80 (HTTP) and port 443 (HTTPS). If the problem persists, please refer to server logs for more information. Please also set up LOG_LEVEL=DEBUG to get more detailed server logs.`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
331
338
|
}
|
|
332
339
|
}
|
|
333
340
|
}
|
|
@@ -43,6 +43,7 @@ import OneUptimeDate from "../../../../Types/Date";
|
|
|
43
43
|
import {
|
|
44
44
|
MicrosoftTeamsAppClientId,
|
|
45
45
|
MicrosoftTeamsAppClientSecret,
|
|
46
|
+
MicrosoftTeamsAppTenantId,
|
|
46
47
|
} from "../../../EnvironmentConfig";
|
|
47
48
|
|
|
48
49
|
// Import services for bot commands
|
|
@@ -91,18 +92,25 @@ const MICROSOFT_TEAMS_APP_TYPE: string = "SingleTenant";
|
|
|
91
92
|
const MICROSOFT_TEAMS_MAX_PAGES: number = 500;
|
|
92
93
|
|
|
93
94
|
export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
95
|
+
private static cachedAdapter: CloudAdapter | null = null;
|
|
94
96
|
private static readonly WELCOME_CARD_STATE_KEY: string =
|
|
95
97
|
"oneuptime.microsoftTeams.welcomeCardSent";
|
|
96
98
|
// Get or create Bot Framework adapter for a specific tenant
|
|
97
|
-
private static getBotAdapter(
|
|
99
|
+
private static getBotAdapter(): CloudAdapter {
|
|
100
|
+
if (this.cachedAdapter) {
|
|
101
|
+
return this.cachedAdapter;
|
|
102
|
+
}
|
|
103
|
+
|
|
98
104
|
if (!MicrosoftTeamsAppClientId || !MicrosoftTeamsAppClientSecret) {
|
|
99
105
|
throw new BadDataException(
|
|
100
106
|
"Microsoft Teams App credentials not configured",
|
|
101
107
|
);
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
if (!
|
|
105
|
-
throw new BadDataException(
|
|
110
|
+
if (!MicrosoftTeamsAppTenantId) {
|
|
111
|
+
throw new BadDataException(
|
|
112
|
+
"Microsoft Teams app tenant ID is not configured",
|
|
113
|
+
);
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
logger.debug(
|
|
@@ -110,18 +118,19 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
110
118
|
);
|
|
111
119
|
logger.debug(`App ID: ${MicrosoftTeamsAppClientId}`);
|
|
112
120
|
logger.debug(`App Type: ${MICROSOFT_TEAMS_APP_TYPE}`);
|
|
113
|
-
logger.debug(`Tenant ID: ${
|
|
121
|
+
logger.debug(`Tenant ID: ${MicrosoftTeamsAppTenantId}`);
|
|
114
122
|
|
|
115
123
|
const authConfig: ConfigurationBotFrameworkAuthenticationOptions = {
|
|
116
124
|
MicrosoftAppId: MicrosoftTeamsAppClientId,
|
|
117
125
|
MicrosoftAppPassword: MicrosoftTeamsAppClientSecret,
|
|
118
126
|
MicrosoftAppType: MICROSOFT_TEAMS_APP_TYPE,
|
|
119
|
-
MicrosoftAppTenantId:
|
|
127
|
+
MicrosoftAppTenantId: MicrosoftTeamsAppTenantId,
|
|
120
128
|
};
|
|
121
129
|
|
|
122
130
|
const botFrameworkAuthentication: ConfigurationBotFrameworkAuthentication =
|
|
123
131
|
new ConfigurationBotFrameworkAuthentication(authConfig);
|
|
124
132
|
const adapter: CloudAdapter = new CloudAdapter(botFrameworkAuthentication);
|
|
133
|
+
this.cachedAdapter = adapter;
|
|
125
134
|
|
|
126
135
|
logger.debug("Bot Framework adapter created successfully");
|
|
127
136
|
return adapter;
|
|
@@ -1141,7 +1150,7 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1141
1150
|
logger.debug(`Using bot ID: ${miscData.botId}`);
|
|
1142
1151
|
|
|
1143
1152
|
// Get Bot Framework adapter
|
|
1144
|
-
const adapter: CloudAdapter = this.getBotAdapter(
|
|
1153
|
+
const adapter: CloudAdapter = this.getBotAdapter();
|
|
1145
1154
|
|
|
1146
1155
|
// Create conversation reference for the channel
|
|
1147
1156
|
const conversationReference: ConversationReference = {
|
|
@@ -2564,7 +2573,7 @@ All monitoring checks are passing normally.`;
|
|
|
2564
2573
|
}
|
|
2565
2574
|
|
|
2566
2575
|
// Get Bot Framework adapter
|
|
2567
|
-
const adapter: CloudAdapter = this.getBotAdapter(
|
|
2576
|
+
const adapter: CloudAdapter = this.getBotAdapter();
|
|
2568
2577
|
|
|
2569
2578
|
// Create custom activity handler class that extends TeamsActivityHandler
|
|
2570
2579
|
class OneUptimeTeamsActivityHandler extends TeamsActivityHandler {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import HCaptcha from "@hcaptcha/react-hcaptcha";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
export interface CaptchaProps {
|
|
5
|
+
siteKey: string;
|
|
6
|
+
resetSignal?: number | undefined;
|
|
7
|
+
error?: string | undefined;
|
|
8
|
+
onTokenChange?: (token: string) => void;
|
|
9
|
+
onBlur?: (() => void) | undefined;
|
|
10
|
+
className?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Captcha: React.FC<CaptchaProps> = ({
|
|
14
|
+
siteKey,
|
|
15
|
+
resetSignal = 0,
|
|
16
|
+
error,
|
|
17
|
+
onTokenChange,
|
|
18
|
+
onBlur,
|
|
19
|
+
className,
|
|
20
|
+
}: CaptchaProps): JSX.Element => {
|
|
21
|
+
const captchaRef: React.MutableRefObject<HCaptcha | null> =
|
|
22
|
+
React.useRef<HCaptcha | null>(null);
|
|
23
|
+
const onTokenChangeRef: React.MutableRefObject<
|
|
24
|
+
CaptchaProps["onTokenChange"]
|
|
25
|
+
> = React.useRef<CaptchaProps["onTokenChange"]>(onTokenChange);
|
|
26
|
+
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
onTokenChangeRef.current = onTokenChange;
|
|
29
|
+
}, [onTokenChange]);
|
|
30
|
+
|
|
31
|
+
const handleTokenChange: (token: string | null) => void = React.useCallback(
|
|
32
|
+
(token: string | null) => {
|
|
33
|
+
onTokenChangeRef.current?.(token || "");
|
|
34
|
+
},
|
|
35
|
+
[],
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
captchaRef.current?.resetCaptcha();
|
|
40
|
+
handleTokenChange("");
|
|
41
|
+
}, [resetSignal, handleTokenChange]);
|
|
42
|
+
|
|
43
|
+
if (!siteKey) {
|
|
44
|
+
return (
|
|
45
|
+
<div className={className || "text-center text-sm text-red-500"}>
|
|
46
|
+
Captcha is not configured.
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className={className || "flex flex-col items-center gap-2"}>
|
|
53
|
+
<HCaptcha
|
|
54
|
+
sitekey={siteKey}
|
|
55
|
+
ref={captchaRef}
|
|
56
|
+
onVerify={(token: string) => {
|
|
57
|
+
handleTokenChange(token);
|
|
58
|
+
onBlur?.();
|
|
59
|
+
}}
|
|
60
|
+
onExpire={() => {
|
|
61
|
+
handleTokenChange(null);
|
|
62
|
+
captchaRef.current?.resetCaptcha();
|
|
63
|
+
onBlur?.();
|
|
64
|
+
}}
|
|
65
|
+
onError={() => {
|
|
66
|
+
handleTokenChange(null);
|
|
67
|
+
onBlur?.();
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
{error && <span className="text-sm text-red-500">{error}</span>}
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default Captcha;
|
package/UI/Config.ts
CHANGED
|
@@ -51,6 +51,9 @@ export const IS_ENTERPRISE_EDITION: boolean =
|
|
|
51
51
|
env("IS_ENTERPRISE_EDITION") === "true";
|
|
52
52
|
export const BILLING_PUBLIC_KEY: string = env("BILLING_PUBLIC_KEY") || "";
|
|
53
53
|
|
|
54
|
+
export const CAPTCHA_ENABLED: boolean = env("CAPTCHA_ENABLED") === "true";
|
|
55
|
+
export const CAPTCHA_SITE_KEY: string = env("CAPTCHA_SITE_KEY") || "";
|
|
56
|
+
|
|
54
57
|
// VAPID Configuration for Push Notifications
|
|
55
58
|
export const VAPID_PUBLIC_KEY: string = env("VAPID_PUBLIC_KEY") || "";
|
|
56
59
|
|
|
@@ -43,7 +43,11 @@ let BillingPaymentMethod = class BillingPaymentMethod extends BaseModel {
|
|
|
43
43
|
};
|
|
44
44
|
__decorate([
|
|
45
45
|
ColumnAccessControl({
|
|
46
|
-
create: [
|
|
46
|
+
create: [
|
|
47
|
+
Permission.ProjectOwner,
|
|
48
|
+
Permission.ManageProjectBilling,
|
|
49
|
+
Permission.CreateBillingPaymentMethod,
|
|
50
|
+
],
|
|
47
51
|
read: [
|
|
48
52
|
Permission.ProjectOwner,
|
|
49
53
|
Permission.ProjectUser,
|
|
@@ -73,7 +77,11 @@ __decorate([
|
|
|
73
77
|
], BillingPaymentMethod.prototype, "project", void 0);
|
|
74
78
|
__decorate([
|
|
75
79
|
ColumnAccessControl({
|
|
76
|
-
create: [
|
|
80
|
+
create: [
|
|
81
|
+
Permission.ProjectOwner,
|
|
82
|
+
Permission.ManageProjectBilling,
|
|
83
|
+
Permission.CreateBillingPaymentMethod,
|
|
84
|
+
],
|
|
77
85
|
read: [
|
|
78
86
|
Permission.ProjectOwner,
|
|
79
87
|
Permission.ProjectAdmin,
|
|
@@ -100,7 +108,11 @@ __decorate([
|
|
|
100
108
|
], BillingPaymentMethod.prototype, "projectId", void 0);
|
|
101
109
|
__decorate([
|
|
102
110
|
ColumnAccessControl({
|
|
103
|
-
create: [
|
|
111
|
+
create: [
|
|
112
|
+
Permission.ProjectOwner,
|
|
113
|
+
Permission.ManageProjectBilling,
|
|
114
|
+
Permission.CreateBillingPaymentMethod,
|
|
115
|
+
],
|
|
104
116
|
read: [
|
|
105
117
|
Permission.ProjectOwner,
|
|
106
118
|
Permission.ProjectAdmin,
|
|
@@ -130,7 +142,11 @@ __decorate([
|
|
|
130
142
|
], BillingPaymentMethod.prototype, "createdByUser", void 0);
|
|
131
143
|
__decorate([
|
|
132
144
|
ColumnAccessControl({
|
|
133
|
-
create: [
|
|
145
|
+
create: [
|
|
146
|
+
Permission.ProjectOwner,
|
|
147
|
+
Permission.ManageProjectBilling,
|
|
148
|
+
Permission.CreateBillingPaymentMethod,
|
|
149
|
+
],
|
|
134
150
|
read: [
|
|
135
151
|
Permission.ProjectOwner,
|
|
136
152
|
Permission.ProjectAdmin,
|
|
@@ -209,7 +225,11 @@ __decorate([
|
|
|
209
225
|
], BillingPaymentMethod.prototype, "deletedByUserId", void 0);
|
|
210
226
|
__decorate([
|
|
211
227
|
ColumnAccessControl({
|
|
212
|
-
create: [
|
|
228
|
+
create: [
|
|
229
|
+
Permission.ProjectOwner,
|
|
230
|
+
Permission.ManageProjectBilling,
|
|
231
|
+
Permission.CreateBillingPaymentMethod,
|
|
232
|
+
],
|
|
213
233
|
read: [
|
|
214
234
|
Permission.ProjectOwner,
|
|
215
235
|
Permission.ProjectAdmin,
|
|
@@ -272,7 +292,11 @@ __decorate([
|
|
|
272
292
|
], BillingPaymentMethod.prototype, "paymentProviderCustomerId", void 0);
|
|
273
293
|
__decorate([
|
|
274
294
|
ColumnAccessControl({
|
|
275
|
-
create: [
|
|
295
|
+
create: [
|
|
296
|
+
Permission.ProjectOwner,
|
|
297
|
+
Permission.ManageProjectBilling,
|
|
298
|
+
Permission.CreateBillingPaymentMethod,
|
|
299
|
+
],
|
|
276
300
|
read: [
|
|
277
301
|
Permission.ProjectOwner,
|
|
278
302
|
Permission.ProjectAdmin,
|
|
@@ -293,7 +317,11 @@ __decorate([
|
|
|
293
317
|
], BillingPaymentMethod.prototype, "last4Digits", void 0);
|
|
294
318
|
__decorate([
|
|
295
319
|
ColumnAccessControl({
|
|
296
|
-
create: [
|
|
320
|
+
create: [
|
|
321
|
+
Permission.ProjectOwner,
|
|
322
|
+
Permission.ManageProjectBilling,
|
|
323
|
+
Permission.CreateBillingPaymentMethod,
|
|
324
|
+
],
|
|
297
325
|
read: [
|
|
298
326
|
Permission.ProjectOwner,
|
|
299
327
|
Permission.ProjectAdmin,
|
|
@@ -315,7 +343,11 @@ BillingPaymentMethod = __decorate([
|
|
|
315
343
|
AllowAccessIfSubscriptionIsUnpaid(),
|
|
316
344
|
TenantColumn("projectId"),
|
|
317
345
|
TableAccessControl({
|
|
318
|
-
create: [
|
|
346
|
+
create: [
|
|
347
|
+
Permission.ProjectOwner,
|
|
348
|
+
Permission.ManageProjectBilling,
|
|
349
|
+
Permission.CreateBillingPaymentMethod,
|
|
350
|
+
],
|
|
319
351
|
read: [
|
|
320
352
|
Permission.ProjectOwner,
|
|
321
353
|
Permission.ProjectUser,
|
|
@@ -323,7 +355,11 @@ BillingPaymentMethod = __decorate([
|
|
|
323
355
|
Permission.ProjectMember,
|
|
324
356
|
Permission.ReadBillingPaymentMethod,
|
|
325
357
|
],
|
|
326
|
-
delete: [
|
|
358
|
+
delete: [
|
|
359
|
+
Permission.ProjectOwner,
|
|
360
|
+
Permission.ManageProjectBilling,
|
|
361
|
+
Permission.DeleteBillingPaymentMethod,
|
|
362
|
+
],
|
|
327
363
|
update: [],
|
|
328
364
|
}),
|
|
329
365
|
CrudApiEndpoint(new Route("/billing-payment-methods")),
|