yakmesh 1.0.2 → 1.1.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.
@@ -0,0 +1,67 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint-and-test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [18.x, 20.x, 22.x]
16
+
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js ${{ matrix.node-version }}
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: ${{ matrix.node-version }}
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci --ignore-scripts
29
+
30
+ - name: Check syntax (ESLint)
31
+ run: |
32
+ npm install eslint --save-dev
33
+ npx eslint --no-eslintrc --env node,es2022 --parser-options ecmaVersion:2022,sourceType:module "**/*.js" --ignore-pattern node_modules/ --ignore-pattern dashboard/ || true
34
+ continue-on-error: true
35
+
36
+ - name: Validate imports
37
+ run: |
38
+ echo "Checking for valid ES module syntax..."
39
+ node --check server/index.js || true
40
+ node --check oracle/index.js || true
41
+ node --check cli/index.js || true
42
+
43
+ - name: Security audit
44
+ run: npm audit --audit-level=high || true
45
+ continue-on-error: true
46
+
47
+ publish-check:
48
+ runs-on: ubuntu-latest
49
+ needs: lint-and-test
50
+
51
+ steps:
52
+ - name: Checkout repository
53
+ uses: actions/checkout@v4
54
+
55
+ - name: Setup Node.js
56
+ uses: actions/setup-node@v4
57
+ with:
58
+ node-version: 20.x
59
+
60
+ - name: Verify package.json
61
+ run: |
62
+ echo "Package name: $(node -p "require('./package.json').name")"
63
+ echo "Package version: $(node -p "require('./package.json').version")"
64
+ echo "License: $(node -p "require('./package.json').license")"
65
+
66
+ - name: Dry-run pack
67
+ run: npm pack --dry-run
package/CHANGELOG.md ADDED
@@ -0,0 +1,92 @@
1
+ # Changelog
2
+
3
+ All notable changes to YAKMESH™ will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0] - 2026-01-14
9
+
10
+ ### Added
11
+ - **NAVR (Network Assimilation Validation Routine)**: Computational identity verification for new nodes
12
+ - Replaces traditional "Proof of Work" terminology to avoid blockchain confusion
13
+ - One-time puzzle solve during node registration (NOT mining)
14
+ - Configurable difficulty for network defense scaling
15
+ - **Sybil Defense Module** (`mesh/sybil-defense.js`):
16
+ - NAVR computational puzzle for identity creation
17
+ - ReputationTracker for trust scoring (0.0 to 1.0 scale)
18
+ - SubnetDiversity to prevent eclipse attacks (max 3 connections per /24 subnet)
19
+ - **Replay Defense Module** (`mesh/replay-defense.js`):
20
+ - NonceRegistry with cryptographic 32-byte nonces (1hr expiry)
21
+ - TimestampValidator (10-minute freshness window)
22
+ - SequenceTracker for per-sender message ordering
23
+ - ChallengeResponse for mutual node authentication
24
+ - **Message Validator Module** (`mesh/message-validator.js`):
25
+ - Size limits per message type (1MB max, gossip 64KB, handshake 8KB)
26
+ - Nesting depth protection (max 10 levels)
27
+ - SafeJsonParser with prototype pollution protection
28
+ - Expanded test suite: 24 security tests covering all attack vectors
29
+
30
+ ### Security
31
+ - Protection against Sybil attacks via NAVR + reputation + subnet diversity
32
+ - Protection against replay attacks via nonces + timestamps + sequences
33
+ - Protection against amplification attacks via message size limits
34
+ - Protection against eclipse attacks via subnet connection limits
35
+
36
+ ## [1.0.3] - 2026-01-15
37
+
38
+ ### Fixed
39
+ - **CRITICAL**: Fixed ML-DSA-65 signature verification parameter order (was: publicKey, message, signature → now: signature, message, publicKey)
40
+
41
+ ### Added
42
+ - **Rate Limiter**: New `ConnectionRateLimiter` class for DoS protection
43
+ - Connection flood protection (30 connections/minute per IP)
44
+ - Handshake spam detection (100 handshakes/minute global)
45
+ - Gossip message throttling (500 messages/minute)
46
+ - Automatic cleanup of stale tracking data
47
+ - Comprehensive test suite (17 tests covering crypto, security, performance)
48
+ - Stress test suite (14 tests with edge cases)
49
+
50
+ ### Security
51
+ - Integrated rate limiting into mesh/network.js WebSocket handling
52
+ - Protection against 51% / network isolation attacks via message throttling
53
+
54
+ ## [1.0.2] - 2026-01-14
55
+
56
+ ### Fixed
57
+ - Fixed README.md formatting for proper rendering on npm and GitHub
58
+
59
+ ## [1.0.1] - 2026-01-14
60
+
61
+ ### Fixed
62
+ - Removed Pro-only security module from public npm package
63
+ - Added `.npmignore` to exclude proprietary code
64
+
65
+ ## [1.0.0] - 2026-01-14
66
+
67
+ ### Added
68
+ - **Post-Quantum Cryptography**: ML-DSA-65 (NIST FIPS 204) signatures
69
+ - **Self-Verifying Oracle**: Deterministic validation without external trust
70
+ - **Mesh Networking**: P2P WebSocket communication with gossip protocol
71
+ - **Precision Timing**: Support for atomic clocks, GPS, PTP, NTP time sources
72
+ - **Plugin Architecture**: BaseAdapter for custom database integrations
73
+ - **Phase Modulation**: Time-based anti-replay protection
74
+ - **Network Identity**: Configurable salts for isolated network deployments
75
+ - **Code Proof Protocol**: Integrity verification for distributed code
76
+ - **Consensus Engine**: Distributed agreement on network state
77
+ - **CLI Tools**: `yakmesh init`, `yakmesh start`, `yakmesh status`
78
+ - **Dashboard**: Web-based node monitoring interface
79
+ - **Embedded Webserver**: Caddy integration for HTTPS/reverse proxy
80
+
81
+ ### Security
82
+ - XChaCha20-Poly1305 encryption for message payloads
83
+ - Lattice-based cryptography resistant to quantum attacks
84
+ - Hardware timestamping support for timing attack mitigation
85
+
86
+ ---
87
+
88
+ [1.0.3]: https://github.com/yakmesh/yakmesh/releases/tag/v1.0.3
89
+ [1.0.2]: https://github.com/yakmesh/yakmesh/releases/tag/v1.0.2
90
+ [1.0.1]: https://github.com/yakmesh/yakmesh/releases/tag/v1.0.1
91
+ [1.0.0]: https://github.com/yakmesh/yakmesh/releases/tag/v1.0.0
92
+
package/SECURITY.md ADDED
@@ -0,0 +1,57 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | ------------------ |
7
+ | 1.0.x | :white_check_mark: |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ We take security seriously at YAKMESH™. If you discover a security vulnerability, please report it responsibly.
12
+
13
+ ### How to Report
14
+
15
+ **Email**: security@yakmesh.dev
16
+
17
+ **Do NOT**:
18
+ - Open a public GitHub issue for security vulnerabilities
19
+ - Disclose the vulnerability publicly before we've had a chance to address it
20
+
21
+ ### What to Include
22
+
23
+ - Description of the vulnerability
24
+ - Steps to reproduce
25
+ - Potential impact
26
+ - Suggested fix (if any)
27
+
28
+ ### Response Timeline
29
+
30
+ - **Acknowledgment**: Within 48 hours
31
+ - **Initial Assessment**: Within 7 days
32
+ - **Resolution Target**: Within 30 days (depending on severity)
33
+
34
+ ### Recognition
35
+
36
+ We appreciate responsible disclosure and will:
37
+ - Credit you in the security advisory (unless you prefer anonymity)
38
+ - Work with you to understand and resolve the issue
39
+ - Not take legal action for good-faith security research
40
+
41
+ ## Security Features
42
+
43
+ YAKMESH implements multiple layers of security:
44
+
45
+ - **Post-Quantum Cryptography**: ML-DSA-65 signatures (NIST FIPS 204)
46
+ - **Authenticated Encryption**: XChaCha20-Poly1305
47
+ - **Replay Protection**: Phase-epoch based message validation
48
+ - **Code Integrity**: Self-verifying oracle with module sealing
49
+
50
+ ## Known Limitations
51
+
52
+ - NTP time sources are not suitable for oracle operations (use GPS/PTP/Atomic)
53
+ - Community edition does not include WebSocket authentication (see Pro)
54
+
55
+ ---
56
+
57
+ YAKMESH™ is a trademark of PeerQuanta (USPTO Serial No. 99594620)
@@ -60,8 +60,8 @@ export function verifySignature(message, signatureHex, publicKeyHex) {
60
60
  const messageBytes = typeof message === 'string'
61
61
  ? new TextEncoder().encode(message)
62
62
  : message;
63
- // ml_dsa65.verify takes (publicKey, message, signature)
64
- return ml_dsa65.verify(publicKey, messageBytes, signature);
63
+ // ml_dsa65.verify takes (signature, message, publicKey)
64
+ return ml_dsa65.verify(signature, messageBytes, publicKey);
65
65
  } catch (e) {
66
66
  console.error('Signature verification failed:', e.message);
67
67
  return false;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Message Validation Module
3
+ * @module mesh/message-validator.js
4
+ */
5
+
6
+ export const SIZE_LIMITS = {
7
+ maxMessageSize: 1024 * 1024,
8
+ maxPayloadSizes: { gossip: 64 * 1024, handshake: 8 * 1024, listing: 128 * 1024, data: 512 * 1024 },
9
+ maxDepth: 10,
10
+ maxArrayLength: 1000,
11
+ maxStringLength: 100000,
12
+ };
13
+
14
+ export class MessageValidator {
15
+ constructor(options = {}) {
16
+ this.limits = { ...SIZE_LIMITS, ...options.limits };
17
+ this.stats = { validated: 0, rejected: 0, rejectionReasons: new Map() };
18
+ }
19
+
20
+ validateRaw(rawMessage, type = 'gossip') {
21
+ const size = typeof rawMessage === 'string' ? Buffer.byteLength(rawMessage, 'utf8') : rawMessage.length;
22
+ if (size > this.limits.maxMessageSize) return this._reject('Message too large (' + size + ' > ' + this.limits.maxMessageSize + ')');
23
+ const typeLimit = this.limits.maxPayloadSizes[type] || this.limits.maxPayloadSizes.gossip;
24
+ if (size > typeLimit) return this._reject(type + ' message too large (' + size + ' > ' + typeLimit + ')');
25
+ this.stats.validated++;
26
+ return { valid: true, size };
27
+ }
28
+
29
+ validateStructure(message, type = 'gossip') {
30
+ if (message === null || message === undefined) return this._reject('Message is null or undefined');
31
+ if (typeof message !== 'object') return this._reject('Expected object, got ' + typeof message);
32
+ const depthCheck = this._checkDepth(message, 0);
33
+ if (!depthCheck.valid) return depthCheck;
34
+ const requiredCheck = this._checkRequiredFields(message, type);
35
+ if (!requiredCheck.valid) return requiredCheck;
36
+ this.stats.validated++;
37
+ return { valid: true };
38
+ }
39
+
40
+ _checkDepth(obj, depth) {
41
+ if (depth > this.limits.maxDepth) return this._reject('Message nesting too deep');
42
+ if (Array.isArray(obj)) {
43
+ if (obj.length > this.limits.maxArrayLength) return this._reject('Array too long');
44
+ for (const item of obj) {
45
+ if (typeof item === 'object' && item !== null) {
46
+ const check = this._checkDepth(item, depth + 1);
47
+ if (!check.valid) return check;
48
+ }
49
+ }
50
+ } else if (typeof obj === 'object' && obj !== null) {
51
+ for (const value of Object.values(obj)) {
52
+ if (typeof value === 'string' && value.length > this.limits.maxStringLength) return this._reject('String too long');
53
+ if (typeof value === 'object' && value !== null) {
54
+ const check = this._checkDepth(value, depth + 1);
55
+ if (!check.valid) return check;
56
+ }
57
+ }
58
+ }
59
+ return { valid: true };
60
+ }
61
+
62
+ _checkRequiredFields(message, type) {
63
+ const requirements = { handshake: ['type', 'nodeId'], gossip: ['type'], listing: ['type', 'data', 'signature'], data: ['type', 'payload'] };
64
+ const required = requirements[type] || requirements.gossip;
65
+ for (const field of required) { if (!(field in message)) return this._reject('Missing required field: ' + field); }
66
+ return { valid: true };
67
+ }
68
+
69
+ _reject(reason) {
70
+ this.stats.rejected++;
71
+ const count = this.stats.rejectionReasons.get(reason) || 0;
72
+ this.stats.rejectionReasons.set(reason, count + 1);
73
+ return { valid: false, reason };
74
+ }
75
+
76
+ getStats() {
77
+ return { validated: this.stats.validated, rejected: this.stats.rejected, topReasons: [...this.stats.rejectionReasons.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10) };
78
+ }
79
+ }
80
+
81
+ export class SafeJsonParser {
82
+ constructor(options = {}) {
83
+ this.maxSize = options.maxSize || SIZE_LIMITS.maxMessageSize;
84
+ }
85
+
86
+ parse(json) {
87
+ if (typeof json !== 'string') return { success: false, error: 'Input must be a string' };
88
+ if (json.length > this.maxSize) return { success: false, error: 'JSON too large' };
89
+ if (/__proto__|constructor.*prototype/i.test(json)) return { success: false, error: 'Suspicious content detected' };
90
+ try { return { success: true, data: JSON.parse(json) }; }
91
+ catch (e) { return { success: false, error: 'JSON parse error: ' + e.message }; }
92
+ }
93
+ }
94
+
95
+ export default MessageValidator;
package/mesh/network.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { WebSocketServer, WebSocket } from 'ws';
7
+ import { ConnectionRateLimiter } from './rate-limiter.js';
7
8
 
8
9
  /**
9
10
  * Message types for mesh protocol
@@ -47,6 +48,9 @@ export class MeshNetwork {
47
48
  this.messageHandlers = new Map();
48
49
  this.seenMessages = new Set(); // For gossip deduplication
49
50
 
51
+ // Rate limiter for connection/message flood protection
52
+ this.rateLimiter = new ConnectionRateLimiter(config.rateLimiter || {});
53
+
50
54
  this._setupDefaultHandlers();
51
55
  }
52
56
 
@@ -327,7 +331,16 @@ export class MeshNetwork {
327
331
  }
328
332
 
329
333
  _handleIncomingConnection(ws, req) {
330
- console.log(`← Incoming connection from ${req.socket.remoteAddress}`);
334
+ const clientIp = req.socket.remoteAddress || 'unknown';
335
+ console.log(`← Incoming connection from ${clientIp}`);
336
+
337
+ // SECURITY: Rate limit check for connection flood protection
338
+ const connectionCheck = this.rateLimiter.checkConnection(clientIp);
339
+ if (!connectionCheck.allowed) {
340
+ console.warn(`⚠️ Connection rejected (rate limit): ${clientIp} - ${connectionCheck.reason}`);
341
+ ws.close(1008, connectionCheck.reason);
342
+ return;
343
+ }
331
344
 
332
345
  ws.on('message', (data) => {
333
346
  this._handleMessage(ws, data, req);