buzzster 1.0.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/SKILL.md ADDED
@@ -0,0 +1,765 @@
1
+ ---
2
+ name: biofirewall-client
3
+ version: 3.0.0
4
+ description: Express middleware to protect your APIs with agent authentication.
5
+ homepage: https://github.com/openclaw/biofirewall
6
+ metadata: {"biofirewall-client":{"emoji":"🔒","category":"security"}}
7
+ ---
8
+
9
+ # BioFirewall Client 🔒 SKILL.md
10
+
11
+ **For Developers:** How to protect your APIs with agent-only authentication.
12
+
13
+ ---
14
+
15
+ ## What Is biofirewall-client?
16
+
17
+ An Express middleware that:
18
+ 1. **Blocks browsers** (User-Agent detection)
19
+ 2. **Verifies tokens** with central BioFirewall API
20
+ 3. **Caches verification** locally (30s, reduces API load)
21
+ 4. **Attaches agent info** to `req.agent`
22
+ 5. **Returns helpful errors**
23
+
24
+ **Think:** A bouncer that only lets verified robots in.
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install biofirewall-client
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Quick Start (2 Minutes)
37
+
38
+ ### 1. Basic Setup
39
+
40
+ ```javascript
41
+ const express = require('express');
42
+ const BioFirewall = require('biofirewall-client');
43
+
44
+ const app = express();
45
+
46
+ // Create middleware
47
+ const bioFirewall = new BioFirewall('http://localhost:3333');
48
+
49
+ // Protect all routes
50
+ app.use(bioFirewall);
51
+
52
+ // Now only agents can access
53
+ app.get('/api/secret', (req, res) => {
54
+ res.json({
55
+ message: 'Hello, ' + req.agent.name,
56
+ agentId: req.agent.id
57
+ });
58
+ });
59
+
60
+ app.listen(8080);
61
+ ```
62
+
63
+ ### 2. Test It
64
+
65
+ ```bash
66
+ # As a browser (blocked)
67
+ curl http://localhost:8080/api/secret \
68
+ -H "User-Agent: Mozilla/5.0 Chrome/..."
69
+ # Response: 406 Not Acceptable
70
+
71
+ # As an agent (allowed)
72
+ curl http://localhost:8080/api/secret \
73
+ -H "X-Bio-Agent-Id: agent_abc123" \
74
+ -H "X-Bio-Token: eyJhbGc..." \
75
+ -H "User-Agent: MyAgent/1.0" \
76
+ -H "Accept: application/json"
77
+ # Response: 200 OK
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Configuration
83
+
84
+ ```javascript
85
+ const bioFirewall = new BioFirewall({
86
+ // Required
87
+ apiUrl: 'http://localhost:3333',
88
+
89
+ // Optional
90
+ blockBrowsers: true, // Block User-Agents that look like browsers
91
+ enforceAuthentication: true, // Require X-Bio-Token header
92
+ cacheTokens: true, // Cache verification results locally
93
+ cacheTTL: 30000 // Cache time-to-live (milliseconds)
94
+ });
95
+
96
+ app.use(bioFirewall);
97
+ ```
98
+
99
+ ### Configuration Options
100
+
101
+ | Option | Default | Purpose |
102
+ |--------|---------|---------|
103
+ | `apiUrl` | required | Central BioFirewall API URL |
104
+ | `blockBrowsers` | true | Block requests that look like browsers |
105
+ | `enforceAuthentication` | true | Require valid authentication |
106
+ | `cacheTokens` | true | Cache token verification locally |
107
+ | `cacheTTL` | 30000 | Cache time-to-live in milliseconds |
108
+
109
+ ---
110
+
111
+ ## How It Works
112
+
113
+ ### Three Layers of Security
114
+
115
+ #### Layer 1️⃣: Passive Filtering (Local, <1ms)
116
+
117
+ Blocks obvious browsers without API call:
118
+
119
+ ```
120
+ User-Agent: Mozilla/5.0 Chrome/... → 406 (instant)
121
+ Accept: text/html → 406 (instant)
122
+ Accept-Language: en-US → 406 (instant)
123
+ ```
124
+
125
+ **Why:** Fast rejection of obvious non-agents.
126
+
127
+ #### Layer 2️⃣: Token Verification (Central API, ~20ms)
128
+
129
+ For requests that pass Layer 1:
130
+
131
+ ```
132
+ POST /verify on central API
133
+ {
134
+ "agentId": "agent_xyz",
135
+ "token": "eyJhbGc..."
136
+ }
137
+
138
+ Response:
139
+ {
140
+ "valid": true,
141
+ "agent": { "id": "agent_xyz", "name": "MyAgent" }
142
+ }
143
+ ```
144
+
145
+ **Why:** Cryptographic verification with central registry.
146
+
147
+ #### Layer 3️⃣: Caching (Local, <1ms)
148
+
149
+ Result cached for 30 seconds:
150
+
151
+ ```
152
+ Request 1 (07:00:00) → API call ~20ms
153
+ Request 2 (07:00:10) → Cache hit ~0ms
154
+ Request 3 (07:00:20) → Cache hit ~0ms
155
+ Request 4 (07:00:35) → API call ~20ms (cache expired)
156
+ ```
157
+
158
+ **Why:** Reduce load on central API during request bursts.
159
+
160
+ ---
161
+
162
+ ## Usage Examples
163
+
164
+ ### Protect Specific Routes
165
+
166
+ ```javascript
167
+ const express = require('express');
168
+ const BioFirewall = require('biofirewall-client');
169
+
170
+ const app = express();
171
+ const bioFirewall = new BioFirewall('http://localhost:3333');
172
+
173
+ // Public routes (no auth)
174
+ app.get('/', (req, res) => {
175
+ res.json({ service: 'My API', status: 'online' });
176
+ });
177
+
178
+ // Protected routes (auth required)
179
+ app.get('/api/secret', bioFirewall, (req, res) => {
180
+ res.json({
181
+ message: 'Secret data',
182
+ agent: req.agent
183
+ });
184
+ });
185
+
186
+ app.post('/api/data', bioFirewall, (req, res) => {
187
+ res.json({
188
+ success: true,
189
+ agent: req.agent.id
190
+ });
191
+ });
192
+
193
+ app.listen(8080);
194
+ ```
195
+
196
+ ### Protect All Routes Except /health
197
+
198
+ ```javascript
199
+ const app = express();
200
+ const bioFirewall = new BioFirewall('http://localhost:3333');
201
+
202
+ // Health check (no auth)
203
+ app.get('/health', (req, res) => {
204
+ res.json({ status: 'ok' });
205
+ });
206
+
207
+ // Protect everything else
208
+ app.use(bioFirewall);
209
+
210
+ app.get('/api/data', (req, res) => {
211
+ res.json({ agent: req.agent.name });
212
+ });
213
+ ```
214
+
215
+ ### Access Agent Information
216
+
217
+ ```javascript
218
+ app.get('/api/profile', bioFirewall, (req, res) => {
219
+ // req.agent is populated by middleware
220
+ res.json({
221
+ you: req.agent.name,
222
+ yourId: req.agent.id,
223
+ version: req.agent.version,
224
+ permissions: req.agent.permissions
225
+ });
226
+ });
227
+ ```
228
+
229
+ ### Custom Error Handling
230
+
231
+ ```javascript
232
+ const bioFirewall = new BioFirewall('http://localhost:3333');
233
+
234
+ app.use((req, res, next) => {
235
+ bioFirewall(req, res, (err) => {
236
+ if (err) {
237
+ // Custom error handling
238
+ console.error('Auth error:', err);
239
+ return res.status(401).json({
240
+ success: false,
241
+ message: 'Custom error message'
242
+ });
243
+ }
244
+ next();
245
+ });
246
+ });
247
+ ```
248
+
249
+ ### With Route Guards
250
+
251
+ ```javascript
252
+ const bioFirewall = new BioFirewall('http://localhost:3333');
253
+
254
+ // Middleware
255
+ const requireAgent = bioFirewall;
256
+
257
+ const requireAdmin = (req, res, next) => {
258
+ if (req.agent.permissions.includes('admin')) {
259
+ next();
260
+ } else {
261
+ res.status(403).json({ error: 'Requires admin permission' });
262
+ }
263
+ };
264
+
265
+ // Routes
266
+ app.get('/api/user-data', requireAgent, (req, res) => {
267
+ res.json({ data: 'user data' });
268
+ });
269
+
270
+ app.post('/api/system-control', requireAgent, requireAdmin, (req, res) => {
271
+ res.json({ success: true });
272
+ });
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Request Headers
278
+
279
+ ### Required Headers (When Accessing Protected Route)
280
+
281
+ ```
282
+ X-Bio-Agent-Id: agent_a1b2c3d4e5f6g7h8 (your agent ID)
283
+ X-Bio-Token: eyJhbGciOiJSUzI1NiIsInR5cCI... (JWT you signed)
284
+ User-Agent: MyAgent/1.0 (your agent name/version)
285
+ Accept: application/json (ask for JSON, not HTML)
286
+ ```
287
+
288
+ ### Headers NOT to Send
289
+
290
+ ❌ `Accept: text/html` (looks human)
291
+ ❌ `Accept-Language: en-US` (human trait)
292
+ ❌ `Accept-Encoding: gzip, deflate` (browser thing)
293
+ ❌ Browser User-Agent like `Mozilla/5.0 Chrome/...`
294
+
295
+ ### Example Correct Request
296
+
297
+ ```bash
298
+ curl http://localhost:8080/api/secret \
299
+ -H "X-Bio-Agent-Id: agent_abc123" \
300
+ -H "X-Bio-Token: eyJhbGc..." \
301
+ -H "User-Agent: MyAgent/1.0" \
302
+ -H "Accept: application/json"
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Response Headers
308
+
309
+ Middleware adds these headers when authentication succeeds:
310
+
311
+ ```
312
+ X-Bio-Verified: true
313
+ X-Bio-Agent-Name: MyAgent
314
+ X-Bio-Version: 3.0
315
+ ```
316
+
317
+ Use these in your code:
318
+
319
+ ```javascript
320
+ app.get('/api/secret', bioFirewall, (req, res) => {
321
+ const headers = res.getHeaders();
322
+ console.log(headers['x-bio-verified']); // 'true'
323
+ console.log(headers['x-bio-agent-name']); // 'MyAgent'
324
+ });
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Error Responses
330
+
331
+ ### 406 Not Acceptable (Looks Like a Browser)
332
+
333
+ ```json
334
+ {
335
+ "success": false,
336
+ "error": "BIOLOGICAL_ENTITY_DETECTED",
337
+ "message": "This resource is reserved for automated agents",
338
+ "tip": "Use an API client. Ensure User-Agent does not look like a browser"
339
+ }
340
+ ```
341
+
342
+ **Causes:**
343
+ - User-Agent contains "Mozilla", "Chrome", "Safari", etc.
344
+ - Accept header contains `text/html`
345
+ - Accept-Language header present
346
+
347
+ **Fix:**
348
+ ```bash
349
+ # Don't do this
350
+ curl -H "User-Agent: Mozilla/5.0 Chrome/..." http://localhost:8080/api/secret
351
+
352
+ # Do this instead
353
+ curl \
354
+ -H "User-Agent: MyAgent/1.0" \
355
+ -H "Accept: application/json" \
356
+ -H "X-Bio-Agent-Id: agent_abc123" \
357
+ -H "X-Bio-Token: eyJhbGc..." \
358
+ http://localhost:8080/api/secret
359
+ ```
360
+
361
+ ### 428 Precondition Required (Missing Headers)
362
+
363
+ ```json
364
+ {
365
+ "success": false,
366
+ "error": "AUTHENTICATION_REQUIRED",
367
+ "message": "Valid agent token required to access this resource",
368
+ "protocol": {
369
+ "version": "3.0",
370
+ "method": "JWT + RS256",
371
+ "headers": {
372
+ "X-Bio-Agent-Id": "Your agent ID from registration",
373
+ "X-Bio-Token": "JWT token signed with your private key"
374
+ }
375
+ }
376
+ }
377
+ ```
378
+
379
+ **Cause:** Missing `X-Bio-Agent-Id` or `X-Bio-Token` header
380
+
381
+ **Fix:** Include both headers with valid values
382
+
383
+ ### 401 Unauthorized (Invalid Token)
384
+
385
+ ```json
386
+ {
387
+ "success": false,
388
+ "error": "INVALID_TOKEN",
389
+ "message": "Token signature is invalid"
390
+ }
391
+ ```
392
+
393
+ **Causes:**
394
+ - Token signed with wrong private key
395
+ - Token expired (>1 hour old)
396
+ - Token corrupted/tampered
397
+
398
+ **Fix:**
399
+ ```javascript
400
+ // Regenerate token with correct private key
401
+ const newToken = crypto.createToken(privateKey, agentId, metadata, 3600);
402
+
403
+ // Then retry request with new token
404
+ ```
405
+
406
+ ### 403 Forbidden (Agent Revoked)
407
+
408
+ ```json
409
+ {
410
+ "success": false,
411
+ "error": "AGENT_NOT_ACTIVE",
412
+ "message": "Agent status is revoked"
413
+ }
414
+ ```
415
+
416
+ **Cause:** Agent was revoked by administrator
417
+
418
+ **Fix:** Contact administrator to reactivate
419
+
420
+ ### 404 Agent Not Found
421
+
422
+ ```json
423
+ {
424
+ "success": false,
425
+ "error": "AGENT_NOT_FOUND",
426
+ "message": "Agent not registered"
427
+ }
428
+ ```
429
+
430
+ **Cause:** Agent ID doesn't exist in central registry
431
+
432
+ **Fix:** Register agent first:
433
+ ```bash
434
+ curl -X POST http://localhost:3333/register \
435
+ -d '{"publicKey": "...", "metadata": {...}}'
436
+ ```
437
+
438
+ ---
439
+
440
+ ## Token Caching
441
+
442
+ By default, token verification results are cached for 30 seconds locally:
443
+
444
+ ```javascript
445
+ // Prevents hammering central API
446
+ // Typical cache hit rate: 95%+ for normal usage
447
+
448
+ // Clear all cache (if needed)
449
+ bioFirewall.clearCache?.();
450
+
451
+ // Or disable caching
452
+ const bioFirewall = new BioFirewall({
453
+ apiUrl: 'http://localhost:3333',
454
+ cacheTokens: false // No local caching
455
+ });
456
+ ```
457
+
458
+ ---
459
+
460
+ ## Performance
461
+
462
+ ### Typical Response Times
463
+
464
+ ```
465
+ Browser request (Layer 1): ~0ms (instant rejection)
466
+ Agent request (Layer 2 cache): ~1ms (cached)
467
+ Agent request (Layer 2 API): ~20ms (central API call)
468
+ ```
469
+
470
+ ### Optimization Tips
471
+
472
+ 1. **Reuse middleware instance:**
473
+ ```javascript
474
+ const bioFirewall = new BioFirewall('http://localhost:3333');
475
+ app.use('/api', bioFirewall); // Single instance
476
+ ```
477
+
478
+ 2. **Use token caching (default):**
479
+ ```javascript
480
+ const bioFirewall = new BioFirewall({
481
+ apiUrl: 'http://localhost:3333',
482
+ cacheTokens: true, // Default: ON
483
+ cacheTTL: 30000 // 30 seconds
484
+ });
485
+ ```
486
+
487
+ 3. **Keep central API close (low latency):**
488
+ - Same data center if possible
489
+ - CDN for geographically distributed apps
490
+
491
+ ---
492
+
493
+ ## Testing
494
+
495
+ ### Unit Tests
496
+
497
+ ```javascript
498
+ const request = require('supertest');
499
+ const app = require('./app');
500
+
501
+ describe('Protected endpoint', () => {
502
+ it('should reject browsers', async () => {
503
+ const res = await request(app)
504
+ .get('/api/secret')
505
+ .set('User-Agent', 'Mozilla/5.0 Chrome/...');
506
+
507
+ expect(res.status).toBe(406);
508
+ expect(res.body.error).toBe('BIOLOGICAL_ENTITY_DETECTED');
509
+ });
510
+
511
+ it('should reject missing auth', async () => {
512
+ const res = await request(app)
513
+ .get('/api/secret')
514
+ .set('User-Agent', 'MyBot/1.0');
515
+
516
+ expect(res.status).toBe(428);
517
+ expect(res.body.error).toBe('AUTHENTICATION_REQUIRED');
518
+ });
519
+
520
+ it('should allow valid agents', async () => {
521
+ const res = await request(app)
522
+ .get('/api/secret')
523
+ .set('User-Agent', 'MyBot/1.0')
524
+ .set('X-Bio-Agent-Id', 'agent_test123')
525
+ .set('X-Bio-Token', 'valid_jwt_token');
526
+
527
+ expect(res.status).toBe(200);
528
+ expect(res.body.agent.id).toBe('agent_test123');
529
+ });
530
+
531
+ it('should include response headers', async () => {
532
+ const res = await request(app)
533
+ .get('/api/secret')
534
+ .set('User-Agent', 'MyBot/1.0')
535
+ .set('X-Bio-Agent-Id', 'agent_test123')
536
+ .set('X-Bio-Token', 'valid_jwt_token');
537
+
538
+ expect(res.headers['x-bio-verified']).toBe('true');
539
+ expect(res.headers['x-bio-agent-name']).toBe('MyAgent');
540
+ });
541
+ });
542
+ ```
543
+
544
+ ### Integration Test
545
+
546
+ ```bash
547
+ #!/bin/bash
548
+
549
+ # Test 1: Browser blocked
550
+ echo "Test 1: Block browser"
551
+ curl -v \
552
+ -H "User-Agent: Mozilla/5.0 Chrome/..." \
553
+ http://localhost:8080/api/secret
554
+ # Expected: 406
555
+
556
+ # Test 2: Missing auth
557
+ echo "Test 2: Missing auth"
558
+ curl -v \
559
+ -H "User-Agent: MyBot/1.0" \
560
+ http://localhost:8080/api/secret
561
+ # Expected: 428
562
+
563
+ # Test 3: Valid agent
564
+ echo "Test 3: Valid agent"
565
+ curl -v \
566
+ -H "User-Agent: MyBot/1.0" \
567
+ -H "X-Bio-Agent-Id: agent_test123" \
568
+ -H "X-Bio-Token: eyJhbGc..." \
569
+ http://localhost:8080/api/secret
570
+ # Expected: 200
571
+ ```
572
+
573
+ ---
574
+
575
+ ## Troubleshooting
576
+
577
+ ### "Cannot connect to central API"
578
+
579
+ ```javascript
580
+ // Check API URL
581
+ const bioFirewall = new BioFirewall('http://localhost:3333');
582
+
583
+ // Verify API is running
584
+ curl http://localhost:3333/health
585
+
586
+ // Check firewall rules
587
+ # Allow traffic on 3333
588
+ ```
589
+
590
+ ### "Token always invalid"
591
+
592
+ ```javascript
593
+ // Ensure token signed with correct private key
594
+ const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });
595
+
596
+ // Verify agent is registered
597
+ curl http://localhost:3333/agents/agent_abc123
598
+
599
+ // Check token not expired (max 1 hour old)
600
+ ```
601
+
602
+ ### "Agents keep getting 406"
603
+
604
+ ```bash
605
+ # Check headers
606
+ curl -v \
607
+ -H "User-Agent: MyBot/1.0" \
608
+ -H "Accept: application/json" \
609
+ -H "X-Bio-Agent-Id: agent_xyz" \
610
+ -H "X-Bio-Token: ..." \
611
+ http://localhost:8080/api/secret
612
+
613
+ # Don't include:
614
+ # - "Mozilla" in User-Agent
615
+ # - "text/html" in Accept header
616
+ # - "Accept-Language" header
617
+ ```
618
+
619
+ ---
620
+
621
+ ## Complete Example App
622
+
623
+ ```javascript
624
+ const express = require('express');
625
+ const BioFirewall = require('biofirewall-client');
626
+
627
+ const app = express();
628
+
629
+ // Setup
630
+ const bioFirewall = new BioFirewall('http://localhost:3333');
631
+
632
+ // Middleware
633
+ app.use(express.json());
634
+
635
+ // Public route (no auth)
636
+ app.get('/', (req, res) => {
637
+ res.json({
638
+ service: 'Protected API',
639
+ status: 'online',
640
+ endpoints: {
641
+ public: ['GET /'],
642
+ protected: ['GET /api/secret', 'POST /api/data']
643
+ }
644
+ });
645
+ });
646
+
647
+ // Protected routes
648
+ app.get('/api/secret', bioFirewall, (req, res) => {
649
+ res.json({
650
+ message: 'Secret data',
651
+ agent: {
652
+ id: req.agent.id,
653
+ name: req.agent.name,
654
+ version: req.agent.version
655
+ }
656
+ });
657
+ });
658
+
659
+ app.post('/api/data', bioFirewall, (req, res) => {
660
+ res.json({
661
+ success: true,
662
+ message: 'Data received',
663
+ agent: req.agent.id,
664
+ data: req.body
665
+ });
666
+ });
667
+
668
+ // Error handler
669
+ app.use((err, req, res, next) => {
670
+ console.error(err);
671
+ res.status(500).json({
672
+ error: 'Internal server error'
673
+ });
674
+ });
675
+
676
+ // Start
677
+ const PORT = process.env.PORT || 8080;
678
+ app.listen(PORT, () => {
679
+ console.log(`🔒 Protected API running on port ${PORT}`);
680
+ console.log(` Central API: http://localhost:3333`);
681
+ });
682
+ ```
683
+
684
+ ---
685
+
686
+ ## Deployment
687
+
688
+ ### Docker
689
+
690
+ ```dockerfile
691
+ FROM node:18-alpine
692
+
693
+ WORKDIR /app
694
+
695
+ COPY package*.json ./
696
+ RUN npm install
697
+
698
+ COPY . .
699
+
700
+ ENV BIOFIREWALL_API=http://biofirewall-api:3333
701
+ ENV PORT=8080
702
+
703
+ EXPOSE 8080
704
+
705
+ CMD ["npm", "start"]
706
+ ```
707
+
708
+ ### Environment Variables
709
+
710
+ ```bash
711
+ BIOFIREWALL_API=http://localhost:3333
712
+ NODE_ENV=production
713
+ PORT=8080
714
+ ```
715
+
716
+ ---
717
+
718
+ ## Security Best Practices
719
+
720
+ ✅ **DO:**
721
+ - Use HTTPS in production
722
+ - Keep central API URL secret
723
+ - Monitor for unusual patterns
724
+ - Log authentication attempts
725
+ - Update middleware regularly
726
+ - Use caching (reduces API calls)
727
+
728
+ ❌ **DON'T:**
729
+ - Expose central API URL in client code
730
+ - Log tokens or agent secrets
731
+ - Disable browser detection
732
+ - Disable token verification
733
+ - Use old versions
734
+
735
+ ---
736
+
737
+ ## FAQ
738
+
739
+ **Q: Can I use biofirewall-client without central API?**
740
+ A: No. It requires a running central API for token verification.
741
+
742
+ **Q: How do I set up central API?**
743
+ A: See `/biofirewall-api/README.md` or `npm install biofirewall-api`.
744
+
745
+ **Q: Can I customize error messages?**
746
+ A: Yes, implement custom middleware before biofirewall.
747
+
748
+ **Q: How do I handle 404 from central API?**
749
+ A: Middleware will return 500. Ensure central API is reachable.
750
+
751
+ **Q: Can multiple services use same central API?**
752
+ A: Yes! That's the point. Central API is shared.
753
+
754
+ ---
755
+
756
+ ## Support
757
+
758
+ - 📖 [biofirewall-api/SKILL.md](../biofirewall-api/SKILL.md) — Agent registration guide
759
+ - 💓 [biofirewall-api/HEARTBEAT.md](../biofirewall-api/HEARTBEAT.md) — Agent activity routine
760
+ - 🏗️ [ARCHITECTURE.md](../ARCHITECTURE.md) — System design
761
+ - 🔗 GitHub: https://github.com/openclaw/biofirewall
762
+
763
+ ---
764
+
765
+ *BioFirewall Client v3.0 | Protect your APIs. Verify silicon.* 🔒