widget(0.1.36): better widget ui

This commit is contained in:
tiago
2026-02-28 12:11:07 +00:00
parent a17cd63ade
commit aa73ca2865
32 changed files with 1375 additions and 1344 deletions
+4
View File
@@ -15,3 +15,7 @@ run `bun install` in each Bun package you want to work on to install dependencie
- we recommend [Biome](https://biomejs.dev/) for formatting and linting. please fix all errors and warnings before submitting a PR
- [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) are preferred
## current roadmap
javascript challenges and reputation-based difficulties are the main new feature focus.
+28
View File
@@ -1,11 +1,13 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "cap-demo",
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4",
"lightningcss": "^1.31.1",
},
},
},
@@ -24,6 +26,8 @@
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"elysia": ["elysia@1.3.4", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-kAfM3Zwovy3z255IZgTKVxBw91HbgKhYl3TqrGRdZqqr+Fd+4eKOfvxgaKij22+MZLczPzIHtscAmvfpI3+q/A=="],
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
@@ -36,6 +40,30 @@
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
+24 -2
View File
@@ -1,7 +1,23 @@
import fs from "node:fs/promises";
import { Elysia, file } from "elysia";
import { transform } from "lightningcss";
import Cap from "../../server/index.js";
const processCSS = async () => {
const raw = await fs.readFile("../../widget/src/src/cap.css", "utf-8");
const { code } = transform({
filename: "cap.css",
code: Buffer.from(raw),
minify: true,
targets: {
chrome: 90 << 16,
firefox: 90 << 16,
safari: 14 << 16,
},
});
return code.toString();
};
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
@@ -11,14 +27,15 @@ const app = new Elysia();
app.get("/", () => file("./index.html"));
app.get("/cap.js", async ({ set }) => {
// in the newest version, the worker is injected into the main file
// in the newest version, the worker and CSS are injected into the main file
// by a build script. since we don't have a build script here,
// we'll need to run a minimal build ourselves.
const main = await fs.readFile("../../widget/src/src/cap.js", "utf-8");
const worker = await fs.readFile("../../widget/src/src/worker.js", "utf-8");
const css = await processCSS();
const bundle = main.replace("%%workerScript%%", worker);
const bundle = main.replace("%%workerScript%%", worker).replace("%%capCSS%%", css);
set.headers = {
"Content-Type": "application/javascript",
@@ -29,6 +46,11 @@ app.get("/cap.js", async ({ set }) => {
app.get("/cap-floating.js", () => file("../../widget/src/src/cap-floating.js"));
app.get("/cap.css", async ({ set }) => {
set.headers = { "Content-Type": "text/css" };
return processCSS();
});
app.post("/api/challenge", () => cap.createChallenge());
app.post("/api/redeem", async ({ body, set }) => {
+2 -1
View File
@@ -12,6 +12,7 @@
},
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4"
"elysia": "^1.3.4",
"lightningcss": "^1.31.1"
}
}
-54
View File
@@ -1,54 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
"@cap.js/server": "latest",
"elysia": "^1.3.3",
},
},
},
"packages": {
"@cap.js/server": ["@cap.js/server@1.0.15", "", { "dependencies": { "@types/node": "^22.14.1", "typescript": "^5.8.3" } }, "sha512-mcDbHAL4ar5O4gnDE+62ZPeXhLXxd1KKHzJCsZfn81HY8Fgo5ousxYCnzhsLfki5sH6sO6jpNtS4MZXlKDq+fA=="],
"@sinclair/typebox": ["@sinclair/typebox@0.34.33", "", {}, "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g=="],
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="],
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
"@types/node": ["@types/node@22.15.29", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"elysia": ["elysia@1.3.3", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-x6a89d4h0xX9TB0CSGkUuKNqIK776HBJw0WHtK1B3ViQqZijsLnOor6be/7TwVl8MG6m59NHGHbmbBS6lnCXSw=="],
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
"file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
"peek-readable": ["peek-readable@7.0.0", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
"strtok3": ["strtok3@10.2.2", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^7.0.0" } }, "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg=="],
"token-types": ["token-types@6.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
}
}
-22
View File
@@ -1,22 +0,0 @@
import { Elysia, file } from "elysia";
import { capMiddleware } from "../../../checkpoints/elysia/index";
// import { capMiddleware } from "@cap.js/middleware-elysia";
new Elysia()
.use(
capMiddleware({
/*
token_validity_hours: 32, // how long the token is valid for
tokens_store_path: ".data/tokensList.json",
token_size: 16, // token size in bytes
verification_template_path: join(
dirname(fileURLToPath(import.meta.url)),
"./index.html"
),
scoping: "scoped", // 'global' | 'scoped'
*/
}),
)
.get("/", () => file("success.html"))
.listen(3000);
-6
View File
@@ -1,6 +0,0 @@
{
"dependencies": {
"@cap.js/server": "latest",
"elysia": "^1.3.3"
}
}
-52
View File
@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Success!</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0px;
padding: 0px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
sans-serif;
text-align: center;
}
h1 {
font-size: 4em;
margin-bottom: 0px;
}
p {
max-width: 250px;
line-height: 1.4;
}
button {
background-color: transparent;
font-weight: 500;
border: none;
cursor: pointer;
font-family: inherit;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content">
<h1>🎉</h1>
<p>You have successfully passed Cap's checkpoint.</p>
<button>Try again</button>
</div>
</body>
<script>
document.querySelector("button").addEventListener("click", () => {
document.cookie =
"__cap_clearance=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/";
location.reload();
});
</script>
</html>
-157
View File
@@ -1,157 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
"@cap.js/server": "latest",
"cookie-parser": "^1.4.7",
"express": "^5.1.0",
},
},
},
"packages": {
"@cap.js/server": ["@cap.js/server@1.0.15", "", { "dependencies": { "@types/node": "^22.14.1", "typescript": "^5.8.3" } }, "sha512-mcDbHAL4ar5O4gnDE+62ZPeXhLXxd1KKHzJCsZfn81HY8Fgo5ousxYCnzhsLfki5sH6sO6jpNtS4MZXlKDq+fA=="],
"@types/node": ["@types/node@22.15.29", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ=="],
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
"cookie-parser": ["cookie-parser@1.4.7", "", { "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.6" } }, "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw=="],
"cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
"path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
}
}
-32
View File
@@ -1,32 +0,0 @@
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import cookieParser from "cookie-parser";
import express from "express";
import { capCheckpoint } from "../../../checkpoints/express/index";
// import { capCheckpoint } from "@cap.js/checkpoint-express";
const app = express();
const __dirname = dirname(fileURLToPath(import.meta.url));
app.use(express.json());
app.use(cookieParser());
app.use(
capCheckpoint({
/*
token_validity_hours: 32,
tokens_store_path: ".data/tokensList.json",
token_size: 16,
verification_template_path: join(__dirname, "./index.html"),
*/
}),
);
app.get("/", (_, res) => {
res.sendFile(path.join(__dirname, "success.html"));
});
app.listen(3000, () => {
console.log(`Server running on http://localhost:3000`);
});
-7
View File
@@ -1,7 +0,0 @@
{
"dependencies": {
"@cap.js/server": "latest",
"cookie-parser": "^1.4.7",
"express": "^5.1.0"
}
}
-52
View File
@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Success!</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0px;
padding: 0px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
sans-serif;
text-align: center;
}
h1 {
font-size: 4em;
margin-bottom: 0px;
}
p {
max-width: 250px;
line-height: 1.4;
}
button {
background-color: transparent;
font-weight: 500;
border: none;
cursor: pointer;
font-family: inherit;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content">
<h1>🎉</h1>
<p>You have successfully passed Cap's checkpoint.</p>
<button>Try again</button>
</div>
</body>
<script>
document.querySelector("button").addEventListener("click", () => {
document.cookie =
"__cap_clearance=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/";
location.reload();
});
</script>
</html>
-22
View File
@@ -1,22 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
"@cap.js/server": "latest",
"hono": "^4.7.10",
},
},
},
"packages": {
"@cap.js/server": ["@cap.js/server@1.0.15", "", { "dependencies": { "@types/node": "^22.14.1", "typescript": "^5.8.3" } }, "sha512-mcDbHAL4ar5O4gnDE+62ZPeXhLXxd1KKHzJCsZfn81HY8Fgo5ousxYCnzhsLfki5sH6sO6jpNtS4MZXlKDq+fA=="],
"@types/node": ["@types/node@22.15.28", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-I0okKVDmyKR281I0UIFV7EWAWRnR0gkuSKob5wVcByyyhr7Px/slhkQapcYX4u00ekzNWaS1gznKZnuzxwo4pw=="],
"hono": ["hono@4.7.10", "", {}, "sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
}
}
-24
View File
@@ -1,24 +0,0 @@
import { Hono } from "hono";
import { serveStatic } from "hono/bun";
import { capCheckpoint } from "../../../checkpoints/hono/index";
// import { capCheckpoint } from "@cap.js/checkpoint-hono";
const app = new Hono();
app.use(
"*",
capCheckpoint({
/*
token_validity_hours: 32, // how long the token is valid for
tokens_store_path: ".data/tokensList.json",
token_size: 16, // token size in bytes
verification_template_path: join(
dirname(fileURLToPath(import.meta.url)),
"./index.html"
)
*/
})
);
app.get("/", serveStatic({ path: "./success.html" }));
export default app;
-6
View File
@@ -1,6 +0,0 @@
{
"dependencies": {
"@cap.js/server": "latest",
"hono": "^4.7.10"
}
}
-52
View File
@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Success!</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0px;
padding: 0px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
sans-serif;
text-align: center;
}
h1 {
font-size: 4em;
margin-bottom: 0px;
}
p {
max-width: 250px;
line-height: 1.4;
}
button {
background-color: transparent;
font-weight: 500;
border: none;
cursor: pointer;
font-family: inherit;
font-size: 16px;
}
</style>
</head>
<body>
<div class="content">
<h1>🎉</h1>
<p>You have successfully passed Cap's checkpoint.</p>
<button>Try again</button>
</div>
</body>
<script>
document.querySelector("button").addEventListener("click", () => {
document.cookie =
"__cap_clearance=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/";
location.reload();
});
</script>
</html>
+28
View File
@@ -1,11 +1,13 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "cap-demo",
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4",
"lightningcss": "^1.31.1",
},
},
},
@@ -24,6 +26,8 @@
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"elysia": ["elysia@1.3.4", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-kAfM3Zwovy3z255IZgTKVxBw91HbgKhYl3TqrGRdZqqr+Fd+4eKOfvxgaKij22+MZLczPzIHtscAmvfpI3+q/A=="],
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
@@ -36,6 +40,30 @@
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
+24 -2
View File
@@ -3,6 +3,22 @@
import fs from "node:fs/promises";
import Cap from "@cap.js/server";
import { Elysia, file } from "elysia";
import { transform } from "lightningcss";
const processCSS = async () => {
const raw = await fs.readFile("../../widget/src/src/cap.css", "utf-8");
const { code } = transform({
filename: "cap.css",
code: Buffer.from(raw),
minify: true,
targets: {
chrome: 90 << 16,
firefox: 90 << 16,
safari: 14 << 16,
},
});
return code.toString();
};
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
@@ -13,14 +29,15 @@ const app = new Elysia();
app.get("/", () => file("./index.html"));
app.get("/cap.js", async ({ set }) => {
// in the newest version, the worker is injected into the main file
// in the newest version, the worker and CSS are injected into the main file
// by a build script. since we don't have a build script here,
// we'll need to build it ourselves.
const main = await fs.readFile("../../widget/src/src/cap.js", "utf-8");
const worker = await fs.readFile("../../widget/src/src/worker.js", "utf-8");
const css = await processCSS();
const bundle = main.replace("%%workerScript%%", worker);
const bundle = main.replace("%%workerScript%%", worker).replace("%%capCSS%%", css);
set.headers = {
"Content-Type": "application/javascript",
@@ -31,6 +48,11 @@ app.get("/cap.js", async ({ set }) => {
app.get("/cap-floating.js", () => file("../../widget/src/src/cap-floating.js"));
app.get("/cap.css", async ({ set }) => {
set.headers = { "Content-Type": "text/css" };
return processCSS();
});
app.post("/api/challenge", () => cap.createChallenge());
app.post("/api/redeem", async ({ body, set }) => {
+2 -1
View File
@@ -12,6 +12,7 @@
},
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4"
"elysia": "^1.3.4",
"lightningcss": "^1.31.1"
}
}
+28
View File
@@ -1,11 +1,13 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "cap-demo",
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4",
"lightningcss": "^1.31.1",
},
},
},
@@ -24,6 +26,8 @@
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"elysia": ["elysia@1.3.4", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-kAfM3Zwovy3z255IZgTKVxBw91HbgKhYl3TqrGRdZqqr+Fd+4eKOfvxgaKij22+MZLczPzIHtscAmvfpI3+q/A=="],
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
@@ -36,6 +40,30 @@
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
+31 -14
View File
@@ -1,8 +1,24 @@
import { Database } from "bun:sqlite";
import fs from "node:fs/promises";
import { Elysia, file } from "elysia";
import { transform } from "lightningcss";
import Cap from "../../server/index.js";
const processCSS = async () => {
const raw = await fs.readFile("../../widget/src/src/cap.css", "utf-8");
const { code } = transform({
filename: "cap.css",
code: Buffer.from(raw),
minify: true,
targets: {
chrome: 90 << 16,
firefox: 90 << 16,
safari: 14 << 16,
},
});
return code.toString();
};
const db = new Database("./.data/cap.db");
db.exec(`
@@ -21,9 +37,7 @@ const cap = new Cap({
storage: {
challenges: {
store: async (token, challengeData) => {
db.prepare(
"INSERT OR REPLACE INTO challenges (token, data, expires) VALUES (?, ?, ?)",
).run(
db.prepare("INSERT OR REPLACE INTO challenges (token, data, expires) VALUES (?, ?, ?)").run(
token,
JSON.stringify(challengeData.challenge),
challengeData.expires,
@@ -31,14 +45,10 @@ const cap = new Cap({
},
read: async (token) => {
const row = db
.prepare(
"SELECT data, expires FROM challenges WHERE token = ? AND expires > ?",
)
.prepare("SELECT data, expires FROM challenges WHERE token = ? AND expires > ?")
.get(token, Date.now());
return row
? { challenge: JSON.parse(row.data), expires: row.expires }
: null;
return row ? { challenge: JSON.parse(row.data), expires: row.expires } : null;
},
delete: async (token) => {
db.prepare("DELETE FROM challenges WHERE token = ?").run(token);
@@ -49,9 +59,10 @@ const cap = new Cap({
},
tokens: {
store: async (tokenKey, expires) => {
db.prepare(
"INSERT OR REPLACE INTO tokens (key, expires) VALUES (?, ?)",
).run(tokenKey, expires);
db.prepare("INSERT OR REPLACE INTO tokens (key, expires) VALUES (?, ?)").run(
tokenKey,
expires,
);
},
get: async (tokenKey) => {
const row = db
@@ -75,14 +86,15 @@ const app = new Elysia();
app.get("/", () => file("./index.html"));
app.get("/cap.js", async ({ set }) => {
// in the newest version, the worker is injected into the main file
// in the newest version, the worker and CSS are injected into the main file
// by a build script. since we don't have a build script here,
// we'll need to run a minimal build ourselves.
const main = await fs.readFile("../../widget/src/src/cap.js", "utf-8");
const worker = await fs.readFile("../../widget/src/src/worker.js", "utf-8");
const css = await processCSS();
const bundle = main.replace("%%workerScript%%", worker);
const bundle = main.replace("%%workerScript%%", worker).replace("%%capCSS%%", css);
set.headers = {
"Content-Type": "application/javascript",
@@ -93,6 +105,11 @@ app.get("/cap.js", async ({ set }) => {
app.get("/cap-floating.js", () => file("../../widget/src/src/cap-floating.js"));
app.get("/cap.css", async ({ set }) => {
set.headers = { "Content-Type": "text/css" };
return processCSS();
});
app.post("/api/challenge", () => cap.createChallenge());
app.post("/api/redeem", async ({ body, set }) => {
+2 -1
View File
@@ -12,6 +12,7 @@
},
"dependencies": {
"@cap.js/server": "^1.0.13",
"elysia": "^1.3.4"
"elysia": "^1.3.4",
"lightningcss": "^1.31.1"
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ export default withMermaid({
[
"script",
{
src: "https://cdn.jsdelivr.net/npm/@cap.js/widget@0.1.35",
src: "https://cdn.jsdelivr.net/npm/@cap.js/widget@0.1.36",
async: true,
},
],
+26 -9
View File
@@ -1,8 +1,23 @@
import fs from "node:fs/promises";
import { transform } from "lightningcss";
import { chromium } from "playwright";
import { minify } from "terser";
const min = async (input) => {
const minifyCSS = (input) => {
const { code } = transform({
filename: "cap.css",
code: Buffer.from(input),
minify: true,
targets: {
chrome: 90 << 16,
firefox: 90 << 16,
safari: 14 << 16,
},
});
return code.toString();
};
const minifyJS = async (input) => {
return (
await minify(input, {
compress: {
@@ -17,28 +32,30 @@ const min = async (input) => {
mangle: true,
})
).code
.split("\\n")
.split("\n")
.map((e) => {
return e.trimStart();
})
.join("\\n");
.join("\n");
};
console.time("build");
const rawMain = await fs.readFile("./src/src/cap.js", "utf-8");
const minifiedWorker = await min(
await fs.readFile("./src/src/worker.js", "utf-8"),
);
const rawCSS = await fs.readFile("./src/src/cap.css", "utf-8");
const minifiedWorker = await minifyJS(await fs.readFile("./src/src/worker.js", "utf-8"));
const minifiedCSS = minifyCSS(rawCSS);
const bundle = rawMain.replace("%%workerScript%%", minifiedWorker);
const bundle = rawMain
.replace("%%workerScript%%", minifiedWorker)
.replace("%%capCSS%%", minifiedCSS);
await fs.writeFile("./src/cap.min.js", bundle);
await fs.writeFile("./src/cap.min.js", await min(bundle));
await fs.writeFile("./src/cap.min.js", await minifyJS(bundle));
await fs.writeFile(
"./src/cap-floating.min.js",
await min(await fs.readFile("./src/src/cap-floating.js", "utf-8")),
await minifyJS(await fs.readFile("./src/src/cap-floating.js", "utf-8")),
);
console.timeEnd("build");
+28
View File
@@ -1,9 +1,11 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "widget",
"dependencies": {
"lightningcss": "^1.31.1",
"playwright": "^1.52.0",
"terser": "^5.43.1",
},
@@ -42,8 +44,34 @@
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"playwright": ["playwright@1.52.0", "", { "dependencies": { "playwright-core": "1.52.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw=="],
"playwright-core": ["playwright-core@1.52.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg=="],
+1
View File
@@ -8,6 +8,7 @@
"typescript": "^5"
},
"dependencies": {
"lightningcss": "^1.31.1",
"playwright": "^1.52.0",
"terser": "^5.43.1"
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@cap.js/widget",
"version": "0.1.35",
"version": "0.1.36",
"description": "Client-side widget for Cap, a lightweight, modern open-source CAPTCHA alternative designed using SHA-256 PoW.",
"keywords": [
"security",
+231
View File
@@ -0,0 +1,231 @@
@media (prefers-reduced-motion: reduce) {
.captcha,
.captcha * {
transition: none !important;
animation: none !important;
}
.label {
transition: none !important;
transform: none !important;
filter: none !important;
opacity: 1 !important;
}
.label:not(.active) {
display: none !important;
}
.label.exit {
display: none !important;
}
}
.captcha,
.captcha * {
box-sizing: border-box;
}
.captcha {
background-color: var(--cap-background, #fdfdfd);
border: 1px solid var(--cap-border-color, #dddddd8f);
border-radius: var(--cap-border-radius, 14px);
user-select: none;
height: var(--cap-widget-height, 58px);
width: var(--cap-widget-width, 260px);
display: flex;
align-items: center;
padding: var(--cap-widget-padding, 14px);
gap: var(--cap-gap, 15px);
cursor: pointer;
transition:
filter 0.2s,
transform 0.2s;
position: relative;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
overflow: hidden;
color: var(--cap-color, #212121);
}
.captcha:hover {
filter: brightness(98%);
}
.captcha * {
font-family: var(
--cap-font,
system,
-apple-system,
"BlinkMacSystemFont",
".SFNSText-Regular",
"San Francisco",
"Roboto",
"Segoe UI",
"Helvetica Neue",
"Lucida Grande",
"Ubuntu",
"arial",
sans-serif
);
}
.checkbox {
width: var(--cap-checkbox-size, 25px);
height: var(--cap-checkbox-size, 25px);
border: var(--cap-checkbox-border, 1px solid #aaaaaad1);
border-radius: var(--cap-checkbox-border-radius, 6px);
background-color: var(--cap-checkbox-background, #fafafa91);
transition: opacity 0.2s;
margin-top: var(--cap-checkbox-margin, 2px);
margin-bottom: var(--cap-checkbox-margin, 2px);
}
.captcha p {
margin: 0;
font-weight: 500;
font-size: 15px;
user-select: none;
}
.label-wrapper {
position: relative;
height: 2em;
overflow: hidden;
flex: 1;
min-width: 0;
display: flex;
align-items: center;
}
.label-wrapper::before,
.label-wrapper::after {
content: "";
pointer-events: none;
position: absolute;
left: 0;
width: 100%;
height: 0.6em;
z-index: 1;
}
.label-wrapper::before {
top: 0;
background: linear-gradient(to bottom, var(--cap-background, #fdfdfd), transparent);
}
.label-wrapper::after {
bottom: 0;
background: linear-gradient(to top, var(--cap-background, #fdfdfd), transparent);
}
.label {
position: absolute;
white-space: nowrap;
opacity: 0;
transform: translateY(100%);
transition:
transform 0.5s cubic-bezier(0.25, 1, 0.5, 1),
opacity 0.5s ease,
filter 0.5s ease;
filter: blur(2px);
}
.label.active {
opacity: 1;
transform: translateY(0);
filter: none;
}
.label.exit {
opacity: 0;
transform: translateY(-100%);
filter: blur(2px);
}
.checkbox .progress-ring {
display: none;
width: 100%;
height: 100%;
transform: rotate(-90deg);
}
.checkbox .progress-ring-bg {
fill: none;
stroke: var(--cap-spinner-background-color, #eee);
stroke-width: var(--cap-spinner-thickness, 3);
}
.checkbox .progress-ring-circle {
fill: none;
stroke: var(--cap-spinner-color, #000);
stroke-width: var(--cap-spinner-thickness, 3);
stroke-linecap: round;
stroke-dasharray: 87.96;
stroke-dashoffset: 87.96;
transition: stroke-dashoffset 0.3s ease;
}
.captcha[data-state="verifying"] .checkbox {
background: none;
display: flex;
align-items: center;
justify-content: center;
transform: scale(1.1);
border: none;
border-radius: 50%;
background-color: transparent;
}
.captcha[data-state="verifying"] .checkbox .progress-ring {
display: block;
}
.captcha[data-state="done"] .checkbox {
border: 1px solid transparent;
background-image: var(
--cap-checkmark,
url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E")
);
background-size: cover;
}
.captcha[data-state="done"] .checkbox .progress-ring {
display: none;
}
.captcha[data-state="error"] .checkbox {
border: 1px solid transparent;
background-image: var(
--cap-error-cross,
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E")
);
background-size: cover;
}
.captcha[data-state="error"] .checkbox .progress-ring {
display: none;
}
.captcha[disabled] {
cursor: not-allowed;
}
.captcha[disabled][data-state="verifying"] {
cursor: progress;
}
.captcha[disabled][data-state="done"] {
cursor: default;
}
.captcha .credits {
position: absolute;
bottom: 10px;
right: 10px;
font-size: 12px;
color: var(--cap-color, #212121);
opacity: 0.8;
text-underline-offset: 0.18em;
text-decoration-thickness: 0.08em;
z-index: 6;
}
+148 -104
View File
@@ -5,11 +5,25 @@
return;
}
const capFetch = (...args) => {
const capFetch = (u, _conf = {}) => {
const conf = {
..._conf,
headers: {
...(_conf.headers || {}),
"Cap-Stamp": btoa(
String.fromCharCode(
...[[Date.now()]].map((n) => [n >> 24, n >> 16, n >> 8, n[0]].map((x) => x & 255))[0],
),
).replace(/=/g, ""),
"Cap-Solver": `0,${WASM_VERSION}`,
},
};
if (window?.CAP_CUSTOM_FETCH) {
return window.CAP_CUSTOM_FETCH(...args);
return window.CAP_CUSTOM_FETCH(u, conf);
}
return fetch(...args);
return fetch(u, conf);
};
function prng(seed, length) {
@@ -17,8 +31,7 @@
let hash = 2166136261;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash +=
(hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
}
return hash >>> 0;
}
@@ -41,20 +54,36 @@
return result.substring(0, length);
}
if (!window.CAP_CUSTOM_WASM_URL) {
// preloads the wasm files to save up time on solve
[
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm.min.js`,
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm_bg.wasm`,
].forEach((url) => {
const link = document.createElement("link");
link.rel = "prefetch";
link.href = url;
link.as = url.endsWith(".wasm") ? "fetch" : "script";
document.head.appendChild(link);
let wasmModulePromise = null;
const getWasmModule = () => {
if (wasmModulePromise) return wasmModulePromise;
const wasmUrl =
window.CAP_CUSTOM_WASM_URL ||
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm_bg.wasm`;
wasmModulePromise = fetch(wasmUrl)
.then((r) => {
if (!r.ok) throw new Error(`Failed to fetch wasm: ${r.status}`);
return r.arrayBuffer();
})
.then((buf) => WebAssembly.compile(buf))
.catch((e) => {
wasmModulePromise = null;
throw e;
});
return wasmModulePromise;
};
if (typeof WebAssembly === "object" && typeof WebAssembly.compile === "function") {
getWasmModule().catch(() => {});
}
const prefersReducedMotion = () =>
window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
class CapWidget extends HTMLElement {
#workerUrl = "";
#resetTimer = null;
@@ -78,7 +107,6 @@
"onerror",
"data-cap-worker-count",
"data-cap-i18n-initial-state",
"[cap]",
];
}
@@ -134,12 +162,9 @@
if (
name === "data-cap-i18n-initial-state" &&
this.#div &&
this.#div?.querySelector("p")?.innerText
this.#div?.querySelector(".label.active")
) {
this.#div.querySelector("p").innerText = this.getI18nText(
"initial-state",
"Verify you're human",
);
this.animateLabel(this.getI18nText("initial-state", "Verify you're human"));
}
}
@@ -155,8 +180,7 @@
const workers = this.getAttribute("data-cap-worker-count");
const parsedWorkers = workers ? parseInt(workers, 10) : null;
this.setWorkersCount(parsedWorkers || navigator.hardwareConcurrency || 8);
const fieldName =
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
this.#host.innerHTML = `<input type="hidden" name="${fieldName}">`;
}
@@ -167,18 +191,11 @@
try {
this.#solving = true;
this.updateUI(
"verifying",
this.getI18nText("verifying-label", "Verifying..."),
true,
);
this.updateUI("verifying", this.getI18nText("verifying-label", "Verifying..."), true);
this.#div.setAttribute(
"aria-label",
this.getI18nText(
"verifying-aria-label",
"Verifying you're a human, please wait",
),
this.getI18nText("verifying-aria-label", "Verifying you're a human, please wait"),
);
this.dispatchEvent("progress", { progress: 0 });
@@ -211,10 +228,7 @@
challenges = Array.from({ length: challenge.c }, () => {
i = i + 1;
return [
prng(`${token}${i}`, challenge.s),
prng(`${token}${i}d`, challenge.d),
];
return [prng(`${token}${i}`, challenge.s), prng(`${token}${i}d`, challenge.d)];
});
}
@@ -231,8 +245,7 @@
this.dispatchEvent("progress", { progress: 100 });
if (!resp.success) throw new Error("Invalid solution");
const fieldName =
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
if (this.querySelector(`input[name='${fieldName}']`)) {
this.querySelector(`input[name='${fieldName}']`).value = resp.token;
}
@@ -260,10 +273,7 @@
} catch (err) {
this.#div.setAttribute(
"aria-label",
this.getI18nText(
"error-aria-label",
"An error occurred, please try again",
),
this.getI18nText("error-aria-label", "An error occurred, please try again"),
);
this.error(err.message);
throw err;
@@ -273,10 +283,39 @@
}
}
async solveChallenges(challenge) {
const total = challenge.length;
async solveChallenges(challenges) {
const total = challenges.length;
let completed = 0;
let wasmModule = null;
const wasmSupported =
typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function";
if (wasmSupported) {
try {
wasmModule = await getWasmModule();
} catch (e) {
console.warn("[cap] wasm unavailable, falling back to JS solver:", e);
}
}
if (!wasmSupported) {
if (!this.#shadow.querySelector(".warning")) {
const warningEl = document.createElement("div");
warningEl.className = "warning";
warningEl.style.cssText = `width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;`;
warningEl.innerText = this.getI18nText(
"wasm-disabled",
"Enable WASM for significantly faster solving",
);
this.#shadow.insertBefore(warningEl, this.#shadow.firstChild);
setTimeout(() => {
warningEl.style.marginBottom = `calc(-1 * var(--cap-border-radius, 14px))`;
warningEl.style.opacity = 1;
}, 10);
}
}
const workers = Array(this.#workersCount)
.fill(null)
.map(() => {
@@ -312,40 +351,17 @@
reject(err);
};
worker.postMessage({
salt,
target,
wasmUrl:
window.CAP_CUSTOM_WASM_URL ||
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm.min.js`,
});
if (
typeof WebAssembly !== "object" ||
typeof WebAssembly?.instantiate !== "function"
) {
if (this.#shadow.querySelector(".warning")) return;
const warningEl = document.createElement("div");
warningEl.className = "warning";
warningEl.style.cssText = `width: var(--cap-widget-width, 230px);background: rgb(237, 56, 46);color: white;padding: 4px 6px;padding-bottom: calc(var(--cap-border-radius, 14px) + 5px);font-size: 10px;box-sizing: border-box;font-family: system-ui;border-top-left-radius: 8px;border-top-right-radius: 8px;text-align: center;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);user-select:none;margin-bottom: -35.5px;opacity: 0;transition: margin-bottom .3s,opacity .3s;`;
warningEl.innerText =
this.getI18nText("wasm-disabled", "Enable WASM for significantly faster solving");
this.#shadow.insertBefore(warningEl, this.#shadow.firstChild);
setTimeout(() => {
warningEl.style.marginBottom = `calc(-1 * var(--cap-border-radius, 14px))`
warningEl.style.opacity = 1;
}, 10);
if (wasmModule) {
worker.postMessage({ salt, target, wasmModule }, []);
} else {
worker.postMessage({ salt, target });
}
});
const results = [];
try {
for (let i = 0; i < challenge.length; i += this.#workersCount) {
const chunk = challenge.slice(
i,
Math.min(i + this.#workersCount, challenge.length),
);
for (let i = 0; i < challenges.length; i += this.#workersCount) {
const chunk = challenges.slice(i, Math.min(i + this.#workersCount, challenges.length));
const chunkResults = await Promise.all(
chunk.map((c, idx) => solveSingleChallenge(c, idx)),
);
@@ -370,9 +386,7 @@
const parsedWorkers = parseInt(workers, 10);
const maxWorkers = Math.min(navigator.hardwareConcurrency || 8, 16);
this.#workersCount =
!Number.isNaN(parsedWorkers) &&
parsedWorkers > 0 &&
parsedWorkers <= maxWorkers
!Number.isNaN(parsedWorkers) && parsedWorkers > 0 && parsedWorkers <= maxWorkers
? parsedWorkers
: navigator.hardwareConcurrency || 8;
}
@@ -387,12 +401,14 @@
);
this.#div.setAttribute("aria-live", "polite");
this.#div.setAttribute("disabled", "true");
this.#div.innerHTML = `<div class="checkbox" part="checkbox"><svg class="progress-ring" viewBox="0 0 32 32"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label">${this.getI18nText(
this.#div.innerHTML = `<div class="checkbox" part="checkbox"><svg class="progress-ring" viewBox="0 0 32 32"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText(
"initial-state",
"Verify you're human",
)}</p><a part="attribution" aria-label="Secured by Cap" href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener">Cap</a>`;
)}</span></p><a part="attribution" aria-label="Secured by Cap" href="https://capjs.js.org/" class="credits" target="_blank" rel="follow noopener" title="Secured by Cap: Self-hosted CAPTCHA for the modern web.">Cap</a>`;
this.#shadow.innerHTML = `<style${window.CAP_CSS_NONCE ? ` nonce=${window.CAP_CSS_NONCE}` : ""}>.captcha,.captcha * {box-sizing:border-box;}.captcha{background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);user-select:none;height:var(--cap-widget-height, 58px);width:var(--cap-widget-width, 260px);display:flex;align-items:center;padding:var(--cap-widget-padding,14px);gap:var(--cap-gap,15px);cursor:pointer;transition:filter .2s,transform .2s;position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color,#212121)}.captcha:hover{filter:brightness(98%)}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);transition:opacity .2s;margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px)}.captcha *{font-family:var(--cap-font,system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity .2s}.checkbox .progress-ring{display:none;width:100%;height:100%;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96;transition:stroke-dashoffset 0.3s ease}.captcha[data-state=verifying] .checkbox{background:none;display:flex;align-items:center;justify-content:center;transform:scale(1.1);border:none;border-radius:50%;background-color:transparent}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark,url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E"));background-size:cover}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C/svg%3E"));background-size:cover}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha[disabled]{cursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:12px;color:var(--cap-color,#212121);opacity:0.8;text-underline-offset: 1.5px;}</style>`;
const css = `%%capCSS%%`;
this.#shadow.innerHTML = `<style${window.CAP_CSS_NONCE ? ` nonce=${window.CAP_CSS_NONCE}` : ""}>${css}</style>`;
this.#shadow.appendChild(this.#div);
}
@@ -411,10 +427,7 @@
});
this.#div.addEventListener("keydown", (e) => {
if (
(e.key === "Enter" || e.key === " ") &&
!this.#div.hasAttribute("disabled")
) {
if ((e.key === "Enter" || e.key === " ") && !this.#div.hasAttribute("disabled")) {
e.preventDefault();
e.stopPropagation();
this.solve();
@@ -427,12 +440,47 @@
this.addEventListener("reset", this.boundHandleReset);
}
animateLabel(text) {
if (!this.#div) return;
const wrapper = this.#div.querySelector(".label-wrapper");
if (!wrapper) return;
if (prefersReducedMotion()) {
const current = wrapper.querySelector(".label.active");
if (current) {
current.textContent = text;
} else {
const span = document.createElement("span");
span.className = "label active";
span.textContent = text;
wrapper.appendChild(span);
}
return;
}
const current = wrapper.querySelector(".label.active");
const next = document.createElement("span");
next.className = "label";
next.textContent = text;
wrapper.appendChild(next);
void next.offsetWidth;
next.classList.add("active");
if (current) {
current.classList.remove("active");
current.classList.add("exit");
current.addEventListener("transitionend", () => current.remove(), { once: true });
}
}
updateUI(state, text, disabled = false) {
if (!this.#div) return;
this.#div.setAttribute("data-state", state);
this.#div.querySelector("p").innerText = text;
this.animateLabel(text);
if (disabled) {
this.#div.setAttribute("disabled", "true");
@@ -444,35 +492,32 @@
handleProgress(event) {
if (!this.#div) return;
const progressElement = this.#div.querySelector("p");
const progressCircle = this.#div.querySelector(".progress-ring-circle");
if (progressElement && progressCircle) {
if (progressCircle) {
const circumference = 2 * Math.PI * 14;
const offset = circumference - (event.detail.progress / 100) * circumference;
progressCircle.style.strokeDashoffset = offset;
progressElement.innerText = `${this.getI18nText(
"verifying-label",
"Verifying...",
)} ${event.detail.progress}%`;
}
const wrapper = this.#div.querySelector(".label-wrapper");
if (wrapper) {
const activeLabel = wrapper.querySelector(".label.active");
if (activeLabel) {
activeLabel.textContent = `${this.getI18nText("verifying-label", "Verifying...")} ${event.detail.progress}%`;
}
}
this.executeAttributeCode("onprogress", event);
}
handleSolve(event) {
this.updateUI(
"done",
this.getI18nText("solved-label", "You're a human"),
true,
);
this.updateUI("done", this.getI18nText("solved-label", "You're a human"), true);
this.executeAttributeCode("onsolve", event);
}
handleError(event) {
this.updateUI(
"error",
this.getI18nText("error-label", "Error. Try again."),
);
this.updateUI("error", this.getI18nText("error-label", "Error. Try again."));
this.executeAttributeCode("onerror", event);
}
@@ -511,8 +556,7 @@
}
this.dispatchEvent("reset");
this.token = null;
const fieldName =
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
const fieldName = this.getAttribute("data-cap-hidden-field-name") || "cap-token";
if (this.querySelector(`input[name='${fieldName}']`)) {
this.querySelector(`input[name='${fieldName}']`).value = "";
}
@@ -554,7 +598,6 @@
}
}
// MARK: Invisible
class Cap {
constructor(config = {}, el) {
const widget = el || document.createElement("cap-widget");
@@ -591,11 +634,12 @@
}
}
}
window.Cap = Cap;
if (!customElements.get("cap-widget") && !window?.CAP_DONT_SKIP_REDEFINE) {
customElements.define("cap-widget", CapWidget);
} else {
} else if (customElements.get("cap-widget")) {
console.warn(
"[cap] the cap-widget element has already been defined, skipping re-defining it.\nto prevent this, set window.CAP_DONT_SKIP_REDEFINE to true",
);
+91 -22
View File
@@ -46,10 +46,7 @@
}
};
if (
typeof WebAssembly !== "object" ||
typeof WebAssembly?.instantiate !== "function"
) {
if (typeof WebAssembly !== "object" || typeof WebAssembly?.instantiate !== "function") {
console.warn(
"[cap worker] wasm not supported, falling back to alternative solver. this will be significantly slower.",
);
@@ -61,29 +58,101 @@
return;
}
let wasmCacheUrl, solve_pow_function;
let solve_pow_function = null;
self.onmessage = async ({ data: { salt, target, wasmUrl } }) => {
let fb;
const initFromModule = (wasmModule) => {
try {
let wasm;
let WASM_VECTOR_LEN = 0;
let cachedUint8ArrayMemory = null;
if (wasmCacheUrl !== wasmUrl) {
wasmCacheUrl = wasmUrl;
await import(wasmUrl)
.then((wasmModule) => {
return wasmModule.default().then((instance) => {
solve_pow_function = (
instance?.exports ? instance.exports : wasmModule
).solve_pow;
});
})
.catch((e) => {
console.error("[cap worker] using fallback solver due to error:", e);
fb = true;
const getMemory = () => {
if (cachedUint8ArrayMemory === null || cachedUint8ArrayMemory.byteLength === 0) {
cachedUint8ArrayMemory = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory;
};
const encoder = new TextEncoder();
const passStringToWasm = (str, malloc, realloc) => {
if (realloc === undefined) {
const encoded = encoder.encode(str);
const ptr = malloc(encoded.length, 1) >>> 0;
getMemory()
.subarray(ptr, ptr + encoded.length)
.set(encoded);
WASM_VECTOR_LEN = encoded.length;
return ptr;
}
let len = str.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getMemory();
let offset = 0;
for (; offset < len; offset++) {
const code = str.charCodeAt(offset);
if (code > 127) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) str = str.slice(offset);
ptr = realloc(ptr, len, (len = offset + str.length * 3), 1) >>> 0;
const subarray = getMemory().subarray(ptr + offset, ptr + len);
const { written } = encoder.encodeInto(str, subarray);
offset += written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}
WASM_VECTOR_LEN = offset;
return ptr;
};
const imports = { wbg: {} };
imports.wbg.__wbindgen_init_externref_table = () => {
const table = wasm.__wbindgen_export_0;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
};
const instance = new WebAssembly.Instance(wasmModule, imports);
wasm = instance.exports;
if (wasm.__wbindgen_start) wasm.__wbindgen_start();
solve_pow_function = (salt, target) => {
const saltPtr = passStringToWasm(salt, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const saltLen = WASM_VECTOR_LEN;
const targetPtr = passStringToWasm(target, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const targetLen = WASM_VECTOR_LEN;
return BigInt.asUintN(64, wasm.solve_pow(saltPtr, saltLen, targetPtr, targetLen));
};
return true;
} catch (e) {
console.error("[cap worker] failed to init wasm from module:", e);
return false;
}
};
self.onmessage = async ({ data: { salt, target, wasmModule } }) => {
if (wasmModule instanceof WebAssembly.Module && solve_pow_function === null) {
const ok = initFromModule(wasmModule);
if (!ok) {
console.warn("[cap worker] wasm init failed, falling back to JS solver.");
return solveFallback({ salt, target });
});
}
}
if (fb) return;
if (solve_pow_function === null) {
console.warn("[cap worker] no wasm module provided, falling back to JS solver.");
return solveFallback({ salt, target });
}
try {
-25
View File
@@ -359,26 +359,6 @@
});
});
// ====================================================
// this is a now unused library which an old version of
// cap depended on. to avoid breaking things as much as
// possible, we've kept it here.
try {
// lets us know how many people are actually using this
// so we can know when it's safe to deprecate.
// server source code:
// https://gist.github.com/tiagozip/ffb39489f5af91e6e45f94f1bfa14ab2
fetch(
`https://api.tiagorangel.com/cap-legacy-widget?h=${self.location?.hostname || "unknown"}`,
{
mode: "no-cors",
},
).catch(() => {});
} catch {}
console.warn(
`[cap]
%cYou're using a deprecated version of Cap's widget that still relies on this file.
@@ -388,8 +368,3 @@ It may continue to work for now, but could break at any time since this dependen
Please update Cap to fix this.`,
"font-size:15px;background-image:url('https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fpreview.colorkit.co%2Fcolor%2FEEEEEE.png%3Ftype%3Darticle-preview-logo%26size%3Dsocial%26colorname%3DSuper%2520Silver&f=1&nofb=1&ipt=49845e9195461b7c779182793c2ebf7834102eaf5561c15fa2cbb55494b77a9b');background-size:10px",
);
console.log(
`%cTo help us understand how many people are using this legacy version and when it's safe to deprecate it, we've sent a small, privacy-friendly beacon to our servers. All related code, including the telemetry server, is open source.\n\nYou might have gotten a CSP error before this, it should be safe to ignore. Server source code: https://gist.github.com/tiagozip/ffb39489f5af91e6e45f94f1bfa14ab2`,
"font-size:11px;color:#b7b7b7",
);