Dependency inject `me` into post validation schemas to enforce no forwarding posts to self (#485)

Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
SatsAllDay 2023-09-12 12:56:59 -04:00 committed by GitHub
parent 16a6f93708
commit 1a6dc879a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 27 deletions

View File

@ -621,7 +621,7 @@ export default {
return await models.item.update({ where: { id: Number(id) }, data })
},
upsertLink: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
await ssValidate(linkSchema, item, models)
await ssValidate(linkSchema, item, models, me)
if (id) {
return await updateItem(parent, { id, ...item }, { me, models })
@ -630,7 +630,7 @@ export default {
}
},
upsertDiscussion: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
await ssValidate(discussionSchema, item, models)
await ssValidate(discussionSchema, item, models, me)
if (id) {
return await updateItem(parent, { id, ...item }, { me, models })
@ -639,7 +639,7 @@ export default {
}
},
upsertBounty: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
await ssValidate(bountySchema, item, models)
await ssValidate(bountySchema, item, models, me)
if (id) {
return await updateItem(parent, { id, ...item }, { me, models })
@ -656,7 +656,7 @@ export default {
})
: 0
await ssValidate(pollSchema, item, models, optionCount)
await ssValidate(pollSchema, item, models, me, optionCount)
if (id) {
return await updateItem(parent, { id, ...item }, { me, models })

View File

@ -11,6 +11,7 @@ import CancelButton from './cancel-button'
import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
export function BountyForm ({
item,
@ -25,7 +26,8 @@ export function BountyForm ({
}) {
const router = useRouter()
const client = useApolloClient()
const schema = bountySchema(client)
const me = useMe()
const schema = bountySchema(client, me)
const [upsertBounty] = useMutation(
gql`
mutation upsertBounty(

View File

@ -15,6 +15,7 @@ import CancelButton from './cancel-button'
import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
export function DiscussionForm ({
item, sub, editThreshold, titleLabel = 'title',
@ -23,11 +24,11 @@ export function DiscussionForm ({
}) {
const router = useRouter()
const client = useApolloClient()
const schema = discussionSchema(client)
const me = useMe()
const schema = discussionSchema(client, me)
// if Web Share Target API was used
const shareTitle = router.query.title
// const me = useMe()
const [upsertDiscussion] = useMutation(
gql`
mutation upsertDiscussion($sub: String, $id: ID, $title: String!, $text: String, $boost: Int, $forward: [ItemForwardInput], $hash: String, $hmac: String) {

View File

@ -16,11 +16,13 @@ import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { normalizeForwards } from '../lib/form'
import { MAX_TITLE_LENGTH } from '../lib/constants'
import { useMe } from './me'
export function LinkForm ({ item, sub, editThreshold, children }) {
const router = useRouter()
const client = useApolloClient()
const schema = linkSchema(client)
const me = useMe()
const schema = linkSchema(client, me)
// if Web Share Target API was used
const shareUrl = router.query.url
const shareTitle = router.query.title

View File

@ -12,11 +12,13 @@ import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
import { useCallback } from 'react'
import { normalizeForwards } from '../lib/form'
import { useMe } from './me'
export function PollForm ({ item, sub, editThreshold, children }) {
const router = useRouter()
const client = useApolloClient()
const schema = pollSchema(client)
const me = useMe()
const schema = pollSchema(client, me)
const [upsertPoll] = useMutation(
gql`

View File

@ -58,7 +58,7 @@ async function usernameExists (client, name) {
return !!user
}
export function advPostSchemaMembers (client) {
export function advPostSchemaMembers (client, me) {
return {
boost: intValidator
.min(BOOST_MIN, `must be blank or at least ${BOOST_MIN}`).test({
@ -66,18 +66,25 @@ export function advPostSchemaMembers (client) {
test: async boost => !boost || boost % BOOST_MIN === 0,
message: `must be divisble be ${BOOST_MIN}`
}),
// XXX this lets you forward to youself (it's financially equivalent but it should be disallowed)
forward: array()
.max(MAX_FORWARDS, `you can only configure ${MAX_FORWARDS} forward recipients`)
.of(object().shape({
nym: string().required('must specify a stacker').test({
name: 'nym',
test: async name => {
if (!name || !name.length) return true
return await usernameExists(client, name)
},
message: 'stacker does not exist'
}),
nym: string().required('must specify a stacker')
.test({
name: 'nym',
test: async name => {
if (!name || !name.length) return false
return await usernameExists(client, name)
},
message: 'stacker does not exist'
})
.test({
name: 'self',
test: async name => {
return me?.name !== name
},
message: 'cannot forward to yourself'
}),
pct: intValidator.required('must specify a percentage').min(1, 'percentage must be at least 1').max(100, 'percentage must not exceed 100')
}))
.compact((v) => !v.nym && !v.pct)
@ -100,35 +107,35 @@ export function subSelectSchemaMembers (client) {
}
}
export function bountySchema (client) {
export function bountySchema (client, me) {
return object({
title: titleValidator,
bounty: intValidator
.min(1000, 'must be at least 1000')
.max(1000000, 'must be at most 1m'),
...advPostSchemaMembers(client),
...advPostSchemaMembers(client, me),
...subSelectSchemaMembers()
})
}
export function discussionSchema (client) {
export function discussionSchema (client, me) {
return object({
title: titleValidator,
...advPostSchemaMembers(client),
...advPostSchemaMembers(client, me),
...subSelectSchemaMembers()
})
}
export function linkSchema (client) {
export function linkSchema (client, me) {
return object({
title: titleValidator,
url: string().matches(URL_REGEXP, 'invalid url').required('required'),
...advPostSchemaMembers(client),
...advPostSchemaMembers(client, me),
...subSelectSchemaMembers()
})
}
export function pollSchema (client, numExistingChoices = 0) {
export function pollSchema (client, me, numExistingChoices = 0) {
return object({
title: titleValidator,
options: array().of(
@ -144,7 +151,7 @@ export function pollSchema (client, numExistingChoices = 0) {
message: `at least ${MIN_POLL_NUM_CHOICES} choices required`,
test: arr => arr.length >= MIN_POLL_NUM_CHOICES - numExistingChoices
}),
...advPostSchemaMembers(client),
...advPostSchemaMembers(client, me),
...subSelectSchemaMembers()
})
}