Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix linking #767

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions proto/autogenerated/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@ The nostr server will send back a message response, and inside the body there wi
- This methods has an __empty__ __request__ body
- output: [MigrationUpdate](#MigrationUpdate)

- GetNPubLinkingState
- auth type: __App__
- http method: __post__
- http route: __/api/app/user/npub/token__
- input: [GetNPubLinking](#GetNPubLinking)
- output: [NPubLinking](#NPubLinking)

- GetPaymentState
- auth type: __User__
- http method: __post__
Expand Down Expand Up @@ -862,6 +869,9 @@ The nostr server will send back a message response, and inside the body there wi
### GetInviteTokenStateResponse
- __used__: _boolean_

### GetNPubLinking
- __user_identifier__: _string_

### GetPaymentStateRequest
- __invoice__: _string_

Expand Down Expand Up @@ -967,6 +977,9 @@ The nostr server will send back a message response, and inside the body there wi
- __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional
- __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional

### NPubLinking
- __state__: _[NPubLinking_state](#NPubLinking_state)_

### NewAddressRequest
- __addressType__: _[AddressType](#AddressType)_

Expand Down
30 changes: 30 additions & 0 deletions proto/autogenerated/go/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type Client struct {
GetLnurlWithdrawInfo func(query GetLnurlWithdrawInfo_Query) (*LnurlWithdrawInfoResponse, error)
GetLnurlWithdrawLink func() (*LnurlLinkResponse, error)
GetMigrationUpdate func() (*MigrationUpdate, error)
GetNPubLinkingState func(req GetNPubLinking) (*NPubLinking, error)
GetPaymentState func(req GetPaymentStateRequest) (*PaymentState, error)
GetSeed func() (*LndSeed, error)
GetUsageMetrics func() (*UsageMetrics, error)
Expand Down Expand Up @@ -834,6 +835,35 @@ func NewClient(params ClientParams) *Client {
return &res, nil
},
// server streaming method: GetMigrationUpdate not implemented
GetNPubLinkingState: func(req GetNPubLinking) (*NPubLinking, error) {
auth, err := params.RetrieveAppAuth()
if err != nil {
return nil, err
}
finalRoute := "/api/app/user/npub/token"
body, err := json.Marshal(req)
if err != nil {
return nil, err
}
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
if err != nil {
return nil, err
}
result := ResultError{}
err = json.Unmarshal(resBody, &result)
if err != nil {
return nil, err
}
if result.Status == "ERROR" {
return nil, fmt.Errorf(result.Reason)
}
res := NPubLinking{}
err = json.Unmarshal(resBody, &res)
if err != nil {
return nil, err
}
return &res, nil
},
GetPaymentState: func(req GetPaymentStateRequest) (*PaymentState, error) {
auth, err := params.RetrieveUserAuth()
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions proto/autogenerated/go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ type GetInviteTokenStateRequest struct {
type GetInviteTokenStateResponse struct {
Used bool `json:"used"`
}
type GetNPubLinking struct {
User_identifier string `json:"user_identifier"`
}
type GetPaymentStateRequest struct {
Invoice string `json:"invoice"`
}
Expand Down Expand Up @@ -333,6 +336,9 @@ type MigrationUpdate struct {
Closure *ClosureMigration `json:"closure"`
Relays *RelaysMigration `json:"relays"`
}
type NPubLinking struct {
State *NPubLinking_state `json:"state"`
}
type NewAddressRequest struct {
Addresstype AddressType `json:"addressType"`
}
Expand Down Expand Up @@ -542,3 +548,17 @@ type LiveDebitRequest_debit struct {
Full_access *Empty `json:"full_access"`
Invoice *string `json:"invoice"`
}
type NPubLinking_state_type string

const (
LINKED_NPUB NPubLinking_state_type = "linked_npub"
LINKING_TOKEN NPubLinking_state_type = "linking_token"
UNLINKED NPubLinking_state_type = "unlinked"
)

type NPubLinking_state struct {
Type NPubLinking_state_type `json:"type"`
Linked_npub *string `json:"linked_npub"`
Linking_token *string `json:"linking_token"`
Unlinked *Empty `json:"unlinked"`
}
22 changes: 22 additions & 0 deletions proto/autogenerated/ts/express_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,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.GetNPubLinkingState) throw new Error('method: GetNPubLinkingState is not implemented')
app.post('/api/app/user/npub/token', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetNPubLinkingState', 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.GetNPubLinkingState) throw new Error('method: GetNPubLinkingState is not implemented')
const authContext = await opts.AppAuthGuard(req.headers['authorization'])
authCtx = authContext
stats.guard = process.hrtime.bigint()
const request = req.body
const error = Types.GetNPubLinkingValidate(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
const response = await methods.GetNPubLinkingState({rpcName:'GetNPubLinkingState', ctx:authContext , req: request})
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.GetPaymentState) throw new Error('method: GetPaymentState is not implemented')
app.post('/api/user/payment/state', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetPaymentState', batch: false, nostr: false, batchSize: 0}
Expand Down
14 changes: 14 additions & 0 deletions proto/autogenerated/ts/http_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,20 @@ export default (params: ClientParams) => ({
return { status: 'ERROR', reason: 'invalid response' }
},
GetMigrationUpdate: async (cb: (v:ResultError | ({ status: 'OK' }& Types.MigrationUpdate)) => void): Promise<void> => { throw new Error('http streams are not supported')},
GetNPubLinkingState: async (request: Types.GetNPubLinking): Promise<ResultError | ({ status: 'OK' }& Types.NPubLinking)> => {
const auth = await params.retrieveAppAuth()
if (auth === null) throw new Error('retrieveAppAuth() returned null')
let finalRoute = '/api/app/user/npub/token'
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.NPubLinkingValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetPaymentState: async (request: Types.GetPaymentStateRequest): Promise<ResultError | ({ status: 'OK' }& Types.PaymentState)> => {
const auth = await params.retrieveUserAuth()
if (auth === null) throw new Error('retrieveUserAuth() returned null')
Expand Down
89 changes: 87 additions & 2 deletions proto/autogenerated/ts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export type AdminMethodOutputs = AddApp_Output | AuthApp_Output | BanUser_Output
export type AppContext = {
app_id: string
}
export type AppMethodInputs = AddAppInvoice_Input | AddAppUser_Input | AddAppUserInvoice_Input | GetApp_Input | GetAppUser_Input | GetAppUserLNURLInfo_Input | PayAppUserInvoice_Input | RequestNPubLinkingToken_Input | ResetNPubLinkingToken_Input | SendAppUserToAppPayment_Input | SendAppUserToAppUserPayment_Input | SetMockAppBalance_Input | SetMockAppUserBalance_Input
export type AppMethodOutputs = AddAppInvoice_Output | AddAppUser_Output | AddAppUserInvoice_Output | GetApp_Output | GetAppUser_Output | GetAppUserLNURLInfo_Output | PayAppUserInvoice_Output | RequestNPubLinkingToken_Output | ResetNPubLinkingToken_Output | SendAppUserToAppPayment_Output | SendAppUserToAppUserPayment_Output | SetMockAppBalance_Output | SetMockAppUserBalance_Output
export type AppMethodInputs = AddAppInvoice_Input | AddAppUser_Input | AddAppUserInvoice_Input | GetApp_Input | GetAppUser_Input | GetAppUserLNURLInfo_Input | GetNPubLinkingState_Input | PayAppUserInvoice_Input | RequestNPubLinkingToken_Input | ResetNPubLinkingToken_Input | SendAppUserToAppPayment_Input | SendAppUserToAppUserPayment_Input | SetMockAppBalance_Input | SetMockAppUserBalance_Input
export type AppMethodOutputs = AddAppInvoice_Output | AddAppUser_Output | AddAppUserInvoice_Output | GetApp_Output | GetAppUser_Output | GetAppUserLNURLInfo_Output | GetNPubLinkingState_Output | PayAppUserInvoice_Output | RequestNPubLinkingToken_Output | ResetNPubLinkingToken_Output | SendAppUserToAppPayment_Output | SendAppUserToAppUserPayment_Output | SetMockAppBalance_Output | SetMockAppUserBalance_Output
export type GuestContext = {
}
export type GuestMethodInputs = EncryptionExchange_Input | GetLnurlPayInfo_Input | GetLnurlWithdrawInfo_Input | HandleLnurlAddress_Input | HandleLnurlPay_Input | HandleLnurlWithdraw_Input | Health_Input | SetMockInvoiceAsPaid_Input
Expand Down Expand Up @@ -137,6 +137,9 @@ export type GetLnurlWithdrawLink_Output = ResultError | ({ status: 'OK' } & Lnur
export type GetMigrationUpdate_Input = {rpcName:'GetMigrationUpdate', cb:(res: MigrationUpdate, err:Error|null)=> void}
export type GetMigrationUpdate_Output = ResultError | { status: 'OK' }

export type GetNPubLinkingState_Input = {rpcName:'GetNPubLinkingState', req: GetNPubLinking}
export type GetNPubLinkingState_Output = ResultError | ({ status: 'OK' } & NPubLinking)

export type GetPaymentState_Input = {rpcName:'GetPaymentState', req: GetPaymentStateRequest}
export type GetPaymentState_Output = ResultError | ({ status: 'OK' } & PaymentState)

Expand Down Expand Up @@ -277,6 +280,7 @@ export type ServerMethods = {
GetLnurlWithdrawInfo?: (req: GetLnurlWithdrawInfo_Input & {ctx: GuestContext }) => Promise<LnurlWithdrawInfoResponse>
GetLnurlWithdrawLink?: (req: GetLnurlWithdrawLink_Input & {ctx: UserContext }) => Promise<LnurlLinkResponse>
GetMigrationUpdate?: (req: GetMigrationUpdate_Input & {ctx: UserContext }) => Promise<void>
GetNPubLinkingState?: (req: GetNPubLinkingState_Input & {ctx: AppContext }) => Promise<NPubLinking>
GetPaymentState?: (req: GetPaymentState_Input & {ctx: UserContext }) => Promise<PaymentState>
GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise<LndSeed>
GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetrics>
Expand Down Expand Up @@ -1263,6 +1267,24 @@ export const GetInviteTokenStateResponseValidate = (o?: GetInviteTokenStateRespo
return null
}

export type GetNPubLinking = {
user_identifier: string
}
export const GetNPubLinkingOptionalFields: [] = []
export type GetNPubLinkingOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
user_identifier_CustomCheck?: (v: string) => boolean
}
export const GetNPubLinkingValidate = (o?: GetNPubLinking, opts: GetNPubLinkingOptions = {}, path: string = 'GetNPubLinking::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.user_identifier !== 'string') return new Error(`${path}.user_identifier: is not a string`)
if (opts.user_identifier_CustomCheck && !opts.user_identifier_CustomCheck(o.user_identifier)) return new Error(`${path}.user_identifier: custom check failed`)

return null
}

export type GetPaymentStateRequest = {
invoice: string
}
Expand Down Expand Up @@ -1910,6 +1932,25 @@ export const MigrationUpdateValidate = (o?: MigrationUpdate, opts: MigrationUpda
return null
}

export type NPubLinking = {
state: NPubLinking_state
}
export const NPubLinkingOptionalFields: [] = []
export type NPubLinkingOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
state_Options?: NPubLinking_stateOptions
}
export const NPubLinkingValidate = (o?: NPubLinking, opts: NPubLinkingOptions = {}, path: string = 'NPubLinking::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')

const stateErr = NPubLinking_stateValidate(o.state, opts.state_Options, `${path}.state`)
if (stateErr !== null) return stateErr


return null
}

export type NewAddressRequest = {
addressType: AddressType
}
Expand Down Expand Up @@ -2982,6 +3023,50 @@ export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
if (opts.invoice_CustomCheck && !opts.invoice_CustomCheck(o.invoice)) return new Error(`${path}.invoice: custom check failed`)

break
default:
return new Error(path + ': unknown type '+ stringType)
}
return null
}
export enum NPubLinking_state_type {
LINKED_NPUB = 'linked_npub',
LINKING_TOKEN = 'linking_token',
UNLINKED = 'unlinked',
}
export const enumCheckNPubLinking_state_type = (e?: NPubLinking_state_type): boolean => {
for (const v in NPubLinking_state_type) if (e === v) return true
return false
}
export type NPubLinking_state =
{type:NPubLinking_state_type.LINKED_NPUB, linked_npub:string}|
{type:NPubLinking_state_type.LINKING_TOKEN, linking_token:string}|
{type:NPubLinking_state_type.UNLINKED, unlinked:Empty}

export type NPubLinking_stateOptions = {
linked_npub_CustomCheck?: (v: string) => boolean
linking_token_CustomCheck?: (v: string) => boolean
unlinked_Options?: EmptyOptions
}
export const NPubLinking_stateValidate = (o?: NPubLinking_state, opts:NPubLinking_stateOptions = {}, path: string = 'NPubLinking_state::root.'): Error | null => {
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
const stringType: string = o.type
switch (o.type) {
case NPubLinking_state_type.LINKED_NPUB:
if (typeof o.linked_npub !== 'string') return new Error(`${path}.linked_npub: is not a string`)
if (opts.linked_npub_CustomCheck && !opts.linked_npub_CustomCheck(o.linked_npub)) return new Error(`${path}.linked_npub: custom check failed`)

break
case NPubLinking_state_type.LINKING_TOKEN:
if (typeof o.linking_token !== 'string') return new Error(`${path}.linking_token: is not a string`)
if (opts.linking_token_CustomCheck && !opts.linking_token_CustomCheck(o.linking_token)) return new Error(`${path}.linking_token: custom check failed`)

break
case NPubLinking_state_type.UNLINKED:
const unlinkedErr = EmptyValidate(o.unlinked, opts.unlinked_Options, `${path}.unlinked`)
if (unlinkedErr !== null) return unlinkedErr


break
default:
return new Error(path + ': unknown type '+ stringType)
Expand Down
9 changes: 7 additions & 2 deletions proto/service/methods.proto
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,19 @@ service LightningPub {
option (http_method) = "post";
option (http_route) = "/api/app/mock/blance/set";
}
rpc GetNPubLinkingState(structs.GetNPubLinking) returns (structs.NPubLinking) {
option (auth_type) = "App";
option (http_method) = "post";
option (http_route) = "/api/app/user/npub/token";
}
rpc RequestNPubLinkingToken(structs.RequestNPubLinkingTokenRequest) returns (structs.RequestNPubLinkingTokenResponse) {
option (auth_type) = "App";
option(http_method) = "post";
option (http_method) = "post";
option (http_route) = "/api/app/user/npub/token";
}
rpc ResetNPubLinkingToken(structs.RequestNPubLinkingTokenRequest) returns (structs.RequestNPubLinkingTokenResponse) {
option (auth_type) = "App";
option(http_method) = "post";
option (http_method) = "post";
option (http_route) = "/api/app/user/npub/token/reset";
}
// </App>
Expand Down
12 changes: 12 additions & 0 deletions proto/service/structs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,18 @@ message RelaysMigration {
repeated string relays = 1;
}

message GetNPubLinking {
string user_identifier = 1;
}

message NPubLinking {
oneof state {
Empty unlinked = 1;
string linked_npub = 2;
string linking_token = 3;
}
}


message RequestNPubLinkingTokenRequest {
string user_identifier = 1;
Expand Down
15 changes: 15 additions & 0 deletions src/services/main/applicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type NsecLinkingData = {
expiry: number
}
export default class {

storage: Storage
settings: MainSettings
paymentManager: PaymentManager
Expand Down Expand Up @@ -242,6 +243,20 @@ export default class {
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
return this.paymentManager.GetLnurlPayInfoFromUser(user.user.user_id, app, { baseUrl: req.base_url_override })
}

async GetNPubLinkingState(app_id: string, req: Types.GetNPubLinking): Promise<Types.NPubLinking> {
const app = await this.storage.applicationStorage.GetApplication(app_id);
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier);
const linking = Object.entries(this.nPubLinkingTokens).find(([_, data]) => data.serialId === user.serial_id)
if (linking) {
return { state: { type: Types.NPubLinking_state_type.LINKING_TOKEN, linking_token: linking[0] } }
}
if (user.nostr_public_key) {
return { state: { type: Types.NPubLinking_state_type.LINKED_NPUB, linked_npub: user.nostr_public_key } }
}
return { state: { type: Types.NPubLinking_state_type.UNLINKED, unlinked: {} } }
}

async RequestNPubLinkingToken(appId: string, req: Types.RequestNPubLinkingTokenRequest, reset: boolean): Promise<Types.RequestNPubLinkingTokenResponse> {
const app = await this.storage.applicationStorage.GetApplication(appId);
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier);
Expand Down
7 changes: 7 additions & 0 deletions src/services/serverMethods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ export default (mainHandler: Main): Types.ServerMethods => {
},
GetMigrationUpdate: async ({ ctx, cb }) => {
},
GetNPubLinkingState: async ({ ctx, req }) => {
const err = Types.GetNPubLinkingValidate(req, {
user_identifier_CustomCheck: userIdentifier => userIdentifier !== '',
})
if (err != null) throw new Error(err.message)
return mainHandler.applicationManager.GetNPubLinkingState(ctx.app_id, req)
},
RequestNPubLinkingToken: async ({ ctx, req }) => {
const err = Types.RequestNPubLinkingTokenRequestValidate(req, {
user_identifier_CustomCheck: userIdentifier => userIdentifier !== '',
Expand Down
Loading