web-agent-bridge 3.16.0 → 3.20.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.
Files changed (61) hide show
  1. package/README.ar.md +27 -8
  2. package/README.md +95 -0
  3. package/bin/wab-init.js +38 -0
  4. package/package.json +1 -1
  5. package/public/atp-semantics.html +216 -0
  6. package/public/benchmarks.html +151 -0
  7. package/public/dashboard.html +1 -0
  8. package/public/docs.html +113 -43
  9. package/public/index.html +142 -8
  10. package/public/key-rotation.html +184 -0
  11. package/public/llms.txt +54 -0
  12. package/public/notary.html +94 -0
  13. package/public/observatory.html +103 -0
  14. package/public/research.html +57 -0
  15. package/public/researchers.html +113 -0
  16. package/public/responsible-disclosure.html +294 -0
  17. package/public/robots.txt +17 -0
  18. package/public/security.html +157 -0
  19. package/public/threat-model.html +153 -0
  20. package/public/viral-coefficient.html +533 -0
  21. package/public/wab-dataset.html +501 -0
  22. package/public/wab-email.html +78 -0
  23. package/public/wab-lens.html +61 -0
  24. package/public/wab-p2p.html +96 -0
  25. package/public/wab-registry.html +481 -0
  26. package/public/wab-today.html +448 -0
  27. package/public/wab-uri.html +88 -0
  28. package/public/webhooks.html +181 -0
  29. package/script/ai-agent-bridge.js +24 -4
  30. package/server/index.js +1193 -827
  31. package/server/models/db.js +2 -1
  32. package/server/routes/admin-shieldlink.js +1 -1
  33. package/server/routes/admin-shieldqr.js +1 -1
  34. package/server/routes/admin-trust-monitor.js +1 -1
  35. package/server/routes/api-keys.js +2 -1
  36. package/server/routes/customer-shieldlink.js +1 -1
  37. package/server/routes/enterprise-mesh.js +2 -1
  38. package/server/routes/genius-bridge.js +256 -0
  39. package/server/routes/genius-gateway.js +137 -0
  40. package/server/routes/governance-saas.js +2 -1
  41. package/server/routes/notary.js +309 -0
  42. package/server/routes/observatory.js +109 -0
  43. package/server/routes/partners.js +2 -1
  44. package/server/routes/registry.js +352 -0
  45. package/server/routes/research.js +83 -0
  46. package/server/routes/ring4.js +2 -1
  47. package/server/routes/runtime.js +98 -25
  48. package/server/routes/security-researchers.js +161 -0
  49. package/server/routes/shieldqr.js +1 -1
  50. package/server/routes/traces.js +247 -0
  51. package/server/services/agent-tasks.js +9 -7
  52. package/server/services/email.js +50 -2
  53. package/server/services/marketplace.js +27 -8
  54. package/server/services/plans.js +1 -1
  55. package/server/services/shieldlink.js +1 -1
  56. package/server/services/ssl-ct-monitor.js +1 -1
  57. package/server/services/ssl-monitor.js +1 -1
  58. package/server/services/stripe.js +29 -4
  59. package/server/services/webhooks.js +61 -1
  60. package/server/utils/migrate.js +1 -1
  61. package/server/utils/safe-compare.js +26 -0
@@ -0,0 +1,181 @@
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" />
6
+ <title>Webhooks · Web Agent Bridge</title>
7
+ <link rel="stylesheet" href="/css/dashboard.css" />
8
+ <style>
9
+ body { background: #f7f8fa; color: #111; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; }
10
+ .wrap { max-width: 980px; margin: 0 auto; padding: 32px 24px; }
11
+ h1 { margin: 0 0 8px; font-size: 28px; }
12
+ .lede { color: #555; margin: 0 0 28px; }
13
+ .card { background: #fff; border: 1px solid #e6e7ea; border-radius: 12px; padding: 20px; margin-bottom: 20px; box-shadow: 0 1px 2px rgba(0,0,0,.03); }
14
+ .row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
15
+ input, select, button { font: inherit; padding: 9px 12px; border-radius: 8px; border: 1px solid #cfd1d6; background: #fff; }
16
+ input { flex: 1 1 280px; min-width: 240px; }
17
+ button { background: #111; color: #fff; border-color: #111; cursor: pointer; }
18
+ button.ghost { background: #fff; color: #111; }
19
+ button.danger { background: #c0392b; border-color: #c0392b; }
20
+ table { width: 100%; border-collapse: collapse; }
21
+ th, td { padding: 10px 8px; text-align: left; border-bottom: 1px solid #eee; font-size: 14px; vertical-align: top; }
22
+ th { color: #666; font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .03em; }
23
+ code, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
24
+ .pill { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; }
25
+ .pill.ok { background: #e7f6ee; color: #146c43; }
26
+ .pill.off { background: #fdecea; color: #b71c1c; }
27
+ .pill.warn { background: #fff4e5; color: #8a5a00; }
28
+ .secret-box { background: #fff8e1; border: 1px solid #f1d27a; border-radius: 8px; padding: 12px; margin: 10px 0; }
29
+ .muted { color: #777; font-size: 13px; }
30
+ details summary { cursor: pointer; color: #2563eb; font-size: 13px; }
31
+ .empty { text-align: center; color: #888; padding: 28px; }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ <div class="wrap">
36
+ <h1>Webhooks</h1>
37
+ <p class="lede">Subscribe to instant push notifications for revocation events. Each payload is HMAC-signed with your subscription secret and Ed25519-signed by the operator.</p>
38
+
39
+ <div class="card">
40
+ <h3 style="margin-top:0">Create subscription</h3>
41
+ <form id="createForm" class="row" autocomplete="off">
42
+ <input id="urlInput" type="url" placeholder="https://your-endpoint/webhooks" required />
43
+ <input id="descInput" type="text" placeholder="Optional description" style="flex: 0 1 220px" />
44
+ <button type="submit">Subscribe</button>
45
+ </form>
46
+ <p class="muted" style="margin: 10px 0 0">Receives <code>revocation.opened</code>, <code>revocation.reinstated</code>, <code>revocation.appeal_decided</code>. <a href="/api/webhooks/events" target="_blank">View events</a> · <a href="/api/operator-key.json" target="_blank">Operator public key</a></p>
47
+ <div id="secretBox" class="secret-box" style="display:none"></div>
48
+ </div>
49
+
50
+ <div class="card">
51
+ <div class="row" style="justify-content: space-between; margin-bottom: 12px">
52
+ <h3 style="margin: 0">Your subscriptions</h3>
53
+ <button class="ghost" onclick="loadSubs()">Refresh</button>
54
+ </div>
55
+ <table>
56
+ <thead><tr><th>URL</th><th>Events</th><th>Status</th><th>Last result</th><th></th></tr></thead>
57
+ <tbody id="subsBody"><tr><td colspan="5" class="empty">Loading…</td></tr></tbody>
58
+ </table>
59
+ </div>
60
+
61
+ <div class="card">
62
+ <h3 style="margin-top:0">Verifying a delivery</h3>
63
+ <p class="muted">Every request carries two signatures:</p>
64
+ <ol class="muted" style="line-height: 1.7">
65
+ <li><strong>HMAC-SHA256</strong> per subscription — header <code>X-WAB-Webhook-Signature: t=&lt;unix&gt;,v1=&lt;hex&gt;</code>. Recompute over <code>${'`${t}.${rawBody}`'}</code> with your secret.</li>
66
+ <li><strong>Ed25519 operator signature</strong> — header <code>X-WAB-Operator-Signature</code> + embedded <code>signature.value</code>. Fetch the public key at <code>/api/operator-key.json</code> and verify over the RFC 8785 canonicalisation of the envelope minus the <code>signature</code> field.</li>
67
+ </ol>
68
+ </div>
69
+ </div>
70
+
71
+ <script>
72
+ const TOKEN = localStorage.getItem('wab_token');
73
+ if (!TOKEN) { location.href = '/login.html?next=/webhooks.html'; }
74
+
75
+ const H = { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json' };
76
+
77
+ async function api(method, path, body) {
78
+ const opts = { method, headers: H };
79
+ if (body !== undefined) opts.body = JSON.stringify(body);
80
+ const r = await fetch(path, opts);
81
+ const j = await r.json().catch(() => ({}));
82
+ if (!r.ok) throw new Error(j.message || j.error || `HTTP ${r.status}`);
83
+ return j.data;
84
+ }
85
+
86
+ function escape(s) {
87
+ return String(s == null ? '' : s).replace(/[&<>"]/g, (c) => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;' })[c]);
88
+ }
89
+
90
+ function pill(active, lastError) {
91
+ if (!active) return '<span class="pill off">disabled</span>';
92
+ if (lastError) return '<span class="pill warn">warning</span>';
93
+ return '<span class="pill ok">active</span>';
94
+ }
95
+
96
+ async function loadSubs() {
97
+ const body = document.getElementById('subsBody');
98
+ body.innerHTML = '<tr><td colspan="5" class="empty">Loading…</td></tr>';
99
+ try {
100
+ const subs = await api('GET', '/api/webhooks');
101
+ if (!subs.length) {
102
+ body.innerHTML = '<tr><td colspan="5" class="empty">No subscriptions yet.</td></tr>';
103
+ return;
104
+ }
105
+ body.innerHTML = subs.map((s) => `
106
+ <tr>
107
+ <td><div class="mono">${escape(s.url)}</div>${s.description ? `<div class="muted">${escape(s.description)}</div>` : ''}</td>
108
+ <td><div class="muted">${s.events.map(escape).join('<br>')}</div></td>
109
+ <td>${pill(s.active, s.last_error)}</td>
110
+ <td>
111
+ ${s.last_success_at ? `<div class="muted">ok: ${escape(s.last_success_at)}</div>` : ''}
112
+ ${s.last_error_at ? `<div class="muted">err: ${escape(s.last_error_at)}</div>` : ''}
113
+ ${s.consecutive_failures ? `<div class="muted">${s.consecutive_failures} consecutive failures</div>` : ''}
114
+ </td>
115
+ <td style="text-align:right; white-space: nowrap">
116
+ <button class="ghost" onclick="toggle('${s.id}', ${!s.active})">${s.active ? 'Pause' : 'Resume'}</button>
117
+ <button class="ghost" onclick="showDeliveries('${s.id}')">Deliveries</button>
118
+ <button class="danger" onclick="del('${s.id}')">Delete</button>
119
+ </td>
120
+ </tr>
121
+ <tr id="deliv-${s.id}" style="display:none"><td colspan="5"><div id="deliv-body-${s.id}" class="muted">Loading deliveries…</div></td></tr>
122
+ `).join('');
123
+ } catch (e) {
124
+ body.innerHTML = `<tr><td colspan="5" class="empty">Error: ${escape(e.message)}</td></tr>`;
125
+ }
126
+ }
127
+
128
+ async function showDeliveries(id) {
129
+ const row = document.getElementById('deliv-' + id);
130
+ const target = document.getElementById('deliv-body-' + id);
131
+ if (row.style.display === 'table-row') { row.style.display = 'none'; return; }
132
+ row.style.display = 'table-row';
133
+ try {
134
+ const list = await api('GET', `/api/webhooks/${id}/deliveries?limit=20`);
135
+ if (!list.length) { target.innerHTML = 'No deliveries yet.'; return; }
136
+ target.innerHTML = '<table>' +
137
+ '<thead><tr><th>Event</th><th>Status</th><th>Attempts</th><th>Code</th><th>When</th><th>Error</th></tr></thead><tbody>' +
138
+ list.map((d) => `<tr>
139
+ <td class="mono">${escape(d.event_type)}</td>
140
+ <td>${escape(d.status)}</td>
141
+ <td>${d.attempts}</td>
142
+ <td>${d.last_status_code || ''}</td>
143
+ <td class="muted">${escape(d.delivered_at || d.created_at)}</td>
144
+ <td class="muted" style="max-width: 320px; word-break: break-word">${escape(d.last_error || '')}</td>
145
+ </tr>`).join('') + '</tbody></table>';
146
+ } catch (e) {
147
+ target.innerHTML = 'Error: ' + escape(e.message);
148
+ }
149
+ }
150
+
151
+ async function toggle(id, active) {
152
+ try { await api('PATCH', '/api/webhooks/' + id, { active }); loadSubs(); }
153
+ catch (e) { alert(e.message); }
154
+ }
155
+
156
+ async function del(id) {
157
+ if (!confirm('Delete this subscription?')) return;
158
+ try { await api('DELETE', '/api/webhooks/' + id); loadSubs(); }
159
+ catch (e) { alert(e.message); }
160
+ }
161
+
162
+ document.getElementById('createForm').addEventListener('submit', async (ev) => {
163
+ ev.preventDefault();
164
+ const url = document.getElementById('urlInput').value.trim();
165
+ const description = document.getElementById('descInput').value.trim() || null;
166
+ try {
167
+ const sub = await api('POST', '/api/webhooks', { url, description });
168
+ const box = document.getElementById('secretBox');
169
+ box.style.display = 'block';
170
+ box.innerHTML = '<strong>Subscription created.</strong> Save this secret now — it will not be shown again:' +
171
+ `<div class="mono" style="margin-top:8px; word-break: break-all; user-select: all">${escape(sub.secret)}</div>`;
172
+ document.getElementById('urlInput').value = '';
173
+ document.getElementById('descInput').value = '';
174
+ loadSubs();
175
+ } catch (e) { alert(e.message); }
176
+ });
177
+
178
+ loadSubs();
179
+ </script>
180
+ </body>
181
+ </html>
@@ -1,8 +1,19 @@
1
1
  /**
2
- * Web Agent Bridge v2.0.0
3
- * Open-source middleware for AI agent ↔ website interaction
4
- * https://github.com/web-agent-bridge
5
- * License: MIT
2
+ * Web Agent Bridge — Legacy v1/v2 Browser Bridge (window.AIBridgeConfig)
3
+ *
4
+ * @status legacy
5
+ * @since 2.0.0
6
+ * @deprecated 3.0.0 Prefer the modern WAB protocol surface:
7
+ * • wab.json manifest — https://webagentbridge.com/docs#wab-json
8
+ * • DNS TXT discovery — _wab.<domain>
9
+ * • ATP (signed intents) — https://webagentbridge.com/atp-semantics
10
+ * • Security / threat model — https://webagentbridge.com/security
11
+ *
12
+ * This file remains fully supported for backward compatibility. The
13
+ * `window.AIBridgeConfig` + `licenseKey` model is NOT recommended for new
14
+ * integrations; it predates the discovery + trust + transaction model.
15
+ *
16
+ * License: MIT — https://github.com/web-agent-bridge
6
17
  */
7
18
  (function (global) {
8
19
  'use strict';
@@ -10,6 +21,15 @@
10
21
  const VERSION = '2.2.0';
11
22
  const LICENSING_SERVER = 'https://api.webagentbridge.com';
12
23
 
24
+ // One-shot soft warning so integrators know a modern surface exists.
25
+ try {
26
+ if (global && global.console && !global.__wabLegacyWarned) {
27
+ global.__wabLegacyWarned = true;
28
+ // eslint-disable-next-line no-console
29
+ console.info('[WAB] Loaded legacy bridge (window.AIBridgeConfig). For new integrations see https://webagentbridge.com/docs — wab.json + DNS discovery + ATP.');
30
+ }
31
+ } catch (_) { /* noop */ }
32
+
13
33
  // ─── Default Configuration ────────────────────────────────────────────
14
34
  const DEFAULT_CONFIG = {
15
35
  agentPermissions: {