94 lines
3.7 KiB
JavaScript

import axios from "axios";
import crypto from "crypto";
import { verifyEvent } from 'nostr-tools/pure';
import appConfig from "@/config/appConfig";
import { runMiddleware, corsMiddleware } from "@/utils/corsMiddleware";
import { getLightningAddressByName } from "@/db/models/lightningAddressModels";
const BACKEND_URL = process.env.BACKEND_URL;
const PLEBDEVS_API_KEY = process.env.PLEBDEVS_API_KEY;
export default async function handler(req, res) {
await runMiddleware(req, res, corsMiddleware);
const { slug, ...queryParams } = req.query;
let foundAddress = null;
const customAddress = appConfig.customLightningAddresses.find(addr => addr.name === slug);
if (customAddress) {
foundAddress = customAddress;
} else {
foundAddress = await getLightningAddressByName(slug);
}
if (!foundAddress) {
res.status(404).json({ error: 'Lightning address not found' });
return;
}
if (foundAddress) {
if (queryParams.amount) {
const amount = parseInt(queryParams.amount);
let metadata, metadataString, hash, descriptionHash;
if (queryParams?.nostr) {
// This is a zap request
const zapRequest = JSON.parse(decodeURIComponent(queryParams.nostr));
// Verify the zap request
if (!verifyEvent(zapRequest)) {
res.status(400).json({ error: 'Invalid zap request' });
return;
}
// Validate zap request
if (zapRequest.kind !== 9734) {
res.status(400).json({ error: 'Invalid zap request' });
return;
}
metadataString = JSON.stringify(zapRequest);
hash = crypto.createHash('sha256').update(metadataString).digest('hex');
descriptionHash = Buffer.from(hash, 'hex').toString('base64');
} else {
// This is a regular lnurl-pay request
metadata = [
["text/plain", `${foundAddress.name}'s LNURL endpoint, CHEERS!`]
];
metadataString = JSON.stringify(metadata);
hash = crypto.createHash('sha256').update(metadataString).digest('hex');
descriptionHash = Buffer.from(hash, 'hex').toString('base64');
}
// Check amount against BigInt min/max values
if (amount < foundAddress.minSendable) {
res.status(400).json({ error: 'Amount too low' });
return;
} else if (amount > foundAddress.maxSendable) {
res.status(400).json({ error: 'Amount too high' });
return;
} else {
try {
const response = await axios.post(`${BACKEND_URL}/api/lightning-address/lnd`, {
amount: amount,
description_hash: descriptionHash,
name: slug,
zap_request: queryParams?.nostr ? queryParams.nostr : null
}, {
headers: {
'Authorization': PLEBDEVS_API_KEY
}
});
res.status(200).json({ pr: response.data.invoice, verify: `${BACKEND_URL}/api/lightning-address/verify/${slug}/${response.data.payment_hash}` });
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Failed to generate invoice' });
}
}
} else {
res.status(400).json({ error: 'Amount not specified' });
}
} else {
res.status(404).json({ error: 'Lightning address not found' });
}
}