webfingerget_test.go (7774B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package webfinger_test 19 20 import ( 21 "bytes" 22 "context" 23 "crypto/rand" 24 "crypto/rsa" 25 "encoding/json" 26 "fmt" 27 "io" 28 "net/http" 29 "net/http/httptest" 30 "testing" 31 32 "github.com/stretchr/testify/suite" 33 "github.com/superseriousbusiness/gotosocial/internal/ap" 34 apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" 35 "github.com/superseriousbusiness/gotosocial/internal/api/wellknown/webfinger" 36 "github.com/superseriousbusiness/gotosocial/internal/config" 37 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 38 "github.com/superseriousbusiness/gotosocial/internal/processing" 39 "github.com/superseriousbusiness/gotosocial/testrig" 40 ) 41 42 type WebfingerGetTestSuite struct { 43 WebfingerStandardTestSuite 44 } 45 46 func (suite *WebfingerGetTestSuite) finger(requestPath string) string { 47 // Set up the request. 48 recorder := httptest.NewRecorder() 49 ctx, _ := testrig.CreateGinTestContext(recorder, nil) 50 ctx.Request = httptest.NewRequest(http.MethodGet, requestPath, nil) 51 ctx.Request.Header.Set("accept", "application/jrd+json") 52 53 // Trigger the handler. 54 suite.webfingerModule.WebfingerGETRequest(ctx) 55 56 // Read the result + return it 57 // as nicely indented JSON. 58 result := recorder.Result() 59 defer result.Body.Close() 60 61 // Result should always use the 62 // webfinger content-type. 63 if ct := result.Header.Get("content-type"); ct != string(apiutil.AppJRDJSON) { 64 suite.FailNow("", "expected content type %s, got %s", apiutil.AppJRDJSON, ct) 65 } 66 67 b, err := io.ReadAll(result.Body) 68 if err != nil { 69 suite.FailNow(err.Error()) 70 } 71 72 var dst bytes.Buffer 73 if err := json.Indent(&dst, b, "", " "); err != nil { 74 suite.FailNow(err.Error()) 75 } 76 77 return dst.String() 78 } 79 80 func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDomain string) *gtsmodel.Account { 81 // Reset suite structs + config 82 // to new host + account domain. 83 config.SetHost(host) 84 config.SetAccountDomain(accountDomain) 85 suite.processor = processing.NewProcessor(suite.tc, suite.federator, testrig.NewTestOauthServer(suite.db), testrig.NewTestMediaManager(&suite.state), &suite.state, suite.emailSender) 86 suite.webfingerModule = webfinger.New(suite.processor) 87 88 // Generate a new account for the 89 // tester, which uses the new host. 90 privateKey, err := rsa.GenerateKey(rand.Reader, 2048) 91 if err != nil { 92 panic(err) 93 } 94 publicKey := &privateKey.PublicKey 95 96 targetAccount := >smodel.Account{ 97 ID: "01FG1K8EA7SYHEC7V6XKVNC4ZA", 98 Username: "new_account_domain_user", 99 Privacy: gtsmodel.VisibilityDefault, 100 URI: "http://" + host + "/users/new_account_domain_user", 101 URL: "http://" + host + "/@new_account_domain_user", 102 InboxURI: "http://" + host + "/users/new_account_domain_user/inbox", 103 OutboxURI: "http://" + host + "/users/new_account_domain_user/outbox", 104 FollowingURI: "http://" + host + "/users/new_account_domain_user/following", 105 FollowersURI: "http://" + host + "/users/new_account_domain_user/followers", 106 FeaturedCollectionURI: "http://" + host + "/users/new_account_domain_user/collections/featured", 107 ActorType: ap.ActorPerson, 108 PrivateKey: privateKey, 109 PublicKey: publicKey, 110 PublicKeyURI: "http://" + host + "/users/new_account_domain_user/main-key", 111 } 112 113 if err := suite.db.PutAccount(context.Background(), targetAccount); err != nil { 114 suite.FailNow(err.Error()) 115 } 116 117 return targetAccount 118 } 119 120 func (suite *WebfingerGetTestSuite) TestFingerUser() { 121 targetAccount := suite.testAccounts["local_account_1"] 122 requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, config.GetHost()) 123 124 resp := suite.finger(requestPath) 125 suite.Equal(`{ 126 "subject": "acct:the_mighty_zork@localhost:8080", 127 "aliases": [ 128 "http://localhost:8080/users/the_mighty_zork", 129 "http://localhost:8080/@the_mighty_zork" 130 ], 131 "links": [ 132 { 133 "rel": "http://webfinger.net/rel/profile-page", 134 "type": "text/html", 135 "href": "http://localhost:8080/@the_mighty_zork" 136 }, 137 { 138 "rel": "self", 139 "type": "application/activity+json", 140 "href": "http://localhost:8080/users/the_mighty_zork" 141 } 142 ] 143 }`, resp) 144 } 145 146 func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByHost() { 147 targetAccount := suite.funkifyAccountDomain("gts.example.org", "example.org") 148 requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, config.GetHost()) 149 150 resp := suite.finger(requestPath) 151 suite.Equal(`{ 152 "subject": "acct:new_account_domain_user@example.org", 153 "aliases": [ 154 "http://gts.example.org/users/new_account_domain_user", 155 "http://gts.example.org/@new_account_domain_user" 156 ], 157 "links": [ 158 { 159 "rel": "http://webfinger.net/rel/profile-page", 160 "type": "text/html", 161 "href": "http://gts.example.org/@new_account_domain_user" 162 }, 163 { 164 "rel": "self", 165 "type": "application/activity+json", 166 "href": "http://gts.example.org/users/new_account_domain_user" 167 } 168 ] 169 }`, resp) 170 } 171 172 func (suite *WebfingerGetTestSuite) TestFingerUserWithDifferentAccountDomainByAccountDomain() { 173 targetAccount := suite.funkifyAccountDomain("gts.example.org", "example.org") 174 requestPath := fmt.Sprintf("/%s?resource=acct:%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, config.GetAccountDomain()) 175 176 resp := suite.finger(requestPath) 177 suite.Equal(`{ 178 "subject": "acct:new_account_domain_user@example.org", 179 "aliases": [ 180 "http://gts.example.org/users/new_account_domain_user", 181 "http://gts.example.org/@new_account_domain_user" 182 ], 183 "links": [ 184 { 185 "rel": "http://webfinger.net/rel/profile-page", 186 "type": "text/html", 187 "href": "http://gts.example.org/@new_account_domain_user" 188 }, 189 { 190 "rel": "self", 191 "type": "application/activity+json", 192 "href": "http://gts.example.org/users/new_account_domain_user" 193 } 194 ] 195 }`, resp) 196 } 197 198 func (suite *WebfingerGetTestSuite) TestFingerUserWithoutAcct() { 199 // Leave out the 'acct:' part in the request path; 200 // the handler should be generous + still work OK. 201 targetAccount := suite.testAccounts["local_account_1"] 202 requestPath := fmt.Sprintf("/%s?resource=%s@%s", webfinger.WebfingerBasePath, targetAccount.Username, config.GetHost()) 203 204 resp := suite.finger(requestPath) 205 suite.Equal(`{ 206 "subject": "acct:the_mighty_zork@localhost:8080", 207 "aliases": [ 208 "http://localhost:8080/users/the_mighty_zork", 209 "http://localhost:8080/@the_mighty_zork" 210 ], 211 "links": [ 212 { 213 "rel": "http://webfinger.net/rel/profile-page", 214 "type": "text/html", 215 "href": "http://localhost:8080/@the_mighty_zork" 216 }, 217 { 218 "rel": "self", 219 "type": "application/activity+json", 220 "href": "http://localhost:8080/users/the_mighty_zork" 221 } 222 ] 223 }`, resp) 224 } 225 226 func TestWebfingerGetTestSuite(t *testing.T) { 227 suite.Run(t, new(WebfingerGetTestSuite)) 228 }