From 268e1259d6918fc203a0964fee06e706ea23c8a6 Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Sun, 27 Nov 2022 03:21:07 -0800 Subject: [PATCH] Fix invoice validator --- frontend/package-lock.json | 91 +++++++++++++++++- frontend/package.json | 1 + frontend/src/basic/Main.tsx | 2 +- .../TradeBox/Forms/LightningPayout.tsx | 93 +++++-------------- frontend/src/components/UnsafeAlert.js | 1 - frontend/src/models/Settings.model.ts | 4 +- 6 files changed, 115 insertions(+), 77 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6710d371..8c3ac4ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "frontend", - "version": "0.3.0", + "version": "0.3.1", "license": "ISC", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.16.7", @@ -30,6 +30,7 @@ "i18next-http-backend": "^1.4.0", "install": "^0.13.0", "js-sha256": "^0.9.0", + "light-bolt11-decoder": "^2.1.0", "npm": "^8.19.1", "openpgp": "^5.2.1", "react": "^18.2.0", @@ -4876,6 +4877,11 @@ } ] }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -4985,6 +4991,29 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -7468,6 +7497,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -9811,6 +9859,16 @@ "node": ">= 0.8.0" } }, + "node_modules/light-bolt11-decoder": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-2.1.0.tgz", + "integrity": "sha512-/AaSWTldx3aaFD7DgMVbX77MVEgLEPI0Zyx4Fjg23u3WpEoc536vz5LTXBU8oXAcrEcyDyn5GpBi2pEYuL351Q==", + "dependencies": { + "bech32": "^1.1.2", + "bn.js": "^4.11.8", + "buffer": "^6.0.3" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -18428,6 +18486,11 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, "big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -18509,6 +18572,15 @@ "node-int64": "^0.4.0" } }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -20381,6 +20453,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -22104,6 +22181,16 @@ "type-check": "~0.4.0" } }, + "light-bolt11-decoder": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-2.1.0.tgz", + "integrity": "sha512-/AaSWTldx3aaFD7DgMVbX77MVEgLEPI0Zyx4Fjg23u3WpEoc536vz5LTXBU8oXAcrEcyDyn5GpBi2pEYuL351Q==", + "requires": { + "bech32": "^1.1.2", + "bn.js": "^4.11.8", + "buffer": "^6.0.3" + } + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6dfaf904..bfcc387c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -68,6 +68,7 @@ "i18next-http-backend": "^1.4.0", "install": "^0.13.0", "js-sha256": "^0.9.0", + "light-bolt11-decoder": "^2.1.0", "npm": "^8.19.1", "openpgp": "^5.2.1", "react": "^18.2.0", diff --git a/frontend/src/basic/Main.tsx b/frontend/src/basic/Main.tsx index 794a8e05..31322587 100644 --- a/frontend/src/basic/Main.tsx +++ b/frontend/src/basic/Main.tsx @@ -204,7 +204,7 @@ const Main = ({ settings, setSettings }: MainProps): JSX.Element => { useEffect(() => { // Sets Setting network from coordinator API param if accessing via web if (settings.network == undefined) { - setSettings({ ...settings, network: data.network }); + setSettings({ ...settings, network: info.network }); } }, [info]); diff --git a/frontend/src/components/TradeBox/Forms/LightningPayout.tsx b/frontend/src/components/TradeBox/Forms/LightningPayout.tsx index a74b840f..9a314f93 100644 --- a/frontend/src/components/TradeBox/Forms/LightningPayout.tsx +++ b/frontend/src/components/TradeBox/Forms/LightningPayout.tsx @@ -20,12 +20,14 @@ import { IconButton, FormHelperText, } from '@mui/material'; + import { Order, Settings } from '../../../models'; +import {decode} from 'light-bolt11-decoder' import WalletsButton from '../WalletsButton'; import { LoadingButton } from '@mui/lab'; import { pn } from '../../../utils'; -import { ContentCopy, Help, RoundaboutRight, Route, SelfImprovement } from '@mui/icons-material'; +import { ContentCopy, Help, SelfImprovement } from '@mui/icons-material'; import { apiClient } from '../../../services/api'; import lnproxies from '../../../../static/lnproxies.json'; @@ -98,11 +100,17 @@ export const LightningPayoutForm = ({ }; const validateInvoice = function (invoice: string, targetAmount: number) { - const invoiceAmount = Number(invoice.substring(4, 5 + Math.floor(Math.log10(targetAmount)))); - if (targetAmount != invoiceAmount && invoice.length > 20) { - return 'Invalid invoice amount'; - } else { - return ''; + try { + const decoded = decode(invoice) + const invoiceAmount = Math.floor(decoded['sections'][2]['value']/1000) + if (targetAmount != invoiceAmount) { + return 'Invalid invoice amount'; + } else { + return ''; + } + } catch(err) { + const error = err.toString() + return `${error.substring(0,100)}${error.length >100 ? '...' : ''}` } }; @@ -138,7 +146,6 @@ export const LightningPayoutForm = ({ }, [lightning.lnproxyInvoice, lightning.lnproxyAmount]); const lnproxyUrl = function () { - console.log(settings); const bitcoinNetwork = settings?.network ?? 'mainnet'; let internetNetwork: 'Clearnet' | 'I2P' | 'TOR' = 'Clearnet'; if (settings.host?.includes('.i2p')) { @@ -180,7 +187,7 @@ export const LightningPayoutForm = ({ setLoadingLnproxy(true); fetch( lnproxyUrl() + - `/api/${lightning.lnproxyInvoice}${ + `/api/${lightning.lnproxyInvoice.toLocaleLowerCase()}${ lightning.lnproxyBudgetSats > 0 ? `?routing_msat=${lightning.lnproxyBudgetSats * 1000}` : '' @@ -189,9 +196,10 @@ export const LightningPayoutForm = ({ .then((response) => response.text()) .then((text) => { if (text.includes('lnproxy error')) { - setLightning({ ...lightning, badLnproxy: text }); + setLightning({ ...lightning, badLnproxy: text}); } else { - setLightning({ ...lightning, invoice: text, badLnproxy: '' }); + const invoice = text.replace('\n',"") + setLightning({ ...lightning, invoice, badLnproxy: '' }); } }) .catch(() => { @@ -513,6 +521,7 @@ export const LightningPayoutForm = ({ fullWidth={true} disabled={!lightning.useLnproxy} error={lightning.badLnproxy != ''} + FormHelperTextProps={{style:{wordBreak: 'break-all'}}} helperText={lightning.badLnproxy ? t(lightning.badLnproxy) : ''} label={t('Invoice to wrap')} required @@ -534,6 +543,7 @@ export const LightningPayoutForm = ({ disabled={lightning.useLnproxy} error={lightning.badInvoice != ''} helperText={lightning.badInvoice ? t(lightning.badInvoice) : ''} + FormHelperTextProps={{style:{wordBreak: 'break-all'}}} label={lightning.useLnproxy ? t('Wrapped invoice') : t('Payout Lightning Invoice')} required value={lightning.invoice} @@ -555,7 +565,7 @@ export const LightningPayoutForm = ({ disabled={ lightning.lnproxyInvoice.length < 20 || badLnproxyServer != '' || - lightning.badLnproxy + lightning.badLnproxy != '' } onClick={fetchLnproxy} variant='outlined' @@ -568,7 +578,7 @@ export const LightningPayoutForm = ({ )} onClickSubmit(lightning.invoice)} variant='outlined' color='primary' @@ -580,65 +590,6 @@ export const LightningPayoutForm = ({ - {/* - - - - -
- - setLightning({ - ...lightning, - useCustomBudget: e.target.checked, - routingBudgetSats: defaultLightning.routingBudgetSats, - routingBudgetPPM: defaultLightning.routingBudgetPPM, - }) - } - control={} - label={ - - {t('Use custom routing budget')} - - } - /> -
-
-
- -
-
-
*/} - diff --git a/frontend/src/components/UnsafeAlert.js b/frontend/src/components/UnsafeAlert.js index 14b75bba..590437cb 100644 --- a/frontend/src/components/UnsafeAlert.js +++ b/frontend/src/components/UnsafeAlert.js @@ -50,7 +50,6 @@ class UnsafeAlert extends Component { render() { const { t } = this.props; - console.log(this.state); // If alert is hidden return null if (!this.state.show) { diff --git a/frontend/src/models/Settings.model.ts b/frontend/src/models/Settings.model.ts index ce0fd874..cf7b3be9 100644 --- a/frontend/src/models/Settings.model.ts +++ b/frontend/src/models/Settings.model.ts @@ -39,7 +39,7 @@ class BaseSettings { : i18n.resolvedLanguage.substring(0, 2); const networkCookie = systemClient.getItem('settings_network'); - this.network = networkCookie !== '' ? networkCookie : 'mainnet'; + this.network = networkCookie !== '' ? networkCookie : undefined; } public frontend: 'basic' | 'pro' = 'basic'; @@ -47,7 +47,7 @@ class BaseSettings { public fontSize: number = 14; public language?: Language; public freezeViewports: boolean = false; - public network: 'mainnet' | 'testnet' | undefined = 'mainnet'; + public network: 'mainnet' | 'testnet' | undefined = undefined; public coordinator: Coordinator | undefined = undefined; public host?: string; public unsafeClient: boolean = false;