2023-02-14 23:12:19 +01:00
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
2024-04-27 14:23:37 +02:00
"context"
2023-02-14 23:12:19 +01:00
"errors"
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
2024-04-14 19:22:14 +02:00
"code.gitea.io/gitea/models/db"
2023-02-14 23:12:19 +01:00
user_model "code.gitea.io/gitea/models/user"
2023-02-19 08:35:20 +01:00
pwd "code.gitea.io/gitea/modules/auth/password"
2024-02-23 03:18:33 +01:00
"code.gitea.io/gitea/modules/optional"
2023-02-14 23:12:19 +01:00
"code.gitea.io/gitea/modules/setting"
2023-07-21 11:28:19 +02:00
"github.com/urfave/cli/v2"
2023-02-14 23:12:19 +01:00
)
2023-07-21 11:28:19 +02:00
var microcmdUserCreate = & cli . Command {
2023-02-14 23:12:19 +01:00
Name : "create" ,
Usage : "Create a new user in database" ,
Action : runCreateUser ,
Flags : [ ] cli . Flag {
2023-07-21 11:28:19 +02:00
& cli . StringFlag {
2023-02-14 23:12:19 +01:00
Name : "name" ,
Usage : "Username. DEPRECATED: use username instead" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . StringFlag {
2023-02-14 23:12:19 +01:00
Name : "username" ,
Usage : "Username" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . StringFlag {
2023-02-14 23:12:19 +01:00
Name : "password" ,
Usage : "User password" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . StringFlag {
2023-02-14 23:12:19 +01:00
Name : "email" ,
Usage : "User email address" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . BoolFlag {
2023-02-14 23:12:19 +01:00
Name : "admin" ,
Usage : "User is an admin" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . BoolFlag {
2023-02-14 23:12:19 +01:00
Name : "random-password" ,
Usage : "Generate a random password for the user" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . BoolFlag {
2024-04-14 19:22:14 +02:00
Name : "must-change-password" ,
2024-04-27 14:23:37 +02:00
Usage : "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)" ,
2024-04-14 19:22:14 +02:00
DisableDefaultText : true ,
2023-02-14 23:12:19 +01:00
} ,
2023-07-21 11:28:19 +02:00
& cli . IntFlag {
2023-02-14 23:12:19 +01:00
Name : "random-password-length" ,
Usage : "Length of the random password to be generated" ,
Value : 12 ,
} ,
2023-07-21 11:28:19 +02:00
& cli . BoolFlag {
2023-02-14 23:12:19 +01:00
Name : "access-token" ,
Usage : "Generate access token for the user" ,
} ,
2023-07-21 11:28:19 +02:00
& cli . BoolFlag {
2023-02-14 23:12:19 +01:00
Name : "restricted" ,
Usage : "Make a restricted user account" ,
} ,
} ,
}
func runCreateUser ( c * cli . Context ) error {
if err := argsSet ( c , "email" ) ; err != nil {
return err
}
if c . IsSet ( "name" ) && c . IsSet ( "username" ) {
2024-04-14 19:22:14 +02:00
return errors . New ( "cannot set both --name and --username flags" )
2023-02-14 23:12:19 +01:00
}
if ! c . IsSet ( "name" ) && ! c . IsSet ( "username" ) {
2024-04-14 19:22:14 +02:00
return errors . New ( "one of --name or --username flags must be set" )
2023-02-14 23:12:19 +01:00
}
if c . IsSet ( "password" ) && c . IsSet ( "random-password" ) {
return errors . New ( "cannot set both -random-password and -password flags" )
}
var username string
if c . IsSet ( "username" ) {
username = c . String ( "username" )
} else {
username = c . String ( "name" )
2023-08-13 14:49:30 +02:00
_ , _ = fmt . Fprintf ( c . App . ErrWriter , "--name flag is deprecated. Use --username instead.\n" )
2023-02-14 23:12:19 +01:00
}
2024-04-27 14:23:37 +02:00
ctx := c . Context
if ! setting . IsInTesting {
// FIXME: need to refactor the "installSignals/initDB" related code later
// it doesn't make sense to call it in (almost) every command action function
var cancel context . CancelFunc
ctx , cancel = installSignals ( )
defer cancel ( )
if err := initDB ( ctx ) ; err != nil {
return err
}
2023-02-14 23:12:19 +01:00
}
var password string
if c . IsSet ( "password" ) {
password = c . String ( "password" )
} else if c . IsSet ( "random-password" ) {
var err error
password , err = pwd . Generate ( c . Int ( "random-password-length" ) )
if err != nil {
return err
}
fmt . Printf ( "generated random password is '%s'\n" , password )
} else {
return errors . New ( "must set either password or random-password flag" )
}
2024-04-14 19:22:14 +02:00
isAdmin := c . Bool ( "admin" )
mustChangePassword := true // always default to true
2023-02-14 23:12:19 +01:00
if c . IsSet ( "must-change-password" ) {
2024-04-14 19:22:14 +02:00
// if the flag is set, use the value provided by the user
mustChangePassword = c . Bool ( "must-change-password" )
} else {
// check whether there are users in the database
hasUserRecord , err := db . IsTableNotEmpty ( & user_model . User { } )
if err != nil {
return fmt . Errorf ( "IsTableNotEmpty: %w" , err )
}
2024-04-27 14:23:37 +02:00
if ! hasUserRecord {
// if this is the first one being created, don't force to change password (keep the old behavior)
2024-04-14 19:22:14 +02:00
mustChangePassword = false
}
2023-02-14 23:12:19 +01:00
}
2024-02-23 03:18:33 +01:00
restricted := optional . None [ bool ] ( )
2023-02-14 23:12:19 +01:00
if c . IsSet ( "restricted" ) {
2024-02-23 03:18:33 +01:00
restricted = optional . Some ( c . Bool ( "restricted" ) )
2023-02-14 23:12:19 +01:00
}
// default user visibility in app.ini
visibility := setting . Service . DefaultUserVisibilityMode
u := & user_model . User {
Name : username ,
Email : c . String ( "email" ) ,
Passwd : password ,
2024-04-14 19:22:14 +02:00
IsAdmin : isAdmin ,
MustChangePassword : mustChangePassword ,
2023-02-14 23:12:19 +01:00
Visibility : visibility ,
}
overwriteDefault := & user_model . CreateUserOverwriteOptions {
2024-02-23 03:18:33 +01:00
IsActive : optional . Some ( true ) ,
2023-02-14 23:12:19 +01:00
IsRestricted : restricted ,
}
2024-09-09 23:05:16 +02:00
if err := user_model . CreateUser ( ctx , u , & user_model . Meta { } , overwriteDefault ) ; err != nil {
2023-02-14 23:12:19 +01:00
return fmt . Errorf ( "CreateUser: %w" , err )
}
if c . Bool ( "access-token" ) {
t := & auth_model . AccessToken {
Name : "gitea-admin" ,
UID : u . ID ,
}
2023-09-15 08:13:19 +02:00
if err := auth_model . NewAccessToken ( ctx , t ) ; err != nil {
2023-02-14 23:12:19 +01:00
return err
}
fmt . Printf ( "Access token was successfully created... %s\n" , t . Token )
}
fmt . Printf ( "New user '%s' has been successfully created!\n" , username )
return nil
}