You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

user.go 4.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package repl
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "fmt"
  6. "os"
  7. "github.com/spf13/cobra"
  8. "gitlink.org.cn/cloudream/common/pkgs/logger"
  9. stgglb "gitlink.org.cn/cloudream/jcs-pub/common/globals"
  10. hubrpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/hub"
  11. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  12. "gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/accesstoken"
  13. "gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/db"
  14. "golang.org/x/crypto/bcrypt"
  15. "golang.org/x/term"
  16. "gorm.io/gorm"
  17. )
  18. func init() {
  19. userCmd := &cobra.Command{
  20. Use: "user",
  21. Short: "user command",
  22. }
  23. RootCmd.AddCommand(userCmd)
  24. createCmd := &cobra.Command{
  25. Use: "create [account] [nickName]",
  26. Short: "create a new user account",
  27. Args: cobra.ExactArgs(2),
  28. Run: func(cmd *cobra.Command, args []string) {
  29. userCreate(GetCmdCtx(cmd), args[0], args[1])
  30. },
  31. }
  32. userCmd.AddCommand(createCmd)
  33. logoutCmd := &cobra.Command{
  34. Use: "logout [account] [tokenID]",
  35. Short: "logout from a user account",
  36. Args: cobra.ExactArgs(2),
  37. Run: func(cmd *cobra.Command, args []string) {
  38. userLogout(GetCmdCtx(cmd), args[0], jcstypes.AccessTokenID(args[1]))
  39. },
  40. }
  41. userCmd.AddCommand(logoutCmd)
  42. }
  43. func userCreate(ctx *CommandContext, account string, nickName string) {
  44. _, err := ctx.repl.db.User().GetByAccount(ctx.repl.db.DefCtx(), account)
  45. if err == nil {
  46. fmt.Printf("user %s already exists\n", account)
  47. return
  48. }
  49. fmt.Printf("input account password: ")
  50. pass, err := term.ReadPassword(int(os.Stdin.Fd()))
  51. if err != nil {
  52. fmt.Println("error reading password:", err)
  53. return
  54. }
  55. passHash, err := bcrypt.GenerateFromPassword(pass, bcrypt.DefaultCost)
  56. if err != nil {
  57. fmt.Println("error hashing password:", err)
  58. return
  59. }
  60. user, err := db.DoTx01(ctx.repl.db, func(tx db.SQLContext) (jcstypes.User, error) {
  61. return ctx.repl.db.User().Create(tx, account, hex.EncodeToString(passHash), nickName)
  62. })
  63. if err != nil {
  64. fmt.Println("error creating user:", err)
  65. return
  66. }
  67. fmt.Printf("user %s created\n", user.Account)
  68. }
  69. func userLogout(ctx *CommandContext, account string, tokenID jcstypes.AccessTokenID) {
  70. acc, err := ctx.repl.db.User().GetByAccount(ctx.repl.db.DefCtx(), account)
  71. if err != nil {
  72. fmt.Printf("user %s not found\n", account)
  73. return
  74. }
  75. log := logger.WithField("UserID", acc.UserID).WithField("TokenID", tokenID)
  76. d := ctx.repl.db
  77. loaded, err := db.DoTx01(d, func(tx db.SQLContext) ([]jcstypes.LoadedAccessToken, error) {
  78. token, err := d.UserAccessToken().GetByID(tx, acc.UserID, tokenID)
  79. if err != nil {
  80. return nil, err
  81. }
  82. err = d.UserAccessToken().DeleteByID(tx, token.UserID, token.TokenID)
  83. if err != nil {
  84. return nil, err
  85. }
  86. loaded, err := d.LoadedAccessToken().GetByUserIDAndTokenID(tx, token.UserID, token.TokenID)
  87. if err != nil {
  88. return nil, err
  89. }
  90. err = d.LoadedAccessToken().DeleteAllByUserIDAndTokenID(tx, token.UserID, token.TokenID)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return loaded, nil
  95. })
  96. if err != nil {
  97. log.Warnf("delete access token: %v", err)
  98. if err == gorm.ErrRecordNotFound {
  99. return
  100. }
  101. return
  102. }
  103. ctx.repl.accessToken.NotifyTokenInvalid(accesstoken.CacheKey{
  104. UserID: acc.UserID,
  105. TokenID: tokenID,
  106. })
  107. var loadedHubIDs []jcstypes.HubID
  108. for _, l := range loaded {
  109. loadedHubIDs = append(loadedHubIDs, l.HubID)
  110. }
  111. notifyLoadedHubs(ctx, acc.UserID, tokenID, loadedHubIDs)
  112. }
  113. func notifyLoadedHubs(ctx *CommandContext, userID jcstypes.UserID, tokenID jcstypes.AccessTokenID, loadedHubIDs []jcstypes.HubID) {
  114. log := logger.WithField("UserID", userID).WithField("TokenID", tokenID)
  115. d := ctx.repl.db
  116. loadedHubs, err := d.Hub().BatchGetByID(d.DefCtx(), loadedHubIDs)
  117. if err != nil {
  118. log.Warnf("getting hubs: %v", err)
  119. return
  120. }
  121. for _, l := range loadedHubs {
  122. addr, ok := l.Address.(*jcstypes.GRPCAddressInfo)
  123. if !ok {
  124. continue
  125. }
  126. cli := stgglb.HubRPCPool.Get(addr.ExternalIP, addr.ExternalGRPCPort)
  127. // 不关心返回值
  128. cli.NotifyUserAccessTokenInvalid(context.Background(), &hubrpc.NotifyUserAccessTokenInvalid{
  129. UserID: userID,
  130. TokenID: tokenID,
  131. })
  132. cli.Release()
  133. }
  134. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。