]> git.r.bdr.sh - rbdr/mobius/blob - hotline/access.go
Account for the root
[rbdr/mobius] / hotline / access.go
1 package hotline
2
3 import "fmt"
4
5 const (
6 AccessDeleteFile = 0 // File System Maintenance: Can Delete Files
7 AccessUploadFile = 1 // File System Maintenance: Can Upload Files
8 AccessDownloadFile = 2 // File System Maintenance: Can Download Files
9 AccessRenameFile = 3 // File System Maintenance: Can Rename Files
10 AccessMoveFile = 4 // File System Maintenance: Can Move Files
11 AccessCreateFolder = 5 // File System Maintenance: Can Create Folders
12 AccessDeleteFolder = 6 // File System Maintenance: Can Delete Folders
13 AccessRenameFolder = 7 // File System Maintenance: Can Rename Folders
14 AccessMoveFolder = 8 // File System Maintenance: Can Move Folders
15 AccessReadChat = 9 // Chat: Can Read Chat
16 AccessSendChat = 10 // Chat: Can Send Chat
17 AccessOpenChat = 11 // Chat: Can Initial Private Chat
18 AccessCloseChat = 12 // Present in the Hotline 1.9 protocol documentation, but seemingly unused
19 AccessShowInList = 13 // Present in the Hotline 1.9 protocol documentation, but seemingly unused
20 AccessCreateUser = 14 // User Maintenance: Can Create Accounts
21 AccessDeleteUser = 15 // User Maintenance: Can Delete Accounts
22 AccessOpenUser = 16 // User Maintenance: Can Read Accounts
23 AccessModifyUser = 17 // User Maintenance: Can Modify Accounts
24 AccessChangeOwnPass = 18 // Present in the Hotline 1.9 protocol documentation, but seemingly unused
25 AccessNewsReadArt = 20 // News: Can Read Articles
26 AccessNewsPostArt = 21 // News: Can Post Articles
27 AccessDisconUser = 22 // User Maintenance: Can Disconnect Users (Note: Turns username red in user list)
28 AccessCannotBeDiscon = 23 // User Maintenance: Cannot be Disconnected
29 AccessGetClientInfo = 24 // User Maintenance: Can Get User Info
30 AccessUploadAnywhere = 25 // File System Maintenance: Can Upload Anywhere
31 AccessAnyName = 26 // Miscellaneous: Can User Any Name
32 AccessNoAgreement = 27 // Miscellaneous: Don't Show Agreement
33 AccessSetFileComment = 28 // File System Maintenance: Can Comment Files
34 AccessSetFolderComment = 29 // File System Maintenance: Can Comment Folders
35 AccessViewDropBoxes = 30 // File System Maintenance: Can View Drop Boxes
36 AccessMakeAlias = 31 // File System Maintenance: Can Make Aliases
37 AccessBroadcast = 32 // Messaging: Can Broadcast
38 AccessNewsDeleteArt = 33 // News: Can Delete Articles
39 AccessNewsCreateCat = 34 // News: Can Create Categories
40 AccessNewsDeleteCat = 35 // News: Can Delete Categories
41 AccessNewsCreateFldr = 36 // News: Can Create News Bundles
42 AccessNewsDeleteFldr = 37 // News: Can Delete News Bundles
43 AccessUploadFolder = 38 // File System Maintenance: Can Upload Folders
44 AccessDownloadFolder = 39 // File System Maintenance: Can Download Folders
45 AccessSendPrivMsg = 40 // Messaging: Can Send Messages (Note: 1.9 protocol doc incorrectly says this is bit 19)
46 )
47
48 type AccessBitmap [8]byte
49
50 func (bits *AccessBitmap) Set(i int) {
51 bits[i/8] |= 1 << uint(7-i%8)
52 }
53
54 func (bits *AccessBitmap) IsSet(i int) bool {
55 return bits[i/8]&(1<<uint(7-i%8)) != 0
56 }
57
58 func (bits *AccessBitmap) UnmarshalYAML(unmarshal func(interface{}) error) error {
59 var flags interface{}
60 err := unmarshal(&flags)
61 if err != nil {
62 return fmt.Errorf("unmarshal access bitmap: %w", err)
63 }
64
65 switch v := flags.(type) {
66 case []interface{}:
67 // Mobius versions < v0.17.0 store the user access bitmap as an array of int values like:
68 // [96, 112, 12, 32, 3, 128, 0, 0]
69 // This case supports reading of user config files using this format.
70 for i, v := range flags.([]interface{}) {
71 bits[i] = byte(v.(int))
72 }
73 case map[string]interface{}:
74 // Mobius versions >= v0.17.0 store the user access bitmap as map[string]bool to provide a human-readable view of
75 // the account permissions.
76 if f, ok := v["DeleteFile"].(bool); ok && f {
77 bits.Set(AccessDeleteFile)
78 }
79 if f, ok := v["UploadFile"].(bool); ok && f {
80 bits.Set(AccessUploadFile)
81 }
82 if f, ok := v["DownloadFile"].(bool); ok && f {
83 bits.Set(AccessDownloadFile)
84 }
85 if f, ok := v["UploadFolder"].(bool); ok && f {
86 bits.Set(AccessUploadFolder)
87 }
88 if f, ok := v["DownloadFolder"].(bool); ok && f {
89 bits.Set(AccessDownloadFolder)
90 }
91 if f, ok := v["RenameFile"].(bool); ok && f {
92 bits.Set(AccessRenameFile)
93 }
94 if f, ok := v["MoveFile"].(bool); ok && f {
95 bits.Set(AccessMoveFile)
96 }
97 if f, ok := v["CreateFolder"].(bool); ok && f {
98 bits.Set(AccessCreateFolder)
99 }
100 if f, ok := v["DeleteFolder"].(bool); ok && f {
101 bits.Set(AccessDeleteFolder)
102 }
103 if f, ok := v["RenameFolder"].(bool); ok && f {
104 bits.Set(AccessRenameFolder)
105 }
106 if f, ok := v["MoveFolder"].(bool); ok && f {
107 bits.Set(AccessMoveFolder)
108 }
109 if f, ok := v["ReadChat"].(bool); ok && f {
110 bits.Set(AccessReadChat)
111 }
112 if f, ok := v["SendChat"].(bool); ok && f {
113 bits.Set(AccessSendChat)
114 }
115 if f, ok := v["OpenChat"].(bool); ok && f {
116 bits.Set(AccessOpenChat)
117 }
118 if f, ok := v["CloseChat"].(bool); ok && f {
119 bits.Set(AccessCloseChat)
120 }
121 if f, ok := v["ShowInList"].(bool); ok && f {
122 bits.Set(AccessShowInList)
123 }
124 if f, ok := v["CreateUser"].(bool); ok && f {
125 bits.Set(AccessCreateUser)
126 }
127 if f, ok := v["DeleteUser"].(bool); ok && f {
128 bits.Set(AccessDeleteUser)
129 }
130 if f, ok := v["OpenUser"].(bool); ok && f {
131 bits.Set(AccessOpenUser)
132 }
133 if f, ok := v["ModifyUser"].(bool); ok && f {
134 bits.Set(AccessModifyUser)
135 }
136 if f, ok := v["ChangeOwnPass"].(bool); ok && f {
137 bits.Set(AccessChangeOwnPass)
138 }
139 if f, ok := v["NewsReadArt"].(bool); ok && f {
140 bits.Set(AccessNewsReadArt)
141 }
142 if f, ok := v["NewsPostArt"].(bool); ok && f {
143 bits.Set(AccessNewsPostArt)
144 }
145 if f, ok := v["DisconnectUser"].(bool); ok && f {
146 bits.Set(AccessDisconUser)
147 }
148 if f, ok := v["CannotBeDisconnected"].(bool); ok && f {
149 bits.Set(AccessCannotBeDiscon)
150 }
151 if f, ok := v["GetClientInfo"].(bool); ok && f {
152 bits.Set(AccessGetClientInfo)
153 }
154 if f, ok := v["UploadAnywhere"].(bool); ok && f {
155 bits.Set(AccessUploadAnywhere)
156 }
157 if f, ok := v["AnyName"].(bool); ok && f {
158 bits.Set(AccessAnyName)
159 }
160 if f, ok := v["NoAgreement"].(bool); ok && f {
161 bits.Set(AccessNoAgreement)
162 }
163 if f, ok := v["SetFileComment"].(bool); ok && f {
164 bits.Set(AccessSetFileComment)
165 }
166 if f, ok := v["SetFolderComment"].(bool); ok && f {
167 bits.Set(AccessSetFolderComment)
168 }
169 if f, ok := v["ViewDropBoxes"].(bool); ok && f {
170 bits.Set(AccessViewDropBoxes)
171 }
172 if f, ok := v["MakeAlias"].(bool); ok && f {
173 bits.Set(AccessMakeAlias)
174 }
175 if f, ok := v["Broadcast"].(bool); ok && f {
176 bits.Set(AccessBroadcast)
177 }
178 if f, ok := v["NewsDeleteArt"].(bool); ok && f {
179 bits.Set(AccessNewsDeleteArt)
180 }
181 if f, ok := v["NewsCreateCat"].(bool); ok && f {
182 bits.Set(AccessNewsCreateCat)
183 }
184 if f, ok := v["NewsDeleteCat"].(bool); ok && f {
185 bits.Set(AccessNewsDeleteCat)
186 }
187 if f, ok := v["NewsCreateFldr"].(bool); ok && f {
188 bits.Set(AccessNewsCreateFldr)
189 }
190 if f, ok := v["NewsDeleteFldr"].(bool); ok && f {
191 bits.Set(AccessNewsDeleteFldr)
192 }
193 if f, ok := v["SendPrivMsg"].(bool); ok && f {
194 bits.Set(AccessSendPrivMsg)
195 }
196 }
197
198 return nil
199 }
200
201 // accessFlags is used to render the access bitmap to human-readable boolean flags in the account yaml.
202 type accessFlags struct {
203 DownloadFile bool `yaml:"DownloadFile"`
204 DownloadFolder bool `yaml:"DownloadFolder"`
205 UploadFile bool `yaml:"UploadFile"`
206 UploadFolder bool `yaml:"UploadFolder"`
207 DeleteFile bool `yaml:"DeleteFile"`
208 RenameFile bool `yaml:"RenameFile"`
209 MoveFile bool `yaml:"MoveFile"`
210 CreateFolder bool `yaml:"CreateFolder"`
211 DeleteFolder bool `yaml:"DeleteFolder"`
212 RenameFolder bool `yaml:"RenameFolder"`
213 MoveFolder bool `yaml:"MoveFolder"`
214 ReadChat bool `yaml:"ReadChat"`
215 SendChat bool `yaml:"SendChat"`
216 OpenChat bool `yaml:"OpenChat"`
217 CloseChat bool `yaml:"CloseChat"`
218 ShowInList bool `yaml:"ShowInList"`
219 CreateUser bool `yaml:"CreateUser"`
220 DeleteUser bool `yaml:"DeleteUser"`
221 OpenUser bool `yaml:"OpenUser"`
222 ModifyUser bool `yaml:"ModifyUser"`
223 ChangeOwnPass bool `yaml:"ChangeOwnPass"`
224 NewsReadArt bool `yaml:"NewsReadArt"`
225 NewsPostArt bool `yaml:"NewsPostArt"`
226 DisconnectUser bool `yaml:"DisconnectUser"`
227 CannotBeDisconnected bool `yaml:"CannotBeDisconnected"`
228 GetClientInfo bool `yaml:"GetClientInfo"`
229 UploadAnywhere bool `yaml:"UploadAnywhere"`
230 AnyName bool `yaml:"AnyName"`
231 NoAgreement bool `yaml:"NoAgreement"`
232 SetFileComment bool `yaml:"SetFileComment"`
233 SetFolderComment bool `yaml:"SetFolderComment"`
234 ViewDropBoxes bool `yaml:"ViewDropBoxes"`
235 MakeAlias bool `yaml:"MakeAlias"`
236 Broadcast bool `yaml:"Broadcast"`
237 NewsDeleteArt bool `yaml:"NewsDeleteArt"`
238 NewsCreateCat bool `yaml:"NewsCreateCat"`
239 NewsDeleteCat bool `yaml:"NewsDeleteCat"`
240 NewsCreateFldr bool `yaml:"NewsCreateFldr"`
241 NewsDeleteFldr bool `yaml:"NewsDeleteFldr"`
242 SendPrivMsg bool `yaml:"SendPrivMsg"`
243 }
244
245 func (bits AccessBitmap) MarshalYAML() (interface{}, error) {
246 return accessFlags{
247 DownloadFile: bits.IsSet(AccessDownloadFile),
248 DownloadFolder: bits.IsSet(AccessDownloadFolder),
249 UploadFolder: bits.IsSet(AccessUploadFolder),
250 DeleteFile: bits.IsSet(AccessDeleteFile),
251 UploadFile: bits.IsSet(AccessUploadFile),
252 RenameFile: bits.IsSet(AccessRenameFile),
253 MoveFile: bits.IsSet(AccessMoveFile),
254 CreateFolder: bits.IsSet(AccessCreateFolder),
255 DeleteFolder: bits.IsSet(AccessDeleteFolder),
256 RenameFolder: bits.IsSet(AccessRenameFolder),
257 MoveFolder: bits.IsSet(AccessMoveFolder),
258 ReadChat: bits.IsSet(AccessReadChat),
259 SendChat: bits.IsSet(AccessSendChat),
260 OpenChat: bits.IsSet(AccessOpenChat),
261 CloseChat: bits.IsSet(AccessCloseChat),
262 ShowInList: bits.IsSet(AccessShowInList),
263 CreateUser: bits.IsSet(AccessCreateUser),
264 DeleteUser: bits.IsSet(AccessDeleteUser),
265 OpenUser: bits.IsSet(AccessOpenUser),
266 ModifyUser: bits.IsSet(AccessModifyUser),
267 ChangeOwnPass: bits.IsSet(AccessChangeOwnPass),
268 NewsReadArt: bits.IsSet(AccessNewsReadArt),
269 NewsPostArt: bits.IsSet(AccessNewsPostArt),
270 DisconnectUser: bits.IsSet(AccessDisconUser),
271 CannotBeDisconnected: bits.IsSet(AccessCannotBeDiscon),
272 GetClientInfo: bits.IsSet(AccessGetClientInfo),
273 UploadAnywhere: bits.IsSet(AccessUploadAnywhere),
274 AnyName: bits.IsSet(AccessAnyName),
275 NoAgreement: bits.IsSet(AccessNoAgreement),
276 SetFileComment: bits.IsSet(AccessSetFileComment),
277 SetFolderComment: bits.IsSet(AccessSetFolderComment),
278 ViewDropBoxes: bits.IsSet(AccessViewDropBoxes),
279 MakeAlias: bits.IsSet(AccessMakeAlias),
280 Broadcast: bits.IsSet(AccessBroadcast),
281 NewsDeleteArt: bits.IsSet(AccessNewsDeleteArt),
282 NewsCreateCat: bits.IsSet(AccessNewsCreateCat),
283 NewsDeleteCat: bits.IsSet(AccessNewsDeleteCat),
284 NewsCreateFldr: bits.IsSet(AccessNewsCreateFldr),
285 NewsDeleteFldr: bits.IsSet(AccessNewsDeleteFldr),
286 SendPrivMsg: bits.IsSet(AccessSendPrivMsg),
287 }, nil
288 }