/* * Copyright 2026 Oleg Borodin * * This work is published and licensed under a Creative Commons * Attribution-NonCommercial-NoDerivatives 4.0 International License. * * Distribution of this work is permitted, but commercial use and * modifications are strictly prohibited. */ package main import ( "context" "regexp" "strings" "time" "github.com/spf13/cobra" "mstore/app/descr" "mstore/pkg/client" ) const ( uuidRegex = `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$` defaultHostname = "localhost:1025" ) func (util *AccountUtil) CreateAccountCmds() *cobra.Command { var subCmd = &cobra.Command{ Use: "account", Short: "Account operation", } const defaultTimeout uint64 = 10 // CreateAccount var createAccountCmd = &cobra.Command{ Use: "create", Short: "Create user account", Run: util.CreateAccount, } createAccountCmd.Flags().StringVarP(&util.createAccountParams.Username, "user", "u", "", "Username") createAccountCmd.Flags().StringVarP(&util.createAccountParams.Password, "pass", "p", "", "Password") createAccountCmd.Flags().StringVarP(&util.createAccountParams.Hostname, "host", "x", defaultHostname, "Hostname") createAccountCmd.Flags().Uint64VarP(&util.createAccountParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") createAccountCmd.Flags().StringVarP(&util.createAccountParams.NewUsername, "newuser", "U", "", "New account username") createAccountCmd.Flags().StringVarP(&util.createAccountParams.NewPassword, "newpass", "P", "", "New account password") createAccountCmd.MarkFlagRequired("host") createAccountCmd.MarkFlagsRequiredTogether("newuser", "newpass") createAccountCmd.MarkFlagsRequiredTogether("user", "pass") subCmd.AddCommand(createAccountCmd) // GetAccount var getAccountCmd = &cobra.Command{ Use: "get", Short: "Get account info", Run: util.GetAccount, } getAccountCmd.Flags().StringVarP(&util.getAccountParams.Hostname, "host", "x", defaultHostname, "Hostname") getAccountCmd.Flags().StringVarP(&util.getAccountParams.Username, "user", "u", "", "Username") getAccountCmd.Flags().StringVarP(&util.getAccountParams.Password, "pass", "p", "", "Password") getAccountCmd.Flags().Uint64VarP(&util.getAccountParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") getAccountCmd.Flags().StringVarP(&util.getAccountParams.AccountID, "id", "I", "", "Account ID or name") getAccountCmd.Flags().StringVarP(&util.getAccountParams.AccountID, "name", "n", "", "Account ID or name") getAccountCmd.MarkFlagRequired("host") getAccountCmd.MarkFlagsOneRequired("id", "name") getAccountCmd.MarkFlagsRequiredTogether("user", "pass") subCmd.AddCommand(getAccountCmd) // UpdateAccount var updateAccountCmd = &cobra.Command{ Use: "info", Short: "Update account parameters", Run: util.UpdateAccount, } updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.Username, "user", "u", "", "Username") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.Password, "pass", "p", "", "Password") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.Hostname, "host", "x", "", "File path") updateAccountCmd.Flags().Uint64VarP(&util.updateAccountParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.AccountID, "id", "I", "", "Account ID or username") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.AccountID, "name", "n", "", "Account ID or username") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.NewUsername, "newname", "N", "", "New username") updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.NewPassword, "newpass", "P", "", "New password") updateAccountCmd.MarkFlagRequired("host") updateAccountCmd.MarkFlagsOneRequired("id", "name") updateAccountCmd.MarkFlagsOneRequired("newname", "newpass") subCmd.AddCommand(updateAccountCmd) // DeleteAccount var deleteAccountCmd = &cobra.Command{ Use: "delete", Short: "Delete account", Run: util.DeleteAccount, } deleteAccountCmd.Flags().StringVarP(&util.deleteAccountParams.Username, "user", "u", "", "Username") deleteAccountCmd.Flags().StringVarP(&util.deleteAccountParams.Password, "pass", "p", "", "Password") deleteAccountCmd.Flags().StringVarP(&util.deleteAccountParams.Hostname, "host", "x", defaultHostname, "Hostname") deleteAccountCmd.Flags().Uint64VarP(&util.deleteAccountParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") deleteAccountCmd.Flags().StringVarP(&util.deleteAccountParams.AccountID, "id", "I", "", "Account ID") deleteAccountCmd.Flags().StringVarP(&util.updateAccountParams.AccountID, "name", "n", "", "Account ID or username") deleteAccountCmd.MarkFlagRequired("host") deleteAccountCmd.MarkFlagsOneRequired("id", "name") deleteAccountCmd.MarkFlagsRequiredTogether("user", "pass") subCmd.AddCommand(deleteAccountCmd) return subCmd } func (util *AccountUtil) CreateAccountsCmds() *cobra.Command { var subCmd = &cobra.Command{ Use: "accounts", Short: "Accounts operation", } const defaultTimeout uint64 = 10 // ListAccounts var listAccountsCmd = &cobra.Command{ Use: "list", Short: "list accounts", Run: util.ListAccounts, } listAccountsCmd.Flags().StringVarP(&util.listAccountsParams.Username, "user", "u", "", "Username") listAccountsCmd.Flags().StringVarP(&util.listAccountsParams.Password, "pass", "p", "", "Password") listAccountsCmd.Flags().StringVarP(&util.listAccountsParams.Hostname, "host", "x", defaultHostname, "Hostname") listAccountsCmd.Flags().Uint64VarP(&util.listAccountsParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") listAccountsCmd.Flags().BoolVarP(&util.listAccountsParams.Detail, "detail", "d", false, "Show detail information") listAccountsCmd.Flags().StringVarP(&util.listAccountsParams.Regex, "regex", "r", "", "Output regexp for usernames") listAccountsCmd.MarkFlagRequired("host") subCmd.AddCommand(listAccountsCmd) return subCmd } type AccountUtil struct { createAccountParams CreateAccountParams updateAccountParams UpdateAccountParams getAccountParams GetAccountParams deleteAccountParams DeleteAccountParams listAccountsParams ListAccountsParams } // CreateAccount type CreateAccountParams struct { Username string Password string Hostname string NewUsername string NewPassword string Timeout uint64 } type CreateAccountResult struct { AccountID string } func (util *AccountUtil) CreateAccount(cmd *cobra.Command, args []string) { res, err := util.createAccount(&util.createAccountParams) printResponse(res, err) } func (util *AccountUtil) createAccount(params *CreateAccountParams) (*CreateAccountResult, error) { var err error res := &CreateAccountResult{} params.Hostname, err = packUserinfo(params.Hostname, params.NewUsername, params.NewPassword) if err != nil { return res, err } timeout := time.Duration(params.Timeout) * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) accountID, err := client.NewClient().CreateAccount(ctx, params.Hostname, params.NewUsername, params.NewPassword) if err != nil { return res, err } res.AccountID = accountID return res, err } // UpdateAccount type UpdateAccountParams struct { Hostname string Username string Password string Timeout uint64 AccountID string NewUsername string NewPassword string } type UpdateAccountResult struct { File *descr.File `json:"file,omitempty"` } func (util *AccountUtil) UpdateAccount(cmd *cobra.Command, args []string) { res, err := util.updateAccount(&util.updateAccountParams) printResponse(res, err) } func (util *AccountUtil) updateAccount(params *UpdateAccountParams) (*UpdateAccountResult, error) { var err error res := &UpdateAccountResult{} params.Hostname, err = packUserinfo(params.Hostname, params.Username, params.Password) if err != nil { return res, err } timeout := time.Duration(params.Timeout) * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) re := regexp.MustCompile(uuidRegex) id := strings.ToLower(params.AccountID) if re.MatchString(id) { err = client.NewClient().UpdateAccountByID(ctx, params.Hostname, id, params.NewUsername, params.NewPassword) } else { err = client.NewClient().UpdateAccountByName(ctx, params.Hostname, params.AccountID, params.NewUsername, params.NewPassword) } if err != nil { return res, err } return res, err } // Get file type GetAccountParams struct { Hostname string Username string Password string Timeout uint64 AccountID string } func (util *AccountUtil) GetAccount(cmd *cobra.Command, args []string) { res, err := util.getAccount(&util.getAccountParams) printResponse(res, err) } type GetAccountResult struct { Account *descr.AccountShort `json:"account,omitempty"` } func (util *AccountUtil) getAccount(params *GetAccountParams) (*GetAccountResult, error) { var err error res := &GetAccountResult{} params.Hostname, err = packUserinfo(params.Hostname, params.Username, params.Password) if err != nil { return res, err } timeout := time.Duration(params.Timeout) * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) opRes := &descr.AccountShort{} re := regexp.MustCompile(uuidRegex) id := strings.ToLower(params.AccountID) if re.MatchString(id) { opRes, err = client.NewClient().GetAccountByID(ctx, params.Hostname, id) } else { opRes, err = client.NewClient().GetAccountByName(ctx, params.Hostname, params.AccountID) } if err != nil { return res, err } res.Account = opRes return res, err } // DeleteAccount type DeleteAccountParams struct { Hostname string Username string Password string AccountID string Timeout uint64 } type DeleteAccountResult struct{} func (util *AccountUtil) DeleteAccount(cmd *cobra.Command, args []string) { res, err := util.deleteAccount(&util.deleteAccountParams) printResponse(res, err) } func (util *AccountUtil) deleteAccount(params *DeleteAccountParams) (*DeleteAccountResult, error) { var err error res := &DeleteAccountResult{} params.Hostname, err = packUserinfo(params.Hostname, params.Username, params.Password) if err != nil { return res, err } timeout := time.Duration(params.Timeout) * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) re := regexp.MustCompile(uuidRegex) id := strings.ToLower(params.AccountID) if re.MatchString(id) { err = client.NewClient().DeleteAccountByID(ctx, params.Hostname, id) } else { err = client.NewClient().DeleteAccountByName(ctx, params.Hostname, params.AccountID) } if err != nil { return res, err } return res, err } // ListAccounts type ListAccountsParams struct { Hostname string Username string Password string Timeout uint64 Detail bool Regex string } type ListAccountsResult struct { Accounts []descr.AccountShort `json:"accounts,omitempty"` Usernames []string `json:"names,omitempty"` } func (util *AccountUtil) ListAccounts(cmd *cobra.Command, args []string) { res, err := util.listAccounts(&util.listAccountsParams) printResponse(res, err) } func (util *AccountUtil) listAccounts(params *ListAccountsParams) (*ListAccountsResult, error) { var err error res := &ListAccountsResult{} params.Hostname, err = packUserinfo(params.Hostname, params.Username, params.Password) if err != nil { return res, err } outRe, err := regexp.Compile(params.Regex) if err != nil { return res, err } timeout := time.Duration(params.Timeout) * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) accounts, err := client.NewClient().ListAccounts(ctx, params.Hostname) if err != nil { return res, err } outAccounts := make([]descr.AccountShort, 0) if params.Regex != "" { for _, item := range accounts { if outRe.MatchString(item.Username) { outAccounts = append(outAccounts, item) } } } else { outAccounts = accounts } if params.Detail { res.Accounts = outAccounts } else { res.Usernames = make([]string, 0) for _, item := range outAccounts { res.Usernames = append(res.Usernames, item.Username) } } return res, err }