@nocobase/plugin-verification 1.7.0-beta.8 → 1.8.0-beta.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/dist/client/83b24f85ae99a175.js +10 -0
- package/dist/client/937c9eccebc38607.js +10 -0
- package/dist/client/{providerTypes/index.d.ts → VerificationMenu.d.ts} +5 -4
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +1 -1
- package/dist/client/locale/index.d.ts +1 -1
- package/dist/client/otp-verification/VerificationCode.d.ts +16 -0
- package/dist/client/otp-verification/sms/AdminSettingsForm.d.ts +12 -0
- package/dist/client/otp-verification/sms/BindForm.d.ts +11 -0
- package/dist/client/otp-verification/sms/VerificationForm.d.ts +11 -0
- package/dist/client/otp-verification/sms/index.d.ts +26 -0
- package/dist/client/otp-verification/sms/provider-manager.d.ts +19 -0
- package/dist/client/{VerificationProviders.d.ts → otp-verification/sms/providers/AliyunSettings.d.ts} +1 -1
- package/dist/{server/actions/index.d.ts → client/otp-verification/sms/providers/TencentSettings.d.ts} +2 -3
- package/dist/client/schemas/verifiers.d.ts +66 -0
- package/dist/client/verification-manager/index.d.ts +32 -0
- package/dist/client/{ProviderOptions.d.ts → verifiers/VerifierSelect.d.ts} +1 -2
- package/dist/client/verifiers/Verifiers.d.ts +12 -0
- package/dist/client/verifiers/verification-types.d.ts +24 -0
- package/dist/collections/verificators.d.ts +50 -0
- package/dist/collections/verificators.js +70 -0
- package/dist/collections/verifiers.d.ts +50 -0
- package/dist/collections/verifiers.js +70 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.js +42 -0
- package/dist/externalVersion.js +14 -13
- package/dist/locale/en-US.json +18 -1
- package/dist/locale/zh-CN.json +20 -2
- package/dist/node_modules/@alicloud/dysmsapi20170525/dist/client.js +2 -2
- package/dist/node_modules/@alicloud/dysmsapi20170525/package.json +1 -1
- package/dist/node_modules/@alicloud/openapi-client/dist/client.js +2 -2
- package/dist/node_modules/@alicloud/openapi-client/package.json +1 -1
- package/dist/node_modules/@alicloud/tea-util/dist/client.js +1 -1
- package/dist/node_modules/@alicloud/tea-util/package.json +1 -1
- package/dist/node_modules/tencentcloud-sdk-nodejs/package.json +1 -1
- package/dist/node_modules/tencentcloud-sdk-nodejs/tencentcloud/index.js +2 -2
- package/dist/server/Plugin.d.ts +8 -16
- package/dist/server/Plugin.js +68 -71
- package/dist/server/actions/verifiers.d.ts +18 -0
- package/dist/server/actions/verifiers.js +175 -0
- package/dist/server/{actions/verifications.d.ts → collections/otp-records.d.ts} +2 -2
- package/dist/server/collections/otp-records.js +75 -0
- package/dist/server/collections/users-verificators.d.ts +10 -0
- package/dist/server/collections/users-verificators.js +58 -0
- package/dist/server/collections/users-verifiers.d.ts +14 -0
- package/dist/server/collections/users-verifiers.js +58 -0
- package/dist/server/collections/verificators.d.ts +10 -0
- package/dist/server/{actions/index.js → collections/verificators.js} +10 -19
- package/dist/server/collections/verifiers.d.ts +10 -0
- package/dist/server/{providers/index.js → collections/verifiers.js} +10 -15
- package/dist/server/constants.d.ts +0 -2
- package/dist/server/constants.js +2 -8
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.js +12 -5
- package/dist/server/migrations/20250111192640-providers2verificators.d.ts +14 -0
- package/dist/server/migrations/20250111192640-providers2verificators.js +97 -0
- package/dist/server/migrations/20250507220644-fix-verifier-typo.d.ts +14 -0
- package/dist/server/migrations/20250507220644-fix-verifier-typo.js +86 -0
- package/dist/server/otp-verification/index.d.ts +26 -0
- package/dist/server/otp-verification/index.js +152 -0
- package/dist/server/otp-verification/sms/index.d.ts +37 -0
- package/dist/server/otp-verification/sms/index.js +87 -0
- package/dist/server/{providers/Provider.d.ts → otp-verification/sms/providers/index.d.ts} +2 -4
- package/dist/server/{providers/Provider.js → otp-verification/sms/providers/index.js} +8 -10
- package/dist/server/{providers → otp-verification/sms/providers}/sms-aliyun.d.ts +3 -3
- package/dist/server/{providers → otp-verification/sms/providers}/sms-aliyun.js +4 -4
- package/dist/server/{providers → otp-verification/sms/providers}/sms-tencent.d.ts +3 -3
- package/dist/server/{providers → otp-verification/sms/providers}/sms-tencent.js +4 -4
- package/dist/server/otp-verification/sms/resource/sms-otp-providers.d.ts +16 -0
- package/dist/server/otp-verification/sms/resource/sms-otp-providers.js +41 -0
- package/dist/server/otp-verification/sms/resource/sms-otp.d.ts +18 -0
- package/dist/server/otp-verification/sms/resource/sms-otp.js +141 -0
- package/dist/server/verification-manager.d.ts +68 -0
- package/dist/server/verification-manager.js +223 -0
- package/dist/server/verification.d.ts +70 -0
- package/dist/server/verification.js +70 -0
- package/package.json +8 -6
- package/dist/client/7551e1f2e04bca2f.js +0 -10
- package/dist/client/providerTypes/sms-aliyun.d.ts +0 -66
- package/dist/client/providerTypes/sms-tencent.d.ts +0 -66
- package/dist/server/actions/verifications.js +0 -146
- package/dist/server/providers/index.d.ts +0 -15
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import DysmsApi from '@alicloud/dysmsapi20170525';
|
|
10
|
-
import {
|
|
11
|
-
export default class extends
|
|
10
|
+
import { SMSProvider } from '.';
|
|
11
|
+
export default class extends SMSProvider {
|
|
12
12
|
client: DysmsApi;
|
|
13
|
-
constructor(
|
|
13
|
+
constructor(options: any);
|
|
14
14
|
send(phoneNumbers: any, data?: {}): Promise<never>;
|
|
15
15
|
}
|
|
@@ -42,11 +42,11 @@ module.exports = __toCommonJS(sms_aliyun_exports);
|
|
|
42
42
|
var import_dysmsapi20170525 = __toESM(require("@alicloud/dysmsapi20170525"));
|
|
43
43
|
var OpenApi = __toESM(require("@alicloud/openapi-client"));
|
|
44
44
|
var import_tea_util = require("@alicloud/tea-util");
|
|
45
|
-
var
|
|
46
|
-
class sms_aliyun_default extends
|
|
45
|
+
var import__ = require(".");
|
|
46
|
+
class sms_aliyun_default extends import__.SMSProvider {
|
|
47
47
|
client;
|
|
48
|
-
constructor(
|
|
49
|
-
super(
|
|
48
|
+
constructor(options) {
|
|
49
|
+
super(options);
|
|
50
50
|
const { accessKeyId, accessKeySecret, endpoint } = this.options;
|
|
51
51
|
const config = new OpenApi.Config({
|
|
52
52
|
// 您的 AccessKey ID
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { SMSProvider } from '.';
|
|
10
10
|
declare const smsClient: typeof import("tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/sms_client").Client;
|
|
11
|
-
export default class extends
|
|
11
|
+
export default class extends SMSProvider {
|
|
12
12
|
client: InstanceType<typeof smsClient>;
|
|
13
|
-
constructor(
|
|
13
|
+
constructor(options: any);
|
|
14
14
|
send(phoneNumbers: any, data: {
|
|
15
15
|
code: string;
|
|
16
16
|
}): Promise<string>;
|
|
@@ -40,12 +40,12 @@ __export(sms_tencent_exports, {
|
|
|
40
40
|
});
|
|
41
41
|
module.exports = __toCommonJS(sms_tencent_exports);
|
|
42
42
|
var tencentcloud = __toESM(require("tencentcloud-sdk-nodejs"));
|
|
43
|
-
var
|
|
43
|
+
var import__ = require(".");
|
|
44
44
|
const smsClient = tencentcloud.sms.v20210111.Client;
|
|
45
|
-
class sms_tencent_default extends
|
|
45
|
+
class sms_tencent_default extends import__.SMSProvider {
|
|
46
46
|
client;
|
|
47
|
-
constructor(
|
|
48
|
-
super(
|
|
47
|
+
constructor(options) {
|
|
48
|
+
super(options);
|
|
49
49
|
const { secretId, secretKey, region, endpoint } = this.options;
|
|
50
50
|
this.client = new smsClient({
|
|
51
51
|
credential: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Context, Next } from '@nocobase/actions';
|
|
10
|
+
declare const _default: {
|
|
11
|
+
name: string;
|
|
12
|
+
actions: {
|
|
13
|
+
list: (ctx: Context, next: Next) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var sms_otp_providers_exports = {};
|
|
28
|
+
__export(sms_otp_providers_exports, {
|
|
29
|
+
default: () => sms_otp_providers_default
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(sms_otp_providers_exports);
|
|
32
|
+
var sms_otp_providers_default = {
|
|
33
|
+
name: "smsOTPProviders",
|
|
34
|
+
actions: {
|
|
35
|
+
list: async (ctx, next) => {
|
|
36
|
+
const plugin = ctx.app.pm.get("verification");
|
|
37
|
+
ctx.body = plugin.smsOTPProviderManager.listProviders();
|
|
38
|
+
await next();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Context, Next } from '@nocobase/actions';
|
|
10
|
+
declare function create(ctx: Context, next: Next): Promise<any>;
|
|
11
|
+
declare const _default: {
|
|
12
|
+
name: string;
|
|
13
|
+
actions: {
|
|
14
|
+
create: typeof create;
|
|
15
|
+
publicCreate: typeof create;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var sms_otp_exports = {};
|
|
38
|
+
__export(sms_otp_exports, {
|
|
39
|
+
default: () => sms_otp_default
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(sms_otp_exports);
|
|
42
|
+
var import_dayjs = __toESM(require("dayjs"));
|
|
43
|
+
var import_crypto = require("crypto");
|
|
44
|
+
var import_util = require("util");
|
|
45
|
+
var import_constants = require("../../../constants");
|
|
46
|
+
var import__2 = require("../../..");
|
|
47
|
+
const asyncRandomInt = (0, import_util.promisify)(import_crypto.randomInt);
|
|
48
|
+
async function create(ctx, next) {
|
|
49
|
+
var _a;
|
|
50
|
+
const { action: actionName, verifier: verifierName } = ((_a = ctx.action.params) == null ? void 0 : _a.values) || {};
|
|
51
|
+
const plugin = ctx.app.getPlugin("verification");
|
|
52
|
+
const verificationManager = plugin.verificationManager;
|
|
53
|
+
const action = verificationManager.actions.get(actionName);
|
|
54
|
+
if (!action) {
|
|
55
|
+
return ctx.throw(400, "Invalid action type");
|
|
56
|
+
}
|
|
57
|
+
if (!verifierName) {
|
|
58
|
+
return ctx.throw(400, "Invalid verifier");
|
|
59
|
+
}
|
|
60
|
+
const verifier = await ctx.db.getRepository("verifiers").findOne({
|
|
61
|
+
filter: {
|
|
62
|
+
name: verifierName
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
if (!verifier) {
|
|
66
|
+
return ctx.throw(400, "Invalid verifier");
|
|
67
|
+
}
|
|
68
|
+
const Verification = verificationManager.getVerification(verifier.verificationType);
|
|
69
|
+
const verification = new Verification({
|
|
70
|
+
ctx,
|
|
71
|
+
verifier,
|
|
72
|
+
options: verifier.options
|
|
73
|
+
});
|
|
74
|
+
const provider = await verification.getProvider();
|
|
75
|
+
if (!provider) {
|
|
76
|
+
ctx.log.error(`[verification] no provider for action (${actionName}) provided`);
|
|
77
|
+
return ctx.throw(500, "Invalid provider");
|
|
78
|
+
}
|
|
79
|
+
const { boundInfo } = await verificationManager.getAndValidateBoundInfo(ctx, action, verification);
|
|
80
|
+
const { uuid: receiver } = boundInfo;
|
|
81
|
+
const record = await ctx.db.getRepository("otpRecords").findOne({
|
|
82
|
+
filter: {
|
|
83
|
+
action: actionName,
|
|
84
|
+
receiver,
|
|
85
|
+
status: import_constants.CODE_STATUS_UNUSED,
|
|
86
|
+
expiresAt: {
|
|
87
|
+
$dateAfter: /* @__PURE__ */ new Date()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
if (record) {
|
|
92
|
+
const seconds = (0, import_dayjs.default)(record.get("expiresAt")).diff((0, import_dayjs.default)(), "seconds");
|
|
93
|
+
return ctx.throw(429, {
|
|
94
|
+
code: "RateLimit",
|
|
95
|
+
message: ctx.t("Please don't retry in {{time}} seconds", { time: seconds, ns: import__2.namespace })
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const code = (await asyncRandomInt(999999)).toString(10).padStart(6, "0");
|
|
99
|
+
try {
|
|
100
|
+
await provider.send(receiver, { code });
|
|
101
|
+
} catch (error) {
|
|
102
|
+
switch (error.name) {
|
|
103
|
+
case "InvalidReceiver":
|
|
104
|
+
return ctx.throw(400, {
|
|
105
|
+
code: "InvalidReceiver",
|
|
106
|
+
message: ctx.t("Not a valid cellphone number, please re-enter", { ns: import__2.namespace })
|
|
107
|
+
});
|
|
108
|
+
case "RateLimit":
|
|
109
|
+
return ctx.throw(429, ctx.t("You are trying so frequently, please slow down", { ns: import__2.namespace }));
|
|
110
|
+
default:
|
|
111
|
+
ctx.log.error(error);
|
|
112
|
+
return ctx.throw(
|
|
113
|
+
500,
|
|
114
|
+
ctx.t("Verification send failed, please try later or contact to administrator", { ns: import__2.namespace })
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const result = await ctx.db.getRepository("otpRecords").create({
|
|
119
|
+
values: {
|
|
120
|
+
id: (0, import_crypto.randomUUID)(),
|
|
121
|
+
action: actionName,
|
|
122
|
+
receiver,
|
|
123
|
+
code,
|
|
124
|
+
expiresAt: Date.now() + (verification.expiresIn ?? 60) * 1e3,
|
|
125
|
+
status: import_constants.CODE_STATUS_UNUSED,
|
|
126
|
+
verifierName
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
ctx.body = {
|
|
130
|
+
id: result.id,
|
|
131
|
+
expiresAt: result.expiresAt
|
|
132
|
+
};
|
|
133
|
+
return next();
|
|
134
|
+
}
|
|
135
|
+
var sms_otp_default = {
|
|
136
|
+
name: "smsOTP",
|
|
137
|
+
actions: {
|
|
138
|
+
create,
|
|
139
|
+
publicCreate: create
|
|
140
|
+
}
|
|
141
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Registry } from '@nocobase/utils';
|
|
10
|
+
import { Verification, VerificationExtend } from './verification';
|
|
11
|
+
import { Context, Next } from '@nocobase/actions';
|
|
12
|
+
import { Database } from '@nocobase/database';
|
|
13
|
+
export type VerificationTypeOptions = {
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
bindingRequired?: boolean;
|
|
17
|
+
verification: VerificationExtend<Verification>;
|
|
18
|
+
};
|
|
19
|
+
type SceneRule = (scene: string, verificationType: string) => boolean;
|
|
20
|
+
export interface ActionOptions {
|
|
21
|
+
manual?: boolean;
|
|
22
|
+
getUserIdFromCtx?(ctx: Context): number | Promise<number>;
|
|
23
|
+
getBoundInfoFromCtx?(ctx: Context): any | Promise<any>;
|
|
24
|
+
getVerifyParams?(ctx: Context): any | Promise<any>;
|
|
25
|
+
onVerifySuccess?(ctx: Context, userId: number, verifyResult: any): any | Promise<any>;
|
|
26
|
+
onVerifyFail?(ctx: Context, err: Error, userId: number): any | Promise<any>;
|
|
27
|
+
}
|
|
28
|
+
export interface SceneOptions {
|
|
29
|
+
actions: {
|
|
30
|
+
[key: string]: ActionOptions;
|
|
31
|
+
};
|
|
32
|
+
getVerifiers?(ctx: Context): Promise<string[]>;
|
|
33
|
+
}
|
|
34
|
+
export declare class VerificationManager {
|
|
35
|
+
db: Database;
|
|
36
|
+
verificationTypes: Registry<VerificationTypeOptions>;
|
|
37
|
+
scenes: Registry<SceneOptions>;
|
|
38
|
+
sceneRules: SceneRule[];
|
|
39
|
+
actions: Registry<ActionOptions & {
|
|
40
|
+
scene?: string;
|
|
41
|
+
}>;
|
|
42
|
+
constructor({ db }: {
|
|
43
|
+
db: any;
|
|
44
|
+
});
|
|
45
|
+
registerVerificationType(type: string, options: VerificationTypeOptions): void;
|
|
46
|
+
listTypes(): {
|
|
47
|
+
name: string;
|
|
48
|
+
title: string;
|
|
49
|
+
}[];
|
|
50
|
+
addSceneRule(rule: SceneRule): void;
|
|
51
|
+
registerAction(action: string, options: ActionOptions): void;
|
|
52
|
+
registerScene(scene: string, options: SceneOptions): void;
|
|
53
|
+
getVerificationTypesByScene(scene: string): any[];
|
|
54
|
+
getVerification(type: string): VerificationExtend<Verification>;
|
|
55
|
+
getVerifier(verifierName: string): Promise<any>;
|
|
56
|
+
getVerifiers(verifierNames: string[]): Promise<any>;
|
|
57
|
+
getBoundRecord(userId: number, verifier: string): Promise<any>;
|
|
58
|
+
getAndValidateBoundInfo(ctx: Context, action: ActionOptions, verification: Verification): Promise<{
|
|
59
|
+
boundInfo: {
|
|
60
|
+
uuid: string;
|
|
61
|
+
};
|
|
62
|
+
userId: number;
|
|
63
|
+
}>;
|
|
64
|
+
private validateAndGetVerifier;
|
|
65
|
+
verify(ctx: Context, next: Next): Promise<void>;
|
|
66
|
+
middleware(): (ctx: Context, next: Next) => Promise<any>;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var verification_manager_exports = {};
|
|
28
|
+
__export(verification_manager_exports, {
|
|
29
|
+
VerificationManager: () => VerificationManager
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(verification_manager_exports);
|
|
32
|
+
var import_utils = require("@nocobase/utils");
|
|
33
|
+
class VerificationManager {
|
|
34
|
+
db;
|
|
35
|
+
verificationTypes = new import_utils.Registry();
|
|
36
|
+
scenes = new import_utils.Registry();
|
|
37
|
+
sceneRules = new Array();
|
|
38
|
+
actions = new import_utils.Registry();
|
|
39
|
+
constructor({ db }) {
|
|
40
|
+
this.db = db;
|
|
41
|
+
}
|
|
42
|
+
registerVerificationType(type, options) {
|
|
43
|
+
this.verificationTypes.register(type, options);
|
|
44
|
+
}
|
|
45
|
+
listTypes() {
|
|
46
|
+
return Array.from(this.verificationTypes.getEntities()).map(([verificationType, options]) => ({
|
|
47
|
+
name: verificationType,
|
|
48
|
+
title: options.title
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
addSceneRule(rule) {
|
|
52
|
+
this.sceneRules.push(rule);
|
|
53
|
+
}
|
|
54
|
+
registerAction(action, options) {
|
|
55
|
+
this.actions.register(action, options);
|
|
56
|
+
}
|
|
57
|
+
registerScene(scene, options) {
|
|
58
|
+
this.scenes.register(scene, options);
|
|
59
|
+
const { actions } = options;
|
|
60
|
+
for (const [action, actionOptions] of Object.entries(actions)) {
|
|
61
|
+
this.actions.register(action, {
|
|
62
|
+
...actionOptions,
|
|
63
|
+
scene
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
getVerificationTypesByScene(scene) {
|
|
68
|
+
const verificationTypes = [];
|
|
69
|
+
for (const [type, options] of this.verificationTypes.getEntities()) {
|
|
70
|
+
const item = { type, title: options.title };
|
|
71
|
+
if (this.sceneRules.some((rule) => rule(scene, type))) {
|
|
72
|
+
verificationTypes.push(item);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return verificationTypes;
|
|
76
|
+
}
|
|
77
|
+
getVerification(type) {
|
|
78
|
+
const verificationType = this.verificationTypes.get(type);
|
|
79
|
+
if (!verificationType) {
|
|
80
|
+
throw new Error(`Invalid verification type: ${type}`);
|
|
81
|
+
}
|
|
82
|
+
return verificationType.verification;
|
|
83
|
+
}
|
|
84
|
+
async getVerifier(verifierName) {
|
|
85
|
+
return await this.db.getRepository("verifiers").findOne({
|
|
86
|
+
filter: {
|
|
87
|
+
name: verifierName
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async getVerifiers(verifierNames) {
|
|
92
|
+
return await this.db.getRepository("verifiers").find({
|
|
93
|
+
filter: {
|
|
94
|
+
name: verifierNames
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async getBoundRecord(userId, verifier) {
|
|
99
|
+
return await this.db.getRepository("usersVerifiers").findOne({
|
|
100
|
+
filter: {
|
|
101
|
+
userId,
|
|
102
|
+
verifier
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async getAndValidateBoundInfo(ctx, action, verification) {
|
|
107
|
+
var _a, _b;
|
|
108
|
+
let userId;
|
|
109
|
+
let boundInfo;
|
|
110
|
+
if (action.getBoundInfoFromCtx) {
|
|
111
|
+
boundInfo = await action.getBoundInfoFromCtx(ctx);
|
|
112
|
+
} else {
|
|
113
|
+
if (action.getUserIdFromCtx) {
|
|
114
|
+
userId = await action.getUserIdFromCtx(ctx);
|
|
115
|
+
} else {
|
|
116
|
+
userId = (_b = (_a = ctx.auth) == null ? void 0 : _a.user) == null ? void 0 : _b.id;
|
|
117
|
+
}
|
|
118
|
+
if (!userId) {
|
|
119
|
+
ctx.throw(400, "Invalid user id");
|
|
120
|
+
}
|
|
121
|
+
boundInfo = await verification.getBoundInfo(userId);
|
|
122
|
+
}
|
|
123
|
+
await verification.validateBoundInfo(boundInfo);
|
|
124
|
+
return { boundInfo, userId };
|
|
125
|
+
}
|
|
126
|
+
async validateAndGetVerifier(ctx, scene, verifierName) {
|
|
127
|
+
let verifier;
|
|
128
|
+
if (!verifierName) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
if (scene) {
|
|
132
|
+
const sceneOptions = this.scenes.get(scene);
|
|
133
|
+
if (sceneOptions.getVerifiers) {
|
|
134
|
+
const verifiers = await sceneOptions.getVerifiers(ctx);
|
|
135
|
+
if (!verifiers.includes(verifierName)) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
verifier = await this.getVerifier(verifierName);
|
|
139
|
+
if (!verifier) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
const verificationTypes = this.getVerificationTypesByScene(scene);
|
|
144
|
+
const verifiers = await this.db.getRepository("verifiers").find({
|
|
145
|
+
filter: {
|
|
146
|
+
verificationType: verificationTypes.map((item) => item.type)
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
verifier = verifiers.find((item) => item.name === verifierName);
|
|
150
|
+
if (!verifier) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
verifier = await this.getVerifier(verifierName);
|
|
156
|
+
if (!verifier) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return verifier;
|
|
161
|
+
}
|
|
162
|
+
// verify manually
|
|
163
|
+
async verify(ctx, next) {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
const { resourceName, actionName } = ctx.action;
|
|
166
|
+
const key = `${resourceName}:${actionName}`;
|
|
167
|
+
const action = this.actions.get(key);
|
|
168
|
+
if (!action) {
|
|
169
|
+
ctx.throw(400, "Invalid action");
|
|
170
|
+
}
|
|
171
|
+
const { verifier: verifierName } = ctx.action.params.values || {};
|
|
172
|
+
const verifier = await this.validateAndGetVerifier(ctx, action.scene, verifierName);
|
|
173
|
+
if (!verifier) {
|
|
174
|
+
ctx.throw(400, "Invalid verifier");
|
|
175
|
+
}
|
|
176
|
+
const verifyParams = action.getVerifyParams ? await action.getVerifyParams(ctx) : ctx.action.params.values;
|
|
177
|
+
if (!verifyParams) {
|
|
178
|
+
ctx.throw(400, "Invalid verify params");
|
|
179
|
+
}
|
|
180
|
+
const plugin = ctx.app.pm.get("verification");
|
|
181
|
+
const verificationManager = plugin.verificationManager;
|
|
182
|
+
const Verification2 = verificationManager.getVerification(verifier.verificationType);
|
|
183
|
+
const verification = new Verification2({ ctx, verifier, options: verifier.options });
|
|
184
|
+
const { boundInfo, userId } = await this.getAndValidateBoundInfo(ctx, action, verification);
|
|
185
|
+
try {
|
|
186
|
+
const verifyResult = await verification.verify({
|
|
187
|
+
resource: resourceName,
|
|
188
|
+
action: actionName,
|
|
189
|
+
userId,
|
|
190
|
+
boundInfo,
|
|
191
|
+
verifyParams
|
|
192
|
+
});
|
|
193
|
+
try {
|
|
194
|
+
await ((_a = action.onVerifySuccess) == null ? void 0 : _a.call(action, ctx, userId, verifyResult));
|
|
195
|
+
await next();
|
|
196
|
+
} catch (err) {
|
|
197
|
+
ctx.log.error(err, { module: "verification", method: "verify" });
|
|
198
|
+
throw err;
|
|
199
|
+
} finally {
|
|
200
|
+
await verification.onActionComplete({ userId, verifyResult });
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
await ((_b = action.onVerifyFail) == null ? void 0 : _b.call(action, ctx, err, userId));
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
middleware() {
|
|
208
|
+
const self = this;
|
|
209
|
+
return async function verificationMiddleware(ctx, next) {
|
|
210
|
+
const { resourceName, actionName } = ctx.action;
|
|
211
|
+
const key = `${resourceName}:${actionName}`;
|
|
212
|
+
const action = self.actions.get(key);
|
|
213
|
+
if (!action || action.manual) {
|
|
214
|
+
return next();
|
|
215
|
+
}
|
|
216
|
+
return self.verify(ctx, next);
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
221
|
+
0 && (module.exports = {
|
|
222
|
+
VerificationManager
|
|
223
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Context } from '@nocobase/actions';
|
|
10
|
+
import { Model } from '@nocobase/database';
|
|
11
|
+
export interface IVerification {
|
|
12
|
+
verify(options: {
|
|
13
|
+
resource: string;
|
|
14
|
+
action: string;
|
|
15
|
+
userId: number;
|
|
16
|
+
boundInfo: any;
|
|
17
|
+
verifyParams?: any;
|
|
18
|
+
}): Promise<any>;
|
|
19
|
+
onActionComplete?(options: {
|
|
20
|
+
userId: number;
|
|
21
|
+
verifyResult: any;
|
|
22
|
+
}): Promise<any>;
|
|
23
|
+
getBoundInfo?(userId: number): Promise<any>;
|
|
24
|
+
getPublicBoundInfo?(userId: number): Promise<{
|
|
25
|
+
bound: boolean;
|
|
26
|
+
publicInfo?: any;
|
|
27
|
+
}>;
|
|
28
|
+
validateBoundInfo?(boundInfo: string): Promise<boolean>;
|
|
29
|
+
bind?(userId: number, resource?: string, action?: string): Promise<{
|
|
30
|
+
uuid: string;
|
|
31
|
+
meta?: any;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export declare abstract class Verification implements IVerification {
|
|
35
|
+
verifier: Model;
|
|
36
|
+
protected ctx: Context;
|
|
37
|
+
protected options: Record<string, any>;
|
|
38
|
+
constructor({ ctx, verifier, options }: {
|
|
39
|
+
ctx: any;
|
|
40
|
+
verifier: any;
|
|
41
|
+
options: any;
|
|
42
|
+
});
|
|
43
|
+
get throughRepo(): import("@nocobase/database").Repository<any, any>;
|
|
44
|
+
abstract verify({ resource, action, userId, boundInfo, verifyParams }: {
|
|
45
|
+
resource: any;
|
|
46
|
+
action: any;
|
|
47
|
+
userId: any;
|
|
48
|
+
boundInfo: any;
|
|
49
|
+
verifyParams: any;
|
|
50
|
+
}): Promise<any>;
|
|
51
|
+
onActionComplete(options: {
|
|
52
|
+
userId: number;
|
|
53
|
+
verifyResult: any;
|
|
54
|
+
}): Promise<any>;
|
|
55
|
+
bind(userId: number, resource?: string, action?: string): Promise<{
|
|
56
|
+
uuid: string;
|
|
57
|
+
meta?: any;
|
|
58
|
+
}>;
|
|
59
|
+
getBoundInfo(userId: number): Promise<any>;
|
|
60
|
+
getPublicBoundInfo(userId: number): Promise<{
|
|
61
|
+
bound: boolean;
|
|
62
|
+
publicInfo?: any;
|
|
63
|
+
}>;
|
|
64
|
+
validateBoundInfo(boundInfo: any): Promise<boolean>;
|
|
65
|
+
}
|
|
66
|
+
export type VerificationExtend<T extends Verification> = new ({ ctx, verifier, options }: {
|
|
67
|
+
ctx: any;
|
|
68
|
+
verifier: any;
|
|
69
|
+
options: any;
|
|
70
|
+
}) => T;
|