@prosopo/client-bundle-example 2.11.2 → 2.11.4
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 +4 -7
- package/.turbo/turbo-build$colon$tsc.log +11 -14
- package/.turbo/turbo-build.log +4 -10
- package/CHANGELOG.md +32 -0
- package/LICENSE +201 -0
- package/README.md +6 -6
- package/dist/cjs/plugins/pages.cjs +7 -0
- package/dist/plugins/pages.js +7 -0
- package/env.staging +5 -4
- package/package.json +52 -53
- package/vite.config.ts +50 -1
- package/env.development +0 -7
- package/env.production +0 -6
- package/src/assets/dummy.txt +0 -0
- package/src/frictionless-explicit-web3.html +0 -236
- package/src/frictionless-explicit.html +0 -204
- package/src/frictionless-implicit.html +0 -192
- package/src/frictionless-manual-start.html +0 -204
- package/src/image-explicit-web3.html +0 -182
- package/src/image-explicit.html +0 -151
- package/src/image-implicit.html +0 -192
- package/src/index.html +0 -192
- package/src/index.ts +0 -15
- package/src/invisible-frictionless-explicit.html +0 -123
- package/src/invisible-frictionless-implicit.html +0 -187
- package/src/invisible-image-explicit.html +0 -146
- package/src/invisible-image-implicit.html +0 -187
- package/src/invisible-pow-explicit.html +0 -146
- package/src/invisible-pow-implicit.html +0 -94
- package/src/invisible-puzzle-explicit.html +0 -145
- package/src/invisible-puzzle-implicit.html +0 -94
- package/src/plugins/code-snippet-injector.ts +0 -179
- package/src/plugins/form-filler-injector.ts +0 -148
- package/src/plugins/layout-injector.ts +0 -256
- package/src/plugins/logo.ts +0 -15
- package/src/plugins/pages.ts +0 -219
- package/src/plugins/placement-injector.ts +0 -114
- package/src/plugins/slots.ts +0 -32
- package/src/plugins/status-log-injector.ts +0 -143
- package/src/pow-explicit-web3.html +0 -179
- package/src/pow-explicit.html +0 -143
- package/src/pow-implicit-sessionid.html +0 -209
- package/src/pow-implicit.html +0 -192
- package/src/puzzle-bind-explicit.html +0 -83
- package/src/puzzle-explicit.html +0 -151
- package/src/puzzle-implicit.html +0 -192
- package/src/styles/demo.css +0 -803
- package/src/tests/plugins.unit.test.ts +0 -490
- package/tsconfig.cjs.json +0 -25
- package/tsconfig.json +0 -31
- package/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.types.json +0 -9
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
<title>Procaptcha demo: Proof of Work, invisible, implicit rendering</title>
|
|
6
|
-
<script type="module">
|
|
7
|
-
|
|
8
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
9
|
-
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
10
|
-
|
|
11
|
-
// Monitor DOM for CAPTCHA initialization
|
|
12
|
-
const observer = new MutationObserver((mutations) => {
|
|
13
|
-
mutations.forEach((mutation) => {
|
|
14
|
-
if (mutation.addedNodes.length) {
|
|
15
|
-
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
16
|
-
const node = mutation.addedNodes[i];
|
|
17
|
-
if (node.classList && (node.classList.contains('procaptcha') ||
|
|
18
|
-
node.querySelector && node.querySelector('.procaptcha'))) {
|
|
19
|
-
updateCaptchaStatus('CAPTCHA DOM elements initialized', 'info');
|
|
20
|
-
observer.disconnect();
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Create a method to show CAPTCHA execution events
|
|
32
|
-
document.addEventListener('procaptcha:execute', function(e) {
|
|
33
|
-
updateCaptchaStatus(`CAPTCHA execution started: type=pow, mode=invisible`, 'info');
|
|
34
|
-
updateCaptchaStatus(`Container: ${e.detail.containerId}, timestamp: ${new Date(e.detail.timestamp).toLocaleTimeString()}`, 'info');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
window.onSubmit = function(token) {
|
|
38
|
-
console.log('Procaptcha verified, token: ' + token);
|
|
39
|
-
updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
40
|
-
updateCaptchaStatus(`Token generated: ${token.substring(0, 15)}...`, 'success');
|
|
41
|
-
|
|
42
|
-
// Get form values
|
|
43
|
-
const name = document.getElementById('name').value;
|
|
44
|
-
const email = document.getElementById('email').value;
|
|
45
|
-
|
|
46
|
-
const resultElement = document.getElementById('result');
|
|
47
|
-
if (resultElement) {
|
|
48
|
-
resultElement.innerHTML = `<strong>Form submitted with:</strong><br>
|
|
49
|
-
- Name: ${name}<br>
|
|
50
|
-
- Email: ${email}<br>
|
|
51
|
-
- Procaptcha verified: Yes`;
|
|
52
|
-
resultElement.style.display = 'block';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
updateCaptchaStatus('Form submission completed', 'success');
|
|
56
|
-
|
|
57
|
-
// Prevent actual form submission
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
</script>
|
|
61
|
-
<!-- Load the Procaptcha script -->
|
|
62
|
-
<script type="module" src="%VITE_BUNDLE_URL%" async defer></script>
|
|
63
|
-
</head>
|
|
64
|
-
<body>
|
|
65
|
-
<div class="demo-card">
|
|
66
|
-
|
|
67
|
-
<!-- nosemgrep: python.django.security.django-no-csrf-token.django-no-csrf-token -->
|
|
68
|
-
<form id="demo-form" action="javascript:void(0);" method="POST" class="demo-form">
|
|
69
|
-
<h2>Create an account</h2>
|
|
70
|
-
<div class="demo-field">
|
|
71
|
-
<label for="name">Name</label>
|
|
72
|
-
<input type="text" id="name" name="name" required />
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
<div class="demo-field">
|
|
76
|
-
<label for="email">Email</label>
|
|
77
|
-
<input type="email" id="email" name="email" required />
|
|
78
|
-
</div>
|
|
79
|
-
|
|
80
|
-
<!-- Submit button with Procaptcha attributes -->
|
|
81
|
-
<button
|
|
82
|
-
class="demo-button procaptcha"
|
|
83
|
-
data-sitekey="%PROSOPO_SITE_KEY_POW%"
|
|
84
|
-
data-callback="onSubmit"
|
|
85
|
-
data-size="invisible">
|
|
86
|
-
Submit
|
|
87
|
-
</button>
|
|
88
|
-
</form>
|
|
89
|
-
|
|
90
|
-
<div id="result" class="demo-result" style="display: none;"></div>
|
|
91
|
-
|
|
92
|
-
</div>
|
|
93
|
-
</body>
|
|
94
|
-
</html>
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
<title>Procaptcha demo: Puzzle, invisible, explicit rendering</title>
|
|
6
|
-
<script type="module">
|
|
7
|
-
|
|
8
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
9
|
-
|
|
10
|
-
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
11
|
-
|
|
12
|
-
// Monitor DOM for CAPTCHA initialization
|
|
13
|
-
const observer = new MutationObserver((mutations) => {
|
|
14
|
-
mutations.forEach((mutation) => {
|
|
15
|
-
if (mutation.addedNodes.length) {
|
|
16
|
-
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
17
|
-
const node = mutation.addedNodes[i];
|
|
18
|
-
if (node.classList && (node.classList.contains('procaptcha') ||
|
|
19
|
-
node.querySelector && node.querySelector('.procaptcha'))) {
|
|
20
|
-
updateCaptchaStatus('CAPTCHA DOM elements initialized', 'info');
|
|
21
|
-
observer.disconnect();
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
</script>
|
|
33
|
-
</head>
|
|
34
|
-
<body>
|
|
35
|
-
<div class="demo-card">
|
|
36
|
-
|
|
37
|
-
<form id="demo-form" class="demo-form">
|
|
38
|
-
<h2>Create an account</h2>
|
|
39
|
-
|
|
40
|
-
<div class="demo-field">
|
|
41
|
-
<label for="name">Name</label>
|
|
42
|
-
<input type="text" id="name" name="name" required />
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<div class="demo-field">
|
|
46
|
-
<label for="email">Email</label>
|
|
47
|
-
<input type="email" id="email" name="email" required />
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<div id="procaptcha-container"></div>
|
|
51
|
-
|
|
52
|
-
<button type="submit" class="demo-button">Submit</button>
|
|
53
|
-
|
|
54
|
-
<div id="error"></div>
|
|
55
|
-
</form>
|
|
56
|
-
|
|
57
|
-
<div id="result" class="demo-result" style="display: none;"></div>
|
|
58
|
-
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<script type="module">
|
|
62
|
-
import { render, execute } from "%VITE_BUNDLE_URL%"
|
|
63
|
-
|
|
64
|
-
// Form validation function
|
|
65
|
-
function validateForm() {
|
|
66
|
-
const nameInput = document.getElementById('name');
|
|
67
|
-
const emailInput = document.getElementById('email');
|
|
68
|
-
const errorDisplay = document.getElementById('error');
|
|
69
|
-
|
|
70
|
-
if (!nameInput.value || !emailInput.value) {
|
|
71
|
-
errorDisplay.textContent = 'Please fill out all fields';
|
|
72
|
-
errorDisplay.style.display = 'block';
|
|
73
|
-
window.updateCaptchaStatus('Form validation failed: Empty fields', 'error');
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Basic email validation
|
|
78
|
-
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
79
|
-
if (!emailPattern.test(emailInput.value)) {
|
|
80
|
-
errorDisplay.textContent = 'Please enter a valid email address';
|
|
81
|
-
errorDisplay.style.display = 'block';
|
|
82
|
-
window.updateCaptchaStatus('Form validation failed: Invalid email format', 'error');
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
errorDisplay.style.display = 'none';
|
|
87
|
-
window.updateCaptchaStatus('Form validation passed', 'info');
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Callback for successful CAPTCHA verification
|
|
92
|
-
function handleCaptchaResponse(token) {
|
|
93
|
-
console.log('Procaptcha verified, token:', token);
|
|
94
|
-
window.updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
95
|
-
window.updateCaptchaStatus(`Token generated: ${token.substring(0, 15)}...`, 'success');
|
|
96
|
-
|
|
97
|
-
const name = document.getElementById('name').value;
|
|
98
|
-
const email = document.getElementById('email').value;
|
|
99
|
-
|
|
100
|
-
// Display result. textContent (not innerHTML) — user-typed values
|
|
101
|
-
// must not be interpreted as HTML; whitespace preserved via CSS.
|
|
102
|
-
const resultElement = document.getElementById('result');
|
|
103
|
-
resultElement.textContent = `Form submitted with:\n- Name: ${name}\n- Email: ${email}\n- Procaptcha verified: Yes`;
|
|
104
|
-
resultElement.style.whiteSpace = 'pre-wrap';
|
|
105
|
-
resultElement.style.display = 'block';
|
|
106
|
-
|
|
107
|
-
window.updateCaptchaStatus('Form submission completed', 'success');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Callback for failed CAPTCHA verification
|
|
111
|
-
function handleCaptchaFailed() {
|
|
112
|
-
console.log('Captcha verification failed');
|
|
113
|
-
window.updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
|
|
114
|
-
document.getElementById('error').textContent = 'CAPTCHA verification failed. Please try again.';
|
|
115
|
-
document.getElementById('error').style.display = 'block';
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Wait for DOM content to be loaded
|
|
119
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
120
|
-
window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
|
|
121
|
-
|
|
122
|
-
// Render the CAPTCHA
|
|
123
|
-
const widgetId = render(document.getElementById('procaptcha-container'), {
|
|
124
|
-
siteKey: import.meta.env.PROSOPO_SITE_KEY_PUZZLE,
|
|
125
|
-
callback: handleCaptchaResponse,
|
|
126
|
-
"failed-callback": handleCaptchaFailed,
|
|
127
|
-
size: "invisible"
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
window.updateCaptchaStatus('CAPTCHA render function called with widget ID: ' + widgetId, 'info');
|
|
131
|
-
|
|
132
|
-
// Add form submit handler
|
|
133
|
-
document.getElementById('demo-form').addEventListener('submit', function(e) {
|
|
134
|
-
e.preventDefault();
|
|
135
|
-
window.updateCaptchaStatus('Form submission attempted', 'info');
|
|
136
|
-
if (validateForm()) {
|
|
137
|
-
// Form is valid, CAPTCHA verification will be handled by the callback
|
|
138
|
-
window.updateCaptchaStatus('Waiting for CAPTCHA verification', 'info');
|
|
139
|
-
execute();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
</script>
|
|
144
|
-
</body>
|
|
145
|
-
</html>
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
<title>Procaptcha demo: Puzzle, invisible, implicit rendering</title>
|
|
6
|
-
<script type="module">
|
|
7
|
-
|
|
8
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
9
|
-
updateCaptchaStatus('Page loaded - Initializing CAPTCHA system', 'info');
|
|
10
|
-
|
|
11
|
-
// Monitor DOM for CAPTCHA initialization
|
|
12
|
-
const observer = new MutationObserver((mutations) => {
|
|
13
|
-
mutations.forEach((mutation) => {
|
|
14
|
-
if (mutation.addedNodes.length) {
|
|
15
|
-
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
16
|
-
const node = mutation.addedNodes[i];
|
|
17
|
-
if (node.classList && (node.classList.contains('procaptcha') ||
|
|
18
|
-
node.querySelector && node.querySelector('.procaptcha'))) {
|
|
19
|
-
updateCaptchaStatus('CAPTCHA DOM elements initialized', 'info');
|
|
20
|
-
observer.disconnect();
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Create a method to show CAPTCHA execution events
|
|
32
|
-
document.addEventListener('procaptcha:execute', function(e) {
|
|
33
|
-
updateCaptchaStatus(`CAPTCHA execution started: type=puzzle, mode=invisible`, 'info');
|
|
34
|
-
updateCaptchaStatus(`Container: ${e.detail.containerId}, timestamp: ${new Date(e.detail.timestamp).toLocaleTimeString()}`, 'info');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
window.onSubmit = function(token) {
|
|
38
|
-
console.log('Procaptcha verified, token: ' + token);
|
|
39
|
-
updateCaptchaStatus('Challenge passed successfully!', 'success');
|
|
40
|
-
updateCaptchaStatus(`Token generated: ${token.substring(0, 15)}...`, 'success');
|
|
41
|
-
|
|
42
|
-
// Get form values
|
|
43
|
-
const name = document.getElementById('name').value;
|
|
44
|
-
const email = document.getElementById('email').value;
|
|
45
|
-
|
|
46
|
-
const resultElement = document.getElementById('result');
|
|
47
|
-
if (resultElement) {
|
|
48
|
-
// textContent (not innerHTML) — user-typed values must not be
|
|
49
|
-
// interpreted as HTML; whitespace preserved via CSS below.
|
|
50
|
-
resultElement.textContent = `Form submitted with:\n- Name: ${name}\n- Email: ${email}\n- Procaptcha verified: Yes`;
|
|
51
|
-
resultElement.style.whiteSpace = 'pre-wrap';
|
|
52
|
-
resultElement.style.display = 'block';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
updateCaptchaStatus('Form submission completed', 'success');
|
|
56
|
-
|
|
57
|
-
// Prevent actual form submission
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
</script>
|
|
61
|
-
<!-- Load the Procaptcha script -->
|
|
62
|
-
<script type="module" src="%VITE_BUNDLE_URL%" async defer></script>
|
|
63
|
-
</head>
|
|
64
|
-
<body>
|
|
65
|
-
<div class="demo-card">
|
|
66
|
-
|
|
67
|
-
<!-- nosemgrep: python.django.security.django-no-csrf-token.django-no-csrf-token -->
|
|
68
|
-
<form id="demo-form" action="javascript:void(0);" method="POST" class="demo-form">
|
|
69
|
-
<h2>Create an account</h2>
|
|
70
|
-
<div class="demo-field">
|
|
71
|
-
<label for="name">Name</label>
|
|
72
|
-
<input type="text" id="name" name="name" required />
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
<div class="demo-field">
|
|
76
|
-
<label for="email">Email</label>
|
|
77
|
-
<input type="email" id="email" name="email" required />
|
|
78
|
-
</div>
|
|
79
|
-
|
|
80
|
-
<!-- Submit button with Procaptcha attributes -->
|
|
81
|
-
<button
|
|
82
|
-
class="demo-button procaptcha"
|
|
83
|
-
data-sitekey="%PROSOPO_SITE_KEY_PUZZLE%"
|
|
84
|
-
data-callback="onSubmit"
|
|
85
|
-
data-size="invisible">
|
|
86
|
-
Submit
|
|
87
|
-
</button>
|
|
88
|
-
</form>
|
|
89
|
-
|
|
90
|
-
<div id="result" class="demo-result" style="display: none;"></div>
|
|
91
|
-
|
|
92
|
-
</div>
|
|
93
|
-
</body>
|
|
94
|
-
</html>
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
// Shows the code a site would add to get the setup on the current demo page.
|
|
16
|
-
import type { IndexHtmlTransformContext, Plugin } from "vite";
|
|
17
|
-
import {
|
|
18
|
-
type DemoPage,
|
|
19
|
-
findPageByPath,
|
|
20
|
-
pagePathFromFilename,
|
|
21
|
-
} from "./pages.js";
|
|
22
|
-
import { fillSlot } from "./slots.js";
|
|
23
|
-
|
|
24
|
-
const BUNDLE_URL = "https://js.prosopo.io/js/procaptcha.bundle.js";
|
|
25
|
-
|
|
26
|
-
const implicitSnippet = `<script src="${BUNDLE_URL}" async defer></script>
|
|
27
|
-
|
|
28
|
-
<form action="/signup" method="POST">
|
|
29
|
-
<!-- your fields -->
|
|
30
|
-
<div class="procaptcha" data-sitekey="YOUR_SITE_KEY"></div>
|
|
31
|
-
<button type="submit">Submit</button>
|
|
32
|
-
</form>`;
|
|
33
|
-
|
|
34
|
-
const explicitSnippet = `<div id="procaptcha-container"></div>
|
|
35
|
-
|
|
36
|
-
<script type="module">
|
|
37
|
-
import { render } from "${BUNDLE_URL}";
|
|
38
|
-
|
|
39
|
-
render(document.getElementById("procaptcha-container"), {
|
|
40
|
-
siteKey: "YOUR_SITE_KEY",
|
|
41
|
-
callback: (token) => {
|
|
42
|
-
// send the token to your server with the form
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
</script>`;
|
|
46
|
-
|
|
47
|
-
const manualSnippet = `<script src="${BUNDLE_URL}" async defer></script>
|
|
48
|
-
|
|
49
|
-
<div class="procaptcha" data-sitekey="YOUR_SITE_KEY"
|
|
50
|
-
data-start-mode="manual"></div>
|
|
51
|
-
|
|
52
|
-
<script>
|
|
53
|
-
// nothing runs until this is called or the box is ticked
|
|
54
|
-
window.procaptcha.start();
|
|
55
|
-
</script>`;
|
|
56
|
-
|
|
57
|
-
const boundSnippet = `<div id="procaptcha-container"></div>
|
|
58
|
-
<button id="submit-button" type="submit">Submit</button>
|
|
59
|
-
|
|
60
|
-
<script type="module">
|
|
61
|
-
import { render } from "${BUNDLE_URL}";
|
|
62
|
-
|
|
63
|
-
render(document.getElementById("procaptcha-container"), {
|
|
64
|
-
siteKey: "YOUR_SITE_KEY",
|
|
65
|
-
bind: "#submit-button",
|
|
66
|
-
callback: (token) => {
|
|
67
|
-
// send the token to your server with the form
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
</script>`;
|
|
71
|
-
|
|
72
|
-
const invisibleImplicitSnippet = `<script src="${BUNDLE_URL}" async defer></script>
|
|
73
|
-
|
|
74
|
-
<button class="procaptcha" data-sitekey="YOUR_SITE_KEY"
|
|
75
|
-
data-size="invisible" data-callback="onSubmit">Submit</button>
|
|
76
|
-
|
|
77
|
-
<script>
|
|
78
|
-
function onSubmit(token) {
|
|
79
|
-
// send the token to your server with the form
|
|
80
|
-
}
|
|
81
|
-
</script>`;
|
|
82
|
-
|
|
83
|
-
const invisibleExplicitSnippet = `<div id="procaptcha-container"></div>
|
|
84
|
-
|
|
85
|
-
<script type="module">
|
|
86
|
-
import { render, execute } from "${BUNDLE_URL}";
|
|
87
|
-
|
|
88
|
-
render(document.getElementById("procaptcha-container"), {
|
|
89
|
-
siteKey: "YOUR_SITE_KEY",
|
|
90
|
-
size: "invisible",
|
|
91
|
-
callback: (token) => {
|
|
92
|
-
// send the token to your server with the form
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
document.querySelector("form").addEventListener("submit", (event) => {
|
|
97
|
-
event.preventDefault();
|
|
98
|
-
execute();
|
|
99
|
-
});
|
|
100
|
-
</script>`;
|
|
101
|
-
|
|
102
|
-
export const snippetFor = (page: DemoPage): string => {
|
|
103
|
-
if (page.mode === "invisible") {
|
|
104
|
-
return page.rendering === "explicit"
|
|
105
|
-
? invisibleExplicitSnippet
|
|
106
|
-
: invisibleImplicitSnippet;
|
|
107
|
-
}
|
|
108
|
-
switch (page.rendering) {
|
|
109
|
-
case "explicit":
|
|
110
|
-
return explicitSnippet;
|
|
111
|
-
case "manual":
|
|
112
|
-
return manualSnippet;
|
|
113
|
-
case "bound":
|
|
114
|
-
return boundSnippet;
|
|
115
|
-
default:
|
|
116
|
-
return implicitSnippet;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const escapeHtml = (text: string): string =>
|
|
121
|
-
text
|
|
122
|
-
.replace(/&/g, "&")
|
|
123
|
-
.replace(/</g, "<")
|
|
124
|
-
.replace(/>/g, ">")
|
|
125
|
-
.replace(/"/g, """)
|
|
126
|
-
.replace(/'/g, "'");
|
|
127
|
-
|
|
128
|
-
const copyScript = `
|
|
129
|
-
<script>
|
|
130
|
-
document.addEventListener("click", function (event) {
|
|
131
|
-
var button = event.target.closest && event.target.closest("[data-demo-copy]");
|
|
132
|
-
if (!button) return;
|
|
133
|
-
var code = button.closest(".demo-code-block").querySelector("code");
|
|
134
|
-
navigator.clipboard.writeText(code.textContent).then(function () {
|
|
135
|
-
button.textContent = "Copied";
|
|
136
|
-
setTimeout(function () {
|
|
137
|
-
button.textContent = "Copy";
|
|
138
|
-
}, 1500);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
</script>`;
|
|
142
|
-
|
|
143
|
-
// A plain button, not type="button": several specs probe
|
|
144
|
-
// button[type='button']:nth-of-type(2) and must not find this one.
|
|
145
|
-
const snippetMarkup = (page: DemoPage): string => `
|
|
146
|
-
<div class="demo-code-block">
|
|
147
|
-
<div class="demo-code-bar"><button class="demo-copy" data-demo-copy>Copy</button></div>
|
|
148
|
-
<pre class="demo-code"><code>${escapeHtml(snippetFor(page))}</code></pre>
|
|
149
|
-
</div>
|
|
150
|
-
<p class="demo-note">Pick the captcha type for your site key in the <a href="https://portal.prosopo.io/">portal</a>.</p>
|
|
151
|
-
${copyScript}`;
|
|
152
|
-
|
|
153
|
-
export default function codeSnippetInjector(): Plugin {
|
|
154
|
-
return {
|
|
155
|
-
name: "code-snippet-injector",
|
|
156
|
-
transformIndexHtml: {
|
|
157
|
-
order: "post",
|
|
158
|
-
handler(html: string, ctx: IndexHtmlTransformContext): string {
|
|
159
|
-
if (!html.includes("<body") || !html.includes("</body>")) {
|
|
160
|
-
return html;
|
|
161
|
-
}
|
|
162
|
-
if (html.includes("data-demo-copy")) {
|
|
163
|
-
return html;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const page = findPageByPath(pagePathFromFilename(ctx.filename));
|
|
167
|
-
if (!page) {
|
|
168
|
-
return html;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const markup = snippetMarkup(page);
|
|
172
|
-
return (
|
|
173
|
-
fillSlot(html, "code", markup) ??
|
|
174
|
-
html.replace("</body>", () => `${markup}</body>`)
|
|
175
|
-
);
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
// Vite plugin to inject a button that fills the demo form with sample values.
|
|
16
|
-
import type { IndexHtmlTransformContext, Plugin } from "vite";
|
|
17
|
-
import { fillSlot } from "./slots.js";
|
|
18
|
-
|
|
19
|
-
export default function formFillerInjector(): Plugin {
|
|
20
|
-
// No type attribute: specs probe button[type='button']:nth-of-type(2).
|
|
21
|
-
const buttonHtml = `
|
|
22
|
-
<button id="form-filler-button" class="form-filler-button" title="Fill the form with sample values">
|
|
23
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
|
|
24
|
-
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
|
|
25
|
-
</svg>
|
|
26
|
-
<span>Fill form</span>
|
|
27
|
-
</button>
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
const fillerScript = `
|
|
31
|
-
<script>
|
|
32
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
33
|
-
function fillFormWithDefaults() {
|
|
34
|
-
const inputs = document.querySelectorAll('input, select, textarea');
|
|
35
|
-
const filledElements = [];
|
|
36
|
-
|
|
37
|
-
inputs.forEach(input => {
|
|
38
|
-
let filled = true;
|
|
39
|
-
|
|
40
|
-
if (input.type === 'hidden' || (input.value && input.value.trim() !== '')) {
|
|
41
|
-
filled = false;
|
|
42
|
-
}
|
|
43
|
-
else if (input.type === 'text') {
|
|
44
|
-
if (input.id.toLowerCase().includes('name') || input.name.toLowerCase().includes('name')) {
|
|
45
|
-
input.value = 'John Doe';
|
|
46
|
-
} else {
|
|
47
|
-
input.value = 'Default Text';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else if (input.type === 'email') {
|
|
51
|
-
input.value = 'test@example.com';
|
|
52
|
-
}
|
|
53
|
-
else if (input.type === 'password') {
|
|
54
|
-
input.value = 'Password123!';
|
|
55
|
-
}
|
|
56
|
-
else if (input.type === 'tel') {
|
|
57
|
-
input.value = '+1234567890';
|
|
58
|
-
}
|
|
59
|
-
else if (input.type === 'number') {
|
|
60
|
-
input.value = '42';
|
|
61
|
-
}
|
|
62
|
-
else if (input.type === 'url') {
|
|
63
|
-
input.value = 'https://example.com';
|
|
64
|
-
}
|
|
65
|
-
else if (input.type === 'date') {
|
|
66
|
-
const today = new Date();
|
|
67
|
-
const yyyy = today.getFullYear();
|
|
68
|
-
const mm = String(today.getMonth() + 1).padStart(2, '0');
|
|
69
|
-
const dd = String(today.getDate()).padStart(2, '0');
|
|
70
|
-
input.value = \`\${yyyy}-\${mm}-\${dd}\`;
|
|
71
|
-
}
|
|
72
|
-
else if (input.type === 'time') {
|
|
73
|
-
input.value = '12:00';
|
|
74
|
-
}
|
|
75
|
-
else if (input.type === 'checkbox' || input.type === 'radio') {
|
|
76
|
-
input.checked = true;
|
|
77
|
-
}
|
|
78
|
-
else if (input.tagName === 'SELECT') {
|
|
79
|
-
if (input.options.length > 0) {
|
|
80
|
-
input.selectedIndex = 1 >= input.options.length ? 0 : 1;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else if (input.tagName === 'TEXTAREA') {
|
|
84
|
-
input.value = 'This is a sample text for the textarea field.';
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
input.value = 'Default Value';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (filled) {
|
|
91
|
-
filledElements.push(input);
|
|
92
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
93
|
-
if (input.tagName === 'SELECT') {
|
|
94
|
-
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (filledElements.length > 0) {
|
|
100
|
-
if (typeof window.updateCaptchaStatus === 'function') {
|
|
101
|
-
window.updateCaptchaStatus(\`Filled \${filledElements.length} form fields with default values\`, 'info');
|
|
102
|
-
} else {
|
|
103
|
-
console.log(\`Filled \${filledElements.length} form fields with default values\`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
filledElements.forEach(el => {
|
|
107
|
-
const originalBackground = el.style.backgroundColor;
|
|
108
|
-
const originalTransition = el.style.transition;
|
|
109
|
-
|
|
110
|
-
el.style.transition = 'background-color 1.5s ease';
|
|
111
|
-
el.style.backgroundColor = '#EDECF5';
|
|
112
|
-
|
|
113
|
-
setTimeout(() => {
|
|
114
|
-
el.style.backgroundColor = originalBackground;
|
|
115
|
-
setTimeout(() => {
|
|
116
|
-
el.style.transition = originalTransition;
|
|
117
|
-
}, 1500);
|
|
118
|
-
}, 500);
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const formFillerButton = document.getElementById('form-filler-button');
|
|
124
|
-
if (formFillerButton) {
|
|
125
|
-
formFillerButton.addEventListener('click', fillFormWithDefaults);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
</script>
|
|
129
|
-
`;
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
name: "form-filler-injector",
|
|
133
|
-
transformIndexHtml: {
|
|
134
|
-
order: "post",
|
|
135
|
-
handler(html: string, _ctx: IndexHtmlTransformContext): string {
|
|
136
|
-
if (!html.includes("<body") || !html.includes("</body>")) {
|
|
137
|
-
return html;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const withButton =
|
|
141
|
-
fillSlot(html, "toolbar", buttonHtml) ??
|
|
142
|
-
html.replace("</body>", () => `${buttonHtml}</body>`);
|
|
143
|
-
|
|
144
|
-
return withButton.replace("</body>", () => `${fillerScript}</body>`);
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
}
|