account_test.go (13435B)
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 validate_test 19 20 import ( 21 "crypto/rand" 22 "crypto/rsa" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/suite" 27 "github.com/superseriousbusiness/gotosocial/internal/ap" 28 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 29 "github.com/superseriousbusiness/gotosocial/internal/validate" 30 "github.com/superseriousbusiness/gotosocial/testrig" 31 ) 32 33 func happyAccount() *gtsmodel.Account { 34 priv, err := rsa.GenerateKey(rand.Reader, 2048) 35 if err != nil { 36 panic(err) 37 } 38 pub := &priv.PublicKey 39 40 return >smodel.Account{ 41 ID: "01F8MH1H7YV1Z7D2C8K2730QBF", 42 CreatedAt: time.Now().Add(-48 * time.Hour), 43 UpdatedAt: time.Now().Add(-48 * time.Hour), 44 Username: "the_mighty_zork", 45 Domain: "", 46 AvatarMediaAttachmentID: "01F8MH58A357CV5K7R7TJMSH6S", 47 AvatarMediaAttachment: nil, 48 AvatarRemoteURL: "", 49 HeaderMediaAttachmentID: "01PFPMWK2FF0D9WMHEJHR07C3Q", 50 HeaderMediaAttachment: nil, 51 HeaderRemoteURL: "", 52 DisplayName: "original zork (he/they)", 53 Fields: []*gtsmodel.Field{}, 54 Note: "hey yo this is my profile!", 55 Memorial: testrig.FalseBool(), 56 AlsoKnownAs: "", 57 MovedToAccountID: "", 58 Bot: testrig.FalseBool(), 59 Reason: "I wanna be on this damned webbed site so bad! Please! Wow", 60 Locked: testrig.FalseBool(), 61 Discoverable: testrig.TrueBool(), 62 Privacy: gtsmodel.VisibilityPublic, 63 Sensitive: testrig.FalseBool(), 64 Language: "en", 65 StatusContentType: "text/plain", 66 URI: "http://localhost:8080/users/the_mighty_zork", 67 URL: "http://localhost:8080/@the_mighty_zork", 68 FetchedAt: time.Time{}, 69 InboxURI: "http://localhost:8080/users/the_mighty_zork/inbox", 70 OutboxURI: "http://localhost:8080/users/the_mighty_zork/outbox", 71 FollowersURI: "http://localhost:8080/users/the_mighty_zork/followers", 72 FollowingURI: "http://localhost:8080/users/the_mighty_zork/following", 73 FeaturedCollectionURI: "http://localhost:8080/users/the_mighty_zork/collections/featured", 74 ActorType: ap.ActorPerson, 75 PrivateKey: priv, 76 PublicKey: pub, 77 PublicKeyURI: "http://localhost:8080/users/the_mighty_zork#main-key", 78 SensitizedAt: time.Time{}, 79 SilencedAt: time.Time{}, 80 SuspendedAt: time.Time{}, 81 HideCollections: testrig.FalseBool(), 82 SuspensionOrigin: "", 83 } 84 } 85 86 type AccountValidateTestSuite struct { 87 suite.Suite 88 } 89 90 func (suite *AccountValidateTestSuite) TestValidateAccountHappyPath() { 91 // no problem here 92 a := happyAccount() 93 err := validate.Struct(*a) 94 suite.NoError(err) 95 } 96 97 // ID must be set and be valid ULID 98 func (suite *AccountValidateTestSuite) TestValidateAccountBadID() { 99 a := happyAccount() 100 101 a.ID = "" 102 err := validate.Struct(*a) 103 suite.EqualError(err, "Key: 'Account.ID' Error:Field validation for 'ID' failed on the 'required' tag") 104 105 a.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" 106 err = validate.Struct(*a) 107 suite.EqualError(err, "Key: 'Account.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") 108 } 109 110 // CreatedAt can be set or not -- it will be set in the database anyway 111 func (suite *AccountValidateTestSuite) TestValidateAccountNoCreatedAt() { 112 a := happyAccount() 113 114 a.CreatedAt = time.Time{} 115 err := validate.Struct(*a) 116 suite.NoError(err) 117 } 118 119 // FetchedAt must be defined if remote account 120 func (suite *AccountValidateTestSuite) TestValidateAccountNoWebfingeredAt() { 121 a := happyAccount() 122 123 a.Domain = "example.org" 124 a.FetchedAt = time.Time{} 125 err := validate.Struct(*a) 126 suite.EqualError(err, "Key: 'Account.FetchedAt' Error:Field validation for 'FetchedAt' failed on the 'required_with' tag") 127 } 128 129 // Username must be set 130 func (suite *AccountValidateTestSuite) TestValidateAccountUsername() { 131 a := happyAccount() 132 133 a.Username = "" 134 err := validate.Struct(*a) 135 suite.EqualError(err, "Key: 'Account.Username' Error:Field validation for 'Username' failed on the 'required' tag") 136 } 137 138 // Domain must be either empty (for local accounts) or proper fqdn (for remote accounts) 139 func (suite *AccountValidateTestSuite) TestValidateAccountDomain() { 140 a := happyAccount() 141 a.FetchedAt = time.Now() 142 143 a.Domain = "" 144 err := validate.Struct(*a) 145 suite.NoError(err) 146 147 a.Domain = "localhost:8080" 148 err = validate.Struct(*a) 149 suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") 150 151 a.Domain = "ahhhhh" 152 err = validate.Struct(*a) 153 suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") 154 155 a.Domain = "https://www.example.org" 156 err = validate.Struct(*a) 157 suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") 158 159 a.Domain = "example.org:8080" 160 err = validate.Struct(*a) 161 suite.EqualError(err, "Key: 'Account.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") 162 163 a.Domain = "example.org" 164 err = validate.Struct(*a) 165 suite.NoError(err) 166 } 167 168 // Attachment IDs must either be not set, or must be valid ULID 169 func (suite *AccountValidateTestSuite) TestValidateAttachmentIDs() { 170 a := happyAccount() 171 172 a.AvatarMediaAttachmentID = "" 173 a.HeaderMediaAttachmentID = "" 174 err := validate.Struct(*a) 175 suite.NoError(err) 176 177 a.AvatarMediaAttachmentID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" 178 a.HeaderMediaAttachmentID = "aaaa" 179 err = validate.Struct(*a) 180 suite.EqualError(err, "Key: 'Account.AvatarMediaAttachmentID' Error:Field validation for 'AvatarMediaAttachmentID' failed on the 'ulid' tag\nKey: 'Account.HeaderMediaAttachmentID' Error:Field validation for 'HeaderMediaAttachmentID' failed on the 'ulid' tag") 181 } 182 183 // Attachment remote URLs must either not be set, or be valid URLs 184 func (suite *AccountValidateTestSuite) TestValidateAttachmentRemoteURLs() { 185 a := happyAccount() 186 187 a.AvatarRemoteURL = "" 188 a.HeaderRemoteURL = "" 189 err := validate.Struct(*a) 190 suite.NoError(err) 191 192 a.AvatarRemoteURL = "-------------" 193 a.HeaderRemoteURL = "https://valid-url.com" 194 err = validate.Struct(*a) 195 suite.EqualError(err, "Key: 'Account.AvatarRemoteURL' Error:Field validation for 'AvatarRemoteURL' failed on the 'url' tag") 196 197 a.AvatarRemoteURL = "https://valid-url.com" 198 a.HeaderRemoteURL = "" 199 err = validate.Struct(*a) 200 suite.NoError(err) 201 } 202 203 // Default privacy must be set if account is local 204 func (suite *AccountValidateTestSuite) TestValidatePrivacy() { 205 a := happyAccount() 206 a.FetchedAt = time.Now() 207 208 a.Privacy = "" 209 err := validate.Struct(*a) 210 suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'required_without' tag") 211 212 a.Privacy = "not valid" 213 err = validate.Struct(*a) 214 suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'oneof' tag") 215 216 a.Privacy = gtsmodel.VisibilityFollowersOnly 217 err = validate.Struct(*a) 218 suite.NoError(err) 219 220 a.Privacy = "" 221 a.Domain = "example.org" 222 err = validate.Struct(*a) 223 suite.NoError(err) 224 225 a.Privacy = "invalid" 226 err = validate.Struct(*a) 227 suite.EqualError(err, "Key: 'Account.Privacy' Error:Field validation for 'Privacy' failed on the 'oneof' tag") 228 } 229 230 // If set, language must be a valid language 231 func (suite *AccountValidateTestSuite) TestValidateLanguage() { 232 a := happyAccount() 233 234 a.Language = "" 235 err := validate.Struct(*a) 236 suite.NoError(err) 237 238 a.Language = "not valid" 239 err = validate.Struct(*a) 240 suite.EqualError(err, "Key: 'Account.Language' Error:Field validation for 'Language' failed on the 'bcp47_language_tag' tag") 241 242 a.Language = "en-uk" 243 err = validate.Struct(*a) 244 suite.NoError(err) 245 } 246 247 // Account URI must be set and must be valid 248 func (suite *AccountValidateTestSuite) TestValidateAccountURI() { 249 a := happyAccount() 250 251 a.URI = "invalid-uri" 252 err := validate.Struct(*a) 253 suite.EqualError(err, "Key: 'Account.URI' Error:Field validation for 'URI' failed on the 'url' tag") 254 255 a.URI = "" 256 err = validate.Struct(*a) 257 suite.EqualError(err, "Key: 'Account.URI' Error:Field validation for 'URI' failed on the 'required' tag") 258 } 259 260 // ActivityPub URIs must be set on account if it's local 261 func (suite *AccountValidateTestSuite) TestValidateAccountURIs() { 262 a := happyAccount() 263 a.FetchedAt = time.Now() 264 265 a.InboxURI = "invalid-uri" 266 a.OutboxURI = "invalid-uri" 267 a.FollowersURI = "invalid-uri" 268 a.FollowingURI = "invalid-uri" 269 a.FeaturedCollectionURI = "invalid-uri" 270 a.PublicKeyURI = "invalid-uri" 271 err := validate.Struct(*a) 272 suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'url' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'url' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'url' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'url' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'url' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'url' tag") 273 274 a.InboxURI = "" 275 a.OutboxURI = "" 276 a.FollowersURI = "" 277 a.FollowingURI = "" 278 a.FeaturedCollectionURI = "" 279 a.PublicKeyURI = "" 280 err = validate.Struct(*a) 281 suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'required_without' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'required_without' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'required_without' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'required_without' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'required_without' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'required' tag") 282 283 a.Domain = "example.org" 284 err = validate.Struct(*a) 285 suite.EqualError(err, "Key: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'required' tag") 286 287 a.InboxURI = "invalid-uri" 288 a.OutboxURI = "invalid-uri" 289 a.FollowersURI = "invalid-uri" 290 a.FollowingURI = "invalid-uri" 291 a.FeaturedCollectionURI = "invalid-uri" 292 a.PublicKeyURI = "invalid-uri" 293 err = validate.Struct(*a) 294 suite.EqualError(err, "Key: 'Account.InboxURI' Error:Field validation for 'InboxURI' failed on the 'url' tag\nKey: 'Account.OutboxURI' Error:Field validation for 'OutboxURI' failed on the 'url' tag\nKey: 'Account.FollowingURI' Error:Field validation for 'FollowingURI' failed on the 'url' tag\nKey: 'Account.FollowersURI' Error:Field validation for 'FollowersURI' failed on the 'url' tag\nKey: 'Account.FeaturedCollectionURI' Error:Field validation for 'FeaturedCollectionURI' failed on the 'url' tag\nKey: 'Account.PublicKeyURI' Error:Field validation for 'PublicKeyURI' failed on the 'url' tag") 295 } 296 297 // Actor type must be set and valid 298 func (suite *AccountValidateTestSuite) TestValidateActorType() { 299 a := happyAccount() 300 301 a.ActorType = "" 302 err := validate.Struct(*a) 303 suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") 304 305 a.ActorType = "not valid" 306 err = validate.Struct(*a) 307 suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") 308 309 a.ActorType = ap.ActivityArrive 310 err = validate.Struct(*a) 311 suite.EqualError(err, "Key: 'Account.ActorType' Error:Field validation for 'ActorType' failed on the 'oneof' tag") 312 313 a.ActorType = ap.ActorOrganization 314 err = validate.Struct(*a) 315 suite.NoError(err) 316 } 317 318 // Private key must be set on local accounts 319 func (suite *AccountValidateTestSuite) TestValidatePrivateKey() { 320 a := happyAccount() 321 a.FetchedAt = time.Now() 322 323 a.PrivateKey = nil 324 err := validate.Struct(*a) 325 suite.EqualError(err, "Key: 'Account.PrivateKey' Error:Field validation for 'PrivateKey' failed on the 'required_without' tag") 326 327 a.Domain = "example.org" 328 err = validate.Struct(*a) 329 suite.NoError(err) 330 } 331 332 // Public key must be set 333 func (suite *AccountValidateTestSuite) TestValidatePublicKey() { 334 a := happyAccount() 335 336 a.PublicKey = nil 337 err := validate.Struct(*a) 338 suite.EqualError(err, "Key: 'Account.PublicKey' Error:Field validation for 'PublicKey' failed on the 'required' tag") 339 } 340 341 func TestAccountValidateTestSuite(t *testing.T) { 342 suite.Run(t, new(AccountValidateTestSuite)) 343 }