@nocobase/plugin-verification 0.9.0-alpha.1 → 0.9.1-alpha.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/README.md +9 -0
- package/README.zh-CN.md +9 -0
- package/lib/client/locale/index.js +7 -12
- package/lib/client/locale/zh-CN.d.ts +6 -0
- package/lib/client/locale/zh-CN.js +7 -1
- package/lib/client/providerTypes/index.js +3 -0
- package/lib/client/providerTypes/sms-tencent.d.ts +57 -0
- package/lib/client/providerTypes/sms-tencent.js +58 -0
- package/lib/client/schemas/providers.js +3 -0
- package/lib/server/actions/verifications.js +1 -6
- package/lib/server/collections/verifications.d.ts +2 -0
- package/lib/server/collections/verifications.js +2 -0
- package/lib/server/collections/verifications_providers.d.ts +2 -0
- package/lib/server/collections/verifications_providers.js +2 -0
- package/lib/server/constants.d.ts +1 -0
- package/lib/server/constants.js +3 -1
- package/lib/server/providers/index.js +1 -1
- package/lib/server/providers/sms-tencent.d.ts +10 -0
- package/lib/server/providers/sms-tencent.js +94 -0
- package/package.json +8 -7
- package/src/client/locale/index.ts +2 -3
- package/src/client/locale/zh-CN.ts +7 -0
- package/src/client/providerTypes/index.ts +2 -0
- package/src/client/providerTypes/sms-tencent.ts +52 -0
- package/src/client/schemas/providers.ts +1 -0
- package/src/server/actions/verifications.ts +3 -8
- package/src/server/collections/verifications.ts +2 -0
- package/src/server/collections/verifications_providers.ts +2 -0
- package/src/server/constants.ts +1 -0
- package/src/server/locale/zh-CN.ts +1 -1
- package/src/server/providers/index.ts +6 -5
- package/src/server/providers/sms-tencent.ts +57 -0
package/README.md
ADDED
package/README.zh-CN.md
ADDED
|
@@ -7,35 +7,30 @@ exports.NAMESPACE = void 0;
|
|
|
7
7
|
exports.lang = lang;
|
|
8
8
|
exports.useVerificationTranslation = useVerificationTranslation;
|
|
9
9
|
|
|
10
|
-
function
|
|
11
|
-
const data = require("
|
|
10
|
+
function _client() {
|
|
11
|
+
const data = require("@nocobase/client");
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
_client = function _client() {
|
|
14
14
|
return data;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
return data;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
function
|
|
21
|
-
const data = require("
|
|
20
|
+
function _reactI18next() {
|
|
21
|
+
const data = require("react-i18next");
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
_reactI18next = function _reactI18next() {
|
|
24
24
|
return data;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
return data;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
30
|
+
const NAMESPACE = 'verification'; // i18n.addResources('zh-CN', NAMESPACE, zhCN);
|
|
33
31
|
|
|
34
|
-
const NAMESPACE = 'verification';
|
|
35
32
|
exports.NAMESPACE = NAMESPACE;
|
|
36
33
|
|
|
37
|
-
_client().i18n.addResources('zh-CN', NAMESPACE, _zhCN.default);
|
|
38
|
-
|
|
39
34
|
function lang(key) {
|
|
40
35
|
return _client().i18n.t(key, {
|
|
41
36
|
ns: NAMESPACE
|
|
@@ -8,5 +8,11 @@ declare const _default: {
|
|
|
8
8
|
Endpoint: string;
|
|
9
9
|
Sign: string;
|
|
10
10
|
'Template code': string;
|
|
11
|
+
'Secret Id': string;
|
|
12
|
+
'Secret Key': string;
|
|
13
|
+
Region: string;
|
|
14
|
+
'Sign name': string;
|
|
15
|
+
'Sms sdk app id': string;
|
|
16
|
+
'Template Id': string;
|
|
11
17
|
};
|
|
12
18
|
export default _default;
|
|
@@ -14,6 +14,12 @@ var _default = {
|
|
|
14
14
|
'Access Key Secret': 'Access Key Secret',
|
|
15
15
|
'Endpoint': '接入点',
|
|
16
16
|
'Sign': '签名',
|
|
17
|
-
'Template code': '模板代码'
|
|
17
|
+
'Template code': '模板代码',
|
|
18
|
+
'Secret Id': 'Secret Id',
|
|
19
|
+
'Secret Key': 'Secret Key',
|
|
20
|
+
'Region': '地域',
|
|
21
|
+
'Sign name': '短信签名内容',
|
|
22
|
+
'Sms sdk app id': '短信应用 ID',
|
|
23
|
+
'Template Id': '短信模板 ID'
|
|
18
24
|
};
|
|
19
25
|
exports.default = _default;
|
|
@@ -17,9 +17,12 @@ function _client() {
|
|
|
17
17
|
|
|
18
18
|
var _smsAliyun = _interopRequireDefault(require("./sms-aliyun"));
|
|
19
19
|
|
|
20
|
+
var _smsTencent = _interopRequireDefault(require("./sms-tencent"));
|
|
21
|
+
|
|
20
22
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
23
|
|
|
22
24
|
const providerTypes = new (_client().Registry)();
|
|
23
25
|
providerTypes.register('sms-aliyun', _smsAliyun.default);
|
|
26
|
+
providerTypes.register('sms-tencent', _smsTencent.default);
|
|
24
27
|
var _default = providerTypes;
|
|
25
28
|
exports.default = _default;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
declare const _default: import("@formily/react").Stringify<{
|
|
2
|
+
[key: symbol]: any;
|
|
3
|
+
[key: `x-${string}`]: any;
|
|
4
|
+
[key: `x-${number}`]: any;
|
|
5
|
+
version?: string;
|
|
6
|
+
name?: import("@formily/react").SchemaKey;
|
|
7
|
+
title?: any;
|
|
8
|
+
description?: any;
|
|
9
|
+
default?: any;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
writeOnly?: boolean;
|
|
12
|
+
type?: import("@formily/react").SchemaTypes;
|
|
13
|
+
enum?: import("@formily/react").SchemaEnum<any>;
|
|
14
|
+
const?: any;
|
|
15
|
+
multipleOf?: number;
|
|
16
|
+
maximum?: number;
|
|
17
|
+
exclusiveMaximum?: number;
|
|
18
|
+
minimum?: number;
|
|
19
|
+
exclusiveMinimum?: number;
|
|
20
|
+
maxLength?: number;
|
|
21
|
+
minLength?: number;
|
|
22
|
+
pattern?: string | RegExp;
|
|
23
|
+
maxItems?: number;
|
|
24
|
+
minItems?: number;
|
|
25
|
+
uniqueItems?: boolean;
|
|
26
|
+
maxProperties?: number;
|
|
27
|
+
minProperties?: number;
|
|
28
|
+
required?: string | boolean | string[];
|
|
29
|
+
format?: string;
|
|
30
|
+
$ref?: string;
|
|
31
|
+
$namespace?: string;
|
|
32
|
+
definitions?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
|
|
33
|
+
properties?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
|
|
34
|
+
items?: import("@formily/react").SchemaItems<any, any, any, any, any, any, any, any>;
|
|
35
|
+
additionalItems?: import("@formily/react").Stringify<any>;
|
|
36
|
+
patternProperties?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
|
|
37
|
+
additionalProperties?: import("@formily/react").Stringify<any>;
|
|
38
|
+
"x-value"?: any;
|
|
39
|
+
"x-index"?: number;
|
|
40
|
+
"x-pattern"?: any;
|
|
41
|
+
"x-display"?: any;
|
|
42
|
+
"x-validator"?: any;
|
|
43
|
+
"x-decorator"?: any;
|
|
44
|
+
"x-decorator-props"?: any;
|
|
45
|
+
"x-component"?: any;
|
|
46
|
+
"x-component-props"?: any;
|
|
47
|
+
"x-reactions"?: import("@formily/react").SchemaReactions<any>;
|
|
48
|
+
"x-content"?: any;
|
|
49
|
+
"x-data"?: any;
|
|
50
|
+
"x-visible"?: boolean;
|
|
51
|
+
"x-hidden"?: boolean;
|
|
52
|
+
"x-disabled"?: boolean;
|
|
53
|
+
"x-editable"?: boolean;
|
|
54
|
+
"x-read-only"?: boolean;
|
|
55
|
+
"x-read-pretty"?: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
export default _default;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _locale = require("../locale");
|
|
9
|
+
|
|
10
|
+
var _default = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
secretId: {
|
|
14
|
+
title: `{{t("Secret Id", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
15
|
+
type: 'string',
|
|
16
|
+
'x-decorator': 'FormItem',
|
|
17
|
+
'x-component': 'Input'
|
|
18
|
+
},
|
|
19
|
+
secretKey: {
|
|
20
|
+
title: `{{t("Secret Key", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
21
|
+
type: 'string',
|
|
22
|
+
'x-decorator': 'FormItem',
|
|
23
|
+
'x-component': 'Password'
|
|
24
|
+
},
|
|
25
|
+
region: {
|
|
26
|
+
title: `{{t("Region", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
27
|
+
type: 'string',
|
|
28
|
+
'x-decorator': 'FormItem',
|
|
29
|
+
'x-component': 'Input'
|
|
30
|
+
},
|
|
31
|
+
endpoint: {
|
|
32
|
+
title: `{{t("Endpoint", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
33
|
+
type: 'string',
|
|
34
|
+
'x-decorator': 'FormItem',
|
|
35
|
+
'x-component': 'Input',
|
|
36
|
+
default: 'sms.tencentcloudapi.com'
|
|
37
|
+
},
|
|
38
|
+
SignName: {
|
|
39
|
+
title: `{{t("Sign name", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
40
|
+
type: 'string',
|
|
41
|
+
'x-decorator': 'FormItem',
|
|
42
|
+
'x-component': 'Input'
|
|
43
|
+
},
|
|
44
|
+
SmsSdkAppId: {
|
|
45
|
+
title: `{{t("Sms sdk app id", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
46
|
+
type: 'string',
|
|
47
|
+
'x-decorator': 'FormItem',
|
|
48
|
+
'x-component': 'Input'
|
|
49
|
+
},
|
|
50
|
+
TemplateId: {
|
|
51
|
+
title: `{{t("Template Id", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
52
|
+
type: 'string',
|
|
53
|
+
'x-decorator': 'FormItem',
|
|
54
|
+
'x-component': 'Input'
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.default = _default;
|
|
@@ -83,12 +83,7 @@ function _create() {
|
|
|
83
83
|
return context.throw(400, 'Invalid action type');
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const
|
|
87
|
-
const providerItem = yield ProviderRepo.findOne({
|
|
88
|
-
filter: {
|
|
89
|
-
default: true
|
|
90
|
-
}
|
|
91
|
-
});
|
|
86
|
+
const providerItem = yield plugin.getDefault();
|
|
92
87
|
|
|
93
88
|
if (!providerItem) {
|
|
94
89
|
console.error(`[verification] no provider for action (${values.type}) provided`);
|
package/lib/server/constants.js
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.PROVIDER_TYPE_SMS_ALIYUN = exports.CODE_STATUS_USED = exports.CODE_STATUS_UNUSED = void 0;
|
|
6
|
+
exports.PROVIDER_TYPE_SMS_TENCENT = exports.PROVIDER_TYPE_SMS_ALIYUN = exports.CODE_STATUS_USED = exports.CODE_STATUS_UNUSED = void 0;
|
|
7
7
|
const PROVIDER_TYPE_SMS_ALIYUN = 'sms-aliyun';
|
|
8
8
|
exports.PROVIDER_TYPE_SMS_ALIYUN = PROVIDER_TYPE_SMS_ALIYUN;
|
|
9
|
+
const PROVIDER_TYPE_SMS_TENCENT = 'sms-tencent';
|
|
10
|
+
exports.PROVIDER_TYPE_SMS_TENCENT = PROVIDER_TYPE_SMS_TENCENT;
|
|
9
11
|
const CODE_STATUS_UNUSED = 0;
|
|
10
12
|
exports.CODE_STATUS_UNUSED = CODE_STATUS_UNUSED;
|
|
11
13
|
const CODE_STATUS_USED = 1;
|
|
@@ -70,7 +70,7 @@ exports.Provider = Provider;
|
|
|
70
70
|
|
|
71
71
|
function _default(plugin, more = {}) {
|
|
72
72
|
const providers = plugin.providers;
|
|
73
|
-
const natives = [_constants.PROVIDER_TYPE_SMS_ALIYUN].reduce((result, key) => Object.assign(result, {
|
|
73
|
+
const natives = [_constants.PROVIDER_TYPE_SMS_ALIYUN, _constants.PROVIDER_TYPE_SMS_TENCENT].reduce((result, key) => Object.assign(result, {
|
|
74
74
|
[key]: (0, _utils().requireModule)(_path().default.isAbsolute(key) ? key : _path().default.join(__dirname, key))
|
|
75
75
|
}), {});
|
|
76
76
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Provider } from '.';
|
|
2
|
+
declare const smsClient: typeof import("tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/sms_client").Client;
|
|
3
|
+
export default class extends Provider {
|
|
4
|
+
client: InstanceType<typeof smsClient>;
|
|
5
|
+
constructor(plugin: any, options: any);
|
|
6
|
+
send(phoneNumbers: any, data: {
|
|
7
|
+
code: string;
|
|
8
|
+
}): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _ = require(".");
|
|
9
|
+
|
|
10
|
+
function tencentcloud() {
|
|
11
|
+
const data = _interopRequireWildcard(require("tencentcloud-sdk-nodejs"));
|
|
12
|
+
|
|
13
|
+
tencentcloud = function tencentcloud() {
|
|
14
|
+
return data;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
21
|
+
|
|
22
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
23
|
+
|
|
24
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
25
|
+
|
|
26
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
27
|
+
|
|
28
|
+
// 导入对应产品模块的client models。
|
|
29
|
+
const smsClient = tencentcloud().sms.v20210111.Client;
|
|
30
|
+
|
|
31
|
+
class _default extends _.Provider {
|
|
32
|
+
constructor(plugin, options) {
|
|
33
|
+
super(plugin, options);
|
|
34
|
+
this.client = void 0;
|
|
35
|
+
const _this$options = this.options,
|
|
36
|
+
secretId = _this$options.secretId,
|
|
37
|
+
secretKey = _this$options.secretKey,
|
|
38
|
+
region = _this$options.region,
|
|
39
|
+
endpoint = _this$options.endpoint;
|
|
40
|
+
/* 实例化要请求产品(以sms为例)的client对象 */
|
|
41
|
+
|
|
42
|
+
this.client = new smsClient({
|
|
43
|
+
credential: {
|
|
44
|
+
secretId,
|
|
45
|
+
secretKey
|
|
46
|
+
},
|
|
47
|
+
region,
|
|
48
|
+
profile: {
|
|
49
|
+
httpProfile: {
|
|
50
|
+
endpoint
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
send(phoneNumbers, data) {
|
|
57
|
+
var _this = this;
|
|
58
|
+
|
|
59
|
+
return _asyncToGenerator(function* () {
|
|
60
|
+
const _this$options2 = _this.options,
|
|
61
|
+
SignName = _this$options2.SignName,
|
|
62
|
+
TemplateId = _this$options2.TemplateId,
|
|
63
|
+
SmsSdkAppId = _this$options2.SmsSdkAppId;
|
|
64
|
+
const result = yield _this.client.SendSms({
|
|
65
|
+
PhoneNumberSet: [phoneNumbers],
|
|
66
|
+
SignName,
|
|
67
|
+
TemplateId,
|
|
68
|
+
SmsSdkAppId,
|
|
69
|
+
TemplateParamSet: [data.code]
|
|
70
|
+
});
|
|
71
|
+
const errCode = result.SendStatusSet[0].Code;
|
|
72
|
+
const error = new Error(`${errCode}:${result.SendStatusSet[0].Message}`);
|
|
73
|
+
|
|
74
|
+
switch (errCode) {
|
|
75
|
+
case 'Ok':
|
|
76
|
+
return result.RequestId;
|
|
77
|
+
|
|
78
|
+
case 'InvalidParameterValue.IncorrectPhoneNumber':
|
|
79
|
+
error.name = 'InvalidReceiver';
|
|
80
|
+
|
|
81
|
+
case 'LimitExceeded.DeliveryFrequencyLimit':
|
|
82
|
+
case 'LimitExceeded.PhoneNumberDailyLimit':
|
|
83
|
+
case 'LimitExceeded.PhoneNumberThirtySecondLimit':
|
|
84
|
+
case 'LimitExceeded.PhoneNumberOneHourLimit':
|
|
85
|
+
error.name = 'RateLimit';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
throw error;
|
|
89
|
+
})();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.default = _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/plugin-verification",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
"@alicloud/dysmsapi20170525": "2.0.17",
|
|
10
10
|
"@alicloud/openapi-client": "0.4.1",
|
|
11
11
|
"@alicloud/tea-util": "1.4.4",
|
|
12
|
-
"@nocobase/actions": "0.9.
|
|
13
|
-
"@nocobase/resourcer": "0.9.
|
|
14
|
-
"@nocobase/server": "0.9.
|
|
15
|
-
"@nocobase/utils": "0.9.
|
|
12
|
+
"@nocobase/actions": "0.9.1-alpha.1",
|
|
13
|
+
"@nocobase/resourcer": "0.9.1-alpha.1",
|
|
14
|
+
"@nocobase/server": "0.9.1-alpha.1",
|
|
15
|
+
"@nocobase/utils": "0.9.1-alpha.1",
|
|
16
|
+
"tencentcloud-sdk-nodejs": "^4.0.525"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
|
-
"@nocobase/test": "0.9.
|
|
19
|
+
"@nocobase/test": "0.9.1-alpha.1"
|
|
19
20
|
},
|
|
20
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "56cb184b00dc383b853015d525bf6e79dea92169"
|
|
21
22
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { useTranslation } from 'react-i18next';
|
|
2
1
|
import { i18n } from '@nocobase/client';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
3
|
|
|
4
|
-
import zhCN from './zh-CN';
|
|
5
4
|
|
|
6
5
|
export const NAMESPACE = 'verification';
|
|
7
6
|
|
|
8
|
-
i18n.addResources('zh-CN', NAMESPACE, zhCN);
|
|
7
|
+
// i18n.addResources('zh-CN', NAMESPACE, zhCN);
|
|
9
8
|
|
|
10
9
|
export function lang(key: string) {
|
|
11
10
|
return i18n.t(key, { ns: NAMESPACE });
|
|
@@ -10,4 +10,11 @@ export default {
|
|
|
10
10
|
'Endpoint': '接入点',
|
|
11
11
|
'Sign': '签名',
|
|
12
12
|
'Template code': '模板代码',
|
|
13
|
+
|
|
14
|
+
'Secret Id': 'Secret Id',
|
|
15
|
+
'Secret Key': 'Secret Key',
|
|
16
|
+
'Region': '地域',
|
|
17
|
+
'Sign name': '短信签名内容',
|
|
18
|
+
'Sms sdk app id': '短信应用 ID',
|
|
19
|
+
'Template Id': '短信模板 ID'
|
|
13
20
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ISchema } from '@formily/react';
|
|
2
2
|
import { Registry } from "@nocobase/utils/client";
|
|
3
3
|
import SMSAliyun from './sms-aliyun';
|
|
4
|
+
import SMSTencent from './sms-tencent';
|
|
4
5
|
|
|
5
6
|
const providerTypes: Registry<ISchema> = new Registry();
|
|
6
7
|
|
|
7
8
|
providerTypes.register('sms-aliyun', SMSAliyun);
|
|
9
|
+
providerTypes.register('sms-tencent', SMSTencent);
|
|
8
10
|
|
|
9
11
|
export default providerTypes;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ISchema } from '@formily/react';
|
|
2
|
+
|
|
3
|
+
import { NAMESPACE } from '../locale';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
secretId: {
|
|
9
|
+
title: `{{t("Secret Id", { ns: "${NAMESPACE}" })}}`,
|
|
10
|
+
type: 'string',
|
|
11
|
+
'x-decorator': 'FormItem',
|
|
12
|
+
'x-component': 'Input',
|
|
13
|
+
},
|
|
14
|
+
secretKey: {
|
|
15
|
+
title: `{{t("Secret Key", { ns: "${NAMESPACE}" })}}`,
|
|
16
|
+
type: 'string',
|
|
17
|
+
'x-decorator': 'FormItem',
|
|
18
|
+
'x-component': 'Password',
|
|
19
|
+
},
|
|
20
|
+
region: {
|
|
21
|
+
title: `{{t("Region", { ns: "${NAMESPACE}" })}}`,
|
|
22
|
+
type: 'string',
|
|
23
|
+
'x-decorator': 'FormItem',
|
|
24
|
+
'x-component': 'Input',
|
|
25
|
+
},
|
|
26
|
+
endpoint: {
|
|
27
|
+
title: `{{t("Endpoint", { ns: "${NAMESPACE}" })}}`,
|
|
28
|
+
type: 'string',
|
|
29
|
+
'x-decorator': 'FormItem',
|
|
30
|
+
'x-component': 'Input',
|
|
31
|
+
default: 'sms.tencentcloudapi.com',
|
|
32
|
+
},
|
|
33
|
+
SignName: {
|
|
34
|
+
title: `{{t("Sign name", { ns: "${NAMESPACE}" })}}`,
|
|
35
|
+
type: 'string',
|
|
36
|
+
'x-decorator': 'FormItem',
|
|
37
|
+
'x-component': 'Input',
|
|
38
|
+
},
|
|
39
|
+
SmsSdkAppId: {
|
|
40
|
+
title: `{{t("Sms sdk app id", { ns: "${NAMESPACE}" })}}`,
|
|
41
|
+
type: 'string',
|
|
42
|
+
'x-decorator': 'FormItem',
|
|
43
|
+
'x-component': 'Input',
|
|
44
|
+
},
|
|
45
|
+
TemplateId: {
|
|
46
|
+
title: `{{t("Template Id", { ns: "${NAMESPACE}" })}}`,
|
|
47
|
+
type: 'string',
|
|
48
|
+
'x-decorator': 'FormItem',
|
|
49
|
+
'x-component': 'Input',
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} as ISchema;
|
|
@@ -19,12 +19,7 @@ export async function create(context: Context, next: Next) {
|
|
|
19
19
|
return context.throw(400, 'Invalid action type');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
const providerItem = await ProviderRepo.findOne({
|
|
24
|
-
filter: {
|
|
25
|
-
default: true
|
|
26
|
-
}
|
|
27
|
-
});
|
|
22
|
+
const providerItem = await plugin.getDefault()
|
|
28
23
|
if (!providerItem) {
|
|
29
24
|
console.error(`[verification] no provider for action (${values.type}) provided`);
|
|
30
25
|
return context.throw(500);
|
|
@@ -32,7 +27,7 @@ export async function create(context: Context, next: Next) {
|
|
|
32
27
|
|
|
33
28
|
const receiver = interceptor.getReceiver(context);
|
|
34
29
|
if (!receiver) {
|
|
35
|
-
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace }) });
|
|
30
|
+
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
|
|
36
31
|
}
|
|
37
32
|
const VerificationModel = context.db.getModel('verifications');
|
|
38
33
|
const record = await VerificationModel.findOne({
|
|
@@ -70,7 +65,7 @@ export async function create(context: Context, next: Next) {
|
|
|
70
65
|
switch (error.name) {
|
|
71
66
|
case 'InvalidReceiver':
|
|
72
67
|
// TODO: message should consider email and other providers, maybe use "receiver"
|
|
73
|
-
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace })});
|
|
68
|
+
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
|
|
74
69
|
case 'RateLimit':
|
|
75
70
|
return context.throw(429, context.t('You are trying so frequently, please slow down', { ns: namespace }));
|
|
76
71
|
default:
|
package/src/server/constants.ts
CHANGED
|
@@ -3,5 +3,5 @@ export default {
|
|
|
3
3
|
'Not a valid cellphone number, please re-enter': '不是有效的手机号,请重新输入',
|
|
4
4
|
"Please don't retry in {{time}} seconds": '请 {{time}} 秒后再试',
|
|
5
5
|
'You are trying so frequently, please slow down': '您的操作太频繁,请稍后再试',
|
|
6
|
-
'Verification code is invalid': '无效的验证码'
|
|
6
|
+
'Verification code is invalid': '无效的验证码',
|
|
7
7
|
};
|
|
@@ -3,25 +3,26 @@ import path from 'path';
|
|
|
3
3
|
import { requireModule } from '@nocobase/utils';
|
|
4
4
|
|
|
5
5
|
import Plugin from '../Plugin';
|
|
6
|
-
import { PROVIDER_TYPE_SMS_ALIYUN } from '../constants';
|
|
6
|
+
import { PROVIDER_TYPE_SMS_ALIYUN, PROVIDER_TYPE_SMS_TENCENT } from '../constants';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
export class Provider {
|
|
11
|
-
constructor(protected plugin: Plugin, protected options) {}
|
|
11
|
+
constructor(protected plugin: Plugin, protected options) { }
|
|
12
12
|
|
|
13
|
-
async send(receiver: string, data: { [key: string]: any }): Promise<any>{}
|
|
13
|
+
async send(receiver: string, data: { [key: string]: any }): Promise<any> { }
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
interface Providers {
|
|
17
17
|
[key: string]: typeof Provider
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export default function(plugin: Plugin, more: Providers = {}) {
|
|
20
|
+
export default function (plugin: Plugin, more: Providers = {}) {
|
|
21
21
|
const { providers } = plugin;
|
|
22
22
|
|
|
23
23
|
const natives = [
|
|
24
|
-
PROVIDER_TYPE_SMS_ALIYUN
|
|
24
|
+
PROVIDER_TYPE_SMS_ALIYUN,
|
|
25
|
+
PROVIDER_TYPE_SMS_TENCENT
|
|
25
26
|
].reduce((result, key) => Object.assign(result, {
|
|
26
27
|
[key]: requireModule(path.isAbsolute(key) ? key : path.join(__dirname, key)) as typeof Provider
|
|
27
28
|
}), {} as Providers);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Provider } from '.';
|
|
2
|
+
import * as tencentcloud from "tencentcloud-sdk-nodejs"
|
|
3
|
+
|
|
4
|
+
// 导入对应产品模块的client models。
|
|
5
|
+
const smsClient = tencentcloud.sms.v20210111.Client;
|
|
6
|
+
|
|
7
|
+
export default class extends Provider {
|
|
8
|
+
client: InstanceType<typeof smsClient>;
|
|
9
|
+
|
|
10
|
+
constructor(plugin, options) {
|
|
11
|
+
super(plugin, options);
|
|
12
|
+
|
|
13
|
+
const { secretId, secretKey, region, endpoint } = this.options;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/* 实例化要请求产品(以sms为例)的client对象 */
|
|
17
|
+
this.client = new smsClient({
|
|
18
|
+
credential: {
|
|
19
|
+
secretId,
|
|
20
|
+
secretKey
|
|
21
|
+
},
|
|
22
|
+
region,
|
|
23
|
+
profile: {
|
|
24
|
+
httpProfile: {
|
|
25
|
+
endpoint
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async send(phoneNumbers, data: { code: string }) {
|
|
33
|
+
const { SignName, TemplateId, SmsSdkAppId } = this.options
|
|
34
|
+
const result = await this.client.SendSms({
|
|
35
|
+
PhoneNumberSet: [phoneNumbers],
|
|
36
|
+
SignName,
|
|
37
|
+
TemplateId,
|
|
38
|
+
SmsSdkAppId,
|
|
39
|
+
TemplateParamSet: [data.code]
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const errCode = result.SendStatusSet[0].Code
|
|
43
|
+
const error = new Error(`${errCode}:${result.SendStatusSet[0].Message}`)
|
|
44
|
+
switch (errCode) {
|
|
45
|
+
case 'Ok':
|
|
46
|
+
return result.RequestId
|
|
47
|
+
case 'InvalidParameterValue.IncorrectPhoneNumber':
|
|
48
|
+
error.name = 'InvalidReceiver'
|
|
49
|
+
case 'LimitExceeded.DeliveryFrequencyLimit':
|
|
50
|
+
case 'LimitExceeded.PhoneNumberDailyLimit':
|
|
51
|
+
case 'LimitExceeded.PhoneNumberThirtySecondLimit':
|
|
52
|
+
case 'LimitExceeded.PhoneNumberOneHourLimit':
|
|
53
|
+
error.name = 'RateLimit'
|
|
54
|
+
}
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
}
|