Move all validation schema into lib/validate
This commit is contained in:
parent
39d8928772
commit
b96757b366
|
@ -1,5 +1,4 @@
|
||||||
import { TOR_REGEXP } from '@/lib/url'
|
import { LNbitsSchema } from '@/lib/validate'
|
||||||
import { object, string } from 'yup'
|
|
||||||
|
|
||||||
export const name = 'lnbits'
|
export const name = 'lnbits'
|
||||||
|
|
||||||
|
@ -28,30 +27,7 @@ export async function validate ({ logger, url, adminKey }) {
|
||||||
logger.ok('wallet found')
|
logger.ok('wallet found')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schema = object({
|
export const schema = LNbitsSchema
|
||||||
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 async function sendPayment ({ bolt11, url, adminKey }) {
|
export async function sendPayment ({ bolt11, url, adminKey }) {
|
||||||
const response = await postPayment(url, adminKey, bolt11)
|
const response = await postPayment(url, adminKey, bolt11)
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import bip39Words from '@/lib/bip39-words'
|
|
||||||
import LNC from '@lightninglabs/lnc-web'
|
import LNC from '@lightninglabs/lnc-web'
|
||||||
import { Mutex } from 'async-mutex'
|
import { Mutex } from 'async-mutex'
|
||||||
import { string, array, object } from 'yup'
|
|
||||||
import { Form, PasswordInput, SubmitButton } from '@/components/form'
|
import { Form, PasswordInput, SubmitButton } from '@/components/form'
|
||||||
import CancelButton from '@/components/cancel-button'
|
import CancelButton from '@/components/cancel-button'
|
||||||
import { InvoiceCanceledError, InvoiceExpiredError } from '@/components/payment'
|
import { InvoiceCanceledError, InvoiceExpiredError } from '@/components/payment'
|
||||||
import { bolt11Tags } from '@/lib/bolt11'
|
import { bolt11Tags } from '@/lib/bolt11'
|
||||||
import { Status } from '@/components/wallet'
|
import { Status } from '@/components/wallet'
|
||||||
|
import { LNCSchema } from '@/lib/validate'
|
||||||
|
|
||||||
export const name = 'lnc'
|
export const name = 'lnc'
|
||||||
|
|
||||||
|
@ -58,20 +57,7 @@ export async function validate ({ me, logger, pairingPhrase, password }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schema = object({
|
export const schema = LNCSchema
|
||||||
pairingPhrase: array()
|
|
||||||
.transform(function (value, originalValue) {
|
|
||||||
if (this.isType(value) && value !== null) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return originalValue ? originalValue.split(/[\s]+/) : []
|
|
||||||
})
|
|
||||||
.of(string().trim().oneOf(bip39Words, ({ value }) => `'${value}' is not a valid pairing phrase word`))
|
|
||||||
.min(2, 'needs at least two words')
|
|
||||||
.max(10, 'max 10 words')
|
|
||||||
.required('required'),
|
|
||||||
password: string()
|
|
||||||
})
|
|
||||||
|
|
||||||
const mutex = new Mutex()
|
const mutex = new Mutex()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { NOSTR_PUBKEY_HEX } from '@/lib/nostr'
|
|
||||||
import { parseNwcUrl } from '@/lib/url'
|
import { parseNwcUrl } from '@/lib/url'
|
||||||
|
import { NWCSchema } from '@/lib/validate'
|
||||||
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
|
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
|
||||||
import { object, string } from 'yup'
|
|
||||||
|
|
||||||
export const name = 'nwc'
|
export const name = 'nwc'
|
||||||
|
|
||||||
|
@ -19,31 +18,7 @@ export const card = {
|
||||||
badges: ['send only', 'non-custodialish']
|
badges: ['send only', 'non-custodialish']
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schema = object({
|
export const schema = NWCSchema
|
||||||
nwcUrl: string()
|
|
||||||
.required('required')
|
|
||||||
.test(async (nwcUrl, context) => {
|
|
||||||
// run validation in sequence to control order of errors
|
|
||||||
// inspired by https://github.com/jquense/yup/issues/851#issuecomment-1049705180
|
|
||||||
try {
|
|
||||||
await string().required('required').validate(nwcUrl)
|
|
||||||
await string().matches(/^nostr\+?walletconnect:\/\//, { message: 'must start with nostr+walletconnect://' }).validate(nwcUrl)
|
|
||||||
let relayUrl, walletPubkey, secret
|
|
||||||
try {
|
|
||||||
({ relayUrl, walletPubkey, secret } = parseNwcUrl(nwcUrl))
|
|
||||||
} catch {
|
|
||||||
// invalid URL error. handle as if pubkey validation failed to not confuse user.
|
|
||||||
throw new Error('pubkey must be 64 hex chars')
|
|
||||||
}
|
|
||||||
await string().required('pubkey required').trim().matches(NOSTR_PUBKEY_HEX, 'pubkey must be 64 hex chars').validate(walletPubkey)
|
|
||||||
await string().required('relay url required').trim().wss('relay must use wss://').validate(relayUrl)
|
|
||||||
await string().required('secret required').trim().matches(/^[0-9a-fA-F]{64}$/, 'secret must be 64 hex chars').validate(secret)
|
|
||||||
} catch (err) {
|
|
||||||
return context.createError({ message: err.message })
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
export async function validate ({ logger, nwcUrl }) {
|
export async function validate ({ logger, nwcUrl }) {
|
||||||
const { relayUrl, walletPubkey } = parseNwcUrl(nwcUrl)
|
const { relayUrl, walletPubkey } = parseNwcUrl(nwcUrl)
|
||||||
|
|
|
@ -12,6 +12,8 @@ import * as subsFragments from '@/fragments/subs'
|
||||||
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
import { isInvoicableMacaroon, isInvoiceMacaroon } from './macaroon'
|
||||||
import { datePivot } from './time'
|
import { datePivot } from './time'
|
||||||
import { decodeRune } from '@/lib/cln'
|
import { decodeRune } from '@/lib/cln'
|
||||||
|
import { TOR_REGEXP, parseNwcUrl } from '@/lib/url'
|
||||||
|
import bip39Words from '@/lib/bip39-words'
|
||||||
|
|
||||||
const { SUB } = subsFragments
|
const { SUB } = subsFragments
|
||||||
const { NAME_QUERY } = usersFragments
|
const { NAME_QUERY } = usersFragments
|
||||||
|
@ -303,6 +305,72 @@ export function advSchema (args) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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')
|
||||||
|
.test(async (nwcUrl, context) => {
|
||||||
|
// run validation in sequence to control order of errors
|
||||||
|
// inspired by https://github.com/jquense/yup/issues/851#issuecomment-1049705180
|
||||||
|
try {
|
||||||
|
await string().required('required').validate(nwcUrl)
|
||||||
|
await string().matches(/^nostr\+?walletconnect:\/\//, { message: 'must start with nostr+walletconnect://' }).validate(nwcUrl)
|
||||||
|
let relayUrl, walletPubkey, secret
|
||||||
|
try {
|
||||||
|
({ relayUrl, walletPubkey, secret } = parseNwcUrl(nwcUrl))
|
||||||
|
} catch {
|
||||||
|
// invalid URL error. handle as if pubkey validation failed to not confuse user.
|
||||||
|
throw new Error('pubkey must be 64 hex chars')
|
||||||
|
}
|
||||||
|
await string().required('pubkey required').trim().matches(NOSTR_PUBKEY_HEX, 'pubkey must be 64 hex chars').validate(walletPubkey)
|
||||||
|
await string().required('relay url required').trim().wss('relay must use wss://').validate(relayUrl)
|
||||||
|
await string().required('secret required').trim().matches(/^[0-9a-fA-F]{64}$/, 'secret must be 64 hex chars').validate(secret)
|
||||||
|
} catch (err) {
|
||||||
|
return context.createError({ message: err.message })
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export const LNCSchema = object({
|
||||||
|
pairingPhrase: array()
|
||||||
|
.transform(function (value, originalValue) {
|
||||||
|
if (this.isType(value) && value !== null) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return originalValue ? originalValue.split(/[\s]+/) : []
|
||||||
|
})
|
||||||
|
.of(string().trim().oneOf(bip39Words, ({ value }) => `'${value}' is not a valid pairing phrase word`))
|
||||||
|
.min(2, 'needs at least two words')
|
||||||
|
.max(10, 'max 10 words')
|
||||||
|
.required('required'),
|
||||||
|
password: string()
|
||||||
|
})
|
||||||
|
|
||||||
export function lnAddrAutowithdrawSchema ({ me } = {}) {
|
export function lnAddrAutowithdrawSchema ({ me } = {}) {
|
||||||
return object({
|
return object({
|
||||||
address: lightningAddressValidator.required('required').test({
|
address: lightningAddressValidator.required('required').test({
|
||||||
|
|
Loading…
Reference in New Issue