Generate validation schema for LNbits
This commit is contained in:
parent
9587ff9a52
commit
fb2b34ce67
|
@ -10,7 +10,7 @@ import { msatsToSats, numWithUnits, abbrNum, ensureB64, B64_URL_REGEX } from './
|
|||
import * as usersFragments from '@/fragments/users'
|
||||
import * as subsFragments from '@/fragments/subs'
|
||||
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
||||
import { TOR_REGEXP, parseNwcUrl } from './url'
|
||||
import { parseNwcUrl } from './url'
|
||||
import { datePivot } from './time'
|
||||
import { decodeRune } from '@/lib/cln'
|
||||
import bip39Words from './bip39-words'
|
||||
|
@ -600,31 +600,6 @@ export const lnAddrSchema = ({ payerData, min, max, commentAllowed } = {}) =>
|
|||
return accum
|
||||
}, {})))
|
||||
|
||||
export const lnbitsSchema = object({
|
||||
url: process.env.NODE_ENV === 'development'
|
||||
? string()
|
||||
.or([string().matches(/^(http:\/\/)?localhost:\d+$/), string().url()], 'invalid url')
|
||||
.required('required').trim()
|
||||
: string().url().required('required').trim()
|
||||
.test(async (url, context) => {
|
||||
if (TOR_REGEXP.test(url)) {
|
||||
// allow HTTP and HTTPS over Tor
|
||||
if (!/^https?:\/\//.test(url)) {
|
||||
return context.createError({ message: 'http or https required' })
|
||||
}
|
||||
return true
|
||||
}
|
||||
try {
|
||||
// force HTTPS over clearnet
|
||||
await string().https().validate(url)
|
||||
} catch (err) {
|
||||
return context.createError({ message: err.message })
|
||||
}
|
||||
return true
|
||||
}),
|
||||
adminKey: string().length(32)
|
||||
})
|
||||
|
||||
export const nwcSchema = object({
|
||||
nwcUrl: string()
|
||||
.required('required')
|
||||
|
|
|
@ -10,6 +10,10 @@ import Info from '@/components/info'
|
|||
import Text from '@/components/text'
|
||||
import { AutowithdrawSettings } from '@/components/autowithdraw-shared'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { object, string } from 'yup'
|
||||
import { autowithdrawSchemaMembers } from '@/lib/validate'
|
||||
import { useMe } from '@/components/me'
|
||||
import { TOR_REGEXP } from '@/lib/url'
|
||||
|
||||
const WalletButtonBar = dynamic(() => import('@/components/wallet-buttonbar.js'), { ssr: false })
|
||||
|
||||
|
@ -20,6 +24,7 @@ export default function WalletSettings () {
|
|||
const router = useRouter()
|
||||
const { wallet: name } = router.query
|
||||
const wallet = useWallet(name)
|
||||
const me = useMe()
|
||||
|
||||
const initial = wallet.fields.reduce((acc, field) => {
|
||||
// We still need to run over all wallet fields via reduce
|
||||
|
@ -33,6 +38,8 @@ export default function WalletSettings () {
|
|||
}
|
||||
}, wallet.config)
|
||||
|
||||
const schema = generateSchema(wallet, { me })
|
||||
|
||||
return (
|
||||
<CenterLayout>
|
||||
<h2 className='pb-2'>{wallet.card.title}</h2>
|
||||
|
@ -40,7 +47,7 @@ export default function WalletSettings () {
|
|||
{!wallet.walletType && <WalletSecurityBanner />}
|
||||
<Form
|
||||
initial={initial}
|
||||
schema={wallet.schema}
|
||||
schema={schema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const newConfig = !wallet.isConfigured
|
||||
|
@ -130,3 +137,67 @@ function WalletFields ({ wallet: { config, fields } }) {
|
|||
return null
|
||||
})
|
||||
}
|
||||
|
||||
function generateSchema (wallet, { me }) {
|
||||
if (wallet.schema) return wallet.schema
|
||||
|
||||
const fieldValidator = (field) => {
|
||||
if (!field.validate) {
|
||||
// default validation
|
||||
let validator = string()
|
||||
if (!field.optional) validator = validator.required('required')
|
||||
return validator
|
||||
}
|
||||
|
||||
const { type: validationType } = field.validate
|
||||
|
||||
let validator
|
||||
|
||||
const stringTypes = ['url', 'string']
|
||||
|
||||
if (stringTypes.includes(validationType)) {
|
||||
validator = string()
|
||||
|
||||
if (field.validate.length) {
|
||||
validator = validator.length(field.validate.length)
|
||||
}
|
||||
}
|
||||
|
||||
if (validationType === 'url') {
|
||||
validator = process.env.NODE_ENV === 'development'
|
||||
? validator
|
||||
.or([string().matches(/^(http:\/\/)?localhost:\d+$/), string().url()], 'invalid url')
|
||||
: validator
|
||||
.url()
|
||||
.test(async (url, context) => {
|
||||
if (field.validate.onionAllowed && TOR_REGEXP.test(url)) {
|
||||
// allow HTTP and HTTPS over Tor
|
||||
if (!/^https?:\/\//.test(url)) {
|
||||
return context.createError({ message: 'http or https required' })
|
||||
}
|
||||
return true
|
||||
}
|
||||
try {
|
||||
// force HTTPS over clearnet
|
||||
await string().https().validate(url)
|
||||
} catch (err) {
|
||||
return context.createError({ message: err.message })
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
if (!field.optional) validator = validator.required('required')
|
||||
|
||||
return validator
|
||||
}
|
||||
|
||||
return object(
|
||||
wallet.fields.reduce((acc, field) => {
|
||||
return {
|
||||
...acc,
|
||||
[field.name]: fieldValidator(field)
|
||||
}
|
||||
}, wallet.walletType ? autowithdrawSchemaMembers({ me }) : {})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
import { lnbitsSchema } from '@/lib/validate'
|
||||
|
||||
export const name = 'lnbits'
|
||||
|
||||
export const fields = [
|
||||
{
|
||||
name: 'url',
|
||||
label: 'lnbits url',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
validate: {
|
||||
type: 'url',
|
||||
onionAllowed: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'adminKey',
|
||||
label: 'admin key',
|
||||
type: 'password'
|
||||
type: 'password',
|
||||
validate: {
|
||||
type: 'string',
|
||||
length: 32
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -20,5 +26,3 @@ export const card = {
|
|||
subtitle: 'use [LNbits](https://lnbits.com/) for payments',
|
||||
badges: ['send only', 'non-custodialish']
|
||||
}
|
||||
|
||||
export const schema = lnbitsSchema
|
||||
|
|
Loading…
Reference in New Issue