summaryrefslogtreecommitdiffstats
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/auth/README.md4
-rw-r--r--internal/auth/auth_test.go4
-rw-r--r--internal/auth/interceptor.go15
-rw-r--r--internal/config/config.go75
-rw-r--r--internal/metrics/metrics.go9
5 files changed, 80 insertions, 27 deletions
diff --git a/internal/auth/README.md b/internal/auth/README.md
index de37010..98d1437 100644
--- a/internal/auth/README.md
+++ b/internal/auth/README.md
@@ -142,11 +142,11 @@ import (
142 142
143// Create auth options 143// Create auth options
144authOpts := &auth.InterceptorOptions{ 144authOpts := &auth.InterceptorOptions{
145 Read: auth.OperationAuthConfig{ 145 Read: auth.AuthOperationConfig{
146 Enabled: true, // Require auth for reads 146 Enabled: true, // Require auth for reads
147 AllowedNpubs: nil, // Accept any valid signature 147 AllowedNpubs: nil, // Accept any valid signature
148 }, 148 },
149 Write: auth.OperationAuthConfig{ 149 Write: auth.AuthOperationConfig{
150 Enabled: true, 150 Enabled: true,
151 AllowedNpubs: []string{"hex-pubkey-1", "hex-pubkey-2"}, // Whitelist 151 AllowedNpubs: []string{"hex-pubkey-1", "hex-pubkey-2"}, // Whitelist
152 }, 152 },
diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go
index 7b0fa13..68c68f5 100644
--- a/internal/auth/auth_test.go
+++ b/internal/auth/auth_test.go
@@ -243,11 +243,11 @@ func TestValidateAuthFromContext(t *testing.T) {
243 ctx := metadata.NewIncomingContext(context.Background(), md) 243 ctx := metadata.NewIncomingContext(context.Background(), md)
244 244
245 opts := &InterceptorOptions{ 245 opts := &InterceptorOptions{
246 Read: OperationAuthConfig{ 246 Read: AuthOperationConfig{
247 Enabled: true, 247 Enabled: true,
248 AllowedNpubs: nil, 248 AllowedNpubs: nil,
249 }, 249 },
250 Write: OperationAuthConfig{ 250 Write: AuthOperationConfig{
251 Enabled: true, 251 Enabled: true,
252 AllowedNpubs: nil, 252 AllowedNpubs: nil,
253 }, 253 },
diff --git a/internal/auth/interceptor.go b/internal/auth/interceptor.go
index 42c2688..67450ce 100644
--- a/internal/auth/interceptor.go
+++ b/internal/auth/interceptor.go
@@ -18,28 +18,25 @@ const (
18) 18)
19 19
20type InterceptorOptions struct { 20type InterceptorOptions struct {
21 Read OperationAuthConfig 21 Read AuthOperationConfig
22 Write OperationAuthConfig 22 Write AuthOperationConfig
23 TimestampWindow int64 23 TimestampWindow int64
24 ValidatePayload bool 24 ValidatePayload bool
25 SkipMethods []string 25 SkipMethods []string
26} 26}
27 27
28// OperationAuthConfig configures auth for read or write operations. 28type AuthOperationConfig struct {
29// Three states: disabled (allow all), enabled with empty list (require auth),
30// enabled with npubs (whitelist only). Npubs normalized to hex at load time.
31type OperationAuthConfig struct {
32 Enabled bool 29 Enabled bool
33 AllowedNpubs []string 30 AllowedNpubs []string
34} 31}
35 32
36func DefaultInterceptorOptions() *InterceptorOptions { 33func DefaultInterceptorOptions() *InterceptorOptions {
37 return &InterceptorOptions{ 34 return &InterceptorOptions{
38 Read: OperationAuthConfig{ 35 Read: AuthOperationConfig{
39 Enabled: false, 36 Enabled: false,
40 AllowedNpubs: nil, 37 AllowedNpubs: nil,
41 }, 38 },
42 Write: OperationAuthConfig{ 39 Write: AuthOperationConfig{
43 Enabled: false, 40 Enabled: false,
44 AllowedNpubs: nil, 41 AllowedNpubs: nil,
45 }, 42 },
@@ -154,7 +151,7 @@ func validateAuthFromContext(ctx context.Context, method string, opts *Intercept
154 151
155 pubkey := ExtractPubkey(event) 152 pubkey := ExtractPubkey(event)
156 153
157 var opConfig OperationAuthConfig 154 var opConfig AuthOperationConfig
158 if isWriteMethod(method) { 155 if isWriteMethod(method) {
159 opConfig = opts.Write 156 opConfig = opts.Write
160 } else { 157 } else {
diff --git a/internal/config/config.go b/internal/config/config.go
index 36c8be5..dcceade 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -7,6 +7,9 @@ import (
7 "time" 7 "time"
8 8
9 "gopkg.in/yaml.v3" 9 "gopkg.in/yaml.v3"
10 "northwest.io/muxstr/internal/auth"
11 "northwest.io/muxstr/internal/metrics"
12 "northwest.io/muxstr/internal/ratelimit"
10 "northwest.io/nostr" 13 "northwest.io/nostr"
11) 14)
12 15
@@ -33,18 +36,10 @@ type DatabaseConfig struct {
33} 36}
34 37
35type AuthConfig struct { 38type AuthConfig struct {
36 Read AuthOperationConfig `yaml:"read"` 39 Read auth.AuthOperationConfig `yaml:"read"`
37 Write AuthOperationConfig `yaml:"write"` 40 Write auth.AuthOperationConfig `yaml:"write"`
38 TimestampWindow int64 `yaml:"timestamp_window"` 41 TimestampWindow int64 `yaml:"timestamp_window"`
39 SkipMethods []string `yaml:"skip_methods"` 42 SkipMethods []string `yaml:"skip_methods"`
40}
41
42// AuthOperationConfig configures auth for read or write operations.
43// Three states: disabled (allow all), enabled with empty list (require auth),
44// enabled with npubs (whitelist only). Npubs normalized to hex at load time.
45type AuthOperationConfig struct {
46 Enabled bool `yaml:"enabled"`
47 AllowedNpubs []string `yaml:"allowed_npubs"`
48} 43}
49 44
50type RateLimitConfig struct { 45type RateLimitConfig struct {
@@ -105,11 +100,11 @@ func Default() *Config {
105 Path: "relay.db", 100 Path: "relay.db",
106 }, 101 },
107 Auth: AuthConfig{ 102 Auth: AuthConfig{
108 Read: AuthOperationConfig{ 103 Read: auth.AuthOperationConfig{
109 Enabled: false, 104 Enabled: false,
110 AllowedNpubs: nil, 105 AllowedNpubs: nil,
111 }, 106 },
112 Write: AuthOperationConfig{ 107 Write: auth.AuthOperationConfig{
113 Enabled: false, 108 Enabled: false,
114 AllowedNpubs: nil, 109 AllowedNpubs: nil,
115 }, 110 },
@@ -349,3 +344,55 @@ func (c *Config) Save(filename string) error {
349 344
350 return nil 345 return nil
351} 346}
347
348func (r *RateLimitConfig) ToRateLimiter() *ratelimit.Config {
349 rlConfig := &ratelimit.Config{
350 RequestsPerSecond: r.DefaultRPS,
351 BurstSize: r.DefaultBurst,
352 IPRequestsPerSecond: r.IPRPS,
353 IPBurstSize: r.IPBurst,
354 SkipMethods: r.SkipMethods,
355 SkipUsers: r.SkipUsers,
356 CleanupInterval: r.CleanupInterval,
357 MaxIdleTime: r.MaxIdleTime,
358 }
359
360 if r.Methods != nil {
361 rlConfig.MethodLimits = make(map[string]ratelimit.MethodLimit, len(r.Methods))
362 for method, limit := range r.Methods {
363 rlConfig.MethodLimits[method] = ratelimit.MethodLimit{
364 RequestsPerSecond: limit.RPS,
365 BurstSize: limit.Burst,
366 }
367 }
368 }
369
370 if r.Users != nil {
371 rlConfig.UserLimits = make(map[string]ratelimit.UserLimit, len(r.Users))
372 for user, limit := range r.Users {
373 userLimit := ratelimit.UserLimit{
374 RequestsPerSecond: limit.RPS,
375 BurstSize: limit.Burst,
376 }
377 if limit.Methods != nil {
378 userLimit.MethodLimits = make(map[string]ratelimit.MethodLimit, len(limit.Methods))
379 for method, methodLimit := range limit.Methods {
380 userLimit.MethodLimits[method] = ratelimit.MethodLimit{
381 RequestsPerSecond: methodLimit.RPS,
382 BurstSize: methodLimit.Burst,
383 }
384 }
385 }
386 rlConfig.UserLimits[user] = userLimit
387 }
388 }
389
390 return rlConfig
391}
392
393func (m *MetricsConfig) ToMetrics() *metrics.Config {
394 return &metrics.Config{
395 Namespace: m.Namespace,
396 Subsystem: m.Subsystem,
397 }
398}
diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go
index 3cb675f..9030d67 100644
--- a/internal/metrics/metrics.go
+++ b/internal/metrics/metrics.go
@@ -1,8 +1,11 @@
1package metrics 1package metrics
2 2
3import ( 3import (
4 "net/http"
5
4 "github.com/prometheus/client_golang/prometheus" 6 "github.com/prometheus/client_golang/prometheus"
5 "github.com/prometheus/client_golang/prometheus/promauto" 7 "github.com/prometheus/client_golang/prometheus/promauto"
8 "github.com/prometheus/client_golang/prometheus/promhttp"
6) 9)
7 10
8// Metrics holds all Prometheus metrics for the relay. 11// Metrics holds all Prometheus metrics for the relay.
@@ -280,3 +283,9 @@ const (
280 StatusRateLimited RequestStatus = "rate_limited" 283 StatusRateLimited RequestStatus = "rate_limited"
281 StatusInvalidRequest RequestStatus = "invalid_request" 284 StatusInvalidRequest RequestStatus = "invalid_request"
282) 285)
286
287func (m *Metrics) Serve(addr, path string) error {
288 mux := http.NewServeMux()
289 mux.Handle(path, promhttp.Handler())
290 return http.ListenAndServe(addr, mux)
291}