Stateless auth proxy that converts AT Protocol native apps from public to confidential OAuth clients. Deploy once, get 180-day refresh tokens instead of 24-hour ones.
9
fork

Configure Feed

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

at main 97 lines 3.3 kB view raw
1package main 2 3import ( 4 "net" 5 "testing" 6) 7 8func TestValidateTokenEndpoint(t *testing.T) { 9 clearAllowedHosts() 10 11 tests := []struct { 12 name string 13 rawURL string 14 wantErr bool 15 }{ 16 {name: "valid HTTPS URL", rawURL: "https://bsky.social/oauth/token"}, 17 {name: "HTTP rejected", rawURL: "http://bsky.social/oauth/token", wantErr: true}, 18 {name: "empty URL rejected", rawURL: "", wantErr: true}, 19 {name: "localhost rejected", rawURL: "https://localhost/oauth/token", wantErr: true}, 20 {name: "loopback rejected", rawURL: "https://127.0.0.1/oauth/token", wantErr: true}, 21 {name: "private IPv4 rejected", rawURL: "https://10.0.0.1/oauth/token", wantErr: true}, 22 {name: "cloud metadata rejected", rawURL: "https://169.254.169.254/oauth/token", wantErr: true}, 23 {name: "IPv6 loopback rejected", rawURL: "https://[::1]/oauth/token", wantErr: true}, 24 {name: "query rejected", rawURL: "https://bsky.social/oauth/token?x=1", wantErr: true}, 25 {name: "fragment rejected", rawURL: "https://bsky.social/oauth/token#frag", wantErr: true}, 26 {name: "no scheme rejected", rawURL: "bsky.social/oauth/token", wantErr: true}, 27 } 28 29 for _, tt := range tests { 30 t.Run(tt.name, func(t *testing.T) { 31 err := ValidateTokenEndpoint(tt.rawURL) 32 if (err != nil) != tt.wantErr { 33 t.Fatalf("ValidateTokenEndpoint(%q) error = %v, wantErr=%v", tt.rawURL, err, tt.wantErr) 34 } 35 }) 36 } 37} 38 39func TestValidateIssuer(t *testing.T) { 40 clearAllowedHosts() 41 42 tests := []struct { 43 name string 44 issuer string 45 wantErr bool 46 }{ 47 {name: "valid issuer", issuer: "https://bsky.social"}, 48 {name: "valid issuer with trailing slash", issuer: "https://bsky.social/"}, 49 {name: "issuer path rejected", issuer: "https://bsky.social/oauth", wantErr: true}, 50 {name: "issuer query rejected", issuer: "https://bsky.social?x=1", wantErr: true}, 51 {name: "issuer fragment rejected", issuer: "https://bsky.social#frag", wantErr: true}, 52 {name: "issuer localhost rejected", issuer: "https://localhost", wantErr: true}, 53 {name: "issuer default port rejected", issuer: "https://bsky.social:443", wantErr: true}, 54 } 55 56 for _, tt := range tests { 57 t.Run(tt.name, func(t *testing.T) { 58 _, err := ValidateIssuer(tt.issuer) 59 if (err != nil) != tt.wantErr { 60 t.Fatalf("ValidateIssuer(%q) error = %v, wantErr=%v", tt.issuer, err, tt.wantErr) 61 } 62 }) 63 } 64} 65 66func TestIsPublicIPAddress(t *testing.T) { 67 tests := []struct { 68 ipStr string 69 isPublic bool 70 }{ 71 {ipStr: "8.8.8.8", isPublic: true}, 72 {ipStr: "1.1.1.1", isPublic: true}, 73 {ipStr: "10.0.0.1", isPublic: false}, 74 {ipStr: "100.64.0.1", isPublic: false}, 75 {ipStr: "127.0.0.1", isPublic: false}, 76 {ipStr: "169.254.169.254", isPublic: false}, 77 {ipStr: "192.0.2.10", isPublic: false}, 78 {ipStr: "203.0.113.10", isPublic: false}, 79 {ipStr: "::1", isPublic: false}, 80 {ipStr: "fe80::1", isPublic: false}, 81 {ipStr: "fc00::1", isPublic: false}, 82 {ipStr: "2606:4700:4700::1111", isPublic: true}, 83 } 84 85 for _, tt := range tests { 86 t.Run(tt.ipStr, func(t *testing.T) { 87 ip := net.ParseIP(tt.ipStr) 88 if ip == nil { 89 t.Fatalf("failed to parse IP %q", tt.ipStr) 90 } 91 92 if got := IsPublicIPAddress(ip); got != tt.isPublic { 93 t.Fatalf("IsPublicIPAddress(%q) = %v, want %v", tt.ipStr, got, tt.isPublic) 94 } 95 }) 96 } 97}