wire localhost screens
This commit is contained in:
parent
c2cab40a2e
commit
a8d447110f
36 changed files with 6075 additions and 4966 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -14,3 +14,5 @@ logs
|
|||
data/
|
||||
.wallet_secret
|
||||
.wallet_password
|
||||
.admin_enroll
|
||||
admin.npub
|
||||
|
|
@ -13,11 +13,51 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
## NOSTR Methods
|
||||
### These are the nostr methods the client implements to communicate with the API via nostr
|
||||
|
||||
- LndGetInfo
|
||||
- auth type: __Admin__
|
||||
- input: [LndGetInfoRequest](#LndGetInfoRequest)
|
||||
- output: [LndGetInfoResponse](#LndGetInfoResponse)
|
||||
|
||||
- AddApp
|
||||
- auth type: __Admin__
|
||||
- input: [AddAppRequest](#AddAppRequest)
|
||||
- output: [AuthApp](#AuthApp)
|
||||
|
||||
- AuthApp
|
||||
- auth type: __Admin__
|
||||
- input: [AuthAppRequest](#AuthAppRequest)
|
||||
- output: [AuthApp](#AuthApp)
|
||||
|
||||
- BanUser
|
||||
- auth type: __Admin__
|
||||
- input: [BanUserRequest](#BanUserRequest)
|
||||
- output: [BanUserResponse](#BanUserResponse)
|
||||
|
||||
- GetUsageMetrics
|
||||
- auth type: __Metrics__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [UsageMetrics](#UsageMetrics)
|
||||
|
||||
- GetAppsMetrics
|
||||
- auth type: __Metrics__
|
||||
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
||||
- output: [AppsMetrics](#AppsMetrics)
|
||||
|
||||
- GetLndMetrics
|
||||
- auth type: __Metrics__
|
||||
- input: [LndMetricsRequest](#LndMetricsRequest)
|
||||
- output: [LndMetrics](#LndMetrics)
|
||||
|
||||
- LinkNPubThroughToken
|
||||
- auth type: __User__
|
||||
- input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- EnrollAdminToken
|
||||
- auth type: __User__
|
||||
- input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- UserHealth
|
||||
- auth type: __User__
|
||||
- This methods has an __empty__ __request__ body
|
||||
|
|
@ -120,9 +160,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
|
||||
- __User__:
|
||||
- expected context content
|
||||
- __user_id__: _string_
|
||||
- __app_id__: _string_
|
||||
- __app_user_id__: _string_
|
||||
- __user_id__: _string_
|
||||
|
||||
- __Admin__:
|
||||
- expected context content
|
||||
|
|
@ -265,6 +305,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [LinkNPubThroughTokenRequest](#LinkNPubThroughTokenRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- EnrollAdminToken
|
||||
- auth type: __User__
|
||||
- http method: __post__
|
||||
- http route: __/api/guest/npub/enroll/admin__
|
||||
- input: [EnrollAdminTokenRequest](#EnrollAdminTokenRequest)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- GetApp
|
||||
- auth type: __App__
|
||||
- http method: __post__
|
||||
|
|
@ -482,47 +529,36 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
## Messages
|
||||
### The content of requests and response from the methods
|
||||
|
||||
### LnurlLinkResponse
|
||||
- __lnurl__: _string_
|
||||
- __k1__: _string_
|
||||
### Empty
|
||||
|
||||
### RelaysMigration
|
||||
- __relays__: ARRAY of: _string_
|
||||
|
||||
### RequestNPubLinkingTokenResponse
|
||||
- __token__: _string_
|
||||
|
||||
### BannedAppUser
|
||||
- __app_name__: _string_
|
||||
- __app_id__: _string_
|
||||
- __user_identifier__: _string_
|
||||
- __nostr_pub__: _string_
|
||||
|
||||
### Application
|
||||
- __name__: _string_
|
||||
- __id__: _string_
|
||||
- __balance__: _number_
|
||||
- __npub__: _string_
|
||||
|
||||
### PayInvoiceResponse
|
||||
- __preimage__: _string_
|
||||
- __amount_paid__: _number_
|
||||
- __operation_id__: _string_
|
||||
- __service_fee__: _number_
|
||||
- __network_fee__: _number_
|
||||
|
||||
### OpenChannelRequest
|
||||
- __destination__: _string_
|
||||
- __fundingAmount__: _number_
|
||||
- __pushAmount__: _number_
|
||||
- __closeAddress__: _string_
|
||||
|
||||
### LndMetrics
|
||||
- __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_
|
||||
### LndMetricsRequest
|
||||
- __from_unix__: _number_ *this field is optional
|
||||
- __to_unix__: _number_ *this field is optional
|
||||
|
||||
### LndGetInfoResponse
|
||||
- __alias__: _string_
|
||||
|
||||
### PayAppUserInvoiceRequest
|
||||
- __user_identifier__: _string_
|
||||
- __invoice__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### Product
|
||||
- __id__: _string_
|
||||
- __name__: _string_
|
||||
- __price_sats__: _number_
|
||||
|
||||
### LndGetInfoRequest
|
||||
- __nodeId__: _number_
|
||||
|
||||
### BanUserResponse
|
||||
- __balance_sats__: _number_
|
||||
- __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_
|
||||
|
||||
### AuthAppRequest
|
||||
- __name__: _string_
|
||||
- __allow_user_creation__: _boolean_ *this field is optional
|
||||
|
||||
### PayAddressRequest
|
||||
- __address__: _string_
|
||||
- __amoutSats__: _number_
|
||||
|
|
@ -533,69 +569,94 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __to_unix__: _number_ *this field is optional
|
||||
- __include_operations__: _boolean_ *this field is optional
|
||||
|
||||
### AppsMetrics
|
||||
- __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_
|
||||
|
||||
### RoutingEvent
|
||||
- __timestamp_ns__: _number_
|
||||
- __event_type__: _string_
|
||||
- __settled__: _boolean_
|
||||
- __offchain__: _boolean_
|
||||
- __incoming_channel_id__: _number_
|
||||
- __incoming_htlc_id__: _number_
|
||||
- __outgoing_channel_id__: _number_
|
||||
- __outgoing_htlc_id__: _number_
|
||||
- __timestamp_ns__: _number_
|
||||
- __event_type__: _string_
|
||||
- __forward_fail_event__: _boolean_
|
||||
- __incoming_amt_msat__: _number_
|
||||
- __outgoing_amt_msat__: _number_
|
||||
- __failure_string__: _string_
|
||||
- __settled__: _boolean_
|
||||
- __offchain__: _boolean_
|
||||
- __forward_fail_event__: _boolean_
|
||||
|
||||
### ClosedChannel
|
||||
- __channel_id__: _string_
|
||||
- __capacity__: _number_
|
||||
- __closed_height__: _number_
|
||||
### BannedAppUser
|
||||
- __app_name__: _string_
|
||||
- __app_id__: _string_
|
||||
- __user_identifier__: _string_
|
||||
- __nostr_pub__: _string_
|
||||
|
||||
### AddAppRequest
|
||||
### GetUserOperationsResponse
|
||||
- __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
|
||||
- __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_
|
||||
|
||||
### RequestNPubLinkingTokenResponse
|
||||
- __token__: _string_
|
||||
|
||||
### UsageMetric
|
||||
- __processed_at_ms__: _number_
|
||||
- __auth_in_nano__: _number_
|
||||
- __rpc_name__: _string_
|
||||
- __nostr__: _boolean_
|
||||
- __batch_size__: _number_
|
||||
- __parsed_in_nano__: _number_
|
||||
- __validate_in_nano__: _number_
|
||||
- __handle_in_nano__: _number_
|
||||
- __batch__: _boolean_
|
||||
|
||||
### NewInvoiceRequest
|
||||
- __amountSats__: _number_
|
||||
- __memo__: _string_
|
||||
|
||||
### OpenChannelRequest
|
||||
- __destination__: _string_
|
||||
- __fundingAmount__: _number_
|
||||
- __pushAmount__: _number_
|
||||
- __closeAddress__: _string_
|
||||
|
||||
### ChainBalanceEvent
|
||||
- __block_height__: _number_
|
||||
- __confirmed_balance__: _number_
|
||||
- __unconfirmed_balance__: _number_
|
||||
- __total_balance__: _number_
|
||||
|
||||
### GetAppUserRequest
|
||||
- __user_identifier__: _string_
|
||||
|
||||
### NewAddressResponse
|
||||
- __address__: _string_
|
||||
|
||||
### PayInvoiceResponse
|
||||
- __preimage__: _string_
|
||||
- __amount_paid__: _number_
|
||||
- __operation_id__: _string_
|
||||
- __service_fee__: _number_
|
||||
- __network_fee__: _number_
|
||||
|
||||
### AddProductRequest
|
||||
- __name__: _string_
|
||||
- __allow_user_creation__: _boolean_
|
||||
- __price_sats__: _number_
|
||||
|
||||
### MigrationUpdate
|
||||
- __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional
|
||||
- __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional
|
||||
|
||||
### ClosureMigration
|
||||
- __closes_at_unix__: _number_
|
||||
|
||||
### BanUserResponse
|
||||
- __balance_sats__: _number_
|
||||
- __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_
|
||||
|
||||
### AddAppUserRequest
|
||||
- __identifier__: _string_
|
||||
- __fail_if_exists__: _boolean_
|
||||
- __balance__: _number_
|
||||
|
||||
### SetMockAppUserBalanceRequest
|
||||
- __user_identifier__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### PayInvoiceRequest
|
||||
- __invoice__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### LnurlWithdrawInfoResponse
|
||||
- __tag__: _string_
|
||||
- __callback__: _string_
|
||||
- __k1__: _string_
|
||||
- __defaultDescription__: _string_
|
||||
- __minWithdrawable__: _number_
|
||||
- __maxWithdrawable__: _number_
|
||||
- __balanceCheck__: _string_
|
||||
- __payLink__: _string_
|
||||
|
||||
### UsageMetric
|
||||
- __processed_at_ms__: _number_
|
||||
- __parsed_in_nano__: _number_
|
||||
- __auth_in_nano__: _number_
|
||||
- __validate_in_nano__: _number_
|
||||
- __handle_in_nano__: _number_
|
||||
- __rpc_name__: _string_
|
||||
- __batch__: _boolean_
|
||||
- __nostr__: _boolean_
|
||||
- __batch_size__: _number_
|
||||
### EncryptionExchangeRequest
|
||||
- __publicKey__: _string_
|
||||
- __deviceId__: _string_
|
||||
|
||||
### UsersInfo
|
||||
- __total__: _number_
|
||||
|
|
@ -605,207 +666,70 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __balance_avg__: _number_
|
||||
- __balance_median__: _number_
|
||||
|
||||
### BanUserRequest
|
||||
- __user_id__: _string_
|
||||
|
||||
### UserOperations
|
||||
- __fromIndex__: _number_
|
||||
- __toIndex__: _number_
|
||||
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
|
||||
|
||||
### RequestNPubLinkingTokenRequest
|
||||
- __user_identifier__: _string_
|
||||
|
||||
### UserOperation
|
||||
- __paidAtUnix__: _number_
|
||||
- __type__: _[UserOperationType](#UserOperationType)_
|
||||
- __inbound__: _boolean_
|
||||
- __amount__: _number_
|
||||
- __identifier__: _string_
|
||||
- __operationId__: _string_
|
||||
- __service_fee__: _number_
|
||||
- __network_fee__: _number_
|
||||
- __confirmed__: _boolean_
|
||||
- __tx_hash__: _string_
|
||||
- __internal__: _boolean_
|
||||
|
||||
### Product
|
||||
- __id__: _string_
|
||||
- __name__: _string_
|
||||
- __price_sats__: _number_
|
||||
|
||||
### LinkNPubThroughTokenRequest
|
||||
- __token__: _string_
|
||||
- __nostr_pub__: _string_
|
||||
|
||||
### EncryptionExchangeRequest
|
||||
- __publicKey__: _string_
|
||||
- __deviceId__: _string_
|
||||
|
||||
### PayAppUserInvoiceRequest
|
||||
- __user_identifier__: _string_
|
||||
- __invoice__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### SendAppUserToAppPaymentRequest
|
||||
- __from_user_identifier__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### SendAppUserToAppUserPaymentRequest
|
||||
- __from_user_identifier__: _string_
|
||||
- __to_user_identifier__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### NewInvoiceRequest
|
||||
- __amountSats__: _number_
|
||||
- __memo__: _string_
|
||||
|
||||
### MigrationUpdate
|
||||
- __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional
|
||||
- __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional
|
||||
|
||||
### GetUserOperationsResponse
|
||||
- __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_
|
||||
- __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
|
||||
- __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
|
||||
|
||||
### AddAppUserInvoiceRequest
|
||||
- __receiver_identifier__: _string_
|
||||
- __payer_identifier__: _string_
|
||||
- __http_callback_url__: _string_
|
||||
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
|
||||
|
||||
### DecodeInvoiceRequest
|
||||
- __invoice__: _string_
|
||||
|
||||
### UserInfo
|
||||
- __userId__: _string_
|
||||
- __balance__: _number_
|
||||
- __max_withdrawable__: _number_
|
||||
- __user_identifier__: _string_
|
||||
- __service_fee_bps__: _number_
|
||||
- __network_max_fee_bps__: _number_
|
||||
- __network_max_fee_fixed__: _number_
|
||||
|
||||
### DecodeInvoiceResponse
|
||||
- __amount__: _number_
|
||||
|
||||
### OpenChannelResponse
|
||||
- __channelId__: _string_
|
||||
|
||||
### LiveUserOperation
|
||||
- __operation__: _[UserOperation](#UserOperation)_
|
||||
|
||||
### UsageMetrics
|
||||
- __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_
|
||||
|
||||
### AuthApp
|
||||
- __app__: _[Application](#Application)_
|
||||
- __auth_token__: _string_
|
||||
|
||||
### AddAppInvoiceRequest
|
||||
- __payer_identifier__: _string_
|
||||
- __http_callback_url__: _string_
|
||||
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
|
||||
|
||||
### HandleLnurlPayResponse
|
||||
- __pr__: _string_
|
||||
- __routes__: ARRAY of: _[Empty](#Empty)_
|
||||
|
||||
### Empty
|
||||
|
||||
### ChannelBalanceEvent
|
||||
- __block_height__: _number_
|
||||
- __channel_id__: _string_
|
||||
- __local_balance_sats__: _number_
|
||||
- __remote_balance_sats__: _number_
|
||||
|
||||
### GetAppUserRequest
|
||||
- __user_identifier__: _string_
|
||||
### ChannelRouting
|
||||
- __receive_errors__: _number_
|
||||
- __forward_errors_as_output__: _number_
|
||||
- __missed_forward_fee_as_output__: _number_
|
||||
- __events_number__: _number_
|
||||
- __channel_id__: _string_
|
||||
- __forward_errors_as_input__: _number_
|
||||
- __missed_forward_fee_as_input__: _number_
|
||||
- __forward_fee_as_input__: _number_
|
||||
- __forward_fee_as_output__: _number_
|
||||
- __send_errors__: _number_
|
||||
|
||||
### AddProductRequest
|
||||
- __name__: _string_
|
||||
- __price_sats__: _number_
|
||||
|
||||
### AppUser
|
||||
- __identifier__: _string_
|
||||
- __info__: _[UserInfo](#UserInfo)_
|
||||
- __max_withdrawable__: _number_
|
||||
|
||||
### GetAppUserLNURLInfoRequest
|
||||
- __user_identifier__: _string_
|
||||
- __base_url_override__: _string_
|
||||
### SendAppUserToAppPaymentRequest
|
||||
- __from_user_identifier__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### SetMockAppBalanceRequest
|
||||
- __amount__: _number_
|
||||
|
||||
### NewAddressRequest
|
||||
- __addressType__: _[AddressType](#AddressType)_
|
||||
|
||||
### GetProductBuyLinkResponse
|
||||
- __link__: _string_
|
||||
|
||||
### HttpCreds
|
||||
- __url__: _string_
|
||||
- __token__: _string_
|
||||
|
||||
### AppMetrics
|
||||
- __app__: _[Application](#Application)_
|
||||
- __users__: _[UsersInfo](#UsersInfo)_
|
||||
- __received__: _number_
|
||||
- __spent__: _number_
|
||||
- __available__: _number_
|
||||
- __fees__: _number_
|
||||
- __invoices__: _number_
|
||||
- __total_fees__: _number_
|
||||
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
|
||||
### ClosedChannel
|
||||
- __channel_id__: _string_
|
||||
- __capacity__: _number_
|
||||
- __closed_height__: _number_
|
||||
|
||||
### ChainBalanceEvent
|
||||
- __block_height__: _number_
|
||||
- __confirmed_balance__: _number_
|
||||
- __unconfirmed_balance__: _number_
|
||||
- __total_balance__: _number_
|
||||
### Application
|
||||
- __id__: _string_
|
||||
- __balance__: _number_
|
||||
- __npub__: _string_
|
||||
- __name__: _string_
|
||||
|
||||
### SetMockInvoiceAsPaidRequest
|
||||
- __invoice__: _string_
|
||||
### AddAppUserRequest
|
||||
- __balance__: _number_
|
||||
- __identifier__: _string_
|
||||
- __fail_if_exists__: _boolean_
|
||||
|
||||
### SetMockAppUserBalanceRequest
|
||||
- __user_identifier__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### LndGetInfoRequest
|
||||
- __nodeId__: _number_
|
||||
|
||||
### NewAddressResponse
|
||||
- __address__: _string_
|
||||
|
||||
### PayAddressResponse
|
||||
- __txId__: _string_
|
||||
- __operation_id__: _string_
|
||||
- __service_fee__: _number_
|
||||
- __network_fee__: _number_
|
||||
- __txId__: _string_
|
||||
|
||||
### AppsMetrics
|
||||
- __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_
|
||||
### NewInvoiceResponse
|
||||
- __invoice__: _string_
|
||||
|
||||
### LndNodeMetrics
|
||||
- __channels_balance_events__: ARRAY of: _[ChannelBalanceEvent](#ChannelBalanceEvent)_
|
||||
- __chain_balance_events__: ARRAY of: _[ChainBalanceEvent](#ChainBalanceEvent)_
|
||||
- __offline_channels__: _number_
|
||||
- __online_channels__: _number_
|
||||
- __pending_channels__: _number_
|
||||
- __closing_channels__: _number_
|
||||
- __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
|
||||
- __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_
|
||||
- __channel_routing__: ARRAY of: _[ChannelRouting](#ChannelRouting)_
|
||||
### RequestNPubLinkingTokenRequest
|
||||
- __user_identifier__: _string_
|
||||
|
||||
### AuthAppRequest
|
||||
- __name__: _string_
|
||||
- __allow_user_creation__: _boolean_ *this field is optional
|
||||
|
||||
### LndMetricsRequest
|
||||
- __from_unix__: _number_ *this field is optional
|
||||
- __to_unix__: _number_ *this field is optional
|
||||
### LinkNPubThroughTokenRequest
|
||||
- __token__: _string_
|
||||
- __nostr_pub__: _string_
|
||||
|
||||
### OpenChannel
|
||||
- __channel_id__: _string_
|
||||
|
|
@ -815,38 +739,164 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __local_balance__: _number_
|
||||
- __remote_balance__: _number_
|
||||
|
||||
### NewInvoiceResponse
|
||||
### SetMockInvoiceAsPaidRequest
|
||||
- __invoice__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### AddAppUserInvoiceRequest
|
||||
- __receiver_identifier__: _string_
|
||||
- __payer_identifier__: _string_
|
||||
- __http_callback_url__: _string_
|
||||
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
|
||||
|
||||
### DecodeInvoiceResponse
|
||||
- __amount__: _number_
|
||||
|
||||
### OpenChannelResponse
|
||||
- __channelId__: _string_
|
||||
|
||||
### RelaysMigration
|
||||
- __relays__: ARRAY of: _string_
|
||||
|
||||
### LndMetrics
|
||||
- __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_
|
||||
|
||||
### AppUser
|
||||
- __identifier__: _string_
|
||||
- __info__: _[UserInfo](#UserInfo)_
|
||||
- __max_withdrawable__: _number_
|
||||
|
||||
### AddAppInvoiceRequest
|
||||
- __payer_identifier__: _string_
|
||||
- __http_callback_url__: _string_
|
||||
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
|
||||
|
||||
### UserOperations
|
||||
- __fromIndex__: _number_
|
||||
- __toIndex__: _number_
|
||||
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
|
||||
|
||||
### BanUserRequest
|
||||
- __user_id__: _string_
|
||||
|
||||
### NewAddressRequest
|
||||
- __addressType__: _[AddressType](#AddressType)_
|
||||
|
||||
### DecodeInvoiceRequest
|
||||
- __invoice__: _string_
|
||||
|
||||
### ChannelRouting
|
||||
- __channel_id__: _string_
|
||||
- __send_errors__: _number_
|
||||
- __receive_errors__: _number_
|
||||
- __forward_errors_as_input__: _number_
|
||||
- __forward_errors_as_output__: _number_
|
||||
- __missed_forward_fee_as_input__: _number_
|
||||
- __missed_forward_fee_as_output__: _number_
|
||||
- __forward_fee_as_input__: _number_
|
||||
- __forward_fee_as_output__: _number_
|
||||
- __events_number__: _number_
|
||||
|
||||
### LnurlPayInfoResponse
|
||||
- __tag__: _string_
|
||||
### LnurlWithdrawInfoResponse
|
||||
- __callback__: _string_
|
||||
- __maxSendable__: _number_
|
||||
- __minSendable__: _number_
|
||||
- __metadata__: _string_
|
||||
- __allowsNostr__: _boolean_
|
||||
- __nostrPubkey__: _string_
|
||||
- __k1__: _string_
|
||||
- __defaultDescription__: _string_
|
||||
- __minWithdrawable__: _number_
|
||||
- __maxWithdrawable__: _number_
|
||||
- __balanceCheck__: _string_
|
||||
- __payLink__: _string_
|
||||
- __tag__: _string_
|
||||
|
||||
### GetUserOperationsRequest
|
||||
- __latestIncomingInvoice__: _number_
|
||||
- __latestOutgoingInvoice__: _number_
|
||||
- __latestIncomingTx__: _number_
|
||||
- __latestOutgoingTx__: _number_
|
||||
- __latestIncomingUserToUserPayment__: _number_
|
||||
- __latestOutgoingUserToUserPayment__: _number_
|
||||
- __max_size__: _number_
|
||||
- __latestIncomingInvoice__: _number_
|
||||
|
||||
### AppMetrics
|
||||
- __spent__: _number_
|
||||
- __available__: _number_
|
||||
- __fees__: _number_
|
||||
- __invoices__: _number_
|
||||
- __total_fees__: _number_
|
||||
- __app__: _[Application](#Application)_
|
||||
- __users__: _[UsersInfo](#UsersInfo)_
|
||||
- __received__: _number_
|
||||
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
|
||||
|
||||
### AddAppRequest
|
||||
- __name__: _string_
|
||||
- __allow_user_creation__: _boolean_
|
||||
|
||||
### SendAppUserToAppUserPaymentRequest
|
||||
- __amount__: _number_
|
||||
- __from_user_identifier__: _string_
|
||||
- __to_user_identifier__: _string_
|
||||
|
||||
### LnurlPayInfoResponse
|
||||
- __callback__: _string_
|
||||
- __maxSendable__: _number_
|
||||
- __minSendable__: _number_
|
||||
- __metadata__: _string_
|
||||
- __allowsNostr__: _boolean_
|
||||
- __nostrPubkey__: _string_
|
||||
- __tag__: _string_
|
||||
|
||||
### HandleLnurlPayResponse
|
||||
- __pr__: _string_
|
||||
- __routes__: ARRAY of: _[Empty](#Empty)_
|
||||
|
||||
### EnrollAdminTokenRequest
|
||||
- __admin_token__: _string_
|
||||
|
||||
### UsageMetrics
|
||||
- __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_
|
||||
|
||||
### LnurlLinkResponse
|
||||
- __k1__: _string_
|
||||
- __lnurl__: _string_
|
||||
|
||||
### LiveUserOperation
|
||||
- __operation__: _[UserOperation](#UserOperation)_
|
||||
|
||||
### PayInvoiceRequest
|
||||
- __invoice__: _string_
|
||||
- __amount__: _number_
|
||||
|
||||
### GetProductBuyLinkResponse
|
||||
- __link__: _string_
|
||||
|
||||
### LndNodeMetrics
|
||||
- __chain_balance_events__: ARRAY of: _[ChainBalanceEvent](#ChainBalanceEvent)_
|
||||
- __online_channels__: _number_
|
||||
- __closing_channels__: _number_
|
||||
- __channels_balance_events__: ARRAY of: _[ChannelBalanceEvent](#ChannelBalanceEvent)_
|
||||
- __pending_channels__: _number_
|
||||
- __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
|
||||
- __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_
|
||||
- __channel_routing__: ARRAY of: _[ChannelRouting](#ChannelRouting)_
|
||||
- __offline_channels__: _number_
|
||||
|
||||
### AuthApp
|
||||
- __app__: _[Application](#Application)_
|
||||
- __auth_token__: _string_
|
||||
|
||||
### GetAppUserLNURLInfoRequest
|
||||
- __user_identifier__: _string_
|
||||
- __base_url_override__: _string_
|
||||
|
||||
### UserInfo
|
||||
- __network_max_fee_fixed__: _number_
|
||||
- __userId__: _string_
|
||||
- __balance__: _number_
|
||||
- __max_withdrawable__: _number_
|
||||
- __user_identifier__: _string_
|
||||
- __service_fee_bps__: _number_
|
||||
- __network_max_fee_bps__: _number_
|
||||
|
||||
### UserOperation
|
||||
- __paidAtUnix__: _number_
|
||||
- __service_fee__: _number_
|
||||
- __confirmed__: _boolean_
|
||||
- __tx_hash__: _string_
|
||||
- __internal__: _boolean_
|
||||
- __network_fee__: _number_
|
||||
- __type__: _[UserOperationType](#UserOperationType)_
|
||||
- __inbound__: _boolean_
|
||||
- __amount__: _number_
|
||||
- __identifier__: _string_
|
||||
- __operationId__: _string_
|
||||
## Enums
|
||||
### The enumerators used in the messages
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -364,6 +364,28 @@ 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.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented')
|
||||
app.post('/api/guest/npub/enroll/admin', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'EnrollAdminToken', 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.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented')
|
||||
const authContext = await opts.UserAuthGuard(req.headers['authorization'])
|
||||
authCtx = authContext
|
||||
stats.guard = process.hrtime.bigint()
|
||||
const request = req.body
|
||||
const error = Types.EnrollAdminTokenRequestValidate(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
|
||||
const params = req.params
|
||||
await methods.EnrollAdminToken({rpcName:'EnrollAdminToken', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({status: 'OK'})
|
||||
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.GetApp) throw new Error('method: GetApp is not implemented')
|
||||
app.post('/api/app/get', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetApp', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
@ -948,6 +970,18 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'EnrollAdminToken':
|
||||
if (!methods.EnrollAdminToken) {
|
||||
throw new Error('method EnrollAdminToken not found' )
|
||||
} else {
|
||||
const error = Types.EnrollAdminTokenRequestValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.EnrollAdminToken({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UserHealth':
|
||||
if (!methods.UserHealth) {
|
||||
throw new Error('method UserHealth not found' )
|
||||
|
|
@ -1121,6 +1155,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
var server: { close: () => void } | undefined
|
||||
return {
|
||||
Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() },
|
||||
Listen: (port: number) => { server = app.listen(port, () => logger.log('Example app listening on port ' + port)) }
|
||||
Listen: (port: number) => { server = app.listen(port, () => logger.log('LightningPub listening on port ' + port)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,17 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
let finalRoute = '/api/guest/npub/enroll/admin'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
return data
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetApp: async (): Promise<ResultError | ({ status: 'OK' }& Types.Application)> => {
|
||||
const auth = await params.retrieveAppAuth()
|
||||
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||
|
|
|
|||
|
|
@ -5,10 +5,116 @@ export type ResultError = { status: 'ERROR', reason: string }
|
|||
|
||||
export type NostrClientParams = {
|
||||
pubDestination: string
|
||||
retrieveNostrAdminAuth: () => Promise<string | null>
|
||||
retrieveNostrMetricsAuth: () => Promise<string | null>
|
||||
retrieveNostrUserAuth: () => Promise<string | null>
|
||||
checkResult?: true
|
||||
}
|
||||
export default (params: NostrClientParams, send: (to:string, message: NostrRequest) => Promise<any>, subscribe: (to:string, message: NostrRequest, cb:(res:any)=> void) => void) => ({
|
||||
LndGetInfo: async (request: Types.LndGetInfoRequest): Promise<ResultError | ({ status: 'OK' }& Types.LndGetInfoResponse)> => {
|
||||
const auth = await params.retrieveNostrAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'LndGetInfo',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.LndGetInfoResponseValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AddApp: async (request: Types.AddAppRequest): Promise<ResultError | ({ status: 'OK' }& Types.AuthApp)> => {
|
||||
const auth = await params.retrieveNostrAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'AddApp',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.AuthAppValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
AuthApp: async (request: Types.AuthAppRequest): Promise<ResultError | ({ status: 'OK' }& Types.AuthApp)> => {
|
||||
const auth = await params.retrieveNostrAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'AuthApp',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.AuthAppValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
BanUser: async (request: Types.BanUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.BanUserResponse)> => {
|
||||
const auth = await params.retrieveNostrAdminAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrAdminAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'BanUser',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.BanUserResponseValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetUsageMetrics: async (): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetrics)> => {
|
||||
const auth = await params.retrieveNostrMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
const data = await send(params.pubDestination, {rpcName:'GetUsageMetrics',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.UsageMetricsValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetAppsMetrics: async (request: Types.AppsMetricsRequest): Promise<ResultError | ({ status: 'OK' }& Types.AppsMetrics)> => {
|
||||
const auth = await params.retrieveNostrMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'GetAppsMetrics',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.AppsMetricsValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetLndMetrics: async (request: Types.LndMetricsRequest): Promise<ResultError | ({ status: 'OK' }& Types.LndMetrics)> => {
|
||||
const auth = await params.retrieveNostrMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'GetLndMetrics',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.LndMetricsValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
LinkNPubThroughToken: async (request: Types.LinkNPubThroughTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
@ -21,6 +127,18 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
EnrollAdminToken: async (request: Types.EnrollAdminTokenRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
const nostrRequest: NostrRequest = {}
|
||||
nostrRequest.body = request
|
||||
const data = await send(params.pubDestination, {rpcName:'EnrollAdminToken',authIdentifier:auth, ...nostrRequest })
|
||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||
if (data.status === 'OK') {
|
||||
return data
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
UserHealth: async (): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export type NostrOptions = {
|
|||
logger?: Logger
|
||||
throwErrors?: true
|
||||
metricsCallback: (metrics: Types.RequestMetric[]) => void
|
||||
NostrAdminAuthGuard: (appId?:string, identifier?: string) => Promise<Types.AdminContext>
|
||||
NostrMetricsAuthGuard: (appId?:string, identifier?: string) => Promise<Types.MetricsContext>
|
||||
NostrUserAuthGuard: (appId?:string, identifier?: string) => Promise<Types.UserContext>
|
||||
}
|
||||
const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => {
|
||||
|
|
@ -29,6 +31,115 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
const stats: Types.RequestStats = { startMs, start: startTime, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
||||
let authCtx: Types.AuthContext = {}
|
||||
switch (req.rpcName) {
|
||||
case 'LndGetInfo':
|
||||
try {
|
||||
if (!methods.LndGetInfo) throw new Error('method: LndGetInfo is not implemented')
|
||||
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.LndGetInfoRequestValidate(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.LndGetInfo({rpcName:'LndGetInfo', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'AddApp':
|
||||
try {
|
||||
if (!methods.AddApp) throw new Error('method: AddApp is not implemented')
|
||||
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.AddAppRequestValidate(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.AddApp({rpcName:'AddApp', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'AuthApp':
|
||||
try {
|
||||
if (!methods.AuthApp) throw new Error('method: AuthApp is not implemented')
|
||||
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.AuthAppRequestValidate(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.AuthApp({rpcName:'AuthApp', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'BanUser':
|
||||
try {
|
||||
if (!methods.BanUser) throw new Error('method: BanUser is not implemented')
|
||||
const authContext = await opts.NostrAdminAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.BanUserRequestValidate(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.BanUser({rpcName:'BanUser', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'GetUsageMetrics':
|
||||
try {
|
||||
if (!methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented')
|
||||
const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
stats.validate = stats.guard
|
||||
const response = await methods.GetUsageMetrics({rpcName:'GetUsageMetrics', ctx:authContext })
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'GetAppsMetrics':
|
||||
try {
|
||||
if (!methods.GetAppsMetrics) throw new Error('method: GetAppsMetrics is not implemented')
|
||||
const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.AppsMetricsRequestValidate(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.GetAppsMetrics({rpcName:'GetAppsMetrics', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'GetLndMetrics':
|
||||
try {
|
||||
if (!methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented')
|
||||
const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.LndMetricsRequestValidate(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.GetLndMetrics({rpcName:'GetLndMetrics', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
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 'LinkNPubThroughToken':
|
||||
try {
|
||||
if (!methods.LinkNPubThroughToken) throw new Error('method: LinkNPubThroughToken is not implemented')
|
||||
|
|
@ -45,6 +156,22 @@ 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 'EnrollAdminToken':
|
||||
try {
|
||||
if (!methods.EnrollAdminToken) throw new Error('method: EnrollAdminToken is not implemented')
|
||||
const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier)
|
||||
stats.guard = process.hrtime.bigint()
|
||||
authCtx = authContext
|
||||
const request = req.body
|
||||
const error = Types.EnrollAdminTokenRequestValidate(request)
|
||||
stats.validate = process.hrtime.bigint()
|
||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
||||
await methods.EnrollAdminToken({rpcName:'EnrollAdminToken', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res({status: 'OK'})
|
||||
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 'UserHealth':
|
||||
try {
|
||||
if (!methods.UserHealth) throw new Error('method: UserHealth is not implemented')
|
||||
|
|
@ -321,6 +448,18 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
|||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'EnrollAdminToken':
|
||||
if (!methods.EnrollAdminToken) {
|
||||
throw new Error('method not defined: EnrollAdminToken')
|
||||
} else {
|
||||
const error = Types.EnrollAdminTokenRequestValidate(operation.req)
|
||||
opStats.validate = process.hrtime.bigint()
|
||||
if (error !== null) throw error
|
||||
await methods.EnrollAdminToken({...operation, ctx}); responses.push({ status: 'OK' })
|
||||
opStats.handle = process.hrtime.bigint()
|
||||
callsMetrics.push({ ...opInfo, ...opStats, ...ctx })
|
||||
}
|
||||
break
|
||||
case 'UserHealth':
|
||||
if (!methods.UserHealth) {
|
||||
throw new Error('method not defined: UserHealth')
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Binary file not shown.
BIN
proto/protoc-gen-pub_old
Executable file
BIN
proto/protoc-gen-pub_old
Executable file
Binary file not shown.
|
|
@ -92,42 +92,49 @@ service LightningPub {
|
|||
option (auth_type) = "Admin";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/admin/lnd/getinfo";
|
||||
option (nostr) = true;
|
||||
};
|
||||
|
||||
rpc AddApp(structs.AddAppRequest) returns (structs.AuthApp) {
|
||||
option (auth_type) = "Admin";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/admin/app/add";
|
||||
option (nostr) = true;
|
||||
};
|
||||
|
||||
rpc AuthApp(structs.AuthAppRequest) returns (structs.AuthApp) {
|
||||
option (auth_type) = "Admin";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/admin/app/auth";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc BanUser(structs.BanUserRequest) returns (structs.BanUserResponse) {
|
||||
option (auth_type) = "Admin";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/admin/user/ban";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetUsageMetrics(structs.Empty) returns (structs.UsageMetrics) {
|
||||
option (auth_type) = "Metrics";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/reports/usage";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetAppsMetrics(structs.AppsMetricsRequest) returns (structs.AppsMetrics) {
|
||||
option (auth_type) = "Metrics";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/reports/apps";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
rpc GetLndMetrics(structs.LndMetricsRequest) returns (structs.LndMetrics) {
|
||||
option (auth_type) = "Metrics";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/reports/lnd";
|
||||
option (nostr) = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -182,10 +189,16 @@ service LightningPub {
|
|||
|
||||
rpc LinkNPubThroughToken(structs.LinkNPubThroughTokenRequest) returns (structs.Empty) {
|
||||
option (auth_type) = "User";
|
||||
option(http_method) = "post";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/guest/npub/link";
|
||||
option (nostr) = true;
|
||||
}
|
||||
rpc EnrollAdminToken(structs.EnrollAdminTokenRequest) returns (structs.Empty) {
|
||||
option (auth_type) = "User";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/api/guest/npub/enroll/admin";
|
||||
option (nostr) = true;
|
||||
}
|
||||
//</Guest>
|
||||
|
||||
// <App>
|
||||
|
|
|
|||
|
|
@ -450,3 +450,7 @@ message HttpCreds {
|
|||
string url = 1;
|
||||
string token = 2;
|
||||
}
|
||||
|
||||
message EnrollAdminTokenRequest {
|
||||
string admin_token = 1;
|
||||
}
|
||||
|
|
@ -51,15 +51,20 @@ service Wizard {
|
|||
option (http_method) = "get";
|
||||
option (http_route) = "/wizard/state";
|
||||
};
|
||||
rpc WizardConfig(wizard_structs.ConfigRequest) returns (wizard_structs.ConfigResponse){
|
||||
rpc WizardConfig(wizard_structs.ConfigRequest) returns (wizard_structs.Empty){
|
||||
option (auth_type) = "Guest";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/wizard/config";
|
||||
};
|
||||
rpc WizardConfirm(wizard_structs.ConfirmRequest) returns (wizard_structs.ConfirmResponse){
|
||||
rpc GetAdminConnectInfo(wizard_structs.Empty) returns (wizard_structs.AdminConnectInfoResponse){
|
||||
option (auth_type) = "Guest";
|
||||
option (http_method) = "post";
|
||||
option (http_route) = "/wizard/confirm";
|
||||
option (http_method) = "get";
|
||||
option (http_route) = "/wizard/admin_connect_info";
|
||||
};
|
||||
rpc GetServiceState(wizard_structs.Empty) returns (wizard_structs.ServiceStateResponse){
|
||||
option (auth_type) = "Guest";
|
||||
option (http_method) = "get";
|
||||
option (http_route) = "/wizard/service_state";
|
||||
};
|
||||
// </Guest>
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@ option go_package = "github.com/shocknet/lightning.pub";
|
|||
message Empty {}
|
||||
|
||||
message StateResponse {
|
||||
bool already_initialized = 1;
|
||||
bool config_sent = 1;
|
||||
bool admin_linked = 2;
|
||||
}
|
||||
message ConfigRequest {
|
||||
string source_name = 1;
|
||||
|
|
@ -15,18 +16,25 @@ message ConfigRequest {
|
|||
bool automate_liquidity = 3;
|
||||
bool push_backups_to_nostr = 4;
|
||||
}
|
||||
|
||||
|
||||
message ConfigResponse {
|
||||
bool already_initialized = 1;
|
||||
repeated string seed = 2;
|
||||
string confirmation_id = 3;
|
||||
message AdminConnectInfoResponse {
|
||||
string nprofile = 1;
|
||||
oneof connect_info {
|
||||
string admin_token = 2;
|
||||
string enrolled_npub = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ConfirmRequest {
|
||||
string confirmation_id = 1;
|
||||
enum LndState {
|
||||
OFFLINE = 0;
|
||||
SYNCING = 1;
|
||||
ONLINE = 2;
|
||||
}
|
||||
|
||||
message ConfirmResponse {
|
||||
string admin_key = 1;
|
||||
message ServiceStateResponse {
|
||||
string provider_name = 1;
|
||||
repeated string relays = 2;
|
||||
string admin_npub = 3;
|
||||
bool relay_connected = 4;
|
||||
LndState lnd_state = 5;
|
||||
bool watchdog_ok = 6;
|
||||
string http_url = 7;
|
||||
string nprofile = 8;
|
||||
}
|
||||
|
|
@ -36,27 +36,30 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- http method: __post__
|
||||
- http route: __/wizard/config__
|
||||
- input: [ConfigRequest](#ConfigRequest)
|
||||
- output: [ConfigResponse](#ConfigResponse)
|
||||
- This methods has an __empty__ __response__ body
|
||||
|
||||
- WizardConfirm
|
||||
- GetAdminConnectInfo
|
||||
- auth type: __Guest__
|
||||
- http method: __post__
|
||||
- http route: __/wizard/confirm__
|
||||
- input: [ConfirmRequest](#ConfirmRequest)
|
||||
- output: [ConfirmResponse](#ConfirmResponse)
|
||||
- http method: __get__
|
||||
- http route: __/wizard/admin_connect_info__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [AdminConnectInfoResponse](#AdminConnectInfoResponse)
|
||||
|
||||
- GetServiceState
|
||||
- auth type: __Guest__
|
||||
- http method: __get__
|
||||
- http route: __/wizard/service_state__
|
||||
- This methods has an __empty__ __request__ body
|
||||
- output: [ServiceStateResponse](#ServiceStateResponse)
|
||||
|
||||
# INPUTS AND OUTPUTS
|
||||
|
||||
## Messages
|
||||
### The content of requests and response from the methods
|
||||
|
||||
### ConfirmResponse
|
||||
- __admin_key__: _string_
|
||||
|
||||
### Empty
|
||||
|
||||
### StateResponse
|
||||
- __already_initialized__: _boolean_
|
||||
- __config_sent__: _boolean_
|
||||
- __admin_linked__: _boolean_
|
||||
|
||||
### ConfigRequest
|
||||
- __source_name__: _string_
|
||||
|
|
@ -64,12 +67,25 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __automate_liquidity__: _boolean_
|
||||
- __push_backups_to_nostr__: _boolean_
|
||||
|
||||
### ConfigResponse
|
||||
- __already_initialized__: _boolean_
|
||||
- __seed__: ARRAY of: _string_
|
||||
- __confirmation_id__: _string_
|
||||
### AdminConnectInfoResponse
|
||||
- __nprofile__: _string_
|
||||
- __connect_info__: _AdminConnectInfoResponse_connect_info_
|
||||
|
||||
### ConfirmRequest
|
||||
- __confirmation_id__: _string_
|
||||
### ServiceStateResponse
|
||||
- __http_url__: _string_
|
||||
- __nprofile__: _string_
|
||||
- __provider_name__: _string_
|
||||
- __relays__: ARRAY of: _string_
|
||||
- __admin_npub__: _string_
|
||||
- __relay_connected__: _boolean_
|
||||
- __lnd_state__: _[LndState](#LndState)_
|
||||
- __watchdog_ok__: _boolean_
|
||||
|
||||
### Empty
|
||||
## Enums
|
||||
### The enumerators used in the messages
|
||||
|
||||
### LndState
|
||||
- __OFFLINE__
|
||||
- __SYNCING__
|
||||
- __ONLINE__
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
([]*main.Method) (len=3 cap=4) {
|
||||
(*main.Method)(0xc0002221e0)({
|
||||
([]*main.Method) (len=4 cap=4) {
|
||||
(*main.Method)(0xc00022a280)({
|
||||
in: (main.MethodMessage) {
|
||||
name: (string) (len=5) "Empty",
|
||||
hasZeroFields: (bool) true
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
name: (string) (len=13) "StateResponse",
|
||||
hasZeroFields: (bool) false
|
||||
},
|
||||
opts: (*main.methodOptions)(0xc00009e6c0)({
|
||||
authType: (*main.supportedAuth)(0xc0003bd290)({
|
||||
opts: (*main.methodOptions)(0xc00009a9c0)({
|
||||
authType: (*main.supportedAuth)(0xc0003c9aa0)({
|
||||
id: (string) (len=5) "guest",
|
||||
name: (string) (len=5) "Guest",
|
||||
context: (map[string]string) {
|
||||
|
|
@ -27,18 +27,18 @@
|
|||
}),
|
||||
serverStream: (bool) false
|
||||
}),
|
||||
(*main.Method)(0xc000222230)({
|
||||
(*main.Method)(0xc00022a2d0)({
|
||||
in: (main.MethodMessage) {
|
||||
name: (string) (len=13) "ConfigRequest",
|
||||
hasZeroFields: (bool) false
|
||||
},
|
||||
name: (string) (len=12) "WizardConfig",
|
||||
out: (main.MethodMessage) {
|
||||
name: (string) (len=14) "ConfigResponse",
|
||||
hasZeroFields: (bool) false
|
||||
name: (string) (len=5) "Empty",
|
||||
hasZeroFields: (bool) true
|
||||
},
|
||||
opts: (*main.methodOptions)(0xc00009e840)({
|
||||
authType: (*main.supportedAuth)(0xc0003bd350)({
|
||||
opts: (*main.methodOptions)(0xc00009ab40)({
|
||||
authType: (*main.supportedAuth)(0xc0003c9b60)({
|
||||
id: (string) (len=5) "guest",
|
||||
name: (string) (len=5) "Guest",
|
||||
context: (map[string]string) {
|
||||
|
|
@ -55,26 +55,54 @@
|
|||
}),
|
||||
serverStream: (bool) false
|
||||
}),
|
||||
(*main.Method)(0xc0002225a0)({
|
||||
(*main.Method)(0xc00022a640)({
|
||||
in: (main.MethodMessage) {
|
||||
name: (string) (len=14) "ConfirmRequest",
|
||||
hasZeroFields: (bool) false
|
||||
name: (string) (len=5) "Empty",
|
||||
hasZeroFields: (bool) true
|
||||
},
|
||||
name: (string) (len=13) "WizardConfirm",
|
||||
name: (string) (len=19) "GetAdminConnectInfo",
|
||||
out: (main.MethodMessage) {
|
||||
name: (string) (len=15) "ConfirmResponse",
|
||||
name: (string) (len=24) "AdminConnectInfoResponse",
|
||||
hasZeroFields: (bool) false
|
||||
},
|
||||
opts: (*main.methodOptions)(0xc00009e9c0)({
|
||||
authType: (*main.supportedAuth)(0xc0003bd410)({
|
||||
opts: (*main.methodOptions)(0xc00009acc0)({
|
||||
authType: (*main.supportedAuth)(0xc0003c9c20)({
|
||||
id: (string) (len=5) "guest",
|
||||
name: (string) (len=5) "Guest",
|
||||
context: (map[string]string) {
|
||||
}
|
||||
}),
|
||||
method: (string) (len=4) "post",
|
||||
method: (string) (len=3) "get",
|
||||
route: (main.decodedRoute) {
|
||||
route: (string) (len=15) "/wizard/confirm",
|
||||
route: (string) (len=26) "/wizard/admin_connect_info",
|
||||
params: ([]string) <nil>
|
||||
},
|
||||
query: ([]string) <nil>,
|
||||
nostr: (bool) false,
|
||||
batch: (bool) false
|
||||
}),
|
||||
serverStream: (bool) false
|
||||
}),
|
||||
(*main.Method)(0xc00022a690)({
|
||||
in: (main.MethodMessage) {
|
||||
name: (string) (len=5) "Empty",
|
||||
hasZeroFields: (bool) true
|
||||
},
|
||||
name: (string) (len=15) "GetServiceState",
|
||||
out: (main.MethodMessage) {
|
||||
name: (string) (len=20) "ServiceStateResponse",
|
||||
hasZeroFields: (bool) false
|
||||
},
|
||||
opts: (*main.methodOptions)(0xc00009ae40)({
|
||||
authType: (*main.supportedAuth)(0xc0003c9ce0)({
|
||||
id: (string) (len=5) "guest",
|
||||
name: (string) (len=5) "Guest",
|
||||
context: (map[string]string) {
|
||||
}
|
||||
}),
|
||||
method: (string) (len=3) "get",
|
||||
route: (main.decodedRoute) {
|
||||
route: (string) (len=21) "/wizard/service_state",
|
||||
params: ([]string) <nil>
|
||||
},
|
||||
query: ([]string) <nil>,
|
||||
|
|
@ -85,137 +113,247 @@
|
|||
})
|
||||
}
|
||||
|
||||
([]*main.Enum) <nil>
|
||||
([]*main.Enum) (len=1 cap=1) {
|
||||
(*main.Enum)(0xc0003c9680)({
|
||||
name: (string) (len=8) "LndState",
|
||||
values: ([]main.EnumValue) (len=3 cap=4) {
|
||||
(main.EnumValue) {
|
||||
number: (int64) 0,
|
||||
name: (string) (len=7) "OFFLINE"
|
||||
},
|
||||
(main.EnumValue) {
|
||||
number: (int64) 1,
|
||||
name: (string) (len=7) "SYNCING"
|
||||
},
|
||||
(main.EnumValue) {
|
||||
number: (int64) 2,
|
||||
name: (string) (len=6) "ONLINE"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
(map[string]*main.Message) (len=6) {
|
||||
(string) (len=13) "StateResponse": (*main.Message)(0xc0003ee1c0)({
|
||||
(map[string]*main.Message) (len=5) {
|
||||
(string) (len=5) "Empty": (*main.Message)(0xc0003c94a0)({
|
||||
fullName: (string) (len=5) "Empty",
|
||||
name: (string) (len=5) "Empty",
|
||||
fields: (map[string]*main.Field) {
|
||||
}
|
||||
}),
|
||||
(string) (len=13) "StateResponse": (*main.Message)(0xc0003c9500)({
|
||||
fullName: (string) (len=13) "StateResponse",
|
||||
name: (string) (len=13) "StateResponse",
|
||||
fields: ([]*main.Field) (len=1 cap=1) {
|
||||
(*main.Field)(0xc0003bccc0)({
|
||||
name: (string) (len=19) "already_initialized",
|
||||
fields: (map[string]*main.Field) (len=2) {
|
||||
(string) (len=11) "config_sent": (*main.Field)(0xc0003ee440)({
|
||||
name: (string) (len=11) "config_sent",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=13) "ConfigRequest": (*main.Message)(0xc0003ee200)({
|
||||
fullName: (string) (len=13) "ConfigRequest",
|
||||
name: (string) (len=13) "ConfigRequest",
|
||||
fields: ([]*main.Field) (len=4 cap=4) {
|
||||
(*main.Field)(0xc0003bccf0)({
|
||||
name: (string) (len=11) "source_name",
|
||||
kind: (string) (len=6) "string",
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=12) "admin_linked": (*main.Field)(0xc0003ee480)({
|
||||
name: (string) (len=12) "admin_linked",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
}),
|
||||
(*main.Field)(0xc0003bcd20)({
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=13) "ConfigRequest": (*main.Message)(0xc0003c9560)({
|
||||
fullName: (string) (len=13) "ConfigRequest",
|
||||
name: (string) (len=13) "ConfigRequest",
|
||||
fields: (map[string]*main.Field) (len=4) {
|
||||
(string) (len=9) "relay_url": (*main.Field)(0xc0003ee500)({
|
||||
name: (string) (len=9) "relay_url",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(*main.Field)(0xc0003bcd50)({
|
||||
(string) (len=18) "automate_liquidity": (*main.Field)(0xc0003ee540)({
|
||||
name: (string) (len=18) "automate_liquidity",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(*main.Field)(0xc0003bcd80)({
|
||||
(string) (len=21) "push_backups_to_nostr": (*main.Field)(0xc0003ee580)({
|
||||
name: (string) (len=21) "push_backups_to_nostr",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=11) "source_name": (*main.Field)(0xc0003ee4c0)({
|
||||
name: (string) (len=11) "source_name",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=14) "ConfigResponse": (*main.Message)(0xc0003ee240)({
|
||||
fullName: (string) (len=14) "ConfigResponse",
|
||||
name: (string) (len=14) "ConfigResponse",
|
||||
fields: ([]*main.Field) (len=3 cap=4) {
|
||||
(*main.Field)(0xc0003bcdb0)({
|
||||
name: (string) (len=19) "already_initialized",
|
||||
(string) (len=24) "AdminConnectInfoResponse": (*main.Message)(0xc0003c95c0)({
|
||||
fullName: (string) (len=24) "AdminConnectInfoResponse",
|
||||
name: (string) (len=24) "AdminConnectInfoResponse",
|
||||
fields: (map[string]*main.Field) (len=2) {
|
||||
(string) (len=8) "nprofile": (*main.Field)(0xc0003ee5c0)({
|
||||
name: (string) (len=8) "nprofile",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=37) "AdminConnectInfoResponse_connect_info": (*main.Field)(0xc0003eea80)({
|
||||
name: (string) (len=12) "connect_info",
|
||||
kind: (string) (len=37) "AdminConnectInfoResponse_connect_info",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) (len=12) "connect_info"
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=20) "ServiceStateResponse": (*main.Message)(0xc0003c9620)({
|
||||
fullName: (string) (len=20) "ServiceStateResponse",
|
||||
name: (string) (len=20) "ServiceStateResponse",
|
||||
fields: (map[string]*main.Field) (len=8) {
|
||||
(string) (len=10) "admin_npub": (*main.Field)(0xc0003ee700)({
|
||||
name: (string) (len=10) "admin_npub",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=15) "relay_connected": (*main.Field)(0xc0003ee740)({
|
||||
name: (string) (len=15) "relay_connected",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(*main.Field)(0xc0003bcde0)({
|
||||
name: (string) (len=4) "seed",
|
||||
(string) (len=9) "lnd_state": (*main.Field)(0xc0003ee780)({
|
||||
name: (string) (len=9) "lnd_state",
|
||||
kind: (string) (len=8) "LndState",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) true,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=11) "watchdog_ok": (*main.Field)(0xc0003ee7c0)({
|
||||
name: (string) (len=11) "watchdog_ok",
|
||||
kind: (string) (len=4) "bool",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=8) "http_url": (*main.Field)(0xc0003ee800)({
|
||||
name: (string) (len=8) "http_url",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=8) "nprofile": (*main.Field)(0xc0003ee840)({
|
||||
name: (string) (len=8) "nprofile",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=13) "provider_name": (*main.Field)(0xc0003ee680)({
|
||||
name: (string) (len=13) "provider_name",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
}),
|
||||
(string) (len=6) "relays": (*main.Field)(0xc0003ee6c0)({
|
||||
name: (string) (len=6) "relays",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) true,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
}),
|
||||
(*main.Field)(0xc0003bce10)({
|
||||
name: (string) (len=15) "confirmation_id",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) ""
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=14) "ConfirmRequest": (*main.Message)(0xc0003ee280)({
|
||||
fullName: (string) (len=14) "ConfirmRequest",
|
||||
name: (string) (len=14) "ConfirmRequest",
|
||||
fields: ([]*main.Field) (len=1 cap=1) {
|
||||
(*main.Field)(0xc0003bce40)({
|
||||
name: (string) (len=15) "confirmation_id",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=15) "ConfirmResponse": (*main.Message)(0xc0003ee2c0)({
|
||||
fullName: (string) (len=15) "ConfirmResponse",
|
||||
name: (string) (len=15) "ConfirmResponse",
|
||||
fields: ([]*main.Field) (len=1 cap=1) {
|
||||
(*main.Field)(0xc0003bce70)({
|
||||
name: (string) (len=9) "admin_key",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false
|
||||
})
|
||||
}
|
||||
}),
|
||||
(string) (len=5) "Empty": (*main.Message)(0xc0003ee080)({
|
||||
fullName: (string) (len=5) "Empty",
|
||||
name: (string) (len=5) "Empty",
|
||||
fields: ([]*main.Field) <nil>
|
||||
})
|
||||
}
|
||||
|
||||
parsing file: wizard_structs 6
|
||||
(map[string][]*main.Field) (len=1) {
|
||||
(string) (len=37) "AdminConnectInfoResponse_connect_info": ([]*main.Field) (len=2 cap=2) {
|
||||
(*main.Field)(0xc0003ee600)({
|
||||
name: (string) (len=11) "admin_token",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) (len=12) "connect_info"
|
||||
}),
|
||||
(*main.Field)(0xc0003ee640)({
|
||||
name: (string) (len=13) "enrolled_npub",
|
||||
kind: (string) (len=6) "string",
|
||||
isMap: (bool) false,
|
||||
isArray: (bool) false,
|
||||
isEnum: (bool) false,
|
||||
isMessage: (bool) false,
|
||||
isOptional: (bool) false,
|
||||
oneOfName: (string) (len=12) "connect_info"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
parsing file: wizard_structs 5
|
||||
parsing file: wizard_methods 2
|
||||
-> [{guest Guest map[]}]
|
||||
|
||||
([]interface {}) <nil>
|
||||
|
||||
|
|
|
|||
|
|
@ -64,29 +64,45 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||
const query = req.query
|
||||
const params = req.params
|
||||
const response = await methods.WizardConfig({rpcName:'WizardConfig', ctx:authContext , req: request})
|
||||
await methods.WizardConfig({rpcName:'WizardConfig', ctx:authContext , req: request})
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({status: 'OK'})
|
||||
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.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented')
|
||||
app.get('/wizard/admin_connect_info', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetAdminConnectInfo', 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.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented')
|
||||
const authContext = await opts.GuestAuthGuard(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.GetAdminConnectInfo({rpcName:'GetAdminConnectInfo', ctx:authContext })
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({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 }
|
||||
})
|
||||
if (!opts.allowNotImplementedMethods && !methods.WizardConfirm) throw new Error('method: WizardConfirm is not implemented')
|
||||
app.post('/wizard/confirm', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'WizardConfirm', batch: false, nostr: false, batchSize: 0}
|
||||
if (!opts.allowNotImplementedMethods && !methods.GetServiceState) throw new Error('method: GetServiceState is not implemented')
|
||||
app.get('/wizard/service_state', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetServiceState', 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.WizardConfirm) throw new Error('method: WizardConfirm is not implemented')
|
||||
if (!methods.GetServiceState) throw new Error('method: GetServiceState is not implemented')
|
||||
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
||||
authCtx = authContext
|
||||
stats.guard = process.hrtime.bigint()
|
||||
const request = req.body
|
||||
const error = Types.ConfirmRequestValidate(request)
|
||||
stats.validate = process.hrtime.bigint()
|
||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||
stats.validate = stats.guard
|
||||
const query = req.query
|
||||
const params = req.params
|
||||
const response = await methods.WizardConfirm({rpcName:'WizardConfirm', ctx:authContext , req: request})
|
||||
const response = await methods.GetServiceState({rpcName:'GetServiceState', ctx:authContext })
|
||||
stats.handle = process.hrtime.bigint()
|
||||
res.json({status: 'OK', ...response})
|
||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
||||
|
|
@ -99,6 +115,6 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|||
var server: { close: () => void } | undefined
|
||||
return {
|
||||
Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() },
|
||||
Listen: (port: number) => { server = app.listen(port, () => logger.log('Example app listening on port ' + port)) }
|
||||
Listen: (port: number) => { server = app.listen(port, () => logger.log('Wizard listening on port ' + port)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,30 +26,41 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
WizardConfig: async (request: Types.ConfigRequest): Promise<ResultError | ({ status: 'OK' }& Types.ConfigResponse)> => {
|
||||
WizardConfig: async (request: Types.ConfigRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||
const auth = await params.retrieveGuestAuth()
|
||||
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||
let finalRoute = '/wizard/config'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||
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.ConfigResponseValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
return data
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
WizardConfirm: async (request: Types.ConfirmRequest): Promise<ResultError | ({ status: 'OK' }& Types.ConfirmResponse)> => {
|
||||
GetAdminConnectInfo: async (): Promise<ResultError | ({ status: 'OK' }& Types.AdminConnectInfoResponse)> => {
|
||||
const auth = await params.retrieveGuestAuth()
|
||||
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||
let finalRoute = '/wizard/confirm'
|
||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||
let finalRoute = '/wizard/admin_connect_info'
|
||||
const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } })
|
||||
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.ConfirmResponseValidate(result)
|
||||
const error = Types.AdminConnectInfoResponseValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetServiceState: async (): Promise<ResultError | ({ status: 'OK' }& Types.ServiceStateResponse)> => {
|
||||
const auth = await params.retrieveGuestAuth()
|
||||
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||
let finalRoute = '/wizard/service_state'
|
||||
const { data } = await axios.get(params.baseUrl + finalRoute, { headers: { 'authorization': auth } })
|
||||
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.ServiceStateResponseValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
|
|
|
|||
|
|
@ -6,97 +6,43 @@ export type RequestStats = { startMs:number, start:bigint, parse: bigint, guard:
|
|||
export type RequestMetric = AuthContext & RequestInfo & RequestStats & { error?: string }
|
||||
export type GuestContext = {
|
||||
}
|
||||
export type GuestMethodInputs = WizardState_Input | WizardConfig_Input | WizardConfirm_Input
|
||||
export type GuestMethodOutputs = WizardState_Output | WizardConfig_Output | WizardConfirm_Output
|
||||
export type GuestMethodInputs = WizardState_Input | WizardConfig_Input | GetAdminConnectInfo_Input | GetServiceState_Input
|
||||
export type GuestMethodOutputs = WizardState_Output | WizardConfig_Output | GetAdminConnectInfo_Output | GetServiceState_Output
|
||||
export type AuthContext = GuestContext
|
||||
|
||||
export type WizardState_Input = {rpcName:'WizardState'}
|
||||
export type WizardState_Output = ResultError | ({ status: 'OK' } & StateResponse)
|
||||
|
||||
export type WizardConfig_Input = {rpcName:'WizardConfig', req: ConfigRequest}
|
||||
export type WizardConfig_Output = ResultError | ({ status: 'OK' } & ConfigResponse)
|
||||
export type WizardConfig_Output = ResultError | { status: 'OK' }
|
||||
|
||||
export type WizardConfirm_Input = {rpcName:'WizardConfirm', req: ConfirmRequest}
|
||||
export type WizardConfirm_Output = ResultError | ({ status: 'OK' } & ConfirmResponse)
|
||||
export type GetAdminConnectInfo_Input = {rpcName:'GetAdminConnectInfo'}
|
||||
export type GetAdminConnectInfo_Output = ResultError | ({ status: 'OK' } & AdminConnectInfoResponse)
|
||||
|
||||
export type GetServiceState_Input = {rpcName:'GetServiceState'}
|
||||
export type GetServiceState_Output = ResultError | ({ status: 'OK' } & ServiceStateResponse)
|
||||
|
||||
export type ServerMethods = {
|
||||
WizardState?: (req: WizardState_Input & {ctx: GuestContext }) => Promise<StateResponse>
|
||||
WizardConfig?: (req: WizardConfig_Input & {ctx: GuestContext }) => Promise<ConfigResponse>
|
||||
WizardConfirm?: (req: WizardConfirm_Input & {ctx: GuestContext }) => Promise<ConfirmResponse>
|
||||
WizardConfig?: (req: WizardConfig_Input & {ctx: GuestContext }) => Promise<void>
|
||||
GetAdminConnectInfo?: (req: GetAdminConnectInfo_Input & {ctx: GuestContext }) => Promise<AdminConnectInfoResponse>
|
||||
GetServiceState?: (req: GetServiceState_Input & {ctx: GuestContext }) => Promise<ServiceStateResponse>
|
||||
}
|
||||
|
||||
export enum LndState {
|
||||
OFFLINE = 'OFFLINE',
|
||||
SYNCING = 'SYNCING',
|
||||
ONLINE = 'ONLINE',
|
||||
}
|
||||
export const enumCheckLndState = (e?: LndState): boolean => {
|
||||
for (const v in LndState) if (e === v) return true
|
||||
return false
|
||||
}
|
||||
|
||||
export type OptionsBaseMessage = {
|
||||
allOptionalsAreSet?: true
|
||||
}
|
||||
|
||||
export type ConfigResponse = {
|
||||
already_initialized: boolean
|
||||
seed: string[]
|
||||
confirmation_id: string
|
||||
}
|
||||
export const ConfigResponseOptionalFields: [] = []
|
||||
export type ConfigResponseOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
already_initialized_CustomCheck?: (v: boolean) => boolean
|
||||
seed_CustomCheck?: (v: string[]) => boolean
|
||||
confirmation_id_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const ConfigResponseValidate = (o?: ConfigResponse, opts: ConfigResponseOptions = {}, path: string = 'ConfigResponse::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.already_initialized !== 'boolean') return new Error(`${path}.already_initialized: is not a boolean`)
|
||||
if (opts.already_initialized_CustomCheck && !opts.already_initialized_CustomCheck(o.already_initialized)) return new Error(`${path}.already_initialized: custom check failed`)
|
||||
|
||||
if (!Array.isArray(o.seed)) return new Error(`${path}.seed: is not an array`)
|
||||
for (let index = 0; index < o.seed.length; index++) {
|
||||
if (typeof o.seed[index] !== 'string') return new Error(`${path}.seed[${index}]: is not a string`)
|
||||
}
|
||||
if (opts.seed_CustomCheck && !opts.seed_CustomCheck(o.seed)) return new Error(`${path}.seed: custom check failed`)
|
||||
|
||||
if (typeof o.confirmation_id !== 'string') return new Error(`${path}.confirmation_id: is not a string`)
|
||||
if (opts.confirmation_id_CustomCheck && !opts.confirmation_id_CustomCheck(o.confirmation_id)) return new Error(`${path}.confirmation_id: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type ConfirmRequest = {
|
||||
confirmation_id: string
|
||||
}
|
||||
export const ConfirmRequestOptionalFields: [] = []
|
||||
export type ConfirmRequestOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
confirmation_id_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const ConfirmRequestValidate = (o?: ConfirmRequest, opts: ConfirmRequestOptions = {}, path: string = 'ConfirmRequest::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.confirmation_id !== 'string') return new Error(`${path}.confirmation_id: is not a string`)
|
||||
if (opts.confirmation_id_CustomCheck && !opts.confirmation_id_CustomCheck(o.confirmation_id)) return new Error(`${path}.confirmation_id: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type ConfirmResponse = {
|
||||
admin_key: string
|
||||
}
|
||||
export const ConfirmResponseOptionalFields: [] = []
|
||||
export type ConfirmResponseOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
admin_key_CustomCheck?: (v: string) => boolean
|
||||
}
|
||||
export const ConfirmResponseValidate = (o?: ConfirmResponse, opts: ConfirmResponseOptions = {}, path: string = 'ConfirmResponse::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.admin_key !== 'string') return new Error(`${path}.admin_key: is not a string`)
|
||||
if (opts.admin_key_CustomCheck && !opts.admin_key_CustomCheck(o.admin_key)) return new Error(`${path}.admin_key: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type Empty = {
|
||||
}
|
||||
export const EmptyOptionalFields: [] = []
|
||||
|
|
@ -111,19 +57,24 @@ export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string =
|
|||
}
|
||||
|
||||
export type StateResponse = {
|
||||
already_initialized: boolean
|
||||
config_sent: boolean
|
||||
admin_linked: boolean
|
||||
}
|
||||
export const StateResponseOptionalFields: [] = []
|
||||
export type StateResponseOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
already_initialized_CustomCheck?: (v: boolean) => boolean
|
||||
config_sent_CustomCheck?: (v: boolean) => boolean
|
||||
admin_linked_CustomCheck?: (v: boolean) => boolean
|
||||
}
|
||||
export const StateResponseValidate = (o?: StateResponse, opts: StateResponseOptions = {}, path: string = 'StateResponse::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.already_initialized !== 'boolean') return new Error(`${path}.already_initialized: is not a boolean`)
|
||||
if (opts.already_initialized_CustomCheck && !opts.already_initialized_CustomCheck(o.already_initialized)) return new Error(`${path}.already_initialized: custom check failed`)
|
||||
if (typeof o.config_sent !== 'boolean') return new Error(`${path}.config_sent: is not a boolean`)
|
||||
if (opts.config_sent_CustomCheck && !opts.config_sent_CustomCheck(o.config_sent)) return new Error(`${path}.config_sent: custom check failed`)
|
||||
|
||||
if (typeof o.admin_linked !== 'boolean') return new Error(`${path}.admin_linked: is not a boolean`)
|
||||
if (opts.admin_linked_CustomCheck && !opts.admin_linked_CustomCheck(o.admin_linked)) return new Error(`${path}.admin_linked: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
@ -137,10 +88,10 @@ export type ConfigRequest = {
|
|||
export const ConfigRequestOptionalFields: [] = []
|
||||
export type ConfigRequestOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
push_backups_to_nostr_CustomCheck?: (v: boolean) => boolean
|
||||
source_name_CustomCheck?: (v: string) => boolean
|
||||
relay_url_CustomCheck?: (v: string) => boolean
|
||||
automate_liquidity_CustomCheck?: (v: boolean) => boolean
|
||||
push_backups_to_nostr_CustomCheck?: (v: boolean) => boolean
|
||||
}
|
||||
export const ConfigRequestValidate = (o?: ConfigRequest, opts: ConfigRequestOptions = {}, path: string = 'ConfigRequest::root.'): Error | null => {
|
||||
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
|
||||
|
|
@ -161,3 +112,103 @@ export const ConfigRequestValidate = (o?: ConfigRequest, opts: ConfigRequestOpti
|
|||
return null
|
||||
}
|
||||
|
||||
export type AdminConnectInfoResponse = {
|
||||
nprofile: string
|
||||
connect_info: AdminConnectInfoResponse_connect_info
|
||||
}
|
||||
export const AdminConnectInfoResponseOptionalFields: [] = []
|
||||
export type AdminConnectInfoResponseOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
nprofile_CustomCheck?: (v: string) => boolean
|
||||
connect_info_CustomCheck?: (v: AdminConnectInfoResponse_connect_info) => boolean
|
||||
}
|
||||
export const AdminConnectInfoResponseValidate = (o?: AdminConnectInfoResponse, opts: AdminConnectInfoResponseOptions = {}, path: string = 'AdminConnectInfoResponse::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.nprofile !== 'string') return new Error(`${path}.nprofile: is not a string`)
|
||||
if (opts.nprofile_CustomCheck && !opts.nprofile_CustomCheck(o.nprofile)) return new Error(`${path}.nprofile: custom check failed`)
|
||||
|
||||
const connect_infoErr = AdminConnectInfoResponse_connect_infoValidate(o.connect_info,{}, `${path}.connect_info`)
|
||||
if (connect_infoErr !== null) return connect_infoErr
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type ServiceStateResponse = {
|
||||
http_url: string
|
||||
nprofile: string
|
||||
provider_name: string
|
||||
relays: string[]
|
||||
admin_npub: string
|
||||
relay_connected: boolean
|
||||
lnd_state: LndState
|
||||
watchdog_ok: boolean
|
||||
}
|
||||
export const ServiceStateResponseOptionalFields: [] = []
|
||||
export type ServiceStateResponseOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
http_url_CustomCheck?: (v: string) => boolean
|
||||
nprofile_CustomCheck?: (v: string) => boolean
|
||||
provider_name_CustomCheck?: (v: string) => boolean
|
||||
relays_CustomCheck?: (v: string[]) => boolean
|
||||
admin_npub_CustomCheck?: (v: string) => boolean
|
||||
relay_connected_CustomCheck?: (v: boolean) => boolean
|
||||
lnd_state_CustomCheck?: (v: LndState) => boolean
|
||||
watchdog_ok_CustomCheck?: (v: boolean) => boolean
|
||||
}
|
||||
export const ServiceStateResponseValidate = (o?: ServiceStateResponse, opts: ServiceStateResponseOptions = {}, path: string = 'ServiceStateResponse::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.relays)) return new Error(`${path}.relays: is not an array`)
|
||||
for (let index = 0; index < o.relays.length; index++) {
|
||||
if (typeof o.relays[index] !== 'string') return new Error(`${path}.relays[${index}]: is not a string`)
|
||||
}
|
||||
if (opts.relays_CustomCheck && !opts.relays_CustomCheck(o.relays)) return new Error(`${path}.relays: custom check failed`)
|
||||
|
||||
if (typeof o.admin_npub !== 'string') return new Error(`${path}.admin_npub: is not a string`)
|
||||
if (opts.admin_npub_CustomCheck && !opts.admin_npub_CustomCheck(o.admin_npub)) return new Error(`${path}.admin_npub: custom check failed`)
|
||||
|
||||
if (typeof o.relay_connected !== 'boolean') return new Error(`${path}.relay_connected: is not a boolean`)
|
||||
if (opts.relay_connected_CustomCheck && !opts.relay_connected_CustomCheck(o.relay_connected)) return new Error(`${path}.relay_connected: custom check failed`)
|
||||
|
||||
if (!enumCheckLndState(o.lnd_state)) return new Error(`${path}.lnd_state: is not a valid LndState`)
|
||||
if (opts.lnd_state_CustomCheck && !opts.lnd_state_CustomCheck(o.lnd_state)) return new Error(`${path}.lnd_state: custom check failed`)
|
||||
|
||||
if (typeof o.watchdog_ok !== 'boolean') return new Error(`${path}.watchdog_ok: is not a boolean`)
|
||||
if (opts.watchdog_ok_CustomCheck && !opts.watchdog_ok_CustomCheck(o.watchdog_ok)) return new Error(`${path}.watchdog_ok: custom check failed`)
|
||||
|
||||
if (typeof o.http_url !== 'string') return new Error(`${path}.http_url: is not a string`)
|
||||
if (opts.http_url_CustomCheck && !opts.http_url_CustomCheck(o.http_url)) return new Error(`${path}.http_url: custom check failed`)
|
||||
|
||||
if (typeof o.nprofile !== 'string') return new Error(`${path}.nprofile: is not a string`)
|
||||
if (opts.nprofile_CustomCheck && !opts.nprofile_CustomCheck(o.nprofile)) return new Error(`${path}.nprofile: custom check failed`)
|
||||
|
||||
if (typeof o.provider_name !== 'string') return new Error(`${path}.provider_name: is not a string`)
|
||||
if (opts.provider_name_CustomCheck && !opts.provider_name_CustomCheck(o.provider_name)) return new Error(`${path}.provider_name: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export enum AdminConnectInfoResponse_connect_info_type {
|
||||
ADMIN_TOKEN = 'admin_token',
|
||||
ENROLLED_NPUB = 'enrolled_npub',
|
||||
}
|
||||
export type AdminConnectInfoResponse_connect_info =
|
||||
{type:AdminConnectInfoResponse_connect_info_type.ADMIN_TOKEN, admin_token:string}|
|
||||
{type:AdminConnectInfoResponse_connect_info_type.ENROLLED_NPUB, enrolled_npub:string}
|
||||
|
||||
export const AdminConnectInfoResponse_connect_infoValidate = (o?: AdminConnectInfoResponse_connect_info, opts = {}, path: string = 'AdminConnectInfoResponse_connect_info::root.'): Error | null => {
|
||||
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
|
||||
switch (o.type) {
|
||||
case 'admin_token':
|
||||
if (typeof o.admin_token !== 'string') return new Error(`${path}.admin_token: is not a string`)
|
||||
break
|
||||
case 'enrolled_npub':
|
||||
if (typeof o.enrolled_npub !== 'string') return new Error(`${path}.enrolled_npub: is not a string`)
|
||||
break
|
||||
}
|
||||
return new Error(path + ': unknown type'+ o.type)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import nostrMiddleware from './nostrMiddleware.js'
|
|||
import { getLogger } from './services/helpers/logger.js';
|
||||
import { initMainHandler } from './services/main/init.js';
|
||||
import { LoadMainSettingsFromEnv } from './services/main/settings.js';
|
||||
import { encodeNprofile } from './custom-nip19.js';
|
||||
|
||||
const start = async () => {
|
||||
const log = getLogger({})
|
||||
|
|
@ -16,7 +17,7 @@ const start = async () => {
|
|||
log("manual process ended")
|
||||
return
|
||||
}
|
||||
const { apps, mainHandler, liquidityProviderInfo } = keepOn
|
||||
const { apps, mainHandler, liquidityProviderInfo, wizard } = keepOn
|
||||
const serverMethods = GetServerMethods(mainHandler)
|
||||
const nostrSettings = LoadNosrtSettingsFromEnv()
|
||||
log("initializing nostr middleware")
|
||||
|
|
@ -27,6 +28,9 @@ const start = async () => {
|
|||
log("starting server")
|
||||
mainHandler.attachNostrSend(Send)
|
||||
mainHandler.StartBeacons()
|
||||
if (wizard) {
|
||||
wizard.AddConnectInfo(encodeNprofile({ pubkey: liquidityProviderInfo.publicKey, relays: nostrSettings.relays }), nostrSettings.relays)
|
||||
}
|
||||
const Server = NewServer(serverMethods, serverOptions(mainHandler))
|
||||
Server.Listen(mainSettings.servicePort)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,20 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
|||
const nostrUser = await mainHandler.storage.applicationStorage.GetOrCreateNostrAppUser(app, pub || "")
|
||||
return { user_id: nostrUser.user.user_id, app_user_id: nostrUser.identifier, app_id: appId || "" }
|
||||
},
|
||||
NostrAdminAuthGuard: async (appId, pub) => {
|
||||
const adminNpub = mainHandler.adminManager.GetAdminNpub()
|
||||
if (!adminNpub) { throw new Error("admin access not configured") }
|
||||
if (pub !== adminNpub) { throw new Error("admin access denied") }
|
||||
log("admin access from", pub)
|
||||
return { admin_id: pub }
|
||||
},
|
||||
NostrMetricsAuthGuard: async (appId, pub) => {
|
||||
const adminNpub = mainHandler.adminManager.GetAdminNpub()
|
||||
if (!adminNpub) { throw new Error("admin access not configured") }
|
||||
if (pub !== adminNpub) { throw new Error("admin access denied") }
|
||||
log("operator access from", pub)
|
||||
return { operator_id: pub }
|
||||
},
|
||||
metricsCallback: metrics => mainHandler.settings.recordPerformance ? mainHandler.metricsManager.AddMetrics(metrics) : null,
|
||||
logger: { log: console.log, error: err => log(ERROR, err) }
|
||||
})
|
||||
|
|
|
|||
97
src/services/main/adminManager.ts
Normal file
97
src/services/main/adminManager.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import fs, { watchFile } from "fs";
|
||||
import crypto from 'crypto'
|
||||
import { getLogger } from "../helpers/logger.js";
|
||||
import { MainSettings, getDataPath } from "./settings.js";
|
||||
import Storage from "../storage/index.js";
|
||||
export class AdminManager {
|
||||
storage: Storage
|
||||
log = getLogger({ component: "adminManager" })
|
||||
adminNpub = ""
|
||||
dataDir: string
|
||||
adminNpubPath: string
|
||||
adminEnrollTokenPath: string
|
||||
interval: NodeJS.Timer
|
||||
constructor(mainSettings: MainSettings, storage: Storage) {
|
||||
this.storage = storage
|
||||
this.dataDir = mainSettings.storageSettings.dataDir
|
||||
this.adminNpubPath = getDataPath(this.dataDir, 'admin.npub')
|
||||
this.adminEnrollTokenPath = getDataPath(this.dataDir, '.admin_enroll')
|
||||
this.start()
|
||||
}
|
||||
Stop = () => {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
|
||||
GenerateAdminEnrollToken = async () => {
|
||||
const token = crypto.randomBytes(32).toString('hex')
|
||||
fs.writeFileSync(this.adminEnrollTokenPath, token)
|
||||
return token
|
||||
}
|
||||
|
||||
start = () => {
|
||||
const adminNpub = this.ReadAdminNpub()
|
||||
if (adminNpub) {
|
||||
this.adminNpub = adminNpub
|
||||
} else if (!fs.existsSync(this.adminEnrollTokenPath)) {
|
||||
this.GenerateAdminEnrollToken()
|
||||
}
|
||||
this.interval = setInterval(() => {
|
||||
if (!this.adminNpub) {
|
||||
return
|
||||
}
|
||||
const deleted = !fs.existsSync(this.adminNpubPath)
|
||||
if (deleted) {
|
||||
this.adminNpub = ""
|
||||
this.log("admin npub file deleted")
|
||||
this.GenerateAdminEnrollToken()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ReadAdminEnrollToken = () => {
|
||||
try {
|
||||
return fs.readFileSync(this.adminEnrollTokenPath, 'utf8').trim()
|
||||
} catch (err: any) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
ReadAdminNpub = () => {
|
||||
try {
|
||||
return fs.readFileSync(this.adminNpubPath, 'utf8').trim()
|
||||
} catch (err: any) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
GetAdminNpub = () => {
|
||||
return this.adminNpub
|
||||
}
|
||||
|
||||
ClearExistingAdmin = () => {
|
||||
try {
|
||||
fs.unlinkSync(this.adminNpubPath)
|
||||
} catch (err: any) { }
|
||||
}
|
||||
|
||||
PromoteUserToAdmin = async (appId: string, appUserId: string, token: string) => {
|
||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
||||
const npub = appUser.nostr_public_key
|
||||
if (!npub) {
|
||||
throw new Error("no npub found for user")
|
||||
}
|
||||
let actualToken
|
||||
try {
|
||||
actualToken = fs.readFileSync(this.adminEnrollTokenPath, 'utf8').trim()
|
||||
} catch (err: any) {
|
||||
throw new Error("invalid enroll token")
|
||||
}
|
||||
if (token !== actualToken) {
|
||||
throw new Error("invalid enroll token")
|
||||
}
|
||||
fs.writeFileSync(this.adminNpubPath, npub)
|
||||
fs.unlinkSync(this.adminEnrollTokenPath)
|
||||
this.adminNpub = npub
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import { LiquidityProvider } from "./liquidityProvider.js"
|
|||
import { LiquidityManager } from "./liquidityManager.js"
|
||||
import { Utils } from "../helpers/utilsWrapper.js"
|
||||
import { RugPullTracker } from "./rugPullTracker.js"
|
||||
import { AdminManager } from "./adminManager.js"
|
||||
|
||||
type UserOperationsSub = {
|
||||
id: string
|
||||
|
|
@ -33,21 +34,23 @@ export default class {
|
|||
lnd: LND
|
||||
settings: MainSettings
|
||||
userOperationsSub: UserOperationsSub | null = null
|
||||
adminManager: AdminManager
|
||||
productManager: ProductManager
|
||||
applicationManager: ApplicationManager
|
||||
appUserManager: AppUserManager
|
||||
paymentManager: PaymentManager
|
||||
paymentSubs: Record<string, ((op: Types.UserOperation) => void) | null> = {}
|
||||
metricsManager: MetricsManager
|
||||
liquidityProvider: LiquidityProvider
|
||||
liquidityManager: LiquidityManager
|
||||
liquidityProvider: LiquidityProvider
|
||||
utils: Utils
|
||||
rugPullTracker: RugPullTracker
|
||||
nostrSend: NostrSend = () => { getLogger({})("nostr send not initialized yet") }
|
||||
constructor(settings: MainSettings, storage: Storage, utils: Utils) {
|
||||
constructor(settings: MainSettings, storage: Storage, adminManager: AdminManager, utils: Utils) {
|
||||
this.settings = settings
|
||||
this.storage = storage
|
||||
this.utils = utils
|
||||
this.adminManager = adminManager
|
||||
const updateProviderBalance = (b: number) => this.storage.liquidityStorage.IncrementTrackedProviderBalance('lnPub', settings.liquiditySettings.liquidityProviderPub, b)
|
||||
this.liquidityProvider = new LiquidityProvider(settings.liquiditySettings.liquidityProviderPub, this.utils, this.invoicePaidCb, updateProviderBalance)
|
||||
this.rugPullTracker = new RugPullTracker(this.storage, this.liquidityProvider)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import SanityChecker from "./sanityChecker.js"
|
|||
import { LoadMainSettingsFromEnv, MainSettings } from "./settings.js"
|
||||
import { Utils } from "../helpers/utilsWrapper.js"
|
||||
import { Wizard } from "../wizard/index.js"
|
||||
import { AdminManager } from "./adminManager.js"
|
||||
import { encodeNprofile } from "../../custom-nip19.js"
|
||||
export type AppData = {
|
||||
privateKey: string;
|
||||
publicKey: string;
|
||||
|
|
@ -21,19 +23,20 @@ export const initMainHandler = async (log: PubLogger, mainSettings: MainSettings
|
|||
if (manualMigration) {
|
||||
return
|
||||
}
|
||||
const unlocker = new Unlocker(mainSettings, storageManager)
|
||||
await unlocker.Unlock()
|
||||
const adminManager = new AdminManager(mainSettings, storageManager)
|
||||
let reloadedSettings = mainSettings
|
||||
let wizard: Wizard | null = null
|
||||
if (mainSettings.wizard) {
|
||||
const wizard = new Wizard(mainSettings, storageManager)
|
||||
const reload = await wizard.WaitUntilConfigured()
|
||||
wizard = new Wizard(mainSettings, storageManager, adminManager)
|
||||
const reload = await wizard.Configure()
|
||||
if (reload) {
|
||||
reloadedSettings = LoadMainSettingsFromEnv()
|
||||
}
|
||||
} else {
|
||||
const unlocker = new Unlocker(mainSettings, storageManager)
|
||||
await unlocker.Unlock()
|
||||
}
|
||||
|
||||
const mainHandler = new Main(reloadedSettings, storageManager, utils)
|
||||
const mainHandler = new Main(reloadedSettings, storageManager, adminManager, utils)
|
||||
await mainHandler.lnd.Warmup()
|
||||
if (!reloadedSettings.skipSanityCheck) {
|
||||
const sanityChecker = new SanityChecker(storageManager, mainHandler.lnd)
|
||||
|
|
@ -70,7 +73,7 @@ export const initMainHandler = async (log: PubLogger, mainSettings: MainSettings
|
|||
return
|
||||
}
|
||||
mainHandler.paymentManager.watchDog.Start()
|
||||
return { mainHandler, apps, liquidityProviderInfo, liquidityProviderApp }
|
||||
return { mainHandler, apps, liquidityProviderInfo, liquidityProviderApp, wizard }
|
||||
}
|
||||
|
||||
const processArgs = async (mainHandler: Main) => {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ export class LiquidityManager {
|
|||
}
|
||||
|
||||
onNewBlock = async () => {
|
||||
await this.shouldDrainProvider()
|
||||
try {
|
||||
await this.shouldDrainProvider()
|
||||
} catch (err: any) {
|
||||
this.log("error in onNewBlock", err.message || err)
|
||||
}
|
||||
}
|
||||
|
||||
beforeInvoiceCreation = async (amount: number): Promise<'lnd' | 'provider'> => {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ export class LiquidityProvider {
|
|||
this.client = newNostrClient({
|
||||
pubDestination: this.pubDestination,
|
||||
retrieveNostrUserAuth: async () => this.myPub,
|
||||
retrieveNostrAdminAuth: async () => this.myPub,
|
||||
retrieveNostrMetricsAuth: async () => this.myPub,
|
||||
}, this.clientSend, this.clientSub)
|
||||
|
||||
this.configuredInterval = setInterval(() => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { getLogger } from '../helpers/logger.js'
|
|||
import fs from 'fs'
|
||||
import crypto from 'crypto';
|
||||
import { LiquiditySettings, LoadLiquiditySettingsFromEnv } from './liquidityManager.js'
|
||||
|
||||
export type MainSettings = {
|
||||
storageSettings: StorageSettings,
|
||||
lndSettings: LndSettings,
|
||||
|
|
@ -44,6 +45,7 @@ export type TestSettings = MainSettings & { lndSettings: { otherNode: NodeSettin
|
|||
export const LoadMainSettingsFromEnv = (): MainSettings => {
|
||||
const storageSettings = LoadStorageSettingsFromEnv()
|
||||
const outgoingAppUserInvoiceFeeBps = EnvCanBeInteger("OUTGOING_INVOICE_FEE_USER_BPS", 0)
|
||||
|
||||
return {
|
||||
watchDogSettings: LoadWatchdogSettingsFromEnv(),
|
||||
lndSettings: LoadLndSettingsFromEnv(),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export class Unlocker {
|
|||
settings: MainSettings
|
||||
storage: Storage
|
||||
abortController = new AbortController()
|
||||
pendingSeed: Record<string, EncryptedData> = {}
|
||||
subbedToBackups = false
|
||||
log = getLogger({ component: "unlocker" })
|
||||
constructor(settings: MainSettings, storage: Storage) {
|
||||
this.settings = settings
|
||||
|
|
@ -46,55 +46,29 @@ export class Unlocker {
|
|||
return { lndCert, macaroon }
|
||||
}
|
||||
|
||||
IsInitialized = async () => {
|
||||
const { macaroon } = await this.getCreds()
|
||||
IsInitialized = () => {
|
||||
const { macaroon } = this.getCreds()
|
||||
return macaroon !== ''
|
||||
}
|
||||
|
||||
InitInteractive = async (): Promise<{ alreadyInitizialized: true } | { alreadyInitizialized: false, seed: string[], confirmationId: string }> => {
|
||||
const { lndCert, macaroon } = await this.getCreds()
|
||||
if (macaroon !== '') {
|
||||
const { ln, pub } = await this.UnlockFlow(lndCert, macaroon)
|
||||
Unlock = async (): Promise<'created' | 'unlocked' | 'noaction'> => {
|
||||
const { lndCert, macaroon } = this.getCreds()
|
||||
if (macaroon === "") {
|
||||
const { ln, pub } = await this.InitFlow(lndCert)
|
||||
this.subscribeToBackups(ln, pub)
|
||||
return { alreadyInitizialized: true }
|
||||
return 'created'
|
||||
}
|
||||
const unlocker = this.GetUnlockerClient(lndCert)
|
||||
const seed = await this.genSeed(unlocker)
|
||||
const confirmationId = crypto.randomBytes(32).toString('hex')
|
||||
this.pendingSeed[confirmationId] = seed.encryptedSeed
|
||||
return { alreadyInitizialized: false, seed: seed.plaintextSeed, confirmationId }
|
||||
}
|
||||
|
||||
ConfirmInitInteractive = async (confirmationId: string) => {
|
||||
const { lndCert, macaroon } = await this.getCreds()
|
||||
if (macaroon !== '') {
|
||||
const { ln, pub } = await this.UnlockFlow(lndCert, macaroon)
|
||||
this.subscribeToBackups(ln, pub)
|
||||
return { alreadyInitizialized: true }
|
||||
}
|
||||
const seed = this.pendingSeed[confirmationId]
|
||||
if (!seed) {
|
||||
throw new Error("seed not found")
|
||||
}
|
||||
delete this.pendingSeed[confirmationId]
|
||||
const plaintextSeed = this.DecryptWalletSeed(seed)
|
||||
const unlocker = this.GetUnlockerClient(lndCert)
|
||||
const { ln, pub } = await this.initWallet(lndCert, unlocker, { plaintextSeed, encryptedSeed: seed })
|
||||
const { ln, pub, action } = await this.UnlockFlow(lndCert, macaroon)
|
||||
this.subscribeToBackups(ln, pub)
|
||||
return action
|
||||
}
|
||||
|
||||
Unlock = async () => {
|
||||
const { lndCert, macaroon } = await this.getCreds()
|
||||
const { ln, pub } = macaroon === "" ? await this.InitFlow(lndCert) : await this.UnlockFlow(lndCert, macaroon)
|
||||
this.subscribeToBackups(ln, pub)
|
||||
}
|
||||
|
||||
UnlockFlow = async (lndCert: Buffer, macaroon: string) => {
|
||||
UnlockFlow = async (lndCert: Buffer, macaroon: string): Promise<{ ln: LightningClient, pub: string, action: 'unlocked' | 'noaction' }> => {
|
||||
const ln = this.GetLightningClient(lndCert, macaroon)
|
||||
const info = await this.GetLndInfo(ln)
|
||||
if (info.ok) {
|
||||
this.log("the wallet is already unlocked with pub:", info.pub)
|
||||
return { ln, pub: info.pub }
|
||||
return { ln, pub: info.pub, action: 'noaction' }
|
||||
}
|
||||
if (info.failure !== 'locked') {
|
||||
throw new Error("failed to get lnd info for reason: " + info.failure)
|
||||
|
|
@ -108,7 +82,7 @@ export class Unlocker {
|
|||
throw new Error("failed to unlock lnd wallet " + infoAfter.failure)
|
||||
}
|
||||
this.log("unlocked wallet with pub:", infoAfter.pub)
|
||||
return { ln, pub: infoAfter.pub }
|
||||
return { ln, pub: infoAfter.pub, action: 'unlocked' }
|
||||
}
|
||||
|
||||
InitFlow = async (lndCert: Buffer) => {
|
||||
|
|
@ -254,6 +228,10 @@ export class Unlocker {
|
|||
}
|
||||
|
||||
subscribeToBackups = async (ln: LightningClient, pub: string) => {
|
||||
if (this.subbedToBackups) {
|
||||
return
|
||||
}
|
||||
this.subbedToBackups = true
|
||||
this.log("subscribing to channel backups for: ", pub)
|
||||
const stream = ln.subscribeChannelBackups({}, { abort: this.abortController.signal })
|
||||
stream.responses.onMessage(async (msg) => {
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ export default class Handler {
|
|||
await p
|
||||
sent = true
|
||||
} catch (e: any) {
|
||||
console.log(e)
|
||||
log(e)
|
||||
}
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -214,6 +214,13 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
|||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.applicationManager.LinkNpubThroughToken(ctx, req)
|
||||
}
|
||||
},
|
||||
EnrollAdminToken: async ({ ctx, req }) => {
|
||||
const err = Types.EnrollAdminTokenRequestValidate(req, {
|
||||
admin_token_CustomCheck: token => token !== ''
|
||||
})
|
||||
if (err != null) throw new Error(err.message)
|
||||
return mainHandler.adminManager.PromoteUserToAdmin(ctx.app_id, ctx.app_user_id, req.admin_token)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import * as WizardTypes from "../../../proto/wizard_service/autogenerated/ts/typ
|
|||
import { MainSettings } from "../main/settings.js"
|
||||
import Storage from '../storage/index.js'
|
||||
import { Unlocker } from "../main/unlocker.js"
|
||||
import { AdminManager } from '../main/adminManager.js';
|
||||
export type WizardSettings = {
|
||||
sourceName: string
|
||||
relayUrl: string
|
||||
|
|
@ -17,31 +18,92 @@ const defaultProviderPub = ""
|
|||
export class Wizard {
|
||||
log = getLogger({ component: "wizard" })
|
||||
settings: MainSettings
|
||||
unlocker: Unlocker
|
||||
initialized = false
|
||||
adminManager: AdminManager
|
||||
storage: Storage
|
||||
configQueue: { res: (reload: boolean) => void }[] = []
|
||||
pendingConfig: WizardSettings | null = null
|
||||
constructor(mainSettings: MainSettings, storage: Storage) {
|
||||
awaitingNprofile: { res: (nprofile: string) => void }[] = []
|
||||
nprofile = ""
|
||||
relays: string[] = []
|
||||
constructor(mainSettings: MainSettings, storage: Storage, adminManager: AdminManager) {
|
||||
this.settings = mainSettings
|
||||
this.adminManager = adminManager
|
||||
this.storage = storage
|
||||
this.log('Starting wizard...')
|
||||
this.unlocker = new Unlocker(mainSettings, storage)
|
||||
const wizardServer = NewWizardServer({
|
||||
WizardState: async () => { return { already_initialized: await this.IsInitialized() } },
|
||||
WizardState: async () => { return this.WizardState() },
|
||||
WizardConfig: async ({ req }) => { return this.wizardConfig(req) },
|
||||
WizardConfirm: async ({ req }) => { return this.wizardConfirm(req) },
|
||||
GetAdminConnectInfo: async () => { return this.GetAdminConnectInfo() },
|
||||
GetServiceState: async () => { return this.GetServiceState() }
|
||||
}, { GuestAuthGuard: async () => "", metricsCallback: () => { }, staticFiles: 'static' })
|
||||
wizardServer.Listen(mainSettings.servicePort + 1)
|
||||
}
|
||||
|
||||
IsInitialized = () => {
|
||||
if (this.initialized) {
|
||||
return true
|
||||
GetServiceState = async (): Promise<WizardTypes.ServiceStateResponse> => {
|
||||
const apps = await this.storage.applicationStorage.GetApplications()
|
||||
const appNamesList = apps.map(app => app.name).join(', ')
|
||||
return {
|
||||
admin_npub: this.adminManager.GetAdminNpub(),
|
||||
http_url: this.settings.serviceUrl,
|
||||
lnd_state: WizardTypes.LndState.OFFLINE,
|
||||
nprofile: this.nprofile,
|
||||
provider_name: appNamesList,
|
||||
relay_connected: false,
|
||||
relays: this.relays,
|
||||
watchdog_ok: false
|
||||
}
|
||||
return this.unlocker.IsInitialized()
|
||||
}
|
||||
WizardState = async (): Promise<WizardTypes.StateResponse> => {
|
||||
return {
|
||||
config_sent: this.pendingConfig !== null,
|
||||
admin_linked: this.adminManager.GetAdminNpub() !== "",
|
||||
}
|
||||
}
|
||||
IsInitialized = () => {
|
||||
return !!this.adminManager.GetAdminNpub()
|
||||
}
|
||||
|
||||
WaitUntilConfigured = async (): Promise<boolean> => {
|
||||
if (this.initialized) {
|
||||
GetAdminConnectInfo = async (): Promise<WizardTypes.AdminConnectInfoResponse> => {
|
||||
const nprofile = await this.getNprofile()
|
||||
const enrolledAdmin = this.adminManager.GetAdminNpub()
|
||||
if (enrolledAdmin !== "") {
|
||||
return {
|
||||
nprofile, connect_info: {
|
||||
type: WizardTypes.AdminConnectInfoResponse_connect_info_type.ENROLLED_NPUB,
|
||||
enrolled_npub: enrolledAdmin
|
||||
}
|
||||
}
|
||||
}
|
||||
const adminEnroll = this.adminManager.ReadAdminEnrollToken()
|
||||
if (adminEnroll !== "") {
|
||||
return {
|
||||
nprofile, connect_info: {
|
||||
type: WizardTypes.AdminConnectInfoResponse_connect_info_type.ADMIN_TOKEN,
|
||||
admin_token: adminEnroll
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error("something went wrong initializing admin creds")
|
||||
}
|
||||
|
||||
getNprofile = async (): Promise<string> => {
|
||||
if (this.nprofile !== "") {
|
||||
return this.nprofile
|
||||
}
|
||||
console.log("waiting for nprofile")
|
||||
return new Promise((res) => {
|
||||
this.awaitingNprofile.push({ res })
|
||||
})
|
||||
}
|
||||
|
||||
AddConnectInfo = (nprofile: string, relays: string[]) => {
|
||||
this.nprofile = nprofile
|
||||
this.awaitingNprofile.forEach(q => q.res(nprofile))
|
||||
this.awaitingNprofile = []
|
||||
}
|
||||
|
||||
Configure = async (): Promise<boolean> => {
|
||||
if (this.IsInitialized() || this.pendingConfig !== null) {
|
||||
return false
|
||||
}
|
||||
return new Promise((res) => {
|
||||
|
|
@ -49,80 +111,58 @@ export class Wizard {
|
|||
})
|
||||
}
|
||||
|
||||
wizardConfig = async (req: WizardTypes.ConfigRequest): Promise<WizardTypes.ConfigResponse> => {
|
||||
wizardConfig = async (req: WizardTypes.ConfigRequest): Promise<void> => {
|
||||
const err = WizardTypes.ConfigRequestValidate(req, {
|
||||
source_name_CustomCheck: source => source !== '',
|
||||
relay_url_CustomCheck: relay => relay !== '',
|
||||
})
|
||||
if (err != null) { throw new Error(err.message) }
|
||||
|
||||
const res = await this.unlocker.InitInteractive()
|
||||
if (res.alreadyInitizialized) {
|
||||
this.initialized = true
|
||||
this.configQueue.forEach(q => q.res(false))
|
||||
return { already_initialized: true, confirmation_id: "", seed: [] }
|
||||
if (this.IsInitialized() || this.pendingConfig !== null) {
|
||||
throw new Error("already initialized")
|
||||
}
|
||||
this.pendingConfig = { sourceName: req.source_name, relayUrl: req.relay_url, automateLiquidity: req.automate_liquidity, pushBackupsToNostr: req.push_backups_to_nostr }
|
||||
return { already_initialized: false, confirmation_id: res.confirmationId, seed: res.seed }
|
||||
|
||||
}
|
||||
|
||||
wizardConfirm = async (req: WizardTypes.ConfirmRequest): Promise<WizardTypes.ConfirmResponse> => {
|
||||
const err = WizardTypes.ConfirmRequestValidate(req, {
|
||||
confirmation_id_CustomCheck: conf => conf !== '',
|
||||
})
|
||||
if (err != null) { throw new Error(err.message) }
|
||||
|
||||
const res = await this.unlocker.ConfirmInitInteractive(req.confirmation_id)
|
||||
if (res?.alreadyInitizialized) {
|
||||
this.initialized = true
|
||||
this.configQueue.forEach(q => q.res(false))
|
||||
return { admin_key: "" }
|
||||
}
|
||||
this.initialized = true
|
||||
this.updateEnvFile()
|
||||
const pendingConfig = { sourceName: req.source_name, relayUrl: req.relay_url, automateLiquidity: req.automate_liquidity, pushBackupsToNostr: req.push_backups_to_nostr }
|
||||
this.updateEnvFile(pendingConfig)
|
||||
this.configQueue.forEach(q => q.res(true))
|
||||
return { admin_key: process.env.ADMIN_TOKEN || "" }
|
||||
this.configQueue = []
|
||||
return
|
||||
}
|
||||
|
||||
updateEnvFile = () => {
|
||||
if (!this.pendingConfig) {
|
||||
return
|
||||
}
|
||||
updateEnvFile = (pendingConfig: WizardSettings) => {
|
||||
let envFileContent: string[] = []
|
||||
try {
|
||||
envFileContent = fs.readFileSync('.env', 'utf-8').split('\n')
|
||||
} catch (err: any) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
const toMerge: string[] = []
|
||||
const sourceNameIndex = envFileContent.findIndex(line => line.startsWith('DEFAULT_APP_NAME'))
|
||||
if (sourceNameIndex === -1) {
|
||||
toMerge.push(`DEFAULT_APP_NAME=${this.pendingConfig.sourceName}`)
|
||||
toMerge.push(`DEFAULT_APP_NAME=${pendingConfig.sourceName}`)
|
||||
} else {
|
||||
envFileContent[sourceNameIndex] = `DEFAULT_APP_NAME=${this.pendingConfig.sourceName}`
|
||||
envFileContent[sourceNameIndex] = `DEFAULT_APP_NAME=${pendingConfig.sourceName}`
|
||||
}
|
||||
const relayUrlIndex = envFileContent.findIndex(line => line.startsWith('RELAY_URL'))
|
||||
if (relayUrlIndex === -1) {
|
||||
toMerge.push(`RELAY_URL=${this.pendingConfig.relayUrl}`)
|
||||
toMerge.push(`RELAY_URL=${pendingConfig.relayUrl}`)
|
||||
} else {
|
||||
envFileContent[relayUrlIndex] = `RELAY_URL=${this.pendingConfig.relayUrl}`
|
||||
envFileContent[relayUrlIndex] = `RELAY_URL=${pendingConfig.relayUrl}`
|
||||
}
|
||||
|
||||
const automateLiquidityIndex = envFileContent.findIndex(line => line.startsWith('LIQUIDITY_PROVIDER_PUB'))
|
||||
if (automateLiquidityIndex === -1) {
|
||||
toMerge.push(`LIQUIDITY_PROVIDER_PUB=${this.pendingConfig.automateLiquidity ? defaultProviderPub : ""}`)
|
||||
toMerge.push(`LIQUIDITY_PROVIDER_PUB=${pendingConfig.automateLiquidity ? defaultProviderPub : ""}`)
|
||||
} else {
|
||||
envFileContent[automateLiquidityIndex] = `LIQUIDITY_PROVIDER_PUB=`
|
||||
}
|
||||
|
||||
const pushBackupsToNostrIndex = envFileContent.findIndex(line => line.startsWith('PUSH_BACKUPS_TO_NOSTR'))
|
||||
if (pushBackupsToNostrIndex === -1) {
|
||||
toMerge.push(`PUSH_BACKUPS_TO_NOSTR=${this.pendingConfig.pushBackupsToNostr ? 'true' : 'false'}`)
|
||||
toMerge.push(`PUSH_BACKUPS_TO_NOSTR=${pendingConfig.pushBackupsToNostr ? 'true' : 'false'}`)
|
||||
} else {
|
||||
envFileContent[pushBackupsToNostrIndex] = `PUSH_BACKUPS_TO_NOSTR=${this.pendingConfig.pushBackupsToNostr ? 'true' : 'false'}`
|
||||
envFileContent[pushBackupsToNostrIndex] = `PUSH_BACKUPS_TO_NOSTR=${pendingConfig.pushBackupsToNostr ? 'true' : 'false'}`
|
||||
}
|
||||
const merged = [...envFileContent, ...toMerge].join('\n')
|
||||
fs.writeFileSync('.env', merged)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,31 @@
|
|||
|
||||
<script src="js/backup.js"></script>
|
||||
<script>
|
||||
const sendConfig = async () => {
|
||||
const req = {
|
||||
source_name: localStorage.getItem("wizard/nodeName"),
|
||||
relay_url: localStorage.getItem("wizard/relayUrl"),
|
||||
automate_liquidity: localStorage.getItem("wizard/liquidity") === 'automate',
|
||||
push_backups_to_nostr: localStorage.getItem("wizard/backup") === 'backup',
|
||||
}
|
||||
const res = await fetch("/wizard/config", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(req)
|
||||
})
|
||||
if (res.status !== 200) {
|
||||
document.getElementById('errorText').innerText = "failed to start service"
|
||||
return
|
||||
}
|
||||
const j = await res.json()
|
||||
if (j.status !== 'OK') {
|
||||
document.getElementById('errorText').innerText = "failed to start service" + j.reason
|
||||
return
|
||||
}
|
||||
location.href = 'connect.html'
|
||||
}
|
||||
document.getElementById("next-button").onclick = (e) => {
|
||||
const backup = document.getElementById('backup').checked
|
||||
const manual = document.getElementById('manual-backup').checked
|
||||
|
|
@ -109,7 +134,7 @@
|
|||
} else {
|
||||
localStorage.setItem('wizard/backup', 'manual')
|
||||
}
|
||||
location.href = 'seed.html'
|
||||
sendConfig()
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,80 +1,116 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title></title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat"
|
||||
/>
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/connect.css" />
|
||||
<!-- HTML Meta Tags -->
|
||||
<title>Lightning.Pub</title>
|
||||
<meta name="description" content="Lightning for Everyone" />
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<img
|
||||
src="img/pub_logo.png"
|
||||
width="38px"
|
||||
height="auto"
|
||||
alt="Lightning Pub logo"
|
||||
/>
|
||||
<img src="img/LightningPub.png" height="33px" alt="Lightning Pub logo" />
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="setup-header">
|
||||
<button class="icon-button back-button" onclick="history.back()">
|
||||
<img src="img/back.svg" alt="" />
|
||||
</button>
|
||||
<h2>Connect</h2>
|
||||
<p class="header-title">
|
||||
You can now manage your node remotely
|
||||
</p>
|
||||
</section>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title></title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat" />
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/connect.css" />
|
||||
<!-- HTML Meta Tags -->
|
||||
<title>Lightning.Pub</title>
|
||||
<meta name="description" content="Lightning for Everyone" />
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<div class="line"></div>
|
||||
<body>
|
||||
<header>
|
||||
<img src="img/pub_logo.png" width="38px" height="auto" alt="Lightning Pub logo" />
|
||||
<img src="img/LightningPub.png" height="33px" alt="Lightning Pub logo" />
|
||||
</header>
|
||||
|
||||
<section class="setup-content">
|
||||
<div>For dashboard access, use <a href="https://preview.uxpin.com/ae6e6372ab26cd13438d486d4d1ac9d184ec8e82#/pages/164889267" style="color: #2aabe9;" target="_blank">ShockWallet</a> and tap the logo 3 times.</div>
|
||||
<div style="font-size: 13px; margin-top: 5px;">Scan the QR or Copy-Paste the string to establish the connection.</div>
|
||||
<div style="display: flex; justify-content: center;">
|
||||
<div class="qrcode-box" id="codebox">
|
||||
<div style="font-size: 11px;">
|
||||
<div style="text-align: center; color: #a3a3a3;">Code contains a one-time pairing secret</div>
|
||||
<div style="text-align: center; color: #c434e0;" id="click-text">Click to reveal</div>
|
||||
</div>
|
||||
<div id="qrcode"></div>
|
||||
<div style="color: #a3a3a3; font-size: 11px;">
|
||||
<div>npub123abcdefghhhhhhhhhhhhhhh</div>
|
||||
<div>relay.lightning.pub</div>
|
||||
</div>
|
||||
<main>
|
||||
<section class="setup-header">
|
||||
<button class="icon-button back-button" onclick="history.back()">
|
||||
<img src="img/back.svg" alt="" />
|
||||
</button>
|
||||
<h2>Connect</h2>
|
||||
<p class="header-title">
|
||||
You can now manage your node remotely
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<div class="line"></div>
|
||||
|
||||
<section class="setup-content">
|
||||
<div>For dashboard access, use <a
|
||||
href="https://preview.uxpin.com/ae6e6372ab26cd13438d486d4d1ac9d184ec8e82#/pages/164889267"
|
||||
style="color: #2aabe9;" target="_blank">ShockWallet</a> and tap the logo 3 times.</div>
|
||||
<div style="font-size: 13px; margin-top: 5px;">Scan the QR or Copy-Paste the string to establish the connection.
|
||||
</div>
|
||||
<div style="display: flex; justify-content: center;">
|
||||
<div class="qrcode-box" id="codebox">
|
||||
<div style="font-size: 11px;">
|
||||
<div style="text-align: center; color: #a3a3a3;">Code contains a one-time pairing secret</div>
|
||||
<div style="text-align: center; color: #c434e0;" id="click-text">Click to reveal</div>
|
||||
</div>
|
||||
<div id="qrcode"></div>
|
||||
<div style="color: #a3a3a3; font-size: 11px;">
|
||||
<div id="connectString"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="footer-text">
|
||||
<div>By proceeding you acknowledge that this is</div>
|
||||
<div>bleeding-edge software, and agree to the providers</div>
|
||||
<div>
|
||||
<span style="color: #c434e0">terms</span> regarding any services
|
||||
herein.
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<a href="https://docs.shock.network" class="marked need-help">Need Help?</a>
|
||||
</footer>
|
||||
</section>
|
||||
</main>
|
||||
<p class="errorText" style="color:red"></p>
|
||||
<footer>
|
||||
<div class="footer-text">
|
||||
<div>By proceeding you acknowledge that this is</div>
|
||||
<div>bleeding-edge software, and agree to the providers</div>
|
||||
<div>
|
||||
<span style="color: #c434e0">terms</span> regarding any services
|
||||
herein.
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<a href="https://docs.shock.network" class="marked need-help">Need Help?</a>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
|
||||
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
|
||||
|
||||
<script src="js/connect.js"></script>
|
||||
<script>
|
||||
const fetchInfo = async () => {
|
||||
console.log("fewtching...")
|
||||
const res = await fetch("/wizard/admin_connect_info")
|
||||
console.log(res)
|
||||
if (res.status !== 200) {
|
||||
document.getElementById('errorText').innerText = "failed to get connection info"
|
||||
return
|
||||
}
|
||||
const j = await res.json()
|
||||
console.log(j)
|
||||
if (j.status !== 'OK') {
|
||||
document.getElementById('errorText').innerText = "failed to get connection info" + j.reason
|
||||
return
|
||||
}
|
||||
if (j.connect_info.enrolled_npub) {
|
||||
location.href = 'status.html'
|
||||
} else {
|
||||
const connectString = j.nprofile + ":" + j.connect_info.admin_token
|
||||
console.log({ connectString })
|
||||
const qrElement = document.getElementById("qrcode")
|
||||
qrElement.onclick = () => {
|
||||
document.navigator.clipboard.writeText(connectString)
|
||||
}
|
||||
const qrcode = new QRCode(qrElement, {
|
||||
text: connectString,
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
width: 157,
|
||||
height: 157,
|
||||
// correctLevel : QRCode.CorrectLevel.H
|
||||
});
|
||||
document.getElementById('connectString').innerHTML = connectString
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
||||
fetchInfo()
|
||||
} catch (e) { console.log({ e }) }
|
||||
</script>
|
||||
</body>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
<script src="js/connect.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -96,9 +96,10 @@
|
|||
fetch("/wizard/state").then((res) => {
|
||||
if (res.status === 200) {
|
||||
res.json().then((data) => {
|
||||
if (data.already_initialized) {
|
||||
if (data.admin_linked) {
|
||||
location.href = 'status.html'
|
||||
console.log("already init")
|
||||
} else if (data.config_sent) {
|
||||
location.href = 'connect.html'
|
||||
} else {
|
||||
console.log("ready to initialize")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,60 +69,6 @@
|
|||
</footer>
|
||||
|
||||
<script src="js/seed.js"></script>
|
||||
<script>
|
||||
let latestConfirmationId = ""
|
||||
document.getElementById("next-button").onclick = (e) => {
|
||||
if (!latestConfirmationId) {
|
||||
return
|
||||
}
|
||||
fetch("/wizard/confirm", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
confirmation_id: latestConfirmationId,
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
location.href = 'connect.html'
|
||||
}
|
||||
})
|
||||
}
|
||||
fetch("/wizard/config", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
source_name: localStorage.getItem("wizard/nodeName"),
|
||||
relay_url: localStorage.getItem("wizard/relayUrl"),
|
||||
automate_liquidity: localStorage.getItem("wizard/liquidity") === 'automate',
|
||||
push_backups_to_nostr: localStorage.getItem("wizard/backup") === 'backup',
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
res.json().then((data) => {
|
||||
if (data.already_initialized) {
|
||||
location.href = 'status.html'
|
||||
return
|
||||
}
|
||||
const seedContainer = document.getElementById("seed-box-container")
|
||||
latestConfirmationId = data.confirmation_id
|
||||
console.log(latestConfirmationId)
|
||||
data.seed.forEach((word, index) => {
|
||||
const seedBox = document.createElement('div')
|
||||
seedBox.classList.add('seed-box')
|
||||
seedBox.innerHTML = `
|
||||
<span>${index + 1}</span>
|
||||
<span>${word}</span>
|
||||
`
|
||||
seedContainer.appendChild(seedBox)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
<div class="line" style="width: 100%;"></div>
|
||||
|
||||
<section class="node-status">
|
||||
<p id="errorText" style="color:red"></p>
|
||||
<div>
|
||||
<div class="status-element" style="margin-top: 15px;">
|
||||
<div style="text-align: left;">Public Node Name:</div>
|
||||
|
|
@ -69,8 +70,8 @@
|
|||
</div>
|
||||
<div class="status-element" style="margin-top: 15px;">
|
||||
<div>Administrator:</div>
|
||||
<div>
|
||||
npub12334556677889990
|
||||
<div id="adminNpub" style="line-break: anywhere;">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -99,14 +100,14 @@
|
|||
<div style="margin-top: 40px;">
|
||||
<div class="status-element">
|
||||
<div>Relay Status:</div>
|
||||
<div>
|
||||
<span class="green-dot">●</span> Connected
|
||||
<div id="relayStatus">
|
||||
<span class="yellow-dot">●</span> Loading...
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-element">
|
||||
<div>Lightning Status:</div>
|
||||
<div>
|
||||
<span class="yellow-dot">●</span> Syncing
|
||||
<div id="lndStatus">
|
||||
<span class="yellow-dot">●</span> Loading...
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-element">
|
||||
|
|
@ -118,15 +119,15 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="green-dot">●</span> No Alarms
|
||||
<div id="watchdog-status">
|
||||
<span class="green-dot">●</span> Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 20px;">
|
||||
<div style="font-size: 13px; text-align: left;">Guest Invitation Link:</div>
|
||||
<a href="https://my.shockwallet.app/invite/nprofile12345678899988" target="_blank" style="font-size: 11px;"
|
||||
class="invite-link">
|
||||
<a href="https://my.shockwallet.app/invite/nprofile12345678899988" target="_blank"
|
||||
style="font-size: 11px;line-break: anywhere;" id="inviteLinkHttp" class="invite-link">
|
||||
https://my.shockwallet.app/invite/nprofile12345678899988
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -140,6 +141,34 @@
|
|||
</footer>
|
||||
|
||||
<script src="js/status.js"></script>
|
||||
<script>
|
||||
const fetchInfo = async () => {
|
||||
console.log("fewtching...")
|
||||
const res = await fetch("/wizard/service_state")
|
||||
console.log(res)
|
||||
if (res.status !== 200) {
|
||||
document.getElementById('errorText').innerText = "failed to get state info"
|
||||
return
|
||||
}
|
||||
const j = await res.json()
|
||||
console.log(j)
|
||||
if (j.status !== 'OK') {
|
||||
document.getElementById('errorText').innerText = "failed to get state info" + j.reason
|
||||
return
|
||||
}
|
||||
document.getElementById("show-nodey-text").innerHTML = j.provider_name
|
||||
document.getElementById("show-nostr-text").innerHTML = j.relays[0]
|
||||
document.getElementById("adminNpub").innerText = j.admin_npub
|
||||
document.getElementById("relayStatus").innerHTML = `<span class="${j.relay_connected ? 'green-dot' : 'red-dot'}">●</span> ${j.relay_connected ? 'Connected' : 'Disconnected'}`
|
||||
document.getElementById("lndStatus").innerHTML = `<span class="${j.lnd_state === 'ONLINE' ? 'green-dot' : 'red-dot'}">●</span> ${j.lnd_state}`
|
||||
document.getElementById("watchdog-status").innerHTML = `<span class="${j.watchdog_ok ? 'green-dot' : 'red-dot'}">●</span> ${j.watchdog_ok ? 'No Alerts' : 'ALERT!!'}`
|
||||
document.getElementById("inviteLinkHttp").href = `https://my.shockwallet.app/invite/${j.nprofile}`
|
||||
document.getElementById("inviteLinkHttp").innerHTML = `https://my.shockwallet.app/invite/${j.nprofile}`
|
||||
}
|
||||
try {
|
||||
fetchInfo()
|
||||
} catch (e) { console.log({ e }) }
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue