Files
next.orly.dev/pkg/bunker/acl_adapter.go
woikos d41c332d06
Some checks failed
Go / build-and-release (push) Has been cancelled
Add NRC (Nostr Relay Connect) protocol and web UI (v0.48.9)
- Implement NIP-NRC protocol for remote relay access through public relay tunnel
- Add NRC bridge service with NIP-44 encrypted message tunneling
- Add NRC client library for applications
- Add session management with subscription tracking and expiry
- Add URI parsing for nostr+relayconnect:// scheme with secret and CAT auth
- Add NRC API endpoints for connection management (create/list/delete/get-uri)
- Add RelayConnectView.svelte component for managing NRC connections in web UI
- Add NRC database storage for connection secrets and labels
- Add NRC CLI commands (generate, list, revoke)
- Add support for Cashu Access Tokens (CAT) in NRC URIs
- Add ScopeNRC constant for Cashu token scope
- Add wasm build infrastructure and stub files

Files modified:
- app/config/config.go: NRC configuration options
- app/handle-nrc.go: New API handlers for NRC connections
- app/main.go: NRC bridge startup integration
- app/server.go: Register NRC API routes
- app/web/src/App.svelte: Add Relay Connect tab
- app/web/src/RelayConnectView.svelte: New NRC management component
- app/web/src/api.js: NRC API client functions
- main.go: NRC CLI command handlers
- pkg/bunker/acl_adapter.go: Add NRC scope mapping
- pkg/cashu/token/token.go: Add ScopeNRC constant
- pkg/database/nrc.go: NRC connection storage
- pkg/protocol/nrc/: New NRC protocol implementation
- docs/NIP-NRC.md: NIP specification document

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 03:40:12 +01:00

102 lines
2.9 KiB
Go

// Package bunker implements NIP-46 remote signing with Cashu token authentication.
package bunker
import (
"context"
"next.orly.dev/pkg/acl"
acliface "next.orly.dev/pkg/interfaces/acl"
cashuiface "next.orly.dev/pkg/interfaces/cashu"
"next.orly.dev/pkg/cashu/token"
)
// ACLAuthzChecker adapts ORLY's ACL system to cashu.AuthzChecker.
// This allows the Cashu token system to use the existing ACL for authorization.
type ACLAuthzChecker struct {
// ScopeRequirements maps scopes to required access levels.
// If not set, defaults are used.
ScopeRequirements map[string]string
}
// NewACLAuthzChecker creates a new ACL-based authorization checker.
func NewACLAuthzChecker() *ACLAuthzChecker {
return &ACLAuthzChecker{
ScopeRequirements: map[string]string{
token.ScopeRelay: acliface.Write, // Relay access requires write
token.ScopeNIP46: acliface.Write, // Bunker access requires write
token.ScopeBlossom: acliface.Write, // Blossom access requires write
token.ScopeAPI: acliface.Admin, // API access requires admin
token.ScopeNRC: acliface.Write, // NRC tunnel access requires write
},
}
}
// CheckAuthorization checks if a pubkey is authorized for a scope.
func (a *ACLAuthzChecker) CheckAuthorization(ctx context.Context, pubkey []byte, scope string, remoteAddr string) error {
// Get access level from ACL registry
level := acl.Registry.GetAccessLevel(pubkey, remoteAddr)
// Check against required level for scope
requiredLevel, ok := a.ScopeRequirements[scope]
if !ok {
// Default to write access for unknown scopes
requiredLevel = acliface.Write
}
if !hasAccessLevel(level, requiredLevel) {
return cashuiface.NewAuthzError(
cashuiface.ErrCodeInsufficientAccess,
"insufficient access level for scope "+scope,
)
}
// Check for banned/blocked status
if level == "banned" {
return cashuiface.ErrBanned
}
if level == "blocked" {
return cashuiface.ErrBlocked
}
return nil
}
// ReauthorizationEnabled returns true - we always re-check ACL on each verification.
func (a *ACLAuthzChecker) ReauthorizationEnabled() bool {
return true
}
// hasAccessLevel checks if the actual level meets or exceeds the required level.
func hasAccessLevel(actual, required string) bool {
levels := map[string]int{
acliface.None: 0,
"banned": 0,
"blocked": 0,
acliface.Read: 1,
acliface.Write: 2,
acliface.Admin: 3,
acliface.Owner: 4,
}
actualLevel, aok := levels[actual]
requiredLevel, rok := levels[required]
if !aok || !rok {
return false
}
return actualLevel >= requiredLevel
}
// SetScopeRequirement sets the required access level for a scope.
func (a *ACLAuthzChecker) SetScopeRequirement(scope, level string) {
if a.ScopeRequirements == nil {
a.ScopeRequirements = make(map[string]string)
}
a.ScopeRequirements[scope] = level
}
// Ensure ACLAuthzChecker implements both interfaces.
var _ cashuiface.AuthzChecker = (*ACLAuthzChecker)(nil)
var _ cashuiface.ReauthorizationChecker = (*ACLAuthzChecker)(nil)