alby-hub/http/http_service_test.go
Roland 363c22f6d3
Some checks are pending
Multiplatform Docker build & push / build (push) Waiting to run
Code quality - linting and typechecking / linting (push) Waiting to run
Backend testing with Postgres / test-postgres (push) Waiting to run
fix: switch unlock rate limiter from per-IP to global (#2540)
The unlock endpoints were rate limited per client IP, which is derived
from request headers and so is chosen by the caller. Switch to a single
global rate limiter (one bucket for all callers) and apply it to every
endpoint that verifies the unlock password: start, unlock, backup,
mnemonic, apps, autoswap, unlock-password and auto-unlock. A small burst
keeps unlocking and immediately performing an action working.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 16:25:56 +07:00

645 lines
22 KiB
Go

package http
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/getAlby/hub/api"
"github.com/getAlby/hub/config"
"github.com/getAlby/hub/constants"
"github.com/getAlby/hub/events"
"github.com/getAlby/hub/lnclient"
"github.com/getAlby/hub/logger"
"github.com/getAlby/hub/tests/db"
"github.com/getAlby/hub/tests/mocks"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestUnlock_IncorrectPassword(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(false)
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))
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.StatusUnauthorized, rec.Code)
mockConfig.AssertNotCalled(t, "GetJWTSecret")
}
func TestUnlock_UnknownPermission(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)
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))
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
httpSvc.RegisterSharedRoutes(e)
requestBody := api.UnlockRequest{UnlockPassword: "123", Permission: "unknown"}
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.StatusBadRequest, rec.Code)
mockConfig.AssertNotCalled(t, "GetJWTSecret")
}
// TestUnlock_RateLimited verifies that repeated requests to an unlock-password
// endpoint are throttled with HTTP 429 once the limit is exceeded.
func TestUnlock_RateLimited(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", "wrong").Return(false)
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))
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
httpSvc.RegisterSharedRoutes(e)
jsonBody, _ := json.Marshal(api.UnlockRequest{UnlockPassword: "wrong", Permission: "full"})
send := func() int {
req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)
return rec.Code
}
// the burst of 2 is served (wrong password, so unauthorized)
assert.Equal(t, http.StatusUnauthorized, send())
assert.Equal(t, http.StatusUnauthorized, send())
// the next request exceeds the limit and is rejected with 429
assert.Equal(t, http.StatusTooManyRequests, send())
}
// TestUnlock_RateLimitNotBypassedBySpoofedIP verifies that the unlock rate
// limiter is global rather than per-IP: varying the X-Forwarded-For header per
// request does not grant each request a fresh bucket.
func TestUnlock_RateLimitNotBypassedBySpoofedIP(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", "wrong").Return(false)
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))
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
httpSvc.RegisterSharedRoutes(e)
jsonBody, _ := json.Marshal(api.UnlockRequest{UnlockPassword: "wrong", Permission: "full"})
send := func(forwardedFor string) int {
req := httptest.NewRequest(http.MethodPost, "/api/unlock", bytes.NewBuffer(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Forwarded-For", forwardedFor)
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)
return rec.Code
}
rateLimited := 0
for i := 0; i < 12; i++ {
// each request presents a distinct client address
if send("10.0.0."+strconv.Itoa(i)) == http.StatusTooManyRequests {
rateLimited++
}
}
assert.Positive(t, rateLimited, "spoofing X-Forwarded-For must not grant a fresh rate-limit bucket")
}
func TestGetApps_NoToken(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 := mocks.NewMockEventPublisher(t)
mockConfig := mocks.NewMockConfig(t)
mockConfig.On("GetEnv").Return(&config.AppConfig{})
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))
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
httpSvc.RegisterSharedRoutes(e)
req := httptest.NewRequest(http.MethodGet, "/api/apps", nil)
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)
assert.Equal(t, http.StatusUnauthorized, rec.Code)
}
func TestUnlock_NodeNotStarted(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)
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))
mockSvc.On("GetLNClient").Return(nil)
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")
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)
assert.Equal(t, http.StatusBadRequest, rec.Code)
body, err := io.ReadAll(rec.Body)
require.NoError(t, err)
var response ErrorResponse
err = json.Unmarshal(body, &response)
require.NoError(t, err)
assert.Equal(t, "Node is not running, start it before unlocking.", response.Message)
mockConfig.AssertNotCalled(t, "GetJWTSecret")
}
func TestGetApps_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/apps", nil)
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
rec2 := httptest.NewRecorder()
e.ServeHTTP(rec2, req2)
assert.Equal(t, http.StatusOK, rec2.Code)
}
func TestGetApps_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/apps", nil)
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
rec2 := httptest.NewRecorder()
e.ServeHTTP(rec2, req2)
assert.Equal(t, http.StatusOK, rec2.Code)
}
func TestCreateApp_NoToken(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 := mocks.NewMockEventPublisher(t)
mockConfig := mocks.NewMockConfig(t)
mockConfig.On("GetEnv").Return(&config.AppConfig{})
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))
httpSvc := NewHttpService(mockSvc, mockEventPublisher)
httpSvc.RegisterSharedRoutes(e)
requestBody := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
jsonBody, _ := json.Marshal(requestBody)
req := httptest.NewRequest(http.MethodPost, "/api/apps", 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.StatusUnauthorized, rec.Code)
}
func TestCreateApp_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)
mockConfig.On("GetRelayUrls").Return([]string{})
mockKeys := mocks.NewMockKeys(t)
mockKeys.On("GetAppWalletKey", uint(1)).Return("", nil)
mockAlbyOAuthService := mocks.NewMockAlbyOAuthService(t)
mockAlbyOAuthService.On("GetLightningAddress").Return("", nil)
mockSvc.On("GetDB").Return(gormDb)
mockSvc.On("GetConfig").Return(mockConfig)
mockSvc.On("GetKeys").Return(mockKeys)
mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
mockSvc.On("GetAlbyOAuthSvc").Return(mockAlbyOAuthService)
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)
requestBody2 := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
jsonBody2, _ := json.Marshal(requestBody2)
req2 := httptest.NewRequest(http.MethodPost, "/api/apps", bytes.NewBuffer(jsonBody2))
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
req2.Header.Set("Content-Type", "application/json") // Set Content-Type header
rec2 := httptest.NewRecorder()
e.ServeHTTP(rec2, req2)
assert.Equal(t, http.StatusOK, rec2.Code)
}
func TestCreateApp_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)
mockKeys := mocks.NewMockKeys(t)
mockAlbyOAuthService := mocks.NewMockAlbyOAuthService(t)
mockSvc.On("GetDB").Return(gormDb)
mockSvc.On("GetConfig").Return(mockConfig)
mockSvc.On("GetKeys").Return(mockKeys)
mockSvc.On("GetAlbySvc").Return(mocks.NewMockAlbyService(t))
mockSvc.On("GetAlbyOAuthSvc").Return(mockAlbyOAuthService)
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)
requestBody2 := api.CreateAppRequest{Name: "Test app", Scopes: []string{constants.PAY_INVOICE_SCOPE}}
jsonBody2, _ := json.Marshal(requestBody2)
req2 := httptest.NewRequest(http.MethodPost, "/api/apps", bytes.NewBuffer(jsonBody2))
req2.Header.Set("Authorization", "Bearer "+unlockAuthTokenResponse.Token)
req2.Header.Set("Content-Type", "application/json") // Set Content-Type header
rec2 := httptest.NewRecorder()
e.ServeHTTP(rec2, req2)
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)
}