yakmesh 2.8.2 → 3.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/CHANGELOG.md +637 -0
- package/CONTRIBUTING.md +42 -0
- package/Caddyfile +77 -0
- package/README.md +119 -29
- package/adapters/adapter-mlv-bible/README.md +124 -0
- package/adapters/adapter-mlv-bible/index.js +400 -0
- package/adapters/chat-mod-adapter.js +532 -0
- package/adapters/content-adapter.js +273 -0
- package/content/api.js +50 -41
- package/content/index.js +2 -2
- package/content/store.js +355 -173
- package/dashboard/index.html +19 -3
- package/database/replication.js +117 -37
- package/docs/CRYPTO-AGILITY.md +204 -0
- package/docs/MTLS-RESEARCH.md +367 -0
- package/docs/NAMCHE-SPEC.md +681 -0
- package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
- package/docs/PRECISION-DISCLOSURE.md +96 -0
- package/docs/README.md +76 -0
- package/docs/ROADMAP-2.4.0.md +447 -0
- package/docs/ROADMAP-2.5.0.md +244 -0
- package/docs/SECURITY-AUDIT-REPORT.md +306 -0
- package/docs/SST-INTEGRATION.md +712 -0
- package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
- package/docs/TERNARY-AUDIT-REPORT.md +247 -0
- package/docs/TME-FAQ.md +221 -0
- package/docs/WHITEPAPER.md +623 -0
- package/docs/adapters.html +1001 -0
- package/docs/advanced-systems.html +1045 -0
- package/docs/annex.html +1046 -0
- package/docs/api.html +970 -0
- package/docs/business/response-templates.md +160 -0
- package/docs/c2c.html +1225 -0
- package/docs/cli.html +1332 -0
- package/docs/configuration.html +1248 -0
- package/docs/darshan.html +1085 -0
- package/docs/dharma.html +966 -0
- package/docs/docs-bundle.html +1075 -0
- package/docs/docs.css +3120 -0
- package/docs/docs.js +556 -0
- package/docs/doko.html +969 -0
- package/docs/geo-proof.html +858 -0
- package/docs/getting-started.html +840 -0
- package/docs/gumba-tutorial.html +1144 -0
- package/docs/gumba.html +1098 -0
- package/docs/index.html +914 -0
- package/docs/jhilke.html +1312 -0
- package/docs/karma.html +1100 -0
- package/docs/katha.html +1037 -0
- package/docs/lama.html +978 -0
- package/docs/mandala.html +1067 -0
- package/docs/mani.html +964 -0
- package/docs/mantra.html +967 -0
- package/docs/mesh.html +1409 -0
- package/docs/nakpak.html +869 -0
- package/docs/namche.html +928 -0
- package/docs/nav-order.json +53 -0
- package/docs/prahari.html +1043 -0
- package/docs/prism-bash.min.js +1 -0
- package/docs/prism-javascript.min.js +1 -0
- package/docs/prism-json.min.js +1 -0
- package/docs/prism-tomorrow.min.css +1 -0
- package/docs/prism.min.js +1 -0
- package/docs/privacy.html +699 -0
- package/docs/quick-reference.html +1181 -0
- package/docs/sakshi.html +1402 -0
- package/docs/sandboxing.md +386 -0
- package/docs/seva.html +911 -0
- package/docs/sherpa.html +871 -0
- package/docs/studio.html +860 -0
- package/docs/stupa.html +995 -0
- package/docs/tailwind.min.css +2 -0
- package/docs/tattva.html +1332 -0
- package/docs/terms.html +686 -0
- package/docs/time-server-deployment.md +166 -0
- package/docs/time-sources.html +1392 -0
- package/docs/tivra.html +1127 -0
- package/docs/trademark-policy.html +686 -0
- package/docs/tribhuj.html +1183 -0
- package/docs/trust-security.html +1029 -0
- package/docs/tutorials/backup-recovery.html +654 -0
- package/docs/tutorials/dashboard.html +604 -0
- package/docs/tutorials/domain-setup.html +605 -0
- package/docs/tutorials/host-website.html +456 -0
- package/docs/tutorials/mesh-network.html +505 -0
- package/docs/tutorials/mobile-access.html +445 -0
- package/docs/tutorials/privacy.html +467 -0
- package/docs/tutorials/raspberry-pi.html +600 -0
- package/docs/tutorials/security-basics.html +539 -0
- package/docs/tutorials/share-files.html +431 -0
- package/docs/tutorials/troubleshooting.html +637 -0
- package/docs/tutorials/trust-karma.html +419 -0
- package/docs/tutorials/yak-protocol.html +456 -0
- package/docs/tutorials.html +1034 -0
- package/docs/vani.html +1270 -0
- package/docs/webserver.html +809 -0
- package/docs/yak-protocol.html +940 -0
- package/docs/yak-timeserver-design.md +475 -0
- package/docs/yakapp.html +1015 -0
- package/docs/ypc27.html +1069 -0
- package/docs/yurt.html +1344 -0
- package/embedded-docs/bundle.js +334 -74
- package/gossip/protocol.js +247 -27
- package/identity/key-resolver.js +262 -0
- package/identity/machine-seed.js +632 -0
- package/identity/node-key.js +669 -368
- package/identity/tribhuj-ratchet.js +506 -0
- package/knowledge-base.js +37 -8
- package/launcher/yakmesh.bat +62 -0
- package/launcher/yakmesh.sh +70 -0
- package/mesh/annex.js +462 -108
- package/mesh/beacon-broadcast.js +113 -1
- package/mesh/darshan.js +1718 -0
- package/mesh/gumba.js +1567 -0
- package/mesh/jhilke.js +651 -0
- package/mesh/katha.js +1012 -0
- package/mesh/nakpak-routing.js +8 -5
- package/mesh/network.js +724 -34
- package/mesh/pulse-sync.js +4 -1
- package/mesh/rate-limiter.js +127 -15
- package/mesh/seva.js +526 -0
- package/mesh/sherpa-discovery.js +89 -8
- package/mesh/sybil-defense.js +19 -5
- package/mesh/temporal-encoder.js +4 -3
- package/mesh/vani.js +1364 -0
- package/mesh/yurt.js +1340 -0
- package/models/entropy-sentinel.onnx +0 -0
- package/models/karma-trust.onnx +0 -0
- package/models/manifest.json +43 -0
- package/models/sakshi-anomaly.onnx +0 -0
- package/oracle/code-proof-protocol.js +7 -6
- package/oracle/codebase-lock.js +257 -28
- package/oracle/index.js +74 -15
- package/oracle/ma902-snmp.js +678 -0
- package/oracle/module-sealer.js +5 -3
- package/oracle/network-identity.js +16 -0
- package/oracle/packet-checksum.js +201 -0
- package/oracle/sst.js +579 -0
- package/oracle/ternary-144t.js +714 -0
- package/oracle/ternary-ml.js +481 -0
- package/oracle/time-api.js +239 -0
- package/oracle/time-source.js +137 -47
- package/oracle/validation-oracle-hardened.js +1111 -1071
- package/oracle/validation-oracle.js +4 -2
- package/oracle/ypc27.js +211 -0
- package/package.json +20 -3
- package/protocol/yak-handler.js +35 -9
- package/protocol/yak-protocol.js +28 -13
- package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
- package/reference/cpp/yakmesh_ypc27.cpp +179 -0
- package/sbom.json +87 -0
- package/scripts/security-audit.mjs +264 -0
- package/scripts/update-docs-nav.js +194 -0
- package/scripts/update-docs-sidebar.cjs +164 -0
- package/security/crypto-config.js +4 -3
- package/security/dharma-moderation.js +517 -0
- package/security/doko-identity.js +193 -143
- package/security/domain-consensus.js +86 -85
- package/security/fs-hardening.js +620 -0
- package/security/hardware-attestation.js +5 -3
- package/security/hybrid-trust.js +227 -87
- package/security/karma-rate-limiter.js +692 -0
- package/security/khata-protocol.js +22 -21
- package/security/khata-trust-integration.js +277 -150
- package/security/memory-safety.js +635 -0
- package/security/mesh-auth.js +11 -10
- package/security/mesh-revocation.js +373 -5
- package/security/namche-gateway.js +298 -69
- package/security/sakshi.js +460 -3
- package/security/sangha.js +770 -0
- package/security/secure-config.js +473 -0
- package/security/silicon-parity.js +13 -10
- package/security/steadywatch.js +1142 -0
- package/security/strike-system.js +32 -3
- package/security/temporal-signing.js +488 -0
- package/security/trit-commitment.js +464 -0
- package/server/crypto/annex.js +247 -0
- package/server/darshan-api.js +343 -0
- package/server/index.js +3259 -362
- package/server/komm-api.js +668 -0
- package/utils/accel.js +2273 -0
- package/utils/ternary-id.js +79 -0
- package/utils/verify-worker.js +57 -0
- package/webserver/index.js +95 -5
- package/assets/yakmesh-logo.png +0 -0
- package/assets/yakmesh-logo.svg +0 -80
- package/assets/yakmesh-logo2.png +0 -0
- package/assets/yakmesh-logo2sm.png +0 -0
- package/assets/ymsm.png +0 -0
- package/website/assets/silhouettes/adapters.svg +0 -107
- package/website/assets/silhouettes/api-endpoints.svg +0 -115
- package/website/assets/silhouettes/atomic-clock.svg +0 -83
- package/website/assets/silhouettes/base-camp.svg +0 -81
- package/website/assets/silhouettes/bridge.svg +0 -69
- package/website/assets/silhouettes/docs-bundle.svg +0 -113
- package/website/assets/silhouettes/doko-basket.svg +0 -70
- package/website/assets/silhouettes/fortress.svg +0 -93
- package/website/assets/silhouettes/gateway.svg +0 -54
- package/website/assets/silhouettes/gears.svg +0 -93
- package/website/assets/silhouettes/globe-satellite.svg +0 -67
- package/website/assets/silhouettes/karma-wheel.svg +0 -137
- package/website/assets/silhouettes/lama-council.svg +0 -141
- package/website/assets/silhouettes/mandala-network.svg +0 -169
- package/website/assets/silhouettes/mani-stones.svg +0 -149
- package/website/assets/silhouettes/mantra-wheel.svg +0 -116
- package/website/assets/silhouettes/mesh-nodes.svg +0 -113
- package/website/assets/silhouettes/nakpak.svg +0 -56
- package/website/assets/silhouettes/peak-lightning.svg +0 -73
- package/website/assets/silhouettes/sherpa.svg +0 -69
- package/website/assets/silhouettes/stupa-tower.svg +0 -119
- package/website/assets/silhouettes/tattva-eye.svg +0 -78
- package/website/assets/silhouettes/terminal.svg +0 -74
- package/website/assets/silhouettes/webserver.svg +0 -145
- package/website/assets/silhouettes/yak.svg +0 -78
- package/website/assets/yakmesh-logo.png +0 -0
- package/website/assets/yakmesh-logo.webp +0 -0
- package/website/assets/yakmesh-logo128x140.webp +0 -0
- package/website/assets/yakmesh-logo2.png +0 -0
- package/website/assets/yakmesh-logo2.svg +0 -51
- package/website/assets/yakmesh-logo40x44.webp +0 -0
- package/website/assets/yakmesh.gif +0 -0
- package/website/assets/yakmesh.ico +0 -0
- package/website/assets/yakmesh.jpg +0 -0
- package/website/assets/yakmesh.pdf +0 -0
- package/website/assets/yakmesh.png +0 -0
- package/website/assets/yakmesh.svg +0 -70
- package/website/assets/yakmesh128.webp +0 -0
- package/website/assets/yakmesh32.png +0 -0
- package/website/assets/yakmesh32.svg +0 -65
- package/website/assets/yakmesh32o.ico +0 -2
- package/website/assets/yakmesh32o.svg +0 -65
- package/website/assets/yakmesh32o.svgz +0 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
# time.yakmesh.dev — Public Atomic Time Service
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-02-21
|
|
4
|
+
**Status**: Design Draft
|
|
5
|
+
**Domain**: time.yakmesh.dev
|
|
6
|
+
**Hardware**: MA-902/S-C1 GPS Gigabit Time Server at 192.168.1.30
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Concept
|
|
11
|
+
|
|
12
|
+
Any device can gain atomic-grade time synchronization by pointing at a yakmesh node.
|
|
13
|
+
The MA-902 GPS time server already provides Stratum 1 NTP on the LAN — this design
|
|
14
|
+
exposes that precision publicly through three tiers:
|
|
15
|
+
|
|
16
|
+
| Tier | Protocol | URL / Address | Accuracy | Use Case |
|
|
17
|
+
|------|----------|---------------|----------|----------|
|
|
18
|
+
| **1. NTP** | NTPv4 (UDP 123) | `ntp.yakmesh.dev` | ±1ms | OS-level time sync (`w32tm`, `chrony`, `ntpd`) |
|
|
19
|
+
| **2. HTTP Time API** | HTTPS (Caddy) | `https://time.yakmesh.dev/api/time` | ±5ms | Web apps, IoT, scripts, cross-platform |
|
|
20
|
+
| **3. NTS** | NTS-KE + NTPv4 | `nts.yakmesh.dev` | ±1ms | Authenticated, tamper-proof time (RFC 8915) |
|
|
21
|
+
|
|
22
|
+
**Why better than OS standard:**
|
|
23
|
+
- Most machines sync to `time.windows.com` or `pool.ntp.org` — Stratum 2-3 servers
|
|
24
|
+
with ±10-50ms accuracy and no authentication
|
|
25
|
+
- time.yakmesh.dev is **Stratum 1** (direct GPS antenna), ±1ms, with satellite health
|
|
26
|
+
telemetry and optional NTS authentication
|
|
27
|
+
- MA-902 tracks GPS + BeiDou constellations with 8-12 satellites in fix solution
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Internet
|
|
35
|
+
│
|
|
36
|
+
┌────────────┴────────────┐
|
|
37
|
+
│ yakmesh.dev VPS │
|
|
38
|
+
│ │
|
|
39
|
+
│ ┌───────────────────┐ │
|
|
40
|
+
│ │ Caddy (HTTPS) │ │
|
|
41
|
+
│ │ time.yakmesh. │ │
|
|
42
|
+
│ │ dev :443 │──┼──→ /api/time → time-api.js (Node)
|
|
43
|
+
│ │ │ │ /api/health → satellite status
|
|
44
|
+
│ │ │ │ / → landing page
|
|
45
|
+
│ └───────────────────┘ │
|
|
46
|
+
│ │
|
|
47
|
+
│ ┌───────────────────┐ │
|
|
48
|
+
│ │ NTP relay/proxy │ │
|
|
49
|
+
│ │ :123 UDP │──┼──→ Forwards to MA-902 192.168.1.30:123
|
|
50
|
+
│ │ (chrony or ntpd) │ │ via WireGuard tunnel
|
|
51
|
+
│ └───────────────────┘ │
|
|
52
|
+
│ │
|
|
53
|
+
└─────────┬───────────────┘
|
|
54
|
+
│ WireGuard tunnel
|
|
55
|
+
│
|
|
56
|
+
┌─────────┴───────────────┐
|
|
57
|
+
│ LAN (192.168.1.x) │
|
|
58
|
+
│ │
|
|
59
|
+
│ ┌───────────────────┐ │
|
|
60
|
+
│ │ MA-902/S-C1 GPS │ │
|
|
61
|
+
│ │ 192.168.1.30 │ │
|
|
62
|
+
│ │ NTP Stratum 1 │ │
|
|
63
|
+
│ │ SNMP v2c │ │
|
|
64
|
+
│ │ GPS+BeiDou │ │
|
|
65
|
+
│ └───────────────────┘ │
|
|
66
|
+
│ │
|
|
67
|
+
│ ┌───────────────────┐ │
|
|
68
|
+
│ │ Yakmesh Node │ │
|
|
69
|
+
│ │ (this machine) │ │
|
|
70
|
+
│ │ ma902-snmp.js │──┼──→ SNMP telemetry
|
|
71
|
+
│ │ time-api.js │──┼──→ HTTP time endpoint (local)
|
|
72
|
+
│ └───────────────────┘ │
|
|
73
|
+
│ │
|
|
74
|
+
└─────────────────────────┘
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Tier 1: NTP Service (`ntp.yakmesh.dev`)
|
|
80
|
+
|
|
81
|
+
### Option A: Direct NTP Relay (Preferred)
|
|
82
|
+
|
|
83
|
+
Run `chrony` on the VPS with the MA-902 as its upstream source via WireGuard.
|
|
84
|
+
The VPS becomes a **Stratum 2** NTP server that anyone can use.
|
|
85
|
+
|
|
86
|
+
```ini
|
|
87
|
+
# /etc/chrony/chrony.conf on the VPS
|
|
88
|
+
server 10.0.0.30 iburst prefer # MA-902 via WireGuard
|
|
89
|
+
driftfile /var/lib/chrony/drift
|
|
90
|
+
makestep 1.0 3
|
|
91
|
+
rtcsync
|
|
92
|
+
allow 0.0.0.0/0 # Allow all clients
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
DNS: `ntp.yakmesh.dev` → VPS public IP (A record)
|
|
96
|
+
|
|
97
|
+
**Usage by end users:**
|
|
98
|
+
```bash
|
|
99
|
+
# Windows
|
|
100
|
+
w32tm /config /manualpeerlist:"ntp.yakmesh.dev" /syncfromflags:manual /update
|
|
101
|
+
|
|
102
|
+
# Linux (chrony)
|
|
103
|
+
echo "server ntp.yakmesh.dev iburst" >> /etc/chrony/chrony.conf
|
|
104
|
+
|
|
105
|
+
# Linux (systemd-timesyncd)
|
|
106
|
+
echo 'NTP=ntp.yakmesh.dev' >> /etc/systemd/timesyncd.conf
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Option B: LAN-Only NTP (Simpler)
|
|
110
|
+
|
|
111
|
+
If no VPS/tunnel, the MA-902 at 192.168.1.30 already serves NTP locally.
|
|
112
|
+
Yakmesh nodes on the LAN can use it directly. Remote nodes use the HTTP API.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Tier 2: HTTP Time API (`time.yakmesh.dev`)
|
|
117
|
+
|
|
118
|
+
### Caddy Configuration
|
|
119
|
+
|
|
120
|
+
```caddyfile
|
|
121
|
+
time.yakmesh.dev {
|
|
122
|
+
# Time API — reverse proxy to local Node.js time service
|
|
123
|
+
handle /api/* {
|
|
124
|
+
reverse_proxy localhost:3099
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Landing page — static site
|
|
128
|
+
handle {
|
|
129
|
+
root * /var/www/yak-timeserver
|
|
130
|
+
file_server
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Security headers
|
|
134
|
+
header {
|
|
135
|
+
X-Content-Type-Options nosniff
|
|
136
|
+
X-Frame-Options DENY
|
|
137
|
+
Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
|
|
138
|
+
Access-Control-Allow-Origin "*"
|
|
139
|
+
Access-Control-Allow-Methods "GET, HEAD, OPTIONS"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# CORS preflight
|
|
143
|
+
@cors_preflight method OPTIONS
|
|
144
|
+
handle @cors_preflight {
|
|
145
|
+
header Access-Control-Max-Age "86400"
|
|
146
|
+
respond "" 204
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Rate limiting
|
|
150
|
+
rate_limit {
|
|
151
|
+
zone time_api {
|
|
152
|
+
key {remote_host}
|
|
153
|
+
events 60
|
|
154
|
+
window 1m
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Time API Endpoints
|
|
161
|
+
|
|
162
|
+
#### `GET /api/time`
|
|
163
|
+
|
|
164
|
+
Returns current atomic time with metadata.
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"iso": "2026-02-21T14:30:00.123Z",
|
|
169
|
+
"unix": 1771598200.123,
|
|
170
|
+
"unix_ms": 1771598200123,
|
|
171
|
+
"stratum": 1,
|
|
172
|
+
"source": "MA-902/S-C1 GPS",
|
|
173
|
+
"accuracy_ms": 1,
|
|
174
|
+
"leap_indicator": 0,
|
|
175
|
+
"satellites": {
|
|
176
|
+
"visible": 12,
|
|
177
|
+
"used": 9,
|
|
178
|
+
"tracking": 11,
|
|
179
|
+
"constellations": ["GPS", "BeiDou"]
|
|
180
|
+
},
|
|
181
|
+
"lock": true,
|
|
182
|
+
"quality": "excellent",
|
|
183
|
+
"offset_ns": 0,
|
|
184
|
+
"reference_id": "GPS"
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Headers returned:**
|
|
189
|
+
```
|
|
190
|
+
X-Yakmesh-Time: 1771598200.123
|
|
191
|
+
X-Yakmesh-Stratum: 1
|
|
192
|
+
X-Yakmesh-Source: GPS
|
|
193
|
+
Date: Fri, 21 Feb 2026 14:30:00 GMT
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### `GET /api/time/simple`
|
|
197
|
+
|
|
198
|
+
Minimal response for constrained clients:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"t": 1771598200123,
|
|
203
|
+
"s": 1,
|
|
204
|
+
"q": "excellent"
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `GET /api/health`
|
|
209
|
+
|
|
210
|
+
Satellite health and SNMP telemetry:
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"status": "healthy",
|
|
215
|
+
"uptime_s": 864000,
|
|
216
|
+
"lock": true,
|
|
217
|
+
"satellites_visible": 12,
|
|
218
|
+
"satellites_used": 9,
|
|
219
|
+
"constellations": ["GPS", "BeiDou"],
|
|
220
|
+
"alarm": false,
|
|
221
|
+
"quality": 1,
|
|
222
|
+
"last_poll": "2026-02-21T14:29:55Z",
|
|
223
|
+
"drift_ns": 0,
|
|
224
|
+
"trust_level": "atomic"
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `HEAD /api/time`
|
|
229
|
+
|
|
230
|
+
Returns only headers — zero body. Fastest way to get time:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
X-Yakmesh-Time: 1771598200.123
|
|
234
|
+
X-Yakmesh-Stratum: 1
|
|
235
|
+
Content-Length: 0
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Node.js Time API Service (`oracle/time-api.js`)
|
|
239
|
+
|
|
240
|
+
New module that bridges MA-902 SNMP telemetry to an HTTP endpoint:
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
// oracle/time-api.js — HTTP Atomic Time API
|
|
244
|
+
//
|
|
245
|
+
// Reads GPS time from MA-902 via the existing MA902Monitor SNMP module
|
|
246
|
+
// and serves it as a lightweight HTTP endpoint.
|
|
247
|
+
//
|
|
248
|
+
// Runs on port 3099 (configurable via YAKMESH_TIME_API_PORT).
|
|
249
|
+
// Reverse-proxied by Caddy at time.yakmesh.dev.
|
|
250
|
+
|
|
251
|
+
import http from 'node:http';
|
|
252
|
+
import { MA902Monitor } from './ma902-snmp.js';
|
|
253
|
+
|
|
254
|
+
const PORT = parseInt(process.env.YAKMESH_TIME_API_PORT || '3099');
|
|
255
|
+
|
|
256
|
+
const monitor = new MA902Monitor({
|
|
257
|
+
host: process.env.MA902_HOST || '192.168.1.30',
|
|
258
|
+
community: process.env.MA902_COMMUNITY || 'public',
|
|
259
|
+
pollInterval: 5000,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Cache last SNMP telemetry
|
|
263
|
+
let lastTelemetry = null;
|
|
264
|
+
monitor.on('telemetry', (data) => { lastTelemetry = data; });
|
|
265
|
+
monitor.start();
|
|
266
|
+
|
|
267
|
+
const server = http.createServer((req, res) => {
|
|
268
|
+
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
269
|
+
|
|
270
|
+
// CORS
|
|
271
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
272
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
|
|
273
|
+
|
|
274
|
+
if (req.method === 'OPTIONS') {
|
|
275
|
+
res.writeHead(204);
|
|
276
|
+
return res.end();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
const unixS = now / 1000;
|
|
281
|
+
|
|
282
|
+
// Common time headers
|
|
283
|
+
res.setHeader('X-Yakmesh-Time', unixS.toFixed(3));
|
|
284
|
+
res.setHeader('X-Yakmesh-Stratum', lastTelemetry?.lockStatus ? '1' : '2');
|
|
285
|
+
res.setHeader('X-Yakmesh-Source', lastTelemetry?.lockStatus ? 'GPS' : 'system');
|
|
286
|
+
|
|
287
|
+
if (url.pathname === '/api/time' && req.method === 'HEAD') {
|
|
288
|
+
res.writeHead(200);
|
|
289
|
+
return res.end();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (url.pathname === '/api/time/simple') {
|
|
293
|
+
const body = JSON.stringify({
|
|
294
|
+
t: now,
|
|
295
|
+
s: lastTelemetry?.lockStatus ? 1 : 2,
|
|
296
|
+
q: getQuality(),
|
|
297
|
+
});
|
|
298
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
299
|
+
return res.end(body);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (url.pathname === '/api/time') {
|
|
303
|
+
const body = JSON.stringify({
|
|
304
|
+
iso: new Date(now).toISOString(),
|
|
305
|
+
unix: unixS,
|
|
306
|
+
unix_ms: now,
|
|
307
|
+
stratum: lastTelemetry?.lockStatus ? 1 : 2,
|
|
308
|
+
source: 'MA-902/S-C1 GPS',
|
|
309
|
+
accuracy_ms: lastTelemetry?.lockStatus ? 1 : 50,
|
|
310
|
+
leap_indicator: 0,
|
|
311
|
+
satellites: {
|
|
312
|
+
visible: lastTelemetry?.satsVisible ?? 0,
|
|
313
|
+
used: lastTelemetry?.satsUsed ?? 0,
|
|
314
|
+
tracking: lastTelemetry?.satsTracking ?? 0,
|
|
315
|
+
constellations: lastTelemetry?.constellations ?? [],
|
|
316
|
+
},
|
|
317
|
+
lock: lastTelemetry?.lockStatus ?? false,
|
|
318
|
+
quality: getQuality(),
|
|
319
|
+
offset_ns: lastTelemetry?.offset ?? 0,
|
|
320
|
+
reference_id: lastTelemetry?.lockStatus ? 'GPS' : 'SYS',
|
|
321
|
+
});
|
|
322
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
323
|
+
return res.end(body);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (url.pathname === '/api/health') {
|
|
327
|
+
const body = JSON.stringify({
|
|
328
|
+
status: lastTelemetry?.lockStatus ? 'healthy' : 'degraded',
|
|
329
|
+
lock: lastTelemetry?.lockStatus ?? false,
|
|
330
|
+
satellites_visible: lastTelemetry?.satsVisible ?? 0,
|
|
331
|
+
satellites_used: lastTelemetry?.satsUsed ?? 0,
|
|
332
|
+
constellations: lastTelemetry?.constellations ?? [],
|
|
333
|
+
alarm: lastTelemetry?.alarm ?? false,
|
|
334
|
+
quality: lastTelemetry?.quality ?? 0,
|
|
335
|
+
last_poll: lastTelemetry?.timestamp
|
|
336
|
+
? new Date(lastTelemetry.timestamp).toISOString()
|
|
337
|
+
: null,
|
|
338
|
+
trust_level: lastTelemetry?.trustLevel ?? 'unknown',
|
|
339
|
+
});
|
|
340
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
341
|
+
return res.end(body);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
345
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
function getQuality() {
|
|
349
|
+
if (!lastTelemetry) return 'unknown';
|
|
350
|
+
const sats = lastTelemetry.satsUsed || 0;
|
|
351
|
+
if (sats >= 8) return 'excellent';
|
|
352
|
+
if (sats >= 5) return 'good';
|
|
353
|
+
if (sats >= 3) return 'marginal';
|
|
354
|
+
return 'degraded';
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
server.listen(PORT, () => {
|
|
358
|
+
console.log(`Yakmesh Time API listening on :${PORT}`);
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Tier 3: NTS — Network Time Security (Future)
|
|
365
|
+
|
|
366
|
+
NTS (RFC 8915) adds TLS-based authentication to NTP, preventing MITM time attacks.
|
|
367
|
+
This is a natural extension of yakmesh's post-quantum stance.
|
|
368
|
+
|
|
369
|
+
**Requirements:**
|
|
370
|
+
- NTS-KE (Key Establishment) server on port 4460
|
|
371
|
+
- TLS certificate (Let's Encrypt via Caddy)
|
|
372
|
+
- Compatible NTP server (chrony 4.0+ supports NTS natively)
|
|
373
|
+
|
|
374
|
+
**chrony NTS config:**
|
|
375
|
+
```ini
|
|
376
|
+
ntsserverkey /etc/letsencrypt/live/nts.yakmesh.dev/privkey.pem
|
|
377
|
+
ntsservercert /etc/letsencrypt/live/nts.yakmesh.dev/fullchain.pem
|
|
378
|
+
ntsport 4460
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Post-quantum consideration:** NTS currently uses TLS 1.3 with X25519/AES.
|
|
382
|
+
When PQ TLS (ML-KEM hybrid) ships in standard libraries, the NTS-KE handshake
|
|
383
|
+
becomes quantum-resistant. The NTP payload is already authenticated with AEAD.
|
|
384
|
+
|
|
385
|
+
**Client usage:**
|
|
386
|
+
```bash
|
|
387
|
+
# chrony client
|
|
388
|
+
server nts.yakmesh.dev nts iburst
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## MANI Protocol Integration
|
|
394
|
+
|
|
395
|
+
The time API feeds directly into the existing MANI (prayer stone) time
|
|
396
|
+
synchronization protocol. Every yakmesh node can:
|
|
397
|
+
|
|
398
|
+
1. Use `ntp.yakmesh.dev` as its NTP source (OS-level)
|
|
399
|
+
2. Query `time.yakmesh.dev/api/time` for satellite health telemetry
|
|
400
|
+
3. Feed responses into `ManiTimeDetector` for trust assessment
|
|
401
|
+
4. Broadcast time trust level via MANI gossip to mesh peers
|
|
402
|
+
|
|
403
|
+
This means **any yakmesh node with internet access automatically gains
|
|
404
|
+
atomic-grade time** — even without a local GPS receiver.
|
|
405
|
+
|
|
406
|
+
### Config Addition (yakmesh-node env vars)
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
YAKMESH_TIME_API_PORT=3099 # Local time API port
|
|
410
|
+
YAKMESH_TIME_SOURCE=ma902 # 'ma902' | 'ntp' | 'system'
|
|
411
|
+
MA902_HOST=192.168.1.30 # MA-902 SNMP address
|
|
412
|
+
MA902_COMMUNITY=public # SNMP community string
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## DNS Setup
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
time.yakmesh.dev A → VPS IP (Caddy serves HTTPS API + landing page)
|
|
421
|
+
ntp.yakmesh.dev A → VPS IP (chrony NTP relay on UDP 123)
|
|
422
|
+
nts.yakmesh.dev A → VPS IP (NTS-KE on TCP 4460 + NTP on UDP 123)
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
All subdomains under `yakmesh.dev` — no additional domain purchase needed.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Landing Page (`time.yakmesh.dev/`)
|
|
430
|
+
|
|
431
|
+
Static HTML page (served by Caddy) showing:
|
|
432
|
+
|
|
433
|
+
- **Live atomic clock** — JavaScript fetching `/api/time` every second
|
|
434
|
+
- **Satellite constellation map** — GPS/BeiDou satellite visualization from health data
|
|
435
|
+
- **Setup instructions** — How to configure your OS/device to use time.yakmesh.dev
|
|
436
|
+
- **About** — MA-902 hardware details, GPS antenna, accuracy specs
|
|
437
|
+
- **Status badge** — Green/yellow/red based on satellite lock
|
|
438
|
+
- **Integration with yakmesh** — Link to MANI docs, time-sources.html
|
|
439
|
+
|
|
440
|
+
Design: Match yakmesh.dev aesthetic (dark theme, system fonts, zero external deps).
|
|
441
|
+
Same domain family — consistent branding under `*.yakmesh.dev`.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Implementation Order
|
|
446
|
+
|
|
447
|
+
| Step | Task | Effort | Depends On |
|
|
448
|
+
|------|------|--------|------------|
|
|
449
|
+
| 1 | Create `oracle/time-api.js` — HTTP time service | 2 hours | MA-902 SNMP module (done) |
|
|
450
|
+
| 2 | Add Caddy site block for `time.yakmesh.dev` to `generateCaddyfile()` | 1 hour | Step 1 |
|
|
451
|
+
| 3 | Create landing page (static HTML) | 3 hours | Step 1 |
|
|
452
|
+
| 4 | DNS setup (A/CNAME records) | 15 min | Domain registrar access |
|
|
453
|
+
| 5 | VPS chrony configuration (NTP relay) | 1 hour | WireGuard tunnel to LAN |
|
|
454
|
+
| 6 | Add `/api/time` docs section to `time-sources.html` | 1 hour | Step 1 |
|
|
455
|
+
| 7 | MANI integration — remote nodes query time.yakmesh.dev | 2 hours | Step 1, MANI module |
|
|
456
|
+
| 8 | NTS setup (optional, future) | 4 hours | Step 5, chrony 4.0+ |
|
|
457
|
+
|
|
458
|
+
**Total: ~10 hours for Tiers 1+2, ~14 hours with NTS**
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Security Considerations
|
|
463
|
+
|
|
464
|
+
- **Rate limiting**: 60 req/min per IP on the HTTP API (Caddy rate_limit plugin)
|
|
465
|
+
- **No auth required**: Time is a public good — unauthenticated, CORS-open
|
|
466
|
+
- **Read-only**: API is GET/HEAD only, no writes, no state mutation
|
|
467
|
+
- **SNMP isolation**: MA-902 SNMP is LAN-only (192.168.1.x), never exposed publicly
|
|
468
|
+
- **GPS spoofing**: MA-902 has quality indicators; if satellites degrade, the API
|
|
469
|
+
returns `"quality": "degraded"` and clients can fall back to system time
|
|
470
|
+
- **DDoS**: Caddy handles TLS termination; chrony handles NTP amplification protection
|
|
471
|
+
via `ratelimit` directive
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
*Created: 2026-02-21 | Part of YAKMESH MANI Time Protocol Suite*
|