summaryrefslogtreecommitdiffstats
path: root/internal/config/config_test.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-14 10:02:52 -0800
committerbndw <ben@bdw.to>2026-02-14 10:02:52 -0800
commit5d21632ea70e1c7de7becb7ab6227b06b1535a83 (patch)
treee63bcbe8cdf7dc888ca0e3476ad529690a0a44a8 /internal/config/config_test.go
parentd30459513ec44ab298fafd1bfe0edc08d6ab62e4 (diff)
feat: add separate read/write allowlists for granular access control
- Split allowed_npubs into allowed_npubs_read and allowed_npubs_write - Write operations: Publish, Delete, Create, Update, Insert, Remove, Set, Put - Read operations: everything else (Query, Subscribe, Get, List, etc.) - Auth interceptor checks appropriate list based on method type - Enables common patterns: - Public relay: only some can write, everyone can read - Private relay: restricted read and write - Open relay: everyone can read and write - Updated config, docs, and comprehensive tests Use cases: "only some can write, everyone can read"
Diffstat (limited to 'internal/config/config_test.go')
-rw-r--r--internal/config/config_test.go136
1 files changed, 102 insertions, 34 deletions
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 5fa159e..c0d4555 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -260,9 +260,11 @@ database:
260 260
261auth: 261auth:
262 enabled: true 262 enabled: true
263 allowed_npubs: 263 allowed_npubs_read:
264 - npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6 264 - npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6
265 - npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft 265 - npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft
266 allowed_npubs_write:
267 - npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6
266` 268`
267 269
268 if _, err := tmpfile.Write([]byte(configData)); err != nil { 270 if _, err := tmpfile.Write([]byte(configData)); err != nil {
@@ -275,18 +277,32 @@ auth:
275 t.Fatalf("failed to load config: %v", err) 277 t.Fatalf("failed to load config: %v", err)
276 } 278 }
277 279
278 // Verify npubs were normalized to hex 280 // Verify read npubs were normalized to hex
279 if len(cfg.Auth.AllowedNpubs) != 2 { 281 if len(cfg.Auth.AllowedNpubsRead) != 2 {
280 t.Errorf("expected 2 allowed npubs, got %d", len(cfg.Auth.AllowedNpubs)) 282 t.Errorf("expected 2 allowed npubs for read, got %d", len(cfg.Auth.AllowedNpubsRead))
283 }
284
285 // Verify write npubs were normalized to hex
286 if len(cfg.Auth.AllowedNpubsWrite) != 1 {
287 t.Errorf("expected 1 allowed npub for write, got %d", len(cfg.Auth.AllowedNpubsWrite))
281 } 288 }
282 289
283 // Check that they're hex format (64 chars, not npub1...) 290 // Check that they're hex format (64 chars, not npub1...)
284 for i, pubkey := range cfg.Auth.AllowedNpubs { 291 for i, pubkey := range cfg.Auth.AllowedNpubsRead {
292 if len(pubkey) != 64 {
293 t.Errorf("read npub %d: expected 64 hex chars, got %d", i, len(pubkey))
294 }
295 if len(pubkey) >= 5 && pubkey[:5] == "npub1" {
296 t.Errorf("read npub %d: should be normalized to hex, still in npub format", i)
297 }
298 }
299
300 for i, pubkey := range cfg.Auth.AllowedNpubsWrite {
285 if len(pubkey) != 64 { 301 if len(pubkey) != 64 {
286 t.Errorf("npub %d: expected 64 hex chars, got %d", i, len(pubkey)) 302 t.Errorf("write npub %d: expected 64 hex chars, got %d", i, len(pubkey))
287 } 303 }
288 if pubkey[:5] == "npub1" { 304 if len(pubkey) >= 5 && pubkey[:5] == "npub1" {
289 t.Errorf("npub %d: should be normalized to hex, still in npub format", i) 305 t.Errorf("write npub %d: should be normalized to hex, still in npub format", i)
290 } 306 }
291 } 307 }
292 308
@@ -294,46 +310,98 @@ auth:
294 expectedHex1 := "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" 310 expectedHex1 := "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
295 expectedHex2 := "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52" 311 expectedHex2 := "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"
296 312
297 if cfg.Auth.AllowedNpubs[0] != expectedHex1 { 313 if cfg.Auth.AllowedNpubsRead[0] != expectedHex1 {
298 t.Errorf("npub 0: expected %s, got %s", expectedHex1, cfg.Auth.AllowedNpubs[0]) 314 t.Errorf("read npub 0: expected %s, got %s", expectedHex1, cfg.Auth.AllowedNpubsRead[0])
315 }
316 if cfg.Auth.AllowedNpubsRead[1] != expectedHex2 {
317 t.Errorf("read npub 1: expected %s, got %s", expectedHex2, cfg.Auth.AllowedNpubsRead[1])
299 } 318 }
300 if cfg.Auth.AllowedNpubs[1] != expectedHex2 { 319 if cfg.Auth.AllowedNpubsWrite[0] != expectedHex1 {
301 t.Errorf("npub 1: expected %s, got %s", expectedHex2, cfg.Auth.AllowedNpubs[1]) 320 t.Errorf("write npub 0: expected %s, got %s", expectedHex1, cfg.Auth.AllowedNpubsWrite[0])
302 } 321 }
303} 322}
304 323
305func TestNpubValidation(t *testing.T) { 324func TestNpubValidation(t *testing.T) {
306 tmpfile, err := os.CreateTemp("", "config-*.yaml") 325 tests := []struct {
307 if err != nil { 326 name string
308 t.Fatal(err) 327 config string
309 } 328 expectError bool
310 defer os.Remove(tmpfile.Name()) 329 errorMsg string
311 330 }{
312 // Invalid: hex format instead of npub 331 {
313 configData := ` 332 name: "invalid hex in read list",
333 config: `
314server: 334server:
315 grpc_addr: ":50051" 335 grpc_addr: ":50051"
316 http_addr: ":8080" 336 http_addr: ":8080"
317
318database: 337database:
319 path: "test.db" 338 path: "test.db"
320
321auth: 339auth:
322 allowed_npubs: 340 allowed_npubs_read:
323 - 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d 341 - 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
324` 342`,
325 343 expectError: true,
326 if _, err := tmpfile.Write([]byte(configData)); err != nil { 344 errorMsg: "must start with 'npub1'",
327 t.Fatal(err) 345 },
346 {
347 name: "invalid hex in write list",
348 config: `
349server:
350 grpc_addr: ":50051"
351 http_addr: ":8080"
352database:
353 path: "test.db"
354auth:
355 allowed_npubs_write:
356 - 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
357`,
358 expectError: true,
359 errorMsg: "must start with 'npub1'",
360 },
361 {
362 name: "valid npub lists",
363 config: `
364server:
365 grpc_addr: ":50051"
366 http_addr: ":8080"
367database:
368 path: "test.db"
369auth:
370 allowed_npubs_read:
371 - npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6
372 allowed_npubs_write:
373 - npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft
374`,
375 expectError: false,
376 },
328 } 377 }
329 tmpfile.Close()
330 378
331 _, err = Load(tmpfile.Name()) 379 for _, tt := range tests {
332 if err == nil { 380 t.Run(tt.name, func(t *testing.T) {
333 t.Error("expected error for hex format in allowed_npubs, got nil") 381 tmpfile, err := os.CreateTemp("", "config-*.yaml")
334 } 382 if err != nil {
335 if err != nil && !strings.Contains(err.Error(), "must start with 'npub1'") { 383 t.Fatal(err)
336 t.Errorf("expected 'must start with npub1' error, got: %v", err) 384 }
385 defer os.Remove(tmpfile.Name())
386
387 if _, err := tmpfile.Write([]byte(tt.config)); err != nil {
388 t.Fatal(err)
389 }
390 tmpfile.Close()
391
392 _, err = Load(tmpfile.Name())
393 if tt.expectError {
394 if err == nil {
395 t.Error("expected error, got nil")
396 } else if !strings.Contains(err.Error(), tt.errorMsg) {
397 t.Errorf("expected error containing %q, got: %v", tt.errorMsg, err)
398 }
399 } else {
400 if err != nil {
401 t.Errorf("unexpected error: %v", err)
402 }
403 }
404 })
337 } 405 }
338} 406}
339 407