Skip to content

Commit

Permalink
Merge branch 'master' into cowboy-credits
Browse files Browse the repository at this point in the history
  • Loading branch information
huumn authored Jan 2, 2025
2 parents 91fce73 + d53bc09 commit cc39790
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 13 deletions.
15 changes: 12 additions & 3 deletions api/resolvers/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ export async function getWithdrawl (parent, { id }, { me, models, lnd }) {
}

export function createHmac (hash) {
if (!hash) throw new GqlInputError('hash required to create hmac')
const key = Buffer.from(process.env.INVOICE_HMAC_KEY, 'hex')
return crypto.createHmac('sha256', key).update(Buffer.from(hash, 'hex')).digest('hex')
}

export function verifyHmac (hash, hmac) {
if (!hash || !hmac) throw new GqlInputError('hash or hmac missing')
const hmac2 = createHmac(hash)
if (!timingSafeEqual(Buffer.from(hmac), Buffer.from(hmac2))) {
throw new GqlAuthorizationError('bad hmac')
Expand Down Expand Up @@ -487,10 +489,17 @@ const resolvers = {
},
createWithdrawl: createWithdrawal,
sendToLnAddr,
cancelInvoice: async (parent, { hash, hmac }, { models, lnd, boss }) => {
verifyHmac(hash, hmac)
cancelInvoice: async (parent, { hash, hmac, userCancel }, { me, models, lnd, boss }) => {
// stackers can cancel their own invoices without hmac
if (me && !hmac) {
const inv = await models.invoice.findUnique({ where: { hash } })
if (!inv) throw new GqlInputError('invoice not found')
if (inv.userId !== me.id) throw new GqlInputError('not ur invoice')
} else {
verifyHmac(hash, hmac)
}
await finalizeHodlInvoice({ data: { hash }, lnd, models, boss })
return await models.invoice.findFirst({ where: { hash } })
return await models.invoice.update({ where: { hash }, data: { userCancel: !!userCancel } })
},
dropBolt11: async (parent, { hash }, { me, models, lnd }) => {
if (!me) {
Expand Down
2 changes: 1 addition & 1 deletion api/typeDefs/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const typeDefs = `
createInvoice(amount: Int!): InvoiceOrDirect!
createWithdrawl(invoice: String!, maxFee: Int!): Withdrawl!
sendToLnAddr(addr: String!, amount: Int!, maxFee: Int!, comment: String, identifier: Boolean, name: String, email: String): Withdrawl!
cancelInvoice(hash: String!, hmac: String!): Invoice!
cancelInvoice(hash: String!, hmac: String, userCancel: Boolean): Invoice!
dropBolt11(hash: String!): Boolean
removeWallet(id: ID!): Boolean
deleteWalletLogs(wallet: String): Boolean
Expand Down
8 changes: 2 additions & 6 deletions components/use-invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,9 @@ export default function useInvoice () {
return { invoice: data.invoice, check: that(data.invoice) }
}, [client])

const cancel = useCallback(async ({ hash, hmac }) => {
if (!hash || !hmac) {
throw new Error('missing hash or hmac')
}

const cancel = useCallback(async ({ hash, hmac }, { userCancel = false } = {}) => {
console.log('canceling invoice:', hash)
const { data } = await cancelInvoice({ variables: { hash, hmac } })
const { data } = await cancelInvoice({ variables: { hash, hmac, userCancel } })
return data.cancelInvoice
}, [cancelInvoice])

Expand Down
2 changes: 1 addition & 1 deletion components/use-qr-payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function useQrPayment () {
let paid
const cancelAndReject = async (onClose) => {
if (!paid && cancelOnClose) {
const updatedInv = await invoice.cancel(inv)
const updatedInv = await invoice.cancel(inv, { userCancel: true })
reject(new InvoiceCanceledError(updatedInv))
}
resolve(inv)
Expand Down
4 changes: 2 additions & 2 deletions fragments/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ export const SET_WALLET_PRIORITY = gql`

export const CANCEL_INVOICE = gql`
${INVOICE_FIELDS}
mutation cancelInvoice($hash: String!, $hmac: String!) {
cancelInvoice(hash: $hash, hmac: $hmac) {
mutation cancelInvoice($hash: String!, $hmac: String, $userCancel: Boolean) {
cancelInvoice(hash: $hash, hmac: $hmac, userCancel: $userCancel) {
...InvoiceFields
}
}
Expand Down
28 changes: 28 additions & 0 deletions prisma/migrations/20241231223214_invoice_user_cancel/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- AlterTable
ALTER TABLE "Invoice" ADD COLUMN "userCancel" BOOLEAN;

-- Migrate existing rows
UPDATE "Invoice" SET "userCancel" = false;

-- Add constraint to ensure consistent cancel state
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_cancel" CHECK (
("cancelled" = true AND "cancelledAt" IS NOT NULL AND "userCancel" IS NOT NULL) OR
("cancelled" = false AND "cancelledAt" IS NULL AND "userCancel" IS NULL)
);

-- Add trigger to set userCancel to false by default when cancelled updated and userCancel not specified
CREATE OR REPLACE FUNCTION invoice_set_user_cancel_default()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.cancelled AND NEW."userCancel" IS NULL THEN
NEW."userCancel" := false;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER invoice_user_cancel_trigger
BEFORE UPDATE ON "Invoice"
FOR EACH ROW
EXECUTE FUNCTION invoice_set_user_cancel_default();

1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,7 @@ model Invoice {
confirmedIndex BigInt?
cancelled Boolean @default(false)
cancelledAt DateTime?
userCancel Boolean?
msatsRequested BigInt
msatsReceived BigInt?
desc String?
Expand Down

0 comments on commit cc39790

Please sign in to comment.