Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview: router: no-@ handles and flattened dids

Introduces two new user routing options: handles without @'s will
redirect to their @'d counterparts, and did-plc-foobar (a flattened
did) will redirect to did:plc:foobar.

These can now be used as valid Go modules.

+179 -1
+1 -1
appview/state/pull.go
··· 122 122 123 123 secret, err := db.GetRegistrationKey(s.db, f.Knot) 124 124 if err != nil { 125 - log.Printf("failed to get registration key: %w", err) 125 + log.Printf("failed to get registration key: %v", err) 126 126 return types.MergeCheckResponse{ 127 127 Error: "failed to check merge status: this knot is unregistered", 128 128 }
+64
appview/state/router.go
··· 2 2 3 3 import ( 4 4 "net/http" 5 + "regexp" 5 6 "strings" 6 7 7 8 "github.com/go-chi/chi/v5" ··· 16 15 if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") { 17 16 s.UserRouter().ServeHTTP(w, r) 18 17 } else { 18 + // Check if the first path element is a valid handle without '@' or a flattened DID 19 + pathParts := strings.SplitN(pat, "/", 2) 20 + if len(pathParts) > 0 { 21 + if isHandleNoAt(pathParts[0]) { 22 + // Redirect to the same path but with '@' prefixed to the handle 23 + redirectPath := "@" + pat 24 + http.Redirect(w, r, "/"+redirectPath, http.StatusFound) 25 + return 26 + } else if isFlattenedDid(pathParts[0]) { 27 + // Redirect to the unflattened DID version 28 + unflattenedDid := unflattenDid(pathParts[0]) 29 + var redirectPath string 30 + if len(pathParts) > 1 { 31 + redirectPath = unflattenedDid + "/" + pathParts[1] 32 + } else { 33 + redirectPath = unflattenedDid 34 + } 35 + http.Redirect(w, r, "/"+redirectPath, http.StatusFound) 36 + return 37 + } 38 + } 19 39 s.StandardRouter().ServeHTTP(w, r) 20 40 } 21 41 }) 22 42 23 43 return router 44 + } 45 + 46 + func isHandleNoAt(s string) bool { 47 + // ref: https://atproto.com/specs/handle 48 + re := regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`) 49 + return re.MatchString(s) 50 + } 51 + 52 + func unflattenDid(s string) string { 53 + if !isFlattenedDid(s) { 54 + return s 55 + } 56 + 57 + parts := strings.SplitN(s[4:], "-", 2) // Skip "did-" prefix and split on first "-" 58 + if len(parts) != 2 { 59 + return s 60 + } 61 + 62 + return "did:" + parts[0] + ":" + parts[1] 63 + } 64 + 65 + // isFlattenedDid checks if the given string is a flattened DID. 66 + // A flattened DID is a DID with the :s swapped to -s to satisfy certain 67 + // application requirements, such as Go module naming conventions. 68 + func isFlattenedDid(s string) bool { 69 + // Check if the string starts with "did-" 70 + if !strings.HasPrefix(s, "did-") { 71 + return false 72 + } 73 + 74 + // Split the string to extract method and identifier 75 + parts := strings.SplitN(s[4:], "-", 2) // Skip "did-" prefix and split on first "-" 76 + if len(parts) != 2 { 77 + return false 78 + } 79 + 80 + // Reconstruct as a standard DID format 81 + // Example: "did-plc-xyz-abc" becomes "did:plc:xyz-abc" 82 + reconstructed := "did:" + parts[0] + ":" + parts[1] 83 + re := regexp.MustCompile(`^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$`) 84 + 85 + return re.MatchString(reconstructed) 24 86 } 25 87 26 88 func (s *State) UserRouter() http.Handler {
+114
appview/state/router_test.go
··· 1 + package state 2 + 3 + import "testing" 4 + 5 + func TestUnflattenDid(t *testing.T) { 6 + unflattenedMap := map[string]string{ 7 + "did-plc-abcdefghijklmnopqrstuvwxyz": "did:plc:abcdefghijklmnopqrstuvwxyz", 8 + "did-plc-1234567890": "did:plc:1234567890", 9 + "did-key-z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", 10 + "did-plc-abcdefghi-jklmnopqr-stuvwxyz": "did:plc:abcdefghi-jklmnopqr-stuvwxyz", 11 + "plc-abcdefghijklmnopqrstuvwxyz": "plc-abcdefghijklmnopqrstuvwxyz", 12 + "didplc-abcdefghijklmnopqrstuvwxyz": "didplc-abcdefghijklmnopqrstuvwxyz", 13 + "": "", 14 + "did-": "did-", 15 + "did:plc:abcdefghijklmnopqrstuvwxyz": "did:plc:abcdefghijklmnopqrstuvwxyz", 16 + "did-invalid$format:something": "did-invalid$format:something", 17 + } 18 + 19 + tests := []struct { 20 + name string 21 + input string 22 + expected string 23 + }{} 24 + 25 + for _, tc := range isFlattenedDidTests { 26 + tests = append(tests, struct { 27 + name string 28 + input string 29 + expected string 30 + }{ 31 + name: tc.name, 32 + input: tc.input, 33 + expected: unflattenedMap[tc.input], 34 + }) 35 + } 36 + 37 + for _, tc := range tests { 38 + t.Run(tc.name, func(t *testing.T) { 39 + result := unflattenDid(tc.input) 40 + if result != tc.expected { 41 + t.Errorf("unflattenDid(%q) = %q, want %q", tc.input, result, tc.expected) 42 + } 43 + }) 44 + } 45 + } 46 + 47 + var isFlattenedDidTests = []struct { 48 + name string 49 + input string 50 + expected bool 51 + }{ 52 + { 53 + name: "valid flattened DID", 54 + input: "did-plc-abcdefghijklmnopqrstuvwxyz", 55 + expected: true, 56 + }, 57 + { 58 + name: "valid flattened DID with numbers", 59 + input: "did-plc-1234567890", 60 + expected: true, 61 + }, 62 + { 63 + name: "valid flattened DID with special characters", 64 + input: "did-key-z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", 65 + expected: true, 66 + }, 67 + { 68 + name: "valid flattened DID with dashes", 69 + input: "did-plc-abcdefghi-jklmnopqr-stuvwxyz", 70 + expected: true, 71 + }, 72 + 73 + { 74 + name: "doesn't start with did-", 75 + input: "plc-abcdefghijklmnopqrstuvwxyz", 76 + expected: false, 77 + }, 78 + { 79 + name: "no hyphen after did", 80 + input: "didplc-abcdefghijklmnopqrstuvwxyz", 81 + expected: false, 82 + }, 83 + { 84 + name: "empty string", 85 + input: "", 86 + expected: false, 87 + }, 88 + { 89 + name: "only did-", 90 + input: "did-", 91 + expected: false, 92 + }, 93 + { 94 + name: "standard DID format, not flattened", 95 + input: "did:plc:abcdefghijklmnopqrstuvwxyz", 96 + expected: false, 97 + }, 98 + { 99 + name: "invalid reconstructed DID format", 100 + input: "did-invalid$format:something", 101 + expected: false, 102 + }, 103 + } 104 + 105 + func TestIsFlattenedDid(t *testing.T) { 106 + for _, tc := range isFlattenedDidTests { 107 + t.Run(tc.name, func(t *testing.T) { 108 + result := isFlattenedDid(tc.input) 109 + if result != tc.expected { 110 + t.Errorf("isFlattenedDid(%q) = %v, want %v", tc.input, result, tc.expected) 111 + } 112 + }) 113 + } 114 + }