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.
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}