]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/access.go
Improve human readability of account config files
[rbdr/mobius] / hotline / access.go
index 2d78464177e22e29c76889a873e04aedd8c51d97..42e96c4bac5407027818b84cd8b1a06f9cb34edc 100644 (file)
@@ -1,5 +1,7 @@
 package hotline
 
+import "fmt"
+
 const (
        AccessDeleteFile       = 0  // File System Maintenance: Can Delete Files
        AccessUploadFile       = 1  // File System Maintenance: Can Upload Files
@@ -38,6 +40,8 @@ const (
        AccessNewsDeleteCat    = 35 // News: Can Delete Categories
        AccessNewsCreateFldr   = 36 // News: Can Create News Bundles
        AccessNewsDeleteFldr   = 37 // News: Can Delete News Bundles
+       AccessUploadFolder     = 38 // File System Maintenance: Can Upload Folders
+       AccessDownloadFolder   = 39 // File System Maintenance: Can Download Folders
        AccessSendPrivMsg      = 40 // Messaging: Can Send Messages (Note: 1.9 protocol doc incorrectly says this is bit 19)
 )
 
@@ -50,3 +54,235 @@ func (bits *AccessBitmap) Set(i int) {
 func (bits *AccessBitmap) IsSet(i int) bool {
        return bits[i/8]&(1<<uint(7-i%8)) != 0
 }
+
+func (bits *AccessBitmap) UnmarshalYAML(unmarshal func(interface{}) error) error {
+       var flags interface{}
+       err := unmarshal(&flags)
+       if err != nil {
+               return fmt.Errorf("unmarshal access bitmap: %w", err)
+       }
+
+       switch v := flags.(type) {
+       case []interface{}:
+               // Mobius versions < v0.17.0 store the user access bitmap as an array of int values like:
+               // [96, 112, 12, 32, 3, 128, 0, 0]
+               // This case supports reading of user config files using this format.
+               for i, v := range flags.([]interface{}) {
+                       bits[i] = byte(v.(int))
+               }
+       case map[string]interface{}:
+               // Mobius versions >= v0.17.0 store the user access bitmap as map[string]bool to provide a human-readable view of
+               // the account permissions.
+               if f, ok := v["DeleteFile"].(bool); ok && f {
+                       bits.Set(AccessDeleteFile)
+               }
+               if f, ok := v["UploadFile"].(bool); ok && f {
+                       bits.Set(AccessUploadFile)
+               }
+               if f, ok := v["DownloadFile"].(bool); ok && f {
+                       bits.Set(AccessDownloadFile)
+               }
+               if f, ok := v["UploadFolder"].(bool); ok && f {
+                       bits.Set(AccessUploadFolder)
+               }
+               if f, ok := v["DownloadFolder"].(bool); ok && f {
+                       bits.Set(AccessDownloadFolder)
+               }
+               if f, ok := v["RenameFile"].(bool); ok && f {
+                       bits.Set(AccessRenameFile)
+               }
+               if f, ok := v["MoveFile"].(bool); ok && f {
+                       bits.Set(AccessMoveFile)
+               }
+               if f, ok := v["CreateFolder"].(bool); ok && f {
+                       bits.Set(AccessCreateFolder)
+               }
+               if f, ok := v["DeleteFolder"].(bool); ok && f {
+                       bits.Set(AccessDeleteFolder)
+               }
+               if f, ok := v["RenameFolder"].(bool); ok && f {
+                       bits.Set(AccessRenameFolder)
+               }
+               if f, ok := v["MoveFolder"].(bool); ok && f {
+                       bits.Set(AccessMoveFolder)
+               }
+               if f, ok := v["ReadChat"].(bool); ok && f {
+                       bits.Set(AccessReadChat)
+               }
+               if f, ok := v["SendChat"].(bool); ok && f {
+                       bits.Set(AccessSendChat)
+               }
+               if f, ok := v["OpenChat"].(bool); ok && f {
+                       bits.Set(AccessOpenChat)
+               }
+               if f, ok := v["CloseChat"].(bool); ok && f {
+                       bits.Set(AccessCloseChat)
+               }
+               if f, ok := v["ShowInList"].(bool); ok && f {
+                       bits.Set(AccessShowInList)
+               }
+               if f, ok := v["CreateUser"].(bool); ok && f {
+                       bits.Set(AccessCreateUser)
+               }
+               if f, ok := v["DeleteUser"].(bool); ok && f {
+                       bits.Set(AccessDeleteUser)
+               }
+               if f, ok := v["OpenUser"].(bool); ok && f {
+                       bits.Set(AccessOpenUser)
+               }
+               if f, ok := v["ModifyUser"].(bool); ok && f {
+                       bits.Set(AccessModifyUser)
+               }
+               if f, ok := v["ChangeOwnPass"].(bool); ok && f {
+                       bits.Set(AccessChangeOwnPass)
+               }
+               if f, ok := v["NewsReadArt"].(bool); ok && f {
+                       bits.Set(AccessNewsReadArt)
+               }
+               if f, ok := v["NewsPostArt"].(bool); ok && f {
+                       bits.Set(AccessNewsPostArt)
+               }
+               if f, ok := v["DisconnectUser"].(bool); ok && f {
+                       bits.Set(AccessDisconUser)
+               }
+               if f, ok := v["CannotBeDisconnected"].(bool); ok && f {
+                       bits.Set(AccessCannotBeDiscon)
+               }
+               if f, ok := v["GetClientInfo"].(bool); ok && f {
+                       bits.Set(AccessGetClientInfo)
+               }
+               if f, ok := v["UploadAnywhere"].(bool); ok && f {
+                       bits.Set(AccessUploadAnywhere)
+               }
+               if f, ok := v["AnyName"].(bool); ok && f {
+                       bits.Set(AccessAnyName)
+               }
+               if f, ok := v["NoAgreement"].(bool); ok && f {
+                       bits.Set(AccessNoAgreement)
+               }
+               if f, ok := v["SetFileComment"].(bool); ok && f {
+                       bits.Set(AccessSetFileComment)
+               }
+               if f, ok := v["SetFolderComment"].(bool); ok && f {
+                       bits.Set(AccessSetFolderComment)
+               }
+               if f, ok := v["ViewDropBoxes"].(bool); ok && f {
+                       bits.Set(AccessViewDropBoxes)
+               }
+               if f, ok := v["MakeAlias"].(bool); ok && f {
+                       bits.Set(AccessMakeAlias)
+               }
+               if f, ok := v["Broadcast"].(bool); ok && f {
+                       bits.Set(AccessBroadcast)
+               }
+               if f, ok := v["NewsDeleteArt"].(bool); ok && f {
+                       bits.Set(AccessNewsDeleteArt)
+               }
+               if f, ok := v["NewsCreateCat"].(bool); ok && f {
+                       bits.Set(AccessNewsCreateCat)
+               }
+               if f, ok := v["NewsDeleteCat"].(bool); ok && f {
+                       bits.Set(AccessNewsDeleteCat)
+               }
+               if f, ok := v["NewsCreateFldr"].(bool); ok && f {
+                       bits.Set(AccessNewsCreateFldr)
+               }
+               if f, ok := v["NewsDeleteFldr"].(bool); ok && f {
+                       bits.Set(AccessNewsDeleteFldr)
+               }
+               if f, ok := v["SendPrivMsg"].(bool); ok && f {
+                       bits.Set(AccessSendPrivMsg)
+               }
+       }
+
+       return nil
+}
+
+// accessFlags is used to render the access bitmap to human-readable boolean flags in the account yaml.
+type accessFlags struct {
+       DownloadFile         bool `yaml:"DownloadFile"`
+       DownloadFolder       bool `yaml:"DownloadFolder"`
+       UploadFile           bool `yaml:"UploadFile"`
+       UploadFolder         bool `yaml:"UploadFolder"`
+       DeleteFile           bool `yaml:"DeleteFile"`
+       RenameFile           bool `yaml:"RenameFile"`
+       MoveFile             bool `yaml:"MoveFile"`
+       CreateFolder         bool `yaml:"CreateFolder"`
+       DeleteFolder         bool `yaml:"DeleteFolder"`
+       RenameFolder         bool `yaml:"RenameFolder"`
+       MoveFolder           bool `yaml:"MoveFolder"`
+       ReadChat             bool `yaml:"ReadChat"`
+       SendChat             bool `yaml:"SendChat"`
+       OpenChat             bool `yaml:"OpenChat"`
+       CloseChat            bool `yaml:"CloseChat"`
+       ShowInList           bool `yaml:"ShowInList"`
+       CreateUser           bool `yaml:"CreateUser"`
+       DeleteUser           bool `yaml:"DeleteUser"`
+       OpenUser             bool `yaml:"OpenUser"`
+       ModifyUser           bool `yaml:"ModifyUser"`
+       ChangeOwnPass        bool `yaml:"ChangeOwnPass"`
+       NewsReadArt          bool `yaml:"NewsReadArt"`
+       NewsPostArt          bool `yaml:"NewsPostArt"`
+       DisconnectUser       bool `yaml:"DisconnectUser"`
+       CannotBeDisconnected bool `yaml:"CannotBeDisconnected"`
+       GetClientInfo        bool `yaml:"GetClientInfo"`
+       UploadAnywhere       bool `yaml:"UploadAnywhere"`
+       AnyName              bool `yaml:"AnyName"`
+       NoAgreement          bool `yaml:"NoAgreement"`
+       SetFileComment       bool `yaml:"SetFileComment"`
+       SetFolderComment     bool `yaml:"SetFolderComment"`
+       ViewDropBoxes        bool `yaml:"ViewDropBoxes"`
+       MakeAlias            bool `yaml:"MakeAlias"`
+       Broadcast            bool `yaml:"Broadcast"`
+       NewsDeleteArt        bool `yaml:"NewsDeleteArt"`
+       NewsCreateCat        bool `yaml:"NewsCreateCat"`
+       NewsDeleteCat        bool `yaml:"NewsDeleteCat"`
+       NewsCreateFldr       bool `yaml:"NewsCreateFldr"`
+       NewsDeleteFldr       bool `yaml:"NewsDeleteFldr"`
+       SendPrivMsg          bool `yaml:"SendPrivMsg"`
+}
+
+func (bits AccessBitmap) MarshalYAML() (interface{}, error) {
+       return accessFlags{
+               DownloadFile:         bits.IsSet(AccessDownloadFile),
+               DownloadFolder:       bits.IsSet(AccessDownloadFolder),
+               UploadFolder:         bits.IsSet(AccessUploadFolder),
+               DeleteFile:           bits.IsSet(AccessDeleteFile),
+               UploadFile:           bits.IsSet(AccessUploadFile),
+               RenameFile:           bits.IsSet(AccessRenameFile),
+               MoveFile:             bits.IsSet(AccessMoveFile),
+               CreateFolder:         bits.IsSet(AccessCreateFolder),
+               DeleteFolder:         bits.IsSet(AccessDeleteFolder),
+               RenameFolder:         bits.IsSet(AccessRenameFolder),
+               MoveFolder:           bits.IsSet(AccessMoveFolder),
+               ReadChat:             bits.IsSet(AccessReadChat),
+               SendChat:             bits.IsSet(AccessSendChat),
+               OpenChat:             bits.IsSet(AccessOpenChat),
+               CloseChat:            bits.IsSet(AccessCloseChat),
+               ShowInList:           bits.IsSet(AccessShowInList),
+               CreateUser:           bits.IsSet(AccessCreateUser),
+               DeleteUser:           bits.IsSet(AccessDeleteUser),
+               OpenUser:             bits.IsSet(AccessOpenUser),
+               ModifyUser:           bits.IsSet(AccessModifyUser),
+               ChangeOwnPass:        bits.IsSet(AccessChangeOwnPass),
+               NewsReadArt:          bits.IsSet(AccessNewsReadArt),
+               NewsPostArt:          bits.IsSet(AccessNewsPostArt),
+               DisconnectUser:       bits.IsSet(AccessDisconUser),
+               CannotBeDisconnected: bits.IsSet(AccessCannotBeDiscon),
+               GetClientInfo:        bits.IsSet(AccessGetClientInfo),
+               UploadAnywhere:       bits.IsSet(AccessUploadAnywhere),
+               AnyName:              bits.IsSet(AccessAnyName),
+               NoAgreement:          bits.IsSet(AccessNoAgreement),
+               SetFileComment:       bits.IsSet(AccessSetFileComment),
+               SetFolderComment:     bits.IsSet(AccessSetFolderComment),
+               ViewDropBoxes:        bits.IsSet(AccessViewDropBoxes),
+               MakeAlias:            bits.IsSet(AccessMakeAlias),
+               Broadcast:            bits.IsSet(AccessBroadcast),
+               NewsDeleteArt:        bits.IsSet(AccessNewsDeleteArt),
+               NewsCreateCat:        bits.IsSet(AccessNewsCreateCat),
+               NewsDeleteCat:        bits.IsSet(AccessNewsDeleteCat),
+               NewsCreateFldr:       bits.IsSet(AccessNewsCreateFldr),
+               NewsDeleteFldr:       bits.IsSet(AccessNewsDeleteFldr),
+               SendPrivMsg:          bits.IsSet(AccessSendPrivMsg),
+       }, nil
+}