]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/transaction_handlers.go
Ignore files with incompatible names
[rbdr/mobius] / hotline / transaction_handlers.go
index 1ef8ad3498582ff83b843d765c700eaeabfae24a..d4269af7dab773bb0c163982720913d15a4ed9ed 100644 (file)
@@ -663,6 +663,9 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error
        newAccessLvl := t.GetField(FieldUserAccess).Data
 
        account := cc.Server.Accounts[login]
+       if account == nil {
+               return append(res, cc.NewErrReply(t, "Account not found.")), nil
+       }
        account.Name = userName
        copy(account.Access[:], newAccessLvl)
 
@@ -671,7 +674,8 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error
        if t.GetField(FieldUserPassword).Data == nil {
                account.Password = hashAndSalt([]byte(""))
        }
-       if len(t.GetField(FieldUserPassword).Data) > 1 {
+
+       if !bytes.Equal([]byte{0}, t.GetField(FieldUserPassword).Data) {
                account.Password = hashAndSalt(t.GetField(FieldUserPassword).Data)
        }
 
@@ -772,36 +776,63 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er
                        return res, err
                }
 
+               // If there's only one subfield, that indicates this is a delete operation for the login in FieldData
                if len(subFields) == 1 {
-                       login := decodeString(getField(FieldData, &subFields).Data)
-                       cc.logger.Infow("DeleteUser", "login", login)
-
                        if !cc.Authorize(accessDeleteUser) {
                                res = append(res, cc.NewErrReply(t, "You are not allowed to delete accounts."))
                                return res, err
                        }
 
+                       login := decodeString(getField(FieldData, &subFields).Data)
+                       cc.logger.Infow("DeleteUser", "login", login)
+
                        if err := cc.Server.DeleteUser(login); err != nil {
                                return res, err
                        }
                        continue
                }
 
-               login := decodeString(getField(FieldUserLogin, &subFields).Data)
+               // login of the account to update
+               var accountToUpdate, loginToRename string
 
-               // check if the login dataFile; if so, we know we are updating an existing user
-               if acc, ok := cc.Server.Accounts[login]; ok {
-                       cc.logger.Infow("UpdateUser", "login", login)
+               // If FieldData is included, this is a rename operation where FieldData contains the login of the existing
+               // account and FieldUserLogin contains the new login.
+               if getField(FieldData, &subFields) != nil {
+                       loginToRename = decodeString(getField(FieldData, &subFields).Data)
+               }
+               userLogin := decodeString(getField(FieldUserLogin, &subFields).Data)
+               if loginToRename != "" {
+                       accountToUpdate = loginToRename
+               } else {
+                       accountToUpdate = userLogin
+               }
 
-                       // account dataFile, so this is an update action
+               // Check if accountToUpdate has an existing account.  If so, we know we are updating an existing user.
+               if acc, ok := cc.Server.Accounts[accountToUpdate]; ok {
+                       if loginToRename != "" {
+                               cc.logger.Infow("RenameUser", "prevLogin", accountToUpdate, "newLogin", userLogin)
+                       } else {
+                               cc.logger.Infow("UpdateUser", "login", accountToUpdate)
+                       }
+
+                       // account exists, so this is an update action
                        if !cc.Authorize(accessModifyUser) {
                                res = append(res, cc.NewErrReply(t, "You are not allowed to modify accounts."))
-                               return res, err
+                               return res, nil
                        }
 
+                       // This part is a bit tricky. There are three possibilities:
+                       // 1) The transaction is intended to update the password.
+                       //        In this case, FieldUserPassword is sent with the new password.
+                       // 2) The transaction is intended to remove the password.
+                       //    In this case, FieldUserPassword is not sent.
+                       // 3) The transaction updates the users access bits, but not the password.
+                       //    In this case, FieldUserPassword is sent with zero as the only byte.
                        if getField(FieldUserPassword, &subFields) != nil {
                                newPass := getField(FieldUserPassword, &subFields).Data
-                               acc.Password = hashAndSalt(newPass)
+                               if !bytes.Equal([]byte{0}, newPass) {
+                                       acc.Password = hashAndSalt(newPass)
+                               }
                        } else {
                                acc.Password = hashAndSalt([]byte(""))
                        }
@@ -821,13 +852,13 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er
                                return res, err
                        }
                } else {
-                       cc.logger.Infow("CreateUser", "login", login)
-
                        if !cc.Authorize(accessCreateUser) {
                                res = append(res, cc.NewErrReply(t, "You are not allowed to create new accounts."))
-                               return res, err
+                               return res, nil
                        }
 
+                       cc.logger.Infow("CreateUser", "login", userLogin)
+
                        newAccess := accessBitmap{}
                        copy(newAccess[:], getField(FieldUserAccess, &subFields).Data)
 
@@ -835,14 +866,14 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er
                        for i := 0; i < 64; i++ {
                                if newAccess.IsSet(i) {
                                        if !cc.Authorize(i) {
-                                               return append(res, cc.NewErrReply(t, "Cannot create account with more access than yourself.")), err
+                                               return append(res, cc.NewErrReply(t, "Cannot create account with more access than yourself.")), nil
                                        }
                                }
                        }
 
-                       err := cc.Server.NewUser(login, string(getField(FieldUserName, &subFields).Data), string(getField(FieldUserPassword, &subFields).Data), newAccess)
+                       err = cc.Server.NewUser(userLogin, string(getField(FieldUserName, &subFields).Data), string(getField(FieldUserPassword, &subFields).Data), newAccess)
                        if err != nil {
-                               return []Transaction{}, err
+                               return append(res, cc.NewErrReply(t, "Cannot create account because there is already an account with that login.")), nil
                        }
                }
        }
@@ -880,7 +911,8 @@ func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error
        }
 
        if err := cc.Server.NewUser(login, string(t.GetField(FieldUserName).Data), string(t.GetField(FieldUserPassword).Data), newAccess); err != nil {
-               return []Transaction{}, err
+               res = append(res, cc.NewErrReply(t, "Cannot create account because there is already an account with that login."))
+               return res, err
        }
 
        res = append(res, cc.NewReply(t))
@@ -890,10 +922,9 @@ func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error
 func HandleDeleteUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        if !cc.Authorize(accessDeleteUser) {
                res = append(res, cc.NewErrReply(t, "You are not allowed to delete accounts."))
-               return res, err
+               return res, nil
        }
 
-       // TODO: Handle case where account doesn't exist; e.g. delete race condition
        login := decodeString(t.GetField(FieldUserLogin).Data)
 
        if err := cc.Server.DeleteUser(login); err != nil {