vona-module-a-captcha 5.0.9 → 5.0.11
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/.metadata/index.d.ts +10 -10
- package/dist/bean/interceptor.captchaVerify.d.ts +11 -0
- package/dist/dto/captchaData.d.ts +3 -2
- package/dist/index.js +41 -33
- package/dist/lib/captcha.d.ts +6 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/types/captchaProvider.d.ts +1 -1
- package/dist/types/captchaScene.d.ts +1 -1
- package/package.json +1 -1
- package/dist/bean/middleware.captcha.d.ts +0 -11
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import type { TypeSymbolKeyFieldsMore } from 'vona-module-a-orm';
|
|
2
2
|
import type { TypeEntityOptionsFields, TypeControllerOptionsActions } from 'vona-module-a-openapi';
|
|
3
|
-
/**
|
|
4
|
-
export * from '../bean/
|
|
5
|
-
import type {
|
|
3
|
+
/** interceptor: begin */
|
|
4
|
+
export * from '../bean/interceptor.captchaVerify.ts';
|
|
5
|
+
import type { IInterceptorOptionsCaptchaVerify } from '../bean/interceptor.captchaVerify.ts';
|
|
6
6
|
import 'vona';
|
|
7
7
|
declare module 'vona-module-a-aspect' {
|
|
8
|
-
interface
|
|
9
|
-
'a-captcha:
|
|
8
|
+
interface IInterceptorRecordLocal {
|
|
9
|
+
'a-captcha:captchaVerify': IInterceptorOptionsCaptchaVerify;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
declare module 'vona-module-a-captcha' {
|
|
13
|
-
interface
|
|
13
|
+
interface InterceptorCaptchaVerify {
|
|
14
14
|
}
|
|
15
|
-
interface
|
|
16
|
-
get $beanFullName(): 'a-captcha.
|
|
17
|
-
get $onionName(): 'a-captcha:
|
|
15
|
+
interface InterceptorCaptchaVerify {
|
|
16
|
+
get $beanFullName(): 'a-captcha.interceptor.captchaVerify';
|
|
17
|
+
get $onionName(): 'a-captcha:captchaVerify';
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
20
|
+
/** interceptor: end */
|
|
21
21
|
/** bean: begin */
|
|
22
22
|
export * from '../bean/bean.captcha.ts';
|
|
23
23
|
import 'vona';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Next } from 'vona';
|
|
2
|
+
import type { IDecoratorInterceptorOptions, IInterceptorExecute } from 'vona-module-a-aspect';
|
|
3
|
+
import type { ICaptchaSceneRecord } from '../types/captchaScene.ts';
|
|
4
|
+
import { BeanBase } from 'vona';
|
|
5
|
+
export interface IInterceptorOptionsCaptchaVerify extends IDecoratorInterceptorOptions {
|
|
6
|
+
scene?: keyof ICaptchaSceneRecord;
|
|
7
|
+
bodyField?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class InterceptorCaptchaVerify extends BeanBase implements IInterceptorExecute {
|
|
10
|
+
execute(options: IInterceptorOptionsCaptchaVerify, next: Next): Promise<any>;
|
|
11
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { IDecoratorDtoOptions } from 'vona-module-a-web';
|
|
2
|
+
import type { ICaptchaProviderRecord } from '../types/captchaProvider.ts';
|
|
2
3
|
export interface IDtoOptionsCaptchaData extends IDecoratorDtoOptions {
|
|
3
4
|
}
|
|
4
5
|
export declare class DtoCaptchaData {
|
|
5
6
|
id: string;
|
|
6
|
-
provider:
|
|
7
|
-
token
|
|
7
|
+
provider: keyof ICaptchaProviderRecord;
|
|
8
|
+
token?: unknown;
|
|
8
9
|
payload: unknown;
|
|
9
10
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,35 @@
|
|
|
1
1
|
import { BeanInfo, BeanBase, uuidv4, beanFullNameFromOnionName, deepExtend, BeanScopeBase, createBeanDecorator } from 'vona';
|
|
2
|
-
import {
|
|
2
|
+
import { Interceptor, Aspect } from 'vona-module-a-aspect';
|
|
3
3
|
import { getRandomInt } from '@cabloy/utils';
|
|
4
4
|
import { Bean, Scope } from 'vona-module-a-bean';
|
|
5
5
|
import { CacheRedis, BeanCacheRedisBase } from 'vona-module-a-cache';
|
|
6
|
-
import { Api } from 'vona-module-a-openapi';
|
|
6
|
+
import { Api, v } from 'vona-module-a-openapi';
|
|
7
7
|
import { Dto, Controller, Web, Arg } from 'vona-module-a-web';
|
|
8
|
-
import { Passport } from 'vona-module-a-user';
|
|
9
8
|
import z from 'zod';
|
|
9
|
+
import { Passport } from 'vona-module-a-user';
|
|
10
10
|
|
|
11
11
|
var _dec$6, _dec2$6, _class$6;
|
|
12
|
-
let
|
|
12
|
+
let InterceptorCaptchaVerify = (_dec$6 = Interceptor({
|
|
13
13
|
bodyField: 'captcha'
|
|
14
14
|
}), _dec2$6 = BeanInfo({
|
|
15
15
|
module: "a-captcha"
|
|
16
|
-
}), _dec$6(_class$6 = _dec2$6(_class$6 = class
|
|
16
|
+
}), _dec$6(_class$6 = _dec2$6(_class$6 = class InterceptorCaptchaVerify extends BeanBase {
|
|
17
17
|
async execute(options, next) {
|
|
18
|
+
// scene
|
|
18
19
|
const sceneName = options.scene;
|
|
19
|
-
if (!sceneName) throw new Error('
|
|
20
|
+
if (!sceneName) throw new Error('should specify the captchaVerify scene name');
|
|
20
21
|
// captcha
|
|
21
22
|
const bodyField = options.bodyField;
|
|
22
23
|
const captcha = this.ctx.request.body[bodyField];
|
|
23
24
|
if (!captcha) throw new Error('not found captcha data');
|
|
25
|
+
if (typeof captcha !== 'object') throw new Error('not found valid captcha data');
|
|
26
|
+
// verify
|
|
24
27
|
const verified = await this.bean.captcha.verify(captcha.id, captcha.token, sceneName);
|
|
25
|
-
if (!verified) throw
|
|
28
|
+
if (!verified) throw this.bean.zod.customError([bodyField], this.scope.locale.CaptchaInvalid());
|
|
26
29
|
// next
|
|
27
30
|
return next();
|
|
28
31
|
}
|
|
29
32
|
}) || _class$6) || _class$6);
|
|
30
|
-
function combineCaptchaError(bodyField, message) {
|
|
31
|
-
// error
|
|
32
|
-
const error = new Error();
|
|
33
|
-
error.code = 422;
|
|
34
|
-
error.message = [{
|
|
35
|
-
code: 'custom',
|
|
36
|
-
path: [bodyField],
|
|
37
|
-
message
|
|
38
|
-
}];
|
|
39
|
-
return error;
|
|
40
|
-
}
|
|
41
33
|
|
|
42
34
|
var _dec$5, _dec2$5, _class$5;
|
|
43
35
|
const SymbolProviders = Symbol('SymbolProviders');
|
|
@@ -111,7 +103,7 @@ let BeanCaptcha = (_dec$5 = Bean(), _dec2$5 = BeanInfo({
|
|
|
111
103
|
return result;
|
|
112
104
|
}
|
|
113
105
|
async verify(id, token, sceneName) {
|
|
114
|
-
|
|
106
|
+
let captchaData = await this.getCaptchaData(id);
|
|
115
107
|
if (!captchaData) return false;
|
|
116
108
|
// scene
|
|
117
109
|
if (captchaData.scene !== sceneName) return false;
|
|
@@ -119,44 +111,53 @@ let BeanCaptcha = (_dec$5 = Bean(), _dec2$5 = BeanInfo({
|
|
|
119
111
|
const tokenSecondary = captchaData.token2;
|
|
120
112
|
if (tokenSecondary) {
|
|
121
113
|
// delete cache
|
|
122
|
-
this.
|
|
123
|
-
await this.scope.cacheRedis.captcha.del(id);
|
|
124
|
-
});
|
|
114
|
+
await this.scope.cacheRedis.captcha.del(id);
|
|
125
115
|
return tokenSecondary === token;
|
|
126
116
|
}
|
|
127
117
|
// provider
|
|
128
118
|
const beanInstance = this._getProviderInstance(captchaData.provider);
|
|
129
119
|
const providerOptions = this._getProviderOptions(captchaData.scene, captchaData.provider);
|
|
130
120
|
// verify
|
|
121
|
+
if (!captchaData.token) return false;
|
|
131
122
|
const verified = await beanInstance.verify(captchaData.token, token, providerOptions);
|
|
132
123
|
if (!verified) {
|
|
133
|
-
//
|
|
124
|
+
// update token. not delete cache for refresh
|
|
125
|
+
captchaData = {
|
|
126
|
+
...captchaData,
|
|
127
|
+
token: undefined
|
|
128
|
+
};
|
|
129
|
+
await this.scope.cacheRedis.captcha.set(captchaData, id, {
|
|
130
|
+
ttl: providerOptions.ttl ?? this.scope.config.captchaProvider.ttl
|
|
131
|
+
});
|
|
134
132
|
return false;
|
|
135
133
|
}
|
|
136
134
|
// delete cache
|
|
137
|
-
this.
|
|
138
|
-
await this.scope.cacheRedis.captcha.del(id);
|
|
139
|
-
});
|
|
135
|
+
await this.scope.cacheRedis.captcha.del(id);
|
|
140
136
|
// ok
|
|
141
137
|
return true;
|
|
142
138
|
}
|
|
143
139
|
async verifyImmediate(id, token) {
|
|
144
140
|
let captchaData = await this.getCaptchaData(id);
|
|
145
141
|
if (!captchaData) return false;
|
|
146
|
-
|
|
147
|
-
let tokenSecondary = captchaData.token2;
|
|
148
|
-
if (tokenSecondary) return tokenSecondary; // maybe called more times
|
|
142
|
+
if (!captchaData.token) return false;
|
|
149
143
|
// provider
|
|
150
144
|
const beanInstance = this._getProviderInstance(captchaData.provider);
|
|
151
145
|
const providerOptions = this._getProviderOptions(captchaData.scene, captchaData.provider);
|
|
152
146
|
// verify
|
|
153
147
|
const verified = await beanInstance.verify(captchaData.token, token, providerOptions);
|
|
154
148
|
if (!verified) {
|
|
155
|
-
//
|
|
149
|
+
// update token. not delete cache for refresh
|
|
150
|
+
captchaData = {
|
|
151
|
+
...captchaData,
|
|
152
|
+
token: undefined
|
|
153
|
+
};
|
|
154
|
+
await this.scope.cacheRedis.captcha.set(captchaData, id, {
|
|
155
|
+
ttl: providerOptions.ttl ?? this.scope.config.captchaProvider.ttl
|
|
156
|
+
});
|
|
156
157
|
return false;
|
|
157
158
|
}
|
|
158
159
|
// tokenSecondary
|
|
159
|
-
tokenSecondary = uuidv4();
|
|
160
|
+
const tokenSecondary = uuidv4();
|
|
160
161
|
captchaData = {
|
|
161
162
|
...captchaData,
|
|
162
163
|
token: undefined,
|
|
@@ -264,7 +265,7 @@ function _initializerDefineProperty(e, i, r, l) {
|
|
|
264
265
|
var _dec$3, _dec2$3, _dec3$2, _dec4$2, _dec5$2, _dec6$2, _dec7$1, _dec8$1, _dec9$1, _dec0$1, _class$3, _class2$2, _descriptor$1, _descriptor2$1, _descriptor3, _descriptor4;
|
|
265
266
|
let DtoCaptchaData = (_dec$3 = Dto(), _dec2$3 = BeanInfo({
|
|
266
267
|
module: "a-captcha"
|
|
267
|
-
}), _dec3$2 = Api.field(), _dec4$2 = Reflect.metadata("design:type", String), _dec5$2 = Api.field(), _dec6$2 = Reflect.metadata("design:type",
|
|
268
|
+
}), _dec3$2 = Api.field(), _dec4$2 = Reflect.metadata("design:type", String), _dec5$2 = Api.field(z.string()), _dec6$2 = Reflect.metadata("design:type", Object), _dec7$1 = Api.field(v.optional()), _dec8$1 = Reflect.metadata("design:type", Object), _dec9$1 = Api.field(), _dec0$1 = Reflect.metadata("design:type", Object), _dec$3(_class$3 = _dec2$3(_class$3 = (_class2$2 = class DtoCaptchaData {
|
|
268
269
|
constructor() {
|
|
269
270
|
_initializerDefineProperty(this, "id", _descriptor$1, this);
|
|
270
271
|
_initializerDefineProperty(this, "provider", _descriptor2$1, this);
|
|
@@ -374,6 +375,13 @@ function $locale(key) {
|
|
|
374
375
|
}
|
|
375
376
|
/** scope: end */
|
|
376
377
|
|
|
378
|
+
function Verify(options) {
|
|
379
|
+
return Aspect.interceptor('a-captcha:captchaVerify', options);
|
|
380
|
+
}
|
|
381
|
+
const Captcha = {
|
|
382
|
+
verify: Verify
|
|
383
|
+
};
|
|
384
|
+
|
|
377
385
|
function CaptchaProvider(options) {
|
|
378
386
|
return createBeanDecorator('captchaProvider', options);
|
|
379
387
|
}
|
|
@@ -382,4 +390,4 @@ function CaptchaScene(options) {
|
|
|
382
390
|
return createBeanDecorator('captchaScene', options);
|
|
383
391
|
}
|
|
384
392
|
|
|
385
|
-
export { $locale, BeanCaptcha, CacheRedisCaptcha, CaptchaProvider, CaptchaScene, ControllerCaptcha, DtoCaptchaData, DtoCaptchaVerify,
|
|
393
|
+
export { $locale, BeanCaptcha, CacheRedisCaptcha, Captcha, CaptchaProvider, CaptchaScene, ControllerCaptcha, DtoCaptchaData, DtoCaptchaVerify, InterceptorCaptchaVerify, ScopeModuleACaptcha, config, locales };
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface IDecoratorCaptchaProviderOptions extends TypeOnionOptionsEnable
|
|
|
16
16
|
}
|
|
17
17
|
declare module 'vona-module-a-onion' {
|
|
18
18
|
interface BeanOnion {
|
|
19
|
-
captchaProvider: ServiceOnion<
|
|
19
|
+
captchaProvider: ServiceOnion<ICaptchaProviderRecord>;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
declare module 'vona' {
|
|
@@ -17,7 +17,7 @@ export interface IDecoratorCaptchaSceneOptions {
|
|
|
17
17
|
}
|
|
18
18
|
declare module 'vona-module-a-onion' {
|
|
19
19
|
interface BeanOnion {
|
|
20
|
-
captchaScene: ServiceOnion<
|
|
20
|
+
captchaScene: ServiceOnion<ICaptchaSceneRecord>;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
declare module 'vona' {
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Next } from 'vona';
|
|
2
|
-
import type { IDecoratorMiddlewareOptions, IMiddlewareExecute } from 'vona-module-a-aspect';
|
|
3
|
-
import type { ICaptchaSceneRecord } from '../types/captchaScene.ts';
|
|
4
|
-
import { BeanBase } from 'vona';
|
|
5
|
-
export interface IMiddlewareOptionsCaptcha extends IDecoratorMiddlewareOptions {
|
|
6
|
-
scene?: keyof ICaptchaSceneRecord;
|
|
7
|
-
bodyField?: string;
|
|
8
|
-
}
|
|
9
|
-
export declare class MiddlewareCaptcha extends BeanBase implements IMiddlewareExecute {
|
|
10
|
-
execute(options: IMiddlewareOptionsCaptcha, next: Next): Promise<any>;
|
|
11
|
-
}
|