@internetarchive/recaptcha-manager 0.1.2-alpha.1 → 1.0.0
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/.editorconfig +29 -29
- package/.github/workflows/ci.yml +27 -26
- package/.github/workflows/gh-pages-main.yml +39 -0
- package/.github/workflows/pr-preview.yml +63 -0
- package/.husky/pre-commit +1 -4
- package/.prettierignore +1 -0
- package/LICENSE +661 -661
- package/README.md +63 -85
- package/coverage/.gitignore +3 -0
- package/coverage/.placeholder +0 -0
- package/demo/app-root.ts +93 -93
- package/demo/index.html +21 -21
- package/dist/demo/app-root.d.ts +14 -14
- package/dist/demo/app-root.js +85 -85
- package/dist/demo/app-root.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/recaptcha-manager.d.ts +34 -35
- package/dist/src/recaptcha-manager.js +54 -52
- package/dist/src/recaptcha-manager.js.map +1 -1
- package/dist/src/recaptcha-widget.d.ts +38 -39
- package/dist/src/recaptcha-widget.js +95 -95
- package/dist/src/recaptcha-widget.js.map +1 -1
- package/dist/test/mock-grecaptcha.d.ts +23 -24
- package/dist/test/mock-grecaptcha.js +59 -61
- package/dist/test/mock-grecaptcha.js.map +1 -1
- package/dist/test/mock-lazy-loader.d.ts +15 -15
- package/dist/test/mock-lazy-loader.js +17 -16
- package/dist/test/mock-lazy-loader.js.map +1 -1
- package/dist/test/recaptcha-manager.test.d.ts +1 -1
- package/dist/test/recaptcha-manager.test.js +137 -137
- package/dist/test/recaptcha-manager.test.js.map +1 -1
- package/dist/vite.config.d.ts +2 -0
- package/dist/vite.config.js +25 -0
- package/dist/vite.config.js.map +1 -0
- package/eslint.config.mjs +53 -0
- package/index.ts +10 -10
- package/package.json +76 -98
- package/renovate.json +6 -0
- package/src/recaptcha-manager.ts +89 -87
- package/src/recaptcha-widget.ts +148 -148
- package/ssl/server.crt +22 -0
- package/ssl/server.key +28 -0
- package/test/mock-grecaptcha.ts +85 -87
- package/test/mock-lazy-loader.ts +39 -38
- package/test/recaptcha-manager.test.ts +151 -151
- package/tsconfig.json +31 -20
- package/vite.config.ts +25 -0
- package/web-dev-server.config.mjs +32 -28
- package/web-test-runner.config.mjs +41 -41
package/src/recaptcha-widget.ts
CHANGED
|
@@ -1,148 +1,148 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This encompasses a widget for a given site key.
|
|
3
|
-
*/
|
|
4
|
-
export interface RecaptchaWidgetInterface {
|
|
5
|
-
/** execute the recaptcha request and returns a token */
|
|
6
|
-
execute(): Promise<string>;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The combines parameters from the Recaptcha config and adds the zIndex, which
|
|
11
|
-
* allows us to control the z-index of the recaptcha widget.
|
|
12
|
-
*/
|
|
13
|
-
export type RecaptchaWidgetConfig = Pick<
|
|
14
|
-
ReCaptchaV2.Parameters,
|
|
15
|
-
'tabindex' | 'theme' | 'type' | 'size' | 'badge'
|
|
16
|
-
> & {
|
|
17
|
-
zIndex?: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* This encompasses a widget for a given site key.
|
|
22
|
-
*/
|
|
23
|
-
export class RecaptchaWidget implements RecaptchaWidgetInterface {
|
|
24
|
-
private executionSuccessBlock?: (token: string) => void;
|
|
25
|
-
|
|
26
|
-
private executionExpiredBlock?: () => void;
|
|
27
|
-
|
|
28
|
-
private executionErrorBlock?: () => void;
|
|
29
|
-
|
|
30
|
-
private grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
|
|
31
|
-
|
|
32
|
-
private siteKey: string;
|
|
33
|
-
|
|
34
|
-
private widgetId: number | null = null;
|
|
35
|
-
|
|
36
|
-
private isExecuting = false;
|
|
37
|
-
|
|
38
|
-
constructor(
|
|
39
|
-
config: {
|
|
40
|
-
siteKey: string;
|
|
41
|
-
grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
|
|
42
|
-
},
|
|
43
|
-
widgetConfig?: RecaptchaWidgetConfig
|
|
44
|
-
) {
|
|
45
|
-
this.siteKey = config.siteKey;
|
|
46
|
-
this.grecaptchaLibrary = config.grecaptchaLibrary;
|
|
47
|
-
|
|
48
|
-
const container = this.createContainer();
|
|
49
|
-
this.setup(container, widgetConfig);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** @inheritdoc */
|
|
53
|
-
async execute(): Promise<string> {
|
|
54
|
-
const { widgetId } = this;
|
|
55
|
-
|
|
56
|
-
if (widgetId === null) {
|
|
57
|
-
throw new Error('Recaptcha is not setup');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (this.isExecuting) {
|
|
61
|
-
// there is no way to know when users have dismissed a previous recaptcha
|
|
62
|
-
// so if we're still in the middle of execution when we call execute again,
|
|
63
|
-
// just reset it and execute it again
|
|
64
|
-
this.finishExecution();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.isExecuting = true;
|
|
68
|
-
|
|
69
|
-
return new Promise((resolve, reject) => {
|
|
70
|
-
this.executionSuccessBlock = (token: string): void => {
|
|
71
|
-
this.finishExecution();
|
|
72
|
-
resolve(token);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
this.executionExpiredBlock = (): void => {
|
|
76
|
-
this.finishExecution();
|
|
77
|
-
reject(new Error('expired'));
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
this.executionErrorBlock = (): void => {
|
|
81
|
-
this.finishExecution();
|
|
82
|
-
reject(new Error('error'));
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
this.grecaptchaLibrary.execute(widgetId);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private finishExecution() {
|
|
90
|
-
this.isExecuting = false;
|
|
91
|
-
const { widgetId } = this;
|
|
92
|
-
if (widgetId === null) return;
|
|
93
|
-
this.grecaptchaLibrary.reset(widgetId);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private setup(
|
|
97
|
-
container: HTMLElement,
|
|
98
|
-
widgetConfig?: ReCaptchaV2.Parameters
|
|
99
|
-
): void {
|
|
100
|
-
this.widgetId = this.grecaptchaLibrary.render(container, {
|
|
101
|
-
callback: this.responseHandler.bind(this),
|
|
102
|
-
'expired-callback': this.expiredHandler.bind(this),
|
|
103
|
-
'error-callback': this.errorHandler.bind(this),
|
|
104
|
-
sitekey: this.siteKey,
|
|
105
|
-
tabindex: widgetConfig?.tabindex,
|
|
106
|
-
theme: widgetConfig?.theme,
|
|
107
|
-
type: widgetConfig?.type,
|
|
108
|
-
size: widgetConfig?.size ?? 'invisible',
|
|
109
|
-
badge: widgetConfig?.badge,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private createContainer(zIndex?: number): HTMLElement {
|
|
114
|
-
const elementId = `recaptchaManager-${this.siteKey}`;
|
|
115
|
-
let element: HTMLElement | null = document.getElementById(elementId);
|
|
116
|
-
if (!element) {
|
|
117
|
-
element = document.createElement('div');
|
|
118
|
-
element.id = elementId;
|
|
119
|
-
element.style.position = 'fixed';
|
|
120
|
-
element.style.top = '50%';
|
|
121
|
-
element.style.left = '50%';
|
|
122
|
-
element.style.zIndex = zIndex ? `${zIndex}` : '10';
|
|
123
|
-
document.body.appendChild(element);
|
|
124
|
-
}
|
|
125
|
-
return element;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private responseHandler(response:
|
|
129
|
-
if (this.executionSuccessBlock) {
|
|
130
|
-
this.executionSuccessBlock(response);
|
|
131
|
-
this.executionSuccessBlock = undefined;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private expiredHandler(): void {
|
|
136
|
-
if (this.executionExpiredBlock) {
|
|
137
|
-
this.executionExpiredBlock();
|
|
138
|
-
this.executionExpiredBlock = undefined;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private errorHandler(): void {
|
|
143
|
-
if (this.executionErrorBlock) {
|
|
144
|
-
this.executionErrorBlock();
|
|
145
|
-
this.executionErrorBlock = undefined;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This encompasses a widget for a given site key.
|
|
3
|
+
*/
|
|
4
|
+
export interface RecaptchaWidgetInterface {
|
|
5
|
+
/** execute the recaptcha request and returns a token */
|
|
6
|
+
execute(): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The combines parameters from the Recaptcha config and adds the zIndex, which
|
|
11
|
+
* allows us to control the z-index of the recaptcha widget.
|
|
12
|
+
*/
|
|
13
|
+
export type RecaptchaWidgetConfig = Pick<
|
|
14
|
+
ReCaptchaV2.Parameters,
|
|
15
|
+
'tabindex' | 'theme' | 'type' | 'size' | 'badge'
|
|
16
|
+
> & {
|
|
17
|
+
zIndex?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This encompasses a widget for a given site key.
|
|
22
|
+
*/
|
|
23
|
+
export class RecaptchaWidget implements RecaptchaWidgetInterface {
|
|
24
|
+
private executionSuccessBlock?: (token: string) => void;
|
|
25
|
+
|
|
26
|
+
private executionExpiredBlock?: () => void;
|
|
27
|
+
|
|
28
|
+
private executionErrorBlock?: () => void;
|
|
29
|
+
|
|
30
|
+
private grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
|
|
31
|
+
|
|
32
|
+
private siteKey: string;
|
|
33
|
+
|
|
34
|
+
private widgetId: number | null = null;
|
|
35
|
+
|
|
36
|
+
private isExecuting = false;
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
config: {
|
|
40
|
+
siteKey: string;
|
|
41
|
+
grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
|
|
42
|
+
},
|
|
43
|
+
widgetConfig?: RecaptchaWidgetConfig,
|
|
44
|
+
) {
|
|
45
|
+
this.siteKey = config.siteKey;
|
|
46
|
+
this.grecaptchaLibrary = config.grecaptchaLibrary;
|
|
47
|
+
|
|
48
|
+
const container = this.createContainer();
|
|
49
|
+
this.setup(container, widgetConfig);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** @inheritdoc */
|
|
53
|
+
async execute(): Promise<string> {
|
|
54
|
+
const { widgetId } = this;
|
|
55
|
+
|
|
56
|
+
if (widgetId === null) {
|
|
57
|
+
throw new Error('Recaptcha is not setup');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.isExecuting) {
|
|
61
|
+
// there is no way to know when users have dismissed a previous recaptcha
|
|
62
|
+
// so if we're still in the middle of execution when we call execute again,
|
|
63
|
+
// just reset it and execute it again
|
|
64
|
+
this.finishExecution();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.isExecuting = true;
|
|
68
|
+
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
this.executionSuccessBlock = (token: string): void => {
|
|
71
|
+
this.finishExecution();
|
|
72
|
+
resolve(token);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
this.executionExpiredBlock = (): void => {
|
|
76
|
+
this.finishExecution();
|
|
77
|
+
reject(new Error('expired'));
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
this.executionErrorBlock = (): void => {
|
|
81
|
+
this.finishExecution();
|
|
82
|
+
reject(new Error('error'));
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
this.grecaptchaLibrary.execute(widgetId);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private finishExecution() {
|
|
90
|
+
this.isExecuting = false;
|
|
91
|
+
const { widgetId } = this;
|
|
92
|
+
if (widgetId === null) return;
|
|
93
|
+
this.grecaptchaLibrary.reset(widgetId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private setup(
|
|
97
|
+
container: HTMLElement,
|
|
98
|
+
widgetConfig?: ReCaptchaV2.Parameters,
|
|
99
|
+
): void {
|
|
100
|
+
this.widgetId = this.grecaptchaLibrary.render(container, {
|
|
101
|
+
callback: this.responseHandler.bind(this),
|
|
102
|
+
'expired-callback': this.expiredHandler.bind(this),
|
|
103
|
+
'error-callback': this.errorHandler.bind(this),
|
|
104
|
+
sitekey: this.siteKey,
|
|
105
|
+
tabindex: widgetConfig?.tabindex,
|
|
106
|
+
theme: widgetConfig?.theme,
|
|
107
|
+
type: widgetConfig?.type,
|
|
108
|
+
size: widgetConfig?.size ?? 'invisible',
|
|
109
|
+
badge: widgetConfig?.badge,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private createContainer(zIndex?: number): HTMLElement {
|
|
114
|
+
const elementId = `recaptchaManager-${this.siteKey}`;
|
|
115
|
+
let element: HTMLElement | null = document.getElementById(elementId);
|
|
116
|
+
if (!element) {
|
|
117
|
+
element = document.createElement('div');
|
|
118
|
+
element.id = elementId;
|
|
119
|
+
element.style.position = 'fixed';
|
|
120
|
+
element.style.top = '50%';
|
|
121
|
+
element.style.left = '50%';
|
|
122
|
+
element.style.zIndex = zIndex ? `${zIndex}` : '10';
|
|
123
|
+
document.body.appendChild(element);
|
|
124
|
+
}
|
|
125
|
+
return element;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private responseHandler(response: string): void {
|
|
129
|
+
if (this.executionSuccessBlock) {
|
|
130
|
+
this.executionSuccessBlock(response);
|
|
131
|
+
this.executionSuccessBlock = undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private expiredHandler(): void {
|
|
136
|
+
if (this.executionExpiredBlock) {
|
|
137
|
+
this.executionExpiredBlock();
|
|
138
|
+
this.executionExpiredBlock = undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private errorHandler(): void {
|
|
143
|
+
if (this.executionErrorBlock) {
|
|
144
|
+
this.executionErrorBlock();
|
|
145
|
+
this.executionErrorBlock = undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
package/ssl/server.crt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDszCCApugAwIBAgIUYr5csS2ntaMTww0b5QoFI0xlOpUwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh
|
|
4
|
+
bmNpc2NvMRkwFwYDVQQKDBBJbnRlcm5ldCBBcmNoaXZlMRowGAYDVQQDDBFsb2Nh
|
|
5
|
+
bC5hcmNoaXZlLm9yZzAeFw0yNTAzMDcxOTM1MzRaFw0yNTA0MDYxOTM1MzRaMGkx
|
|
6
|
+
CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj
|
|
7
|
+
bzEZMBcGA1UECgwQSW50ZXJuZXQgQXJjaGl2ZTEaMBgGA1UEAwwRbG9jYWwuYXJj
|
|
8
|
+
aGl2ZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZqbS9hNS3
|
|
9
|
+
8AtcA7Uszq7EA7RavuHc8AcpbURa6Y7NORs0SmfDD0oLptQ7DX5pSuHyOeDHzQ3U
|
|
10
|
+
XRCUDAhAD1XlaYQ6PPdiJPRAe4ACELzgDzepxVz3pdKPcfXd5/mHV3ghUZya2XW5
|
|
11
|
+
DSF1CRYUX2j10a+JORJIG4bhvTg4HxTJZZDuaNfBMC6ZSn7d9YLQoAf1MLLJm43Y
|
|
12
|
+
cj1WlOnyG4DHxNEqEk260BlbBywJH+SJA6GA0GR2bnzYZaDnZ0wqea0Zamx8ijpd
|
|
13
|
+
JxBUxYOqLfzs2KREVkkGOmsFEu82W6G3D4bKsY1UNaWXb/jcl3UkXIJJij6CdbbM
|
|
14
|
+
QkUJc8dow3sVAgMBAAGjUzBRMB0GA1UdDgQWBBSla0L0Yhpx9/DEV4uJ6OoHH92Q
|
|
15
|
+
bTAfBgNVHSMEGDAWgBSla0L0Yhpx9/DEV4uJ6OoHH92QbTAPBgNVHRMBAf8EBTAD
|
|
16
|
+
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBEzt9sgWtwjLI7AVrejDSE6F/01ng4bTni
|
|
17
|
+
0PJXa7IpwjhAApVWcjxDKp8SkDUAcZNULqBGvpPicqjnKf+wxk3xTMc7pvLqzOor
|
|
18
|
+
pm+plDUBfCEbrv1ouLDMgOtxQxbwbBUPySsLoNmDUGAGnL2zENX7qidOOmmSQEN4
|
|
19
|
+
jZuPtiEkgTqmtkfHaRX/7jhmGVfxMxj0Krlar1/cSbvwaVs4kRSjiL9/avT+AX59
|
|
20
|
+
0QoNYTLGcBP0RKia8NF2A3cgUivIMFZQDvdsiAvqY+DbC7Mnyv4Sj/ZHHwVa9+8k
|
|
21
|
+
iRU56DrOt7sgaa/oQfzWnvRtL0F5eXC3veqM4qZrXs9hHeGlgPFo
|
|
22
|
+
-----END CERTIFICATE-----
|
package/ssl/server.key
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDZqbS9hNS38Atc
|
|
3
|
+
A7Uszq7EA7RavuHc8AcpbURa6Y7NORs0SmfDD0oLptQ7DX5pSuHyOeDHzQ3UXRCU
|
|
4
|
+
DAhAD1XlaYQ6PPdiJPRAe4ACELzgDzepxVz3pdKPcfXd5/mHV3ghUZya2XW5DSF1
|
|
5
|
+
CRYUX2j10a+JORJIG4bhvTg4HxTJZZDuaNfBMC6ZSn7d9YLQoAf1MLLJm43Ycj1W
|
|
6
|
+
lOnyG4DHxNEqEk260BlbBywJH+SJA6GA0GR2bnzYZaDnZ0wqea0Zamx8ijpdJxBU
|
|
7
|
+
xYOqLfzs2KREVkkGOmsFEu82W6G3D4bKsY1UNaWXb/jcl3UkXIJJij6CdbbMQkUJ
|
|
8
|
+
c8dow3sVAgMBAAECggEANgLpITAhcuVDhFk9L3m4H1bF/dCpDmCXfl2pXR/guicm
|
|
9
|
+
C4M9HUeheaOzvVWbXThiOe/HyfylpmFTmFEmCPNlPrDAyYzQXE/MNmYO/TQ3Eihk
|
|
10
|
+
iSG68I764XKHbsG+Byoa2rW8NSaqEjniZ/7Rtkt4qasXMmdxlGgUP9bq6O45g8HV
|
|
11
|
+
kHxneFlA2KbrvmWnBi7NTea9+tp61NWiq5n97UgHacQR6KkYIpbxd7uNSnCSdmXt
|
|
12
|
+
pcwzO4ZPabJ2/DKRjePhU5OggPh+9AhJ3jsBo99GwYPgSZDh8E3vh2OWOtLBMUH3
|
|
13
|
+
rmAYwlRT2aZ5hy5yi+4QD98WoUQtsr+9n757F8V6MQKBgQDzZycdgaKwWd5d34NN
|
|
14
|
+
0TkFtPQPwxxJTCCs3I3q02uWcS3svQzBK0cWb4nISO04TnJ3MnXo83dgGhCMF+uZ
|
|
15
|
+
FCXxAA53z8F92iZo+ELlXFDFwNeNYih/afDA42tWZ6TlVsDnZ4zQgRjHS7jEF/JV
|
|
16
|
+
0ZgwGpw5725JQt64dic8wTOcDQKBgQDk7YYACQcWTnmjDhZQ3PZSX4fcTtzPZKZj
|
|
17
|
+
fa1GrXEaUH1hSyc9VmY6qJpUmXexpvtr194nXE+O5wbThOHcBjVlo2Qv+vswmUX3
|
|
18
|
+
WEcVzTVN4/fODCLCqFcMNIr+BzwZfwpT+p0u8g9FxDy1gGmvkxwIu8DCpnUT12Xj
|
|
19
|
+
hm2wO+UxKQKBgFxCSDBF9+2SUtgQJYv0dwGzwiLLWMhro6MCAoT02D3w7nBihBgg
|
|
20
|
+
GFTnuDkDc285ROfrZ4gB6MizeHwxgOrIGU2NMO62/+d9LbvyBiE76Z3bZ5i+kQ0i
|
|
21
|
+
kc/7I69fn8ASLxJHTLenh0XbbNBfJ0riJCZvn7HSEGKShysyFdNQhAhtAoGAFYVi
|
|
22
|
+
0IQIv4cXFkYPwQBUw7+pVQOw7GpI3heFf5x0goXIk6nuAW0q5R7Oi192CiRphGTh
|
|
23
|
+
xI+ABy4ezSmz1exbfreShpQwowv1sOACpsEI3s6skBlB90y+Ci6yVlk1xCvWO7jW
|
|
24
|
+
qAAngWaGUoXE6bWJsCR+ZY4ieYAJWw9bJnMrA6kCgYAzV4Xeoh5ofENZM21wKW3W
|
|
25
|
+
iCzRibPObv6Vb/j9A9yT57yzI3BdfvsX5zmuSvOJm1DimgGY9nCJUzUEYG0a1Dhh
|
|
26
|
+
/rqObPoVIFGesmvwflVYFktmVHk7ycEDVreSTz23cvmraPz1fnpdKeuEs4sRQJV7
|
|
27
|
+
iJhLoxX5SJlJc0RXMhgHGQ==
|
|
28
|
+
-----END PRIVATE KEY-----
|
package/test/mock-grecaptcha.ts
CHANGED
|
@@ -1,87 +1,85 @@
|
|
|
1
|
-
/* eslint-disable
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
callback?: (
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this
|
|
34
|
-
this
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
break;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
}
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
|
|
3
|
+
export type MockGrecaptchaMode = 'success' | 'expired' | 'error';
|
|
4
|
+
|
|
5
|
+
export class MockGrecaptcha implements ReCaptchaV2.ReCaptcha {
|
|
6
|
+
response = 'foo';
|
|
7
|
+
|
|
8
|
+
renderCalled = false;
|
|
9
|
+
|
|
10
|
+
executeCalled = false;
|
|
11
|
+
|
|
12
|
+
resetCallCount = 0;
|
|
13
|
+
|
|
14
|
+
getResponseCalled = false;
|
|
15
|
+
|
|
16
|
+
mode: MockGrecaptchaMode;
|
|
17
|
+
|
|
18
|
+
addDelay: boolean;
|
|
19
|
+
|
|
20
|
+
callback?: (response: string) => void;
|
|
21
|
+
|
|
22
|
+
'expired-callback'?: () => void;
|
|
23
|
+
|
|
24
|
+
'error-callback'?: () => void;
|
|
25
|
+
|
|
26
|
+
render(
|
|
27
|
+
container: string | HTMLElement,
|
|
28
|
+
parameters?: ReCaptchaV2.Parameters | undefined,
|
|
29
|
+
inherit?: boolean | undefined,
|
|
30
|
+
): number {
|
|
31
|
+
this.callback = parameters?.callback?.bind(this);
|
|
32
|
+
this['error-callback'] = parameters?.['error-callback']?.bind(this);
|
|
33
|
+
this['expired-callback'] = parameters?.['expired-callback']?.bind(this);
|
|
34
|
+
this.renderCalled = true;
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
reset(opt_widget_id?: number | undefined): void {
|
|
39
|
+
this.resetCallCount += 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getResponse(opt_widget_id?: number | undefined): string {
|
|
43
|
+
this.getResponseCalled = true;
|
|
44
|
+
return 'foo';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
execute(opt_widget_id?: number): void {
|
|
48
|
+
this.executeCalled = true;
|
|
49
|
+
|
|
50
|
+
if (this.addDelay) {
|
|
51
|
+
setTimeout(this.callCallback.bind(this), 100);
|
|
52
|
+
} else {
|
|
53
|
+
this.callCallback();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ready(callback: () => void): void {}
|
|
58
|
+
|
|
59
|
+
private callCallback(): void {
|
|
60
|
+
switch (this.mode) {
|
|
61
|
+
case 'success':
|
|
62
|
+
if (this.callback) {
|
|
63
|
+
this.callback('foo');
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'error':
|
|
67
|
+
if (this['error-callback']) {
|
|
68
|
+
this['error-callback']();
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'expired':
|
|
72
|
+
if (this['expired-callback']) {
|
|
73
|
+
this['expired-callback']();
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
constructor(options: { mode: MockGrecaptchaMode; addDelay?: boolean }) {
|
|
82
|
+
this.mode = options.mode;
|
|
83
|
+
this.addDelay = options.addDelay ?? false;
|
|
84
|
+
}
|
|
85
|
+
}
|
package/test/mock-lazy-loader.ts
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
-
import {
|
|
3
|
-
BundleType,
|
|
4
|
-
LazyLoaderServiceEvents,
|
|
5
|
-
LazyLoaderServiceInterface,
|
|
6
|
-
} from '@internetarchive/lazy-loader-service';
|
|
7
|
-
import { Unsubscribe } from 'nanoevents';
|
|
8
|
-
import { MockGrecaptcha } from './mock-grecaptcha';
|
|
9
|
-
|
|
10
|
-
export class MockLazyLoaderService implements LazyLoaderServiceInterface {
|
|
11
|
-
loadScriptSrc?: string;
|
|
12
|
-
|
|
13
|
-
on<E extends keyof LazyLoaderServiceEvents>(
|
|
14
|
-
event: E,
|
|
15
|
-
callback: LazyLoaderServiceEvents[E]
|
|
16
|
-
): Unsubscribe {
|
|
17
|
-
throw new Error('Method not implemented.');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async loadBundle(bundle: {
|
|
21
|
-
module?: string;
|
|
22
|
-
nomodule?: string;
|
|
23
|
-
}): Promise<void> {
|
|
24
|
-
console.debug('loadBundle', bundle);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async loadScript(options: {
|
|
28
|
-
src: string;
|
|
29
|
-
bundleType?: BundleType;
|
|
30
|
-
attributes?: Record<string, string>;
|
|
31
|
-
}): Promise<void> {
|
|
32
|
-
this.loadScriptSrc = options.src;
|
|
33
|
-
window.grecaptcha = new MockGrecaptcha({
|
|
34
|
-
mode: 'success',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import {
|
|
3
|
+
BundleType,
|
|
4
|
+
LazyLoaderServiceEvents,
|
|
5
|
+
LazyLoaderServiceInterface,
|
|
6
|
+
} from '@internetarchive/lazy-loader-service';
|
|
7
|
+
import { Unsubscribe } from 'nanoevents';
|
|
8
|
+
import { MockGrecaptcha } from './mock-grecaptcha';
|
|
9
|
+
|
|
10
|
+
export class MockLazyLoaderService implements LazyLoaderServiceInterface {
|
|
11
|
+
loadScriptSrc?: string;
|
|
12
|
+
|
|
13
|
+
on<E extends keyof LazyLoaderServiceEvents>(
|
|
14
|
+
event: E,
|
|
15
|
+
callback: LazyLoaderServiceEvents[E],
|
|
16
|
+
): Unsubscribe {
|
|
17
|
+
throw new Error('Method not implemented.');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async loadBundle(bundle: {
|
|
21
|
+
module?: string;
|
|
22
|
+
nomodule?: string;
|
|
23
|
+
}): Promise<void> {
|
|
24
|
+
console.debug('loadBundle', bundle);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async loadScript(options: {
|
|
28
|
+
src: string;
|
|
29
|
+
bundleType?: BundleType;
|
|
30
|
+
attributes?: Record<string, string>;
|
|
31
|
+
}): Promise<void> {
|
|
32
|
+
this.loadScriptSrc = options.src;
|
|
33
|
+
window.grecaptcha = new MockGrecaptcha({
|
|
34
|
+
mode: 'success',
|
|
35
|
+
});
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
(window as any).grecaptchaLoadedCallback();
|
|
38
|
+
}
|
|
39
|
+
}
|