mirror of
https://github.com/getAlby/lndhub.go.git
synced 2026-02-23 05:44:23 +01:00
fix merge conflicts
This commit is contained in:
@@ -30,7 +30,18 @@ type AddInvoiceResponseBody struct {
|
||||
PayReq string `json:"pay_req"`
|
||||
}
|
||||
|
||||
// AddInvoice : Add invoice Controller
|
||||
// AddInvoice godoc
|
||||
// @Summary Generate a new invoice
|
||||
// @Description Returns a new bolt11 invoice
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Invoice
|
||||
// @Param invoice body AddInvoiceRequestBody True "Add Invoice"
|
||||
// @Success 200 {object} AddInvoiceResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /addinvoice [post]
|
||||
// @Security OAuth2Password
|
||||
func (controller *AddInvoiceController) AddInvoice(c echo.Context) error {
|
||||
userID := c.Get("UserID").(int64)
|
||||
return AddInvoice(c, controller.svc, userID)
|
||||
@@ -53,11 +64,11 @@ func AddInvoice(c echo.Context, svc *service.LndhubService, userID int64) error
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
c.Logger().Infof("Adding invoice: user_id=%v memo=%s value=%v description_hash=%s", userID, body.Memo, amount, body.DescriptionHash)
|
||||
c.Logger().Infof("Adding invoice: user_id:%v memo:%s value:%v description_hash:%s", userID, body.Memo, amount, body.DescriptionHash)
|
||||
|
||||
invoice, err := svc.AddIncomingInvoice(c.Request().Context(), userID, amount, body.Memo, body.DescriptionHash)
|
||||
if err != nil {
|
||||
c.Logger().Errorf("Error creating invoice: %v", err)
|
||||
c.Logger().Errorf("Error creating invoice: user_id:%v error: %v", userID, err)
|
||||
sentry.CaptureException(err)
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,17 @@ type AuthResponseBody struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
|
||||
// Auth : Auth Controller
|
||||
// Auth godoc
|
||||
// @Summary Authenticate
|
||||
// @Description Exchanges a login + password for a token
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Account
|
||||
// @Param AuthRequestBody body AuthRequestBody false "Login and password"
|
||||
// @Success 200 {object} AuthResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /auth [post]
|
||||
func (controller *AuthController) Auth(c echo.Context) error {
|
||||
|
||||
var body AuthRequestBody
|
||||
@@ -42,6 +52,20 @@ func (controller *AuthController) Auth(c echo.Context) error {
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
|
||||
if body.Login == "" || body.Password == "" {
|
||||
// To support Swagger we also look in the Form data
|
||||
params, err := c.FormParams()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
username := params.Get("username")
|
||||
password := params.Get("password")
|
||||
if username != "" && password != "" {
|
||||
body.Login = username
|
||||
body.Password = password
|
||||
}
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := controller.svc.GenerateToken(c.Request().Context(), body.Login, body.Password, body.RefreshToken)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusUnauthorized, responses.BadAuthError)
|
||||
|
||||
@@ -22,7 +22,17 @@ type BalanceResponse struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Balance : Balance Controller
|
||||
// Balance godoc
|
||||
// @Summary Retrieve balance
|
||||
// @Description Current user's balance in satoshi
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Account
|
||||
// @Success 200 {object} BalanceResponse
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /balance [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *BalanceController) Balance(c echo.Context) error {
|
||||
userId := c.Get("UserID").(int64)
|
||||
balance, err := controller.svc.CurrentUserBalance(c.Request().Context(), userId)
|
||||
|
||||
@@ -21,16 +21,27 @@ func NewCheckPaymentController(svc *service.LndhubService) *CheckPaymentControll
|
||||
return &CheckPaymentController{svc: svc}
|
||||
}
|
||||
|
||||
// CheckPayment : Check Payment Controller
|
||||
// CheckPayment godoc
|
||||
// @Summary Check if an invoice is paid
|
||||
// @Description Checks if an invoice is paid, can be incoming our outgoing
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Invoice
|
||||
// @Param payment_hash path string true "Payment hash"
|
||||
// @Success 200 {object} CheckPaymentResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /checkpayment/{payment_hash} [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *CheckPaymentController) CheckPayment(c echo.Context) error {
|
||||
userId := c.Get("UserID").(int64)
|
||||
userID := c.Get("UserID").(int64)
|
||||
rHash := c.Param("payment_hash")
|
||||
|
||||
invoice, err := controller.svc.FindInvoiceByPaymentHash(c.Request().Context(), userId, rHash)
|
||||
invoice, err := controller.svc.FindInvoiceByPaymentHash(c.Request().Context(), userID, rHash)
|
||||
|
||||
// Probably we did not find the invoice
|
||||
if err != nil {
|
||||
c.Logger().Errorf("Invalid checkpayment request payment_hash=%s", rHash)
|
||||
c.Logger().Errorf("Invalid checkpayment request user_id:%v payment_hash:%s", userID, rHash)
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,17 @@ type CreateUserRequestBody struct {
|
||||
AccountType string `json:"accounttype"`
|
||||
}
|
||||
|
||||
// CreateUser : Create user Controller
|
||||
// CreateUser godoc
|
||||
// @Summary Create an account
|
||||
// @Description Create a new account with a login and password
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Account
|
||||
// @Param account body CreateUserRequestBody false "Create User"
|
||||
// @Success 200 {object} CreateUserResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /create [post]
|
||||
func (controller *CreateUserController) CreateUser(c echo.Context) error {
|
||||
|
||||
var body CreateUserRequestBody
|
||||
|
||||
@@ -7,6 +7,63 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
//Copy over struct for swagger purposes
|
||||
type GetInfoResponse struct {
|
||||
// The version of the LND software that the node is running.
|
||||
Version string `protobuf:"bytes,14,opt,name=version,proto3" json:"version,omitempty"`
|
||||
// The SHA1 commit hash that the daemon is compiled with.
|
||||
CommitHash string `protobuf:"bytes,20,opt,name=commit_hash,json=commitHash,proto3" json:"commit_hash,omitempty"`
|
||||
// The identity pubkey of the current node.
|
||||
IdentityPubkey string `protobuf:"bytes,1,opt,name=identity_pubkey,json=identityPubkey,proto3" json:"identity_pubkey,omitempty"`
|
||||
// If applicable, the alias of the current node, e.g. "bob"
|
||||
Alias string `protobuf:"bytes,2,opt,name=alias,proto3" json:"alias,omitempty"`
|
||||
// The color of the current node in hex code format
|
||||
Color string `protobuf:"bytes,17,opt,name=color,proto3" json:"color,omitempty"`
|
||||
// Number of pending channels
|
||||
NumPendingChannels uint32 `protobuf:"varint,3,opt,name=num_pending_channels,json=numPendingChannels,proto3" json:"num_pending_channels,omitempty"`
|
||||
// Number of active channels
|
||||
NumActiveChannels uint32 `protobuf:"varint,4,opt,name=num_active_channels,json=numActiveChannels,proto3" json:"num_active_channels,omitempty"`
|
||||
// Number of inactive channels
|
||||
NumInactiveChannels uint32 `protobuf:"varint,15,opt,name=num_inactive_channels,json=numInactiveChannels,proto3" json:"num_inactive_channels,omitempty"`
|
||||
// Number of peers
|
||||
NumPeers uint32 `protobuf:"varint,5,opt,name=num_peers,json=numPeers,proto3" json:"num_peers,omitempty"`
|
||||
// The node's current view of the height of the best block
|
||||
BlockHeight uint32 `protobuf:"varint,6,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
|
||||
// The node's current view of the hash of the best block
|
||||
BlockHash string `protobuf:"bytes,8,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
|
||||
// Timestamp of the block best known to the wallet
|
||||
BestHeaderTimestamp int64 `protobuf:"varint,13,opt,name=best_header_timestamp,json=bestHeaderTimestamp,proto3" json:"best_header_timestamp,omitempty"`
|
||||
// Whether the wallet's view is synced to the main chain
|
||||
SyncedToChain bool `protobuf:"varint,9,opt,name=synced_to_chain,json=syncedToChain,proto3" json:"synced_to_chain,omitempty"`
|
||||
// Whether we consider ourselves synced with the public channel graph.
|
||||
SyncedToGraph bool `protobuf:"varint,18,opt,name=synced_to_graph,json=syncedToGraph,proto3" json:"synced_to_graph,omitempty"`
|
||||
//
|
||||
//Whether the current node is connected to testnet. This field is
|
||||
//deprecated and the network field should be used instead
|
||||
//
|
||||
// Deprecated: Do not use.
|
||||
Testnet bool `protobuf:"varint,10,opt,name=testnet,proto3" json:"testnet,omitempty"`
|
||||
// A list of active chains the node is connected to
|
||||
Chains []*Chain `protobuf:"bytes,16,rep,name=chains,proto3" json:"chains,omitempty"`
|
||||
// The URIs of the current node.
|
||||
Uris []string `protobuf:"bytes,12,rep,name=uris,proto3" json:"uris,omitempty"`
|
||||
//
|
||||
//Features that our node has advertised in our init message, node
|
||||
//announcements and invoices.
|
||||
Features map[uint32]*Feature `protobuf:"bytes,19,rep,name=features,proto3" json:"features,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
type Chain struct {
|
||||
// The blockchain the node is on (eg bitcoin, litecoin)
|
||||
Chain string `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"`
|
||||
// The network the node is on (eg regtest, testnet, mainnet)
|
||||
Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
|
||||
}
|
||||
type Feature struct {
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
IsRequired bool `protobuf:"varint,3,opt,name=is_required,json=isRequired,proto3" json:"is_required,omitempty"`
|
||||
IsKnown bool `protobuf:"varint,4,opt,name=is_known,json=isKnown,proto3" json:"is_known,omitempty"`
|
||||
}
|
||||
|
||||
// GetInfoController : GetInfoController struct
|
||||
type GetInfoController struct {
|
||||
svc *service.LndhubService
|
||||
@@ -16,10 +73,19 @@ func NewGetInfoController(svc *service.LndhubService) *GetInfoController {
|
||||
return &GetInfoController{svc: svc}
|
||||
}
|
||||
|
||||
// GetInfo : GetInfo handler
|
||||
// GetInfo godoc
|
||||
// @Summary Get info about the Lightning node
|
||||
// @Description Returns info about the backend node powering this LNDhub instance
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Info
|
||||
// @Success 200 {object} GetInfoResponse
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /getinfo [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *GetInfoController) GetInfo(c echo.Context) error {
|
||||
|
||||
// TODO: add some caching for this GetInfo call. No need to always hit the node
|
||||
info, err := controller.svc.GetInfo(c.Request().Context())
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -42,7 +42,17 @@ type IncomingInvoice struct {
|
||||
IsPaid bool `json:"ispaid"`
|
||||
}
|
||||
|
||||
// GetTXS : Get TXS Controller
|
||||
// GetTXS godoc
|
||||
// @Summary Retrieve outgoing payments
|
||||
// @Description Returns a list of outgoing payments for a user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Account
|
||||
// @Success 200 {object} []OutgoingInvoice
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /gettxs [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *GetTXSController) GetTXS(c echo.Context) error {
|
||||
userId := c.Get("UserID").(int64)
|
||||
|
||||
@@ -68,6 +78,17 @@ func (controller *GetTXSController) GetTXS(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, &response)
|
||||
}
|
||||
|
||||
// GetUserInvoices godoc
|
||||
// @Summary Retrieve incoming invoices
|
||||
// @Description Returns a list of incoming invoices for a user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Account
|
||||
// @Success 200 {object} []IncomingInvoice
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /getuserinvoices [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *GetTXSController) GetUserInvoices(c echo.Context) error {
|
||||
userId := c.Get("UserID").(int64)
|
||||
|
||||
|
||||
@@ -17,7 +17,18 @@ func NewInvoiceController(svc *service.LndhubService) *InvoiceController {
|
||||
return &InvoiceController{svc: svc}
|
||||
}
|
||||
|
||||
// Invoice : Invoice Controller
|
||||
// Invoice godoc
|
||||
// @Summary Generate a new invoice
|
||||
// @Description Returns a new bolt11 invoice for a user with given login, without an Authorization Header
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Invoice
|
||||
// @Param user_login path string true "User Login"
|
||||
// @Param invoice body AddInvoiceRequestBody True "Add Invoice"
|
||||
// @Success 200 {object} AddInvoiceResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /invoice/{user_login} [post]
|
||||
func (controller *InvoiceController) Invoice(c echo.Context) error {
|
||||
user, err := controller.svc.FindUserByLogin(c.Request().Context(), c.Param("user_login"))
|
||||
if err != nil {
|
||||
|
||||
@@ -27,7 +27,20 @@ func NewInvoiceStreamController(svc *service.LndhubService) *InvoiceStreamContro
|
||||
return &InvoiceStreamController{svc: svc}
|
||||
}
|
||||
|
||||
// Stream invoices streams incoming payments to the client
|
||||
// StreamInvoices godoc
|
||||
// @Summary Websocket for incoming payments
|
||||
// @Description Websocket: won't work with Swagger web UI. Returns a stream of settled incoming payments.
|
||||
// @Description A keep-alive message is sent on startup and every 30s.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Invoice
|
||||
// @Param token query string true "Auth token, retrieved from /auth endpoint"
|
||||
// @Param since_payment_hash query string false "Payment hash of earliest invoice. If specified, missing updates starting from this payment will be sent."
|
||||
// @Success 200 {object} []InvoiceEventWrapper
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /invoices/stream [get]
|
||||
// @Security OAuth2Password
|
||||
func (controller *InvoiceStreamController) StreamInvoices(c echo.Context) error {
|
||||
userId, err := tokens.ParseToken(controller.svc.Config.JWTSecret, (c.QueryParam("token")), false)
|
||||
if err != nil {
|
||||
@@ -41,8 +54,11 @@ func (controller *InvoiceStreamController) StreamInvoices(c echo.Context) error
|
||||
return err
|
||||
}
|
||||
//start subscription
|
||||
subId := controller.svc.InvoicePubSub.Subscribe(strconv.FormatInt(userId, 10), invoiceChan)
|
||||
|
||||
subId, err := controller.svc.InvoicePubSub.Subscribe(strconv.FormatInt(userId, 10), invoiceChan)
|
||||
if err != nil {
|
||||
controller.svc.Logger.Error(err)
|
||||
return err
|
||||
}
|
||||
//start with keepalive message
|
||||
err = ws.WriteJSON(&InvoiceEventWrapper{Type: "keepalive"})
|
||||
if err != nil {
|
||||
|
||||
@@ -41,7 +41,18 @@ type KeySendResponseBody struct {
|
||||
PaymentRoute *service.Route `json:"payment_route,omitempty"`
|
||||
}
|
||||
|
||||
// KeySend : Key send Controller
|
||||
//// PayInvoice godoc
|
||||
// @Summary Make a keysend payment
|
||||
// @Description Pay a node without an invoice using it's public key
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Payment
|
||||
// @Param KeySendRequestBody body KeySendRequestBody True "Invoice to pay"
|
||||
// @Success 200 {object} KeySendResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /keysend [post]
|
||||
// @Security OAuth2Password
|
||||
func (controller *KeySendController) KeySend(c echo.Context) error {
|
||||
userID := c.Get("UserID").(int64)
|
||||
reqBody := KeySendRequestBody{}
|
||||
@@ -75,7 +86,7 @@ func (controller *KeySendController) KeySend(c echo.Context) error {
|
||||
}
|
||||
|
||||
if currentBalance < invoice.Amount {
|
||||
c.Logger().Errorf("User does not have enough balance invoice_id=%v user_id=%v balance=%v amount=%v", invoice.ID, userID, currentBalance, invoice.Amount)
|
||||
c.Logger().Errorf("User does not have enough balance invoice_id:%v user_id:%v balance:%v amount:%v", invoice.ID, userID, currentBalance, invoice.Amount)
|
||||
return c.JSON(http.StatusBadRequest, responses.NotEnoughBalanceError)
|
||||
}
|
||||
|
||||
@@ -89,7 +100,7 @@ func (controller *KeySendController) KeySend(c echo.Context) error {
|
||||
}
|
||||
sendPaymentResponse, err := controller.svc.PayInvoice(c.Request().Context(), invoice)
|
||||
if err != nil {
|
||||
c.Logger().Errorf("Payment failed: %v", err)
|
||||
c.Logger().Errorf("Payment failed: user_id:%v error: %v", userID, err)
|
||||
sentry.CaptureException(err)
|
||||
return c.JSON(http.StatusBadRequest, echo.Map{
|
||||
"error": true,
|
||||
|
||||
@@ -38,17 +38,28 @@ type PayInvoiceResponseBody struct {
|
||||
PaymentRoute *service.Route `json:"payment_route,omitempty"`
|
||||
}
|
||||
|
||||
// PayInvoice : Pay invoice Controller
|
||||
// PayInvoice godoc
|
||||
// @Summary Pay an invoice
|
||||
// @Description Pay a bolt11 invoice
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Payment
|
||||
// @Param PayInvoiceRequest body PayInvoiceRequestBody True "Invoice to pay"
|
||||
// @Success 200 {object} PayInvoiceResponseBody
|
||||
// @Failure 400 {object} responses.ErrorResponse
|
||||
// @Failure 500 {object} responses.ErrorResponse
|
||||
// @Router /payinvoice [post]
|
||||
// @Security OAuth2Password
|
||||
func (controller *PayInvoiceController) PayInvoice(c echo.Context) error {
|
||||
userID := c.Get("UserID").(int64)
|
||||
reqBody := PayInvoiceRequestBody{}
|
||||
if err := c.Bind(&reqBody); err != nil {
|
||||
c.Logger().Errorf("Failed to load payinvoice request body: %v", err)
|
||||
c.Logger().Errorf("Failed to load payinvoice request body: user_id:%v error: %v", userID, err)
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
|
||||
if err := c.Validate(&reqBody); err != nil {
|
||||
c.Logger().Errorf("Invalid payinvoice request body: %v", err)
|
||||
c.Logger().Errorf("Invalid payinvoice request body user_id:%v error: %v", userID, err)
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
|
||||
@@ -56,26 +67,22 @@ func (controller *PayInvoiceController) PayInvoice(c echo.Context) error {
|
||||
paymentRequest = strings.ToLower(paymentRequest)
|
||||
decodedPaymentRequest, err := controller.svc.DecodePaymentRequest(c.Request().Context(), paymentRequest)
|
||||
if err != nil {
|
||||
c.Logger().Errorf("Invalid payment request: %v", err)
|
||||
c.Logger().Errorf("Invalid payment request user_id:%v error: %v", userID, err)
|
||||
sentry.CaptureException(err)
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
// TODO: zero amount invoices
|
||||
/*
|
||||
_, err = controller.svc.ParseInt(reqBody.Amount)
|
||||
if err != nil {
|
||||
return c.JSON(http.StatusBadRequest, echo.Map{
|
||||
"error": true,
|
||||
"code": 8,
|
||||
"message": "Bad arguments",
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
lnPayReq := &lnd.LNPayReq{
|
||||
PayReq: decodedPaymentRequest,
|
||||
Keysend: false,
|
||||
}
|
||||
if decodedPaymentRequest.NumSatoshis == 0 {
|
||||
amt, err := controller.svc.ParseInt(reqBody.Amount)
|
||||
if err != nil || amt <= 0 {
|
||||
return c.JSON(http.StatusBadRequest, responses.BadArgumentsError)
|
||||
}
|
||||
lnPayReq.PayReq.NumSatoshis = amt
|
||||
}
|
||||
|
||||
invoice, err := controller.svc.AddOutgoingInvoice(c.Request().Context(), userID, paymentRequest, lnPayReq)
|
||||
if err != nil {
|
||||
@@ -88,14 +95,14 @@ func (controller *PayInvoiceController) PayInvoice(c echo.Context) error {
|
||||
}
|
||||
|
||||
if currentBalance < invoice.Amount {
|
||||
c.Logger().Errorf("User does not have enough balance invoice_id=%v user_id=%v balance=%v amount=%v", invoice.ID, userID, currentBalance, invoice.Amount)
|
||||
c.Logger().Errorf("User does not have enough balance invoice_id:%v user_id:%v balance:%v amount:%v", invoice.ID, userID, currentBalance, invoice.Amount)
|
||||
|
||||
return c.JSON(http.StatusBadRequest, responses.NotEnoughBalanceError)
|
||||
}
|
||||
|
||||
sendPaymentResponse, err := controller.svc.PayInvoice(c.Request().Context(), invoice)
|
||||
if err != nil {
|
||||
c.Logger().Errorf("Payment failed: %v", err)
|
||||
c.Logger().Errorf("Payment failed invoice_id:%v user_id:%v error: %v", invoice.ID, userID, err)
|
||||
sentry.CaptureException(err)
|
||||
return c.JSON(http.StatusBadRequest, echo.Map{
|
||||
"error": true,
|
||||
|
||||
1037
docs/docs.go
Normal file
1037
docs/docs.go
Normal file
File diff suppressed because it is too large
Load Diff
1017
docs/swagger.json
Normal file
1017
docs/swagger.json
Normal file
File diff suppressed because it is too large
Load Diff
674
docs/swagger.yaml
Normal file
674
docs/swagger.yaml
Normal file
@@ -0,0 +1,674 @@
|
||||
basePath: /
|
||||
definitions:
|
||||
controllers.AddInvoiceRequestBody:
|
||||
properties:
|
||||
amt:
|
||||
description: amount in Satoshi
|
||||
description_hash:
|
||||
type: string
|
||||
memo:
|
||||
type: string
|
||||
type: object
|
||||
controllers.AddInvoiceResponseBody:
|
||||
properties:
|
||||
pay_req:
|
||||
type: string
|
||||
payment_request:
|
||||
type: string
|
||||
r_hash:
|
||||
type: string
|
||||
type: object
|
||||
controllers.AuthRequestBody:
|
||||
properties:
|
||||
login:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
refresh_token:
|
||||
type: string
|
||||
type: object
|
||||
controllers.AuthResponseBody:
|
||||
properties:
|
||||
access_token:
|
||||
type: string
|
||||
refresh_token:
|
||||
type: string
|
||||
type: object
|
||||
controllers.BalanceResponse:
|
||||
properties:
|
||||
btc:
|
||||
properties:
|
||||
availableBalance:
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
controllers.Chain:
|
||||
properties:
|
||||
chain:
|
||||
description: The blockchain the node is on (eg bitcoin, litecoin)
|
||||
type: string
|
||||
network:
|
||||
description: The network the node is on (eg regtest, testnet, mainnet)
|
||||
type: string
|
||||
type: object
|
||||
controllers.CheckPaymentResponseBody:
|
||||
properties:
|
||||
paid:
|
||||
type: boolean
|
||||
type: object
|
||||
controllers.CreateUserRequestBody:
|
||||
properties:
|
||||
accounttype:
|
||||
type: string
|
||||
login:
|
||||
type: string
|
||||
partnerid:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
type: object
|
||||
controllers.CreateUserResponseBody:
|
||||
properties:
|
||||
login:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
type: object
|
||||
controllers.Feature:
|
||||
properties:
|
||||
is_known:
|
||||
type: boolean
|
||||
is_required:
|
||||
type: boolean
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
controllers.GetInfoResponse:
|
||||
properties:
|
||||
alias:
|
||||
description: If applicable, the alias of the current node, e.g. "bob"
|
||||
type: string
|
||||
best_header_timestamp:
|
||||
description: Timestamp of the block best known to the wallet
|
||||
type: integer
|
||||
block_hash:
|
||||
description: The node's current view of the hash of the best block
|
||||
type: string
|
||||
block_height:
|
||||
description: The node's current view of the height of the best block
|
||||
type: integer
|
||||
chains:
|
||||
description: A list of active chains the node is connected to
|
||||
items:
|
||||
$ref: '#/definitions/controllers.Chain'
|
||||
type: array
|
||||
color:
|
||||
description: The color of the current node in hex code format
|
||||
type: string
|
||||
commit_hash:
|
||||
description: The SHA1 commit hash that the daemon is compiled with.
|
||||
type: string
|
||||
features:
|
||||
additionalProperties:
|
||||
$ref: '#/definitions/controllers.Feature'
|
||||
description: |-
|
||||
Features that our node has advertised in our init message, node
|
||||
announcements and invoices.
|
||||
type: object
|
||||
identity_pubkey:
|
||||
description: The identity pubkey of the current node.
|
||||
type: string
|
||||
num_active_channels:
|
||||
description: Number of active channels
|
||||
type: integer
|
||||
num_inactive_channels:
|
||||
description: Number of inactive channels
|
||||
type: integer
|
||||
num_peers:
|
||||
description: Number of peers
|
||||
type: integer
|
||||
num_pending_channels:
|
||||
description: Number of pending channels
|
||||
type: integer
|
||||
synced_to_chain:
|
||||
description: Whether the wallet's view is synced to the main chain
|
||||
type: boolean
|
||||
synced_to_graph:
|
||||
description: Whether we consider ourselves synced with the public channel
|
||||
graph.
|
||||
type: boolean
|
||||
testnet:
|
||||
description: |-
|
||||
Whether the current node is connected to testnet. This field is
|
||||
deprecated and the network field should be used instead
|
||||
|
||||
Deprecated: Do not use.
|
||||
type: boolean
|
||||
uris:
|
||||
description: The URIs of the current node.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
version:
|
||||
description: The version of the LND software that the node is running.
|
||||
type: string
|
||||
type: object
|
||||
controllers.IncomingInvoice:
|
||||
properties:
|
||||
amt:
|
||||
type: integer
|
||||
description:
|
||||
type: string
|
||||
expire_time:
|
||||
type: integer
|
||||
ispaid:
|
||||
type: boolean
|
||||
pay_req:
|
||||
type: string
|
||||
payment_hash: {}
|
||||
payment_request:
|
||||
type: string
|
||||
r_hash: {}
|
||||
timestamp:
|
||||
type: integer
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
controllers.InvoiceEventWrapper:
|
||||
properties:
|
||||
invoice:
|
||||
$ref: '#/definitions/controllers.IncomingInvoice'
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
controllers.KeySendRequestBody:
|
||||
properties:
|
||||
amount:
|
||||
type: integer
|
||||
customRecords:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
destination:
|
||||
type: string
|
||||
memo:
|
||||
type: string
|
||||
required:
|
||||
- amount
|
||||
- destination
|
||||
type: object
|
||||
controllers.KeySendResponseBody:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
description_hash:
|
||||
type: string
|
||||
destination:
|
||||
type: string
|
||||
num_satoshis:
|
||||
type: integer
|
||||
payment_error:
|
||||
type: string
|
||||
payment_hash:
|
||||
$ref: '#/definitions/lib.JavaScriptBuffer'
|
||||
payment_preimage:
|
||||
$ref: '#/definitions/lib.JavaScriptBuffer'
|
||||
payment_route:
|
||||
$ref: '#/definitions/service.Route'
|
||||
type: object
|
||||
controllers.OutgoingInvoice:
|
||||
properties:
|
||||
fee:
|
||||
type: integer
|
||||
memo:
|
||||
type: string
|
||||
payment_hash: {}
|
||||
payment_preimage:
|
||||
type: string
|
||||
r_hash: {}
|
||||
timestamp:
|
||||
type: integer
|
||||
type:
|
||||
type: string
|
||||
value:
|
||||
type: integer
|
||||
type: object
|
||||
controllers.PayInvoiceRequestBody:
|
||||
properties:
|
||||
amount: {}
|
||||
invoice:
|
||||
type: string
|
||||
required:
|
||||
- invoice
|
||||
type: object
|
||||
controllers.PayInvoiceResponseBody:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
description_hash:
|
||||
type: string
|
||||
num_satoshis:
|
||||
type: integer
|
||||
pay_req:
|
||||
type: string
|
||||
payment_error:
|
||||
type: string
|
||||
payment_hash:
|
||||
$ref: '#/definitions/lib.JavaScriptBuffer'
|
||||
payment_preimage:
|
||||
$ref: '#/definitions/lib.JavaScriptBuffer'
|
||||
payment_request:
|
||||
type: string
|
||||
payment_route:
|
||||
$ref: '#/definitions/service.Route'
|
||||
type: object
|
||||
lib.JavaScriptBuffer:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
type: object
|
||||
responses.ErrorResponse:
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
error:
|
||||
type: boolean
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
service.Route:
|
||||
properties:
|
||||
total_amt:
|
||||
type: integer
|
||||
total_fees:
|
||||
type: integer
|
||||
type: object
|
||||
info:
|
||||
contact:
|
||||
email: hello@getalby.com
|
||||
name: Alby
|
||||
url: https://getalby.com
|
||||
description: Accounting wrapper for the Lightning Network providing separate accounts
|
||||
for end-users.
|
||||
license:
|
||||
name: GNU GPL
|
||||
url: https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
title: LNDhub.go
|
||||
version: 0.6.1
|
||||
paths:
|
||||
/addinvoice:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns a new bolt11 invoice
|
||||
parameters:
|
||||
- description: Add Invoice
|
||||
in: body
|
||||
name: invoice
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AddInvoiceRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AddInvoiceResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Generate a new invoice
|
||||
tags:
|
||||
- Invoice
|
||||
/auth:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Exchanges a login + password for a token
|
||||
parameters:
|
||||
- description: Login and password
|
||||
in: body
|
||||
name: AuthRequestBody
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AuthRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AuthResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
summary: Authenticate
|
||||
tags:
|
||||
- Account
|
||||
/balance:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Current user's balance in satoshi
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.BalanceResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Retrieve balance
|
||||
tags:
|
||||
- Account
|
||||
/checkpayment/{payment_hash}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Checks if an invoice is paid, can be incoming our outgoing
|
||||
parameters:
|
||||
- description: Payment hash
|
||||
in: path
|
||||
name: payment_hash
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.CheckPaymentResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Check if an invoice is paid
|
||||
tags:
|
||||
- Invoice
|
||||
/create:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Create a new account with a login and password
|
||||
parameters:
|
||||
- description: Create User
|
||||
in: body
|
||||
name: account
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.CreateUserRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.CreateUserResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
summary: Create an account
|
||||
tags:
|
||||
- Account
|
||||
/getinfo:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns info about the backend node powering this LNDhub instance
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.GetInfoResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Get info about the Lightning node
|
||||
tags:
|
||||
- Info
|
||||
/gettxs:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns a list of outgoing payments for a user
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/controllers.OutgoingInvoice'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Retrieve outgoing payments
|
||||
tags:
|
||||
- Account
|
||||
/getuserinvoices:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns a list of incoming invoices for a user
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/controllers.IncomingInvoice'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Retrieve incoming invoices
|
||||
tags:
|
||||
- Account
|
||||
/invoice/{user_login}:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns a new bolt11 invoice for a user with given login, without
|
||||
an Authorization Header
|
||||
parameters:
|
||||
- description: User Login
|
||||
in: path
|
||||
name: user_login
|
||||
required: true
|
||||
type: string
|
||||
- description: Add Invoice
|
||||
in: body
|
||||
name: invoice
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AddInvoiceRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.AddInvoiceResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
summary: Generate a new invoice
|
||||
tags:
|
||||
- Invoice
|
||||
/invoices/stream:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: |-
|
||||
Websocket: won't work with Swagger web UI. Returns a stream of settled incoming payments.
|
||||
A keep-alive message is sent on startup and every 30s.
|
||||
parameters:
|
||||
- description: Auth token, retrieved from /auth endpoint
|
||||
in: query
|
||||
name: token
|
||||
required: true
|
||||
type: string
|
||||
- description: Payment hash of earliest invoice. If specified, missing updates
|
||||
starting from this payment will be sent.
|
||||
in: query
|
||||
name: since_payment_hash
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/controllers.InvoiceEventWrapper'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Websocket for incoming payments
|
||||
tags:
|
||||
- Invoice
|
||||
/keysend:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Pay a node without an invoice using it's public key
|
||||
parameters:
|
||||
- description: Invoice to pay
|
||||
in: body
|
||||
name: KeySendRequestBody
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.KeySendRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.KeySendResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Make a keysend payment
|
||||
tags:
|
||||
- Payment
|
||||
/payinvoice:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Pay a bolt11 invoice
|
||||
parameters:
|
||||
- description: Invoice to pay
|
||||
in: body
|
||||
name: PayInvoiceRequest
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.PayInvoiceRequestBody'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.PayInvoiceResponseBody'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/responses.ErrorResponse'
|
||||
security:
|
||||
- OAuth2Password: []
|
||||
summary: Pay an invoice
|
||||
tags:
|
||||
- Payment
|
||||
schemes:
|
||||
- http
|
||||
- https
|
||||
securityDefinitions:
|
||||
OAuth2Password:
|
||||
flow: password
|
||||
tokenUrl: /auth
|
||||
type: oauth2
|
||||
swagger: "2.0"
|
||||
14
go.mod
14
go.mod
@@ -10,7 +10,7 @@ require (
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/labstack/echo/v4 v4.6.1
|
||||
github.com/labstack/echo/v4 v4.7.2
|
||||
github.com/labstack/gommon v0.3.1
|
||||
github.com/lightningnetwork/lnd v0.14.1-beta
|
||||
github.com/stretchr/testify v1.7.0
|
||||
@@ -21,18 +21,24 @@ require (
|
||||
github.com/uptrace/bun/driver/sqliteshim v1.0.21
|
||||
github.com/uptrace/bun/extra/bundebug v1.0.21
|
||||
github.com/ziflex/lecho/v3 v3.1.0
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
google.golang.org/grpc v1.43.0
|
||||
gopkg.in/macaroon.v2 v2.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
||||
github.com/SporkHubr/echo-http-cache v0.0.0-20200706100054-1d7ae9f38029
|
||||
github.com/go-openapi/spec v0.20.5 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/labstack/echo-contrib v0.12.0
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
github.com/swaggo/echo-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.8.1
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0 // indirect
|
||||
)
|
||||
|
||||
84
go.sum
84
go.sum
@@ -35,8 +35,9 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
||||
@@ -44,11 +45,15 @@ github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5Db
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
|
||||
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
||||
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
|
||||
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
|
||||
@@ -60,6 +65,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -72,6 +79,7 @@ github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
|
||||
github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
|
||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
|
||||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
@@ -225,8 +233,8 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNy
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
|
||||
github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY=
|
||||
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
|
||||
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
@@ -252,7 +260,20 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/spec v0.20.5 h1:skHa8av4VnAtJU5zyAUXrrdK/NDiVX8lchbG+BfcdrE=
|
||||
github.com/go-openapi/spec v0.20.5/go.mod h1:QbfOSIVt3/sac+a1wzmKbbcLXm5NdZnyBZYtCijp43o=
|
||||
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
@@ -468,6 +489,8 @@ github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
@@ -541,10 +564,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo-contrib v0.12.0 h1:NPr1ez+XUa5s/4LujEon+32Bxg5DO6EKSW/va06pmLc=
|
||||
github.com/labstack/echo-contrib v0.12.0/go.mod h1:kR62TbwsBgmpV2HVab5iQRsQtLuhPyGqCBee88XRc4M=
|
||||
github.com/labstack/echo/v4 v4.1.14/go.mod h1:Q5KZ1vD3V5FEzjM79hjwVrC3ABr7F5IdM23bXQMRDGg=
|
||||
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
|
||||
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
|
||||
github.com/labstack/echo/v4 v4.6.1 h1:OMVsrnNFzYlGSdaiYGHbgWQnr+JM7NG+B9suCPie14M=
|
||||
github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k=
|
||||
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
|
||||
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
@@ -587,9 +612,15 @@ github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1s
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -602,6 +633,7 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
@@ -665,8 +697,15 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
|
||||
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ=
|
||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4=
|
||||
@@ -696,7 +735,6 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
@@ -740,8 +778,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
@@ -773,6 +811,13 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/swaggo/echo-swagger v1.3.0 h1:xxL/4jbCY4Z3udUvqOas+IpTMKbxrKdEKwtS7He0Qhg=
|
||||
github.com/swaggo/echo-swagger v1.3.0/go.mod h1:snY6MlGK+pQAfJNEfX5qaOzt/QuM/WINVxGgQaZVJgg=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
|
||||
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
|
||||
github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
|
||||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
|
||||
@@ -902,8 +947,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
@@ -947,8 +992,10 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -987,8 +1034,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1033,6 +1081,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -1041,8 +1090,9 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
|
||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1119,6 +1169,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -1136,11 +1187,13 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211123173158-ef496fb156ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1221,8 +1274,10 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1371,6 +1426,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -109,7 +109,9 @@ func (suite *CheckPaymentTestSuite) TestCheckPaymentProperIsPaidResponse() {
|
||||
assert.False(suite.T(), checkPaymentResponse.IsPaid)
|
||||
|
||||
// pay external from user
|
||||
payResponse := suite.createPayInvoiceReq(invoice.PaymentRequest, suite.userToken)
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: invoice.PayReq,
|
||||
}, suite.userToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
|
||||
// check payment is paid
|
||||
|
||||
@@ -102,7 +102,9 @@ func (suite *GetTxTestSuite) TestGetOutgoingInvoices() {
|
||||
// create invoice
|
||||
invoice = suite.createAddInvoiceReq(500, "integration test internal payment alice", suite.userToken)
|
||||
// pay invoice, this will create outgoing invoice and settle it
|
||||
suite.createPayInvoiceReq(invoice.PayReq, suite.userToken)
|
||||
suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: invoice.PayReq,
|
||||
}, suite.userToken)
|
||||
// check invoices again
|
||||
req = httptest.NewRequest(http.MethodGet, "/gettxs", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", suite.userToken))
|
||||
|
||||
@@ -110,6 +110,45 @@ func (suite *IncomingPaymentTestSuite) TestIncomingPayment() {
|
||||
assert.Equal(suite.T(), int64(fundingSatAmt), balance.BTC.AvailableBalance)
|
||||
|
||||
}
|
||||
func (suite *IncomingPaymentTestSuite) TestIncomingPaymentZeroAmt() {
|
||||
var buf bytes.Buffer
|
||||
req := httptest.NewRequest(http.MethodGet, "/balance", &buf)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", suite.userToken))
|
||||
rec := httptest.NewRecorder()
|
||||
suite.echo.Use(tokens.Middleware([]byte(suite.service.Config.JWTSecret)))
|
||||
suite.echo.GET("/balance", controllers.NewBalanceController(suite.service).Balance)
|
||||
suite.echo.POST("/addinvoice", controllers.NewAddInvoiceController(suite.service).AddInvoice)
|
||||
suite.echo.ServeHTTP(rec, req)
|
||||
//lookup balance before
|
||||
balance := &ExpectedBalanceResponse{}
|
||||
assert.Equal(suite.T(), http.StatusOK, rec.Code)
|
||||
assert.NoError(suite.T(), json.NewDecoder(rec.Body).Decode(&balance))
|
||||
initialBalance := balance.BTC.AvailableBalance
|
||||
fundingSatAmt := 0
|
||||
sendSatAmt := 10
|
||||
invoiceResponse := suite.createAddInvoiceReq(fundingSatAmt, "integration test IncomingPaymentTestSuite", suite.userToken)
|
||||
//try to pay invoice with external node
|
||||
// Prepare the LNRPC call
|
||||
sendPaymentRequest := lnrpc.SendRequest{
|
||||
PaymentRequest: invoiceResponse.PayReq,
|
||||
Amt: int64(sendSatAmt),
|
||||
FeeLimit: nil,
|
||||
}
|
||||
_, err := suite.fundingClient.SendPaymentSync(context.Background(), &sendPaymentRequest)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
//wait a bit for the callback event to hit
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
//check balance again
|
||||
req = httptest.NewRequest(http.MethodGet, "/balance", &buf)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", suite.userToken))
|
||||
suite.echo.ServeHTTP(rec, req)
|
||||
balance = &ExpectedBalanceResponse{}
|
||||
assert.Equal(suite.T(), http.StatusOK, rec.Code)
|
||||
assert.NoError(suite.T(), json.NewDecoder(rec.Body).Decode(&balance))
|
||||
//assert the payment value was added to the user's account
|
||||
assert.Equal(suite.T(), initialBalance+int64(sendSatAmt), balance.BTC.AvailableBalance)
|
||||
}
|
||||
|
||||
func TestIncomingPaymentTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(IncomingPaymentTestSuite))
|
||||
|
||||
@@ -103,7 +103,9 @@ func (suite *PaymentTestSuite) TestInternalPayment() {
|
||||
//create invoice for bob
|
||||
bobInvoice := suite.createAddInvoiceReq(bobSatRequested, "integration test internal payment bob", suite.bobToken)
|
||||
//pay bob from alice
|
||||
payResponse := suite.createPayInvoiceReq(bobInvoice.PayReq, suite.aliceToken)
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: bobInvoice.PayReq,
|
||||
}, suite.aliceToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
|
||||
aliceId := getUserIdFromToken(suite.aliceToken)
|
||||
@@ -152,7 +154,9 @@ func (suite *PaymentTestSuite) TestInternalPaymentFail() {
|
||||
//create invoice for bob
|
||||
bobInvoice := suite.createAddInvoiceReq(bobSatRequested, "integration test internal payment bob", suite.bobToken)
|
||||
//pay bob from alice
|
||||
payResponse := suite.createPayInvoiceReq(bobInvoice.PayReq, suite.aliceToken)
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: bobInvoice.PayReq,
|
||||
}, suite.aliceToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
//try to pay same invoice again for make it fail
|
||||
_ = suite.createPayInvoiceReqError(bobInvoice.PayReq, suite.aliceToken)
|
||||
|
||||
@@ -38,7 +38,9 @@ func (suite *PaymentTestSuite) TestOutGoingPayment() {
|
||||
invoice, err := suite.fundingClient.AddInvoice(context.Background(), &externalInvoice)
|
||||
assert.NoError(suite.T(), err)
|
||||
//pay external from alice
|
||||
payResponse := suite.createPayInvoiceReq(invoice.PaymentRequest, suite.aliceToken)
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: invoice.PaymentRequest,
|
||||
}, suite.aliceToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
|
||||
// check that balance was reduced
|
||||
@@ -125,7 +127,9 @@ func (suite *PaymentTestSuite) TestOutGoingPaymentWithNegativeBalance() {
|
||||
invoice, err := suite.fundingClient.AddInvoice(context.Background(), &externalInvoice)
|
||||
assert.NoError(suite.T(), err)
|
||||
//pay external from alice
|
||||
payResponse := suite.createPayInvoiceReq(invoice.PaymentRequest, suite.aliceToken)
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: invoice.PaymentRequest,
|
||||
}, suite.aliceToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
|
||||
// check that balance was reduced
|
||||
@@ -176,3 +180,34 @@ func (suite *PaymentTestSuite) TestOutGoingPaymentWithNegativeBalance() {
|
||||
// make sure fee entry parent id is previous entry
|
||||
assert.Equal(suite.T(), transactonEntries[1].ID, transactonEntries[2].ParentID)
|
||||
}
|
||||
|
||||
func (suite *PaymentTestSuite) TestZeroAmountInvoice() {
|
||||
aliceFundingSats := 1000
|
||||
amtToPay := 1000
|
||||
//fund alice account
|
||||
invoiceResponse := suite.createAddInvoiceReq(aliceFundingSats, "integration test zero amount payment alice", suite.aliceToken)
|
||||
sendPaymentRequest := lnrpc.SendRequest{
|
||||
PaymentRequest: invoiceResponse.PayReq,
|
||||
FeeLimit: nil,
|
||||
}
|
||||
_, err := suite.fundingClient.SendPaymentSync(context.Background(), &sendPaymentRequest)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
//wait a bit for the callback event to hit
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
//create external invoice
|
||||
externalInvoice := lnrpc.Invoice{
|
||||
Memo: "integration tests: zero amount pay from alice",
|
||||
Value: 0,
|
||||
}
|
||||
invoice, err := suite.fundingClient.AddInvoice(context.Background(), &externalInvoice)
|
||||
assert.NoError(suite.T(), err)
|
||||
//pay external from alice
|
||||
payResponse := suite.createPayInvoiceReq(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: invoice.PaymentRequest,
|
||||
Amount: amtToPay,
|
||||
}, suite.aliceToken)
|
||||
assert.NotEmpty(suite.T(), payResponse.PaymentPreimage)
|
||||
assert.Equal(suite.T(), int64(amtToPay), payResponse.Amount)
|
||||
}
|
||||
|
||||
@@ -229,12 +229,10 @@ func (suite *TestSuite) createKeySendReqError(amount int64, memo, destination, t
|
||||
return checkErrResponse(suite, rec)
|
||||
}
|
||||
|
||||
func (suite *TestSuite) createPayInvoiceReq(payReq string, token string) *ExpectedPayInvoiceResponseBody {
|
||||
func (suite *TestSuite) createPayInvoiceReq(payReq *ExpectedPayInvoiceRequestBody, token string) *ExpectedPayInvoiceResponseBody {
|
||||
rec := httptest.NewRecorder()
|
||||
var buf bytes.Buffer
|
||||
assert.NoError(suite.T(), json.NewEncoder(&buf).Encode(&ExpectedPayInvoiceRequestBody{
|
||||
Invoice: payReq,
|
||||
}))
|
||||
assert.NoError(suite.T(), json.NewEncoder(&buf).Encode(payReq))
|
||||
req := httptest.NewRequest(http.MethodPost, "/payinvoice", &buf)
|
||||
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||
|
||||
@@ -11,6 +11,7 @@ type Config struct {
|
||||
LNDMacaroonHex string `envconfig:"LND_MACAROON_HEX" required:"true"`
|
||||
LNDCertHex string `envconfig:"LND_CERT_HEX"`
|
||||
CustomName string `envconfig:"CUSTOM_NAME"`
|
||||
Host string `envconfig:"HOST" default:"localhost:3000"`
|
||||
Port int `envconfig:"PORT" default:"3000"`
|
||||
DefaultRateLimit int `envconfig:"DEFAULT_RATE_LIMIT" default:"10"`
|
||||
StrictRateLimit int `envconfig:"STRICT_RATE_LIMIT" default:"10"`
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -144,7 +143,10 @@ func createLnRpcSendRequest(invoice *models.Invoice) (*lnrpc.SendRequest, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
preImage := makePreimageHex()
|
||||
preImage, err := makePreimageHex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pHash := sha256.New()
|
||||
pHash.Write(preImage)
|
||||
// Prepare the LNRPC call
|
||||
@@ -340,7 +342,10 @@ func (svc *LndhubService) AddOutgoingInvoice(ctx context.Context, userID int64,
|
||||
}
|
||||
|
||||
func (svc *LndhubService) AddIncomingInvoice(ctx context.Context, userID int64, amount int64, memo, descriptionHashStr string) (*models.Invoice, error) {
|
||||
preimage := makePreimageHex()
|
||||
preimage, err := makePreimageHex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expiry := time.Hour * 24 // invoice expires in 24h
|
||||
// Initialize new DB invoice
|
||||
invoice := models.Invoice{
|
||||
@@ -354,7 +359,7 @@ func (svc *LndhubService) AddIncomingInvoice(ctx context.Context, userID int64,
|
||||
}
|
||||
|
||||
// Save invoice - we save the invoice early to have a record in case the LN call fails
|
||||
_, err := svc.DB.NewInsert().Model(&invoice).Exec(ctx)
|
||||
_, err = svc.DB.NewInsert().Model(&invoice).Exec(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -399,10 +404,6 @@ func (svc *LndhubService) DecodePaymentRequest(ctx context.Context, bolt11 strin
|
||||
|
||||
const hexBytes = random.Hex
|
||||
|
||||
func makePreimageHex() []byte {
|
||||
b := make([]byte, 32)
|
||||
for i := range b {
|
||||
b[i] = hexBytes[rand.Intn(len(hexBytes))]
|
||||
}
|
||||
return b
|
||||
func makePreimageHex() ([]byte, error) {
|
||||
return randBytesFromStr(32, hexBytes)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,11 @@ func (svc *LndhubService) ProcessInvoiceUpdate(ctx context.Context, rawInvoice *
|
||||
InvoiceID: invoice.ID,
|
||||
CreditAccountID: creditAccount.ID,
|
||||
DebitAccountID: debitAccount.ID,
|
||||
Amount: invoice.Amount,
|
||||
Amount: rawInvoice.AmtPaidSat,
|
||||
}
|
||||
|
||||
if rawInvoice.AmtPaidSat != invoice.Amount {
|
||||
svc.Logger.Infof("Incoming invoice amount mismatch. user_id:%v invoice_id:%v, amt:%d, amt_paid:%d.", invoice.UserID, invoice.ID, invoice.Amount, rawInvoice.AmtPaidSat)
|
||||
}
|
||||
|
||||
// Save the transaction entry
|
||||
|
||||
@@ -17,16 +17,20 @@ func NewPubsub() *Pubsub {
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps *Pubsub) Subscribe(topic string, ch chan models.Invoice) (subId string) {
|
||||
func (ps *Pubsub) Subscribe(topic string, ch chan models.Invoice) (subId string, err error) {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
if ps.subs[topic] == nil {
|
||||
ps.subs[topic] = make(map[string]chan models.Invoice)
|
||||
}
|
||||
//re-use preimage code for a uuid
|
||||
subId = string(makePreimageHex())
|
||||
preImageHex, err := makePreimageHex()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
subId = string(preImageHex)
|
||||
ps.subs[topic][subId] = ch
|
||||
return subId
|
||||
return subId, nil
|
||||
}
|
||||
|
||||
func (ps *Pubsub) Unsubscribe(id string, topic string) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"math/rand"
|
||||
|
||||
"github.com/getAlby/lndhub.go/common"
|
||||
"github.com/getAlby/lndhub.go/db/models"
|
||||
@@ -18,11 +17,19 @@ func (svc *LndhubService) CreateUser(ctx context.Context, login string, password
|
||||
// generate user login/password if not provided
|
||||
user.Login = login
|
||||
if login == "" {
|
||||
user.Login = randStringBytes(20)
|
||||
randLoginBytes, err := randBytesFromStr(20, alphaNumBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Login = string(randLoginBytes)
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
password = randStringBytes(20)
|
||||
randPasswordBytes, err := randBytesFromStr(20, alphaNumBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
password = string(randPasswordBytes)
|
||||
}
|
||||
|
||||
// we only store the hashed password but return the initial plain text password in the HTTP response
|
||||
@@ -112,11 +119,3 @@ func (svc *LndhubService) InvoicesFor(ctx context.Context, userId int64, invoice
|
||||
}
|
||||
return invoices, nil
|
||||
}
|
||||
|
||||
func randStringBytes(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = alphaNumBytes[rand.Intn(len(alphaNumBytes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
19
lib/service/util.go
Normal file
19
lib/service/util.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func randBytesFromStr(length int, from string) ([]byte, error) {
|
||||
b := make([]byte, length)
|
||||
fromLenBigInt := big.NewInt(int64(len(from)))
|
||||
for i := range b {
|
||||
r, err := rand.Int(rand.Reader, fromLenBigInt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b[i] = from[r.Int64()]
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
22
main.go
22
main.go
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/getAlby/lndhub.go/controllers"
|
||||
"github.com/getAlby/lndhub.go/db"
|
||||
"github.com/getAlby/lndhub.go/db/migrations"
|
||||
"github.com/getAlby/lndhub.go/docs"
|
||||
"github.com/getAlby/lndhub.go/lib"
|
||||
"github.com/getAlby/lndhub.go/lib/responses"
|
||||
"github.com/getAlby/lndhub.go/lib/service"
|
||||
@@ -29,6 +30,7 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
echoSwagger "github.com/swaggo/echo-swagger"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
"github.com/ziflex/lecho/v3"
|
||||
"golang.org/x/time/rate"
|
||||
@@ -40,6 +42,22 @@ var indexHtml string
|
||||
//go:embed static/*
|
||||
var staticContent embed.FS
|
||||
|
||||
// @title LNDhub.go
|
||||
// @version 0.6.1
|
||||
// @description Accounting wrapper for the Lightning Network providing separate accounts for end-users.
|
||||
|
||||
// @contact.name Alby
|
||||
// @contact.url https://getalby.com
|
||||
// @contact.email hello@getalby.com
|
||||
|
||||
// @license.name GNU GPL
|
||||
// @license.url https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
|
||||
// @BasePath /
|
||||
|
||||
// @securitydefinitions.oauth2.password OAuth2Password
|
||||
// @tokenUrl /auth
|
||||
// @schemes https http
|
||||
func main() {
|
||||
c := &service.Config{}
|
||||
|
||||
@@ -165,6 +183,10 @@ func main() {
|
||||
//Authentication should be done through the query param because this is a websocket
|
||||
e.GET("/invoices/stream", controllers.NewInvoiceStreamController(svc).StreamInvoices)
|
||||
|
||||
//Swagger API spec
|
||||
docs.SwaggerInfo.Host = c.Host
|
||||
e.GET("/swagger/*", echoSwagger.WrapHandler)
|
||||
|
||||
// Subscribe to LND invoice updates in the background
|
||||
go svc.InvoiceUpdateSubscription(context.Background())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user