Skip to content

Commit ef36e75

Browse files
committed
fix: /client:elevate to /client/:id/elevate
1 parent 0ac515f commit ef36e75

8 files changed

Lines changed: 66 additions & 51 deletions

File tree

api/client.go

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func (a *ClientAPI) DeleteClient(ctx *gin.Context) {
246246
})
247247
}
248248

249-
// swagger:operation POST /client:elevate client elevateClient
249+
// swagger:operation POST /client/{id}/elevate client elevateClient
250250
//
251251
// Elevate a client session.
252252
//
@@ -256,6 +256,12 @@ func (a *ClientAPI) DeleteClient(ctx *gin.Context) {
256256
// consumes: [application/json]
257257
// produces: [application/json]
258258
// parameters:
259+
// - name: id
260+
// in: path
261+
// description: the client id
262+
// required: true
263+
// type: integer
264+
// format: int64
259265
// - name: body
260266
// in: body
261267
// description: the elevation request
@@ -279,28 +285,30 @@ func (a *ClientAPI) DeleteClient(ctx *gin.Context) {
279285
// schema:
280286
// $ref: "#/definitions/Error"
281287
func (a *ClientAPI) ElevateClient(ctx *gin.Context) {
282-
var params model.ElevateRequest
283-
if err := ctx.Bind(&params); err != nil {
284-
return
285-
}
288+
withID(ctx, "id", func(id uint) {
289+
var params model.ElevateRequest
290+
if err := ctx.Bind(&params); err != nil {
291+
return
292+
}
286293

287-
client, err := a.DB.GetClientByID(params.ID)
288-
if err != nil {
289-
ctx.AbortWithError(500, err)
290-
return
291-
}
292-
if client == nil || client.UserID != auth.GetUserID(ctx) {
293-
ctx.AbortWithError(404, errors.New("client not found"))
294-
return
295-
}
294+
client, err := a.DB.GetClientByID(id)
295+
if err != nil {
296+
ctx.AbortWithError(500, err)
297+
return
298+
}
299+
if client == nil || client.UserID != auth.GetUserID(ctx) {
300+
ctx.AbortWithError(404, errors.New("client not found"))
301+
return
302+
}
296303

297-
elevatedUntil := time.Now().Add(time.Duration(params.DurationSeconds) * time.Second)
298-
if err := a.DB.UpdateClientElevatedUntil(client.ID, &elevatedUntil); err != nil {
299-
ctx.AbortWithError(500, err)
300-
return
301-
}
304+
elevatedUntil := time.Now().Add(time.Duration(params.DurationSeconds) * time.Second)
305+
if err := a.DB.UpdateClientElevatedUntil(client.ID, &elevatedUntil); err != nil {
306+
ctx.AbortWithError(500, err)
307+
return
308+
}
302309

303-
ctx.Status(204)
310+
ctx.Status(204)
311+
})
304312
}
305313

306314
func (a *ClientAPI) clientExists(token string) bool {

api/client_test.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package api
22

33
import (
4+
"fmt"
45
"net/http/httptest"
56
"net/url"
67
"strings"
@@ -165,7 +166,7 @@ func (s *ClientSuite) Test_DeleteClient_expectNotFound() {
165166

166167
test.WithUser(s.ctx, 5)
167168
s.ctx.Request = httptest.NewRequest("DELETE", "/token/"+firstClientToken, nil)
168-
s.ctx.Params = gin.Params{{Key: "id", Value: "8"}}
169+
s.ctx.AddParam("id", "8")
169170

170171
s.a.DeleteClient(s.ctx)
171172

@@ -177,7 +178,7 @@ func (s *ClientSuite) Test_DeleteClient() {
177178

178179
test.WithUser(s.ctx, 5)
179180
s.ctx.Request = httptest.NewRequest("DELETE", "/token/"+firstClientToken, nil)
180-
s.ctx.Params = gin.Params{{Key: "id", Value: "8"}}
181+
s.ctx.AddParam("id", "8")
181182

182183
assert.False(s.T(), s.notified)
183184

@@ -228,7 +229,7 @@ func (s *ClientSuite) Test_ElevateClient_expectSuccess() {
228229
s.db.User(5).Client(8)
229230

230231
test.WithUser(s.ctx, 5)
231-
s.withJSONBody(`{"id":8,"durationSeconds":900}`)
232+
s.withElevateRequest(8, 900)
232233

233234
before := time.Now()
234235
s.a.ElevateClient(s.ctx)
@@ -245,7 +246,7 @@ func (s *ClientSuite) Test_ElevateClient_expectNotFoundOnMissingClient() {
245246
s.db.User(5)
246247

247248
test.WithUser(s.ctx, 5)
248-
s.withJSONBody(`{"id":8,"durationSeconds":900}`)
249+
s.withElevateRequest(8, 900)
249250

250251
s.a.ElevateClient(s.ctx)
251252

@@ -257,7 +258,7 @@ func (s *ClientSuite) Test_ElevateClient_expectNotFoundOnCurrentUserIsNotOwner()
257258
s.db.User(2)
258259

259260
test.WithUser(s.ctx, 2)
260-
s.withJSONBody(`{"id":8,"durationSeconds":900}`)
261+
s.withElevateRequest(8, 900)
261262

262263
s.a.ElevateClient(s.ctx)
263264

@@ -271,7 +272,7 @@ func (s *ClientSuite) Test_ElevateClient_expectBadRequestOnMissingID() {
271272
s.db.User(5)
272273

273274
test.WithUser(s.ctx, 5)
274-
s.withJSONBody(`{"durationSeconds":900}`)
275+
s.withElevateBody(`{"durationSeconds":900}`)
275276

276277
s.a.ElevateClient(s.ctx)
277278

@@ -282,7 +283,8 @@ func (s *ClientSuite) Test_ElevateClient_expectBadRequestOnMissingDuration() {
282283
s.db.User(5).Client(8)
283284

284285
test.WithUser(s.ctx, 5)
285-
s.withJSONBody(`{"id":8}`)
286+
s.ctx.AddParam("id", "8")
287+
s.withElevateBody(`{}`)
286288

287289
s.a.ElevateClient(s.ctx)
288290

@@ -297,8 +299,13 @@ func (s *ClientSuite) withFormData(formData string) {
297299
s.ctx.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
298300
}
299301

300-
func (s *ClientSuite) withJSONBody(body string) {
301-
s.ctx.Request = httptest.NewRequest("POST", "/client:elevate", strings.NewReader(body))
302+
func (s *ClientSuite) withElevateRequest(id uint, durationSeconds int) {
303+
s.ctx.AddParam("id", fmt.Sprintf("%d", id))
304+
s.withElevateBody(fmt.Sprintf(`{"durationSeconds":%d}`, durationSeconds))
305+
}
306+
307+
func (s *ClientSuite) withElevateBody(body string) {
308+
s.ctx.Request = httptest.NewRequest("POST", "/client/ignored/elevate", strings.NewReader(body))
302309
s.ctx.Request.Header.Set("Content-Type", "application/json")
303310
}
304311

api/oidc.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ type pendingOIDCSession struct {
7171
RedirectURI string
7272
ClientName string
7373
CreatedAt time.Time
74-
Elevate *model.ElevateRequest
74+
Elevate *pendingElevation
75+
}
76+
77+
type pendingElevation struct {
78+
ClientID uint `form:"id" binding:"required"`
79+
DurationSeconds int `form:"durationSeconds" binding:"required"`
7580
}
7681

7782
// OIDCAPI provides handlers for OIDC authentication.
@@ -153,7 +158,7 @@ func (a *OIDCAPI) LoginHandler() gin.HandlerFunc {
153158
// schema:
154159
// $ref: "#/definitions/Error"
155160
func (a *OIDCAPI) ElevateHandler(ctx *gin.Context) {
156-
var elevate model.ElevateRequest
161+
var elevate pendingElevation
157162
if err := ctx.BindQuery(&elevate); err != nil {
158163
return
159164
}
@@ -227,8 +232,8 @@ func (a *OIDCAPI) CallbackHandler() gin.HandlerFunc {
227232
return gin.WrapF(rp.CodeExchangeHandler(rp.UserinfoCallback(callback), a.Provider))
228233
}
229234

230-
func (a *OIDCAPI) handleElevationCallback(w http.ResponseWriter, elevate *model.ElevateRequest, user *model.User) {
231-
client, err := a.DB.GetClientByID(elevate.ID)
235+
func (a *OIDCAPI) handleElevationCallback(w http.ResponseWriter, elevate *pendingElevation, user *model.User) {
236+
client, err := a.DB.GetClientByID(elevate.ClientID)
232237
if err != nil {
233238
http.Error(w, fmt.Sprintf("database error: %v", err), http.StatusInternalServerError)
234239
return

docs/spec.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@
11291129
}
11301130
}
11311131
},
1132-
"/client:elevate": {
1132+
"/client/{id}/elevate": {
11331133
"post": {
11341134
"security": [
11351135
{
@@ -1158,6 +1158,14 @@
11581158
"summary": "Elevate a client session.",
11591159
"operationId": "elevateClient",
11601160
"parameters": [
1161+
{
1162+
"type": "integer",
1163+
"format": "int64",
1164+
"description": "the client id",
1165+
"name": "id",
1166+
"in": "path",
1167+
"required": true
1168+
},
11611169
{
11621170
"description": "the elevation request",
11631171
"name": "body",
@@ -2684,7 +2692,6 @@
26842692
"type": "object",
26852693
"title": "ElevateRequest parameters for client elevation.",
26862694
"required": [
2687-
"id",
26882695
"durationSeconds"
26892696
],
26902697
"properties": {
@@ -2694,13 +2701,6 @@
26942701
"format": "int64",
26952702
"x-go-name": "DurationSeconds",
26962703
"example": 900
2697-
},
2698-
"id": {
2699-
"description": "The client ID to elevate.",
2700-
"type": "integer",
2701-
"format": "int64",
2702-
"x-go-name": "ID",
2703-
"example": 5
27042704
}
27052705
},
27062706
"x-go-package": "github.com/gotify/server/v2/model"

model/elevate.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ import "time"
66
//
77
// swagger:model ElevateRequest
88
type ElevateRequest struct {
9-
// The client ID to elevate.
10-
//
11-
// required: true
12-
// example: 5
13-
ID uint `form:"id" query:"id" json:"id" binding:"required"`
149
// How long the elevation should last, in seconds.
1510
//
1611
// required: true

router/router.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
220220
clientElevated := g.Group("")
221221
{
222222
clientElevated.Use(authentication.RequireElevatedClient)
223-
clientElevated.POST("/client:elevate", clientHandler.ElevateClient)
223+
clientElevated.POST("/client/:id/elevate", clientHandler.ElevateClient)
224224
clientElevated.DELETE("/application/:id", applicationHandler.DeleteApplication)
225225
clientElevated.DELETE("/client/:id", clientHandler.DeleteClient)
226226
clientElevated.POST("/current/user/password", userHandler.ChangePassword)

ui/src/ElevateStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export class ElevateStore {
3333

3434
public localElevate = async (password: string, durationSeconds: number): Promise<void> => {
3535
await axios.create().request({
36-
url: config.get('url') + 'client:elevate',
36+
url: `${config.get('url')}client/${this.currentUser.user.clientId}/elevate`,
3737
method: 'POST',
38-
data: {id: this.currentUser.user.clientId, durationSeconds},
38+
data: {durationSeconds},
3939
headers: {
4040
Authorization: 'Basic ' + btoa(this.currentUser.user.name + ':' + password),
4141
},

ui/src/client/ClientStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class ClientStore extends BaseStore<IClient> {
4141

4242
@action
4343
public elevate = async (id: number, durationSeconds: number): Promise<void> => {
44-
await axios.post(`${config.get('url')}client:elevate`, {id, durationSeconds});
44+
await axios.post(`${config.get('url')}client/${id}/elevate`, {durationSeconds});
4545
await this.refresh();
4646
if (durationSeconds < 0) {
4747
this.snack('Canceled client elevation');

0 commit comments

Comments
 (0)