github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/api_test.go (about) 1 // Copyright 2016 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "crypto/tls" 8 "net/http" 9 "net/url" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 14 keybase1 "github.com/keybase/client/go/protocol/keybase1" 15 ) 16 17 func TestIsReddit(t *testing.T) { 18 // Test both with and without a subdomain. 19 req, _ := http.NewRequest("GET", "http://reddit.com", nil) 20 if !isReddit(req) { 21 t.Fatal("should be a reddit URL") 22 } 23 req, _ = http.NewRequest("GET", "http://www.reddit.com", nil) 24 if !isReddit(req) { 25 t.Fatal("should be a reddit URL") 26 } 27 // Test a non-reddit URL. 28 req, _ = http.NewRequest("GET", "http://github.com", nil) 29 if isReddit(req) { 30 t.Fatal("should NOT be a reddit URL") 31 } 32 } 33 34 const ( 35 uriExpected = "https://api-1.core.keybaseapi.com" 36 pingExpected = "https://api-1.core.keybaseapi.com/_/api/1.0/ping.json" 37 ) 38 39 func TestProductionCA(t *testing.T) { 40 tc := SetupTest(t, "prod_ca", 1) 41 defer tc.Cleanup() 42 mctx := NewMetaContextForTest(tc) 43 44 t.Log("WARNING: setting run mode to production, be careful:") 45 tc.G.Env.Test.UseProductionRunMode = true 46 47 serverURI, err := tc.G.Env.GetServerURI() 48 require.NoError(t, err) 49 50 if serverURI != uriExpected { 51 t.Fatalf("production server uri: %s, expected %s", serverURI, uriExpected) 52 } 53 54 err = tc.G.ConfigureAPI() 55 require.NoError(t, err) 56 57 // make sure endpoint is correct: 58 arg := APIArg{Endpoint: "ping"} 59 internal, ok := tc.G.API.(*InternalAPIEngine) 60 if !ok { 61 t.Fatal("failed to cast API to internal api engine") 62 } 63 url := internal.getURL(arg, false) 64 if url.String() != pingExpected { 65 t.Fatalf("api url: %s, expected %s", url.String(), pingExpected) 66 } 67 68 _, err = tc.G.API.Post(mctx, arg) 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 _, err = tc.G.API.Get(mctx, arg) 74 if err != nil { 75 t.Fatal(err) 76 } 77 } 78 79 func TestProductionBadCA(t *testing.T) { 80 tc := SetupTest(t, "prod_ca", 1) 81 defer tc.Cleanup() 82 mctx := NewMetaContextForTest(tc) 83 84 t.Log("WARNING: setting run mode to production, be careful:") 85 tc.G.Env.Test.UseProductionRunMode = true 86 87 serverURI, err := tc.G.Env.GetServerURI() 88 require.NoError(t, err) 89 90 if serverURI != uriExpected { 91 t.Fatalf("production server uri: %s, expected %s", serverURI, uriExpected) 92 } 93 94 // change the api CA to one that api.keybase.io doesn't know: 95 apiCAOverrideForTest = unknownCA 96 defer func() { 97 apiCAOverrideForTest = "" 98 }() 99 100 err = tc.G.ConfigureAPI() 101 require.NoError(t, err) 102 103 // make sure endpoint is correct: 104 arg := APIArg{Endpoint: "ping"} 105 internal, ok := tc.G.API.(*InternalAPIEngine) 106 if !ok { 107 t.Fatal("failed to cast API to internal api engine") 108 } 109 iurl := internal.getURL(arg, false) 110 if iurl.String() != pingExpected { 111 t.Fatalf("api url: %s, expected %s", iurl.String(), pingExpected) 112 } 113 114 _, err = tc.G.API.Post(mctx, arg) 115 if err == nil { 116 t.Errorf("api ping POST worked with unknown CA") 117 } else { 118 checkX509Err(t, err) 119 } 120 121 _, err = tc.G.API.Get(mctx, arg) 122 if err == nil { 123 t.Errorf("api ping GET worked with unknown CA") 124 } else { 125 checkX509Err(t, err) 126 } 127 } 128 129 // this error is buried, so dig for it: 130 func checkX509Err(t *testing.T, err error) { 131 if err == nil { 132 t.Fatal("isX509Err called with nil error") 133 } 134 135 a, ok := err.(APINetError) 136 if !ok { 137 t.Errorf("invalid error type: %T, expected libkb.APINetError", err) 138 return 139 } 140 141 b, ok := a.Err.(*url.Error) 142 if !ok { 143 t.Errorf("APINetError err field type: %T, expected *url.Error", a.Err) 144 return 145 } 146 147 _, ok = b.Err.(*tls.CertificateVerificationError) 148 if !ok { 149 t.Errorf("url.Error Err field type: %T, expected x509.UnknownAuthorityError", b.Err) 150 } 151 } 152 153 const unknownCA = `-----BEGIN CERTIFICATE----- 154 MIIFgDCCA2gCCQDF4YJuQAWDqTANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMC 155 VVMxCzAJBgNVBAgMAk1BMQ8wDQYDVQQHDAZCb3N0b24xEzARBgNVBAoMCkV4YW1w 156 bGUgQ28xEDAOBgNVBAsMB3RlY2hvcHMxCzAJBgNVBAMMAmNhMSAwHgYJKoZIhvcN 157 AQkBFhFjZXJ0c0BleGFtcGxlLmNvbTAeFw0xNjAyMjUyMTQ3MzhaFw00MzA3MTIy 158 MTQ3MzhaMIGBMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJv 159 c3RvbjETMBEGA1UECgwKRXhhbXBsZSBDbzEQMA4GA1UECwwHdGVjaG9wczELMAkG 160 A1UEAwwCY2ExIDAeBgkqhkiG9w0BCQEWEWNlcnRzQGV4YW1wbGUuY29tMIICIjAN 161 BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8NScIAfl3DK26CwnMSH1TXKurE/B 162 BOocNApkH/913F28AgxzsS+blsG1IyjSuG9ls5shqlGpWQs1kM9PqFz6Yl5Y3H8b 163 cwY0dWk1RmrZ6EWV/lWuLZxiKB8rBJksUVvdcuhnNpvOjYvkTgL9q7OObMdz3lvH 164 2pqwa8TWgw9EITKCam7i4860qcOoVkhCFitrihg182UmXWmuAZOm5N0R9+Y5t8yQ 165 7S3XKYZLtKND7ZGD51AfjN6TN1jN8kd9KMii7JITtvqsJDOxl0Kzn9fefgnCQF1G 166 P7ilLybId4W5pCO/8mKXb0CQlJ9kAYVfxWPNR87ZQA9KLC8nXu3xWaplXZl7T4Tq 167 wZHD85lbpLurSkJliizwDgs3cootEXs04ssl6SpVnc/Qxat3jomCtmKBtY5Cxvy9 168 IwHmaYWCYAIiPcru8U1cVg3xsH6i2JTz7uZRFvEjhYNqr1o6QnKcJ6cYGs13tYwA 169 57Xl1CVJ8hBMmtlzqbA2xMCbmkpWitjzXyArzQjAD0dDeGmStGOOQqy/N4LJaQ6+ 170 +q2bHpx5Cd6DxNf868iWupuKadT923ZDzAn1PhDWugKQ2BSIzM2O57m1HYmGm3be 171 NpwTYKuZGCDaLwDhnbIICTgQXjyCDTV4TfOKBPzr+i+yAjdjJimXHQ5gy7BMJoO6 172 fOWYqbs8vgvx4WUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAhLLxyfdQdQDdo3YG 173 s1fKqm5lLu0Dx6uzNtIVY0n7vyyAolBVDlJ7Du84b344/U4kRgjNwAx2ZECvWkEZ 174 ov6+VMYX6EkV/0nwRNOoADYO8YVlZzBvwZgA12Vkw9NHje18FnQcS3L4nFjJPFoY 175 UEBhK5qTXqxJ9PK9aBZXIhDT2u/o9xEecuC3kjqNI6bi5zsZ5y04Qulr/1UwWy2e 176 IFFfySdL7kzZkhQAawg/+pNgentVykRRNgCVmFQ4uytTpp45pAtSNBaLm8RCrNGF 177 AybVh7HAW+LwjUOPpYQ38j1neiFS8NFJRKNKS2OtbS743NnYWbYOJdGWH4jwOluL 178 PjckYdTGO82EIjxcGXIF5UPw6W3ozwCqGgO1bCY8tgcjoUPm3hUrTzZ5ueXRUkNI 179 qwPrmvpLUtJjI7prCAsi3gDoL/+t7LNEAYPYreRc+LdvJTRj90WwWCdXTHfSMVjt 180 NN9Mt339LkwXGCb6CavmDgE7oVbrFPSTbeFFPhaheQh7pjLFhl9ZBfE7g3d9oNOX 181 PmyY3I0kAE41RiDMrrxHO3tHv9IaQUUDDcGzIWFJlnbvQRXAsWf/HH56Q0eIAZZp 182 K++p6Mo0K+KCu0IwKwdcTYKqty6xefK83p0j/IWVW29Lka44f+ZAroUlBn1+W4GO 183 sB31+boS8zC7SOmgWuaHeOQdLT8= 184 -----END CERTIFICATE----- 185 ` 186 187 type DummyConfigReader struct { 188 NullConfiguration 189 } 190 191 var _ ConfigReader = (*DummyConfigReader)(nil) 192 193 func (r *DummyConfigReader) GetDeviceID() keybase1.DeviceID { 194 return "dummy-device-id" 195 } 196 197 type DummyUpdaterConfigReader struct{} 198 199 var _ UpdaterConfigReader = (*DummyUpdaterConfigReader)(nil) 200 201 func (r *DummyUpdaterConfigReader) GetInstallID() InstallID { 202 return "dummy-install-id" 203 } 204 205 func TestInstallIDHeaders(t *testing.T) { 206 tc := SetupTest(t, "test", 1) 207 defer tc.Cleanup() 208 mctx := NewMetaContextForTest(tc) 209 210 // Hack in the device ID and install ID with dummy readers. 211 tc.G.Env.config = &DummyConfigReader{} 212 tc.G.Env.updaterConfig = &DummyUpdaterConfigReader{} 213 214 api, err := NewInternalAPIEngine(tc.G) 215 if err != nil { 216 t.Fatal(err) 217 } 218 res, err := api.Get(mctx, APIArg{ 219 Endpoint: "pkg/show", 220 SessionType: APISessionTypeOPTIONAL, 221 Args: HTTPArgs{}, 222 }) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 deviceID, err := res.Body.AtKey("device_id").GetString() 228 if err != nil { 229 t.Fatal(err) 230 } 231 if deviceID != "dummy-device-id" { 232 t.Fatalf("expected device ID to be reflected back, got %s", res.Body.MarshalPretty()) 233 } 234 235 installID, err := res.Body.AtKey("install_id").GetString() 236 if err != nil { 237 t.Fatal(err) 238 } 239 if installID != "dummy-install-id" { 240 t.Fatalf("expected install ID to be reflected back, got %s", res.Body.MarshalPretty()) 241 } 242 } 243 func TestInstallIDHeadersAnon(t *testing.T) { 244 tc := SetupTest(t, "test", 1) 245 defer tc.Cleanup() 246 mctx := NewMetaContextForTest(tc) 247 248 // Hack in the device ID and install ID with dummy readers. 249 tc.G.Env.config = &DummyConfigReader{} 250 tc.G.Env.updaterConfig = &DummyUpdaterConfigReader{} 251 252 api, err := NewInternalAPIEngine(tc.G) 253 if err != nil { 254 t.Fatal(err) 255 } 256 res, err := api.Get(mctx, APIArg{ 257 Endpoint: "pkg/show", 258 SessionType: APISessionTypeNONE, 259 Args: HTTPArgs{}, 260 }) 261 if err != nil { 262 t.Fatal(err) 263 } 264 265 _, err = res.Body.AtKey("device_id").GetString() 266 if err == nil { 267 t.Fatal("Device ID should not be here") 268 } 269 270 _, err = res.Body.AtKey("install_id").GetString() 271 if err == nil { 272 t.Fatal("Install ID should not be here") 273 } 274 }