mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
feat: read only JWT for http api use (#1717)
* feat: read only JWT for http api use * fix: pass permission to start and unlock endpoints * chore: add http service JWT tests * chore: update mocks * fix: close db in tests
This commit is contained in:
parent
a294e1b169
commit
595361df27
12 changed files with 2384 additions and 85 deletions
|
|
@ -12,3 +12,13 @@ packages:
|
|||
github.com/getAlby/hub/service:
|
||||
interfaces:
|
||||
Service: {}
|
||||
github.com/getAlby/hub/service/keys:
|
||||
interfaces:
|
||||
Keys: {}
|
||||
github.com/getAlby/hub/alby:
|
||||
interfaces:
|
||||
AlbyService: {}
|
||||
AlbyOAuthService: {}
|
||||
github.com/getAlby/hub/events:
|
||||
interfaces:
|
||||
EventPublisher: {}
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ type StartRequest struct {
|
|||
type UnlockRequest struct {
|
||||
UnlockPassword string `json:"unlockPassword"`
|
||||
TokenExpiryDays *uint64 `json:"tokenExpiryDays"`
|
||||
Permission string `json:"permission,omitempty"` // "full" or "readonly"
|
||||
}
|
||||
|
||||
type BackupReminderRequest struct {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export default function Start() {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
unlockPassword,
|
||||
permission: "full",
|
||||
}),
|
||||
});
|
||||
if (authTokenResponse) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export default function Unlock() {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
unlockPassword,
|
||||
permission: "full",
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { ExternalLinkButton } from "src/components/ui/custom/external-link-butto
|
|||
import { LoadingButton } from "src/components/ui/custom/loading-button";
|
||||
import { Input } from "src/components/ui/input";
|
||||
import { Label } from "src/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "src/components/ui/radio-group";
|
||||
import { Separator } from "src/components/ui/separator";
|
||||
import { useAlbyMe } from "src/hooks/useAlbyMe";
|
||||
import { copyToClipboard } from "src/lib/clipboard";
|
||||
|
|
@ -17,8 +18,12 @@ import { request } from "src/utils/request";
|
|||
export default function DeveloperSettings() {
|
||||
const { data: albyMe } = useAlbyMe();
|
||||
const [token, setToken] = React.useState<string>();
|
||||
const [tokenPermission, setTokenPermission] = React.useState<string>();
|
||||
const [expiryDays, setExpiryDays] = React.useState<string>("365");
|
||||
const [unlockPassword, setUnlockPassword] = React.useState<string>("");
|
||||
const [permission, setPermission] = React.useState<"full" | "readonly">(
|
||||
"full"
|
||||
);
|
||||
const [showCreateTokenForm, setShowCreateTokenForm] =
|
||||
React.useState<boolean>();
|
||||
const [loading, setLoading] = React.useState<boolean>();
|
||||
|
|
@ -27,7 +32,7 @@ export default function DeveloperSettings() {
|
|||
e.preventDefault();
|
||||
try {
|
||||
setLoading(true);
|
||||
if (!expiryDays || !unlockPassword) {
|
||||
if (!expiryDays || !unlockPassword || !permission) {
|
||||
throw new Error("Form not filled");
|
||||
}
|
||||
const authTokenResponse = await request<AuthTokenResponse>(
|
||||
|
|
@ -40,11 +45,13 @@ export default function DeveloperSettings() {
|
|||
body: JSON.stringify({
|
||||
unlockPassword,
|
||||
tokenExpiryDays: +expiryDays,
|
||||
permission,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (authTokenResponse) {
|
||||
setToken(authTokenResponse.token);
|
||||
setTokenPermission(permission);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
@ -113,14 +120,55 @@ export default function DeveloperSettings() {
|
|||
className="w-full md:w-96 flex flex-col gap-4"
|
||||
>
|
||||
<>
|
||||
<div className="grid gap-3">
|
||||
<Label>Token Type</Label>
|
||||
<RadioGroup
|
||||
value={permission}
|
||||
onValueChange={(v) => {
|
||||
if (v != "readonly" && v !== "full") {
|
||||
throw new Error("Unknown permission type");
|
||||
}
|
||||
setPermission(v);
|
||||
}}
|
||||
className="mt-4 gap-4"
|
||||
>
|
||||
<div className="flex items-start space-x-2">
|
||||
<RadioGroupItem value="full" id="full" />
|
||||
<Label
|
||||
htmlFor="full"
|
||||
className="flex-1 flex flex-col justify-center items-start cursor-pointer"
|
||||
>
|
||||
<div className="font-medium shrink-0">Full Access</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Complete control over your hub - can read data and
|
||||
perform all operations (send payments, manage apps,
|
||||
etc.)
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-start space-x-2">
|
||||
<RadioGroupItem value="readonly" id="readonly" />
|
||||
<Label
|
||||
htmlFor="readonly"
|
||||
className="flex-1 flex flex-col justify-center items-start cursor-pointer"
|
||||
>
|
||||
<div className="font-medium">Read-Only Access</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
View-only access - can read balances, transactions, and
|
||||
other data but cannot perform operations
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Token Expiry (Days)</Label>
|
||||
<Label htmlFor="token-expiry">Token Expiry (Days)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
name="token-expiry"
|
||||
id="token-expiry"
|
||||
onChange={(e) => setExpiryDays(e.target.value)}
|
||||
value={expiryDays}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
|
|
@ -129,6 +177,7 @@ export default function DeveloperSettings() {
|
|||
id="password"
|
||||
onChange={setUnlockPassword}
|
||||
value={unlockPassword}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
|
|
@ -184,10 +233,20 @@ export default function DeveloperSettings() {
|
|||
</div>
|
||||
|
||||
<p className="text-xs">
|
||||
This token grants full access to your hub. Please keep it secure.
|
||||
{tokenPermission === "readonly" ? (
|
||||
<>
|
||||
This is a read-only token that can view data but cannot
|
||||
perform operations like sending payments. Please keep it
|
||||
secure.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
This token grants full access to your hub. Please keep it
|
||||
secure.
|
||||
</>
|
||||
)}{" "}
|
||||
If you suspect that the token has been compromised, immediately
|
||||
change your JWT_SECRET environment variable or contact
|
||||
support@getalby.com.
|
||||
change your unlock password.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -28,16 +28,16 @@ func NewAlbyHttpService(svc service.Service, albySvc alby.AlbyService, albyOAuth
|
|||
}
|
||||
}
|
||||
|
||||
func (albyHttpSvc *AlbyHttpService) RegisterSharedRoutes(restrictedApiGroup *echo.Group, e *echo.Echo) {
|
||||
func (albyHttpSvc *AlbyHttpService) RegisterSharedRoutes(readOnlyApiGroup *echo.Group, fullAccessApiGroup *echo.Group, e *echo.Echo) {
|
||||
e.GET("/api/alby/callback", albyHttpSvc.albyCallbackHandler)
|
||||
e.GET("/api/alby/info", albyHttpSvc.albyInfoHandler)
|
||||
e.GET("/api/alby/rates", albyHttpSvc.albyBitcoinRateHandler)
|
||||
restrictedApiGroup.GET("/alby/me", albyHttpSvc.albyMeHandler)
|
||||
restrictedApiGroup.GET("/alby/balance", albyHttpSvc.albyBalanceHandler)
|
||||
restrictedApiGroup.POST("/alby/pay", albyHttpSvc.albyPayHandler)
|
||||
restrictedApiGroup.POST("/alby/link-account", albyHttpSvc.albyLinkAccountHandler)
|
||||
restrictedApiGroup.POST("/alby/auto-channel", albyHttpSvc.autoChannelHandler)
|
||||
restrictedApiGroup.POST("/alby/unlink-account", albyHttpSvc.unlinkHandler)
|
||||
readOnlyApiGroup.GET("/alby/me", albyHttpSvc.albyMeHandler)
|
||||
readOnlyApiGroup.GET("/alby/balance", albyHttpSvc.albyBalanceHandler)
|
||||
fullAccessApiGroup.POST("/alby/pay", albyHttpSvc.albyPayHandler)
|
||||
fullAccessApiGroup.POST("/alby/link-account", albyHttpSvc.albyLinkAccountHandler)
|
||||
fullAccessApiGroup.POST("/alby/auto-channel", albyHttpSvc.autoChannelHandler)
|
||||
fullAccessApiGroup.POST("/alby/unlink-account", albyHttpSvc.unlinkHandler)
|
||||
}
|
||||
|
||||
func (albyHttpSvc *AlbyHttpService) autoChannelHandler(c echo.Context) error {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -35,6 +36,7 @@ type jwtCustomClaims struct {
|
|||
// we can add extra claims here
|
||||
// Name string `json:"name"`
|
||||
// Admin bool `json:"admin"`
|
||||
Permission string `json:"permission,omitempty"` // "full" or "readonly"
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +51,7 @@ type HttpService struct {
|
|||
|
||||
func NewHttpService(svc service.Service, eventPublisher events.EventPublisher) *HttpService {
|
||||
return &HttpService{
|
||||
api: api.NewAPI(svc, svc.GetDB(), svc.GetConfig(), svc.GetKeys(), svc.GetAlbySvc(), svc.GetAlbyOAuthSvc(), svc.GetEventPublisher()),
|
||||
api: api.NewAPI(svc, svc.GetDB(), svc.GetConfig(), svc.GetKeys(), svc.GetAlbySvc(), svc.GetAlbyOAuthSvc(), eventPublisher),
|
||||
albyHttpSvc: NewAlbyHttpService(svc, svc.GetAlbySvc(), svc.GetAlbyOAuthSvc(), svc.GetConfig().GetEnv()),
|
||||
cfg: svc.GetConfig(),
|
||||
eventPublisher: eventPublisher,
|
||||
|
|
@ -116,75 +118,82 @@ func (httpSvc *HttpService) RegisterSharedRoutes(e *echo.Echo) {
|
|||
return []byte(httpSvc.cfg.GetJWTSecret()), nil
|
||||
},
|
||||
}
|
||||
restrictedApiGroup := e.Group("/api")
|
||||
restrictedApiGroup.Use(echojwt.WithConfig(jwtConfig))
|
||||
// Read-only API group - accessible to both full and readonly tokens
|
||||
readOnlyApiGroup := e.Group("/api")
|
||||
readOnlyApiGroup.Use(echojwt.WithConfig(jwtConfig))
|
||||
|
||||
restrictedApiGroup.PATCH("/unlock-password", httpSvc.changeUnlockPasswordHandler)
|
||||
restrictedApiGroup.PATCH("/auto-unlock", httpSvc.autoUnlockHandler)
|
||||
restrictedApiGroup.PATCH("/settings", httpSvc.updateSettingsHandler)
|
||||
restrictedApiGroup.GET("/apps", httpSvc.appsListHandler)
|
||||
restrictedApiGroup.GET("/apps/:pubkey", httpSvc.appsShowByPubkeyHandler)
|
||||
restrictedApiGroup.GET("/v2/apps/:id", httpSvc.appsShowHandler)
|
||||
restrictedApiGroup.PATCH("/apps/:pubkey", httpSvc.appsUpdateHandler)
|
||||
restrictedApiGroup.DELETE("/apps/:pubkey", httpSvc.appsDeleteHandler)
|
||||
restrictedApiGroup.POST("/transfers", httpSvc.transfersHandler)
|
||||
restrictedApiGroup.POST("/apps", httpSvc.appsCreateHandler)
|
||||
restrictedApiGroup.POST("/lightning-addresses", httpSvc.lightningAddressesCreateHandler)
|
||||
restrictedApiGroup.DELETE("/lightning-addresses/:appId", httpSvc.lightningAddressesDeleteHandler)
|
||||
restrictedApiGroup.POST("/mnemonic", httpSvc.mnemonicHandler)
|
||||
restrictedApiGroup.PATCH("/backup-reminder", httpSvc.backupReminderHandler)
|
||||
restrictedApiGroup.GET("/channels", httpSvc.channelsListHandler)
|
||||
restrictedApiGroup.POST("/channels", httpSvc.openChannelHandler)
|
||||
restrictedApiGroup.POST("/channels/rebalance", httpSvc.rebalanceChannelHandler)
|
||||
restrictedApiGroup.GET("/channels/suggestions", httpSvc.channelPeerSuggestionsHandler)
|
||||
restrictedApiGroup.GET("/channel-offer", httpSvc.channelOfferHandler)
|
||||
restrictedApiGroup.POST("/lsp-orders", httpSvc.newInstantChannelInvoiceHandler)
|
||||
restrictedApiGroup.GET("/node/connection-info", httpSvc.nodeConnectionInfoHandler)
|
||||
restrictedApiGroup.GET("/node/status", httpSvc.nodeStatusHandler)
|
||||
restrictedApiGroup.GET("/node/network-graph", httpSvc.nodeNetworkGraphHandler)
|
||||
restrictedApiGroup.POST("/node/migrate-storage", httpSvc.migrateNodeStorageHandler)
|
||||
restrictedApiGroup.GET("/node/transactions", httpSvc.listOnchainTransactionsHandler)
|
||||
restrictedApiGroup.GET("/peers", httpSvc.listPeers)
|
||||
restrictedApiGroup.POST("/peers", httpSvc.connectPeerHandler)
|
||||
restrictedApiGroup.DELETE("/peers/:peerId", httpSvc.disconnectPeerHandler)
|
||||
restrictedApiGroup.DELETE("/peers/:peerId/channels/:channelId", httpSvc.closeChannelHandler)
|
||||
restrictedApiGroup.PATCH("/peers/:peerId/channels/:channelId", httpSvc.updateChannelHandler)
|
||||
restrictedApiGroup.GET("/wallet/address", httpSvc.onchainAddressHandler)
|
||||
restrictedApiGroup.POST("/wallet/new-address", httpSvc.newOnchainAddressHandler)
|
||||
restrictedApiGroup.POST("/wallet/redeem-onchain-funds", httpSvc.redeemOnchainFundsHandler)
|
||||
restrictedApiGroup.POST("/wallet/sign-message", httpSvc.signMessageHandler)
|
||||
restrictedApiGroup.POST("/wallet/sync", httpSvc.walletSyncHandler)
|
||||
restrictedApiGroup.GET("/wallet/capabilities", httpSvc.capabilitiesHandler)
|
||||
restrictedApiGroup.POST("/payments/:invoice", httpSvc.sendPaymentHandler)
|
||||
restrictedApiGroup.POST("/invoices", httpSvc.makeInvoiceHandler)
|
||||
restrictedApiGroup.POST("/offers", httpSvc.makeOfferHandler)
|
||||
restrictedApiGroup.GET("/transactions", httpSvc.listTransactionsHandler)
|
||||
restrictedApiGroup.GET("/transactions/:paymentHash", httpSvc.lookupTransactionHandler)
|
||||
restrictedApiGroup.GET("/balances", httpSvc.balancesHandler)
|
||||
restrictedApiGroup.POST("/reset-router", httpSvc.resetRouterHandler)
|
||||
restrictedApiGroup.POST("/stop", httpSvc.stopHandler)
|
||||
restrictedApiGroup.GET("/mempool", httpSvc.mempoolApiHandler)
|
||||
restrictedApiGroup.POST("/send-payment-probes", httpSvc.sendPaymentProbesHandler)
|
||||
restrictedApiGroup.POST("/send-spontaneous-payment-probes", httpSvc.sendSpontaneousPaymentProbesHandler)
|
||||
restrictedApiGroup.GET("/log/:type", httpSvc.getLogOutputHandler)
|
||||
restrictedApiGroup.GET("/health", httpSvc.healthHandler)
|
||||
restrictedApiGroup.GET("/commands", httpSvc.getCustomNodeCommandsHandler)
|
||||
restrictedApiGroup.POST("/command", httpSvc.execCustomNodeCommandHandler)
|
||||
restrictedApiGroup.GET("/swaps", httpSvc.listSwapsHandler)
|
||||
restrictedApiGroup.GET("/swaps/:swapId", httpSvc.lookupSwapHandler)
|
||||
restrictedApiGroup.GET("/swaps/out/info", httpSvc.getSwapOutInfoHandler)
|
||||
restrictedApiGroup.GET("/swaps/in/info", httpSvc.getSwapInInfoHandler)
|
||||
restrictedApiGroup.POST("/swaps/out", httpSvc.initiateSwapOutHandler)
|
||||
restrictedApiGroup.POST("/swaps/in", httpSvc.initiateSwapInHandler)
|
||||
restrictedApiGroup.POST("/swaps/refund", httpSvc.refundSwapHandler)
|
||||
restrictedApiGroup.GET("/swaps/mnemonic", httpSvc.swapMnemonicHandler)
|
||||
restrictedApiGroup.GET("/autoswap", httpSvc.getAutoSwapConfigHandler)
|
||||
restrictedApiGroup.POST("/autoswap", httpSvc.enableAutoSwapOutHandler)
|
||||
restrictedApiGroup.DELETE("/autoswap", httpSvc.disableAutoSwapOutHandler)
|
||||
restrictedApiGroup.POST("/node/alias", httpSvc.setNodeAliasHandler)
|
||||
restrictedApiGroup.GET("/forwards", httpSvc.forwardsHandler)
|
||||
readOnlyApiGroup.GET("/apps", httpSvc.appsListHandler)
|
||||
readOnlyApiGroup.GET("/apps/:pubkey", httpSvc.appsShowByPubkeyHandler)
|
||||
readOnlyApiGroup.GET("/v2/apps/:id", httpSvc.appsShowHandler)
|
||||
readOnlyApiGroup.GET("/channels", httpSvc.channelsListHandler)
|
||||
readOnlyApiGroup.GET("/channels/suggestions", httpSvc.channelPeerSuggestionsHandler)
|
||||
readOnlyApiGroup.GET("/channel-offer", httpSvc.channelOfferHandler)
|
||||
readOnlyApiGroup.GET("/node/connection-info", httpSvc.nodeConnectionInfoHandler)
|
||||
readOnlyApiGroup.GET("/node/status", httpSvc.nodeStatusHandler)
|
||||
readOnlyApiGroup.GET("/node/network-graph", httpSvc.nodeNetworkGraphHandler)
|
||||
readOnlyApiGroup.GET("/node/transactions", httpSvc.listOnchainTransactionsHandler)
|
||||
readOnlyApiGroup.GET("/peers", httpSvc.listPeers)
|
||||
readOnlyApiGroup.GET("/wallet/address", httpSvc.onchainAddressHandler)
|
||||
readOnlyApiGroup.GET("/wallet/capabilities", httpSvc.capabilitiesHandler)
|
||||
readOnlyApiGroup.GET("/transactions", httpSvc.listTransactionsHandler)
|
||||
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)
|
||||
readOnlyApiGroup.GET("/swaps/:swapId", httpSvc.lookupSwapHandler)
|
||||
readOnlyApiGroup.GET("/swaps/out/info", httpSvc.getSwapOutInfoHandler)
|
||||
readOnlyApiGroup.GET("/swaps/in/info", httpSvc.getSwapInInfoHandler)
|
||||
readOnlyApiGroup.GET("/swaps/mnemonic", httpSvc.swapMnemonicHandler)
|
||||
readOnlyApiGroup.GET("/autoswap", httpSvc.getAutoSwapConfigHandler)
|
||||
readOnlyApiGroup.GET("/forwards", httpSvc.forwardsHandler)
|
||||
|
||||
httpSvc.albyHttpSvc.RegisterSharedRoutes(restrictedApiGroup, e)
|
||||
// Full access API group - requires a token with full permissions
|
||||
fullAccessApiGroup := e.Group("/api")
|
||||
fullAccessApiGroup.Use(echojwt.WithConfig(jwtConfig))
|
||||
fullAccessApiGroup.Use(httpSvc.requireFullAccess)
|
||||
|
||||
fullAccessApiGroup.PATCH("/unlock-password", httpSvc.changeUnlockPasswordHandler)
|
||||
fullAccessApiGroup.PATCH("/auto-unlock", httpSvc.autoUnlockHandler)
|
||||
fullAccessApiGroup.PATCH("/settings", httpSvc.updateSettingsHandler)
|
||||
fullAccessApiGroup.PATCH("/apps/:pubkey", httpSvc.appsUpdateHandler)
|
||||
fullAccessApiGroup.DELETE("/apps/:pubkey", httpSvc.appsDeleteHandler)
|
||||
fullAccessApiGroup.POST("/transfers", httpSvc.transfersHandler)
|
||||
fullAccessApiGroup.POST("/apps", httpSvc.appsCreateHandler)
|
||||
fullAccessApiGroup.POST("/lightning-addresses", httpSvc.lightningAddressesCreateHandler)
|
||||
fullAccessApiGroup.DELETE("/lightning-addresses/:appId", httpSvc.lightningAddressesDeleteHandler)
|
||||
fullAccessApiGroup.POST("/mnemonic", httpSvc.mnemonicHandler)
|
||||
fullAccessApiGroup.PATCH("/backup-reminder", httpSvc.backupReminderHandler)
|
||||
fullAccessApiGroup.POST("/channels", httpSvc.openChannelHandler)
|
||||
fullAccessApiGroup.POST("/channels/rebalance", httpSvc.rebalanceChannelHandler)
|
||||
fullAccessApiGroup.POST("/lsp-orders", httpSvc.newInstantChannelInvoiceHandler)
|
||||
fullAccessApiGroup.POST("/node/migrate-storage", httpSvc.migrateNodeStorageHandler)
|
||||
fullAccessApiGroup.POST("/peers", httpSvc.connectPeerHandler)
|
||||
fullAccessApiGroup.DELETE("/peers/:peerId", httpSvc.disconnectPeerHandler)
|
||||
fullAccessApiGroup.DELETE("/peers/:peerId/channels/:channelId", httpSvc.closeChannelHandler)
|
||||
fullAccessApiGroup.PATCH("/peers/:peerId/channels/:channelId", httpSvc.updateChannelHandler)
|
||||
fullAccessApiGroup.POST("/wallet/new-address", httpSvc.newOnchainAddressHandler)
|
||||
fullAccessApiGroup.POST("/wallet/redeem-onchain-funds", httpSvc.redeemOnchainFundsHandler)
|
||||
fullAccessApiGroup.POST("/wallet/sign-message", httpSvc.signMessageHandler)
|
||||
fullAccessApiGroup.POST("/wallet/sync", httpSvc.walletSyncHandler)
|
||||
fullAccessApiGroup.POST("/payments/:invoice", httpSvc.sendPaymentHandler)
|
||||
fullAccessApiGroup.POST("/invoices", httpSvc.makeInvoiceHandler)
|
||||
fullAccessApiGroup.POST("/offers", httpSvc.makeOfferHandler)
|
||||
fullAccessApiGroup.POST("/reset-router", httpSvc.resetRouterHandler)
|
||||
fullAccessApiGroup.POST("/stop", httpSvc.stopHandler)
|
||||
fullAccessApiGroup.POST("/send-payment-probes", httpSvc.sendPaymentProbesHandler)
|
||||
fullAccessApiGroup.POST("/send-spontaneous-payment-probes", httpSvc.sendSpontaneousPaymentProbesHandler)
|
||||
fullAccessApiGroup.POST("/command", httpSvc.execCustomNodeCommandHandler)
|
||||
fullAccessApiGroup.POST("/swaps/out", httpSvc.initiateSwapOutHandler)
|
||||
fullAccessApiGroup.POST("/swaps/in", httpSvc.initiateSwapInHandler)
|
||||
fullAccessApiGroup.POST("/swaps/refund", httpSvc.refundSwapHandler)
|
||||
fullAccessApiGroup.POST("/autoswap", httpSvc.enableAutoSwapOutHandler)
|
||||
fullAccessApiGroup.DELETE("/autoswap", httpSvc.disableAutoSwapOutHandler)
|
||||
fullAccessApiGroup.POST("/node/alias", httpSvc.setNodeAliasHandler)
|
||||
|
||||
httpSvc.albyHttpSvc.RegisterSharedRoutes(readOnlyApiGroup, fullAccessApiGroup, e)
|
||||
}
|
||||
|
||||
func (httpSvc *HttpService) infoHandler(c echo.Context) error {
|
||||
|
|
@ -277,7 +286,7 @@ func (httpSvc *HttpService) startHandler(c echo.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
token, err := httpSvc.createJWT(nil)
|
||||
token, err := httpSvc.createJWT(nil, "full")
|
||||
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusInternalServerError, ErrorResponse{
|
||||
|
|
@ -306,7 +315,19 @@ func (httpSvc *HttpService) unlockHandler(c echo.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
token, err := httpSvc.createJWT(unlockRequest.TokenExpiryDays)
|
||||
if unlockRequest.Permission == "" {
|
||||
return c.JSON(http.StatusBadRequest, ErrorResponse{
|
||||
Message: "Permission field is required",
|
||||
})
|
||||
}
|
||||
|
||||
if !slices.Contains([]string{"full", "readonly"}, unlockRequest.Permission) {
|
||||
return c.JSON(http.StatusBadRequest, ErrorResponse{
|
||||
Message: "Permission field is unknown",
|
||||
})
|
||||
}
|
||||
|
||||
token, err := httpSvc.createJWT(unlockRequest.TokenExpiryDays, unlockRequest.Permission)
|
||||
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusInternalServerError, ErrorResponse{
|
||||
|
|
@ -323,6 +344,22 @@ func (httpSvc *HttpService) unlockHandler(c echo.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (httpSvc *HttpService) requireFullAccess(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
token := c.Get("user").(*jwt.Token)
|
||||
claims := token.Claims.(*jwtCustomClaims)
|
||||
|
||||
// Allow if no permission specified (backward compatibility) or if full access
|
||||
if claims.Permission == "" || claims.Permission == "full" {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusForbidden, ErrorResponse{
|
||||
Message: "This operation requires full access permissions",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (httpSvc *HttpService) changeUnlockPasswordHandler(c echo.Context) error {
|
||||
var changeUnlockPasswordRequest api.ChangeUnlockPasswordRequest
|
||||
if err := c.Bind(&changeUnlockPasswordRequest); err != nil {
|
||||
|
|
@ -383,7 +420,11 @@ func (httpSvc *HttpService) autoUnlockHandler(c echo.Context) error {
|
|||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (httpSvc *HttpService) createJWT(tokenExpiryDays *uint64) (string, error) {
|
||||
func (httpSvc *HttpService) createJWT(tokenExpiryDays *uint64, permission string) (string, error) {
|
||||
if !slices.Contains([]string{"full", "readonly"}, permission) {
|
||||
return "", errors.New("invalid token permission")
|
||||
}
|
||||
|
||||
expiryDays := uint64(30)
|
||||
if tokenExpiryDays != nil {
|
||||
expiryDays = *tokenExpiryDays
|
||||
|
|
@ -391,7 +432,8 @@ func (httpSvc *HttpService) createJWT(tokenExpiryDays *uint64) (string, error) {
|
|||
|
||||
// Set custom claims
|
||||
claims := &jwtCustomClaims{
|
||||
jwt.RegisteredClaims{
|
||||
Permission: permission,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * time.Duration(expiryDays))),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
383
http/http_service_test.go
Normal file
383
http/http_service_test.go
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
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/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/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")
|
||||
}
|
||||
|
||||
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.StatusBadRequest, rec.Code)
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
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: "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")
|
||||
|
||||
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.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.StatusBadRequest, 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")
|
||||
mockConfig.On("GetRelayUrl").Return("")
|
||||
|
||||
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)
|
||||
|
||||
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")
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
1004
tests/mocks/AlbyOAuthService.go
Normal file
1004
tests/mocks/AlbyOAuthService.go
Normal file
File diff suppressed because it is too large
Load diff
207
tests/mocks/AlbyService.go
Normal file
207
tests/mocks/AlbyService.go
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/getAlby/hub/alby"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// NewMockAlbyService creates a new instance of MockAlbyService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockAlbyService(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockAlbyService {
|
||||
mock := &MockAlbyService{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// MockAlbyService is an autogenerated mock type for the AlbyService type
|
||||
type MockAlbyService struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockAlbyService_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockAlbyService) EXPECT() *MockAlbyService_Expecter {
|
||||
return &MockAlbyService_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetBitcoinRate provides a mock function for the type MockAlbyService
|
||||
func (_mock *MockAlbyService) GetBitcoinRate(ctx context.Context) (*alby.BitcoinRate, error) {
|
||||
ret := _mock.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetBitcoinRate")
|
||||
}
|
||||
|
||||
var r0 *alby.BitcoinRate
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) (*alby.BitcoinRate, error)); ok {
|
||||
return returnFunc(ctx)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) *alby.BitcoinRate); ok {
|
||||
r0 = returnFunc(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*alby.BitcoinRate)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = returnFunc(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockAlbyService_GetBitcoinRate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBitcoinRate'
|
||||
type MockAlbyService_GetBitcoinRate_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetBitcoinRate is a helper method to define mock.On call
|
||||
// - ctx
|
||||
func (_e *MockAlbyService_Expecter) GetBitcoinRate(ctx interface{}) *MockAlbyService_GetBitcoinRate_Call {
|
||||
return &MockAlbyService_GetBitcoinRate_Call{Call: _e.mock.On("GetBitcoinRate", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetBitcoinRate_Call) Run(run func(ctx context.Context)) *MockAlbyService_GetBitcoinRate_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetBitcoinRate_Call) Return(bitcoinRate *alby.BitcoinRate, err error) *MockAlbyService_GetBitcoinRate_Call {
|
||||
_c.Call.Return(bitcoinRate, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetBitcoinRate_Call) RunAndReturn(run func(ctx context.Context) (*alby.BitcoinRate, error)) *MockAlbyService_GetBitcoinRate_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetChannelPeerSuggestions provides a mock function for the type MockAlbyService
|
||||
func (_mock *MockAlbyService) GetChannelPeerSuggestions(ctx context.Context) ([]alby.ChannelPeerSuggestion, error) {
|
||||
ret := _mock.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetChannelPeerSuggestions")
|
||||
}
|
||||
|
||||
var r0 []alby.ChannelPeerSuggestion
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) ([]alby.ChannelPeerSuggestion, error)); ok {
|
||||
return returnFunc(ctx)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) []alby.ChannelPeerSuggestion); ok {
|
||||
r0 = returnFunc(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]alby.ChannelPeerSuggestion)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = returnFunc(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockAlbyService_GetChannelPeerSuggestions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChannelPeerSuggestions'
|
||||
type MockAlbyService_GetChannelPeerSuggestions_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetChannelPeerSuggestions is a helper method to define mock.On call
|
||||
// - ctx
|
||||
func (_e *MockAlbyService_Expecter) GetChannelPeerSuggestions(ctx interface{}) *MockAlbyService_GetChannelPeerSuggestions_Call {
|
||||
return &MockAlbyService_GetChannelPeerSuggestions_Call{Call: _e.mock.On("GetChannelPeerSuggestions", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetChannelPeerSuggestions_Call) Run(run func(ctx context.Context)) *MockAlbyService_GetChannelPeerSuggestions_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetChannelPeerSuggestions_Call) Return(channelPeerSuggestions []alby.ChannelPeerSuggestion, err error) *MockAlbyService_GetChannelPeerSuggestions_Call {
|
||||
_c.Call.Return(channelPeerSuggestions, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetChannelPeerSuggestions_Call) RunAndReturn(run func(ctx context.Context) ([]alby.ChannelPeerSuggestion, error)) *MockAlbyService_GetChannelPeerSuggestions_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetInfo provides a mock function for the type MockAlbyService
|
||||
func (_mock *MockAlbyService) GetInfo(ctx context.Context) (*alby.AlbyInfo, error) {
|
||||
ret := _mock.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetInfo")
|
||||
}
|
||||
|
||||
var r0 *alby.AlbyInfo
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) (*alby.AlbyInfo, error)); ok {
|
||||
return returnFunc(ctx)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context) *alby.AlbyInfo); ok {
|
||||
r0 = returnFunc(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*alby.AlbyInfo)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = returnFunc(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockAlbyService_GetInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInfo'
|
||||
type MockAlbyService_GetInfo_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetInfo is a helper method to define mock.On call
|
||||
// - ctx
|
||||
func (_e *MockAlbyService_Expecter) GetInfo(ctx interface{}) *MockAlbyService_GetInfo_Call {
|
||||
return &MockAlbyService_GetInfo_Call{Call: _e.mock.On("GetInfo", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetInfo_Call) Run(run func(ctx context.Context)) *MockAlbyService_GetInfo_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetInfo_Call) Return(albyInfo *alby.AlbyInfo, err error) *MockAlbyService_GetInfo_Call {
|
||||
_c.Call.Return(albyInfo, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAlbyService_GetInfo_Call) RunAndReturn(run func(ctx context.Context) (*alby.AlbyInfo, error)) *MockAlbyService_GetInfo_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
208
tests/mocks/EventPublisher.go
Normal file
208
tests/mocks/EventPublisher.go
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"github.com/getAlby/hub/events"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// NewMockEventPublisher creates a new instance of MockEventPublisher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockEventPublisher(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockEventPublisher {
|
||||
mock := &MockEventPublisher{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// MockEventPublisher is an autogenerated mock type for the EventPublisher type
|
||||
type MockEventPublisher struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockEventPublisher_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockEventPublisher) EXPECT() *MockEventPublisher_Expecter {
|
||||
return &MockEventPublisher_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Publish provides a mock function for the type MockEventPublisher
|
||||
func (_mock *MockEventPublisher) Publish(event *events.Event) {
|
||||
_mock.Called(event)
|
||||
return
|
||||
}
|
||||
|
||||
// MockEventPublisher_Publish_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Publish'
|
||||
type MockEventPublisher_Publish_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Publish is a helper method to define mock.On call
|
||||
// - event
|
||||
func (_e *MockEventPublisher_Expecter) Publish(event interface{}) *MockEventPublisher_Publish_Call {
|
||||
return &MockEventPublisher_Publish_Call{Call: _e.mock.On("Publish", event)}
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_Publish_Call) Run(run func(event *events.Event)) *MockEventPublisher_Publish_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(*events.Event))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_Publish_Call) Return() *MockEventPublisher_Publish_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_Publish_Call) RunAndReturn(run func(event *events.Event)) *MockEventPublisher_Publish_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// PublishSync provides a mock function for the type MockEventPublisher
|
||||
func (_mock *MockEventPublisher) PublishSync(event *events.Event) {
|
||||
_mock.Called(event)
|
||||
return
|
||||
}
|
||||
|
||||
// MockEventPublisher_PublishSync_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PublishSync'
|
||||
type MockEventPublisher_PublishSync_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// PublishSync is a helper method to define mock.On call
|
||||
// - event
|
||||
func (_e *MockEventPublisher_Expecter) PublishSync(event interface{}) *MockEventPublisher_PublishSync_Call {
|
||||
return &MockEventPublisher_PublishSync_Call{Call: _e.mock.On("PublishSync", event)}
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_PublishSync_Call) Run(run func(event *events.Event)) *MockEventPublisher_PublishSync_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(*events.Event))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_PublishSync_Call) Return() *MockEventPublisher_PublishSync_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_PublishSync_Call) RunAndReturn(run func(event *events.Event)) *MockEventPublisher_PublishSync_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RegisterSubscriber provides a mock function for the type MockEventPublisher
|
||||
func (_mock *MockEventPublisher) RegisterSubscriber(eventListener events.EventSubscriber) {
|
||||
_mock.Called(eventListener)
|
||||
return
|
||||
}
|
||||
|
||||
// MockEventPublisher_RegisterSubscriber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterSubscriber'
|
||||
type MockEventPublisher_RegisterSubscriber_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RegisterSubscriber is a helper method to define mock.On call
|
||||
// - eventListener
|
||||
func (_e *MockEventPublisher_Expecter) RegisterSubscriber(eventListener interface{}) *MockEventPublisher_RegisterSubscriber_Call {
|
||||
return &MockEventPublisher_RegisterSubscriber_Call{Call: _e.mock.On("RegisterSubscriber", eventListener)}
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RegisterSubscriber_Call) Run(run func(eventListener events.EventSubscriber)) *MockEventPublisher_RegisterSubscriber_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(events.EventSubscriber))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RegisterSubscriber_Call) Return() *MockEventPublisher_RegisterSubscriber_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RegisterSubscriber_Call) RunAndReturn(run func(eventListener events.EventSubscriber)) *MockEventPublisher_RegisterSubscriber_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RemoveSubscriber provides a mock function for the type MockEventPublisher
|
||||
func (_mock *MockEventPublisher) RemoveSubscriber(eventListener events.EventSubscriber) {
|
||||
_mock.Called(eventListener)
|
||||
return
|
||||
}
|
||||
|
||||
// MockEventPublisher_RemoveSubscriber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscriber'
|
||||
type MockEventPublisher_RemoveSubscriber_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RemoveSubscriber is a helper method to define mock.On call
|
||||
// - eventListener
|
||||
func (_e *MockEventPublisher_Expecter) RemoveSubscriber(eventListener interface{}) *MockEventPublisher_RemoveSubscriber_Call {
|
||||
return &MockEventPublisher_RemoveSubscriber_Call{Call: _e.mock.On("RemoveSubscriber", eventListener)}
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RemoveSubscriber_Call) Run(run func(eventListener events.EventSubscriber)) *MockEventPublisher_RemoveSubscriber_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(events.EventSubscriber))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RemoveSubscriber_Call) Return() *MockEventPublisher_RemoveSubscriber_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_RemoveSubscriber_Call) RunAndReturn(run func(eventListener events.EventSubscriber)) *MockEventPublisher_RemoveSubscriber_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetGlobalProperty provides a mock function for the type MockEventPublisher
|
||||
func (_mock *MockEventPublisher) SetGlobalProperty(key string, value interface{}) {
|
||||
_mock.Called(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
// MockEventPublisher_SetGlobalProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetGlobalProperty'
|
||||
type MockEventPublisher_SetGlobalProperty_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SetGlobalProperty is a helper method to define mock.On call
|
||||
// - key
|
||||
// - value
|
||||
func (_e *MockEventPublisher_Expecter) SetGlobalProperty(key interface{}, value interface{}) *MockEventPublisher_SetGlobalProperty_Call {
|
||||
return &MockEventPublisher_SetGlobalProperty_Call{Call: _e.mock.On("SetGlobalProperty", key, value)}
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_SetGlobalProperty_Call) Run(run func(key string, value interface{})) *MockEventPublisher_SetGlobalProperty_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(string), args[1].(interface{}))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_SetGlobalProperty_Call) Return() *MockEventPublisher_SetGlobalProperty_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockEventPublisher_SetGlobalProperty_Call) RunAndReturn(run func(key string, value interface{})) *MockEventPublisher_SetGlobalProperty_Call {
|
||||
_c.Run(run)
|
||||
return _c
|
||||
}
|
||||
383
tests/mocks/Keys.go
Normal file
383
tests/mocks/Keys.go
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/getAlby/hub/config"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
"github.com/tyler-smith/go-bip32"
|
||||
)
|
||||
|
||||
// NewMockKeys creates a new instance of MockKeys. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockKeys(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockKeys {
|
||||
mock := &MockKeys{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// MockKeys is an autogenerated mock type for the Keys type
|
||||
type MockKeys struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockKeys_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockKeys) EXPECT() *MockKeys_Expecter {
|
||||
return &MockKeys_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// DeriveKey provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) DeriveKey(path []uint32) (*bip32.Key, error) {
|
||||
ret := _mock.Called(path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeriveKey")
|
||||
}
|
||||
|
||||
var r0 *bip32.Key
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func([]uint32) (*bip32.Key, error)); ok {
|
||||
return returnFunc(path)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func([]uint32) *bip32.Key); ok {
|
||||
r0 = returnFunc(path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*bip32.Key)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func([]uint32) error); ok {
|
||||
r1 = returnFunc(path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockKeys_DeriveKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeriveKey'
|
||||
type MockKeys_DeriveKey_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeriveKey is a helper method to define mock.On call
|
||||
// - path
|
||||
func (_e *MockKeys_Expecter) DeriveKey(path interface{}) *MockKeys_DeriveKey_Call {
|
||||
return &MockKeys_DeriveKey_Call{Call: _e.mock.On("DeriveKey", path)}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_DeriveKey_Call) Run(run func(path []uint32)) *MockKeys_DeriveKey_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]uint32))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_DeriveKey_Call) Return(key *bip32.Key, err error) *MockKeys_DeriveKey_Call {
|
||||
_c.Call.Return(key, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_DeriveKey_Call) RunAndReturn(run func(path []uint32) (*bip32.Key, error)) *MockKeys_DeriveKey_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetAppWalletKey provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) GetAppWalletKey(childIndex uint) (string, error) {
|
||||
ret := _mock.Called(childIndex)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetAppWalletKey")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(uint) (string, error)); ok {
|
||||
return returnFunc(childIndex)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(uint) string); ok {
|
||||
r0 = returnFunc(childIndex)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(uint) error); ok {
|
||||
r1 = returnFunc(childIndex)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockKeys_GetAppWalletKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAppWalletKey'
|
||||
type MockKeys_GetAppWalletKey_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetAppWalletKey is a helper method to define mock.On call
|
||||
// - childIndex
|
||||
func (_e *MockKeys_Expecter) GetAppWalletKey(childIndex interface{}) *MockKeys_GetAppWalletKey_Call {
|
||||
return &MockKeys_GetAppWalletKey_Call{Call: _e.mock.On("GetAppWalletKey", childIndex)}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetAppWalletKey_Call) Run(run func(childIndex uint)) *MockKeys_GetAppWalletKey_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetAppWalletKey_Call) Return(s string, err error) *MockKeys_GetAppWalletKey_Call {
|
||||
_c.Call.Return(s, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetAppWalletKey_Call) RunAndReturn(run func(childIndex uint) (string, error)) *MockKeys_GetAppWalletKey_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetNostrPublicKey provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) GetNostrPublicKey() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetNostrPublicKey")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockKeys_GetNostrPublicKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNostrPublicKey'
|
||||
type MockKeys_GetNostrPublicKey_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetNostrPublicKey is a helper method to define mock.On call
|
||||
func (_e *MockKeys_Expecter) GetNostrPublicKey() *MockKeys_GetNostrPublicKey_Call {
|
||||
return &MockKeys_GetNostrPublicKey_Call{Call: _e.mock.On("GetNostrPublicKey")}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrPublicKey_Call) Run(run func()) *MockKeys_GetNostrPublicKey_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrPublicKey_Call) Return(s string) *MockKeys_GetNostrPublicKey_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrPublicKey_Call) RunAndReturn(run func() string) *MockKeys_GetNostrPublicKey_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetNostrSecretKey provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) GetNostrSecretKey() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetNostrSecretKey")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockKeys_GetNostrSecretKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNostrSecretKey'
|
||||
type MockKeys_GetNostrSecretKey_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetNostrSecretKey is a helper method to define mock.On call
|
||||
func (_e *MockKeys_Expecter) GetNostrSecretKey() *MockKeys_GetNostrSecretKey_Call {
|
||||
return &MockKeys_GetNostrSecretKey_Call{Call: _e.mock.On("GetNostrSecretKey")}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrSecretKey_Call) Run(run func()) *MockKeys_GetNostrSecretKey_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrSecretKey_Call) Return(s string) *MockKeys_GetNostrSecretKey_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetNostrSecretKey_Call) RunAndReturn(run func() string) *MockKeys_GetNostrSecretKey_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetSwapKey provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) GetSwapKey(childIndex uint) (*btcec.PrivateKey, error) {
|
||||
ret := _mock.Called(childIndex)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetSwapKey")
|
||||
}
|
||||
|
||||
var r0 *btcec.PrivateKey
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(uint) (*btcec.PrivateKey, error)); ok {
|
||||
return returnFunc(childIndex)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(uint) *btcec.PrivateKey); ok {
|
||||
r0 = returnFunc(childIndex)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*btcec.PrivateKey)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(uint) error); ok {
|
||||
r1 = returnFunc(childIndex)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockKeys_GetSwapKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSwapKey'
|
||||
type MockKeys_GetSwapKey_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetSwapKey is a helper method to define mock.On call
|
||||
// - childIndex
|
||||
func (_e *MockKeys_Expecter) GetSwapKey(childIndex interface{}) *MockKeys_GetSwapKey_Call {
|
||||
return &MockKeys_GetSwapKey_Call{Call: _e.mock.On("GetSwapKey", childIndex)}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapKey_Call) Run(run func(childIndex uint)) *MockKeys_GetSwapKey_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapKey_Call) Return(v *btcec.PrivateKey, err error) *MockKeys_GetSwapKey_Call {
|
||||
_c.Call.Return(v, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapKey_Call) RunAndReturn(run func(childIndex uint) (*btcec.PrivateKey, error)) *MockKeys_GetSwapKey_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetSwapMnemonic provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) GetSwapMnemonic() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetSwapMnemonic")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockKeys_GetSwapMnemonic_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSwapMnemonic'
|
||||
type MockKeys_GetSwapMnemonic_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetSwapMnemonic is a helper method to define mock.On call
|
||||
func (_e *MockKeys_Expecter) GetSwapMnemonic() *MockKeys_GetSwapMnemonic_Call {
|
||||
return &MockKeys_GetSwapMnemonic_Call{Call: _e.mock.On("GetSwapMnemonic")}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapMnemonic_Call) Run(run func()) *MockKeys_GetSwapMnemonic_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapMnemonic_Call) Return(s string) *MockKeys_GetSwapMnemonic_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_GetSwapMnemonic_Call) RunAndReturn(run func() string) *MockKeys_GetSwapMnemonic_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Init provides a mock function for the type MockKeys
|
||||
func (_mock *MockKeys) Init(cfg config.Config, encryptionKey string) error {
|
||||
ret := _mock.Called(cfg, encryptionKey)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Init")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if returnFunc, ok := ret.Get(0).(func(config.Config, string) error); ok {
|
||||
r0 = returnFunc(cfg, encryptionKey)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockKeys_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
|
||||
type MockKeys_Init_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Init is a helper method to define mock.On call
|
||||
// - cfg
|
||||
// - encryptionKey
|
||||
func (_e *MockKeys_Expecter) Init(cfg interface{}, encryptionKey interface{}) *MockKeys_Init_Call {
|
||||
return &MockKeys_Init_Call{Call: _e.mock.On("Init", cfg, encryptionKey)}
|
||||
}
|
||||
|
||||
func (_c *MockKeys_Init_Call) Run(run func(cfg config.Config, encryptionKey string)) *MockKeys_Init_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(config.Config), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_Init_Call) Return(err error) *MockKeys_Init_Call {
|
||||
_c.Call.Return(err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockKeys_Init_Call) RunAndReturn(run func(cfg config.Config, encryptionKey string) error) *MockKeys_Init_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue