@@ -25,12 +25,12 @@ func rootEndpoint(w http.ResponseWriter, _ *http.Request) {
2525// GET /config
2626// PATCH /config
2727func configEndpoint (connector * Connector , w http.ResponseWriter , r * http.Request ) {
28- user := connector .ValidateAndReject (w , r )
29- if user == "" {
30- return
31- }
3228 switch r .Method {
3329 case "GET" :
30+ user , hasPerm := connector .ValidateWithPermAndReject (w , r , "config.view" )
31+ if user == "" || ! hasPerm {
32+ return
33+ }
3434 contents , err := os .ReadFile (ConfigJsonPath )
3535 if err != nil {
3636 log .Println ("Error reading " + ConfigJsonPath + " when user accessed /config!" , err )
@@ -41,6 +41,10 @@ func configEndpoint(connector *Connector, w http.ResponseWriter, r *http.Request
4141 w .Header ().Set ("content-type" , "application/json" )
4242 _ , _ = w .Write (contents )
4343 case "PATCH" :
44+ user , hasPerm := connector .ValidateWithPermAndReject (w , r , "config.edit" )
45+ if user == "" || ! hasPerm {
46+ return
47+ }
4448 var buffer bytes.Buffer
4549 _ , err := buffer .ReadFrom (r .Body )
4650 if err != nil {
@@ -83,8 +87,8 @@ func configEndpoint(connector *Connector, w http.ResponseWriter, r *http.Request
8387// GET /config/reload
8488func configReloadEndpoint (connector * Connector , w http.ResponseWriter , r * http.Request ) {
8589 // Check with authenticator.
86- user := connector .ValidateAndReject (w , r )
87- if user == "" {
90+ user , hasPerm := connector .ValidateWithPermAndReject (w , r , "config.reload" )
91+ if user == "" || ! hasPerm {
8892 return
8993 }
9094 // Read the new config.
@@ -109,23 +113,36 @@ type serversResponse struct {
109113
110114func serversEndpoint (connector * Connector , w http.ResponseWriter , r * http.Request ) {
111115 // Check with authenticator.
112- if connector .ValidateAndReject (w , r ) == "" {
116+ user := connector .ValidateAndReject (w , r )
117+ if user == "" {
113118 return
114119 }
115120 // Get a map of processes and their online status.
116121 processes := make (map [string ]interface {})
117- connector .Processes .Range (func (_ string , v * ExposedProcess ) bool {
118- if r .URL .Query ().Get ("extrainfo" ) == "true" {
119- processes [v .Name ] = map [string ]interface {}{
122+ errored := false
123+ connector .Processes .Range (func (name string , v * ExposedProcess ) bool {
124+ hasPerm , err := connector .Authenticator .HasPerm (user , "server<" + name + ">.view" )
125+ if ! hasPerm {
126+ return true
127+ } else if err != nil {
128+ log .Println ("An error occurred while checking permissions for user \" " + user + "\" !" , err )
129+ httpError (w , "Internal Server Error!" , http .StatusInternalServerError )
130+ errored = true
131+ return false
132+ } else if r .URL .Query ().Get ("extrainfo" ) == "true" {
133+ processes [name ] = map [string ]interface {}{
120134 "status" : v .Online .Load (),
121135 "toDelete" : v .ToDelete .Load (),
122136 }
123137 } else {
124- processes [v . Name ] = v .Online .Load ()
138+ processes [name ] = v .Online .Load ()
125139 }
126140 return true
127141 })
128142 // Send the list.
143+ if errored {
144+ return
145+ }
129146 writeJsonStructRes (w , serversResponse {Servers : processes }) // skipcq GSC-G104
130147}
131148
@@ -143,13 +160,23 @@ type serverResponse struct {
143160var totalMemory = int64 (system .GetTotalSystemMemory ())
144161
145162func serverEndpoint (connector * Connector , w http.ResponseWriter , r * http.Request ) {
163+ id := r .PathValue ("id" )
146164 // Check with authenticator.
147- user := connector .ValidateAndReject (w , r )
148- if user == "" {
165+ var perm string
166+ switch r .Method {
167+ case "GET" :
168+ perm = "server<" + id + ">.view"
169+ case "POST" :
170+ perm = "server<" + id + ">.control"
171+ default :
172+ httpError (w , "Only GET and POST is allowed!" , http .StatusMethodNotAllowed )
173+ return
174+ }
175+ user , hasPerm := connector .ValidateWithPermAndReject (w , r , perm )
176+ if user == "" || ! hasPerm {
149177 return
150178 }
151179 // Get the process being accessed.
152- id := r .PathValue ("id" )
153180 process , err := connector .Processes .Load (id )
154181 // In case the process doesn't exist.
155182 if ! err {
@@ -161,8 +188,6 @@ func serverEndpoint(connector *Connector, w http.ResponseWriter, r *http.Request
161188 serverEndpointGet (w , process )
162189 case "POST" :
163190 serverEndpointPost (connector , w , r , process , id , user )
164- default :
165- httpError (w , "Only GET and POST is allowed!" , http .StatusMethodNotAllowed )
166191 }
167192}
168193
@@ -261,10 +286,12 @@ type consolePing struct {
261286}
262287
263288type consoleSettings struct {
264- Type string `json:"type"`
289+ Type string `json:"type"`
290+ ReadOnly bool `json:"readOnly"`
265291}
266292
267293func consoleEndpoint (connector * Connector , w http.ResponseWriter , r * http.Request ) {
294+ id := r .PathValue ("id" )
268295 // Get console protocol version.
269296 v2 := slices .Contains (websocket .Subprotocols (r ), "console-v2" )
270297 // Check with authenticator.
@@ -276,21 +303,31 @@ func consoleEndpoint(connector *Connector, w http.ResponseWriter, r *http.Reques
276303 } else {
277304 user , userErr = connector .Authenticator .Validate (r )
278305 }
306+ hasPerm := false
307+ canWrite := false
308+ if user != "" && userErr == nil {
309+ hasPerm , userErr = connector .Authenticator .HasPerm (user , "server<" + id + ">.console.view" )
310+ if userErr == nil {
311+ canWrite , userErr = connector .Authenticator .HasPerm (user , "server<" + id + ">.console.write" )
312+ }
313+ }
279314 if ! v2 && userErr != nil {
280315 log .Println ("An error occurred while validating authorization for an HTTP request!" , userErr )
281316 httpError (w , "Internal Server Error!" , http .StatusInternalServerError )
282317 return
283318 } else if ! v2 && user == "" {
284319 httpError (w , "You are not authenticated to access this resource!" , http .StatusUnauthorized )
285320 return
321+ } else if ! v2 && ! hasPerm {
322+ httpError (w , "You are not allowed to access this resource!" , http .StatusForbidden )
323+ return
286324 }
287325 // Retrieve the token.
288326 token := auth .GetTokenFromRequest (r )
289327 if ticketExists {
290328 token = ticket .Token
291329 }
292330 // Get the server being accessed.
293- id := r .PathValue ("id" )
294331 process , exists := connector .Processes .Load (id )
295332 // In case the server doesn't exist.
296333 if ! exists && ! v2 {
@@ -311,6 +348,9 @@ func consoleEndpoint(connector *Connector, w http.ResponseWriter, r *http.Reques
311348 } else if user == "" {
312349 errStr = "You are not authenticated to access this resource!"
313350 errNo = 4000 + http .StatusUnauthorized
351+ } else if ! hasPerm {
352+ errStr = "You are not allowed to access this resource!"
353+ errNo = 4000 + http .StatusForbidden
314354 }
315355 if errStr != "" {
316356 c .WriteJSON (consoleError {"error" , errStr })
@@ -327,7 +367,7 @@ func consoleEndpoint(connector *Connector, w http.ResponseWriter, r *http.Reques
327367 // If v2, send settings and set read deadline.
328368 if v2 {
329369 c .SetReadDeadline (time .Now ().Add (timeout ))
330- c .WriteJSON (consoleSettings {"settings" })
370+ c .WriteJSON (consoleSettings {"settings" , ! canWrite })
331371 }
332372 // Use a channel to synchronise all writes to the WebSocket.
333373 writeChannel := make (chan interface {}, 8 )
@@ -398,7 +438,8 @@ func consoleEndpoint(connector *Connector, w http.ResponseWriter, r *http.Reques
398438 var data map [string ]string
399439 err := json .Unmarshal (message , & data )
400440 if err == nil {
401- if data ["type" ] == "input" && data ["data" ] != "" {
441+ if data ["type" ] == "input" && data ["data" ] != "" && canWrite {
442+ // Simply drop inputs if the user cannot write.
402443 connector .Info ("server.console.input" , "ip" , GetIP (r ), "user" , user , "server" , id ,
403444 "input" , data ["data" ])
404445 process .SendCommand (data ["data" ])
@@ -413,7 +454,7 @@ func consoleEndpoint(connector *Connector, w http.ResponseWriter, r *http.Reques
413454 json , _ := json .Marshal (consoleError {"error" , "Invalid message format" })
414455 writeChannel <- json
415456 }
416- } else {
457+ } else if canWrite {
417458 connector .Info ("server.console.input" , "ip" , GetIP (r ), "user" , user , "server" , id ,
418459 "input" , string (message ))
419460 process .SendCommand (string (message ))
0 commit comments