diff options
| author | Jeff Halter <868228+jhalter@users.noreply.github.com> | 2022-06-26 15:40:18 -0700 |
|---|---|---|
| committer | Jeff Halter <868228+jhalter@users.noreply.github.com> | 2022-06-26 15:40:18 -0700 |
| commit | 187d6dc500784760654b740a278fef59072ca5a8 (patch) | |
| tree | 856f011e322446bf16c0f77e676e82901d0dd93b | |
| parent | f168da153f3984af6d532b979219310242f0b8d1 (diff) | |
Refactor user access bitmap handling
| -rw-r--r-- | hotline/access.go | 13 | ||||
| -rw-r--r-- | hotline/access_test.go | 39 | ||||
| -rw-r--r-- | hotline/account.go | 10 | ||||
| -rw-r--r-- | hotline/client_conn.go | 4 | ||||
| -rw-r--r-- | hotline/server.go | 10 | ||||
| -rw-r--r-- | hotline/transaction_handlers.go | 112 | ||||
| -rw-r--r-- | hotline/transaction_handlers_test.go | 282 |
7 files changed, 225 insertions, 245 deletions
diff --git a/hotline/access.go b/hotline/access.go index ae72780..83a4e16 100644 --- a/hotline/access.go +++ b/hotline/access.go @@ -1,10 +1,5 @@ package hotline -import ( - "encoding/binary" - "math/big" -) - const ( accessDeleteFile = 0 // File System Maintenance: Can Delete Files accessUploadFile = 1 // File System Maintenance: Can Upload Files @@ -52,10 +47,6 @@ func (bits *accessBitmap) Set(i int) { bits[i/8] |= 1 << uint(7-i%8) } -// authorize checks if 64 bit access slice contain has accessBit set -// TODO: refactor to use accessBitmap type -func authorize(access *[]byte, accessBit int) bool { - bits := big.NewInt(int64(binary.BigEndian.Uint64(*access))) - - return bits.Bit(63-accessBit) == 1 +func (bits *accessBitmap) IsSet(i int) bool { + return bits[i/8]&(1<<uint(7-i%8)) != 0 } diff --git a/hotline/access_test.go b/hotline/access_test.go new file mode 100644 index 0000000..b262407 --- /dev/null +++ b/hotline/access_test.go @@ -0,0 +1,39 @@ +package hotline + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_accessBitmap_IsSet(t *testing.T) { + type args struct { + i int + } + tests := []struct { + name string + bits accessBitmap + args args + want bool + }{ + { + name: "returns true when bit is set", + bits: func() (access accessBitmap) { + access.Set(22) + return access + }(), + args: args{i: 22}, + want: true, + }, + { + name: "returns false when bit is unset", + bits: accessBitmap{}, + args: args{i: 22}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, tt.bits.IsSet(tt.args.i), "IsSet(%v)", tt.args.i) + }) + } +} diff --git a/hotline/account.go b/hotline/account.go index 2c400ac..a680861 100644 --- a/hotline/account.go +++ b/hotline/account.go @@ -8,10 +8,10 @@ import ( const GuestAccount = "guest" // default account used when no login is provided for a connection type Account struct { - Login string `yaml:"Login"` - Name string `yaml:"Name"` - Password string `yaml:"Password"` - Access *[]byte `yaml:"Access"` // 8 byte bitmap + Login string `yaml:"Login"` + Name string `yaml:"Name"` + Password string `yaml:"Password"` + Access accessBitmap `yaml:"Access"` } // Read implements io.Reader interface for Account @@ -19,7 +19,7 @@ func (a *Account) Read(p []byte) (n int, err error) { fields := []Field{ NewField(fieldUserName, []byte(a.Name)), NewField(fieldUserLogin, negateString([]byte(a.Login))), - NewField(fieldUserAccess, *a.Access), + NewField(fieldUserAccess, a.Access[:]), } if bcrypt.CompareHashAndPassword([]byte(a.Password), []byte("")) != nil { diff --git a/hotline/client_conn.go b/hotline/client_conn.go index 076919f..7f78704 100644 --- a/hotline/client_conn.go +++ b/hotline/client_conn.go @@ -135,9 +135,7 @@ func (cc *ClientConn) uint16ID() uint16 { // Authorize checks if the user account has the specified permission func (cc *ClientConn) Authorize(access int) bool { - i := big.NewInt(int64(binary.BigEndian.Uint64(*cc.Account.Access))) - - return i.Bit(63-access) == 1 + return cc.Account.Access.IsSet(access) } // Disconnect notifies other clients that a client has disconnected diff --git a/hotline/server.go b/hotline/server.go index 0d66e08..3a43c95 100644 --- a/hotline/server.go +++ b/hotline/server.go @@ -392,7 +392,7 @@ func (s *Server) NewClientConn(conn io.ReadWriteCloser, remoteAddr string) *Clie } // NewUser creates a new user account entry in the server map and config file -func (s *Server) NewUser(login, name, password string, access []byte) error { +func (s *Server) NewUser(login, name, password string, access accessBitmap) error { s.mux.Lock() defer s.mux.Unlock() @@ -400,7 +400,7 @@ func (s *Server) NewUser(login, name, password string, access []byte) error { Login: login, Name: name, Password: hashAndSalt([]byte(password)), - Access: &access, + Access: access, } out, err := yaml.Marshal(&account) if err != nil { @@ -411,7 +411,7 @@ func (s *Server) NewUser(login, name, password string, access []byte) error { return s.FS.WriteFile(filepath.Join(s.ConfigDir, "Users", login+".yaml"), out, 0666) } -func (s *Server) UpdateUser(login, newLogin, name, password string, access []byte) error { +func (s *Server) UpdateUser(login, newLogin, name, password string, access accessBitmap) error { s.mux.Lock() defer s.mux.Unlock() @@ -426,7 +426,7 @@ func (s *Server) UpdateUser(login, newLogin, name, password string, access []byt } account := s.Accounts[newLogin] - account.Access = &access + account.Access = access account.Name = name account.Password = password @@ -651,7 +651,7 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser ) // Send user access privs so client UI knows how to behave - c.Server.outbox <- *NewTransaction(tranUserAccess, c.ID, NewField(fieldUserAccess, *c.Account.Access)) + c.Server.outbox <- *NewTransaction(tranUserAccess, c.ID, NewField(fieldUserAccess, c.Account.Access[:])) // Accounts with accessNoAgreement do not receive the server agreement on login. The behavior is different between // client versions. For 1.2.3 client, we do not send tranShowAgreement. For other client versions, we send diff --git a/hotline/transaction_handlers.go b/hotline/transaction_handlers.go index 85879a4..23ac68a 100644 --- a/hotline/transaction_handlers.go +++ b/hotline/transaction_handlers.go @@ -238,7 +238,7 @@ var TransactionHandlers = map[uint16]TransactionType{ } func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessSendChat) { + if !cc.Authorize(accessSendChat) { res = append(res, cc.NewErrReply(t, "You are not allowed to participate in chat.")) return res, err } @@ -276,7 +276,7 @@ func HandleChatSend(cc *ClientConn, t *Transaction) (res []Transaction, err erro for _, c := range sortedClients(cc.Server.Clients) { // Filter out clients that do not have the read chat permission - if authorize(c.Account.Access, accessReadChat) { + if c.Authorize(accessReadChat) { res = append(res, *NewTransaction(tranChatMsg, c.ID, NewField(fieldData, []byte(formattedMsg)))) } } @@ -404,12 +404,12 @@ func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e if t.GetField(fieldFileComment).Data != nil { switch mode := fi.Mode(); { case mode.IsDir(): - if !authorize(cc.Account.Access, accessSetFolderComment) { + if !cc.Authorize(accessSetFolderComment) { res = append(res, cc.NewErrReply(t, "You are not allowed to set comments for folders.")) return res, err } case mode.IsRegular(): - if !authorize(cc.Account.Access, accessSetFileComment) { + if !cc.Authorize(accessSetFileComment) { res = append(res, cc.NewErrReply(t, "You are not allowed to set comments for files.")) return res, err } @@ -438,7 +438,7 @@ func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e if fileNewName != nil { switch mode := fi.Mode(); { case mode.IsDir(): - if !authorize(cc.Account.Access, accessRenameFolder) { + if !cc.Authorize(accessRenameFolder) { res = append(res, cc.NewErrReply(t, "You are not allowed to rename folders.")) return res, err } @@ -448,7 +448,7 @@ func HandleSetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e return res, err } case mode.IsRegular(): - if !authorize(cc.Account.Access, accessRenameFile) { + if !cc.Authorize(accessRenameFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to rename files.")) return res, err } @@ -499,12 +499,12 @@ func HandleDeleteFile(cc *ClientConn, t *Transaction) (res []Transaction, err er switch mode := fi.Mode(); { case mode.IsDir(): - if !authorize(cc.Account.Access, accessDeleteFolder) { + if !cc.Authorize(accessDeleteFolder) { res = append(res, cc.NewErrReply(t, "You are not allowed to delete folders.")) return res, err } case mode.IsRegular(): - if !authorize(cc.Account.Access, accessDeleteFile) { + if !cc.Authorize(accessDeleteFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to delete files.")) return res, err } @@ -549,12 +549,12 @@ func HandleMoveFile(cc *ClientConn, t *Transaction) (res []Transaction, err erro } switch mode := fi.Mode(); { case mode.IsDir(): - if !authorize(cc.Account.Access, accessMoveFolder) { + if !cc.Authorize(accessMoveFolder) { res = append(res, cc.NewErrReply(t, "You are not allowed to move folders.")) return res, err } case mode.IsRegular(): - if !authorize(cc.Account.Access, accessMoveFile) { + if !cc.Authorize(accessMoveFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to move files.")) return res, err } @@ -569,7 +569,7 @@ func HandleMoveFile(cc *ClientConn, t *Transaction) (res []Transaction, err erro } func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessCreateFolder) { + if !cc.Authorize(accessCreateFolder) { res = append(res, cc.NewErrReply(t, "You are not allowed to create folders.")) return res, err } @@ -612,7 +612,7 @@ func HandleNewFolder(cc *ClientConn, t *Transaction) (res []Transaction, err err } func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessModifyUser) { + if !cc.Authorize(accessModifyUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to modify accounts.")) return res, err } @@ -623,8 +623,8 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error newAccessLvl := t.GetField(fieldUserAccess).Data account := cc.Server.Accounts[login] - account.Access = &newAccessLvl account.Name = userName + copy(account.Access[:], newAccessLvl) // If the password field is cleared in the Hotline edit user UI, the SetUser transaction does // not include fieldUserPassword @@ -651,7 +651,7 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error res = append(res, *newT) flagBitmap := big.NewInt(int64(binary.BigEndian.Uint16(c.Flags))) - if authorize(c.Account.Access, accessDisconUser) { + if cc.Authorize(accessDisconUser) { flagBitmap.SetBit(flagBitmap, userFlagAdmin, 1) } else { flagBitmap.SetBit(flagBitmap, userFlagAdmin, 0) @@ -675,7 +675,7 @@ func HandleSetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error } func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessOpenUser) { + if !cc.Authorize(accessOpenUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to view accounts.")) return res, err } @@ -690,13 +690,13 @@ func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error NewField(fieldUserName, []byte(account.Name)), NewField(fieldUserLogin, negateString(t.GetField(fieldUserLogin).Data)), NewField(fieldUserPassword, []byte(account.Password)), - NewField(fieldUserAccess, *account.Access), + NewField(fieldUserAccess, account.Access[:]), )) return res, err } func HandleListUsers(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessOpenUser) { + if !cc.Authorize(accessOpenUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to view accounts.")) return res, err } @@ -736,7 +736,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er login := DecodeUserString(getField(fieldData, &subFields).Data) cc.logger.Infow("DeleteUser", "login", login) - if !authorize(cc.Account.Access, accessDeleteUser) { + if !cc.Authorize(accessDeleteUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to delete accounts.")) return res, err } @@ -754,7 +754,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er cc.logger.Infow("UpdateUser", "login", login) // account dataFile, so this is an update action - if !authorize(cc.Account.Access, accessModifyUser) { + if !cc.Authorize(accessModifyUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to modify accounts.")) return res, err } @@ -767,7 +767,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er } if getField(fieldUserAccess, &subFields) != nil { - acc.Access = &getField(fieldUserAccess, &subFields).Data + copy(acc.Access[:], getField(fieldUserAccess, &subFields).Data) } err = cc.Server.UpdateUser( @@ -775,7 +775,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er DecodeUserString(getField(fieldUserLogin, &subFields).Data), string(getField(fieldUserName, &subFields).Data), acc.Password, - *acc.Access, + acc.Access, ) if err != nil { return res, err @@ -783,17 +783,15 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er } else { cc.logger.Infow("CreateUser", "login", login) - if !authorize(cc.Account.Access, accessCreateUser) { + if !cc.Authorize(accessCreateUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to create new accounts.")) return res, err } - err := cc.Server.NewUser( - login, - string(getField(fieldUserName, &subFields).Data), - string(getField(fieldUserPassword, &subFields).Data), - getField(fieldUserAccess, &subFields).Data, - ) + newAccess := accessBitmap{} + copy(newAccess[:], getField(fieldUserAccess, &subFields).Data[:]) + + err := cc.Server.NewUser(login, string(getField(fieldUserName, &subFields).Data), string(getField(fieldUserPassword, &subFields).Data), newAccess) if err != nil { return []Transaction{}, err } @@ -806,7 +804,7 @@ func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err er // HandleNewUser creates a new user account func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessCreateUser) { + if !cc.Authorize(accessCreateUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to create new accounts.")) return res, err } @@ -819,12 +817,10 @@ func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error return res, err } - if err := cc.Server.NewUser( - login, - string(t.GetField(fieldUserName).Data), - string(t.GetField(fieldUserPassword).Data), - t.GetField(fieldUserAccess).Data, - ); err != nil { + newAccess := accessBitmap{} + copy(newAccess[:], t.GetField(fieldUserAccess).Data[:]) + + if err := cc.Server.NewUser(login, string(t.GetField(fieldUserName).Data), string(t.GetField(fieldUserPassword).Data), newAccess); err != nil { return []Transaction{}, err } @@ -833,7 +829,7 @@ func HandleNewUser(cc *ClientConn, t *Transaction) (res []Transaction, err error } func HandleDeleteUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessDeleteUser) { + if !cc.Authorize(accessDeleteUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to delete accounts.")) return res, err } @@ -851,7 +847,7 @@ func HandleDeleteUser(cc *ClientConn, t *Transaction) (res []Transaction, err er // HandleUserBroadcast sends an Administrator Message to all connected clients of the server func HandleUserBroadcast(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessBroadcast) { + if !cc.Authorize(accessBroadcast) { res = append(res, cc.NewErrReply(t, "You are not allowed to send broadcast messages.")) return res, err } @@ -886,7 +882,7 @@ func byteToInt(bytes []byte) (int, error) { // 102 User name // 101 Data User info text string func HandleGetClientInfoText(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessGetClientInfo) { + if !cc.Authorize(accessGetClientInfo) { res = append(res, cc.NewErrReply(t, "You are not allowed to get client info.")) return res, err } @@ -984,7 +980,7 @@ __________________________________________________________` // Fields used in this request: // 101 Data func HandleTranOldPostNews(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsPostArt) { + if !cc.Authorize(accessNewsPostArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to post news.")) return res, err } @@ -1024,14 +1020,14 @@ func HandleTranOldPostNews(cc *ClientConn, t *Transaction) (res []Transaction, e } func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessDisconUser) { + if !cc.Authorize(accessDisconUser) { res = append(res, cc.NewErrReply(t, "You are not allowed to disconnect users.")) return res, err } clientConn := cc.Server.Clients[binary.BigEndian.Uint16(t.GetField(fieldUserID).Data)] - if authorize(clientConn.Account.Access, accessCannotBeDiscon) { + if clientConn.Authorize(accessCannotBeDiscon) { res = append(res, cc.NewErrReply(t, clientConn.Account.Login+" is not allowed to be disconnected.")) return res, err } @@ -1084,7 +1080,7 @@ func HandleDisconnectUser(cc *ClientConn, t *Transaction) (res []Transaction, er // Fields used in the request: // 325 News path (Optional) func HandleGetNewsCatNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsReadArt) { + if !cc.Authorize(accessNewsReadArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to read news.")) return res, err } @@ -1116,7 +1112,7 @@ func HandleGetNewsCatNameList(cc *ClientConn, t *Transaction) (res []Transaction } func HandleNewNewsCat(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsCreateCat) { + if !cc.Authorize(accessNewsCreateCat) { res = append(res, cc.NewErrReply(t, "You are not allowed to create news categories.")) return res, err } @@ -1143,7 +1139,7 @@ func HandleNewNewsCat(cc *ClientConn, t *Transaction) (res []Transaction, err er // 322 News category name // 325 News path func HandleNewNewsFldr(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsCreateFldr) { + if !cc.Authorize(accessNewsCreateFldr) { res = append(res, cc.NewErrReply(t, "You are not allowed to create news folders.")) return res, err } @@ -1173,7 +1169,7 @@ func HandleNewNewsFldr(cc *ClientConn, t *Transaction) (res []Transaction, err e // Reply fields: // 321 News article list data Optional func HandleGetNewsArtNameList(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsReadArt) { + if !cc.Authorize(accessNewsReadArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to read news.")) return res, err } @@ -1194,7 +1190,7 @@ func HandleGetNewsArtNameList(cc *ClientConn, t *Transaction) (res []Transaction } func HandleGetNewsArtData(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsReadArt) { + if !cc.Authorize(accessNewsReadArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to read news.")) return res, err } @@ -1281,7 +1277,7 @@ func HandleDelNewsItem(cc *ClientConn, t *Transaction) (res []Transaction, err e } func HandleDelNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsDeleteArt) { + if !cc.Authorize(accessNewsDeleteArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to delete news articles.")) return res, err } @@ -1318,7 +1314,7 @@ func HandleDelNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err er // 327 News article data flavor Currently “text/plain” // 333 News article data func HandlePostNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsPostArt) { + if !cc.Authorize(accessNewsPostArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to post news articles.")) return res, err } @@ -1381,7 +1377,7 @@ func HandlePostNewsArt(cc *ClientConn, t *Transaction) (res []Transaction, err e // HandleGetMsgs returns the flat news data func HandleGetMsgs(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessNewsReadArt) { + if !cc.Authorize(accessNewsReadArt) { res = append(res, cc.NewErrReply(t, "You are not allowed to read news.")) return res, err } @@ -1392,7 +1388,7 @@ func HandleGetMsgs(cc *ClientConn, t *Transaction) (res []Transaction, err error } func HandleDownloadFile(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessDownloadFile) { + if !cc.Authorize(accessDownloadFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to download files.")) return res, err } @@ -1454,7 +1450,7 @@ func HandleDownloadFile(cc *ClientConn, t *Transaction) (res []Transaction, err // Download all files from the specified folder and sub-folders func HandleDownloadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessDownloadFile) { + if !cc.Authorize(accessDownloadFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to download folders.")) return res, err } @@ -1506,7 +1502,7 @@ func HandleUploadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err } // Handle special cases for Upload and Drop Box folders - if !authorize(cc.Account.Access, accessUploadAnywhere) { + if !cc.Authorize(accessUploadAnywhere) { if !fp.IsUploadDir() && !fp.IsDropbox() { res = append(res, cc.NewErrReply(t, fmt.Sprintf("Cannot accept upload of the folder \"%v\" because you are only allowed to upload to the \"Uploads\" folder.", string(t.GetField(fieldFileName).Data)))) return res, err @@ -1533,7 +1529,7 @@ func HandleUploadFolder(cc *ClientConn, t *Transaction) (res []Transaction, err // Used only to resume download, currently has value 2" // 108 File transfer size "Optional used if download is not resumed" func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessUploadFile) { + if !cc.Authorize(accessUploadFile) { res = append(res, cc.NewErrReply(t, "You are not allowed to upload files.")) return res, err } @@ -1551,7 +1547,7 @@ func HandleUploadFile(cc *ClientConn, t *Transaction) (res []Transaction, err er } // Handle special cases for Upload and Drop Box folders - if !authorize(cc.Account.Access, accessUploadAnywhere) { + if !cc.Authorize(accessUploadAnywhere) { if !fp.IsUploadDir() && !fp.IsDropbox() { res = append(res, cc.NewErrReply(t, fmt.Sprintf("Cannot accept upload of the file \"%v\" because you are only allowed to upload to the \"Uploads\" folder.", string(fileName)))) return res, err @@ -1668,7 +1664,7 @@ func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, e } // Handle special case for drop box folders - if fp.IsDropbox() && !authorize(cc.Account.Access, accessViewDropBoxes) { + if fp.IsDropbox() && !cc.Authorize(accessViewDropBoxes) { res = append(res, cc.NewErrReply(t, "You are not allowed to view drop boxes.")) return res, err } @@ -1697,7 +1693,7 @@ func HandleGetFileNameList(cc *ClientConn, t *Transaction) (res []Transaction, e // HandleInviteNewChat invites users to new private chat func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessOpenChat) { + if !cc.Authorize(accessOpenChat) { res = append(res, cc.NewErrReply(t, "You are not allowed to request private chat.")) return res, err } @@ -1730,7 +1726,7 @@ func HandleInviteNewChat(cc *ClientConn, t *Transaction) (res []Transaction, err } func HandleInviteToChat(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessOpenChat) { + if !cc.Authorize(accessOpenChat) { res = append(res, cc.NewErrReply(t, "You are not allowed to request private chat.")) return res, err } @@ -1893,7 +1889,7 @@ func HandleSetChatSubject(cc *ClientConn, t *Transaction) (res []Transaction, er // Fields used in the reply: // None func HandleMakeAlias(cc *ClientConn, t *Transaction) (res []Transaction, err error) { - if !authorize(cc.Account.Access, accessMakeAlias) { + if !cc.Authorize(accessMakeAlias) { res = append(res, cc.NewErrReply(t, "You are not allowed to make aliases.")) return res, err } diff --git a/hotline/transaction_handlers_test.go b/hotline/transaction_handlers_test.go index c504bbe..0d6b1dc 100644 --- a/hotline/transaction_handlers_test.go +++ b/hotline/transaction_handlers_test.go @@ -36,13 +36,13 @@ func TestHandleSetChatSubject(t *testing.T) { ClientConn: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -52,13 +52,13 @@ func TestHandleSetChatSubject(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -144,13 +144,13 @@ func TestHandleLeaveChat(t *testing.T) { ClientConn: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -160,13 +160,13 @@ func TestHandleLeaveChat(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -306,11 +306,10 @@ func TestHandleChatSend(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendChat) - access := bits[:] - return &access + return bits }(), }, UserName: []byte{0x00, 0x01}, @@ -318,13 +317,13 @@ func TestHandleChatSend(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -368,10 +367,9 @@ func TestHandleChatSend(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -402,11 +400,10 @@ func TestHandleChatSend(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendChat) - access := bits[:] - return &access + return bits }(), }, UserName: []byte("Testy McTest"), @@ -414,13 +411,13 @@ func TestHandleChatSend(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 2}, }, @@ -465,11 +462,10 @@ func TestHandleChatSend(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendChat) - access := bits[:] - return &access + return bits }(), }, UserName: []byte{0x00, 0x01}, @@ -477,13 +473,16 @@ func TestHandleChatSend(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, - }, + Access: func() accessBitmap { + var bits accessBitmap + bits.Set(accessReadChat) + return bits + }()}, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0}, + Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0}, }, ID: &[]byte{0, 2}, }, @@ -516,11 +515,10 @@ func TestHandleChatSend(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendChat) - access := bits[:] - return &access + return bits }(), }, UserName: []byte{0x00, 0x01}, @@ -540,19 +538,19 @@ func TestHandleChatSend(t *testing.T) { Clients: map[uint16]*ClientConn{ uint16(1): { Account: &Account{ - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, ID: &[]byte{0, 1}, }, uint16(2): { Account: &Account{ - Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0}, + Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0}, }, ID: &[]byte{0, 2}, }, uint16(3): { Account: &Account{ - Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0}, + Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0}, }, ID: &[]byte{0, 3}, }, @@ -702,10 +700,9 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -733,11 +730,10 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCreateFolder) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -781,11 +777,10 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCreateFolder) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -823,11 +818,10 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCreateFolder) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -859,11 +853,10 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCreateFolder) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -900,11 +893,10 @@ func TestHandleNewFolder(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCreateFolder) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -987,12 +979,11 @@ func TestHandleUploadFile(t *testing.T) { FileUpload: {}, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessUploadFile) bits.Set(accessUploadAnywhere) - access := bits[:] - return &access + return bits }(), }, }, @@ -1026,10 +1017,9 @@ func TestHandleUploadFile(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -1091,11 +1081,10 @@ func TestHandleMakeAlias(t *testing.T) { cc: &ClientConn{ logger: NewTestLogger(), Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessMakeAlias) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1143,11 +1132,10 @@ func TestHandleMakeAlias(t *testing.T) { cc: &ClientConn{ logger: NewTestLogger(), Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessMakeAlias) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1197,10 +1185,9 @@ func TestHandleMakeAlias(t *testing.T) { cc: &ClientConn{ logger: NewTestLogger(), Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1273,11 +1260,10 @@ func TestHandleGetUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessOpenUser) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1286,7 +1272,7 @@ func TestHandleGetUser(t *testing.T) { Login: "guest", Name: "Guest", Password: "password", - Access: &[]byte{1}, + Access: accessBitmap{}, }, }, }, @@ -1307,7 +1293,7 @@ func TestHandleGetUser(t *testing.T) { NewField(fieldUserName, []byte("Guest")), NewField(fieldUserLogin, negateString([]byte("guest"))), NewField(fieldUserPassword, []byte("password")), - NewField(fieldUserAccess, []byte{1}), + NewField(fieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}), }, }, }, @@ -1318,10 +1304,9 @@ func TestHandleGetUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1352,11 +1337,10 @@ func TestHandleGetUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessOpenUser) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1411,11 +1395,10 @@ func TestHandleDeleteUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDeleteUser) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1424,7 +1407,7 @@ func TestHandleDeleteUser(t *testing.T) { Login: "testuser", Name: "Testy McTest", Password: "password", - Access: &[]byte{1}, + Access: accessBitmap{}, }, }, FS: func() *MockFileStore { @@ -1456,10 +1439,9 @@ func TestHandleDeleteUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1514,11 +1496,10 @@ func TestHandleGetMsgs(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessNewsReadArt) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1548,10 +1529,9 @@ func TestHandleGetMsgs(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1605,10 +1585,9 @@ func TestHandleNewUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1662,10 +1641,9 @@ func TestHandleListUsers(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1695,11 +1673,10 @@ func TestHandleListUsers(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessOpenUser) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1708,7 +1685,7 @@ func TestHandleListUsers(t *testing.T) { Name: "guest", Login: "guest", Password: "zz", - Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255}, + Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255}, }, }, }, @@ -1765,10 +1742,9 @@ func TestHandleDownloadFile(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{}, @@ -1797,11 +1773,10 @@ func TestHandleDownloadFile(t *testing.T) { FileDownload: {}, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDownloadFile) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1844,11 +1819,10 @@ func TestHandleDownloadFile(t *testing.T) { transfers: map[int]map[[4]byte]*FileTransfer{ FileDownload: {}, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDownloadFile) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -1962,10 +1936,9 @@ func TestHandleUpdateUser(t *testing.T) { Logger: NewTestLogger(), }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2019,10 +1992,9 @@ func TestHandleUpdateUser(t *testing.T) { }, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2075,10 +2047,9 @@ func TestHandleUpdateUser(t *testing.T) { }, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2136,10 +2107,9 @@ func TestHandleDelNewsArt(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2190,10 +2160,9 @@ func TestHandleDisconnectUser(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2225,22 +2194,20 @@ func TestHandleDisconnectUser(t *testing.T) { uint16(1): { Account: &Account{ Login: "unnamed", - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessCannotBeDiscon) - access := bits[:] - return &access + return bits }(), }, }, }, }, Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDisconUser) - access := bits[:] - return &access + return bits }(), }, }, @@ -2292,10 +2259,9 @@ func TestHandleSendInstantMsg(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, }, @@ -2323,11 +2289,10 @@ func TestHandleSendInstantMsg(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendPrivMsg) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -2373,11 +2338,10 @@ func TestHandleSendInstantMsg(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessSendPrivMsg) - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, @@ -2457,10 +2421,9 @@ func TestHandleDeleteFile(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -2517,11 +2480,10 @@ func TestHandleDeleteFile(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDeleteFile) - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -2607,10 +2569,9 @@ func TestHandleGetFileNameList(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -2728,10 +2689,9 @@ func TestHandleGetClientInfoText(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, Server: &Server{ @@ -2764,11 +2724,10 @@ func TestHandleGetClientInfoText(t *testing.T) { UserName: []byte("Testy McTest"), RemoteAddr: "1.2.3.4:12345", Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessGetClientInfo) - access := bits[:] - return &access + return bits }(), Name: "test", Login: "test", @@ -2780,11 +2739,10 @@ func TestHandleGetClientInfoText(t *testing.T) { UserName: []byte("Testy McTest"), RemoteAddr: "1.2.3.4:12345", Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessGetClientInfo) - access := bits[:] - return &access + return bits }(), Name: "test", Login: "test", @@ -2874,12 +2832,11 @@ func TestHandleTranAgreed(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap bits.Set(accessDisconUser) bits.Set(accessAnyName) - access := bits[:] - return &access + return bits }()}, Icon: []byte{0, 1}, Flags: []byte{0, 1}, @@ -2951,10 +2908,9 @@ func TestHandleSetClientUserInfo(t *testing.T) { args: args{ cc: &ClientConn{ Account: &Account{ - Access: func() *[]byte { + Access: func() accessBitmap { var bits accessBitmap - access := bits[:] - return &access + return bits }(), }, ID: &[]byte{0, 1}, |