You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
did:nostr agents are now first-class at level 0: an Authorization: Nostr
header (NIP-98 kind-27235 event) authenticates as did:nostr:<pubkey> with no
registration. lib/nip98.js verifies structure per the nip98 client library's
contract and adds the half it deliberately leaves out — NIP-01 event id +
BIP-340 schnorr via @noble/curves (the repo's one dependency, replacing the
zero-dep claim). Payload-tag binding is strict both ways: a body must hash to
the tag, and a body-carrying request without a payload tag is refused (else a
signed GET header could replay onto a write). Body is read before auth so the
exact wire bytes are verified.
UI gains "Sign in with Nostr" via the vendored xlogin widget (extension,
guest key, or pasted privkey — it's a testnet), served at /xlogin.js
(AGPL-3.0-or-later, same author, licensing noted in the header); api() picks
bearer or window.xlogin.authFetch automatically. Spec §10 now defines both
auth schemes normatively (+ NIP-98 reference); landing + roadmap updated;
signed *transitions* remain level 1. +6 tests incl. all forged/stale/
mismatched/replayed header shapes; 25 green.
Copy file name to clipboardExpand all lines: README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ node server.js
20
20
# solidpay node listening on port 3480 → open http://localhost:3480
21
21
```
22
22
23
-
Zero dependencies — plain Node.js ≥ 20. Behind a proxy:
23
+
One dependency — [`@noble/curves`](https://github.com/paulmillr/noble-curves) for BIP-340 signature verification — on plain Node.js ≥ 20. Behind a proxy:
<button class="btn" id="a-nostr" style="width:100%">⚡ Sign in with Nostr</button>
149
155
<div class="formmsg" id="a-msg"></div>
150
156
</div></div>
151
-
<p class="help" style="text-align:center;margin-top:14px">Testnet — play money, real protocol. did:nostr sign-in arrives in v1.</p>
157
+
<p class="help" style="text-align:center;margin-top:14px">Testnet — play money, real protocol. Nostr sign-in: extension, guest key, or paste a private key (via <a href="https://github.com/melvincarvalho/xlogin">xlogin</a>); requests are NIP-98 signed, your agent is <code>did:nostr:<pubkey></code>.</p>
152
158
</div>
153
159
</section>
154
160
@@ -247,7 +253,17 @@ function whoChip(id){return '<span class="who">'+avatar(id)+'<span class="nm" ti
247
253
function toast(m){var t=$('toast');t.textContent=m;t.classList.add('show');clearTimeout(toast._t);toast._t=setTimeout(function(){t.classList.remove('show')},2300)}
248
254
function token(){return localStorage.getItem('solidpayToken')||''}
249
255
function hdrs(){var h={'content-type':'application/json'};if(token())h.authorization='Bearer '+token();return h}
250
-
function api(p,opt){return fetch('/api'+p,opt).then(function(r){return r.json().then(function(b){return{ok:r.ok,status:r.status,body:b}}).catch(function(){return{ok:r.ok,status:r.status,body:{}}})})}
256
+
function nostrOn(){return !token()&&window.xlogin&&window.xlogin.type==='nostr'&&window.xlogin.id}
257
+
/* One fetch for both auth schemes: a stored bearer wins; else, with an active
var wrap=function(r){return r.json().then(function(b){return{ok:r.ok,status:r.status,body:b}}).catch(function(){return{ok:r.ok,status:r.status,body:{}}})};
0 commit comments