web-agent-bridge 3.4.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +84 -84
- package/README.ar.md +1565 -1304
- package/README.md +171 -298
- package/bin/agent-runner.js +474 -474
- package/bin/cli.js +237 -237
- package/bin/wab-init.js +244 -223
- package/bin/wab.js +80 -80
- package/examples/azure-dns-wab.js +83 -83
- package/examples/bidi-agent.js +119 -119
- package/examples/cloudflare-wab-dns.js +121 -121
- package/examples/cpanel-wab-dns.js +114 -114
- package/examples/cross-site-agent.js +91 -91
- package/examples/dns-discovery-agent.js +166 -166
- package/examples/gcp-dns-wab.js +76 -76
- package/examples/governance-agent.js +169 -169
- package/examples/mcp-agent.js +94 -94
- package/examples/next-app-router/README.md +44 -44
- package/examples/plesk-wab-dns.js +103 -103
- package/examples/puppeteer-agent.js +108 -108
- package/examples/route53-wab-dns.js +144 -144
- package/examples/saas-dashboard/README.md +55 -55
- package/examples/safe-mode-agent.js +96 -96
- package/examples/self-discovery.js +106 -0
- package/examples/shopify-hydrogen/README.md +74 -74
- package/examples/vision-agent.js +171 -171
- package/examples/wab-sign.js +74 -74
- package/examples/wab-verify.js +60 -60
- package/examples/wordpress-elementor/README.md +77 -77
- package/package.json +93 -93
- package/public/.well-known/agent-tools.json +180 -180
- package/public/.well-known/ai-assets.json +59 -59
- package/public/.well-known/security.txt +8 -8
- package/public/.well-known/wab.json +28 -28
- package/public/activate.html +448 -368
- package/public/adopt.html +236 -0
- package/public/adoption-metrics.html +188 -188
- package/public/agent-workspace.html +359 -349
- package/public/ai.html +198 -198
- package/public/api.html +397 -413
- package/public/atp.html +171 -0
- package/public/azure-dns-integration.html +289 -289
- package/public/browser.html +486 -486
- package/public/cloudflare-integration.html +380 -380
- package/public/commander-dashboard.html +243 -243
- package/public/cookies.html +210 -210
- package/public/cpanel-integration.html +398 -398
- package/public/css/agent-workspace.css +1713 -1713
- package/public/css/premium.css +317 -317
- package/public/css/styles.css +1401 -1263
- package/public/dashboard-shieldlink.html +295 -0
- package/public/dashboard.html +711 -707
- package/public/dns.html +436 -436
- package/public/docs.html +588 -588
- package/public/enterprise-mesh.ar.html +80 -0
- package/public/enterprise-mesh.html +81 -0
- package/public/feed.xml +89 -89
- package/public/gcp-dns-integration.html +318 -318
- package/public/governance.ar.html +70 -0
- package/public/governance.html +69 -0
- package/public/growth.html +465 -465
- package/public/index.html +1372 -1266
- package/public/integrations.html +556 -556
- package/public/js/activate.js +449 -145
- package/public/js/agent-workspace.js +1740 -1740
- package/public/js/auth-nav.js +117 -65
- package/public/js/auth-redirect.js +12 -12
- package/public/js/cookie-consent.js +56 -56
- package/public/js/dns.js +438 -438
- package/public/js/wab-demo-page.js +721 -721
- package/public/js/ws-client.js +74 -74
- package/public/l-preview.html +242 -0
- package/public/llms-full.txt +360 -360
- package/public/llms.txt +125 -125
- package/public/login.html +85 -85
- package/public/mesh-dashboard.html +328 -328
- package/public/milestones.html +346 -0
- package/public/one-click.html +779 -0
- package/public/openapi.json +669 -669
- package/public/partners.ar.html +145 -0
- package/public/partners.html +143 -0
- package/public/phone-shield.html +281 -281
- package/public/plesk-integration.html +375 -375
- package/public/premium-dashboard.html +2489 -2489
- package/public/premium.html +793 -793
- package/public/privacy.html +297 -297
- package/public/provider-onboarding.html +172 -172
- package/public/provider-sandbox.html +134 -134
- package/public/providers.html +359 -359
- package/public/refusals.html +172 -0
- package/public/register.html +105 -105
- package/public/registrar-integrations.html +141 -141
- package/public/ring4.html +292 -0
- package/public/robots.txt +99 -99
- package/public/route53-integration.html +531 -531
- package/public/score.html +263 -0
- package/public/script/wab-consent.d.ts +36 -36
- package/public/script/wab-consent.js +104 -104
- package/public/script/wab-schema.js +131 -131
- package/public/script/wab.d.ts +108 -108
- package/public/script/wab.min.js +580 -580
- package/public/security.txt +8 -8
- package/public/shieldlink.html +244 -0
- package/public/shieldqr.html +231 -231
- package/public/sitemap.xml +13 -1
- package/public/terms.html +256 -256
- package/public/trust-graph-api.ar.html +92 -0
- package/public/trust-graph-api.html +91 -0
- package/public/wab-features.html +560 -0
- package/public/wab-trust.html +200 -200
- package/public/wab-truth.html +375 -0
- package/public/wab-vs-protocols.html +210 -210
- package/public/whitepaper.html +449 -449
- package/script/ai-agent-bridge.js +1754 -1754
- package/sdk/README.md +99 -99
- package/sdk/agent-mesh.js +449 -449
- package/sdk/atp.js +103 -0
- package/sdk/auto-discovery.js +301 -288
- package/sdk/commander.js +262 -262
- package/sdk/governance.js +262 -262
- package/sdk/index.d.ts +464 -464
- package/sdk/index.js +653 -649
- package/sdk/multi-agent.js +318 -318
- package/sdk/safe-mode.js +221 -221
- package/sdk/safety-shield.js +219 -219
- package/sdk/schema-discovery.js +83 -83
- package/server/adapters/index.js +520 -520
- package/server/config/plans.js +412 -367
- package/server/config/secrets.js +102 -102
- package/server/control-plane/index.js +301 -301
- package/server/data-plane/index.js +354 -354
- package/server/index.js +793 -670
- package/server/llm/index.js +404 -404
- package/server/middleware/adminAuth.js +35 -35
- package/server/middleware/api-tier.js +170 -0
- package/server/middleware/auth.js +50 -50
- package/server/middleware/featureGate.js +88 -88
- package/server/middleware/rateLimits.js +100 -100
- package/server/middleware/sensitiveAction.js +157 -157
- package/server/middleware/wab-trust.js +141 -0
- package/server/migrations/001_add_analytics_indexes.sql +7 -7
- package/server/migrations/002_premium_features.sql +418 -418
- package/server/migrations/003_ads_integer_cents.sql +33 -33
- package/server/migrations/004_agent_os.sql +158 -158
- package/server/migrations/005_marketplace_metering.sql +126 -126
- package/server/migrations/006_growth_suite.sql +138 -0
- package/server/migrations/007_governance.sql +106 -106
- package/server/migrations/008_plans.sql +144 -144
- package/server/migrations/009_shieldqr.sql +30 -30
- package/server/migrations/010_extended_trust.sql +33 -33
- package/server/migrations/011_outreach.sql +47 -0
- package/server/migrations/012_shieldlink.sql +116 -0
- package/server/migrations/013_ct_monitor.sql +13 -0
- package/server/migrations/014_wab_advanced_features.sql +128 -0
- package/server/migrations/015_wab_truth_layer.sql +101 -0
- package/server/migrations/016_ring4_external_trust.sql +84 -0
- package/server/migrations/017_ring4_extensions.sql +69 -0
- package/server/migrations/018_commercial_foundations.sql +167 -0
- package/server/migrations/019_unify_tier_constraints.sql +133 -0
- package/server/migrations/020_agent_transaction_primitive.sql +119 -0
- package/server/models/adapters/index.js +33 -33
- package/server/models/adapters/mysql.js +183 -183
- package/server/models/adapters/postgresql.js +172 -172
- package/server/models/adapters/sqlite.js +7 -7
- package/server/models/db.js +740 -740
- package/server/observability/failure-analysis.js +337 -337
- package/server/observability/index.js +394 -394
- package/server/protocol/capabilities.js +223 -223
- package/server/protocol/index.js +243 -243
- package/server/protocol/schema.js +584 -584
- package/server/registry/certification.js +271 -271
- package/server/registry/index.js +326 -326
- package/server/routes/activate.js +478 -0
- package/server/routes/admin-outreach.js +239 -0
- package/server/routes/admin-plans.js +76 -76
- package/server/routes/admin-premium.js +674 -673
- package/server/routes/admin-shieldlink.js +137 -0
- package/server/routes/admin-shieldqr.js +90 -90
- package/server/routes/admin-trust-monitor.js +139 -83
- package/server/routes/admin.js +550 -549
- package/server/routes/adopt.js +61 -0
- package/server/routes/ads.js +130 -130
- package/server/routes/agent-workspace.js +540 -540
- package/server/routes/api-keys.js +127 -0
- package/server/routes/api.js +150 -150
- package/server/routes/auth.js +71 -71
- package/server/routes/billing.js +57 -57
- package/server/routes/commander.js +316 -316
- package/server/routes/customer-shieldlink.js +133 -0
- package/server/routes/demo-showcase.js +332 -332
- package/server/routes/demo-store.js +154 -154
- package/server/routes/diagnose.js +373 -0
- package/server/routes/discovery.js +2348 -2348
- package/server/routes/enterprise-mesh.js +170 -0
- package/server/routes/gateway.js +173 -173
- package/server/routes/governance-saas.js +203 -0
- package/server/routes/governance.js +208 -208
- package/server/routes/growth.js +1048 -0
- package/server/routes/intent.js +328 -0
- package/server/routes/license.js +251 -251
- package/server/routes/mesh.js +469 -469
- package/server/routes/noscript.js +543 -543
- package/server/routes/partners.js +201 -0
- package/server/routes/plans.js +33 -33
- package/server/routes/premium-v2.js +686 -686
- package/server/routes/premium.js +724 -724
- package/server/routes/providers.js +650 -650
- package/server/routes/reputation.js +411 -0
- package/server/routes/ring4.js +885 -0
- package/server/routes/runtime.js +2148 -2148
- package/server/routes/shieldlink.js +70 -0
- package/server/routes/shieldqr.js +88 -88
- package/server/routes/sovereign.js +465 -465
- package/server/routes/transactions.js +233 -0
- package/server/routes/truth-layer.js +670 -0
- package/server/routes/universal.js +200 -200
- package/server/routes/unsubscribe.js +51 -0
- package/server/routes/wab-api.js +850 -850
- package/server/routes/wab-cache.js +282 -0
- package/server/runtime/container-worker.js +111 -111
- package/server/runtime/container.js +448 -448
- package/server/runtime/distributed-worker.js +362 -362
- package/server/runtime/event-bus.js +210 -210
- package/server/runtime/index.js +253 -253
- package/server/runtime/queue.js +599 -599
- package/server/runtime/replay.js +666 -666
- package/server/runtime/sandbox.js +266 -266
- package/server/runtime/scheduler.js +534 -534
- package/server/runtime/session-engine.js +293 -293
- package/server/runtime/state-manager.js +188 -188
- package/server/secrets/wab-signing-key.pem +3 -0
- package/server/secrets/wab-signing-pub.pem +3 -0
- package/server/security/cross-site-redactor.js +196 -196
- package/server/security/dry-run.js +180 -180
- package/server/security/human-gate-rate-limit.js +147 -147
- package/server/security/human-gate-transports.js +178 -178
- package/server/security/human-gate.js +281 -281
- package/server/security/index.js +368 -368
- package/server/security/intent-engine.js +245 -245
- package/server/security/reward-guard.js +171 -171
- package/server/security/rollback-store.js +239 -239
- package/server/security/token-scope.js +404 -404
- package/server/security/url-policy.js +139 -139
- package/server/services/adoption-agent.js +182 -0
- package/server/services/agent-chat.js +506 -506
- package/server/services/agent-learning.js +601 -601
- package/server/services/agent-memory.js +625 -625
- package/server/services/agent-mesh.js +555 -555
- package/server/services/agent-symphony.js +717 -717
- package/server/services/agent-tasks.js +1807 -1807
- package/server/services/api-key-engine.js +292 -292
- package/server/services/cluster.js +894 -894
- package/server/services/commander.js +738 -738
- package/server/services/edge-compute.js +440 -440
- package/server/services/email.js +233 -233
- package/server/services/fairness-engine.js +409 -0
- package/server/services/fairness.js +420 -0
- package/server/services/governance.js +466 -466
- package/server/services/hosted-runtime.js +205 -205
- package/server/services/lfd.js +635 -635
- package/server/services/local-ai.js +389 -389
- package/server/services/marketplace.js +270 -270
- package/server/services/metering.js +182 -182
- package/server/services/modules/affiliate-intelligence.js +93 -93
- package/server/services/modules/agent-firewall.js +90 -90
- package/server/services/modules/bounty.js +89 -89
- package/server/services/modules/collective-bargaining.js +92 -92
- package/server/services/modules/dark-pattern.js +66 -66
- package/server/services/modules/gov-intelligence.js +45 -45
- package/server/services/modules/neural.js +55 -55
- package/server/services/modules/notary.js +49 -49
- package/server/services/modules/price-time-machine.js +86 -86
- package/server/services/modules/protocol.js +104 -104
- package/server/services/negotiation.js +439 -439
- package/server/services/outreach-agent.js +312 -0
- package/server/services/plans.js +214 -214
- package/server/services/plugins.js +771 -771
- package/server/services/price-intelligence.js +566 -566
- package/server/services/price-shield.js +1137 -1137
- package/server/services/provider-clients.js +740 -740
- package/server/services/reputation.js +465 -465
- package/server/services/search-engine.js +357 -357
- package/server/services/security.js +513 -513
- package/server/services/self-healing.js +843 -843
- package/server/services/shieldlink.js +492 -0
- package/server/services/shieldqr.js +322 -322
- package/server/services/sovereign-shield.js +542 -542
- package/server/services/ssl-ct-monitor.js +224 -0
- package/server/services/ssl-inspector.js +42 -42
- package/server/services/ssl-monitor.js +167 -167
- package/server/services/stripe.js +206 -205
- package/server/services/swarm.js +788 -788
- package/server/services/transactions.js +525 -0
- package/server/services/universal-scraper.js +662 -662
- package/server/services/verification.js +481 -481
- package/server/services/vision.js +1163 -1163
- package/server/services/wab-crypto.js +178 -178
- package/server/utils/cache.js +125 -125
- package/server/utils/migrate.js +81 -81
- package/server/utils/safe-fetch.js +228 -228
- package/server/utils/secureFields.js +50 -50
- package/server/ws.js +161 -161
- package/templates/artisan-marketplace.yaml +104 -104
- package/templates/book-price-scout.yaml +98 -98
- package/templates/electronics-price-tracker.yaml +108 -108
- package/templates/flight-deal-hunter.yaml +113 -113
- package/templates/freelancer-direct.yaml +116 -116
- package/templates/grocery-price-compare.yaml +93 -93
- package/templates/hotel-direct-booking.yaml +113 -113
- package/templates/local-services.yaml +98 -98
- package/templates/olive-oil-tunisia.yaml +88 -88
- package/templates/organic-farm-fresh.yaml +101 -101
- package/templates/restaurant-direct.yaml +97 -97
- package/templates/ring4/banking-sovereign.yaml +55 -0
- package/templates/ring4/ecommerce-sovereign.yaml +58 -0
- package/templates/ring4/healthcare-sovereign.yaml +60 -0
package/public/shieldqr.html
CHANGED
|
@@ -1,231 +1,231 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>WAB ShieldQR — Scan QR codes safely</title>
|
|
7
|
-
<meta name="description" content="Scan any QR code in your browser and instantly verify the destination with WAB ShieldQR — DNS trust, Ed25519 signatures, SSL inspection.">
|
|
8
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
9
|
-
<link rel="stylesheet" href="/css/styles.css">
|
|
10
|
-
<style>
|
|
11
|
-
body { font-family: 'Inter', system-ui, sans-serif; margin:0; background:#0f172a; color:#e2e8f0; min-height:100vh; }
|
|
12
|
-
.wrap { max-width: 720px; margin: 0 auto; padding: 28px 18px 60px; }
|
|
13
|
-
h1 { font-size: 1.8rem; margin: 0 0 6px; display:flex; align-items:center; gap:10px; }
|
|
14
|
-
.sub { color:#94a3b8; margin: 0 0 22px; }
|
|
15
|
-
.card { background:#1e293b; border:1px solid #334155; border-radius:14px; padding:18px; margin-bottom:16px; }
|
|
16
|
-
#reader { width:100%; border-radius:10px; overflow:hidden; background:#000; }
|
|
17
|
-
#reader video { width:100%; max-height:60vh; }
|
|
18
|
-
.controls { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
|
|
19
|
-
.btn { padding:10px 16px; border-radius:8px; border:none; font-weight:600; cursor:pointer; font-size:.95rem; }
|
|
20
|
-
.btn-primary { background:#6366f1; color:#fff; }
|
|
21
|
-
.btn-primary:hover { background:#4f46e5; }
|
|
22
|
-
.btn-secondary { background:#334155; color:#e2e8f0; }
|
|
23
|
-
.btn-danger { background:#dc2626; color:#fff; }
|
|
24
|
-
.btn-success { background:#16a34a; color:#fff; }
|
|
25
|
-
input[type=text] { flex:1; min-width:200px; padding:10px 12px; border-radius:8px; border:1px solid #475569; background:#0f172a; color:#e2e8f0; font-size:.95rem; }
|
|
26
|
-
.verdict { padding:18px; border-radius:14px; border:2px solid; }
|
|
27
|
-
.verdict.green { border-color:#16a34a; background:rgba(22,163,74,.08); }
|
|
28
|
-
.verdict.yellow { border-color:#ca8a04; background:rgba(202,138,4,.08); }
|
|
29
|
-
.verdict.red { border-color:#dc2626; background:rgba(220,38,38,.08); }
|
|
30
|
-
.verdict h2 { margin:0 0 6px; font-size:1.4rem; }
|
|
31
|
-
.verdict .score { font-size:2.4rem; font-weight:800; }
|
|
32
|
-
.verdict .url { font-family: ui-monospace, Menlo, monospace; font-size:.85rem; word-break: break-all; color:#cbd5e1; margin: 6px 0 12px; }
|
|
33
|
-
.signals { margin-top:10px; }
|
|
34
|
-
.signal { padding:8px 10px; border-radius:8px; background:#0f172a; margin-bottom:6px; font-size:.85rem; display:flex; gap:8px; align-items:flex-start; }
|
|
35
|
-
.signal .sev { font-size:.7rem; font-weight:700; padding:1px 6px; border-radius:4px; text-transform:uppercase; flex-shrink:0; }
|
|
36
|
-
.sev-low { background:#0ea5e9; color:#fff; }
|
|
37
|
-
.sev-medium { background:#ca8a04; color:#fff; }
|
|
38
|
-
.sev-high { background:#dc2626; color:#fff; }
|
|
39
|
-
.meta { display:grid; grid-template-columns:repeat(auto-fit, minmax(140px,1fr)); gap:8px; margin-top:10px; font-size:.85rem; }
|
|
40
|
-
.meta div { background:#0f172a; padding:8px 10px; border-radius:8px; }
|
|
41
|
-
.meta .lbl { color:#94a3b8; font-size:.7rem; text-transform:uppercase; letter-spacing:.04em; }
|
|
42
|
-
.hidden { display:none !important; }
|
|
43
|
-
.footer-note { color:#64748b; font-size:.8rem; text-align:center; margin-top:30px; }
|
|
44
|
-
a { color:#a5b4fc; }
|
|
45
|
-
</style>
|
|
46
|
-
<!-- html5-qrcode loader (CSP-allowed origin) -->
|
|
47
|
-
<script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js"></script>
|
|
48
|
-
</head>
|
|
49
|
-
<body>
|
|
50
|
-
<div class="wrap">
|
|
51
|
-
<h1>🛡️ WAB ShieldQR</h1>
|
|
52
|
-
<p class="sub">Scan any QR code in your browser. We verify the destination with DNS trust records, Ed25519 signatures, and live SSL inspection — <strong>before</strong> you ever open the link.</p>
|
|
53
|
-
|
|
54
|
-
<div class="card">
|
|
55
|
-
<div id="reader"></div>
|
|
56
|
-
<div class="controls">
|
|
57
|
-
<button id="startCam" class="btn btn-primary">📷 Start camera</button>
|
|
58
|
-
<button id="stopCam" class="btn btn-secondary hidden">⏹ Stop</button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div class="card">
|
|
63
|
-
<strong>Or paste a URL manually:</strong>
|
|
64
|
-
<div class="controls" style="margin-top:8px;">
|
|
65
|
-
<input id="manualUrl" type="text" placeholder="https://example.com/...">
|
|
66
|
-
<button id="manualScan" class="btn btn-primary">Verify</button>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div id="result" class="card hidden"></div>
|
|
71
|
-
|
|
72
|
-
<p class="footer-note">
|
|
73
|
-
Powered by <a href="/">Web Agent Bridge</a> · ShieldQR is open and free for everyone ·
|
|
74
|
-
<a href="/api/shieldqr/recent" target="_blank">Recent scans</a>
|
|
75
|
-
</p>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<script>
|
|
79
|
-
(function () {
|
|
80
|
-
const el = (id) => document.getElementById(id);
|
|
81
|
-
const H = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) =>
|
|
82
|
-
({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
83
|
-
|
|
84
|
-
let scanner = null; let lastResult = null;
|
|
85
|
-
|
|
86
|
-
function startCamera() {
|
|
87
|
-
if (typeof Html5Qrcode === 'undefined') {
|
|
88
|
-
alert('QR library failed to load. Check your network or use the manual URL field.');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
el('startCam').classList.add('hidden');
|
|
92
|
-
el('stopCam').classList.remove('hidden');
|
|
93
|
-
scanner = new Html5Qrcode('reader');
|
|
94
|
-
scanner.start(
|
|
95
|
-
{ facingMode: 'environment' },
|
|
96
|
-
{ fps: 10, qrbox: { width: 260, height: 260 } },
|
|
97
|
-
(decodedText) => {
|
|
98
|
-
scanner.stop().catch(() => {});
|
|
99
|
-
el('startCam').classList.remove('hidden');
|
|
100
|
-
el('stopCam').classList.add('hidden');
|
|
101
|
-
verify(decodedText);
|
|
102
|
-
},
|
|
103
|
-
() => {} // ignore per-frame errors
|
|
104
|
-
).catch((err) => {
|
|
105
|
-
alert('Camera error: ' + err);
|
|
106
|
-
el('startCam').classList.remove('hidden');
|
|
107
|
-
el('stopCam').classList.add('hidden');
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function stopCamera() {
|
|
112
|
-
if (!scanner) return;
|
|
113
|
-
scanner.stop().catch(() => {}).finally(() => {
|
|
114
|
-
el('startCam').classList.remove('hidden');
|
|
115
|
-
el('stopCam').classList.add('hidden');
|
|
116
|
-
scanner = null;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function verify(url) {
|
|
121
|
-
const result = el('result');
|
|
122
|
-
result.classList.remove('hidden');
|
|
123
|
-
result.innerHTML = '<div style="text-align:center;padding:20px;">⏳ Verifying <strong>' + H(url) + '</strong>…</div>';
|
|
124
|
-
try {
|
|
125
|
-
const r = await fetch('/api/shieldqr/scan', {
|
|
126
|
-
method: 'POST',
|
|
127
|
-
headers: { 'Content-Type': 'application/json' },
|
|
128
|
-
body: JSON.stringify({ url }),
|
|
129
|
-
});
|
|
130
|
-
const data = await r.json();
|
|
131
|
-
if (!r.ok) throw new Error(data.error || 'scan failed');
|
|
132
|
-
lastResult = data;
|
|
133
|
-
renderVerdict(data, url);
|
|
134
|
-
} catch (err) {
|
|
135
|
-
result.innerHTML = '<div style="color:#fca5a5;text-align:center;padding:20px;">❌ ' + H(err.message) + '</div>';
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function renderVerdict(d, url) {
|
|
140
|
-
const lvl = d.level || 'yellow';
|
|
141
|
-
const icon = { green: '✅', yellow: '⚠️', red: '🛑' }[lvl] || '⚠️';
|
|
142
|
-
const headline = { green: 'Safe — verified', yellow: 'Caution — incomplete trust', red: 'Dangerous — do not open' }[lvl];
|
|
143
|
-
const sslDays = d.ssl && d.ssl.days_until_expiry != null ? d.ssl.days_until_expiry : '—';
|
|
144
|
-
const trustOk = d.trust && d.trust.ok ? '✅ Signed' : '—';
|
|
145
|
-
const dnsOk = d.dns && Array.isArray(d.dns.discovery) && d.dns.discovery.length ? '✅ Present' : '—';
|
|
146
|
-
const signals = (d.signals || []).map((s) => `
|
|
147
|
-
<div class="signal">
|
|
148
|
-
<span class="sev sev-${H(s.severity || 'low')}">${H(s.severity || 'low')}</span>
|
|
149
|
-
<div><strong>${H(s.id || '')}</strong> — ${H(s.message || '')}</div>
|
|
150
|
-
</div>
|
|
151
|
-
`).join('') || '<div class="signal"><span class="sev sev-low">ok</span><div>No signals raised.</div></div>';
|
|
152
|
-
|
|
153
|
-
const openBtn = lvl === 'green'
|
|
154
|
-
? `<a class="btn btn-success" href="${H(url)}" target="_blank" rel="noopener noreferrer">Open destination →</a>`
|
|
155
|
-
: `<button class="btn btn-danger" data-action="forceOpen">Open anyway (risky)</button>`;
|
|
156
|
-
|
|
157
|
-
el('result').innerHTML = `
|
|
158
|
-
<div class="verdict ${H(lvl)}">
|
|
159
|
-
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:14px;flex-wrap:wrap;">
|
|
160
|
-
<div>
|
|
161
|
-
<h2>${icon} ${H(headline)}</h2>
|
|
162
|
-
<div class="url">${H(url)}</div>
|
|
163
|
-
</div>
|
|
164
|
-
<div style="text-align:right;">
|
|
165
|
-
<div class="score">${d.score ?? '—'}</div>
|
|
166
|
-
<div style="font-size:.7rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.05em;">score / 100</div>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
<div class="meta">
|
|
171
|
-
<div><div class="lbl">Host</div>${H(d.host || '—')}</div>
|
|
172
|
-
<div><div class="lbl">DNS _wab</div>${dnsOk}</div>
|
|
173
|
-
<div><div class="lbl">Signed wab.json</div>${trustOk}</div>
|
|
174
|
-
<div><div class="lbl">SSL valid for</div>${sslDays} days</div>
|
|
175
|
-
</div>
|
|
176
|
-
|
|
177
|
-
<div class="signals">${signals}</div>
|
|
178
|
-
|
|
179
|
-
<div class="controls" style="margin-top:14px;">
|
|
180
|
-
${openBtn}
|
|
181
|
-
<button class="btn btn-secondary" data-action="rescan">Scan another</button>
|
|
182
|
-
<button class="btn btn-danger" data-action="report">Report this URL</button>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
el('result').querySelector('[data-action="rescan"]').addEventListener('click', () => {
|
|
188
|
-
el('result').classList.add('hidden');
|
|
189
|
-
el('manualUrl').value = '';
|
|
190
|
-
});
|
|
191
|
-
const forceBtn = el('result').querySelector('[data-action="forceOpen"]');
|
|
192
|
-
if (forceBtn) {
|
|
193
|
-
forceBtn.addEventListener('click', () => {
|
|
194
|
-
if (confirm('This site has not been verified as safe. Open anyway?')) {
|
|
195
|
-
window.open(url, '_blank', 'noopener,noreferrer');
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
el('result').querySelector('[data-action="report"]').addEventListener('click', () => reportUrl(url));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async function reportUrl(url) {
|
|
203
|
-
const reason = prompt('Why are you reporting this URL? (e.g. phishing, malware, scam)');
|
|
204
|
-
if (!reason || reason.trim().length < 4) return;
|
|
205
|
-
try {
|
|
206
|
-
const r = await fetch('/api/shieldqr/report', {
|
|
207
|
-
method: 'POST',
|
|
208
|
-
headers: { 'Content-Type': 'application/json' },
|
|
209
|
-
body: JSON.stringify({ url, reason: reason.trim(), scan_id: lastResult && lastResult.scan_id }),
|
|
210
|
-
});
|
|
211
|
-
const data = await r.json();
|
|
212
|
-
if (!r.ok) throw new Error(data.error || 'report failed');
|
|
213
|
-
alert('Thank you — your report has been submitted.');
|
|
214
|
-
} catch (err) {
|
|
215
|
-
alert('Report failed: ' + err.message);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
el('startCam').addEventListener('click', startCamera);
|
|
220
|
-
el('stopCam').addEventListener('click', stopCamera);
|
|
221
|
-
el('manualScan').addEventListener('click', () => {
|
|
222
|
-
const u = el('manualUrl').value.trim();
|
|
223
|
-
if (u) verify(u);
|
|
224
|
-
});
|
|
225
|
-
el('manualUrl').addEventListener('keydown', (e) => {
|
|
226
|
-
if (e.key === 'Enter') { e.preventDefault(); el('manualScan').click(); }
|
|
227
|
-
});
|
|
228
|
-
})();
|
|
229
|
-
</script>
|
|
230
|
-
</body>
|
|
231
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>WAB ShieldQR — Scan QR codes safely</title>
|
|
7
|
+
<meta name="description" content="Scan any QR code in your browser and instantly verify the destination with WAB ShieldQR — DNS trust, Ed25519 signatures, SSL inspection.">
|
|
8
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
9
|
+
<link rel="stylesheet" href="/css/styles.css">
|
|
10
|
+
<style>
|
|
11
|
+
body { font-family: 'Inter', system-ui, sans-serif; margin:0; background:#0f172a; color:#e2e8f0; min-height:100vh; }
|
|
12
|
+
.wrap { max-width: 720px; margin: 0 auto; padding: 28px 18px 60px; }
|
|
13
|
+
h1 { font-size: 1.8rem; margin: 0 0 6px; display:flex; align-items:center; gap:10px; }
|
|
14
|
+
.sub { color:#94a3b8; margin: 0 0 22px; }
|
|
15
|
+
.card { background:#1e293b; border:1px solid #334155; border-radius:14px; padding:18px; margin-bottom:16px; }
|
|
16
|
+
#reader { width:100%; border-radius:10px; overflow:hidden; background:#000; }
|
|
17
|
+
#reader video { width:100%; max-height:60vh; }
|
|
18
|
+
.controls { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
|
|
19
|
+
.btn { padding:10px 16px; border-radius:8px; border:none; font-weight:600; cursor:pointer; font-size:.95rem; }
|
|
20
|
+
.btn-primary { background:#6366f1; color:#fff; }
|
|
21
|
+
.btn-primary:hover { background:#4f46e5; }
|
|
22
|
+
.btn-secondary { background:#334155; color:#e2e8f0; }
|
|
23
|
+
.btn-danger { background:#dc2626; color:#fff; }
|
|
24
|
+
.btn-success { background:#16a34a; color:#fff; }
|
|
25
|
+
input[type=text] { flex:1; min-width:200px; padding:10px 12px; border-radius:8px; border:1px solid #475569; background:#0f172a; color:#e2e8f0; font-size:.95rem; }
|
|
26
|
+
.verdict { padding:18px; border-radius:14px; border:2px solid; }
|
|
27
|
+
.verdict.green { border-color:#16a34a; background:rgba(22,163,74,.08); }
|
|
28
|
+
.verdict.yellow { border-color:#ca8a04; background:rgba(202,138,4,.08); }
|
|
29
|
+
.verdict.red { border-color:#dc2626; background:rgba(220,38,38,.08); }
|
|
30
|
+
.verdict h2 { margin:0 0 6px; font-size:1.4rem; }
|
|
31
|
+
.verdict .score { font-size:2.4rem; font-weight:800; }
|
|
32
|
+
.verdict .url { font-family: ui-monospace, Menlo, monospace; font-size:.85rem; word-break: break-all; color:#cbd5e1; margin: 6px 0 12px; }
|
|
33
|
+
.signals { margin-top:10px; }
|
|
34
|
+
.signal { padding:8px 10px; border-radius:8px; background:#0f172a; margin-bottom:6px; font-size:.85rem; display:flex; gap:8px; align-items:flex-start; }
|
|
35
|
+
.signal .sev { font-size:.7rem; font-weight:700; padding:1px 6px; border-radius:4px; text-transform:uppercase; flex-shrink:0; }
|
|
36
|
+
.sev-low { background:#0ea5e9; color:#fff; }
|
|
37
|
+
.sev-medium { background:#ca8a04; color:#fff; }
|
|
38
|
+
.sev-high { background:#dc2626; color:#fff; }
|
|
39
|
+
.meta { display:grid; grid-template-columns:repeat(auto-fit, minmax(140px,1fr)); gap:8px; margin-top:10px; font-size:.85rem; }
|
|
40
|
+
.meta div { background:#0f172a; padding:8px 10px; border-radius:8px; }
|
|
41
|
+
.meta .lbl { color:#94a3b8; font-size:.7rem; text-transform:uppercase; letter-spacing:.04em; }
|
|
42
|
+
.hidden { display:none !important; }
|
|
43
|
+
.footer-note { color:#64748b; font-size:.8rem; text-align:center; margin-top:30px; }
|
|
44
|
+
a { color:#a5b4fc; }
|
|
45
|
+
</style>
|
|
46
|
+
<!-- html5-qrcode loader (CSP-allowed origin) -->
|
|
47
|
+
<script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js"></script>
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div class="wrap">
|
|
51
|
+
<h1>🛡️ WAB ShieldQR</h1>
|
|
52
|
+
<p class="sub">Scan any QR code in your browser. We verify the destination with DNS trust records, Ed25519 signatures, and live SSL inspection — <strong>before</strong> you ever open the link.</p>
|
|
53
|
+
|
|
54
|
+
<div class="card">
|
|
55
|
+
<div id="reader"></div>
|
|
56
|
+
<div class="controls">
|
|
57
|
+
<button id="startCam" class="btn btn-primary">📷 Start camera</button>
|
|
58
|
+
<button id="stopCam" class="btn btn-secondary hidden">⏹ Stop</button>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="card">
|
|
63
|
+
<strong>Or paste a URL manually:</strong>
|
|
64
|
+
<div class="controls" style="margin-top:8px;">
|
|
65
|
+
<input id="manualUrl" type="text" placeholder="https://example.com/...">
|
|
66
|
+
<button id="manualScan" class="btn btn-primary">Verify</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div id="result" class="card hidden"></div>
|
|
71
|
+
|
|
72
|
+
<p class="footer-note">
|
|
73
|
+
Powered by <a href="/">Web Agent Bridge</a> · ShieldQR is open and free for everyone ·
|
|
74
|
+
<a href="/api/shieldqr/recent" target="_blank">Recent scans</a>
|
|
75
|
+
</p>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
(function () {
|
|
80
|
+
const el = (id) => document.getElementById(id);
|
|
81
|
+
const H = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) =>
|
|
82
|
+
({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
83
|
+
|
|
84
|
+
let scanner = null; let lastResult = null;
|
|
85
|
+
|
|
86
|
+
function startCamera() {
|
|
87
|
+
if (typeof Html5Qrcode === 'undefined') {
|
|
88
|
+
alert('QR library failed to load. Check your network or use the manual URL field.');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
el('startCam').classList.add('hidden');
|
|
92
|
+
el('stopCam').classList.remove('hidden');
|
|
93
|
+
scanner = new Html5Qrcode('reader');
|
|
94
|
+
scanner.start(
|
|
95
|
+
{ facingMode: 'environment' },
|
|
96
|
+
{ fps: 10, qrbox: { width: 260, height: 260 } },
|
|
97
|
+
(decodedText) => {
|
|
98
|
+
scanner.stop().catch(() => {});
|
|
99
|
+
el('startCam').classList.remove('hidden');
|
|
100
|
+
el('stopCam').classList.add('hidden');
|
|
101
|
+
verify(decodedText);
|
|
102
|
+
},
|
|
103
|
+
() => {} // ignore per-frame errors
|
|
104
|
+
).catch((err) => {
|
|
105
|
+
alert('Camera error: ' + err);
|
|
106
|
+
el('startCam').classList.remove('hidden');
|
|
107
|
+
el('stopCam').classList.add('hidden');
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function stopCamera() {
|
|
112
|
+
if (!scanner) return;
|
|
113
|
+
scanner.stop().catch(() => {}).finally(() => {
|
|
114
|
+
el('startCam').classList.remove('hidden');
|
|
115
|
+
el('stopCam').classList.add('hidden');
|
|
116
|
+
scanner = null;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function verify(url) {
|
|
121
|
+
const result = el('result');
|
|
122
|
+
result.classList.remove('hidden');
|
|
123
|
+
result.innerHTML = '<div style="text-align:center;padding:20px;">⏳ Verifying <strong>' + H(url) + '</strong>…</div>';
|
|
124
|
+
try {
|
|
125
|
+
const r = await fetch('/api/shieldqr/scan', {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: { 'Content-Type': 'application/json' },
|
|
128
|
+
body: JSON.stringify({ url }),
|
|
129
|
+
});
|
|
130
|
+
const data = await r.json();
|
|
131
|
+
if (!r.ok) throw new Error(data.error || 'scan failed');
|
|
132
|
+
lastResult = data;
|
|
133
|
+
renderVerdict(data, url);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
result.innerHTML = '<div style="color:#fca5a5;text-align:center;padding:20px;">❌ ' + H(err.message) + '</div>';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function renderVerdict(d, url) {
|
|
140
|
+
const lvl = d.level || 'yellow';
|
|
141
|
+
const icon = { green: '✅', yellow: '⚠️', red: '🛑' }[lvl] || '⚠️';
|
|
142
|
+
const headline = { green: 'Safe — verified', yellow: 'Caution — incomplete trust', red: 'Dangerous — do not open' }[lvl];
|
|
143
|
+
const sslDays = d.ssl && d.ssl.days_until_expiry != null ? d.ssl.days_until_expiry : '—';
|
|
144
|
+
const trustOk = d.trust && d.trust.ok ? '✅ Signed' : '—';
|
|
145
|
+
const dnsOk = d.dns && Array.isArray(d.dns.discovery) && d.dns.discovery.length ? '✅ Present' : '—';
|
|
146
|
+
const signals = (d.signals || []).map((s) => `
|
|
147
|
+
<div class="signal">
|
|
148
|
+
<span class="sev sev-${H(s.severity || 'low')}">${H(s.severity || 'low')}</span>
|
|
149
|
+
<div><strong>${H(s.id || '')}</strong> — ${H(s.message || '')}</div>
|
|
150
|
+
</div>
|
|
151
|
+
`).join('') || '<div class="signal"><span class="sev sev-low">ok</span><div>No signals raised.</div></div>';
|
|
152
|
+
|
|
153
|
+
const openBtn = lvl === 'green'
|
|
154
|
+
? `<a class="btn btn-success" href="${H(url)}" target="_blank" rel="noopener noreferrer">Open destination →</a>`
|
|
155
|
+
: `<button class="btn btn-danger" data-action="forceOpen">Open anyway (risky)</button>`;
|
|
156
|
+
|
|
157
|
+
el('result').innerHTML = `
|
|
158
|
+
<div class="verdict ${H(lvl)}">
|
|
159
|
+
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:14px;flex-wrap:wrap;">
|
|
160
|
+
<div>
|
|
161
|
+
<h2>${icon} ${H(headline)}</h2>
|
|
162
|
+
<div class="url">${H(url)}</div>
|
|
163
|
+
</div>
|
|
164
|
+
<div style="text-align:right;">
|
|
165
|
+
<div class="score">${d.score ?? '—'}</div>
|
|
166
|
+
<div style="font-size:.7rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.05em;">score / 100</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div class="meta">
|
|
171
|
+
<div><div class="lbl">Host</div>${H(d.host || '—')}</div>
|
|
172
|
+
<div><div class="lbl">DNS _wab</div>${dnsOk}</div>
|
|
173
|
+
<div><div class="lbl">Signed wab.json</div>${trustOk}</div>
|
|
174
|
+
<div><div class="lbl">SSL valid for</div>${sslDays} days</div>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div class="signals">${signals}</div>
|
|
178
|
+
|
|
179
|
+
<div class="controls" style="margin-top:14px;">
|
|
180
|
+
${openBtn}
|
|
181
|
+
<button class="btn btn-secondary" data-action="rescan">Scan another</button>
|
|
182
|
+
<button class="btn btn-danger" data-action="report">Report this URL</button>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
`;
|
|
186
|
+
|
|
187
|
+
el('result').querySelector('[data-action="rescan"]').addEventListener('click', () => {
|
|
188
|
+
el('result').classList.add('hidden');
|
|
189
|
+
el('manualUrl').value = '';
|
|
190
|
+
});
|
|
191
|
+
const forceBtn = el('result').querySelector('[data-action="forceOpen"]');
|
|
192
|
+
if (forceBtn) {
|
|
193
|
+
forceBtn.addEventListener('click', () => {
|
|
194
|
+
if (confirm('This site has not been verified as safe. Open anyway?')) {
|
|
195
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
el('result').querySelector('[data-action="report"]').addEventListener('click', () => reportUrl(url));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function reportUrl(url) {
|
|
203
|
+
const reason = prompt('Why are you reporting this URL? (e.g. phishing, malware, scam)');
|
|
204
|
+
if (!reason || reason.trim().length < 4) return;
|
|
205
|
+
try {
|
|
206
|
+
const r = await fetch('/api/shieldqr/report', {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: { 'Content-Type': 'application/json' },
|
|
209
|
+
body: JSON.stringify({ url, reason: reason.trim(), scan_id: lastResult && lastResult.scan_id }),
|
|
210
|
+
});
|
|
211
|
+
const data = await r.json();
|
|
212
|
+
if (!r.ok) throw new Error(data.error || 'report failed');
|
|
213
|
+
alert('Thank you — your report has been submitted.');
|
|
214
|
+
} catch (err) {
|
|
215
|
+
alert('Report failed: ' + err.message);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
el('startCam').addEventListener('click', startCamera);
|
|
220
|
+
el('stopCam').addEventListener('click', stopCamera);
|
|
221
|
+
el('manualScan').addEventListener('click', () => {
|
|
222
|
+
const u = el('manualUrl').value.trim();
|
|
223
|
+
if (u) verify(u);
|
|
224
|
+
});
|
|
225
|
+
el('manualUrl').addEventListener('keydown', (e) => {
|
|
226
|
+
if (e.key === 'Enter') { e.preventDefault(); el('manualScan').click(); }
|
|
227
|
+
});
|
|
228
|
+
})();
|
|
229
|
+
</script>
|
|
230
|
+
</body>
|
|
231
|
+
</html>
|
package/public/sitemap.xml
CHANGED
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3
3
|
<url>
|
|
4
4
|
<loc>https://webagentbridge.com/</loc>
|
|
5
|
-
<lastmod>2026-
|
|
5
|
+
<lastmod>2026-05-13</lastmod>
|
|
6
6
|
<changefreq>weekly</changefreq>
|
|
7
7
|
<priority>1.0</priority>
|
|
8
8
|
</url>
|
|
9
|
+
<url>
|
|
10
|
+
<loc>https://webagentbridge.com/ring4</loc>
|
|
11
|
+
<lastmod>2026-05-13</lastmod>
|
|
12
|
+
<changefreq>weekly</changefreq>
|
|
13
|
+
<priority>0.95</priority>
|
|
14
|
+
</url>
|
|
15
|
+
<url>
|
|
16
|
+
<loc>https://webagentbridge.com/milestones</loc>
|
|
17
|
+
<lastmod>2026-05-13</lastmod>
|
|
18
|
+
<changefreq>weekly</changefreq>
|
|
19
|
+
<priority>0.9</priority>
|
|
20
|
+
</url>
|
|
9
21
|
<url>
|
|
10
22
|
<loc>https://webagentbridge.com/docs</loc>
|
|
11
23
|
<lastmod>2026-03-28</lastmod>
|