http_service_test.go raw
1 package http
2
3 import (
4 "bytes"
5 "encoding/json"
6 "io"
7 "net/http"
8 "net/http/httptest"
9 "strconv"
10 "testing"
11
12 "github.com/getAlby/hub/api"
13 "github.com/getAlby/hub/config"
14 "github.com/getAlby/hub/constants"
15 "github.com/getAlby/hub/events"
16 "github.com/getAlby/hub/lnclient"
17 "github.com/getAlby/hub/logger"
18 "github.com/getAlby/hub/tests/db"
19 "github.com/getAlby/hub/tests/mocks"
20 "github.com/labstack/echo/v4"
21 "github.com/sirupsen/logrus"
22 "github.com/stretchr/testify/assert"
23 "github.com/stretchr/testify/mock"
24 "github.com/stretchr/testify/require"
25 )
26
27 func TestUnlock_IncorrectPassword(t *testing.T) {
28 e := echo.New()
29 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
30 mockSvc := mocks.NewMockService(t)
31 gormDb, err := db.NewDB(t)
32 require.NoError(t, err)
33 defer db.CloseDB(gormDb)
34
35 mockEventPublisher := events.NewEventPublisher()
36
37 mockConfig := mocks.NewMockConfig(t)
38 mockConfig.On("GetEnv").Return(&config.AppConfig{})
39 mockConfig.On("CheckUnlockPassword", "123").Return(false)
40
41 mockSvc.On("GetDB").Return(gormDb)
42 mockSvc.On("GetConfig").Return(mockConfig)
43 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
44 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
45 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
46
47 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
48 httpSvc.RegisterSharedRoutes(e)
49
50 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
51 jsonBody, _ := json.Marshal(requestBody)
52 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
53 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
54 rec := httptest.NewRecorder()
55 e.ServeHTTP(rec, req)
56
57 assert.Equal(t, http.StatusUnauthorized, rec.Code)
58 mockConfig.AssertNotCalled(t, "GetJWTSecret")
59 }
60
61 func TestUnlock_UnknownPermission(t *testing.T) {
62 e := echo.New()
63 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
64 mockSvc := mocks.NewMockService(t)
65 gormDb, err := db.NewDB(t)
66 require.NoError(t, err)
67 defer db.CloseDB(gormDb)
68
69 mockEventPublisher := events.NewEventPublisher()
70
71 mockConfig := mocks.NewMockConfig(t)
72 mockConfig.On("GetEnv").Return(&config.AppConfig{})
73 mockConfig.On("CheckUnlockPassword", "123").Return(true)
74
75 mockSvc.On("GetDB").Return(gormDb)
76 mockSvc.On("GetConfig").Return(mockConfig)
77 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
78 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
79 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
80
81 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
82 httpSvc.RegisterSharedRoutes(e)
83
84 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "unknown"}
85 jsonBody, _ := json.Marshal(requestBody)
86 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
87 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
88 rec := httptest.NewRecorder()
89 e.ServeHTTP(rec, req)
90
91 assert.Equal(t, http.StatusBadRequest, rec.Code)
92 mockConfig.AssertNotCalled(t, "GetJWTSecret")
93 }
94
95 // TestUnlock_RateLimited verifies that repeated requests to an unlock-password
96 // endpoint are throttled with HTTP 429 once the limit is exceeded.
97 func TestUnlock_RateLimited(t *testing.T) {
98 e := echo.New()
99 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
100 mockSvc := mocks.NewMockService(t)
101 gormDb, err := db.NewDB(t)
102 require.NoError(t, err)
103 defer db.CloseDB(gormDb)
104
105 mockEventPublisher := events.NewEventPublisher()
106
107 mockConfig := mocks.NewMockConfig(t)
108 mockConfig.On("GetEnv").Return(&config.AppConfig{})
109 mockConfig.On("CheckUnlockPassword", "wrong").Return(false)
110
111 mockSvc.On("GetDB").Return(gormDb)
112 mockSvc.On("GetConfig").Return(mockConfig)
113 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
114 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
115 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
116
117 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
118 httpSvc.RegisterSharedRoutes(e)
119
120 jsonBody, _ := json.Marshal(api.UnlockRequest{UnlockPassword: "wrong", Permission: "full"})
121 send := func() int {
122 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
123 req.Header.Set("Content-Type", "application/json")
124 rec := httptest.NewRecorder()
125 e.ServeHTTP(rec, req)
126 return rec.Code
127 }
128
129 // the burst of 2 is served (wrong password, so unauthorized)
130 assert.Equal(t, http.StatusUnauthorized, send())
131 assert.Equal(t, http.StatusUnauthorized, send())
132 // the next request exceeds the limit and is rejected with 429
133 assert.Equal(t, http.StatusTooManyRequests, send())
134 }
135
136 // TestUnlock_RateLimitNotBypassedBySpoofedIP verifies that the unlock rate
137 // limiter is global rather than per-IP: varying the X-Forwarded-For header per
138 // request does not grant each request a fresh bucket.
139 func TestUnlock_RateLimitNotBypassedBySpoofedIP(t *testing.T) {
140 e := echo.New()
141 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
142 mockSvc := mocks.NewMockService(t)
143 gormDb, err := db.NewDB(t)
144 require.NoError(t, err)
145 defer db.CloseDB(gormDb)
146
147 mockEventPublisher := events.NewEventPublisher()
148
149 mockConfig := mocks.NewMockConfig(t)
150 mockConfig.On("GetEnv").Return(&config.AppConfig{})
151 mockConfig.On("CheckUnlockPassword", "wrong").Return(false)
152
153 mockSvc.On("GetDB").Return(gormDb)
154 mockSvc.On("GetConfig").Return(mockConfig)
155 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
156 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
157 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
158
159 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
160 httpSvc.RegisterSharedRoutes(e)
161
162 jsonBody, _ := json.Marshal(api.UnlockRequest{UnlockPassword: "wrong", Permission: "full"})
163
164 send := func(forwardedFor string) int {
165 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
166 req.Header.Set("Content-Type", "application/json")
167 req.Header.Set("X-Forwarded-For", forwardedFor)
168 rec := httptest.NewRecorder()
169 e.ServeHTTP(rec, req)
170 return rec.Code
171 }
172
173 rateLimited := 0
174 for i := 0; i < 12; i++ {
175 // each request presents a distinct client address
176 if send("10.0.0."+strconv.Itoa(i)) == http.StatusTooManyRequests {
177 rateLimited++
178 }
179 }
180
181 assert.Positive(t, rateLimited, "spoofing X-Forwarded-For must not grant a fresh rate-limit bucket")
182 }
183
184 func TestGetApps_NoToken(t *testing.T) {
185 e := echo.New()
186 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
187 mockSvc := mocks.NewMockService(t)
188 gormDb, err := db.NewDB(t)
189 require.NoError(t, err)
190 defer db.CloseDB(gormDb)
191
192 mockEventPublisher := mocks.NewMockEventPublisher(t)
193
194 mockConfig := mocks.NewMockConfig(t)
195 mockConfig.On("GetEnv").Return(&config.AppConfig{})
196
197 mockSvc.On("GetDB").Return(gormDb)
198 mockSvc.On("GetConfig").Return(mockConfig)
199 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
200 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
201 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
202
203 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
204 httpSvc.RegisterSharedRoutes(e)
205
206 req := httptest.NewRequest(http.MethodGet, "/api/apps", nil)
207 rec := httptest.NewRecorder()
208 e.ServeHTTP(rec, req)
209
210 assert.Equal(t, http.StatusUnauthorized, rec.Code)
211 }
212
213 func TestUnlock_NodeNotStarted(t *testing.T) {
214 e := echo.New()
215 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
216 mockSvc := mocks.NewMockService(t)
217 gormDb, err := db.NewDB(t)
218 require.NoError(t, err)
219 defer db.CloseDB(gormDb)
220
221 mockEventPublisher := events.NewEventPublisher()
222
223 mockConfig := mocks.NewMockConfig(t)
224 mockConfig.On("GetEnv").Return(&config.AppConfig{})
225 mockConfig.On("CheckUnlockPassword", "123").Return(true)
226
227 mockSvc.On("GetDB").Return(gormDb)
228 mockSvc.On("GetConfig").Return(mockConfig)
229 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
230 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
231 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
232 mockSvc.On("GetLNClient").Return(nil)
233
234 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
235 httpSvc.RegisterSharedRoutes(e)
236
237 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
238 jsonBody, _ := json.Marshal(requestBody)
239 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
240 req.Header.Set("Content-Type", "application/json")
241 rec := httptest.NewRecorder()
242 e.ServeHTTP(rec, req)
243
244 assert.Equal(t, http.StatusBadRequest, rec.Code)
245
246 body, err := io.ReadAll(rec.Body)
247 require.NoError(t, err)
248
249 var response ErrorResponse
250 err = json.Unmarshal(body, &response)
251 require.NoError(t, err)
252 assert.Equal(t, "Node is not running, start it before unlocking.", response.Message)
253 mockConfig.AssertNotCalled(t, "GetJWTSecret")
254 }
255
256 func TestGetApps_ReadonlyPermission(t *testing.T) {
257 e := echo.New()
258 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
259 mockSvc := mocks.NewMockService(t)
260 gormDb, err := db.NewDB(t)
261 require.NoError(t, err)
262 defer db.CloseDB(gormDb)
263
264 mockEventPublisher := events.NewEventPublisher()
265
266 mockConfig := mocks.NewMockConfig(t)
267 mockConfig.On("GetEnv").Return(&config.AppConfig{})
268 mockConfig.On("CheckUnlockPassword", "123").Return(true)
269 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
270
271 mockSvc.On("GetDB").Return(gormDb)
272 mockSvc.On("GetConfig").Return(mockConfig)
273 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
274 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
275 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
276 lnClient := mocks.NewMockLNClient(t)
277 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
278 mockSvc.On("GetLNClient").Return(lnClient)
279
280 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
281 httpSvc.RegisterSharedRoutes(e)
282
283 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "readonly"}
284 jsonBody, _ := json.Marshal(requestBody)
285 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
286 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
287 rec := httptest.NewRecorder()
288 e.ServeHTTP(rec, req)
289
290 assert.Equal(t, http.StatusOK, rec.Code)
291
292 body, err := io.ReadAll(rec.Body)
293 require.NoError(t, err)
294
295 type authTokenResponse struct {
296 Token string `json:"token"`
297 }
298
299 var unlockAuthTokenResponse authTokenResponse
300 err = json.Unmarshal(body, &unlockAuthTokenResponse)
301 require.NoError(t, err)
302 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
303
304 req2 := httptest.NewRequest(http.MethodGet, "/api/apps", nil)
305 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
306 rec2 := httptest.NewRecorder()
307 e.ServeHTTP(rec2, req2)
308
309 assert.Equal(t, http.StatusOK, rec2.Code)
310 }
311
312 func TestGetApps_FullPermission(t *testing.T) {
313 e := echo.New()
314 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
315 mockSvc := mocks.NewMockService(t)
316 gormDb, err := db.NewDB(t)
317 require.NoError(t, err)
318 defer db.CloseDB(gormDb)
319
320 mockEventPublisher := events.NewEventPublisher()
321
322 mockConfig := mocks.NewMockConfig(t)
323 mockConfig.On("GetEnv").Return(&config.AppConfig{})
324 mockConfig.On("CheckUnlockPassword", "123").Return(true)
325 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
326
327 mockSvc.On("GetDB").Return(gormDb)
328 mockSvc.On("GetConfig").Return(mockConfig)
329 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
330 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
331 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
332 lnClient := mocks.NewMockLNClient(t)
333 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
334 mockSvc.On("GetLNClient").Return(lnClient)
335
336 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
337 httpSvc.RegisterSharedRoutes(e)
338
339 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
340 jsonBody, _ := json.Marshal(requestBody)
341 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
342 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
343 rec := httptest.NewRecorder()
344 e.ServeHTTP(rec, req)
345
346 assert.Equal(t, http.StatusOK, rec.Code)
347
348 body, err := io.ReadAll(rec.Body)
349 require.NoError(t, err)
350
351 type authTokenResponse struct {
352 Token string `json:"token"`
353 }
354
355 var unlockAuthTokenResponse authTokenResponse
356 err = json.Unmarshal(body, &unlockAuthTokenResponse)
357 require.NoError(t, err)
358 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
359
360 req2 := httptest.NewRequest(http.MethodGet, "/api/apps", nil)
361 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
362 rec2 := httptest.NewRecorder()
363 e.ServeHTTP(rec2, req2)
364
365 assert.Equal(t, http.StatusOK, rec2.Code)
366 }
367
368 func TestCreateApp_NoToken(t *testing.T) {
369 e := echo.New()
370 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
371 mockSvc := mocks.NewMockService(t)
372 gormDb, err := db.NewDB(t)
373 require.NoError(t, err)
374 defer db.CloseDB(gormDb)
375
376 mockEventPublisher := mocks.NewMockEventPublisher(t)
377
378 mockConfig := mocks.NewMockConfig(t)
379 mockConfig.On("GetEnv").Return(&config.AppConfig{})
380
381 mockSvc.On("GetDB").Return(gormDb)
382 mockSvc.On("GetConfig").Return(mockConfig)
383 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
384 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
385 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
386
387 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
388 httpSvc.RegisterSharedRoutes(e)
389
390 requestBody := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
391 jsonBody, _ := json.Marshal(requestBody)
392 req := httptest.NewRequest(http.MethodPost, "/api/apps", bytes.NewBuffer(jsonBody))
393 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
394 rec := httptest.NewRecorder()
395 e.ServeHTTP(rec, req)
396
397 assert.Equal(t, http.StatusUnauthorized, rec.Code)
398 }
399
400 func TestCreateApp_FullPermission(t *testing.T) {
401 e := echo.New()
402 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
403 mockSvc := mocks.NewMockService(t)
404 gormDb, err := db.NewDB(t)
405 require.NoError(t, err)
406 defer db.CloseDB(gormDb)
407
408 mockEventPublisher := events.NewEventPublisher()
409
410 mockConfig := mocks.NewMockConfig(t)
411 mockConfig.On("GetEnv").Return(&config.AppConfig{})
412 mockConfig.On("CheckUnlockPassword", "123").Return(true)
413 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
414 mockConfig.On("GetRelayUrls").Return([]string{})
415
416 mockKeys := mocks.NewMockKeys(t)
417 mockKeys.On("GetAppWalletKey", uint(1)).Return("", nil)
418
419 mockAlbyOAuthService := mocks.NewMockAlbyOAuthService(t)
420 mockAlbyOAuthService.On("GetLightningAddress").Return("", nil)
421
422 mockSvc.On("GetDB").Return(gormDb)
423 mockSvc.On("GetConfig").Return(mockConfig)
424 mockSvc.On("GetKeys").Return(mockKeys)
425 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
426 mockSvc.On("GetAlbyOAuthSvc").Return(mockAlbyOAuthService)
427 lnClient := mocks.NewMockLNClient(t)
428 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
429 mockSvc.On("GetLNClient").Return(lnClient)
430
431 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
432 httpSvc.RegisterSharedRoutes(e)
433
434 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
435 jsonBody, _ := json.Marshal(requestBody)
436 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
437 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
438 rec := httptest.NewRecorder()
439 e.ServeHTTP(rec, req)
440
441 assert.Equal(t, http.StatusOK, rec.Code)
442
443 body, err := io.ReadAll(rec.Body)
444 require.NoError(t, err)
445
446 type authTokenResponse struct {
447 Token string `json:"token"`
448 }
449
450 var unlockAuthTokenResponse authTokenResponse
451 err = json.Unmarshal(body, &unlockAuthTokenResponse)
452 require.NoError(t, err)
453 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
454
455 requestBody2 := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
456 jsonBody2, _ := json.Marshal(requestBody2)
457 req2 := httptest.NewRequest(http.MethodPost, "/api/apps", bytes.NewBuffer(jsonBody2))
458 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
459 req2.Header.Set("Content-Type", "application/json") // Set Content-Type header
460
461 rec2 := httptest.NewRecorder()
462 e.ServeHTTP(rec2, req2)
463
464 assert.Equal(t, http.StatusOK, rec2.Code)
465 }
466
467 func TestCreateApp_ReadonlyPermission(t *testing.T) {
468 e := echo.New()
469 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
470 mockSvc := mocks.NewMockService(t)
471 gormDb, err := db.NewDB(t)
472 require.NoError(t, err)
473 defer db.CloseDB(gormDb)
474
475 mockEventPublisher := events.NewEventPublisher()
476
477 mockConfig := mocks.NewMockConfig(t)
478 mockConfig.On("GetEnv").Return(&config.AppConfig{})
479 mockConfig.On("CheckUnlockPassword", "123").Return(true)
480 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
481
482 mockKeys := mocks.NewMockKeys(t)
483
484 mockAlbyOAuthService := mocks.NewMockAlbyOAuthService(t)
485
486 mockSvc.On("GetDB").Return(gormDb)
487 mockSvc.On("GetConfig").Return(mockConfig)
488 mockSvc.On("GetKeys").Return(mockKeys)
489 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
490 mockSvc.On("GetAlbyOAuthSvc").Return(mockAlbyOAuthService)
491 lnClient := mocks.NewMockLNClient(t)
492 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
493 mockSvc.On("GetLNClient").Return(lnClient)
494
495 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
496 httpSvc.RegisterSharedRoutes(e)
497
498 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "readonly"}
499 jsonBody, _ := json.Marshal(requestBody)
500 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
501 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
502 rec := httptest.NewRecorder()
503 e.ServeHTTP(rec, req)
504
505 assert.Equal(t, http.StatusOK, rec.Code)
506
507 body, err := io.ReadAll(rec.Body)
508 require.NoError(t, err)
509
510 type authTokenResponse struct {
511 Token string `json:"token"`
512 }
513
514 var unlockAuthTokenResponse authTokenResponse
515 err = json.Unmarshal(body, &unlockAuthTokenResponse)
516 require.NoError(t, err)
517 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
518
519 requestBody2 := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
520 jsonBody2, _ := json.Marshal(requestBody2)
521 req2 := httptest.NewRequest(http.MethodPost, "/api/apps", bytes.NewBuffer(jsonBody2))
522 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
523 req2.Header.Set("Content-Type", "application/json") // Set Content-Type header
524
525 rec2 := httptest.NewRecorder()
526 e.ServeHTTP(rec2, req2)
527
528 assert.Equal(t, http.StatusForbidden, rec2.Code)
529 }
530
531 func TestGetLogOutput_ReadonlyPermission(t *testing.T) {
532 e := echo.New()
533 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
534 mockSvc := mocks.NewMockService(t)
535 gormDb, err := db.NewDB(t)
536 require.NoError(t, err)
537 defer db.CloseDB(gormDb)
538
539 mockEventPublisher := events.NewEventPublisher()
540
541 mockConfig := mocks.NewMockConfig(t)
542 mockConfig.On("GetEnv").Return(&config.AppConfig{})
543 mockConfig.On("CheckUnlockPassword", "123").Return(true)
544 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
545
546 mockSvc.On("GetDB").Return(gormDb)
547 mockSvc.On("GetConfig").Return(mockConfig)
548 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
549 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
550 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
551 lnClient := mocks.NewMockLNClient(t)
552 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
553 mockSvc.On("GetLNClient").Return(lnClient)
554
555 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
556 httpSvc.RegisterSharedRoutes(e)
557
558 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "readonly"}
559 jsonBody, _ := json.Marshal(requestBody)
560 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
561 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
562 rec := httptest.NewRecorder()
563 e.ServeHTTP(rec, req)
564
565 assert.Equal(t, http.StatusOK, rec.Code)
566
567 body, err := io.ReadAll(rec.Body)
568 require.NoError(t, err)
569
570 type authTokenResponse struct {
571 Token string `json:"token"`
572 }
573
574 var unlockAuthTokenResponse authTokenResponse
575 err = json.Unmarshal(body, &unlockAuthTokenResponse)
576 require.NoError(t, err)
577 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
578
579 req2 := httptest.NewRequest(http.MethodGet, "/api/log/app", nil)
580 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
581 rec2 := httptest.NewRecorder()
582 e.ServeHTTP(rec2, req2)
583
584 assert.Equal(t, http.StatusForbidden, rec2.Code)
585 }
586
587 func TestGetLogOutput_FullPermission(t *testing.T) {
588 e := echo.New()
589 logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
590 mockSvc := mocks.NewMockService(t)
591 gormDb, err := db.NewDB(t)
592 require.NoError(t, err)
593 defer db.CloseDB(gormDb)
594
595 mockEventPublisher := events.NewEventPublisher()
596
597 mockConfig := mocks.NewMockConfig(t)
598 mockConfig.On("GetEnv").Return(&config.AppConfig{})
599 mockConfig.On("CheckUnlockPassword", "123").Return(true)
600 mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
601
602 mockSvc.On("GetDB").Return(gormDb)
603 mockSvc.On("GetConfig").Return(mockConfig)
604 mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
605 mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
606 mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
607 lnClient := mocks.NewMockLNClient(t)
608 lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
609 mockSvc.On("GetLNClient").Return(lnClient)
610
611 httpSvc := NewHttpService(mockSvc, mockEventPublisher)
612 httpSvc.RegisterSharedRoutes(e)
613
614 requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
615 jsonBody, _ := json.Marshal(requestBody)
616 req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
617 req.Header.Set("Content-Type", "application/json") // Set Content-Type header
618 rec := httptest.NewRecorder()
619 e.ServeHTTP(rec, req)
620
621 assert.Equal(t, http.StatusOK, rec.Code)
622
623 body, err := io.ReadAll(rec.Body)
624 require.NoError(t, err)
625
626 type authTokenResponse struct {
627 Token string `json:"token"`
628 }
629
630 var unlockAuthTokenResponse authTokenResponse
631 err = json.Unmarshal(body, &unlockAuthTokenResponse)
632 require.NoError(t, err)
633 assert.NotEmpty(t, unlockAuthTokenResponse.Token)
634
635 req2 := httptest.NewRequest(http.MethodGet, "/api/log/app", nil)
636 req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
637 rec2 := httptest.NewRecorder()
638 e.ServeHTTP(rec2, req2)
639
640 assert.Equal(t, http.StatusOK, rec2.Code)
641
642 var logResponse api.GetLogOutputResponse
643 err = json.Unmarshal(rec2.Body.Bytes(), &logResponse)
644 require.NoError(t, err)
645 }
646