Skip to content

Commit 0706c60

Browse files
authored
chore: Add watch workspace endpoint (#1493)
1 parent b8ee939 commit 0706c60

21 files changed

+259
-37
lines changed

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ func New(options *Options) (http.Handler, func()) {
310310
r.Route("/autostop", func(r chi.Router) {
311311
r.Put("/", api.putWorkspaceAutostop)
312312
})
313+
r.Get("/watch", api.watchWorkspace)
313314
})
314315
})
315316
r.Route("/workspacebuilds/{workspacebuild}", func(r chi.Router) {

coderd/coderd_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func TestAuthorizeAllEndpoints(t *testing.T) {
128128
"PUT:/api/v2/workspaces/{workspace}/autostop": {NoAuthorize: true},
129129
"GET:/api/v2/workspaces/{workspace}/builds": {NoAuthorize: true},
130130
"POST:/api/v2/workspaces/{workspace}/builds": {NoAuthorize: true},
131+
"GET:/api/v2/workspaces/{workspace}/watch": {NoAuthorize: true},
131132

132133
"POST:/api/v2/files": {NoAuthorize: true},
133134
"GET:/api/v2/files/{hash}": {NoAuthorize: true},

coderd/httpmw/apikey.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import (
1717
"github.com/coder/coder/coderd/httpapi"
1818
)
1919

20-
// AuthCookie represents the name of the cookie the API key is stored in.
21-
const AuthCookie = "session_token"
20+
// SessionTokenKey represents the name of the cookie or query paramater the API key is stored in.
21+
const SessionTokenKey = "session_token"
2222

2323
type apiKeyContextKey struct{}
2424

@@ -43,18 +43,24 @@ type OAuth2Configs struct {
4343
func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) http.Handler {
4444
return func(next http.Handler) http.Handler {
4545
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
46-
cookie, err := r.Cookie(AuthCookie)
46+
var cookieValue string
47+
cookie, err := r.Cookie(SessionTokenKey)
4748
if err != nil {
49+
cookieValue = r.URL.Query().Get(SessionTokenKey)
50+
} else {
51+
cookieValue = cookie.Value
52+
}
53+
if cookieValue == "" {
4854
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
49-
Message: fmt.Sprintf("%q cookie must be provided", AuthCookie),
55+
Message: fmt.Sprintf("%q cookie or query parameter must be provided", SessionTokenKey),
5056
})
5157
return
5258
}
53-
parts := strings.Split(cookie.Value, "-")
59+
parts := strings.Split(cookieValue, "-")
5460
// APIKeys are formatted: ID-SECRET
5561
if len(parts) != 2 {
5662
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
57-
Message: fmt.Sprintf("invalid %q cookie api key format", AuthCookie),
63+
Message: fmt.Sprintf("invalid %q cookie api key format", SessionTokenKey),
5864
})
5965
return
6066
}
@@ -63,13 +69,13 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
6369
// Ensuring key lengths are valid.
6470
if len(keyID) != 10 {
6571
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
66-
Message: fmt.Sprintf("invalid %q cookie api key id", AuthCookie),
72+
Message: fmt.Sprintf("invalid %q cookie api key id", SessionTokenKey),
6773
})
6874
return
6975
}
7076
if len(keySecret) != 22 {
7177
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
72-
Message: fmt.Sprintf("invalid %q cookie api key secret", AuthCookie),
78+
Message: fmt.Sprintf("invalid %q cookie api key secret", SessionTokenKey),
7379
})
7480
return
7581
}

coderd/httpmw/apikey_test.go

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestAPIKey(t *testing.T) {
5656
rw = httptest.NewRecorder()
5757
)
5858
r.AddCookie(&http.Cookie{
59-
Name: httpmw.AuthCookie,
59+
Name: httpmw.SessionTokenKey,
6060
Value: "test-wow-hello",
6161
})
6262

@@ -74,7 +74,7 @@ func TestAPIKey(t *testing.T) {
7474
rw = httptest.NewRecorder()
7575
)
7676
r.AddCookie(&http.Cookie{
77-
Name: httpmw.AuthCookie,
77+
Name: httpmw.SessionTokenKey,
7878
Value: "test-wow",
7979
})
8080

@@ -92,7 +92,7 @@ func TestAPIKey(t *testing.T) {
9292
rw = httptest.NewRecorder()
9393
)
9494
r.AddCookie(&http.Cookie{
95-
Name: httpmw.AuthCookie,
95+
Name: httpmw.SessionTokenKey,
9696
Value: "testtestid-wow",
9797
})
9898

@@ -111,7 +111,7 @@ func TestAPIKey(t *testing.T) {
111111
rw = httptest.NewRecorder()
112112
)
113113
r.AddCookie(&http.Cookie{
114-
Name: httpmw.AuthCookie,
114+
Name: httpmw.SessionTokenKey,
115115
Value: fmt.Sprintf("%s-%s", id, secret),
116116
})
117117

@@ -130,7 +130,7 @@ func TestAPIKey(t *testing.T) {
130130
rw = httptest.NewRecorder()
131131
)
132132
r.AddCookie(&http.Cookie{
133-
Name: httpmw.AuthCookie,
133+
Name: httpmw.SessionTokenKey,
134134
Value: fmt.Sprintf("%s-%s", id, secret),
135135
})
136136

@@ -157,7 +157,7 @@ func TestAPIKey(t *testing.T) {
157157
rw = httptest.NewRecorder()
158158
)
159159
r.AddCookie(&http.Cookie{
160-
Name: httpmw.AuthCookie,
160+
Name: httpmw.SessionTokenKey,
161161
Value: fmt.Sprintf("%s-%s", id, secret),
162162
})
163163

@@ -182,7 +182,7 @@ func TestAPIKey(t *testing.T) {
182182
rw = httptest.NewRecorder()
183183
)
184184
r.AddCookie(&http.Cookie{
185-
Name: httpmw.AuthCookie,
185+
Name: httpmw.SessionTokenKey,
186186
Value: fmt.Sprintf("%s-%s", id, secret),
187187
})
188188

@@ -209,6 +209,37 @@ func TestAPIKey(t *testing.T) {
209209
require.Equal(t, sentAPIKey.ExpiresAt, gotAPIKey.ExpiresAt)
210210
})
211211

212+
t.Run("QueryParameter", func(t *testing.T) {
213+
t.Parallel()
214+
var (
215+
db = databasefake.New()
216+
id, secret = randomAPIKeyParts()
217+
hashed = sha256.Sum256([]byte(secret))
218+
r = httptest.NewRequest("GET", "/", nil)
219+
rw = httptest.NewRecorder()
220+
)
221+
q := r.URL.Query()
222+
q.Add(httpmw.SessionTokenKey, fmt.Sprintf("%s-%s", id, secret))
223+
r.URL.RawQuery = q.Encode()
224+
225+
_, err := db.InsertAPIKey(r.Context(), database.InsertAPIKeyParams{
226+
ID: id,
227+
HashedSecret: hashed[:],
228+
ExpiresAt: database.Now().AddDate(0, 0, 1),
229+
})
230+
require.NoError(t, err)
231+
httpmw.ExtractAPIKey(db, nil)(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
232+
// Checks that it exists on the context!
233+
_ = httpmw.APIKey(r)
234+
httpapi.Write(rw, http.StatusOK, httpapi.Response{
235+
Message: "it worked!",
236+
})
237+
})).ServeHTTP(rw, r)
238+
res := rw.Result()
239+
defer res.Body.Close()
240+
require.Equal(t, http.StatusOK, res.StatusCode)
241+
})
242+
212243
t.Run("ValidUpdateLastUsed", func(t *testing.T) {
213244
t.Parallel()
214245
var (
@@ -219,7 +250,7 @@ func TestAPIKey(t *testing.T) {
219250
rw = httptest.NewRecorder()
220251
)
221252
r.AddCookie(&http.Cookie{
222-
Name: httpmw.AuthCookie,
253+
Name: httpmw.SessionTokenKey,
223254
Value: fmt.Sprintf("%s-%s", id, secret),
224255
})
225256

@@ -252,7 +283,7 @@ func TestAPIKey(t *testing.T) {
252283
rw = httptest.NewRecorder()
253284
)
254285
r.AddCookie(&http.Cookie{
255-
Name: httpmw.AuthCookie,
286+
Name: httpmw.SessionTokenKey,
256287
Value: fmt.Sprintf("%s-%s", id, secret),
257288
})
258289

@@ -285,7 +316,7 @@ func TestAPIKey(t *testing.T) {
285316
rw = httptest.NewRecorder()
286317
)
287318
r.AddCookie(&http.Cookie{
288-
Name: httpmw.AuthCookie,
319+
Name: httpmw.SessionTokenKey,
289320
Value: fmt.Sprintf("%s-%s", id, secret),
290321
})
291322

@@ -319,7 +350,7 @@ func TestAPIKey(t *testing.T) {
319350
rw = httptest.NewRecorder()
320351
)
321352
r.AddCookie(&http.Cookie{
322-
Name: httpmw.AuthCookie,
353+
Name: httpmw.SessionTokenKey,
323354
Value: fmt.Sprintf("%s-%s", id, secret),
324355
})
325356

coderd/httpmw/authorize_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func TestExtractUserRoles(t *testing.T) {
9494

9595
req := httptest.NewRequest("GET", "/", nil)
9696
req.AddCookie(&http.Cookie{
97-
Name: httpmw.AuthCookie,
97+
Name: httpmw.SessionTokenKey,
9898
Value: token,
9999
})
100100

coderd/httpmw/organizationparam_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestOrganizationParam(t *testing.T) {
2929
hashed = sha256.Sum256([]byte(secret))
3030
)
3131
r.AddCookie(&http.Cookie{
32-
Name: httpmw.AuthCookie,
32+
Name: httpmw.SessionTokenKey,
3333
Value: fmt.Sprintf("%s-%s", id, secret),
3434
})
3535

coderd/httpmw/templateparam_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestTemplateParam(t *testing.T) {
2929
)
3030
r := httptest.NewRequest("GET", "/", nil)
3131
r.AddCookie(&http.Cookie{
32-
Name: httpmw.AuthCookie,
32+
Name: httpmw.SessionTokenKey,
3333
Value: fmt.Sprintf("%s-%s", id, secret),
3434
})
3535

coderd/httpmw/templateversionparam_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestTemplateVersionParam(t *testing.T) {
2929
)
3030
r := httptest.NewRequest("GET", "/", nil)
3131
r.AddCookie(&http.Cookie{
32-
Name: httpmw.AuthCookie,
32+
Name: httpmw.SessionTokenKey,
3333
Value: fmt.Sprintf("%s-%s", id, secret),
3434
})
3535

coderd/httpmw/userparam_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestUserParam(t *testing.T) {
2929
rw = httptest.NewRecorder()
3030
)
3131
r.AddCookie(&http.Cookie{
32-
Name: httpmw.AuthCookie,
32+
Name: httpmw.SessionTokenKey,
3333
Value: fmt.Sprintf("%s-%s", id, secret),
3434
})
3535

coderd/httpmw/workspaceagent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ func WorkspaceAgent(r *http.Request) database.WorkspaceAgent {
2828
func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
2929
return func(next http.Handler) http.Handler {
3030
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
31-
cookie, err := r.Cookie(AuthCookie)
31+
cookie, err := r.Cookie(SessionTokenKey)
3232
if err != nil {
3333
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
34-
Message: fmt.Sprintf("%q cookie must be provided", AuthCookie),
34+
Message: fmt.Sprintf("%q cookie must be provided", SessionTokenKey),
3535
})
3636
return
3737
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy