mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
fix: require full access api key for log endpoint (#2537)
Move GET /api/log/:type from the read-only API group to the full-access group, matching /api/swaps/mnemonic. Add tests asserting a readonly token receives 403 from the log endpoint and a full-access token can still read it. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
0c24ab84c1
commit
4c5bef42c6
2 changed files with 117 additions and 1 deletions
|
|
@ -142,7 +142,6 @@ func (httpSvc *HttpService) RegisterSharedRoutes(e *echo.Echo) {
|
|||
readOnlyApiGroup.GET("/transactions/:paymentHash", httpSvc.lookupTransactionHandler)
|
||||
readOnlyApiGroup.GET("/balances", httpSvc.balancesHandler)
|
||||
readOnlyApiGroup.GET("/mempool", httpSvc.mempoolApiHandler)
|
||||
readOnlyApiGroup.GET("/log/:type", httpSvc.getLogOutputHandler)
|
||||
readOnlyApiGroup.GET("/health", httpSvc.healthHandler)
|
||||
readOnlyApiGroup.GET("/commands", httpSvc.getCustomNodeCommandsHandler)
|
||||
readOnlyApiGroup.GET("/swaps", httpSvc.listSwapsHandler)
|
||||
|
|
@ -192,6 +191,7 @@ func (httpSvc *HttpService) RegisterSharedRoutes(e *echo.Echo) {
|
|||
fullAccessApiGroup.POST("/swaps/in", httpSvc.initiateSwapInHandler)
|
||||
fullAccessApiGroup.POST("/swaps/refund", httpSvc.refundSwapHandler)
|
||||
fullAccessApiGroup.GET("/swaps/mnemonic", httpSvc.swapMnemonicHandler)
|
||||
fullAccessApiGroup.GET("/log/:type", httpSvc.getLogOutputHandler)
|
||||
fullAccessApiGroup.POST("/autoswap", httpSvc.enableAutoSwapOutHandler)
|
||||
fullAccessApiGroup.DELETE("/autoswap", httpSvc.disableAutoSwapOutHandler)
|
||||
fullAccessApiGroup.POST("/node/alias", httpSvc.setNodeAliasHandler)
|
||||
|
|
|
|||
|
|
@ -438,3 +438,119 @@ func TestCreateApp_ReadonlyPermission(t *testing.T) {
|
|||
|
||||
assert.Equal(t, http.StatusForbidden, rec2.Code)
|
||||
}
|
||||
|
||||
func TestGetLogOutput_ReadonlyPermission(t *testing.T) {
|
||||
e := echo.New()
|
||||
logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
|
||||
mockSvc := mocks.NewMockService(t)
|
||||
gormDb, err := db.NewDB(t)
|
||||
require.NoError(t, err)
|
||||
defer db.CloseDB(gormDb)
|
||||
|
||||
mockEventPublisher := events.NewEventPublisher()
|
||||
|
||||
mockConfig := mocks.NewMockConfig(t)
|
||||
mockConfig.On("GetEnv").Return(&config.AppConfig{})
|
||||
mockConfig.On("CheckUnlockPassword", "123").Return(true)
|
||||
mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
|
||||
|
||||
mockSvc.On("GetDB").Return(gormDb)
|
||||
mockSvc.On("GetConfig").Return(mockConfig)
|
||||
mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
|
||||
mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
|
||||
mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
|
||||
lnClient := mocks.NewMockLNClient(t)
|
||||
lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
|
||||
mockSvc.On("GetLNClient").Return(lnClient)
|
||||
|
||||
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
|
||||
httpSvc.RegisterSharedRoutes(e)
|
||||
|
||||
requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "readonly"}
|
||||
jsonBody, _ := json.Marshal(requestBody)
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
|
||||
req.Header.Set("Content-Type", "application/json") // Set Content-Type header
|
||||
rec := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
body, err := io.ReadAll(rec.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
type authTokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
var unlockAuthTokenResponse authTokenResponse
|
||||
err = json.Unmarshal(body, &unlockAuthTokenResponse)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, unlockAuthTokenResponse.Token)
|
||||
|
||||
req2 := httptest.NewRequest(http.MethodGet, "/api/log/app", nil)
|
||||
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
|
||||
rec2 := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec2, req2)
|
||||
|
||||
assert.Equal(t, http.StatusForbidden, rec2.Code)
|
||||
}
|
||||
|
||||
func TestGetLogOutput_FullPermission(t *testing.T) {
|
||||
e := echo.New()
|
||||
logger.Init(strconv.Itoa(int(logrus.DebugLevel)))
|
||||
mockSvc := mocks.NewMockService(t)
|
||||
gormDb, err := db.NewDB(t)
|
||||
require.NoError(t, err)
|
||||
defer db.CloseDB(gormDb)
|
||||
|
||||
mockEventPublisher := events.NewEventPublisher()
|
||||
|
||||
mockConfig := mocks.NewMockConfig(t)
|
||||
mockConfig.On("GetEnv").Return(&config.AppConfig{})
|
||||
mockConfig.On("CheckUnlockPassword", "123").Return(true)
|
||||
mockConfig.On("GetJWTSecret").Return("dummy secret", nil)
|
||||
|
||||
mockSvc.On("GetDB").Return(gormDb)
|
||||
mockSvc.On("GetConfig").Return(mockConfig)
|
||||
mockSvc.On("GetKeys").Return(mocks.NewMockKeys(t))
|
||||
mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
|
||||
mockSvc.On("GetAlbyOAuthSvc").Return(mocks.NewMockAlbyOAuthService(t))
|
||||
lnClient := mocks.NewMockLNClient(t)
|
||||
lnClient.On("GetNodeStatus", mock.Anything).Return(&lnclient.NodeStatus{}, nil)
|
||||
mockSvc.On("GetLNClient").Return(lnClient)
|
||||
|
||||
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
|
||||
httpSvc.RegisterSharedRoutes(e)
|
||||
|
||||
requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "full"}
|
||||
jsonBody, _ := json.Marshal(requestBody)
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
|
||||
req.Header.Set("Content-Type", "application/json") // Set Content-Type header
|
||||
rec := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
body, err := io.ReadAll(rec.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
type authTokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
var unlockAuthTokenResponse authTokenResponse
|
||||
err = json.Unmarshal(body, &unlockAuthTokenResponse)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, unlockAuthTokenResponse.Token)
|
||||
|
||||
req2 := httptest.NewRequest(http.MethodGet, "/api/log/app", nil)
|
||||
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
|
||||
rec2 := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec2, req2)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec2.Code)
|
||||
|
||||
var logResponse api.GetLogOutputResponse
|
||||
err = json.Unmarshal(rec2.Body.Bytes(), &logResponse)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue