github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/cmd/mattermost/commands/user.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package commands
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"strings"
    12  
    13  	"github.com/mattermost/mattermost-server/v5/app"
    14  	"github.com/mattermost/mattermost-server/v5/audit"
    15  	"github.com/mattermost/mattermost-server/v5/model"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  var UserCmd = &cobra.Command{
    20  	Use:   "user",
    21  	Short: "Management of users",
    22  }
    23  
    24  var UserActivateCmd = &cobra.Command{
    25  	Use:   "activate [emails, usernames, userIds]",
    26  	Short: "Activate users",
    27  	Long:  "Activate users that have been deactivated.",
    28  	Example: `  user activate user@example.com
    29    user activate username`,
    30  	RunE: userActivateCmdF,
    31  }
    32  
    33  var UserDeactivateCmd = &cobra.Command{
    34  	Use:   "deactivate [emails, usernames, userIds]",
    35  	Short: "Deactivate users",
    36  	Long:  "Deactivate users. Deactivated users are immediately logged out of all sessions and are unable to log back in.",
    37  	Example: `  user deactivate user@example.com
    38    user deactivate username`,
    39  	RunE: userDeactivateCmdF,
    40  }
    41  
    42  var UserCreateCmd = &cobra.Command{
    43  	Use:     "create",
    44  	Short:   "Create a user",
    45  	Long:    "Create a user",
    46  	Example: `  user create --email user@example.com --username userexample --password Password1`,
    47  	RunE:    userCreateCmdF,
    48  }
    49  
    50  var UserConvertCmd = &cobra.Command{
    51  	Use:   "convert [emails, usernames, userIds] --bot",
    52  	Short: "Convert users to bots, or a bot to a user",
    53  	Long:  "Convert users to bots, or a bot to a user",
    54  	Example: `  user convert user@example.com anotherUser --bot
    55  	user convert botusername --email new.email@email.com --password password --user`,
    56  	Args: cobra.MinimumNArgs(1),
    57  	RunE: userConvertCmdF,
    58  }
    59  
    60  var UserInviteCmd = &cobra.Command{
    61  	Use:   "invite [email] [teams]",
    62  	Short: "Send user an email invite to a team.",
    63  	Long: `Send user an email invite to a team.
    64  You can invite a user to multiple teams by listing them.
    65  You can specify teams by name or ID.`,
    66  	Example: `  user invite user@example.com myteam
    67    user invite user@example.com myteam1 myteam2`,
    68  	RunE: userInviteCmdF,
    69  }
    70  
    71  var ResetUserPasswordCmd = &cobra.Command{
    72  	Use:     "password [user] [password]",
    73  	Short:   "Set a user's password",
    74  	Long:    "Set a user's password",
    75  	Example: "  user password user@example.com Password1",
    76  	RunE:    resetUserPasswordCmdF,
    77  }
    78  
    79  var updateUserEmailCmd = &cobra.Command{
    80  	Use:     "email [user] [new email]",
    81  	Short:   "Change email of the user",
    82  	Long:    "Change email of the user.",
    83  	Example: "  user email testuser user@example.com",
    84  	RunE:    updateUserEmailCmdF,
    85  }
    86  
    87  var ResetUserMfaCmd = &cobra.Command{
    88  	Use:   "resetmfa [users]",
    89  	Short: "Turn off MFA",
    90  	Long: `Turn off multi-factor authentication for a user.
    91  If MFA enforcement is enabled, the user will be forced to re-enable MFA as soon as they login.`,
    92  	Example: "  user resetmfa user@example.com",
    93  	RunE:    resetUserMfaCmdF,
    94  }
    95  
    96  var DeleteUserCmd = &cobra.Command{
    97  	Use:     "delete [users]",
    98  	Short:   "Delete users and all posts",
    99  	Long:    "Permanently delete user and all related information including posts.",
   100  	Example: "  user delete user@example.com",
   101  	RunE:    deleteUserCmdF,
   102  }
   103  
   104  var DeleteAllUsersCmd = &cobra.Command{
   105  	Use:     "deleteall",
   106  	Short:   "Delete all users and all posts",
   107  	Long:    "Permanently delete all users and all related information including posts.",
   108  	Example: "  user deleteall",
   109  	RunE:    deleteAllUsersCommandF,
   110  }
   111  
   112  var MigrateAuthCmd = &cobra.Command{
   113  	Use:     "migrate_auth [from_auth] [to_auth] [migration-options]",
   114  	Short:   "Mass migrate user accounts authentication type",
   115  	Long:    `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.`,
   116  	Example: "  user migrate_auth email saml users.json",
   117  	Args: func(command *cobra.Command, args []string) error {
   118  		if len(args) < 2 {
   119  			return errors.New("Auth migration requires at least 2 arguments.")
   120  		}
   121  
   122  		toAuth := args[1]
   123  
   124  		if toAuth != "ldap" && toAuth != "saml" {
   125  			return errors.New("Invalid to_auth parameter, must be saml or ldap.")
   126  		}
   127  
   128  		if toAuth == "ldap" && len(args) != 3 {
   129  			return errors.New("Ldap migration requires 3 arguments.")
   130  		}
   131  
   132  		autoFlag, _ := command.Flags().GetBool("auto")
   133  
   134  		if toAuth == "saml" && autoFlag {
   135  			if len(args) != 2 {
   136  				return errors.New("Saml migration requires two arguments when using the --auto flag. See help text for details.")
   137  			}
   138  		}
   139  
   140  		if toAuth == "saml" && !autoFlag {
   141  			if len(args) != 3 {
   142  				return errors.New("Saml migration requires three arguments when not using the --auto flag. See help text for details.")
   143  			}
   144  		}
   145  		return nil
   146  	},
   147  	RunE: migrateAuthCmdF,
   148  }
   149  
   150  var VerifyUserCmd = &cobra.Command{
   151  	Use:     "verify [users]",
   152  	Short:   "Verify email of users",
   153  	Long:    "Verify the emails of some users.",
   154  	Example: "  user verify user1",
   155  	RunE:    verifyUserCmdF,
   156  }
   157  
   158  var SearchUserCmd = &cobra.Command{
   159  	Use:     "search [users]",
   160  	Short:   "Search for users",
   161  	Long:    "Search for users based on username, email, or user ID.",
   162  	Example: "  user search user1@mail.com user2@mail.com",
   163  	RunE:    searchUserCmdF,
   164  }
   165  
   166  func init() {
   167  	UserCreateCmd.Flags().String("username", "", "Required. Username for the new user account.")
   168  	UserCreateCmd.Flags().String("email", "", "Required. The email address for the new user account.")
   169  	UserCreateCmd.Flags().String("password", "", "Required. The password for the new user account.")
   170  	UserCreateCmd.Flags().String("nickname", "", "Optional. The nickname for the new user account.")
   171  	UserCreateCmd.Flags().String("firstname", "", "Optional. The first name for the new user account.")
   172  	UserCreateCmd.Flags().String("lastname", "", "Optional. The last name for the new user account.")
   173  	UserCreateCmd.Flags().String("locale", "", "Optional. The locale (ex: en, fr) for the new user account.")
   174  	UserCreateCmd.Flags().Bool("system_admin", false, "Optional. If supplied, the new user will be a system administrator. Defaults to false.")
   175  
   176  	UserConvertCmd.Flags().Bool("bot", false, "If supplied, convert users to bots.")
   177  	UserConvertCmd.Flags().Bool("user", false, "If supplied, convert a bot to a user.")
   178  	UserConvertCmd.Flags().String("password", "", "The password for converted new user account. Required when \"user\" flag is set.")
   179  	UserConvertCmd.Flags().String("username", "", "Username for the converted user account. Ignored when \"user\" flag is missing.")
   180  	UserConvertCmd.Flags().String("email", "", "The email address for the converted user account. Ignored when \"user\" flag is missing.")
   181  	UserConvertCmd.Flags().String("nickname", "", "The nickname for the converted user account. Ignored when \"user\" flag is missing.")
   182  	UserConvertCmd.Flags().String("firstname", "", "The first name for the converted user account. Ignored when \"user\" flag is missing.")
   183  	UserConvertCmd.Flags().String("lastname", "", "The last name for the converted user account. Ignored when \"user\" flag is missing.")
   184  	UserConvertCmd.Flags().String("locale", "", "The locale (ex: en, fr) for converted new user account. Ignored when \"user\" flag is missing.")
   185  	UserConvertCmd.Flags().Bool("system_admin", false, "If supplied, the converted user will be a system administrator. Defaults to false. Ignored when \"user\" flag is missing.")
   186  
   187  	DeleteUserCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
   188  
   189  	DeleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
   190  
   191  	MigrateAuthCmd.Flags().Bool("force", false, "Force the migration to occur even if there are duplicates on the LDAP server. Duplicates will not be migrated. (ldap only)")
   192  	MigrateAuthCmd.Flags().Bool("auto", false, "Automatically migrate all users. Assumes the usernames and emails are identical between Mattermost and SAML services. (saml only)")
   193  	MigrateAuthCmd.Flags().Bool("dryRun", false, "Run a simulation of the migration process without changing the database.")
   194  	MigrateAuthCmd.SetUsageTemplate(`Usage:
   195    mattermost user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
   196  
   197  Examples:
   198  {{.Example}}
   199  
   200  Arguments:
   201    from_auth:
   202      The authentication service to migrate users accounts from.
   203      Supported options: email, gitlab, ldap, saml.
   204  
   205    to_auth:
   206      The authentication service to migrate users to.
   207      Supported options: ldap, saml.
   208  
   209    migration-options:
   210      Migration specific options, full command help for more information.
   211  
   212  Flags:
   213  {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
   214  
   215  Global Flags:
   216  {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
   217  `)
   218  	MigrateAuthCmd.SetHelpTemplate(`Usage:
   219    mattermost user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
   220  
   221  Examples:
   222  {{.Example}}
   223  
   224  Arguments:
   225    from_auth:
   226      The authentication service to migrate users accounts from.
   227      Supported options: email, gitlab, ldap, saml.
   228  
   229    to_auth:
   230      The authentication service to migrate users to.
   231      Supported options: ldap, saml.
   232  
   233    migration-options (ldap):
   234      match_field:
   235        The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email.
   236        Supported options: email, username.
   237  
   238    migration-options (saml):
   239      users_file:
   240        The path of a json file with the usernames and emails of all users to migrate to SAML. The username and email must be the same that the SAML service provider store. And the email must match with the email in mattermost database.
   241  
   242        Example json content:
   243          {
   244            "usr1@email.com": "usr.one",
   245            "usr2@email.com": "usr.two"
   246          }
   247  
   248  Flags:
   249  {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
   250  
   251  Global Flags:
   252  {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
   253  `)
   254  
   255  	UserCmd.AddCommand(
   256  		UserActivateCmd,
   257  		UserDeactivateCmd,
   258  		UserCreateCmd,
   259  		UserConvertCmd,
   260  		UserInviteCmd,
   261  		ResetUserPasswordCmd,
   262  		updateUserEmailCmd,
   263  		ResetUserMfaCmd,
   264  		DeleteUserCmd,
   265  		DeleteAllUsersCmd,
   266  		MigrateAuthCmd,
   267  		VerifyUserCmd,
   268  		SearchUserCmd,
   269  	)
   270  	RootCmd.AddCommand(UserCmd)
   271  }
   272  
   273  func userActivateCmdF(command *cobra.Command, args []string) error {
   274  	a, err := InitDBCommandContextCobra(command)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	defer a.Srv().Shutdown()
   279  
   280  	if len(args) < 1 {
   281  		return errors.New("Expected at least one argument. See help text for details.")
   282  	}
   283  
   284  	changeUsersActiveStatus(a, args, true)
   285  
   286  	return nil
   287  }
   288  
   289  func changeUsersActiveStatus(a *app.App, userArgs []string, active bool) {
   290  	users := getUsersFromUserArgs(a, userArgs)
   291  	for i, user := range users {
   292  		err := changeUserActiveStatus(a, user, userArgs[i], active)
   293  
   294  		if err != nil {
   295  			CommandPrintErrorln(err.Error())
   296  		}
   297  	}
   298  }
   299  
   300  func changeUserActiveStatus(a *app.App, user *model.User, userArg string, activate bool) error {
   301  	if user == nil {
   302  		return fmt.Errorf("Can't find user '%v'", userArg)
   303  	}
   304  	if user.IsSSOUser() {
   305  		fmt.Println("You must also deactivate this user in the SSO provider or they will be reactivated on next login or sync.")
   306  	}
   307  	updatedUser, err := a.UpdateActive(user, activate)
   308  	if err != nil {
   309  		return fmt.Errorf("Unable to change activation status of user: %v", userArg)
   310  	}
   311  
   312  	auditRec := a.MakeAuditRecord("changeActiveUserStatus", audit.Success)
   313  	auditRec.AddMeta("user", updatedUser)
   314  	auditRec.AddMeta("activate", activate)
   315  	a.LogAuditRec(auditRec, nil)
   316  
   317  	return nil
   318  }
   319  
   320  func userDeactivateCmdF(command *cobra.Command, args []string) error {
   321  	a, err := InitDBCommandContextCobra(command)
   322  	if err != nil {
   323  		return err
   324  	}
   325  	defer a.Srv().Shutdown()
   326  
   327  	if len(args) < 1 {
   328  		return errors.New("Expected at least one argument. See help text for details.")
   329  	}
   330  
   331  	changeUsersActiveStatus(a, args, false)
   332  
   333  	return nil
   334  }
   335  
   336  func userCreateCmdF(command *cobra.Command, args []string) error {
   337  	a, err := InitDBCommandContextCobra(command)
   338  	if err != nil {
   339  		return err
   340  	}
   341  	defer a.Srv().Shutdown()
   342  
   343  	username, erru := command.Flags().GetString("username")
   344  	if erru != nil || username == "" {
   345  		return errors.New("Username is required")
   346  	}
   347  	email, erre := command.Flags().GetString("email")
   348  	if erre != nil || email == "" {
   349  		return errors.New("Email is required")
   350  	}
   351  	email = strings.ToLower((email))
   352  	password, errp := command.Flags().GetString("password")
   353  	if errp != nil || password == "" {
   354  		return errors.New("Password is required")
   355  	}
   356  	nickname, _ := command.Flags().GetString("nickname")
   357  	firstname, _ := command.Flags().GetString("firstname")
   358  	lastname, _ := command.Flags().GetString("lastname")
   359  	locale, _ := command.Flags().GetString("locale")
   360  	systemAdmin, _ := command.Flags().GetBool("system_admin")
   361  
   362  	user := &model.User{
   363  		Username:  username,
   364  		Email:     email,
   365  		Password:  password,
   366  		Nickname:  nickname,
   367  		FirstName: firstname,
   368  		LastName:  lastname,
   369  		Locale:    locale,
   370  	}
   371  
   372  	ruser, err := a.CreateUser(user)
   373  	if ruser == nil {
   374  		return errors.New("Unable to create user. Error: " + err.Error())
   375  	}
   376  
   377  	if systemAdmin {
   378  		if _, err := a.UpdateUserRoles(ruser.Id, "system_user system_admin", false); err != nil {
   379  			return errors.New("Unable to make user system admin. Error: " + err.Error())
   380  		}
   381  	} else {
   382  		// This else case exists to prevent the first user created from being
   383  		// created as a system admin unless explicitly specified.
   384  		if _, err := a.UpdateUserRoles(ruser.Id, "system_user", false); err != nil {
   385  			return errors.New("If this is the first user: Unable to prevent user from being system admin. Error: " + err.Error())
   386  		}
   387  	}
   388  
   389  	CommandPrettyPrintln("id: " + ruser.Id)
   390  	CommandPrettyPrintln("username: " + ruser.Username)
   391  	CommandPrettyPrintln("nickname: " + ruser.Nickname)
   392  	CommandPrettyPrintln("position: " + ruser.Position)
   393  	CommandPrettyPrintln("first_name: " + ruser.FirstName)
   394  	CommandPrettyPrintln("last_name: " + ruser.LastName)
   395  	CommandPrettyPrintln("email: " + ruser.Email)
   396  	CommandPrettyPrintln("auth_service: " + ruser.AuthService)
   397  
   398  	auditRec := a.MakeAuditRecord("userCreate", audit.Success)
   399  	auditRec.AddMeta("user", ruser)
   400  	auditRec.AddMeta("system_admin", systemAdmin)
   401  	a.LogAuditRec(auditRec, nil)
   402  
   403  	return nil
   404  }
   405  
   406  func usersToBots(args []string, a *app.App) {
   407  	users := getUsersFromUserArgs(a, args)
   408  	for i, user := range users {
   409  		if user == nil {
   410  			CommandPrintErrorln(fmt.Errorf("Unable to find user \"%s\"", args[i]))
   411  			continue
   412  		}
   413  
   414  		bot, err := a.ConvertUserToBot(user)
   415  		if err != nil {
   416  			CommandPrintErrorln(err.Error())
   417  			continue
   418  		}
   419  
   420  		CommandPrettyPrintln(fmt.Sprintf("User %s is converted to bot successfully", bot.UserId))
   421  
   422  		auditRec := a.MakeAuditRecord("userToBot", audit.Success)
   423  		auditRec.AddMeta("user", user)
   424  		a.LogAuditRec(auditRec, nil)
   425  	}
   426  }
   427  
   428  func getUpdatedPassword(command *cobra.Command, a *app.App, user *model.User) (string, error) {
   429  	password, err := command.Flags().GetString("password")
   430  	if err != nil {
   431  		return "", fmt.Errorf("Unable to read password. Error: %s", err.Error())
   432  	}
   433  
   434  	if password == "" {
   435  		return "", errors.New("Password is required.")
   436  	}
   437  
   438  	return password, nil
   439  }
   440  
   441  func getUpdatedUserModel(command *cobra.Command, a *app.App, user *model.User) (*model.User, error) {
   442  	username, _ := command.Flags().GetString("username")
   443  	if username == "" {
   444  		if user.Username == "" {
   445  			return nil, errors.New("Invalid username. Username is empty.")
   446  		}
   447  	} else {
   448  		user.Username = username
   449  	}
   450  
   451  	email, _ := command.Flags().GetString("email")
   452  	if email == "" {
   453  		if user.Email == "" {
   454  			return nil, errors.New("Invalid email. Email is empty.")
   455  		}
   456  	} else {
   457  		user.Email = email
   458  	}
   459  
   460  	nickname, _ := command.Flags().GetString("nickname")
   461  	if nickname != "" {
   462  		user.Nickname = nickname
   463  	}
   464  
   465  	firstname, _ := command.Flags().GetString("firstname")
   466  	if firstname != "" {
   467  		user.FirstName = firstname
   468  	}
   469  
   470  	lastname, _ := command.Flags().GetString("lastname")
   471  	if lastname != "" {
   472  		user.LastName = lastname
   473  	}
   474  
   475  	locale, _ := command.Flags().GetString("locale")
   476  	if locale != "" {
   477  		user.Locale = locale
   478  	}
   479  
   480  	if !user.IsLDAPUser() && !user.IsSAMLUser() && !app.CheckUserDomain(user, *a.Config().TeamSettings.RestrictCreationToDomains) {
   481  		return nil, errors.New("The email does not belong to an accepted domain.")
   482  	}
   483  
   484  	return user, nil
   485  }
   486  
   487  func botToUser(command *cobra.Command, args []string, a *app.App) error {
   488  	if len(args) != 1 {
   489  		return errors.New("Expect 1 argument. See help text for more details.")
   490  	}
   491  
   492  	user := getUserFromUserArg(a, args[0])
   493  	if user == nil {
   494  		return errors.New("Unable to find bot.")
   495  	}
   496  
   497  	_, appErr := a.GetBot(user.Id, false)
   498  	if appErr != nil {
   499  		return fmt.Errorf("Unable to find bot. Error: %s", appErr.Error())
   500  	}
   501  
   502  	password, err := getUpdatedPassword(command, a, user)
   503  	if err != nil {
   504  		return err
   505  	}
   506  
   507  	user, err = getUpdatedUserModel(command, a, user)
   508  	if err != nil {
   509  		return err
   510  	}
   511  
   512  	user, appErr = a.UpdateUser(user, false)
   513  	if appErr != nil {
   514  		return fmt.Errorf("Unable to update user. Error: %s" + appErr.Error())
   515  	}
   516  
   517  	appErr = a.UpdatePassword(user, password)
   518  	if appErr != nil {
   519  		return fmt.Errorf("Unable to update password. Error: %s", appErr.Error())
   520  	}
   521  
   522  	systemAdmin, _ := command.Flags().GetBool("system_admin")
   523  	if systemAdmin && !user.IsInRole(model.SYSTEM_ADMIN_ROLE_ID) {
   524  		if _, appErr = a.UpdateUserRoles(
   525  			user.Id,
   526  			fmt.Sprintf("%s %s", user.Roles, model.SYSTEM_ADMIN_ROLE_ID),
   527  			false); appErr != nil {
   528  			return fmt.Errorf("Unable to make user system admin. Error: %s" + appErr.Error())
   529  		}
   530  	}
   531  
   532  	err = a.Srv().Store.Bot().PermanentDelete(user.Id)
   533  	if err != nil {
   534  		return fmt.Errorf("Unable to delete bot. Error: %v", err)
   535  	}
   536  
   537  	CommandPrettyPrintln("id: " + user.Id)
   538  	CommandPrettyPrintln("username: " + user.Username)
   539  	CommandPrettyPrintln("email: " + user.Email)
   540  	CommandPrettyPrintln("nickname: " + user.Nickname)
   541  	CommandPrettyPrintln("first_name: " + user.FirstName)
   542  	CommandPrettyPrintln("last_name: " + user.LastName)
   543  	CommandPrettyPrintln("roles: " + user.Roles)
   544  	CommandPrettyPrintln("locale: " + user.Locale)
   545  
   546  	auditRec := a.MakeAuditRecord("botToUser", audit.Success)
   547  	auditRec.AddMeta("bot", user)
   548  	auditRec.AddMeta("user", user)
   549  	a.LogAuditRec(auditRec, nil)
   550  
   551  	return nil
   552  }
   553  
   554  func userConvertCmdF(command *cobra.Command, args []string) error {
   555  	a, err := InitDBCommandContextCobra(command)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	defer a.Srv().Shutdown()
   560  
   561  	toBot, err := command.Flags().GetBool("bot")
   562  	if err != nil {
   563  		return errors.New("Invalid command. See help text for details.")
   564  	}
   565  
   566  	toUser, err := command.Flags().GetBool("user")
   567  	if err != nil {
   568  		return errors.New("Invalid command. See help text for details.")
   569  	}
   570  
   571  	if !(toUser || toBot) {
   572  		return errors.New("Expect either \"user\" flag or \"bot\" flag. See help text for details.")
   573  	}
   574  
   575  	if toUser && toBot {
   576  		return errors.New("Expect either \"user\" flag or \"bot\" flag but not both. See help text for details.")
   577  	}
   578  
   579  	if toUser {
   580  		return botToUser(command, args, a)
   581  	}
   582  
   583  	usersToBots(args, a)
   584  	return nil
   585  }
   586  
   587  func userInviteCmdF(command *cobra.Command, args []string) error {
   588  	a, err := InitDBCommandContextCobra(command)
   589  	if err != nil {
   590  		return err
   591  	}
   592  	defer a.Srv().Shutdown()
   593  
   594  	if len(args) < 2 {
   595  		return errors.New("Expected at least two arguments. See help text for details.")
   596  	}
   597  
   598  	email := args[0]
   599  	email = strings.ToLower(email)
   600  	if !model.IsValidEmail(email) {
   601  		return errors.New("Invalid email")
   602  	}
   603  
   604  	teams := getTeamsFromTeamArgs(a, args[1:])
   605  	for i, team := range teams {
   606  		err := inviteUser(a, email, team, args[i+1])
   607  
   608  		if err != nil {
   609  			CommandPrintErrorln(err.Error())
   610  		}
   611  	}
   612  
   613  	return nil
   614  }
   615  
   616  func inviteUser(a *app.App, email string, team *model.Team, teamArg string) error {
   617  	invites := []string{email}
   618  	if team == nil {
   619  		return fmt.Errorf("Can't find team '%v'", teamArg)
   620  	}
   621  
   622  	if !*a.Config().ServiceSettings.EnableEmailInvitations {
   623  		return fmt.Errorf("Email invites are disabled.")
   624  	}
   625  
   626  	a.Srv().EmailService.SendInviteEmails(team, "Administrator", "Mattermost CLI "+model.NewId(), invites, *a.Config().ServiceSettings.SiteURL)
   627  	CommandPrettyPrintln("Invites may or may not have been sent.")
   628  
   629  	auditRec := a.MakeAuditRecord("inviteUser", audit.Success)
   630  	auditRec.AddMeta("email", email)
   631  	auditRec.AddMeta("team", team)
   632  	a.LogAuditRec(auditRec, nil)
   633  
   634  	return nil
   635  }
   636  
   637  func resetUserPasswordCmdF(command *cobra.Command, args []string) error {
   638  	a, err := InitDBCommandContextCobra(command)
   639  	if err != nil {
   640  		return err
   641  	}
   642  	defer a.Srv().Shutdown()
   643  
   644  	if len(args) != 2 {
   645  		return errors.New("Expected two arguments. See help text for details.")
   646  	}
   647  
   648  	user := getUserFromUserArg(a, args[0])
   649  	if user == nil {
   650  		return errors.New("Unable to find user '" + args[0] + "'")
   651  	}
   652  	password := args[1]
   653  
   654  	if err := a.Srv().Store.User().UpdatePassword(user.Id, model.HashPassword(password)); err != nil {
   655  		return err
   656  	}
   657  
   658  	auditRec := a.MakeAuditRecord("resetUserPassword", audit.Success)
   659  	auditRec.AddMeta("user", user)
   660  	a.LogAuditRec(auditRec, nil)
   661  
   662  	return nil
   663  }
   664  
   665  func updateUserEmailCmdF(command *cobra.Command, args []string) error {
   666  	a, err := InitDBCommandContextCobra(command)
   667  	if err != nil {
   668  		return err
   669  	}
   670  	defer a.Srv().Shutdown()
   671  
   672  	if len(args) != 2 {
   673  		return errors.New("Expected two arguments. See help text for details.")
   674  	}
   675  
   676  	newEmail := args[1]
   677  	newEmail = strings.ToLower(newEmail)
   678  	if !model.IsValidEmail(newEmail) {
   679  		return errors.New("Invalid email: '" + newEmail + "'")
   680  	}
   681  
   682  	if len(args) != 2 {
   683  		return errors.New("Expected two arguments. See help text for details.")
   684  	}
   685  
   686  	user := getUserFromUserArg(a, args[0])
   687  	if user == nil {
   688  		return errors.New("Unable to find user '" + args[0] + "'")
   689  	}
   690  
   691  	user.Email = newEmail
   692  	_, errUpdate := a.UpdateUser(user, true)
   693  	if errUpdate != nil {
   694  		return errors.New(errUpdate.Message)
   695  	}
   696  
   697  	auditRec := a.MakeAuditRecord("updateUserEmail", audit.Success)
   698  	auditRec.AddMeta("user", user)
   699  	auditRec.AddMeta("email", newEmail)
   700  	a.LogAuditRec(auditRec, nil)
   701  
   702  	return nil
   703  }
   704  
   705  func resetUserMfaCmdF(command *cobra.Command, args []string) error {
   706  	a, err := InitDBCommandContextCobra(command)
   707  	if err != nil {
   708  		return err
   709  	}
   710  	defer a.Srv().Shutdown()
   711  
   712  	if len(args) < 1 {
   713  		return errors.New("Expected at least one argument. See help text for details.")
   714  	}
   715  
   716  	users := getUsersFromUserArgs(a, args)
   717  	for i, user := range users {
   718  		if user == nil {
   719  			return errors.New("Unable to find user '" + args[i] + "'")
   720  		}
   721  
   722  		if err := a.DeactivateMfa(user.Id); err != nil {
   723  			return err
   724  		}
   725  
   726  		auditRec := a.MakeAuditRecord("resetUserMfa", audit.Success)
   727  		auditRec.AddMeta("user", user)
   728  		a.LogAuditRec(auditRec, nil)
   729  	}
   730  
   731  	return nil
   732  }
   733  
   734  func deleteUserCmdF(command *cobra.Command, args []string) error {
   735  	a, err := InitDBCommandContextCobra(command)
   736  	if err != nil {
   737  		return err
   738  	}
   739  	defer a.Srv().Shutdown()
   740  
   741  	if len(args) < 1 {
   742  		return errors.New("Expected at least one argument. See help text for details.")
   743  	}
   744  
   745  	confirmFlag, _ := command.Flags().GetBool("confirm")
   746  	if !confirmFlag {
   747  		var confirm string
   748  		CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
   749  		fmt.Scanln(&confirm)
   750  
   751  		if confirm != "YES" {
   752  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   753  		}
   754  		CommandPrettyPrintln("Are you sure you want to permanently delete the specified users? (YES/NO): ")
   755  		fmt.Scanln(&confirm)
   756  		if confirm != "YES" {
   757  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   758  		}
   759  	}
   760  
   761  	users := getUsersFromUserArgs(a, args)
   762  
   763  	for i, user := range users {
   764  		if user == nil {
   765  			return errors.New("Unable to find user '" + args[i] + "'")
   766  		}
   767  
   768  		if user.IsBot {
   769  			if err := a.PermanentDeleteBot(user.Id); err != nil {
   770  				return err
   771  			}
   772  		} else {
   773  			if err := a.PermanentDeleteUser(user); err != nil {
   774  				return err
   775  			}
   776  		}
   777  
   778  		auditRec := a.MakeAuditRecord("deleteUser", audit.Success)
   779  		auditRec.AddMeta("user", user)
   780  		auditRec.AddMeta("isBot", user.IsBot)
   781  		a.LogAuditRec(auditRec, nil)
   782  	}
   783  
   784  	return nil
   785  }
   786  
   787  func deleteAllUsersCommandF(command *cobra.Command, args []string) error {
   788  	a, err := InitDBCommandContextCobra(command)
   789  	if err != nil {
   790  		return err
   791  	}
   792  	defer a.Srv().Shutdown()
   793  
   794  	if len(args) > 0 {
   795  		return errors.New("Expected zero arguments.")
   796  	}
   797  
   798  	confirmFlag, _ := command.Flags().GetBool("confirm")
   799  	if !confirmFlag {
   800  		var confirm string
   801  		CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
   802  		fmt.Scanln(&confirm)
   803  
   804  		if confirm != "YES" {
   805  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   806  		}
   807  		CommandPrettyPrintln("Are you sure you want to permanently delete all user accounts? (YES/NO): ")
   808  		fmt.Scanln(&confirm)
   809  		if confirm != "YES" {
   810  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   811  		}
   812  	}
   813  
   814  	if err := a.PermanentDeleteAllUsers(); err != nil {
   815  		return err
   816  	}
   817  	CommandPrettyPrintln("All user accounts successfully deleted.")
   818  
   819  	auditRec := a.MakeAuditRecord("deleteAllUsers", audit.Success)
   820  	a.LogAuditRec(auditRec, nil)
   821  
   822  	return nil
   823  }
   824  
   825  func migrateAuthCmdF(command *cobra.Command, args []string) error {
   826  	if args[1] == "saml" {
   827  		return migrateAuthToSamlCmdF(command, args)
   828  	}
   829  	return migrateAuthToLdapCmdF(command, args)
   830  }
   831  
   832  func migrateAuthToLdapCmdF(command *cobra.Command, args []string) error {
   833  	a, err := InitDBCommandContextCobra(command)
   834  	if err != nil {
   835  		return err
   836  	}
   837  	defer a.Srv().Shutdown()
   838  
   839  	fromAuth := args[0]
   840  	matchField := args[2]
   841  
   842  	if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") {
   843  		return errors.New("Invalid from_auth argument")
   844  	}
   845  
   846  	// Email auth in Mattermost system is represented by ""
   847  	if fromAuth == "email" {
   848  		fromAuth = ""
   849  	}
   850  
   851  	if len(matchField) == 0 || (matchField != "email" && matchField != "username") {
   852  		return errors.New("Invalid match_field argument")
   853  	}
   854  
   855  	forceFlag, _ := command.Flags().GetBool("force")
   856  	dryRunFlag, _ := command.Flags().GetBool("dryRun")
   857  
   858  	if migrate := a.AccountMigration(); migrate != nil {
   859  		if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag, dryRunFlag); err != nil {
   860  			return errors.New("Error while migrating users: " + err.Error())
   861  		}
   862  
   863  		CommandPrettyPrintln("Successfully migrated accounts.")
   864  
   865  		if !dryRunFlag {
   866  			auditRec := a.MakeAuditRecord("migrateAuthToLdap", audit.Success)
   867  			auditRec.AddMeta("fromAuth", fromAuth)
   868  			auditRec.AddMeta("matchField", matchField)
   869  			auditRec.AddMeta("force", forceFlag)
   870  			a.LogAuditRec(auditRec, nil)
   871  		}
   872  	}
   873  	return nil
   874  }
   875  
   876  func migrateAuthToSamlCmdF(command *cobra.Command, args []string) error {
   877  	a, err := InitDBCommandContextCobra(command)
   878  	if err != nil {
   879  		return err
   880  	}
   881  	defer a.Srv().Shutdown()
   882  
   883  	dryRunFlag, _ := command.Flags().GetBool("dryRun")
   884  	autoFlag, _ := command.Flags().GetBool("auto")
   885  
   886  	matchesFile := ""
   887  	matches := map[string]string{}
   888  	if !autoFlag {
   889  		matchesFile = args[2]
   890  
   891  		file, e := ioutil.ReadFile(matchesFile)
   892  		if e != nil {
   893  			return errors.New("Invalid users file.")
   894  		}
   895  		if json.Unmarshal(file, &matches) != nil {
   896  			return errors.New("Invalid users file.")
   897  		}
   898  	}
   899  
   900  	fromAuth := args[0]
   901  
   902  	if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "ldap") {
   903  		return errors.New("Invalid from_auth argument")
   904  	}
   905  
   906  	if autoFlag && !dryRunFlag {
   907  		var confirm string
   908  		CommandPrettyPrintln("You are about to perform an automatic \"" + fromAuth + " to saml\" migration. This must only be done if your current Mattermost users with " + fromAuth + " auth have the same username and email in your SAML service. Otherwise, provide the usernames and emails from your SAML Service using the \"users file\" without the \"--auto\" option.\n\nDo you want to proceed with automatic migration anyway? (YES/NO):")
   909  		fmt.Scanln(&confirm)
   910  
   911  		if confirm != "YES" {
   912  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   913  		}
   914  	}
   915  
   916  	// Email auth in Mattermost system is represented by ""
   917  	if fromAuth == "email" {
   918  		fromAuth = ""
   919  	}
   920  
   921  	if migrate := a.AccountMigration(); migrate != nil {
   922  		if err := migrate.MigrateToSaml(fromAuth, matches, autoFlag, dryRunFlag); err != nil {
   923  			return errors.New("Error while migrating users: " + err.Error())
   924  		}
   925  
   926  		CommandPrettyPrintln("Successfully migrated accounts.")
   927  
   928  		if !dryRunFlag {
   929  			auditRec := a.MakeAuditRecord("migrateAuthToSaml", audit.Success)
   930  			auditRec.AddMeta("auto", autoFlag)
   931  			a.LogAuditRec(auditRec, nil)
   932  		}
   933  	}
   934  	return nil
   935  }
   936  
   937  func verifyUserCmdF(command *cobra.Command, args []string) error {
   938  	a, err := InitDBCommandContextCobra(command)
   939  	if err != nil {
   940  		return err
   941  	}
   942  	defer a.Srv().Shutdown()
   943  
   944  	if len(args) < 1 {
   945  		return errors.New("Expected at least one argument. See help text for details.")
   946  	}
   947  
   948  	users := getUsersFromUserArgs(a, args)
   949  
   950  	for i, user := range users {
   951  		if user == nil {
   952  			CommandPrintErrorln("Unable to find user '" + args[i] + "'")
   953  			continue
   954  		}
   955  		if _, err := a.Srv().Store.User().VerifyEmail(user.Id, user.Email); err != nil {
   956  			CommandPrintErrorln("Unable to verify '" + args[i] + "' email. Error: " + err.Error())
   957  		}
   958  	}
   959  
   960  	return nil
   961  }
   962  
   963  func searchUserCmdF(command *cobra.Command, args []string) error {
   964  	a, err := InitDBCommandContextCobra(command)
   965  	if err != nil {
   966  		return err
   967  	}
   968  	defer a.Srv().Shutdown()
   969  
   970  	if len(args) < 1 {
   971  		return errors.New("Expected at least one argument. See help text for details.")
   972  	}
   973  
   974  	users := getUsersFromUserArgs(a, args)
   975  
   976  	for i, user := range users {
   977  		if i > 0 {
   978  			CommandPrettyPrintln("------------------------------")
   979  		}
   980  		if user == nil {
   981  			CommandPrintErrorln("Unable to find user '" + args[i] + "'")
   982  			continue
   983  		}
   984  
   985  		CommandPrettyPrintln("id: " + user.Id)
   986  		CommandPrettyPrintln("username: " + user.Username)
   987  		CommandPrettyPrintln("nickname: " + user.Nickname)
   988  		CommandPrettyPrintln("position: " + user.Position)
   989  		CommandPrettyPrintln("first_name: " + user.FirstName)
   990  		CommandPrettyPrintln("last_name: " + user.LastName)
   991  		CommandPrettyPrintln("email: " + user.Email)
   992  		CommandPrettyPrintln("auth_service: " + user.AuthService)
   993  	}
   994  
   995  	return nil
   996  }