account.go (8510B)
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 account 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "os" 25 "text/tabwriter" 26 "time" 27 28 "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action" 29 "github.com/superseriousbusiness/gotosocial/internal/config" 30 "github.com/superseriousbusiness/gotosocial/internal/db/bundb" 31 "github.com/superseriousbusiness/gotosocial/internal/state" 32 "github.com/superseriousbusiness/gotosocial/internal/validate" 33 "golang.org/x/crypto/bcrypt" 34 ) 35 36 // Create creates a new account in the database using the provided flags. 37 var Create action.GTSAction = func(ctx context.Context) error { 38 var state state.State 39 state.Caches.Init() 40 state.Workers.Start() 41 42 dbConn, err := bundb.NewBunDBService(ctx, &state) 43 if err != nil { 44 return fmt.Errorf("error creating dbservice: %s", err) 45 } 46 47 // Set the state DB connection 48 state.DB = dbConn 49 50 username := config.GetAdminAccountUsername() 51 if username == "" { 52 return errors.New("no username set") 53 } 54 if err := validate.Username(username); err != nil { 55 return err 56 } 57 58 usernameAvailable, err := dbConn.IsUsernameAvailable(ctx, username) 59 if err != nil { 60 return err 61 } 62 if !usernameAvailable { 63 return fmt.Errorf("username %s is already in use", username) 64 } 65 66 email := config.GetAdminAccountEmail() 67 if email == "" { 68 return errors.New("no email set") 69 } 70 if err := validate.Email(email); err != nil { 71 return err 72 } 73 74 emailAvailable, err := dbConn.IsEmailAvailable(ctx, email) 75 if err != nil { 76 return err 77 } 78 if !emailAvailable { 79 return fmt.Errorf("email address %s is already in use", email) 80 } 81 82 password := config.GetAdminAccountPassword() 83 if password == "" { 84 return errors.New("no password set") 85 } 86 if err := validate.NewPassword(password); err != nil { 87 return err 88 } 89 90 _, err = dbConn.NewSignup(ctx, username, "", false, email, password, nil, "", "", true, "", false) 91 if err != nil { 92 return err 93 } 94 95 return dbConn.Stop(ctx) 96 } 97 98 // List returns all existing local accounts. 99 var List action.GTSAction = func(ctx context.Context) error { 100 var state state.State 101 state.Caches.Init() 102 state.Workers.Start() 103 104 dbConn, err := bundb.NewBunDBService(ctx, &state) 105 if err != nil { 106 return fmt.Errorf("error creating dbservice: %s", err) 107 } 108 109 // Set the state DB connection 110 state.DB = dbConn 111 112 users, err := dbConn.GetAllUsers(ctx) 113 if err != nil { 114 return err 115 } 116 117 fmtBool := func(b *bool) string { 118 if b == nil { 119 return "unknown" 120 } 121 if *b { 122 return "yes" 123 } 124 return "no" 125 } 126 127 fmtDate := func(t time.Time) string { 128 if t.Equal(time.Time{}) { 129 return "no" 130 } 131 return "yes" 132 } 133 134 w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) 135 fmt.Fprintln(w, "user\taccount\tapproved\tadmin\tmoderator\tsuspended\tconfirmed") 136 for _, u := range users { 137 fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", u.Account.Username, u.AccountID, fmtBool(u.Approved), fmtBool(u.Admin), fmtBool(u.Moderator), fmtDate(u.Account.SuspendedAt), fmtDate(u.ConfirmedAt)) 138 } 139 w.Flush() 140 return nil 141 } 142 143 // Confirm sets a user to Approved, sets Email to the current UnconfirmedEmail value, and sets ConfirmedAt to now. 144 var Confirm action.GTSAction = func(ctx context.Context) error { 145 var state state.State 146 state.Caches.Init() 147 state.Workers.Start() 148 149 dbConn, err := bundb.NewBunDBService(ctx, &state) 150 if err != nil { 151 return fmt.Errorf("error creating dbservice: %s", err) 152 } 153 154 // Set the state DB connection 155 state.DB = dbConn 156 157 username := config.GetAdminAccountUsername() 158 if username == "" { 159 return errors.New("no username set") 160 } 161 if err := validate.Username(username); err != nil { 162 return err 163 } 164 165 a, err := dbConn.GetAccountByUsernameDomain(ctx, username, "") 166 if err != nil { 167 return err 168 } 169 170 u, err := dbConn.GetUserByAccountID(ctx, a.ID) 171 if err != nil { 172 return err 173 } 174 175 updatingColumns := []string{"approved", "email", "confirmed_at"} 176 approved := true 177 u.Approved = &approved 178 u.Email = u.UnconfirmedEmail 179 u.ConfirmedAt = time.Now() 180 if err := dbConn.UpdateUser(ctx, u, updatingColumns...); err != nil { 181 return err 182 } 183 184 return dbConn.Stop(ctx) 185 } 186 187 // Promote sets a user to admin. 188 var Promote action.GTSAction = func(ctx context.Context) error { 189 var state state.State 190 state.Caches.Init() 191 state.Workers.Start() 192 193 dbConn, err := bundb.NewBunDBService(ctx, &state) 194 if err != nil { 195 return fmt.Errorf("error creating dbservice: %s", err) 196 } 197 198 // Set the state DB connection 199 state.DB = dbConn 200 201 username := config.GetAdminAccountUsername() 202 if username == "" { 203 return errors.New("no username set") 204 } 205 if err := validate.Username(username); err != nil { 206 return err 207 } 208 209 a, err := dbConn.GetAccountByUsernameDomain(ctx, username, "") 210 if err != nil { 211 return err 212 } 213 214 u, err := dbConn.GetUserByAccountID(ctx, a.ID) 215 if err != nil { 216 return err 217 } 218 219 admin := true 220 u.Admin = &admin 221 if err := dbConn.UpdateUser(ctx, u, "admin"); err != nil { 222 return err 223 } 224 225 return dbConn.Stop(ctx) 226 } 227 228 // Demote sets admin on a user to false. 229 var Demote action.GTSAction = func(ctx context.Context) error { 230 var state state.State 231 state.Caches.Init() 232 state.Workers.Start() 233 234 dbConn, err := bundb.NewBunDBService(ctx, &state) 235 if err != nil { 236 return fmt.Errorf("error creating dbservice: %s", err) 237 } 238 239 // Set the state DB connection 240 state.DB = dbConn 241 242 username := config.GetAdminAccountUsername() 243 if username == "" { 244 return errors.New("no username set") 245 } 246 if err := validate.Username(username); err != nil { 247 return err 248 } 249 250 a, err := dbConn.GetAccountByUsernameDomain(ctx, username, "") 251 if err != nil { 252 return err 253 } 254 255 u, err := dbConn.GetUserByAccountID(ctx, a.ID) 256 if err != nil { 257 return err 258 } 259 260 admin := false 261 u.Admin = &admin 262 if err := dbConn.UpdateUser(ctx, u, "admin"); err != nil { 263 return err 264 } 265 266 return dbConn.Stop(ctx) 267 } 268 269 // Disable sets Disabled to true on a user. 270 var Disable action.GTSAction = func(ctx context.Context) error { 271 var state state.State 272 state.Caches.Init() 273 state.Workers.Start() 274 275 dbConn, err := bundb.NewBunDBService(ctx, &state) 276 if err != nil { 277 return fmt.Errorf("error creating dbservice: %s", err) 278 } 279 280 // Set the state DB connection 281 state.DB = dbConn 282 283 username := config.GetAdminAccountUsername() 284 if username == "" { 285 return errors.New("no username set") 286 } 287 if err := validate.Username(username); err != nil { 288 return err 289 } 290 291 a, err := dbConn.GetAccountByUsernameDomain(ctx, username, "") 292 if err != nil { 293 return err 294 } 295 296 u, err := dbConn.GetUserByAccountID(ctx, a.ID) 297 if err != nil { 298 return err 299 } 300 301 disabled := true 302 u.Disabled = &disabled 303 if err := dbConn.UpdateUser(ctx, u, "disabled"); err != nil { 304 return err 305 } 306 307 return dbConn.Stop(ctx) 308 } 309 310 // Password sets the password of target account. 311 var Password action.GTSAction = func(ctx context.Context) error { 312 var state state.State 313 state.Caches.Init() 314 state.Workers.Start() 315 316 dbConn, err := bundb.NewBunDBService(ctx, &state) 317 if err != nil { 318 return fmt.Errorf("error creating dbservice: %s", err) 319 } 320 321 // Set the state DB connection 322 state.DB = dbConn 323 324 username := config.GetAdminAccountUsername() 325 if username == "" { 326 return errors.New("no username set") 327 } 328 if err := validate.Username(username); err != nil { 329 return err 330 } 331 332 password := config.GetAdminAccountPassword() 333 if password == "" { 334 return errors.New("no password set") 335 } 336 if err := validate.NewPassword(password); err != nil { 337 return err 338 } 339 340 a, err := dbConn.GetAccountByUsernameDomain(ctx, username, "") 341 if err != nil { 342 return err 343 } 344 345 u, err := dbConn.GetUserByAccountID(ctx, a.ID) 346 if err != nil { 347 return err 348 } 349 350 pw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) 351 if err != nil { 352 return fmt.Errorf("error hashing password: %s", err) 353 } 354 355 u.EncryptedPassword = string(pw) 356 return dbConn.UpdateUser(ctx, u, "encrypted_password") 357 }