@prosopo/client-bundle-example 2.10.23 → 2.11.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/.turbo/turbo-build$colon$cjs.log +5 -4
- package/.turbo/turbo-build$colon$tsc.log +11 -11
- package/.turbo/turbo-build.log +6 -5
- package/CHANGELOG.md +21 -0
- package/dist/cjs/index.cjs +13 -41
- package/dist/cjs/plugins/pages.cjs +113 -0
- package/dist/index.js +2 -42
- package/dist/plugins/pages.js +103 -0
- package/package.json +7 -7
- package/src/frictionless-explicit-web3.html +10 -23
- package/src/frictionless-explicit.html +18 -22
- package/src/frictionless-implicit.html +60 -86
- package/src/frictionless-manual-start.html +13 -33
- package/src/image-explicit-web3.html +8 -24
- package/src/image-explicit.html +16 -23
- package/src/image-implicit.html +192 -0
- package/src/index.html +11 -26
- package/src/index.ts +1 -62
- package/src/invisible-frictionless-explicit.html +8 -17
- package/src/invisible-frictionless-implicit.html +8 -25
- package/src/invisible-image-explicit.html +8 -23
- package/src/invisible-image-implicit.html +8 -24
- package/src/invisible-pow-explicit.html +8 -23
- package/src/invisible-pow-implicit.html +9 -21
- package/src/invisible-puzzle-explicit.html +8 -23
- package/src/invisible-puzzle-implicit.html +9 -21
- package/src/plugins/code-snippet-injector.ts +179 -0
- package/src/plugins/form-filler-injector.ts +36 -121
- package/src/plugins/layout-injector.ts +238 -0
- package/src/plugins/logo.ts +15 -0
- package/src/plugins/pages.ts +219 -0
- package/src/plugins/placement-injector.ts +114 -0
- package/src/plugins/slots.ts +32 -0
- package/src/plugins/status-log-injector.ts +35 -114
- package/src/pow-explicit-web3.html +8 -24
- package/src/pow-explicit.html +8 -23
- package/src/pow-implicit-sessionid.html +10 -24
- package/src/pow-implicit.html +9 -24
- package/src/puzzle-bind-explicit.html +83 -0
- package/src/puzzle-explicit.html +16 -23
- package/src/puzzle-implicit.html +9 -24
- package/src/styles/demo.css +803 -0
- package/src/tests/plugins.unit.test.ts +285 -118
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.config.ts +11 -5
- package/src/plugins/explanation-injector.ts +0 -294
- package/src/plugins/navigation-injector.ts +0 -605
- package/src/styles/captcha.css +0 -78
- package/src/styles/field.css +0 -12
- package/src/tests/floatLabel.unit.test.ts +0 -195
- package/src/tests/floatLabelReady.unit.test.ts +0 -36
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
|
|
5
|
-
<link href="styles/field.css" rel="stylesheet" type="text/css"/>
|
|
6
4
|
|
|
7
|
-
<
|
|
8
|
-
<link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
|
|
9
|
-
<title>Procaptcha demo: Frictionless CAPTCHA</title>
|
|
10
|
-
<script type="text/javascript">
|
|
11
|
-
window.onCaptchaFailed = function () {
|
|
12
|
-
console.log('Challenge failed');
|
|
13
|
-
updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
14
|
-
}
|
|
15
|
-
</script>
|
|
5
|
+
<title>Procaptcha demo: Frictionless, implicit rendering</title>
|
|
16
6
|
<script type="module">
|
|
17
|
-
// Function to update CAPTCHA status display is now provided by status-log-injector
|
|
18
7
|
|
|
19
8
|
window.addEventListener('load', () => {
|
|
20
|
-
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
21
9
|
|
|
22
10
|
window.setIsError = (isError) => {
|
|
23
11
|
const messageContainer = document.getElementById('messageContainer');
|
|
@@ -32,12 +20,11 @@
|
|
|
32
20
|
window.onLoggedIn = (token) => {
|
|
33
21
|
updateCaptchaStatus('Logged in, fetching private resource', 'info');
|
|
34
22
|
const url = new URL("/private", config.serverUrl).href;
|
|
35
|
-
const origin = new URL(window.location.href).origin;
|
|
36
23
|
console.log("getting private resource with token ", token, "at", url);
|
|
37
24
|
fetch(url, {
|
|
38
25
|
method: "GET",
|
|
39
26
|
headers: {
|
|
40
|
-
Origin:
|
|
27
|
+
Origin: "http://localhost:9232", // TODO: change this to env var
|
|
41
28
|
"Content-Type": "application/json",
|
|
42
29
|
Authorization: `Bearer ${token}`,
|
|
43
30
|
},
|
|
@@ -100,32 +87,34 @@
|
|
|
100
87
|
json,
|
|
101
88
|
})))
|
|
102
89
|
})
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
90
|
+
.then(async ({status, json, ok}) => {
|
|
91
|
+
console.log("status", status, "json", json.message, "ok", ok);
|
|
92
|
+
console.log("json", json)
|
|
93
|
+
try {
|
|
94
|
+
if (status !== 200) {
|
|
95
|
+
updateCaptchaStatus(`API Error: ${json.message}`, 'error');
|
|
96
|
+
setIsError(true);
|
|
97
|
+
setMessage(json.message);
|
|
98
|
+
} else {
|
|
99
|
+
updateCaptchaStatus(`API Success: ${json.message}`, 'success');
|
|
100
|
+
setIsError(false);
|
|
101
|
+
setMessage(json.message);
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.log(err);
|
|
105
|
+
updateCaptchaStatus(`Error processing response: ${err}`, 'error');
|
|
115
106
|
}
|
|
116
|
-
}
|
|
107
|
+
})
|
|
108
|
+
.catch((err) => {
|
|
117
109
|
console.log(err);
|
|
118
|
-
updateCaptchaStatus(`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
console.log(err);
|
|
123
|
-
updateCaptchaStatus(`Fetch error: ${err}`, 'error');
|
|
124
|
-
setIsError(true);
|
|
125
|
-
setMessage("Error: " + err);
|
|
126
|
-
});
|
|
110
|
+
updateCaptchaStatus(`Fetch error: ${err}`, 'error');
|
|
111
|
+
setIsError(true);
|
|
112
|
+
setMessage("Error: " + err);
|
|
113
|
+
});
|
|
127
114
|
};
|
|
128
115
|
|
|
116
|
+
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
117
|
+
|
|
129
118
|
// Monitor DOM for CAPTCHA initialization
|
|
130
119
|
const observer = new MutationObserver((mutations) => {
|
|
131
120
|
mutations.forEach((mutation) => {
|
|
@@ -146,73 +135,58 @@
|
|
|
146
135
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
147
136
|
});
|
|
148
137
|
|
|
149
|
-
|
|
138
|
+
window.onCaptchaFailed = function () {
|
|
139
|
+
console.log('Challenge failed');
|
|
140
|
+
updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
window.onCaptchaVerified = (output) => {
|
|
144
|
+
console.log('Challenge passed');
|
|
145
|
+
updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
146
|
+
updateCaptchaStatus(`Token generated: ${output.substring(0, 15)}...`, 'success');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Add custom event listener for CAPTCHA verification stages
|
|
150
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
updateCaptchaStatus('CAPTCHA script loaded and initialized', 'info');
|
|
153
|
+
updateCaptchaStatus('Waiting for user interaction...', 'info');
|
|
154
|
+
}, 500);
|
|
155
|
+
});
|
|
150
156
|
</script>
|
|
157
|
+
<script id="procaptchaScript" type="module" src="%VITE_BUNDLE_URL%" async defer></script>
|
|
151
158
|
</head>
|
|
152
159
|
<body>
|
|
153
160
|
|
|
154
|
-
<div class="
|
|
155
|
-
<h1>Frictionless CAPTCHA - Explicit Rendering</h1>
|
|
156
|
-
<p>This example demonstrates how to use Procaptcha in frictionless mode with explicit rendering.</p>
|
|
161
|
+
<div class="demo-card">
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<h2>Example Login Form</h2>
|
|
162
|
-
<div class="mui-textfield mui-textfield--float-label">
|
|
163
|
+
<form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="demo-form">
|
|
164
|
+
<h2>Create an account</h2>
|
|
165
|
+
<div class="demo-field">
|
|
163
166
|
<label for="name">Name</label>
|
|
164
167
|
<input id="name" type="text" name="name" required/>
|
|
165
168
|
</div>
|
|
166
|
-
<div class="
|
|
169
|
+
<div class="demo-field">
|
|
167
170
|
<label for="email">Email Address</label>
|
|
168
171
|
<input id="email" type="email" name="email" required/>
|
|
169
172
|
</div>
|
|
170
|
-
<div class="
|
|
173
|
+
<div class="demo-field">
|
|
171
174
|
<label for="password">Password</label>
|
|
172
175
|
<input id="password" type="password" name="password" required/>
|
|
173
176
|
</div>
|
|
174
|
-
<div class="
|
|
175
|
-
<div
|
|
177
|
+
<div class="demo-field">
|
|
178
|
+
<div
|
|
179
|
+
class="procaptcha"
|
|
180
|
+
data-theme="light"
|
|
181
|
+
data-sitekey="%PROSOPO_SITE_KEY_FRICTIONLESS%"
|
|
182
|
+
data-failed-callback="onCaptchaFailed"
|
|
183
|
+
data-callback="onCaptchaVerified"
|
|
184
|
+
></div>
|
|
176
185
|
</div>
|
|
177
186
|
<div id="messageContainer" style="display: none; color: black;"><span id="message"></span></div>
|
|
178
|
-
<button type="button" class="
|
|
187
|
+
<button type="button" class="demo-button" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
|
|
179
188
|
</form>
|
|
180
189
|
|
|
181
190
|
</div>
|
|
182
|
-
<script type="module">
|
|
183
|
-
(async () => {
|
|
184
|
-
|
|
185
|
-
const host = new URL(window.location.href).host;
|
|
186
|
-
|
|
187
|
-
// Use predefined VITE_BUNDLE_URL or default to localhost with the same host as the page, to ensure we load the
|
|
188
|
-
// bundle from the correct location in different environments
|
|
189
|
-
const bundleUrl = import.meta.env.VITE_BUNDLE_URL || 'https://localhost:9269/procaptcha.bundle.js'.replace('localhost', host);
|
|
190
|
-
|
|
191
|
-
// Pattern to avoid race condition between Procaptcha script loading and Procaptcha render function call
|
|
192
|
-
const {render} = await import(bundleUrl);
|
|
193
|
-
|
|
194
|
-
// Define a callback function to be called when the CAPTCHA is verified
|
|
195
|
-
function onCaptchaVerified(output) {
|
|
196
|
-
console.log('Challenge passed');
|
|
197
|
-
window.updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
198
|
-
window.updateCaptchaStatus(`Token generated: ${output.substring(0, 15)}...`, 'success');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const captchaContainer = document.getElementById('procaptcha-container');
|
|
202
|
-
|
|
203
|
-
// Render the CAPTCHA
|
|
204
|
-
const widgetId = render(captchaContainer, {
|
|
205
|
-
siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
|
|
206
|
-
callback: onCaptchaVerified,
|
|
207
|
-
"failed-callback": function () {
|
|
208
|
-
console.log('Challenge failed');
|
|
209
|
-
window.updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
window.updateCaptchaStatus('CAPTCHA render function called with widget ID: ' + widgetId, 'info');
|
|
214
|
-
})();
|
|
215
|
-
</script>
|
|
216
|
-
|
|
217
191
|
</body>
|
|
218
192
|
</html>
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
|
|
5
|
-
<link href="styles/field.css" rel="stylesheet" type="text/css"/>
|
|
6
4
|
|
|
7
|
-
<
|
|
8
|
-
<title>Procaptcha demo: Frictionless - Manual Start</title>
|
|
9
|
-
<link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
|
|
5
|
+
<title>Procaptcha demo: Frictionless, manual start</title>
|
|
10
6
|
<script type="module">
|
|
11
|
-
// Function to update CAPTCHA status display is now provided by status-log-injector
|
|
12
7
|
|
|
13
8
|
window.onStartCaptcha = () => {
|
|
14
9
|
updateCaptchaStatus('window.procaptcha.start() called - frictionless flow starting', 'info');
|
|
@@ -145,7 +140,6 @@
|
|
|
145
140
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
146
141
|
});
|
|
147
142
|
|
|
148
|
-
|
|
149
143
|
window.onCaptchaFailed = function () {
|
|
150
144
|
console.log('Challenge failed');
|
|
151
145
|
updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
@@ -169,34 +163,24 @@
|
|
|
169
163
|
</head>
|
|
170
164
|
<body>
|
|
171
165
|
|
|
172
|
-
<div class="
|
|
173
|
-
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
clicks the checkbox. A click that starts the flow also opens whichever challenge the provider picks,
|
|
179
|
-
so the visitor never has to click twice.
|
|
180
|
-
</p>
|
|
181
|
-
|
|
182
|
-
<!-- CAPTCHA Status Display will be injected by the status-log-injector plugin -->
|
|
183
|
-
|
|
184
|
-
<form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="mui-form">
|
|
185
|
-
<h2>Example Login Form</h2>
|
|
186
|
-
<div class="mui-textfield mui-textfield--float-label">
|
|
166
|
+
<div class="demo-card">
|
|
167
|
+
|
|
168
|
+
<form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="demo-form">
|
|
169
|
+
<h2>Create an account</h2>
|
|
170
|
+
<p class="demo-note">Nothing runs until you tick the box or press <strong>Start CAPTCHA now</strong>, which calls <code>window.procaptcha.start()</code>.</p>
|
|
171
|
+
<div class="demo-field">
|
|
187
172
|
<label for="name">Name</label>
|
|
188
173
|
<input id="name" type="text" name="name" required/>
|
|
189
174
|
</div>
|
|
190
|
-
<div class="
|
|
175
|
+
<div class="demo-field">
|
|
191
176
|
<label for="email">Email Address</label>
|
|
192
177
|
<input id="email" type="email" name="email" required/>
|
|
193
178
|
</div>
|
|
194
|
-
<div class="
|
|
179
|
+
<div class="demo-field">
|
|
195
180
|
<label for="password">Password</label>
|
|
196
181
|
<input id="password" type="password" name="password" required/>
|
|
197
182
|
</div>
|
|
198
|
-
<div class="
|
|
199
|
-
<!-- Dev sitekey -->
|
|
183
|
+
<div class="demo-field">
|
|
200
184
|
<div
|
|
201
185
|
class="procaptcha"
|
|
202
186
|
data-theme="light"
|
|
@@ -206,19 +190,15 @@
|
|
|
206
190
|
data-callback="onCaptchaVerified"
|
|
207
191
|
></div>
|
|
208
192
|
</div>
|
|
209
|
-
<div class="
|
|
210
|
-
<button type="button" class="
|
|
193
|
+
<div class="demo-field">
|
|
194
|
+
<button type="button" class="demo-button demo-button--secondary" onclick="onStartCaptcha()" data-cy="start-captcha-button">
|
|
211
195
|
Start CAPTCHA now
|
|
212
196
|
</button>
|
|
213
197
|
</div>
|
|
214
198
|
<div id="messageContainer" style="display: none; color: black;"><span id="message"></span></div>
|
|
215
|
-
<button type="button" class="
|
|
199
|
+
<button type="button" class="demo-button" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
|
|
216
200
|
</form>
|
|
217
201
|
|
|
218
|
-
<!-- Console output display area -->
|
|
219
|
-
<div id="console-output" class="console-output" style="display: none;"></div>
|
|
220
|
-
|
|
221
|
-
<!-- Explanation will be injected by the explanation-injector plugin -->
|
|
222
202
|
</div>
|
|
223
203
|
</body>
|
|
224
204
|
</html>
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
|
|
5
|
-
<link href="styles/field.css" rel="stylesheet" type="text/css"/>
|
|
6
4
|
|
|
7
|
-
<
|
|
8
|
-
<title>Procaptcha Image Mode - Explicit Rendering</title>
|
|
9
|
-
<link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
|
|
5
|
+
<title>Procaptcha demo: Image, explicit rendering, web3</title>
|
|
10
6
|
<script type="module">
|
|
11
|
-
// Function to update CAPTCHA status display is now provided by status-log-injector
|
|
12
7
|
|
|
13
8
|
document.addEventListener('DOMContentLoaded', function() {
|
|
14
9
|
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
@@ -33,43 +28,33 @@
|
|
|
33
28
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
34
29
|
});
|
|
35
30
|
|
|
36
|
-
// updateCaptchaStatus is now provided by status-log-injector
|
|
37
31
|
</script>
|
|
38
32
|
</head>
|
|
39
33
|
<body>
|
|
40
|
-
<div class="
|
|
41
|
-
<h1>Procaptcha Image Mode - Explicit Rendering</h1>
|
|
42
|
-
<p>This example demonstrates how to use Procaptcha in image mode with explicit rendering.</p>
|
|
34
|
+
<div class="demo-card">
|
|
43
35
|
|
|
44
|
-
|
|
36
|
+
<form id="demo-form" class="demo-form">
|
|
37
|
+
<h2>Create an account</h2>
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
<h2>Example Form</h2>
|
|
48
|
-
|
|
49
|
-
<div class="mui-textfield mui-textfield--float-label">
|
|
39
|
+
<div class="demo-field">
|
|
50
40
|
<label for="name">Name</label>
|
|
51
41
|
<input type="text" id="name" name="name" required />
|
|
52
42
|
</div>
|
|
53
43
|
|
|
54
|
-
<div class="
|
|
44
|
+
<div class="demo-field">
|
|
55
45
|
<label for="email">Email</label>
|
|
56
46
|
<input type="email" id="email" name="email" required />
|
|
57
47
|
</div>
|
|
58
48
|
|
|
59
|
-
<!-- The container for the CAPTCHA -->
|
|
60
49
|
<div id="procaptcha-container"></div>
|
|
61
50
|
|
|
62
|
-
<button type="submit" class="
|
|
51
|
+
<button type="submit" class="demo-button">Submit</button>
|
|
63
52
|
|
|
64
53
|
<div id="error"></div>
|
|
65
54
|
</form>
|
|
66
55
|
|
|
67
|
-
<div id="result" class="
|
|
68
|
-
|
|
69
|
-
<!-- Console output display area -->
|
|
70
|
-
<div id="console-output" class="console-output" style="display: none;"></div>
|
|
56
|
+
<div id="result" class="demo-result" style="display: none;"></div>
|
|
71
57
|
|
|
72
|
-
<!-- Explanation will be injected by the explanation-injector plugin -->
|
|
73
58
|
</div>
|
|
74
59
|
|
|
75
60
|
<script type="module">
|
|
@@ -141,7 +126,6 @@
|
|
|
141
126
|
// render a modal and get the user to select 1 account
|
|
142
127
|
const accountSelect = document.createElement('select');
|
|
143
128
|
accountSelect.id = 'account-select';
|
|
144
|
-
accountSelect.classList.add('mui-select');
|
|
145
129
|
accountSelect.classList.add('account-select');
|
|
146
130
|
accounts.forEach((account) => {
|
|
147
131
|
const option = document.createElement('option');
|
package/src/image-explicit.html
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
|
|
5
|
-
<link href="styles/field.css" rel="stylesheet" type="text/css"/>
|
|
6
4
|
|
|
7
|
-
<
|
|
8
|
-
<title>Procaptcha Image Mode - Explicit Rendering</title>
|
|
9
|
-
<link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
|
|
5
|
+
<title>Procaptcha demo: Image, explicit rendering</title>
|
|
10
6
|
<script type="module">
|
|
11
|
-
// Function to update CAPTCHA status display is now provided by status-log-injector
|
|
12
7
|
|
|
13
8
|
document.addEventListener('DOMContentLoaded', function() {
|
|
14
9
|
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
@@ -33,43 +28,33 @@
|
|
|
33
28
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
34
29
|
});
|
|
35
30
|
|
|
36
|
-
// updateCaptchaStatus is now provided by status-log-injector
|
|
37
31
|
</script>
|
|
38
32
|
</head>
|
|
39
33
|
<body>
|
|
40
|
-
<div class="
|
|
41
|
-
<h1>Procaptcha Image Mode - Explicit Rendering</h1>
|
|
42
|
-
<p>This example demonstrates how to use Procaptcha in image mode with explicit rendering.</p>
|
|
34
|
+
<div class="demo-card">
|
|
43
35
|
|
|
44
|
-
|
|
36
|
+
<form id="demo-form" class="demo-form">
|
|
37
|
+
<h2>Create an account</h2>
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
<h2>Example Form</h2>
|
|
48
|
-
|
|
49
|
-
<div class="mui-textfield mui-textfield--float-label">
|
|
39
|
+
<div class="demo-field">
|
|
50
40
|
<label for="name">Name</label>
|
|
51
41
|
<input type="text" id="name" name="name" required />
|
|
52
42
|
</div>
|
|
53
43
|
|
|
54
|
-
<div class="
|
|
44
|
+
<div class="demo-field">
|
|
55
45
|
<label for="email">Email</label>
|
|
56
46
|
<input type="email" id="email" name="email" required />
|
|
57
47
|
</div>
|
|
58
48
|
|
|
59
|
-
<!-- The container for the CAPTCHA -->
|
|
60
49
|
<div id="procaptcha-container"></div>
|
|
61
50
|
|
|
62
|
-
<button type="submit" class="
|
|
51
|
+
<button type="submit" class="demo-button">Submit</button>
|
|
63
52
|
|
|
64
53
|
<div id="error"></div>
|
|
65
54
|
</form>
|
|
66
55
|
|
|
67
|
-
<div id="result" class="
|
|
68
|
-
|
|
69
|
-
<!-- Console output display area -->
|
|
70
|
-
<div id="console-output" class="console-output" style="display: none;"></div>
|
|
56
|
+
<div id="result" class="demo-result" style="display: none;"></div>
|
|
71
57
|
|
|
72
|
-
<!-- Explanation will be injected by the explanation-injector plugin -->
|
|
73
58
|
</div>
|
|
74
59
|
|
|
75
60
|
<script type="module">
|
|
@@ -135,8 +120,16 @@
|
|
|
135
120
|
window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
|
|
136
121
|
|
|
137
122
|
// Render the CAPTCHA
|
|
123
|
+
// ?placement=float anchors the challenge to the widget; the default is popup.
|
|
124
|
+
const placement =
|
|
125
|
+
new URLSearchParams(window.location.search).get("placement") === "float"
|
|
126
|
+
? "float"
|
|
127
|
+
: "popup";
|
|
128
|
+
window.updateCaptchaStatus('Challenge placement: ' + placement, 'info');
|
|
129
|
+
|
|
138
130
|
const widgetId = render(document.getElementById('procaptcha-container'), {
|
|
139
131
|
siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
|
|
132
|
+
placement,
|
|
140
133
|
callback: handleCaptchaResponse,
|
|
141
134
|
"failed-callback": handleCaptchaFailed
|
|
142
135
|
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<title>Procaptcha demo: Image, implicit rendering</title>
|
|
6
|
+
<script type="module">
|
|
7
|
+
|
|
8
|
+
window.addEventListener('load', () => {
|
|
9
|
+
|
|
10
|
+
window.setIsError = (isError) => {
|
|
11
|
+
const messageContainer = document.getElementById('messageContainer');
|
|
12
|
+
messageContainer.style.color = isError ? 'red' : 'black';
|
|
13
|
+
messageContainer.style.display = 'block';
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
window.setMessage = (message) => {
|
|
17
|
+
document.getElementById('message').innerText = message;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
window.onLoggedIn = (token) => {
|
|
21
|
+
updateCaptchaStatus('Logged in, fetching private resource', 'info');
|
|
22
|
+
const url = new URL("/private", config.serverUrl).href;
|
|
23
|
+
console.log("getting private resource with token ", token, "at", url);
|
|
24
|
+
fetch(url, {
|
|
25
|
+
method: "GET",
|
|
26
|
+
headers: {
|
|
27
|
+
Origin: "http://localhost:9232", // TODO: change this to env var
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
Authorization: `Bearer ${token}`,
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
.then(async (res) => {
|
|
33
|
+
try {
|
|
34
|
+
const jsonRes = await res.json();
|
|
35
|
+
if (res.status === 200) {
|
|
36
|
+
updateCaptchaStatus(`Successfully accessed private resource`, 'success');
|
|
37
|
+
setMessage(jsonRes.message);
|
|
38
|
+
} else {
|
|
39
|
+
updateCaptchaStatus(`Failed to access private resource: ${res.status}`, 'error');
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.log(err);
|
|
43
|
+
updateCaptchaStatus(`Error parsing response: ${err}`, 'error');
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.catch((err) => {
|
|
47
|
+
console.log(err);
|
|
48
|
+
updateCaptchaStatus(`Fetch error: ${err}`, 'error');
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
window.onActionHandler = () => {
|
|
53
|
+
updateCaptchaStatus('Form submission initiated', 'info');
|
|
54
|
+
|
|
55
|
+
const procaptchaElements = document.getElementsByName('procaptcha-response');
|
|
56
|
+
|
|
57
|
+
if (!procaptchaElements.length) {
|
|
58
|
+
updateCaptchaStatus('Error: No CAPTCHA response found', 'error');
|
|
59
|
+
alert("Must complete captcha");
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const procaptchaToken = procaptchaElements[0].value;
|
|
64
|
+
updateCaptchaStatus(`Token received: ${procaptchaToken.substring(0, 15)}...`, 'success');
|
|
65
|
+
|
|
66
|
+
const payload = {
|
|
67
|
+
email: document.getElementById('email').value,
|
|
68
|
+
name: document.getElementById('name').value,
|
|
69
|
+
password: document.getElementById('password').value,
|
|
70
|
+
siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
|
|
71
|
+
"procaptcha-response": procaptchaToken,
|
|
72
|
+
};
|
|
73
|
+
const url = new URL('signup', import.meta.env.PROSOPO_SERVER_URL).href;
|
|
74
|
+
console.log("posting to", url, "with payload", payload);
|
|
75
|
+
fetch(url, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify(payload),
|
|
81
|
+
contentType: "application/json",
|
|
82
|
+
}).then((response) => {
|
|
83
|
+
return new Promise((resolve) => response.json()
|
|
84
|
+
.then((json) => resolve({
|
|
85
|
+
status: response.status,
|
|
86
|
+
ok: response.ok,
|
|
87
|
+
json,
|
|
88
|
+
})))
|
|
89
|
+
})
|
|
90
|
+
.then(async ({status, json, ok}) => {
|
|
91
|
+
console.log("status", status, "json", json.message, "ok", ok);
|
|
92
|
+
console.log("json", json)
|
|
93
|
+
try {
|
|
94
|
+
if (status !== 200) {
|
|
95
|
+
updateCaptchaStatus(`API Error: ${json.message}`, 'error');
|
|
96
|
+
setIsError(true);
|
|
97
|
+
setMessage(json.message);
|
|
98
|
+
} else {
|
|
99
|
+
updateCaptchaStatus(`API Success: ${json.message}`, 'success');
|
|
100
|
+
setIsError(false);
|
|
101
|
+
setMessage(json.message);
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.log(err);
|
|
105
|
+
updateCaptchaStatus(`Error processing response: ${err}`, 'error');
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.catch((err) => {
|
|
109
|
+
console.log(err);
|
|
110
|
+
updateCaptchaStatus(`Fetch error: ${err}`, 'error');
|
|
111
|
+
setIsError(true);
|
|
112
|
+
setMessage("Error: " + err);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
117
|
+
|
|
118
|
+
// Monitor DOM for CAPTCHA initialization
|
|
119
|
+
const observer = new MutationObserver((mutations) => {
|
|
120
|
+
mutations.forEach((mutation) => {
|
|
121
|
+
if (mutation.addedNodes.length) {
|
|
122
|
+
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
123
|
+
const node = mutation.addedNodes[i];
|
|
124
|
+
if (node.classList && (node.classList.contains('procaptcha') ||
|
|
125
|
+
node.querySelector && node.querySelector('.procaptcha'))) {
|
|
126
|
+
updateCaptchaStatus('CAPTCHA DOM elements initialized', 'info');
|
|
127
|
+
observer.disconnect();
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
window.onCaptchaFailed = function () {
|
|
139
|
+
console.log('Challenge failed');
|
|
140
|
+
updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
window.onCaptchaVerified = (output) => {
|
|
144
|
+
console.log('Challenge passed');
|
|
145
|
+
updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
146
|
+
updateCaptchaStatus(`Token generated: ${output.substring(0, 15)}...`, 'success');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Add custom event listener for CAPTCHA verification stages
|
|
150
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
updateCaptchaStatus('CAPTCHA script loaded and initialized', 'info');
|
|
153
|
+
updateCaptchaStatus('Waiting for user interaction...', 'info');
|
|
154
|
+
}, 500);
|
|
155
|
+
});
|
|
156
|
+
</script>
|
|
157
|
+
<script id="procaptchaScript" type="module" src="%VITE_BUNDLE_URL%" async defer></script>
|
|
158
|
+
</head>
|
|
159
|
+
<body>
|
|
160
|
+
|
|
161
|
+
<div class="demo-card">
|
|
162
|
+
|
|
163
|
+
<form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="demo-form">
|
|
164
|
+
<h2>Create an account</h2>
|
|
165
|
+
<div class="demo-field">
|
|
166
|
+
<label for="name">Name</label>
|
|
167
|
+
<input id="name" type="text" name="name" required/>
|
|
168
|
+
</div>
|
|
169
|
+
<div class="demo-field">
|
|
170
|
+
<label for="email">Email Address</label>
|
|
171
|
+
<input id="email" type="email" name="email" required/>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="demo-field">
|
|
174
|
+
<label for="password">Password</label>
|
|
175
|
+
<input id="password" type="password" name="password" required/>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="demo-field">
|
|
178
|
+
<div
|
|
179
|
+
class="procaptcha"
|
|
180
|
+
data-theme="light"
|
|
181
|
+
data-sitekey="%PROSOPO_SITE_KEY_IMAGE%"
|
|
182
|
+
data-failed-callback="onCaptchaFailed"
|
|
183
|
+
data-callback="onCaptchaVerified"
|
|
184
|
+
></div>
|
|
185
|
+
</div>
|
|
186
|
+
<div id="messageContainer" style="display: none; color: black;"><span id="message"></span></div>
|
|
187
|
+
<button type="button" class="demo-button" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
|
|
188
|
+
</form>
|
|
189
|
+
|
|
190
|
+
</div>
|
|
191
|
+
</body>
|
|
192
|
+
</html>
|