diff --git a/datasource.js b/datasource.js index d4ed74ef..691c4f5b 100644 --- a/datasource.js +++ b/datasource.js @@ -24,13 +24,14 @@ import { LiquidityProvider1719335699480 } from './build/src/services/storage/mig import { CreateInviteTokenTable1721751414878 } from './build/src/services/storage/migrations/1721751414878-create_invite_token_table.js' import { PaymentIndex1721760297610 } from './build/src/services/storage/migrations/1721760297610-payment_index.js' import { DebitAccess1726496225078 } from './build/src/services/storage/migrations/1726496225078-debit_access.js' +import { DebitAccessFixes1726685229264 } from './build/src/services/storage/migrations/1726685229264-debit_access_fixes.js' export default new DataSource({ type: "sqlite", database: "db.sqlite", // logging: true, - migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078], + migrations: [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264], entities: [User, UserReceivingInvoice, UserReceivingAddress, AddressReceivingTransaction, UserInvoicePayment, UserTransactionPayment, UserBasicAuth, UserEphemeralKey, Product, UserToUserPayment, Application, ApplicationUser, UserToUserPayment, LspOrder, LndNodeInfo, TrackedProvider, InviteToken, DebitAccess], // synchronize: true, }) -//npx typeorm migration:generate ./src/services/storage/migrations/debit_access -d ./datasource.js \ No newline at end of file +//npx typeorm migration:generate ./src/services/storage/migrations/debit_access_fixes -d ./datasource.js \ No newline at end of file diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index 2d76dae5..cc4fccd3 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -30,8 +30,8 @@ The nostr server will send back a message response, and inside the body there wi - AuthorizeDebit - auth type: __User__ - - input: [DebitAuthorization](#DebitAuthorization) - - output: [AuthorizedDebit](#AuthorizedDebit) + - input: [DebitAuthorizationRequest](#DebitAuthorizationRequest) + - output: [DebitAuthorization](#DebitAuthorization) - BanUser - auth type: __Admin__ @@ -63,10 +63,10 @@ The nostr server will send back a message response, and inside the body there wi - input: [AppsMetricsRequest](#AppsMetricsRequest) - output: [AppsMetrics](#AppsMetrics) -- GetAuthorizedDebits +- GetDebitAuthorizations - auth type: __User__ - This methods has an __empty__ __request__ body - - output: [AuthorizedDebits](#AuthorizedDebits) + - output: [DebitAuthorizations](#DebitAuthorizations) - GetHttpCreds - auth type: __User__ @@ -83,6 +83,11 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - output: [LnurlLinkResponse](#LnurlLinkResponse) +- GetLiveDebitRequests + - auth type: __User__ + - This methods has an __empty__ __request__ body + - output: [LiveDebitRequest](#LiveDebitRequest) + - GetLiveUserOperations - auth type: __User__ - This methods has an __empty__ __request__ body @@ -275,8 +280,8 @@ The nostr server will send back a message response, and inside the body there wi - auth type: __User__ - http method: __post__ - http route: __/api/user/debit/authorize__ - - input: [DebitAuthorization](#DebitAuthorization) - - output: [AuthorizedDebit](#AuthorizedDebit) + - input: [DebitAuthorizationRequest](#DebitAuthorizationRequest) + - output: [DebitAuthorization](#DebitAuthorization) - BanUser - auth type: __Admin__ @@ -348,12 +353,12 @@ The nostr server will send back a message response, and inside the body there wi - input: [AppsMetricsRequest](#AppsMetricsRequest) - output: [AppsMetrics](#AppsMetrics) -- GetAuthorizedDebits +- GetDebitAuthorizations - auth type: __User__ - http method: __get__ - http route: __/api/user/debit/get__ - This methods has an __empty__ __request__ body - - output: [AuthorizedDebits](#AuthorizedDebits) + - output: [DebitAuthorizations](#DebitAuthorizations) - GetHttpCreds - auth type: __User__ @@ -376,6 +381,13 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - output: [LnurlLinkResponse](#LnurlLinkResponse) +- GetLiveDebitRequests + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/debit/sub__ + - This methods has an __empty__ __request__ body + - output: [LiveDebitRequest](#LiveDebitRequest) + - GetLiveUserOperations - auth type: __User__ - http method: __post__ @@ -711,14 +723,6 @@ The nostr server will send back a message response, and inside the body there wi - __allow_user_creation__: _boolean_ *this field is optional - __name__: _string_ -### AuthorizedDebit - - __debit_id__: _string_ - - __debit_type__: _[AuthorizedDebitType](#AuthorizedDebitType)_ - - __key__: _string_ - -### AuthorizedDebits - - __debits__: ARRAY of: _[AuthorizedDebit](#AuthorizedDebit)_ - ### BanUserRequest - __user_id__: _string_ @@ -747,7 +751,23 @@ The nostr server will send back a message response, and inside the body there wi - __invitation_link__: _string_ ### DebitAuthorization - - __authorize_npub__: _string_ *this field is optional + - __authorized__: _boolean_ + - __debit_id__: _string_ + - __npub__: _string_ + - __rules__: ARRAY of: _[DebitRule](#DebitRule)_ + +### DebitAuthorizationRequest + - __authorize_npub__: _string_ + - __rules__: ARRAY of: _[DebitRule](#DebitRule)_ + +### DebitAuthorizations + - __debits__: ARRAY of: _[DebitAuthorization](#DebitAuthorization)_ + +### DebitExpirationRule + - __expires_at_unix__: _number_ + +### DebitRule + - __rule__: _[DebitRule_rule](#DebitRule_rule)_ ### DecodeInvoiceRequest - __invoice__: _string_ @@ -764,6 +784,10 @@ The nostr server will send back a message response, and inside the body there wi ### EnrollAdminTokenRequest - __admin_token__: _string_ +### FrequencyRule + - __interval__: _[IntervalType](#IntervalType)_ + - __number_of_intervals__: _number_ + ### GetAppUserLNURLInfoRequest - __base_url_override__: _string_ - __user_identifier__: _string_ @@ -815,6 +839,11 @@ The nostr server will send back a message response, and inside the body there wi ### LinkNPubThroughTokenRequest - __token__: _string_ +### LiveDebitRequest + - __amount__: _number_ + - __debit__: _[LiveDebitRequest_debit](#LiveDebitRequest_debit)_ + - __npub__: _string_ + ### LiveUserOperation - __operation__: _[UserOperation](#UserOperation)_ @@ -951,7 +980,7 @@ The nostr server will send back a message response, and inside the body there wi - __relays__: ARRAY of: _string_ ### RemoveAuthorizedDebitRequest - - __debit_id__: _string_ + - __npub__: _string_ ### RequestNPubLinkingTokenRequest - __user_identifier__: _string_ @@ -1053,9 +1082,10 @@ The nostr server will send back a message response, and inside the body there wi - __TAPROOT_PUBKEY__ - __WITNESS_PUBKEY_HASH__ -### AuthorizedDebitType - - __KEY__ - - __NPUB__ +### IntervalType + - __DAY__ + - __MONTH__ + - __WEEK__ ### UserOperationType - __INCOMING_INVOICE__ diff --git a/proto/autogenerated/go/http_client.go b/proto/autogenerated/go/http_client.go new file mode 100644 index 00000000..99e511af --- /dev/null +++ b/proto/autogenerated/go/http_client.go @@ -0,0 +1,1551 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! + +package lightning_pub + +import ( + "net/url" + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" +) + +func doPostRequest(url string, body []byte, auth string) ([]byte, error) { + bodyReader := bytes.NewReader(body) + req, err := http.NewRequest(http.MethodPost, url, bodyReader) + if err != nil { + return nil, err + } + req.Header.Set("authorization", auth) + return doRequest(req) +} + +func doGetRequest(url string, auth string) ([]byte, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + req.Header.Set("authorization", auth) + return doRequest(req) +} + +func doRequest(req *http.Request) ([]byte, error) { + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + resBody, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + return resBody, nil +} + +type ClientParams struct { + BaseURL string + RetrieveAdminAuth func() (string, error) + RetrieveAppAuth func() (string, error) + RetrieveGuestAuth func() (string, error) + RetrieveGuestWithPubAuth func() (string, error) + RetrieveMetricsAuth func() (string, error) + RetrieveUserAuth func() (string, error) +} +type Client struct { + AddApp func(req AddAppRequest) (*AuthApp, error) + AddAppInvoice func(req AddAppInvoiceRequest) (*NewInvoiceResponse, error) + AddAppUser func(req AddAppUserRequest) (*AppUser, error) + AddAppUserInvoice func(req AddAppUserInvoiceRequest) (*NewInvoiceResponse, error) + AddProduct func(req AddProductRequest) (*Product, error) + AuthApp func(req AuthAppRequest) (*AuthApp, error) + AuthorizeDebit func(req DebitAuthorizationRequest) (*DebitAuthorization, error) + BanUser func(req BanUserRequest) (*BanUserResponse, error) + // batching method: BatchUser not implemented + CreateOneTimeInviteLink func(req CreateOneTimeInviteLinkRequest) (*CreateOneTimeInviteLinkResponse, error) + DecodeInvoice func(req DecodeInvoiceRequest) (*DecodeInvoiceResponse, error) + EncryptionExchange func(req EncryptionExchangeRequest) error + EnrollAdminToken func(req EnrollAdminTokenRequest) error + GetApp func() (*Application, error) + GetAppUser func(req GetAppUserRequest) (*AppUser, error) + GetAppUserLNURLInfo func(req GetAppUserLNURLInfoRequest) (*LnurlPayInfoResponse, error) + GetAppsMetrics func(req AppsMetricsRequest) (*AppsMetrics, error) + GetDebitAuthorizations func() (*DebitAuthorizations, error) + GetHttpCreds func() (*HttpCreds, error) + GetInviteLinkState func(req GetInviteTokenStateRequest) (*GetInviteTokenStateResponse, error) + GetLNURLChannelLink func() (*LnurlLinkResponse, error) + GetLiveDebitRequests func() (*LiveDebitRequest, error) + GetLiveUserOperations func() (*LiveUserOperation, error) + GetLndMetrics func(req LndMetricsRequest) (*LndMetrics, error) + GetLnurlPayInfo func(query GetLnurlPayInfo_Query) (*LnurlPayInfoResponse, error) + GetLnurlPayLink func() (*LnurlLinkResponse, error) + GetLnurlWithdrawInfo func(query GetLnurlWithdrawInfo_Query) (*LnurlWithdrawInfoResponse, error) + GetLnurlWithdrawLink func() (*LnurlLinkResponse, error) + GetMigrationUpdate func() (*MigrationUpdate, error) + GetPaymentState func(req GetPaymentStateRequest) (*PaymentState, error) + GetSeed func() (*LndSeed, error) + GetUsageMetrics func() (*UsageMetrics, error) + GetUserInfo func() (*UserInfo, error) + GetUserOperations func(req GetUserOperationsRequest) (*GetUserOperationsResponse, error) + HandleLnurlAddress func(routeParams HandleLnurlAddress_RouteParams) (*LnurlPayInfoResponse, error) + HandleLnurlPay func(query HandleLnurlPay_Query) (*HandleLnurlPayResponse, error) + HandleLnurlWithdraw func(query HandleLnurlWithdraw_Query) error + Health func() error + LinkNPubThroughToken func(req LinkNPubThroughTokenRequest) error + ListChannels func() (*LndChannels, error) + LndGetInfo func(req LndGetInfoRequest) (*LndGetInfoResponse, error) + NewAddress func(req NewAddressRequest) (*NewAddressResponse, error) + NewInvoice func(req NewInvoiceRequest) (*NewInvoiceResponse, error) + NewProductInvoice func(query NewProductInvoice_Query) (*NewInvoiceResponse, error) + OpenChannel func(req OpenChannelRequest) (*OpenChannelResponse, error) + PayAddress func(req PayAddressRequest) (*PayAddressResponse, error) + PayAppUserInvoice func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error) + PayInvoice func(req PayInvoiceRequest) (*PayInvoiceResponse, error) + RemoveAuthorizedDebit func(req RemoveAuthorizedDebitRequest) error + RequestNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) + ResetNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) + SendAppUserToAppPayment func(req SendAppUserToAppPaymentRequest) error + SendAppUserToAppUserPayment func(req SendAppUserToAppUserPaymentRequest) error + SetMockAppBalance func(req SetMockAppBalanceRequest) error + SetMockAppUserBalance func(req SetMockAppUserBalanceRequest) error + SetMockInvoiceAsPaid func(req SetMockInvoiceAsPaidRequest) error + UseInviteLink func(req UseInviteLinkRequest) error + UserHealth func() error +} + +func NewClient(params ClientParams) *Client { + return &Client{ + AddApp: func(req AddAppRequest) (*AuthApp, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/app/add" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := AuthApp{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AddAppInvoice: func(req AddAppInvoiceRequest) (*NewInvoiceResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/add/invoice" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := NewInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AddAppUser: func(req AddAppUserRequest) (*AppUser, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/add" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := AppUser{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AddAppUserInvoice: func(req AddAppUserInvoiceRequest) (*NewInvoiceResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/add/invoice" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := NewInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AddProduct: func(req AddProductRequest) (*Product, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/product/add" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := Product{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AuthApp: func(req AuthAppRequest) (*AuthApp, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/app/auth" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := AuthApp{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + AuthorizeDebit: func(req DebitAuthorizationRequest) (*DebitAuthorization, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/debit/authorize" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := DebitAuthorization{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + BanUser: func(req BanUserRequest) (*BanUserResponse, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/user/ban" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := BanUserResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + // batching method: BatchUser not implemented + CreateOneTimeInviteLink: func(req CreateOneTimeInviteLinkRequest) (*CreateOneTimeInviteLinkResponse, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/app/invite/create" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := CreateOneTimeInviteLinkResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + DecodeInvoice: func(req DecodeInvoiceRequest) (*DecodeInvoiceResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/invoice/decode" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := DecodeInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + EncryptionExchange: func(req EncryptionExchangeRequest) error { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return err + } + finalRoute := "/api/encryption/exchange" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + EnrollAdminToken: func(req EnrollAdminTokenRequest) error { + auth, err := params.RetrieveUserAuth() + if err != nil { + return err + } + finalRoute := "/api/guest/npub/enroll/admin" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + GetApp: func() (*Application, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/get" + body := []byte{} + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := Application{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetAppUser: func(req GetAppUserRequest) (*AppUser, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/get" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := AppUser{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetAppUserLNURLInfo: func(req GetAppUserLNURLInfoRequest) (*LnurlPayInfoResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/lnurl/pay/info" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlPayInfoResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetAppsMetrics: func(req AppsMetricsRequest) (*AppsMetrics, error) { + auth, err := params.RetrieveMetricsAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/reports/apps" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := AppsMetrics{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetDebitAuthorizations: func() (*DebitAuthorizations, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/debit/get" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := DebitAuthorizations{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + // server streaming method: GetHttpCreds not implemented + GetInviteLinkState: func(req GetInviteTokenStateRequest) (*GetInviteTokenStateResponse, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/app/invite/get" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := GetInviteTokenStateResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetLNURLChannelLink: func() (*LnurlLinkResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/lnurl_channel/url" + body := []byte{} + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlLinkResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + // server streaming method: GetLiveDebitRequests not implemented + // server streaming method: GetLiveUserOperations not implemented + GetLndMetrics: func(req LndMetricsRequest) (*LndMetrics, error) { + auth, err := params.RetrieveMetricsAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/reports/lnd" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LndMetrics{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetLnurlPayInfo: func(query GetLnurlPayInfo_Query) (*LnurlPayInfoResponse, error) { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/guest/lnurl_pay/info" + vals := url.Values{} + if query.K1 != nil { + vals.Set("k1", *query.K1) + } + q := vals.Encode() + if q != "" { + finalRoute = finalRoute + "?" + q + } + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlPayInfoResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetLnurlPayLink: func() (*LnurlLinkResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/lnurl_pay/link" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlLinkResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetLnurlWithdrawInfo: func(query GetLnurlWithdrawInfo_Query) (*LnurlWithdrawInfoResponse, error) { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/guest/lnurl_withdraw/info" + vals := url.Values{} + if query.K1 != nil { + vals.Set("k1", *query.K1) + } + q := vals.Encode() + if q != "" { + finalRoute = finalRoute + "?" + q + } + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlWithdrawInfoResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetLnurlWithdrawLink: func() (*LnurlLinkResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/lnurl_withdraw/link" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlLinkResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + // server streaming method: GetMigrationUpdate not implemented + GetPaymentState: func(req GetPaymentStateRequest) (*PaymentState, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/payment/state" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := PaymentState{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetSeed: func() (*LndSeed, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/seed" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LndSeed{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetUsageMetrics: func() (*UsageMetrics, error) { + auth, err := params.RetrieveMetricsAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/reports/usage" + body := []byte{} + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := UsageMetrics{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetUserInfo: func() (*UserInfo, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/info" + body := []byte{} + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := UserInfo{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + GetUserOperations: func(req GetUserOperationsRequest) (*GetUserOperationsResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/operations" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := GetUserOperationsResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + HandleLnurlAddress: func(routeParams HandleLnurlAddress_RouteParams) (*LnurlPayInfoResponse, error) { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return nil, err + } + finalRoute := "/.well-known/lnurlp/:address_name" + finalRoute = strings.Replace(finalRoute, ":address_name", routeParams.Address_name, 1) + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LnurlPayInfoResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + HandleLnurlPay: func(query HandleLnurlPay_Query) (*HandleLnurlPayResponse, error) { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/guest/lnurl_pay/handle" + vals := url.Values{} + if query.Amount != nil { + vals.Set("amount", *query.Amount) + } + if query.K1 != nil { + vals.Set("k1", *query.K1) + } + if query.Lnurl != nil { + vals.Set("lnurl", *query.Lnurl) + } + if query.Nostr != nil { + vals.Set("nostr", *query.Nostr) + } + q := vals.Encode() + if q != "" { + finalRoute = finalRoute + "?" + q + } + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := HandleLnurlPayResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + HandleLnurlWithdraw: func(query HandleLnurlWithdraw_Query) error { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return err + } + finalRoute := "/api/guest/lnurl_withdraw/handle" + vals := url.Values{} + if query.K1 != nil { + vals.Set("k1", *query.K1) + } + if query.Pr != nil { + vals.Set("pr", *query.Pr) + } + q := vals.Encode() + if q != "" { + finalRoute = finalRoute + "?" + q + } + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + Health: func() error { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return err + } + finalRoute := "/api/health" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + LinkNPubThroughToken: func(req LinkNPubThroughTokenRequest) error { + auth, err := params.RetrieveGuestWithPubAuth() + if err != nil { + return err + } + finalRoute := "/api/guest/npub/link" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + ListChannels: func() (*LndChannels, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/channels" + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LndChannels{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + LndGetInfo: func(req LndGetInfoRequest) (*LndGetInfoResponse, error) { + auth, err := params.RetrieveAdminAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/admin/lnd/getinfo" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LndGetInfoResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + NewAddress: func(req NewAddressRequest) (*NewAddressResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/chain/new" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := NewAddressResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + NewInvoice: func(req NewInvoiceRequest) (*NewInvoiceResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/invoice/new" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := NewInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + NewProductInvoice: func(query NewProductInvoice_Query) (*NewInvoiceResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/product/get/invoice" + vals := url.Values{} + if query.Id != nil { + vals.Set("id", *query.Id) + } + q := vals.Encode() + if q != "" { + finalRoute = finalRoute + "?" + q + } + resBody, err := doGetRequest(params.BaseURL+finalRoute, auth) + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := NewInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + OpenChannel: func(req OpenChannelRequest) (*OpenChannelResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/open/channel" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := OpenChannelResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + PayAddress: func(req PayAddressRequest) (*PayAddressResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/chain/pay" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := PayAddressResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + PayAppUserInvoice: func(req PayAppUserInvoiceRequest) (*PayInvoiceResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/invoice/pay" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := PayInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + PayInvoice: func(req PayInvoiceRequest) (*PayInvoiceResponse, error) { + auth, err := params.RetrieveUserAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/user/invoice/pay" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := PayInvoiceResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + RemoveAuthorizedDebit: func(req RemoveAuthorizedDebitRequest) error { + auth, err := params.RetrieveUserAuth() + if err != nil { + return err + } + finalRoute := "/api/user/debit/remove" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + RequestNPubLinkingToken: func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/npub/token" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := RequestNPubLinkingTokenResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + ResetNPubLinkingToken: func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) { + auth, err := params.RetrieveAppAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/app/user/npub/token/reset" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := RequestNPubLinkingTokenResponse{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, + SendAppUserToAppPayment: func(req SendAppUserToAppPaymentRequest) error { + auth, err := params.RetrieveAppAuth() + if err != nil { + return err + } + finalRoute := "/api/app/internal/pay" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + SendAppUserToAppUserPayment: func(req SendAppUserToAppUserPaymentRequest) error { + auth, err := params.RetrieveAppAuth() + if err != nil { + return err + } + finalRoute := "/api/app/user/internal/pay" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + SetMockAppBalance: func(req SetMockAppBalanceRequest) error { + auth, err := params.RetrieveAppAuth() + if err != nil { + return err + } + finalRoute := "/api/app/mock/blance/set" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + SetMockAppUserBalance: func(req SetMockAppUserBalanceRequest) error { + auth, err := params.RetrieveAppAuth() + if err != nil { + return err + } + finalRoute := "/api/app/mock/user/blance/set" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + SetMockInvoiceAsPaid: func(req SetMockInvoiceAsPaidRequest) error { + auth, err := params.RetrieveGuestAuth() + if err != nil { + return err + } + finalRoute := "/api/lnd/mock/invoice/paid" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + UseInviteLink: func(req UseInviteLinkRequest) error { + auth, err := params.RetrieveGuestWithPubAuth() + if err != nil { + return err + } + finalRoute := "/api/guest/invite" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + UserHealth: func() error { + auth, err := params.RetrieveUserAuth() + if err != nil { + return err + } + finalRoute := "/api/user/health" + body := []byte{} + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, + } +} diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go new file mode 100644 index 00000000..d9658ebb --- /dev/null +++ b/proto/autogenerated/go/types.go @@ -0,0 +1,515 @@ +// This file was autogenerated from a .proto file, DO NOT EDIT! + +package lightning_pub + +type ResultError struct { + Status string `json:"status"` + Reason string `json:"reason"` +} +type AdminContext struct { + Admin_id string `json:"admin_id"` +} +type AppContext struct { + App_id string `json:"app_id"` +} +type GuestContext struct { +} +type GuestWithPubContext struct { + App_id string `json:"app_id"` + Pub string `json:"pub"` +} +type MetricsContext struct { + Operator_id string `json:"operator_id"` +} +type UserContext struct { + App_id string `json:"app_id"` + App_user_id string `json:"app_user_id"` + User_id string `json:"user_id"` +} +type GetLnurlPayInfo_Query struct { + K1 *string `json:"k1,omitempty"` +} +type GetLnurlWithdrawInfo_Query struct { + K1 *string `json:"k1,omitempty"` +} +type HandleLnurlAddress_RouteParams struct { + Address_name string `json:"address_name"` +} +type HandleLnurlPay_Query struct { + Amount *string `json:"amount,omitempty"` + K1 *string `json:"k1,omitempty"` + Lnurl *string `json:"lnurl,omitempty"` + Nostr *string `json:"nostr,omitempty"` +} +type HandleLnurlWithdraw_Query struct { + K1 *string `json:"k1,omitempty"` + Pr *string `json:"pr,omitempty"` +} +type NewProductInvoice_Query struct { + Id *string `json:"id,omitempty"` +} +type AddressType string + +const ( + NESTED_PUBKEY_HASH AddressType = "NESTED_PUBKEY_HASH" + TAPROOT_PUBKEY AddressType = "TAPROOT_PUBKEY" + WITNESS_PUBKEY_HASH AddressType = "WITNESS_PUBKEY_HASH" +) + +type IntervalType string + +const ( + DAY IntervalType = "DAY" + MONTH IntervalType = "MONTH" + WEEK IntervalType = "WEEK" +) + +type UserOperationType string + +const ( + INCOMING_INVOICE UserOperationType = "INCOMING_INVOICE" + INCOMING_TX UserOperationType = "INCOMING_TX" + INCOMING_USER_TO_USER UserOperationType = "INCOMING_USER_TO_USER" + OUTGOING_INVOICE UserOperationType = "OUTGOING_INVOICE" + OUTGOING_TX UserOperationType = "OUTGOING_TX" + OUTGOING_USER_TO_USER UserOperationType = "OUTGOING_USER_TO_USER" +) + +type AddAppInvoiceRequest struct { + Http_callback_url string `json:"http_callback_url"` + Invoice_req *NewInvoiceRequest `json:"invoice_req"` + Payer_identifier string `json:"payer_identifier"` +} +type AddAppRequest struct { + Allow_user_creation bool `json:"allow_user_creation"` + Name string `json:"name"` +} +type AddAppUserInvoiceRequest struct { + Http_callback_url string `json:"http_callback_url"` + Invoice_req *NewInvoiceRequest `json:"invoice_req"` + Payer_identifier string `json:"payer_identifier"` + Receiver_identifier string `json:"receiver_identifier"` +} +type AddAppUserRequest struct { + Balance int64 `json:"balance"` + Fail_if_exists bool `json:"fail_if_exists"` + Identifier string `json:"identifier"` +} +type AddProductRequest struct { + Name string `json:"name"` + Price_sats int64 `json:"price_sats"` +} +type AppMetrics struct { + App *Application `json:"app"` + Available int64 `json:"available"` + Fees int64 `json:"fees"` + Invoices int64 `json:"invoices"` + Operations []UserOperation `json:"operations"` + Received int64 `json:"received"` + Spent int64 `json:"spent"` + Total_fees int64 `json:"total_fees"` + Users *UsersInfo `json:"users"` +} +type AppUser struct { + Identifier string `json:"identifier"` + Info *UserInfo `json:"info"` + Max_withdrawable int64 `json:"max_withdrawable"` +} +type Application struct { + Balance int64 `json:"balance"` + Id string `json:"id"` + Name string `json:"name"` + Npub string `json:"npub"` +} +type AppsMetrics struct { + Apps []AppMetrics `json:"apps"` +} +type AppsMetricsRequest struct { + From_unix int64 `json:"from_unix"` + Include_operations bool `json:"include_operations"` + To_unix int64 `json:"to_unix"` +} +type AuthApp struct { + App *Application `json:"app"` + Auth_token string `json:"auth_token"` +} +type AuthAppRequest struct { + Allow_user_creation bool `json:"allow_user_creation"` + Name string `json:"name"` +} +type BanUserRequest struct { + User_id string `json:"user_id"` +} +type BanUserResponse struct { + Balance_sats int64 `json:"balance_sats"` + Banned_app_users []BannedAppUser `json:"banned_app_users"` +} +type BannedAppUser struct { + App_id string `json:"app_id"` + App_name string `json:"app_name"` + Nostr_pub string `json:"nostr_pub"` + User_identifier string `json:"user_identifier"` +} +type ClosedChannel struct { + Capacity int64 `json:"capacity"` + Channel_id string `json:"channel_id"` + Closed_height int64 `json:"closed_height"` +} +type ClosureMigration struct { + Closes_at_unix int64 `json:"closes_at_unix"` +} +type CreateOneTimeInviteLinkRequest struct { + Sats int64 `json:"sats"` +} +type CreateOneTimeInviteLinkResponse struct { + Invitation_link string `json:"invitation_link"` +} +type DebitAuthorization struct { + Authorized bool `json:"authorized"` + Debit_id string `json:"debit_id"` + Npub string `json:"npub"` + Rules []DebitRule `json:"rules"` +} +type DebitAuthorizationRequest struct { + Authorize_npub string `json:"authorize_npub"` + Rules []DebitRule `json:"rules"` +} +type DebitAuthorizations struct { + Debits []DebitAuthorization `json:"debits"` +} +type DebitExpirationRule struct { + Expires_at_unix int64 `json:"expires_at_unix"` +} +type DebitRule struct { + Rule *DebitRule_rule `json:"rule"` +} +type DecodeInvoiceRequest struct { + Invoice string `json:"invoice"` +} +type DecodeInvoiceResponse struct { + Amount int64 `json:"amount"` +} +type Empty struct { +} +type EncryptionExchangeRequest struct { + Deviceid string `json:"deviceId"` + Publickey string `json:"publicKey"` +} +type EnrollAdminTokenRequest struct { + Admin_token string `json:"admin_token"` +} +type FrequencyRule struct { + Interval IntervalType `json:"interval"` + Number_of_intervals int64 `json:"number_of_intervals"` +} +type GetAppUserLNURLInfoRequest struct { + Base_url_override string `json:"base_url_override"` + User_identifier string `json:"user_identifier"` +} +type GetAppUserRequest struct { + User_identifier string `json:"user_identifier"` +} +type GetInviteTokenStateRequest struct { + Invite_token string `json:"invite_token"` +} +type GetInviteTokenStateResponse struct { + Used bool `json:"used"` +} +type GetPaymentStateRequest struct { + Invoice string `json:"invoice"` +} +type GetProductBuyLinkResponse struct { + Link string `json:"link"` +} +type GetUserOperationsRequest struct { + Latestincominginvoice int64 `json:"latestIncomingInvoice"` + Latestincomingtx int64 `json:"latestIncomingTx"` + Latestincomingusertouserpayment int64 `json:"latestIncomingUserToUserPayment"` + Latestoutgoinginvoice int64 `json:"latestOutgoingInvoice"` + Latestoutgoingtx int64 `json:"latestOutgoingTx"` + Latestoutgoingusertouserpayment int64 `json:"latestOutgoingUserToUserPayment"` + Max_size int64 `json:"max_size"` +} +type GetUserOperationsResponse struct { + Latestincominginvoiceoperations *UserOperations `json:"latestIncomingInvoiceOperations"` + Latestincomingtxoperations *UserOperations `json:"latestIncomingTxOperations"` + Latestincomingusertouserpayemnts *UserOperations `json:"latestIncomingUserToUserPayemnts"` + Latestoutgoinginvoiceoperations *UserOperations `json:"latestOutgoingInvoiceOperations"` + Latestoutgoingtxoperations *UserOperations `json:"latestOutgoingTxOperations"` + Latestoutgoingusertouserpayemnts *UserOperations `json:"latestOutgoingUserToUserPayemnts"` +} +type GraphPoint struct { + X int64 `json:"x"` + Y int64 `json:"y"` +} +type HandleLnurlPayResponse struct { + Pr string `json:"pr"` + Routes []Empty `json:"routes"` +} +type HttpCreds struct { + Token string `json:"token"` + Url string `json:"url"` +} +type LinkNPubThroughTokenRequest struct { + Token string `json:"token"` +} +type LiveDebitRequest struct { + Amount int64 `json:"amount"` + Debit *LiveDebitRequest_debit `json:"debit"` + Npub string `json:"npub"` +} +type LiveUserOperation struct { + Operation *UserOperation `json:"operation"` +} +type LndChannels struct { + Open_channels []OpenChannel `json:"open_channels"` +} +type LndGetInfoRequest struct { + Nodeid int64 `json:"nodeId"` +} +type LndGetInfoResponse struct { + Alias string `json:"alias"` +} +type LndMetrics struct { + Nodes []LndNodeMetrics `json:"nodes"` +} +type LndMetricsRequest struct { + From_unix int64 `json:"from_unix"` + To_unix int64 `json:"to_unix"` +} +type LndNodeMetrics struct { + Chain_balance []GraphPoint `json:"chain_balance"` + Channel_balance []GraphPoint `json:"channel_balance"` + Closed_channels []ClosedChannel `json:"closed_channels"` + Closing_channels int64 `json:"closing_channels"` + External_balance []GraphPoint `json:"external_balance"` + Forwarding_events int64 `json:"forwarding_events"` + Forwarding_fees int64 `json:"forwarding_fees"` + Offline_channels int64 `json:"offline_channels"` + Online_channels int64 `json:"online_channels"` + Open_channels []OpenChannel `json:"open_channels"` + Pending_channels int64 `json:"pending_channels"` +} +type LndSeed struct { + Seed []string `json:"seed"` +} +type LnurlLinkResponse struct { + K1 string `json:"k1"` + Lnurl string `json:"lnurl"` +} +type LnurlPayInfoResponse struct { + Allowsnostr bool `json:"allowsNostr"` + Callback string `json:"callback"` + Maxsendable int64 `json:"maxSendable"` + Metadata string `json:"metadata"` + Minsendable int64 `json:"minSendable"` + Nostrpubkey string `json:"nostrPubkey"` + Tag string `json:"tag"` +} +type LnurlWithdrawInfoResponse struct { + Balancecheck string `json:"balanceCheck"` + Callback string `json:"callback"` + Defaultdescription string `json:"defaultDescription"` + K1 string `json:"k1"` + Maxwithdrawable int64 `json:"maxWithdrawable"` + Minwithdrawable int64 `json:"minWithdrawable"` + Paylink string `json:"payLink"` + Tag string `json:"tag"` +} +type MigrationUpdate struct { + Closure *ClosureMigration `json:"closure"` + Relays *RelaysMigration `json:"relays"` +} +type NewAddressRequest struct { + Addresstype AddressType `json:"addressType"` +} +type NewAddressResponse struct { + Address string `json:"address"` +} +type NewInvoiceRequest struct { + Amountsats int64 `json:"amountSats"` + Memo string `json:"memo"` +} +type NewInvoiceResponse struct { + Invoice string `json:"invoice"` +} +type OpenChannel struct { + Active bool `json:"active"` + Capacity int64 `json:"capacity"` + Channel_id string `json:"channel_id"` + Label string `json:"label"` + Lifetime int64 `json:"lifetime"` + Local_balance int64 `json:"local_balance"` + Remote_balance int64 `json:"remote_balance"` +} +type OpenChannelRequest struct { + Closeaddress string `json:"closeAddress"` + Destination string `json:"destination"` + Fundingamount int64 `json:"fundingAmount"` + Pushamount int64 `json:"pushAmount"` +} +type OpenChannelResponse struct { + Channelid string `json:"channelId"` +} +type PayAddressRequest struct { + Address string `json:"address"` + Amoutsats int64 `json:"amoutSats"` + Satspervbyte int64 `json:"satsPerVByte"` +} +type PayAddressResponse struct { + Network_fee int64 `json:"network_fee"` + Operation_id string `json:"operation_id"` + Service_fee int64 `json:"service_fee"` + Txid string `json:"txId"` +} +type PayAppUserInvoiceRequest struct { + Amount int64 `json:"amount"` + Invoice string `json:"invoice"` + User_identifier string `json:"user_identifier"` +} +type PayInvoiceRequest struct { + Amount int64 `json:"amount"` + Invoice string `json:"invoice"` +} +type PayInvoiceResponse struct { + Amount_paid int64 `json:"amount_paid"` + Network_fee int64 `json:"network_fee"` + Operation_id string `json:"operation_id"` + Preimage string `json:"preimage"` + Service_fee int64 `json:"service_fee"` +} +type PaymentState struct { + Amount int64 `json:"amount"` + Network_fee int64 `json:"network_fee"` + Paid_at_unix int64 `json:"paid_at_unix"` + Service_fee int64 `json:"service_fee"` +} +type Product struct { + Id string `json:"id"` + Name string `json:"name"` + Noffer string `json:"noffer"` + Price_sats int64 `json:"price_sats"` +} +type RelaysMigration struct { + Relays []string `json:"relays"` +} +type RemoveAuthorizedDebitRequest struct { + Npub string `json:"npub"` +} +type RequestNPubLinkingTokenRequest struct { + User_identifier string `json:"user_identifier"` +} +type RequestNPubLinkingTokenResponse struct { + Token string `json:"token"` +} +type RoutingEvent struct { + Event_type string `json:"event_type"` + Failure_string string `json:"failure_string"` + Forward_fail_event bool `json:"forward_fail_event"` + Incoming_amt_msat int64 `json:"incoming_amt_msat"` + Incoming_channel_id int64 `json:"incoming_channel_id"` + Incoming_htlc_id int64 `json:"incoming_htlc_id"` + Offchain bool `json:"offchain"` + Outgoing_amt_msat int64 `json:"outgoing_amt_msat"` + Outgoing_channel_id int64 `json:"outgoing_channel_id"` + Outgoing_htlc_id int64 `json:"outgoing_htlc_id"` + Settled bool `json:"settled"` + Timestamp_ns int64 `json:"timestamp_ns"` +} +type SendAppUserToAppPaymentRequest struct { + Amount int64 `json:"amount"` + From_user_identifier string `json:"from_user_identifier"` +} +type SendAppUserToAppUserPaymentRequest struct { + Amount int64 `json:"amount"` + From_user_identifier string `json:"from_user_identifier"` + To_user_identifier string `json:"to_user_identifier"` +} +type SetMockAppBalanceRequest struct { + Amount int64 `json:"amount"` +} +type SetMockAppUserBalanceRequest struct { + Amount int64 `json:"amount"` + User_identifier string `json:"user_identifier"` +} +type SetMockInvoiceAsPaidRequest struct { + Amount int64 `json:"amount"` + Invoice string `json:"invoice"` +} +type UsageMetric struct { + Auth_in_nano int64 `json:"auth_in_nano"` + Batch bool `json:"batch"` + Batch_size int64 `json:"batch_size"` + Handle_in_nano int64 `json:"handle_in_nano"` + Nostr bool `json:"nostr"` + Parsed_in_nano int64 `json:"parsed_in_nano"` + Processed_at_ms int64 `json:"processed_at_ms"` + Rpc_name string `json:"rpc_name"` + Validate_in_nano int64 `json:"validate_in_nano"` +} +type UsageMetrics struct { + Metrics []UsageMetric `json:"metrics"` +} +type UseInviteLinkRequest struct { + Invite_token string `json:"invite_token"` +} +type UserInfo struct { + Balance int64 `json:"balance"` + Max_withdrawable int64 `json:"max_withdrawable"` + Network_max_fee_bps int64 `json:"network_max_fee_bps"` + Network_max_fee_fixed int64 `json:"network_max_fee_fixed"` + Noffer string `json:"noffer"` + Service_fee_bps int64 `json:"service_fee_bps"` + Userid string `json:"userId"` + User_identifier string `json:"user_identifier"` +} +type UserOperation struct { + Amount int64 `json:"amount"` + Confirmed bool `json:"confirmed"` + Identifier string `json:"identifier"` + Inbound bool `json:"inbound"` + Internal bool `json:"internal"` + Network_fee int64 `json:"network_fee"` + Operationid string `json:"operationId"` + Paidatunix int64 `json:"paidAtUnix"` + Service_fee int64 `json:"service_fee"` + Tx_hash string `json:"tx_hash"` + Type UserOperationType `json:"type"` +} +type UserOperations struct { + Fromindex int64 `json:"fromIndex"` + Operations []UserOperation `json:"operations"` + Toindex int64 `json:"toIndex"` +} +type UsersInfo struct { + Always_been_inactive int64 `json:"always_been_inactive"` + Balance_avg int64 `json:"balance_avg"` + Balance_median int64 `json:"balance_median"` + Negative_balance int64 `json:"negative_balance"` + No_balance int64 `json:"no_balance"` + Total int64 `json:"total"` +} +type DebitRule_rule_type string + +const ( + EXPIRATION_RULE DebitRule_rule_type = "expiration_rule" + FREQUENCY_RULE DebitRule_rule_type = "frequency_rule" +) + +type DebitRule_rule struct { + Type DebitRule_rule_type `json:"type"` + Expiration_rule *DebitExpirationRule `json:"expiration_rule"` + Frequency_rule *FrequencyRule `json:"frequency_rule"` +} +type LiveDebitRequest_debit_type string + +const ( + FREQUENCY LiveDebitRequest_debit_type = "frequency" + INVOICE LiveDebitRequest_debit_type = "invoice" +) + +type LiveDebitRequest_debit struct { + Type LiveDebitRequest_debit_type `json:"type"` + Frequency *FrequencyRule `json:"frequency"` + Invoice *string `json:"invoice"` +} diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index ba89f29b..2993271d 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -177,7 +177,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { authCtx = authContext stats.guard = process.hrtime.bigint() const request = req.body - const error = Types.DebitAuthorizationValidate(request) + const error = Types.DebitAuthorizationRequestValidate(request) stats.validate = process.hrtime.bigint() if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) const query = req.query @@ -247,7 +247,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { if (!methods.AuthorizeDebit) { throw new Error('method AuthorizeDebit not found' ) } else { - const error = Types.DebitAuthorizationValidate(operation.req) + const error = Types.DebitAuthorizationRequestValidate(operation.req) opStats.validate = process.hrtime.bigint() if (error !== null) throw error const res = await methods.AuthorizeDebit({...operation, ctx}); responses.push({ status: 'OK', ...res }) @@ -279,12 +279,12 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break - case 'GetAuthorizedDebits': - if (!methods.GetAuthorizedDebits) { - throw new Error('method GetAuthorizedDebits not found' ) + case 'GetDebitAuthorizations': + if (!methods.GetDebitAuthorizations) { + throw new Error('method GetDebitAuthorizations not found' ) } else { opStats.validate = opStats.guard - const res = await methods.GetAuthorizedDebits({...operation, ctx}); responses.push({ status: 'OK', ...res }) + const res = await methods.GetDebitAuthorizations({...operation, ctx}); responses.push({ status: 'OK', ...res }) opStats.handle = process.hrtime.bigint() callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } @@ -628,20 +628,20 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) - if (!opts.allowNotImplementedMethods && !methods.GetAuthorizedDebits) throw new Error('method: GetAuthorizedDebits is not implemented') + if (!opts.allowNotImplementedMethods && !methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented') app.get('/api/user/debit/get', async (req, res) => { - const info: Types.RequestInfo = { rpcName: 'GetAuthorizedDebits', batch: false, nostr: false, batchSize: 0} + const info: Types.RequestInfo = { rpcName: 'GetDebitAuthorizations', batch: false, nostr: false, batchSize: 0} const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } let authCtx: Types.AuthContext = {} try { - if (!methods.GetAuthorizedDebits) throw new Error('method: GetAuthorizedDebits is not implemented') + if (!methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented') const authContext = await opts.UserAuthGuard(req.headers['authorization']) authCtx = authContext stats.guard = process.hrtime.bigint() stats.validate = stats.guard const query = req.query const params = req.params - const response = await methods.GetAuthorizedDebits({rpcName:'GetAuthorizedDebits', ctx:authContext }) + const response = await methods.GetDebitAuthorizations({rpcName:'GetDebitAuthorizations', ctx:authContext }) stats.handle = process.hrtime.bigint() res.json({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index ef723331..96f52149 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -101,7 +101,7 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - AuthorizeDebit: async (request: Types.DebitAuthorization): Promise => { + AuthorizeDebit: async (request: Types.DebitAuthorizationRequest): Promise => { const auth = await params.retrieveUserAuth() if (auth === null) throw new Error('retrieveUserAuth() returned null') let finalRoute = '/api/user/debit/authorize' @@ -110,7 +110,7 @@ export default (params: ClientParams) => ({ if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthorizedDebitValidate(result) + const error = Types.DebitAuthorizationValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -246,7 +246,7 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAuthorizedDebits: async (): Promise => { + GetDebitAuthorizations: async (): Promise => { const auth = await params.retrieveUserAuth() if (auth === null) throw new Error('retrieveUserAuth() returned null') let finalRoute = '/api/user/debit/get' @@ -255,7 +255,7 @@ export default (params: ClientParams) => ({ if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthorizedDebitsValidate(result) + const error = Types.DebitAuthorizationsValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -289,6 +289,7 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, + GetLiveDebitRequests: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveDebitRequest)) => void): Promise => { throw new Error('http streams are not supported')}, GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { throw new Error('http streams are not supported')}, GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { const auth = await params.retrieveMetricsAuth() diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index be480249..1f2878b8 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -57,7 +57,7 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - AuthorizeDebit: async (request: Types.DebitAuthorization): Promise => { + AuthorizeDebit: async (request: Types.DebitAuthorizationRequest): Promise => { const auth = await params.retrieveNostrUserAuth() if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') const nostrRequest: NostrRequest = {} @@ -67,7 +67,7 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthorizedDebitValidate(result) + const error = Types.DebitAuthorizationValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -155,16 +155,16 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - GetAuthorizedDebits: async (): Promise => { + GetDebitAuthorizations: async (): Promise => { const auth = await params.retrieveNostrUserAuth() if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') const nostrRequest: NostrRequest = {} - const data = await send(params.pubDestination, {rpcName:'GetAuthorizedDebits',authIdentifier:auth, ...nostrRequest }) + const data = await send(params.pubDestination, {rpcName:'GetDebitAuthorizations',authIdentifier:auth, ...nostrRequest }) if (data.status === 'ERROR' && typeof data.reason === 'string') return data if (data.status === 'OK') { const result = data if(!params.checkResult) return { status: 'OK', ...result } - const error = Types.AuthorizedDebitsValidate(result) + const error = Types.DebitAuthorizationsValidate(result) if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } } return { status: 'ERROR', reason: 'invalid response' } @@ -213,6 +213,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, + GetLiveDebitRequests: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveDebitRequest)) => void): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + subscribe(params.pubDestination, {rpcName:'GetLiveDebitRequests',authIdentifier:auth, ...nostrRequest }, (data) => { + if (data.status === 'ERROR' && typeof data.reason === 'string') return cb(data) + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return cb({ status: 'OK', ...result }) + const error = Types.LiveDebitRequestValidate(result) + if (error === null) { return cb({ status: 'OK', ...result }) } else return cb({ status: 'ERROR', reason: error.message }) + } + return cb({ status: 'ERROR', reason: 'invalid response' }) + }) + }, GetLiveUserOperations: async (cb: (res:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { const auth = await params.retrieveNostrUserAuth() if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index 5d9032af..816b8ad8 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -87,7 +87,7 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { stats.guard = process.hrtime.bigint() authCtx = authContext const request = req.body - const error = Types.DebitAuthorizationValidate(request) + const error = Types.DebitAuthorizationRequestValidate(request) stats.validate = process.hrtime.bigint() if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) const response = await methods.AuthorizeDebit({rpcName:'AuthorizeDebit', ctx:authContext , req: request}) @@ -147,7 +147,7 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { if (!methods.AuthorizeDebit) { throw new Error('method not defined: AuthorizeDebit') } else { - const error = Types.DebitAuthorizationValidate(operation.req) + const error = Types.DebitAuthorizationRequestValidate(operation.req) opStats.validate = process.hrtime.bigint() if (error !== null) throw error const res = await methods.AuthorizeDebit({...operation, ctx}); responses.push({ status: 'OK', ...res }) @@ -179,12 +179,12 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break - case 'GetAuthorizedDebits': - if (!methods.GetAuthorizedDebits) { - throw new Error('method not defined: GetAuthorizedDebits') + case 'GetDebitAuthorizations': + if (!methods.GetDebitAuthorizations) { + throw new Error('method not defined: GetDebitAuthorizations') } else { opStats.validate = opStats.guard - const res = await methods.GetAuthorizedDebits({...operation, ctx}); responses.push({ status: 'OK', ...res }) + const res = await methods.GetDebitAuthorizations({...operation, ctx}); responses.push({ status: 'OK', ...res }) opStats.handle = process.hrtime.bigint() callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } @@ -419,14 +419,14 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break - case 'GetAuthorizedDebits': + case 'GetDebitAuthorizations': try { - if (!methods.GetAuthorizedDebits) throw new Error('method: GetAuthorizedDebits is not implemented') + if (!methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented') const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) stats.guard = process.hrtime.bigint() authCtx = authContext stats.validate = stats.guard - const response = await methods.GetAuthorizedDebits({rpcName:'GetAuthorizedDebits', ctx:authContext }) + const response = await methods.GetDebitAuthorizations({rpcName:'GetDebitAuthorizations', ctx:authContext }) stats.handle = process.hrtime.bigint() res({status: 'OK', ...response}) opts.metricsCallback([{ ...info, ...stats, ...authContext }]) @@ -474,6 +474,19 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break + case 'GetLiveDebitRequests': + try { + if (!methods.GetLiveDebitRequests) throw new Error('method: GetLiveDebitRequests is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + stats.validate = stats.guard + methods.GetLiveDebitRequests({rpcName:'GetLiveDebitRequests', ctx:authContext ,cb: (response, err) => { + stats.handle = process.hrtime.bigint() + if (err) { logErrorAndReturnResponse(err, err.message, res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)} else { res({status: 'OK', ...response});opts.metricsCallback([{ ...info, ...stats, ...authContext }])} + }}) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break case 'GetLiveUserOperations': try { if (!methods.GetLiveUserOperations) throw new Error('method: GetLiveUserOperations is not implemented') diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index 09e00639..4ead50bc 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -34,8 +34,8 @@ export type UserContext = { app_user_id: string user_id: string } -export type UserMethodInputs = AddProduct_Input | AuthorizeDebit_Input | DecodeInvoice_Input | EnrollAdminToken_Input | GetAuthorizedDebits_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | OpenChannel_Input | PayAddress_Input | PayInvoice_Input | RemoveAuthorizedDebit_Input | UserHealth_Input -export type UserMethodOutputs = AddProduct_Output | AuthorizeDebit_Output | DecodeInvoice_Output | EnrollAdminToken_Output | GetAuthorizedDebits_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | OpenChannel_Output | PayAddress_Output | PayInvoice_Output | RemoveAuthorizedDebit_Output | UserHealth_Output +export type UserMethodInputs = AddProduct_Input | AuthorizeDebit_Input | DecodeInvoice_Input | EnrollAdminToken_Input | GetDebitAuthorizations_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | OpenChannel_Input | PayAddress_Input | PayInvoice_Input | RemoveAuthorizedDebit_Input | UserHealth_Input +export type UserMethodOutputs = AddProduct_Output | AuthorizeDebit_Output | DecodeInvoice_Output | EnrollAdminToken_Output | GetDebitAuthorizations_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | OpenChannel_Output | PayAddress_Output | PayInvoice_Output | RemoveAuthorizedDebit_Output | UserHealth_Output export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} @@ -56,8 +56,8 @@ export type AddProduct_Output = ResultError | ({ status: 'OK' } & Product) export type AuthApp_Input = {rpcName:'AuthApp', req: AuthAppRequest} export type AuthApp_Output = ResultError | ({ status: 'OK' } & AuthApp) -export type AuthorizeDebit_Input = {rpcName:'AuthorizeDebit', req: DebitAuthorization} -export type AuthorizeDebit_Output = ResultError | ({ status: 'OK' } & AuthorizedDebit) +export type AuthorizeDebit_Input = {rpcName:'AuthorizeDebit', req: DebitAuthorizationRequest} +export type AuthorizeDebit_Output = ResultError | ({ status: 'OK' } & DebitAuthorization) export type BanUser_Input = {rpcName:'BanUser', req: BanUserRequest} export type BanUser_Output = ResultError | ({ status: 'OK' } & BanUserResponse) @@ -89,8 +89,8 @@ export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & Lnurl export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest} export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics) -export type GetAuthorizedDebits_Input = {rpcName:'GetAuthorizedDebits'} -export type GetAuthorizedDebits_Output = ResultError | ({ status: 'OK' } & AuthorizedDebits) +export type GetDebitAuthorizations_Input = {rpcName:'GetDebitAuthorizations'} +export type GetDebitAuthorizations_Output = ResultError | ({ status: 'OK' } & DebitAuthorizations) export type GetHttpCreds_Input = {rpcName:'GetHttpCreds', cb:(res: HttpCreds, err:Error|null)=> void} export type GetHttpCreds_Output = ResultError | { status: 'OK' } @@ -101,6 +101,9 @@ export type GetInviteLinkState_Output = ResultError | ({ status: 'OK' } & GetInv export type GetLNURLChannelLink_Input = {rpcName:'GetLNURLChannelLink'} export type GetLNURLChannelLink_Output = ResultError | ({ status: 'OK' } & LnurlLinkResponse) +export type GetLiveDebitRequests_Input = {rpcName:'GetLiveDebitRequests', cb:(res: LiveDebitRequest, err:Error|null)=> void} +export type GetLiveDebitRequests_Output = ResultError | { status: 'OK' } + export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void} export type GetLiveUserOperations_Output = ResultError | { status: 'OK' } @@ -238,7 +241,7 @@ export type ServerMethods = { AddAppUserInvoice?: (req: AddAppUserInvoice_Input & {ctx: AppContext }) => Promise AddProduct?: (req: AddProduct_Input & {ctx: UserContext }) => Promise AuthApp?: (req: AuthApp_Input & {ctx: AdminContext }) => Promise - AuthorizeDebit?: (req: AuthorizeDebit_Input & {ctx: UserContext }) => Promise + AuthorizeDebit?: (req: AuthorizeDebit_Input & {ctx: UserContext }) => Promise BanUser?: (req: BanUser_Input & {ctx: AdminContext }) => Promise CreateOneTimeInviteLink?: (req: CreateOneTimeInviteLink_Input & {ctx: AdminContext }) => Promise DecodeInvoice?: (req: DecodeInvoice_Input & {ctx: UserContext }) => Promise @@ -248,10 +251,11 @@ export type ServerMethods = { GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise - GetAuthorizedDebits?: (req: GetAuthorizedDebits_Input & {ctx: UserContext }) => Promise + GetDebitAuthorizations?: (req: GetDebitAuthorizations_Input & {ctx: UserContext }) => Promise GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise GetInviteLinkState?: (req: GetInviteLinkState_Input & {ctx: AdminContext }) => Promise GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise + GetLiveDebitRequests?: (req: GetLiveDebitRequests_Input & {ctx: UserContext }) => Promise GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise @@ -299,12 +303,13 @@ export const enumCheckAddressType = (e?: AddressType): boolean => { for (const v in AddressType) if (e === v) return true return false } -export enum AuthorizedDebitType { - KEY = 'KEY', - NPUB = 'NPUB', +export enum IntervalType { + DAY = 'DAY', + MONTH = 'MONTH', + WEEK = 'WEEK', } -export const enumCheckAuthorizedDebitType = (e?: AuthorizedDebitType): boolean => { - for (const v in AuthorizedDebitType) if (e === v) return true +export const enumCheckIntervalType = (e?: IntervalType): boolean => { + for (const v in IntervalType) if (e === v) return true return false } export enum UserOperationType { @@ -688,57 +693,6 @@ export const AuthAppRequestValidate = (o?: AuthAppRequest, opts: AuthAppRequestO return null } -export type AuthorizedDebit = { - debit_id: string - debit_type: AuthorizedDebitType - key: string -} -export const AuthorizedDebitOptionalFields: [] = [] -export type AuthorizedDebitOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - debit_id_CustomCheck?: (v: string) => boolean - debit_type_CustomCheck?: (v: AuthorizedDebitType) => boolean - key_CustomCheck?: (v: string) => boolean -} -export const AuthorizedDebitValidate = (o?: AuthorizedDebit, opts: AuthorizedDebitOptions = {}, path: string = 'AuthorizedDebit::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (typeof o.debit_id !== 'string') return new Error(`${path}.debit_id: is not a string`) - if (opts.debit_id_CustomCheck && !opts.debit_id_CustomCheck(o.debit_id)) return new Error(`${path}.debit_id: custom check failed`) - - if (!enumCheckAuthorizedDebitType(o.debit_type)) return new Error(`${path}.debit_type: is not a valid AuthorizedDebitType`) - if (opts.debit_type_CustomCheck && !opts.debit_type_CustomCheck(o.debit_type)) return new Error(`${path}.debit_type: custom check failed`) - - if (typeof o.key !== 'string') return new Error(`${path}.key: is not a string`) - if (opts.key_CustomCheck && !opts.key_CustomCheck(o.key)) return new Error(`${path}.key: custom check failed`) - - return null -} - -export type AuthorizedDebits = { - debits: AuthorizedDebit[] -} -export const AuthorizedDebitsOptionalFields: [] = [] -export type AuthorizedDebitsOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: [] - debits_ItemOptions?: AuthorizedDebitOptions - debits_CustomCheck?: (v: AuthorizedDebit[]) => boolean -} -export const AuthorizedDebitsValidate = (o?: AuthorizedDebits, opts: AuthorizedDebitsOptions = {}, path: string = 'AuthorizedDebits::root.'): Error | null => { - if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') - if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - - if (!Array.isArray(o.debits)) return new Error(`${path}.debits: is not an array`) - for (let index = 0; index < o.debits.length; index++) { - const debitsErr = AuthorizedDebitValidate(o.debits[index], opts.debits_ItemOptions, `${path}.debits[${index}]`) - if (debitsErr !== null) return debitsErr - } - if (opts.debits_CustomCheck && !opts.debits_CustomCheck(o.debits)) return new Error(`${path}.debits: custom check failed`) - - return null -} - export type BanUserRequest = { user_id: string } @@ -902,21 +856,128 @@ export const CreateOneTimeInviteLinkResponseValidate = (o?: CreateOneTimeInviteL } export type DebitAuthorization = { - authorize_npub?: string + authorized: boolean + debit_id: string + npub: string + rules: DebitRule[] } -export type DebitAuthorizationOptionalField = 'authorize_npub' -export const DebitAuthorizationOptionalFields: DebitAuthorizationOptionalField[] = ['authorize_npub'] +export const DebitAuthorizationOptionalFields: [] = [] export type DebitAuthorizationOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: DebitAuthorizationOptionalField[] - authorize_npub_CustomCheck?: (v?: string) => boolean + checkOptionalsAreSet?: [] + authorized_CustomCheck?: (v: boolean) => boolean + debit_id_CustomCheck?: (v: string) => boolean + npub_CustomCheck?: (v: string) => boolean + rules_ItemOptions?: DebitRuleOptions + rules_CustomCheck?: (v: DebitRule[]) => boolean } export const DebitAuthorizationValidate = (o?: DebitAuthorization, opts: DebitAuthorizationOptions = {}, path: string = 'DebitAuthorization::root.'): Error | null => { if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - if ((o.authorize_npub || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('authorize_npub')) && typeof o.authorize_npub !== 'string') return new Error(`${path}.authorize_npub: is not a string`) + if (typeof o.authorized !== 'boolean') return new Error(`${path}.authorized: is not a boolean`) + if (opts.authorized_CustomCheck && !opts.authorized_CustomCheck(o.authorized)) return new Error(`${path}.authorized: custom check failed`) + + if (typeof o.debit_id !== 'string') return new Error(`${path}.debit_id: is not a string`) + if (opts.debit_id_CustomCheck && !opts.debit_id_CustomCheck(o.debit_id)) return new Error(`${path}.debit_id: custom check failed`) + + if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) + if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) + + if (!Array.isArray(o.rules)) return new Error(`${path}.rules: is not an array`) + for (let index = 0; index < o.rules.length; index++) { + const rulesErr = DebitRuleValidate(o.rules[index], opts.rules_ItemOptions, `${path}.rules[${index}]`) + if (rulesErr !== null) return rulesErr + } + if (opts.rules_CustomCheck && !opts.rules_CustomCheck(o.rules)) return new Error(`${path}.rules: custom check failed`) + + return null +} + +export type DebitAuthorizationRequest = { + authorize_npub: string + rules: DebitRule[] +} +export const DebitAuthorizationRequestOptionalFields: [] = [] +export type DebitAuthorizationRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + authorize_npub_CustomCheck?: (v: string) => boolean + rules_ItemOptions?: DebitRuleOptions + rules_CustomCheck?: (v: DebitRule[]) => boolean +} +export const DebitAuthorizationRequestValidate = (o?: DebitAuthorizationRequest, opts: DebitAuthorizationRequestOptions = {}, path: string = 'DebitAuthorizationRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.authorize_npub !== 'string') return new Error(`${path}.authorize_npub: is not a string`) if (opts.authorize_npub_CustomCheck && !opts.authorize_npub_CustomCheck(o.authorize_npub)) return new Error(`${path}.authorize_npub: custom check failed`) + if (!Array.isArray(o.rules)) return new Error(`${path}.rules: is not an array`) + for (let index = 0; index < o.rules.length; index++) { + const rulesErr = DebitRuleValidate(o.rules[index], opts.rules_ItemOptions, `${path}.rules[${index}]`) + if (rulesErr !== null) return rulesErr + } + if (opts.rules_CustomCheck && !opts.rules_CustomCheck(o.rules)) return new Error(`${path}.rules: custom check failed`) + + return null +} + +export type DebitAuthorizations = { + debits: DebitAuthorization[] +} +export const DebitAuthorizationsOptionalFields: [] = [] +export type DebitAuthorizationsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + debits_ItemOptions?: DebitAuthorizationOptions + debits_CustomCheck?: (v: DebitAuthorization[]) => boolean +} +export const DebitAuthorizationsValidate = (o?: DebitAuthorizations, opts: DebitAuthorizationsOptions = {}, path: string = 'DebitAuthorizations::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.debits)) return new Error(`${path}.debits: is not an array`) + for (let index = 0; index < o.debits.length; index++) { + const debitsErr = DebitAuthorizationValidate(o.debits[index], opts.debits_ItemOptions, `${path}.debits[${index}]`) + if (debitsErr !== null) return debitsErr + } + if (opts.debits_CustomCheck && !opts.debits_CustomCheck(o.debits)) return new Error(`${path}.debits: custom check failed`) + + return null +} + +export type DebitExpirationRule = { + expires_at_unix: number +} +export const DebitExpirationRuleOptionalFields: [] = [] +export type DebitExpirationRuleOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + expires_at_unix_CustomCheck?: (v: number) => boolean +} +export const DebitExpirationRuleValidate = (o?: DebitExpirationRule, opts: DebitExpirationRuleOptions = {}, path: string = 'DebitExpirationRule::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.expires_at_unix !== 'number') return new Error(`${path}.expires_at_unix: is not a number`) + if (opts.expires_at_unix_CustomCheck && !opts.expires_at_unix_CustomCheck(o.expires_at_unix)) return new Error(`${path}.expires_at_unix: custom check failed`) + + return null +} + +export type DebitRule = { + rule: DebitRule_rule +} +export const DebitRuleOptionalFields: [] = [] +export type DebitRuleOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + rule_Options?: DebitRule_ruleOptions +} +export const DebitRuleValidate = (o?: DebitRule, opts: DebitRuleOptions = {}, path: string = 'DebitRule::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + const ruleErr = DebitRule_ruleValidate(o.rule, opts.rule_Options, `${path}.rule`) + if (ruleErr !== null) return ruleErr + + return null } @@ -1010,6 +1071,29 @@ export const EnrollAdminTokenRequestValidate = (o?: EnrollAdminTokenRequest, opt return null } +export type FrequencyRule = { + interval: IntervalType + number_of_intervals: number +} +export const FrequencyRuleOptionalFields: [] = [] +export type FrequencyRuleOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + interval_CustomCheck?: (v: IntervalType) => boolean + number_of_intervals_CustomCheck?: (v: number) => boolean +} +export const FrequencyRuleValidate = (o?: FrequencyRule, opts: FrequencyRuleOptions = {}, path: string = 'FrequencyRule::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!enumCheckIntervalType(o.interval)) return new Error(`${path}.interval: is not a valid IntervalType`) + if (opts.interval_CustomCheck && !opts.interval_CustomCheck(o.interval)) return new Error(`${path}.interval: custom check failed`) + + if (typeof o.number_of_intervals !== 'number') return new Error(`${path}.number_of_intervals: is not a number`) + if (opts.number_of_intervals_CustomCheck && !opts.number_of_intervals_CustomCheck(o.number_of_intervals)) return new Error(`${path}.number_of_intervals: custom check failed`) + + return null +} + export type GetAppUserLNURLInfoRequest = { base_url_override: string user_identifier: string @@ -1312,6 +1396,35 @@ export const LinkNPubThroughTokenRequestValidate = (o?: LinkNPubThroughTokenRequ return null } +export type LiveDebitRequest = { + amount: number + debit: LiveDebitRequest_debit + npub: string +} +export const LiveDebitRequestOptionalFields: [] = [] +export type LiveDebitRequestOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amount_CustomCheck?: (v: number) => boolean + debit_Options?: LiveDebitRequest_debitOptions + npub_CustomCheck?: (v: string) => boolean +} +export const LiveDebitRequestValidate = (o?: LiveDebitRequest, opts: LiveDebitRequestOptions = {}, path: string = 'LiveDebitRequest::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amount !== 'number') return new Error(`${path}.amount: is not a number`) + if (opts.amount_CustomCheck && !opts.amount_CustomCheck(o.amount)) return new Error(`${path}.amount: custom check failed`) + + const debitErr = LiveDebitRequest_debitValidate(o.debit, opts.debit_Options, `${path}.debit`) + if (debitErr !== null) return debitErr + + + if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) + if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) + + return null +} + export type LiveUserOperation = { operation: UserOperation } @@ -2119,19 +2232,19 @@ export const RelaysMigrationValidate = (o?: RelaysMigration, opts: RelaysMigrati } export type RemoveAuthorizedDebitRequest = { - debit_id: string + npub: string } export const RemoveAuthorizedDebitRequestOptionalFields: [] = [] export type RemoveAuthorizedDebitRequestOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] - debit_id_CustomCheck?: (v: string) => boolean + npub_CustomCheck?: (v: string) => boolean } export const RemoveAuthorizedDebitRequestValidate = (o?: RemoveAuthorizedDebitRequest, opts: RemoveAuthorizedDebitRequestOptions = {}, path: string = 'RemoveAuthorizedDebitRequest::root.'): Error | null => { if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') - if (typeof o.debit_id !== 'string') return new Error(`${path}.debit_id: is not a string`) - if (opts.debit_id_CustomCheck && !opts.debit_id_CustomCheck(o.debit_id)) return new Error(`${path}.debit_id: custom check failed`) + if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) + if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) return null } @@ -2656,3 +2769,76 @@ export const UsersInfoValidate = (o?: UsersInfo, opts: UsersInfoOptions = {}, pa return null } +export enum DebitRule_rule_type { + EXPIRATION_RULE = 'expiration_rule', + FREQUENCY_RULE = 'frequency_rule', +} +export const enumCheckDebitRule_rule_type = (e?: DebitRule_rule_type): boolean => { + for (const v in DebitRule_rule_type) if (e === v) return true + return false +} +export type DebitRule_rule = + {type:DebitRule_rule_type.EXPIRATION_RULE, expiration_rule:DebitExpirationRule}| + {type:DebitRule_rule_type.FREQUENCY_RULE, frequency_rule:FrequencyRule} + +export type DebitRule_ruleOptions = { + expiration_rule_Options?: DebitExpirationRuleOptions + frequency_rule_Options?: FrequencyRuleOptions +} +export const DebitRule_ruleValidate = (o?: DebitRule_rule, opts:DebitRule_ruleOptions = {}, path: string = 'DebitRule_rule::root.'): Error | null => { + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + const stringType: string = o.type + switch (o.type) { + case DebitRule_rule_type.EXPIRATION_RULE: + const expiration_ruleErr = DebitExpirationRuleValidate(o.expiration_rule, opts.expiration_rule_Options, `${path}.expiration_rule`) + if (expiration_ruleErr !== null) return expiration_ruleErr + + + break + case DebitRule_rule_type.FREQUENCY_RULE: + const frequency_ruleErr = FrequencyRuleValidate(o.frequency_rule, opts.frequency_rule_Options, `${path}.frequency_rule`) + if (frequency_ruleErr !== null) return frequency_ruleErr + + + break + default: + return new Error(path + ': unknown type '+ stringType) + } + return null +} +export enum LiveDebitRequest_debit_type { + FREQUENCY = 'frequency', + INVOICE = 'invoice', +} +export const enumCheckLiveDebitRequest_debit_type = (e?: LiveDebitRequest_debit_type): boolean => { + for (const v in LiveDebitRequest_debit_type) if (e === v) return true + return false +} +export type LiveDebitRequest_debit = + {type:LiveDebitRequest_debit_type.FREQUENCY, frequency:FrequencyRule}| + {type:LiveDebitRequest_debit_type.INVOICE, invoice:string} + +export type LiveDebitRequest_debitOptions = { + frequency_Options?: FrequencyRuleOptions + invoice_CustomCheck?: (v: string) => boolean +} +export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:LiveDebitRequest_debitOptions = {}, path: string = 'LiveDebitRequest_debit::root.'): Error | null => { + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + const stringType: string = o.type + switch (o.type) { + case LiveDebitRequest_debit_type.FREQUENCY: + const frequencyErr = FrequencyRuleValidate(o.frequency, opts.frequency_Options, `${path}.frequency`) + if (frequencyErr !== null) return frequencyErr + + + break + case LiveDebitRequest_debit_type.INVOICE: + if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`) + if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`) + + break + default: + return new Error(path + ': unknown type '+ stringType) + } + return null +} diff --git a/proto/protoc-gen-pub b/proto/protoc-gen-pub index 37b547ae..637823db 100755 Binary files a/proto/protoc-gen-pub and b/proto/protoc-gen-pub differ diff --git a/proto/service/methods.proto b/proto/service/methods.proto index fe419927..fde9edeb 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -435,7 +435,7 @@ service LightningPub { option (http_route) = "/api/user/lnurl_channel/url"; option (nostr) = true; } - rpc GetAuthorizedDebits(structs.Empty) returns (structs.AuthorizedDebits){ + rpc GetDebitAuthorizations(structs.Empty) returns (structs.DebitAuthorizations){ option (auth_type) = "User"; option (http_method) = "get"; option (http_route) = "/api/user/debit/get"; @@ -447,12 +447,18 @@ service LightningPub { option (http_route) = "/api/user/debit/remove"; option (nostr) = true; } - rpc AuthorizeDebit(structs.DebitAuthorization) returns (structs.AuthorizedDebit){ + rpc AuthorizeDebit(structs.DebitAuthorizationRequest) returns (structs.DebitAuthorization){ option (auth_type) = "User"; option (http_method) = "post"; option (http_route) = "/api/user/debit/authorize"; option (nostr) = true; } + rpc GetLiveDebitRequests(structs.Empty) returns (stream structs.LiveDebitRequest){ + option (auth_type) = "User"; + option (http_method) = "post"; + option (http_route) = "/api/user/debit/sub"; + option (nostr) = true; + } rpc GetLiveUserOperations(structs.Empty) returns (stream structs.LiveUserOperation){ option (auth_type) = "User"; option (http_method) = "post"; diff --git a/proto/service/structs.proto b/proto/service/structs.proto index c4474b67..c42e582e 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -480,25 +480,53 @@ message GetInviteTokenStateResponse { +message DebitAuthorizationRequest { + string authorize_npub = 1; + repeated DebitRule rules = 2; +} + message DebitAuthorization { - optional string authorize_npub =1; -} - -enum AuthorizedDebitType { - NPUB = 0; - KEY = 1; -} - -message AuthorizedDebit { string debit_id = 1; - AuthorizedDebitType debit_type = 2; - string key = 3; + bool authorized = 2; + string npub = 3; + repeated DebitRule rules = 4; + } -message AuthorizedDebits { - repeated AuthorizedDebit debits = 1; +message DebitAuthorizations { + repeated DebitAuthorization debits = 1; } message RemoveAuthorizedDebitRequest { - string debit_id = 1; + string npub = 1; +} + +message DebitExpirationRule { + int64 expires_at_unix = 1; +} + +enum IntervalType { + DAY = 0; + WEEK = 1; + MONTH = 2; +} +message FrequencyRule { + int64 number_of_intervals = 1; + IntervalType interval = 2; +} + +message DebitRule { + oneof rule { + DebitExpirationRule expiration_rule = 1; + FrequencyRule frequency_rule = 2; + } +} + +message LiveDebitRequest { + string npub = 1; + int64 amount = 2; + oneof debit { + string invoice = 3; + FrequencyRule frequency = 4; + } } \ No newline at end of file diff --git a/src/services/main/debitManager.ts b/src/services/main/debitManager.ts index a7cfa4a1..51166926 100644 --- a/src/services/main/debitManager.ts +++ b/src/services/main/debitManager.ts @@ -1,12 +1,26 @@ import crypto from 'crypto'; import * as Types from "../../../proto/autogenerated/ts/types.js"; import ApplicationManager from "./applicationManager.js"; -import { DebitKeyType } from "../storage/entity/DebitAccess.js"; import Storage from '../storage/index.js' import LND from "../lnd/lnd.js" import { ERROR, getLogger } from "../helpers/logger.js"; -export type NdebitData = { pointer?: string, bolt11: string, amount_sats: number } -export type NdebitSuccess = { res: 'ok', preimage: string } +import { DebitAccess, DebitAccessRules } from '../storage/entity/DebitAccess.js'; +export const expirationRuleName = 'expiration' +export const frequencyRuleName = 'frequency' +type RecurringDebitTimeUnit = 'day' | 'week' | 'month' +type RecurringDebit = { frequency: { number: number, unit: RecurringDebitTimeUnit } } +const unitToIntervalType = (unit: RecurringDebitTimeUnit) => { + switch (unit) { + case 'day': return Types.IntervalType.DAY + case 'week': return Types.IntervalType.WEEK + case 'month': return Types.IntervalType.MONTH + default: throw new Error("invalid unit") + } + +} +export type NdebitData = { pointer?: string, amount_sats: number } & (RecurringDebit | { bolt11: string }) +export type NdebitSuccess = { res: 'ok' } +export type NdebitSuccessPayment = { res: 'ok', preimage: string } export type NdebitFailure = { res: 'GFY', error: string, code: number } const nip68errs = { 1: "Request Denied Warning", @@ -16,8 +30,10 @@ const nip68errs = { 5: "Invalid Amount", 6: "Invalid Request", } -export type NdebitResponse = NdebitSuccess | NdebitFailure -type HandleNdebitRes = { ok: false, debitRes: NdebitFailure } | { ok: true, op: Types.UserOperation, appUserId: string, debitRes: NdebitSuccess } +type HandleNdebitRes = { status: 'fail', debitRes: NdebitFailure } + | { status: 'invoicePaid', op: Types.UserOperation, appUserId: string, debitRes: NdebitSuccessPayment } + | { status: 'authRequired', liveDebitReq: Types.LiveDebitRequest, appUserId: string } + | { status: 'authOk', debitRes: NdebitSuccess } export class DebitManager { @@ -30,35 +46,29 @@ export class DebitManager { this.storage = storage } - AuthorizeDebit = async (ctx: Types.UserContext, req: Types.DebitAuthorization): Promise => { - const debitType = this.getDebitType(req.authorize_npub) - const access = await this.storage.debitStorage.AddDebitAccess(ctx.app_user_id, debitType.key, debitType.keyType) + AuthorizeDebit = async (ctx: Types.UserContext, req: Types.DebitAuthorizationRequest): Promise => { + const access = await this.storage.debitStorage.AddDebitAccess(ctx.app_user_id, req.authorize_npub) return { debit_id: access.serial_id.toString(), - debit_type: debitType.debitType, - key: debitType.key, + npub: req.authorize_npub, + authorized: true, + rules: [] } } - getDebitType = (authorizeNpub?: string): { keyType: DebitKeyType, key: string, debitType: Types.AuthorizedDebitType } => { - if (authorizeNpub) { - return { keyType: 'pubKey', key: authorizeNpub, debitType: Types.AuthorizedDebitType.NPUB } - } - return { keyType: 'simpleId', key: crypto.randomBytes(32).toString('hex'), debitType: Types.AuthorizedDebitType.KEY } - } - - GetAuthorizedDebits = async (ctx: Types.UserContext): Promise => { + GetDebitAuthorizations = async (ctx: Types.UserContext): Promise => { const allDebitsAccesses = await this.storage.debitStorage.GetAllUserDebitAccess(ctx.app_user_id) - const debits: Types.AuthorizedDebit[] = allDebitsAccesses.map(access => ({ + const debits: Types.DebitAuthorization[] = allDebitsAccesses.map(access => ({ debit_id: access.serial_id.toString(), - debit_type: access.key_type === 'pubKey' ? Types.AuthorizedDebitType.NPUB : Types.AuthorizedDebitType.KEY, - key: access.key + authorized: access.authorized, + npub: access.npub, + rules: [] })) return { debits } } RemoveAuthorizedDebit = async (ctx: Types.UserContext, req: Types.RemoveAuthorizedDebitRequest): Promise => { - await this.storage.debitStorage.RemoveDebitAccess(ctx.app_user_id, +req.debit_id) + await this.storage.debitStorage.RemoveDebitAccess(ctx.app_user_id, req.npub) } payNdebitInvoice = async (appId: string, requestorPub: string, pointerdata: NdebitData): Promise => { @@ -66,50 +76,90 @@ export class DebitManager { return await this.doNdebit(appId, requestorPub, pointerdata) } catch (e: any) { this.logger(ERROR, e.message || e) - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } } } doNdebit = async (appId: string, requestorPub: string, pointerdata: NdebitData): Promise => { - const { amount_sats, bolt11, pointer } = pointerdata + const { amount_sats, pointer } = pointerdata + if (!pointer) { + // TODO: debit from app owner balance + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[2], code: 2 } } + } + const appUserId = pointer + const pointerFreq = pointerdata as RecurringDebit + if (pointerFreq.frequency) { + const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub) + if (!debitAccess) { + return { + status: 'authRequired', appUserId, liveDebitReq: { + amount: pointerdata.amount_sats, + npub: requestorPub, + debit: { + type: Types.LiveDebitRequest_debit_type.FREQUENCY, + frequency: { + interval: unitToIntervalType(pointerFreq.frequency.unit), + number_of_intervals: pointerFreq.frequency.number, + } + } + } + } + } else if (!debitAccess.authorized) { + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } + } + return { status: 'authOk', debitRes: { res: 'ok' } } + } + const { bolt11 } = pointerdata as { bolt11: string } if (!bolt11) { - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } } + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } } } const decoded = await this.lnd.DecodeInvoice(bolt11) if (decoded.numSatoshis === 0) { - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } } + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } } } if (amount_sats && amount_sats !== decoded.numSatoshis) { - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } } + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } } } - if (!pointer) { - // TODO: debit from app owner balance - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[2], code: 2 } } - } - const split = pointer.split(':') - let keyType: DebitKeyType - let key: string - let appUserId: string - if (split.length === 1) { - keyType = 'pubKey' - key = requestorPub - appUserId = split[0] - } else { - keyType = 'simpleId' - key = split[0] - appUserId = split[1] - } - const authorization = await this.storage.debitStorage.GetDebitAccess(appUserId, key, keyType) + const authorization = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub) if (!authorization) { - return { ok: false, debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } + return { + status: 'authRequired', appUserId, liveDebitReq: { + amount: pointerdata.amount_sats, + npub: requestorPub, + debit: { + type: Types.LiveDebitRequest_debit_type.INVOICE, + invoice: bolt11 + } + } + } } + if (!authorization.authorized) { + return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } } + } + await this.validateAccessRules(authorization) const payment = await this.applicationManager.PayAppUserInvoice(appId, { amount: 0, invoice: bolt11, user_identifier: appUserId }) - await this.storage.debitStorage.IncrementDebitAccess(appUserId, key, keyType, payment.amount_paid + payment.service_fee + payment.network_fee) + await this.storage.debitStorage.IncrementDebitAccess(appUserId, requestorPub, payment.amount_paid + payment.service_fee + payment.network_fee) const op = this.newPaymentOperation(payment, bolt11) - return { ok: true, op, appUserId, debitRes: { res: 'ok', preimage: payment.preimage } } + return { status: 'invoicePaid', op, appUserId, debitRes: { res: 'ok', preimage: payment.preimage } } } + validateAccessRules = async (access: DebitAccess): Promise => { + const { rules } = access + if (!rules) { + return true + } + return false + // TODO: rules validation + /* if (rules[expirationRuleName]) { + + } + if (rules[frequencyRuleName]) { + + } */ + } + + newPaymentOperation = (payment: Types.PayInvoiceResponse, bolt11: string) => { return { amount: payment.amount_paid, @@ -125,7 +175,5 @@ export class DebitManager { internal: payment.network_fee === 0 } } - - } diff --git a/src/services/main/index.ts b/src/services/main/index.ts index cb0d4dd6..d3af98bc 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -23,7 +23,6 @@ import { AdminManager } from "./adminManager.js" import { Unlocker } from "./unlocker.js" import { defaultInvoiceExpiry } from "../storage/paymentStorage.js" import { DebitPointer } from "../../custom-nip19.js" -import { DebitKeyType } from "../storage/entity/DebitAccess.js" import { DebitManager, NdebitData } from "./debitManager.js" type UserOperationsSub = { @@ -322,16 +321,23 @@ export default class { handleNip68Debit = async (pointerdata: NdebitData, event: NostrEvent) => { const res = await this.debitManager.payNdebitInvoice(event.appId, event.pub, pointerdata) - if (!res.ok) { + if (res.status === 'fail' || res.status === 'authOk') { const e = newNdebitResponse(JSON.stringify(res.debitRes), event) this.nostrSend({ type: 'app', appId: event.appId }, { type: 'event', event: e, encrypt: { toPub: event.pub } }) return } - const { op, appUserId, debitRes } = res - const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } = { operation: op, requestId: "GetLiveUserOperations", status: 'OK' } const app = await this.storage.applicationStorage.GetApplication(event.appId) - const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId) - if (appUser.nostr_public_key) { + const appUser = await this.storage.applicationStorage.GetApplicationUser(app, res.appUserId) + if (res.status === 'authRequired') { + const message: Types.LiveDebitRequest & { requestId: string, status: 'OK' } = { ...res.liveDebitReq, requestId: "GetLiveUserOperations", status: 'OK' } + if (appUser.nostr_public_key) {// TODO - fix before support for http streams + this.nostrSend({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key }) + } + return + } + const { op, debitRes } = res + const message: Types.LiveUserOperation & { requestId: string, status: 'OK' } = { operation: op, requestId: "GetLiveUserOperations", status: 'OK' } + if (appUser.nostr_public_key) { // TODO - fix before support for http streams this.nostrSend({ type: 'app', appId: event.appId }, { type: 'content', content: JSON.stringify(message), pub: appUser.nostr_public_key }) } const e = newNdebitResponse(JSON.stringify(debitRes), event) diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index b6de933a..048aaf7c 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -265,12 +265,12 @@ export default (mainHandler: Main): Types.ServerMethods => { AuthorizeDebit: async ({ ctx, req }) => { return mainHandler.debitManager.AuthorizeDebit(ctx, req) }, - GetAuthorizedDebits: async ({ ctx }) => { - return mainHandler.debitManager.GetAuthorizedDebits(ctx) + GetDebitAuthorizations: async ({ ctx }) => { + return mainHandler.debitManager.GetDebitAuthorizations(ctx) }, RemoveAuthorizedDebit: async ({ ctx, req }) => { const err = Types.RemoveAuthorizedDebitRequestValidate(req, { - debit_id_CustomCheck: id => id !== '', + npub_CustomCheck: pub => pub !== '', }) if (err != null) throw new Error(err.message) return mainHandler.debitManager.RemoveAuthorizedDebit(ctx, req) diff --git a/src/services/storage/debitStorage.ts b/src/services/storage/debitStorage.ts index 5fb344ee..af5457b4 100644 --- a/src/services/storage/debitStorage.ts +++ b/src/services/storage/debitStorage.ts @@ -1,7 +1,7 @@ import { DataSource, EntityManager } from "typeorm" import UserStorage from './userStorage.js'; import TransactionsQueue from "./transactionsQueue.js"; -import { DebitAccess, DebitKeyType } from "./entity/DebitAccess.js"; +import { DebitAccess, DebitAccessRules } from "./entity/DebitAccess.js"; export default class { DB: DataSource | EntityManager txQueue: TransactionsQueue @@ -10,12 +10,11 @@ export default class { this.txQueue = txQueue } - async AddDebitAccess(appUserId: string, key: string, keyType: DebitKeyType, entityManager = this.DB) { + async AddDebitAccess(appUserId: string, pubToAuthorize: string, entityManager = this.DB) { const entry = entityManager.getRepository(DebitAccess).create({ app_user_id: appUserId, - key: key, - key_type: keyType - + npub: pubToAuthorize, + authorized: true, }) return this.txQueue.PushToQueue({ exec: async db => db.getRepository(DebitAccess).save(entry), dbTx: false }) } @@ -24,15 +23,19 @@ export default class { return this.DB.getRepository(DebitAccess).find({ where: { app_user_id: appUserId } }) } - async GetDebitAccess(appUserId: string, key: string, keyType: DebitKeyType) { - return this.DB.getRepository(DebitAccess).findOne({ where: { app_user_id: appUserId, key, key_type: keyType } }) + async GetDebitAccess(appUserId: string, authorizedPub: string) { + return this.DB.getRepository(DebitAccess).findOne({ where: { app_user_id: appUserId, npub: authorizedPub } }) } - async IncrementDebitAccess(appUserId: string, key: string, keyType: DebitKeyType, amount: number) { - return this.DB.getRepository(DebitAccess).increment({ app_user_id: appUserId, key, key_type: keyType }, 'total_debits', amount) + async IncrementDebitAccess(appUserId: string, authorizedPub: string, amount: number) { + return this.DB.getRepository(DebitAccess).increment({ app_user_id: appUserId, npub: authorizedPub }, 'total_debits', amount) } - async RemoveDebitAccess(appUserId: string, serialId: number) { - return this.DB.getRepository(DebitAccess).delete({ app_user_id: appUserId, serial_id: serialId }) + async UpdateDebitAccessRules(appUserId: string, authorizedPub: string, rules: DebitAccessRules) { + return this.DB.getRepository(DebitAccess).update({ app_user_id: appUserId, npub: authorizedPub }, { rules }) + } + + async RemoveDebitAccess(appUserId: string, authorizedPub: string) { + return this.DB.getRepository(DebitAccess).update({ app_user_id: appUserId, npub: authorizedPub }, { authorized: false }) } } \ No newline at end of file diff --git a/src/services/storage/entity/DebitAccess.ts b/src/services/storage/entity/DebitAccess.ts index 3dc9df90..7b1795f4 100644 --- a/src/services/storage/entity/DebitAccess.ts +++ b/src/services/storage/entity/DebitAccess.ts @@ -1,7 +1,7 @@ import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm" -export type DebitKeyType = 'simpleId' | 'pubKey' +export type DebitAccessRules = Record @Entity() -@Index("unique_debit_access", ["app_user_id", "key", "key_type"], { unique: true }) +@Index("unique_debit_access", ["app_user_id", "npub"], { unique: true }) export class DebitAccess { @PrimaryGeneratedColumn() @@ -11,10 +11,13 @@ export class DebitAccess { app_user_id: string @Column() - key: string + npub: string @Column() - key_type: DebitKeyType + authorized: boolean + + @Column({ type: 'simple-json', default: null, nullable: true }) + rules: DebitAccessRules | null @Column({ default: 0 }) total_debits: number diff --git a/src/services/storage/migrations/1726685229264-debit_access_fixes.ts b/src/services/storage/migrations/1726685229264-debit_access_fixes.ts new file mode 100644 index 00000000..36111229 --- /dev/null +++ b/src/services/storage/migrations/1726685229264-debit_access_fixes.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class DebitAccessFixes1726685229264 implements MigrationInterface { + name = 'DebitAccessFixes1726685229264' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "unique_debit_access"`); + await queryRunner.query(`CREATE TABLE "temporary_debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`INSERT INTO "temporary_debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "debit_access"`); + await queryRunner.query(`DROP TABLE "debit_access"`); + await queryRunner.query(`ALTER TABLE "temporary_debit_access" RENAME TO "debit_access"`); + await queryRunner.query(`CREATE TABLE "temporary_debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "npub" varchar NOT NULL, "authorized" boolean NOT NULL, "rules" text)`); + await queryRunner.query(`INSERT INTO "temporary_debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "debit_access"`); + await queryRunner.query(`DROP TABLE "debit_access"`); + await queryRunner.query(`ALTER TABLE "temporary_debit_access" RENAME TO "debit_access"`); + await queryRunner.query(`CREATE UNIQUE INDEX "unique_debit_access" ON "debit_access" ("app_user_id", "npub") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "unique_debit_access"`); + await queryRunner.query(`ALTER TABLE "debit_access" RENAME TO "temporary_debit_access"`); + await queryRunner.query(`CREATE TABLE "debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`INSERT INTO "debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "temporary_debit_access"`); + await queryRunner.query(`DROP TABLE "temporary_debit_access"`); + await queryRunner.query(`ALTER TABLE "debit_access" RENAME TO "temporary_debit_access"`); + await queryRunner.query(`CREATE TABLE "debit_access" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "app_user_id" varchar NOT NULL, "key" varchar NOT NULL, "key_type" varchar NOT NULL, "total_debits" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + await queryRunner.query(`INSERT INTO "debit_access"("serial_id", "app_user_id", "total_debits", "created_at", "updated_at") SELECT "serial_id", "app_user_id", "total_debits", "created_at", "updated_at" FROM "temporary_debit_access"`); + await queryRunner.query(`DROP TABLE "temporary_debit_access"`); + await queryRunner.query(`CREATE UNIQUE INDEX "unique_debit_access" ON "debit_access" ("app_user_id", "key", "key_type") `); + } + +} diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index 3483973d..d8acf9bb 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -13,7 +13,8 @@ import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js' import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js' import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js' import { DebitAccess1726496225078 } from './1726496225078-debit_access.js' -const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078] +import { DebitAccessFixes1726685229264 } from './1726685229264-debit_access_fixes.js' +const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264] const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825] export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { if (arg === 'fake_initial_migration') {