Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37d4be5e93 |
@@ -23,15 +23,27 @@ type CashuMintRequest struct {
|
||||
}
|
||||
|
||||
// CashuMintResponse is the response body for token issuance.
|
||||
// Field names match NIP-XX Cashu Access Tokens spec.
|
||||
type CashuMintResponse struct {
|
||||
BlindedSignature string `json:"blinded_signature"` // Hex-encoded blinded signature C_
|
||||
KeysetID string `json:"keyset_id"` // Keyset ID used
|
||||
Expiry int64 `json:"expiry"` // Token expiration timestamp
|
||||
MintPubkey string `json:"mint_pubkey"` // Hex-encoded mint public key
|
||||
MintPubkey string `json:"pubkey"` // Hex-encoded mint public key (spec: "pubkey")
|
||||
}
|
||||
|
||||
// handleCashuMint handles POST /cashu/mint - issues a new token.
|
||||
func (s *Server) handleCashuMint(w http.ResponseWriter, r *http.Request) {
|
||||
// CORS headers for browser-based CAT token requests
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")
|
||||
|
||||
// Handle preflight
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if Cashu is enabled
|
||||
if s.CashuIssuer == nil {
|
||||
log.W.F("Cashu mint request but issuer not initialized")
|
||||
@@ -107,6 +119,17 @@ func (s *Server) handleCashuMint(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// handleCashuKeysets handles GET /cashu/keysets - returns available keysets.
|
||||
func (s *Server) handleCashuKeysets(w http.ResponseWriter, r *http.Request) {
|
||||
// CORS headers for browser-based CAT support
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept")
|
||||
|
||||
// Handle preflight
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
if s.CashuIssuer == nil {
|
||||
http.Error(w, "Cashu tokens not enabled", http.StatusNotImplemented)
|
||||
return
|
||||
|
||||
@@ -146,8 +146,9 @@ func (l *Listener) HandleEvent(msg []byte) (err error) {
|
||||
// Require Cashu token for NIP-46 events when Cashu is enabled and ACL is active
|
||||
const kindNIP46 = 24133
|
||||
if env.E.Kind == kindNIP46 && l.CashuVerifier != nil && l.Config.ACLMode != "none" {
|
||||
log.D.F("HandleEvent: NIP-46 event from %s, cashuToken=%v, ACLMode=%s", l.remote, l.cashuToken != nil, l.Config.ACLMode)
|
||||
if l.cashuToken == nil {
|
||||
log.W.F("HandleEvent: rejecting NIP-46 event - Cashu access token required")
|
||||
log.W.F("HandleEvent: rejecting NIP-46 event from %s - Cashu access token required (connection has no token)", l.remote)
|
||||
if err = Ok.Error(l, env, "restricted: NIP-46 requires Cashu access token"); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -309,10 +309,12 @@ func (s *Server) Pinger(
|
||||
func (s *Server) extractWebSocketToken(r *http.Request, remote string) *token.Token {
|
||||
// Try query param first (WebSocket clients often can't set custom headers)
|
||||
tokenStr := r.URL.Query().Get("token")
|
||||
log.D.F("ws %s: CAT extraction - query param token: %v", remote, tokenStr != "")
|
||||
|
||||
// Try X-Cashu-Token header
|
||||
if tokenStr == "" {
|
||||
tokenStr = r.Header.Get("X-Cashu-Token")
|
||||
log.D.F("ws %s: CAT extraction - X-Cashu-Token header: %v", remote, tokenStr != "")
|
||||
}
|
||||
|
||||
// Try Authorization: Cashu scheme
|
||||
@@ -321,12 +323,15 @@ func (s *Server) extractWebSocketToken(r *http.Request, remote string) *token.To
|
||||
if strings.HasPrefix(auth, "Cashu ") {
|
||||
tokenStr = strings.TrimPrefix(auth, "Cashu ")
|
||||
}
|
||||
log.D.F("ws %s: CAT extraction - Authorization header: %v", remote, tokenStr != "")
|
||||
}
|
||||
|
||||
// No token provided - this is fine, connection proceeds without token
|
||||
if tokenStr == "" {
|
||||
log.D.F("ws %s: CAT extraction - no token found", remote)
|
||||
return nil
|
||||
}
|
||||
log.D.F("ws %s: CAT extraction - found token (len=%d)", remote, len(tokenStr))
|
||||
|
||||
// Parse the token
|
||||
tok, err := token.Parse(tokenStr)
|
||||
|
||||
@@ -3,6 +3,7 @@ package issuer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -222,22 +223,28 @@ func (i *Issuer) GetActiveKeysetID() string {
|
||||
|
||||
// MintInfo contains public information about the mint.
|
||||
type MintInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version"`
|
||||
TokenTTL int64 `json:"token_ttl"`
|
||||
MaxKinds int `json:"max_kinds,omitempty"`
|
||||
MaxKindRanges int `json:"max_kind_ranges,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version"`
|
||||
Pubkey string `json:"pubkey"`
|
||||
TokenTTL int64 `json:"token_ttl"`
|
||||
MaxKinds int `json:"max_kinds,omitempty"`
|
||||
MaxKindRanges int `json:"max_kind_ranges,omitempty"`
|
||||
SupportedScopes []string `json:"supported_scopes,omitempty"`
|
||||
}
|
||||
|
||||
// GetMintInfo returns public information about the issuer.
|
||||
func (i *Issuer) GetMintInfo(name string) MintInfo {
|
||||
var pubkeyHex string
|
||||
if ks := i.keysets.GetSigningKeyset(); ks != nil {
|
||||
pubkeyHex = hex.EncodeToString(ks.SerializePublicKey())
|
||||
}
|
||||
return MintInfo{
|
||||
Name: name,
|
||||
Version: "NIP-XX/1",
|
||||
TokenTTL: int64(i.config.DefaultTTL.Seconds()),
|
||||
MaxKinds: i.config.MaxKinds,
|
||||
MaxKindRanges: i.config.MaxKindRanges,
|
||||
Name: name,
|
||||
Version: "NIP-XX/1",
|
||||
Pubkey: pubkeyHex,
|
||||
TokenTTL: int64(i.config.DefaultTTL.Seconds()),
|
||||
MaxKinds: i.config.MaxKinds,
|
||||
MaxKindRanges: i.config.MaxKindRanges,
|
||||
SupportedScopes: i.config.AllowedScopes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
v0.50.1
|
||||
v0.51.0
|
||||
Reference in New Issue
Block a user