full access, freq+bol11
This commit is contained in:
parent
1049586646
commit
0dd79eecf6
6 changed files with 57 additions and 27 deletions
7
package-lock.json
generated
7
package-lock.json
generated
|
|
@ -32,7 +32,7 @@
|
||||||
"grpc-tools": "^1.12.4",
|
"grpc-tools": "^1.12.4",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "github:shocknet/nostr-tools#ef16463592e2f7b5bf18abc86ff974615d64bb7d",
|
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
@ -3802,8 +3802,9 @@
|
||||||
},
|
},
|
||||||
"node_modules/nostr-tools": {
|
"node_modules/nostr-tools": {
|
||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#ef16463592e2f7b5bf18abc86ff974615d64bb7d",
|
"resolved": "git+ssh://git@github.com/shocknet/nostr-tools.git#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
||||||
"integrity": "sha512-PSBLCTv5ruThR2uS4CRIFgqU6kySxPpDWiqit2Lkc3c1RbTeyhKMr9pRnLSoulkdRZGtDYSTgmoBxvqPkqO8XQ==",
|
"integrity": "sha512-NWYu4yx9UELd4M333r6Eirg0lKK9vyEiUW/8DDorZtxSlBdH4B9FqH8w7VJrG2LfPJABC89EH6+VNLz7RENCfg==",
|
||||||
|
"license": "Unlicense",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/ciphers": "^0.5.1",
|
"@noble/ciphers": "^0.5.1",
|
||||||
"@noble/curves": "1.2.0",
|
"@noble/curves": "1.2.0",
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
"grpc-tools": "^1.12.4",
|
"grpc-tools": "^1.12.4",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nostr-tools": "github:shocknet/nostr-tools#ef16463592e2f7b5bf18abc86ff974615d64bb7d",
|
"nostr-tools": "github:shocknet/nostr-tools#19271c4bcc9ff9bf18f9208e2d9fd6870e5f350c",
|
||||||
"pg": "^8.4.0",
|
"pg": "^8.4.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
|
||||||
|
|
@ -531,12 +531,14 @@ type DebitRule_rule struct {
|
||||||
type LiveDebitRequest_debit_type string
|
type LiveDebitRequest_debit_type string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FREQUENCY LiveDebitRequest_debit_type = "frequency"
|
FREQUENCY LiveDebitRequest_debit_type = "frequency"
|
||||||
INVOICE LiveDebitRequest_debit_type = "invoice"
|
FULL_ACCESS LiveDebitRequest_debit_type = "full_access"
|
||||||
|
INVOICE LiveDebitRequest_debit_type = "invoice"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LiveDebitRequest_debit struct {
|
type LiveDebitRequest_debit struct {
|
||||||
Type LiveDebitRequest_debit_type `json:"type"`
|
Type LiveDebitRequest_debit_type `json:"type"`
|
||||||
Frequency *FrequencyRule `json:"frequency"`
|
Frequency *FrequencyRule `json:"frequency"`
|
||||||
Invoice *string `json:"invoice"`
|
Full_access *Empty `json:"full_access"`
|
||||||
|
Invoice *string `json:"invoice"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2945,6 +2945,7 @@ export const DebitRule_ruleValidate = (o?: DebitRule_rule, opts:DebitRule_ruleOp
|
||||||
}
|
}
|
||||||
export enum LiveDebitRequest_debit_type {
|
export enum LiveDebitRequest_debit_type {
|
||||||
FREQUENCY = 'frequency',
|
FREQUENCY = 'frequency',
|
||||||
|
FULL_ACCESS = 'full_access',
|
||||||
INVOICE = 'invoice',
|
INVOICE = 'invoice',
|
||||||
}
|
}
|
||||||
export const enumCheckLiveDebitRequest_debit_type = (e?: LiveDebitRequest_debit_type): boolean => {
|
export const enumCheckLiveDebitRequest_debit_type = (e?: LiveDebitRequest_debit_type): boolean => {
|
||||||
|
|
@ -2953,10 +2954,12 @@ export const enumCheckLiveDebitRequest_debit_type = (e?: LiveDebitRequest_debit_
|
||||||
}
|
}
|
||||||
export type LiveDebitRequest_debit =
|
export type LiveDebitRequest_debit =
|
||||||
{type:LiveDebitRequest_debit_type.FREQUENCY, frequency:FrequencyRule}|
|
{type:LiveDebitRequest_debit_type.FREQUENCY, frequency:FrequencyRule}|
|
||||||
|
{type:LiveDebitRequest_debit_type.FULL_ACCESS, full_access:Empty}|
|
||||||
{type:LiveDebitRequest_debit_type.INVOICE, invoice:string}
|
{type:LiveDebitRequest_debit_type.INVOICE, invoice:string}
|
||||||
|
|
||||||
export type LiveDebitRequest_debitOptions = {
|
export type LiveDebitRequest_debitOptions = {
|
||||||
frequency_Options?: FrequencyRuleOptions
|
frequency_Options?: FrequencyRuleOptions
|
||||||
|
full_access_Options?: EmptyOptions
|
||||||
invoice_CustomCheck?: (v: string) => boolean
|
invoice_CustomCheck?: (v: string) => boolean
|
||||||
}
|
}
|
||||||
export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:LiveDebitRequest_debitOptions = {}, path: string = 'LiveDebitRequest_debit::root.'): Error | null => {
|
export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:LiveDebitRequest_debitOptions = {}, path: string = 'LiveDebitRequest_debit::root.'): Error | null => {
|
||||||
|
|
@ -2968,6 +2971,12 @@ export const LiveDebitRequest_debitValidate = (o?: LiveDebitRequest_debit, opts:
|
||||||
if (frequencyErr !== null) return frequencyErr
|
if (frequencyErr !== null) return frequencyErr
|
||||||
|
|
||||||
|
|
||||||
|
break
|
||||||
|
case LiveDebitRequest_debit_type.FULL_ACCESS:
|
||||||
|
const full_accessErr = EmptyValidate(o.full_access, opts.full_access_Options, `${path}.full_access`)
|
||||||
|
if (full_accessErr !== null) return full_accessErr
|
||||||
|
|
||||||
|
|
||||||
break
|
break
|
||||||
case LiveDebitRequest_debit_type.INVOICE:
|
case LiveDebitRequest_debit_type.INVOICE:
|
||||||
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
if (typeof o.invoice !== 'string') return new Error(`${path}.invoice: is not a string`)
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,7 @@ message LiveDebitRequest {
|
||||||
oneof debit {
|
oneof debit {
|
||||||
string invoice = 3;
|
string invoice = 3;
|
||||||
FrequencyRule frequency = 4;
|
FrequencyRule frequency = 4;
|
||||||
|
Empty full_access = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,9 @@ import { Application } from '../storage/entity/Application.js';
|
||||||
import { ApplicationUser } from '../storage/entity/ApplicationUser.js';
|
import { ApplicationUser } from '../storage/entity/ApplicationUser.js';
|
||||||
import { NostrEvent, NostrSend, SendData, SendInitiator } from '../nostr/handler.js';
|
import { NostrEvent, NostrSend, SendData, SendInitiator } from '../nostr/handler.js';
|
||||||
import { UnsignedEvent } from 'nostr-tools';
|
import { UnsignedEvent } from 'nostr-tools';
|
||||||
|
import { BudgetFrequency, NdebitData, NdebitFailure, NdebitSuccess, NdebitSuccessPayment, RecurringDebitTimeUnit } from 'nostr-tools/lib/types/nip68.js';
|
||||||
export const expirationRuleName = 'expiration'
|
export const expirationRuleName = 'expiration'
|
||||||
export const frequencyRuleName = 'frequency'
|
export const frequencyRuleName = 'frequency'
|
||||||
type RecurringDebitTimeUnit = 'day' | 'week' | 'month'
|
|
||||||
type RecurringDebit = { frequency: { number: number, unit: RecurringDebitTimeUnit } }
|
|
||||||
const unitToIntervalType = (unit: RecurringDebitTimeUnit) => {
|
const unitToIntervalType = (unit: RecurringDebitTimeUnit) => {
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case 'day': return Types.IntervalType.DAY
|
case 'day': return Types.IntervalType.DAY
|
||||||
|
|
@ -93,11 +92,6 @@ const debitAccessRulesToDebitRules = (rules: DebitAccessRules | null): Types.Deb
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NdebitData = { pointer?: string, amount_sats: number } & (RecurringDebit | { bolt11: string })
|
|
||||||
export type NdebitSuccess = { res: 'ok' }
|
|
||||||
export type NdebitSuccessPayment = { res: 'ok', preimage: string }
|
|
||||||
export type NdebitFailure = { res: 'GFY', error: string, code: number }
|
|
||||||
const nip68errs = {
|
const nip68errs = {
|
||||||
1: "Request Denied Warning",
|
1: "Request Denied Warning",
|
||||||
2: "Temporary Failure",
|
2: "Temporary Failure",
|
||||||
|
|
@ -244,7 +238,7 @@ export class DebitManager {
|
||||||
|
|
||||||
doNdebit = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => {
|
doNdebit = async (event: NostrEvent, pointerdata: NdebitData): Promise<HandleNdebitRes> => {
|
||||||
const { appId, pub: requestorPub } = event
|
const { appId, pub: requestorPub } = event
|
||||||
const { amount_sats, pointer } = pointerdata
|
const { amount_sats, pointer, bolt11, frequency } = pointerdata
|
||||||
if (!pointer) {
|
if (!pointer) {
|
||||||
// TODO: debit from app owner balance
|
// TODO: debit from app owner balance
|
||||||
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
|
@ -252,9 +246,14 @@ export class DebitManager {
|
||||||
const appUserId = pointer
|
const appUserId = pointer
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, appUserId)
|
||||||
const pointerFreq = pointerdata as RecurringDebit
|
let decodedAmount = null
|
||||||
if (pointerFreq.frequency) {
|
if (bolt11) {
|
||||||
if (!amount_sats) {
|
const decoded = await this.lnd.DecodeInvoice(bolt11)
|
||||||
|
decodedAmount = decoded.numSatoshis
|
||||||
|
}
|
||||||
|
if (frequency) {
|
||||||
|
const amt = amount_sats || decodedAmount
|
||||||
|
if (!amt) {
|
||||||
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
||||||
}
|
}
|
||||||
const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
||||||
|
|
@ -266,9 +265,9 @@ export class DebitManager {
|
||||||
debit: {
|
debit: {
|
||||||
type: Types.LiveDebitRequest_debit_type.FREQUENCY,
|
type: Types.LiveDebitRequest_debit_type.FREQUENCY,
|
||||||
frequency: {
|
frequency: {
|
||||||
interval: unitToIntervalType(pointerFreq.frequency.unit),
|
interval: unitToIntervalType(frequency.unit),
|
||||||
number_of_intervals: pointerFreq.frequency.number,
|
number_of_intervals: frequency.number,
|
||||||
amount: pointerdata.amount_sats,
|
amount: amt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -278,15 +277,33 @@ export class DebitManager {
|
||||||
}
|
}
|
||||||
return { status: 'authOk', debitRes: { res: 'ok' } }
|
return { status: 'authOk', debitRes: { res: 'ok' } }
|
||||||
}
|
}
|
||||||
const { bolt11 } = pointerdata as { bolt11: string }
|
|
||||||
if (!bolt11) {
|
if (!bolt11) {
|
||||||
|
if (!amount_sats) {
|
||||||
|
const debitAccess = await this.storage.debitStorage.GetDebitAccess(appUserId, requestorPub)
|
||||||
|
if (!debitAccess) {
|
||||||
|
return {
|
||||||
|
status: 'authRequired', app, appUser, liveDebitReq: {
|
||||||
|
request_id: event.id,
|
||||||
|
npub: requestorPub,
|
||||||
|
debit: {
|
||||||
|
type: Types.LiveDebitRequest_debit_type.FULL_ACCESS,
|
||||||
|
full_access: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!debitAccess.authorized) {
|
||||||
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[1], code: 1 } }
|
||||||
|
}
|
||||||
|
return { status: 'authOk', debitRes: { res: 'ok' } }
|
||||||
|
}
|
||||||
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
||||||
}
|
}
|
||||||
const decoded = await this.lnd.DecodeInvoice(bolt11)
|
|
||||||
if (decoded.numSatoshis === 0) {
|
if (!decodedAmount) {
|
||||||
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[6], code: 6 } }
|
||||||
}
|
}
|
||||||
if (amount_sats && amount_sats !== decoded.numSatoshis) {
|
if (amount_sats && amount_sats !== decodedAmount) {
|
||||||
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
return { status: 'fail', debitRes: { res: 'GFY', error: nip68errs[5], code: 5 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue