feat: add verifiable listings (proof of possession) with verification widget, badge on cards/detail, i18n (7 langs), fix edit prefill for location/monero, prevent edit/delete on pending listings

This commit is contained in:
2026-02-11 08:14:44 +01:00
parent f5cfab6a2a
commit 53673b4650
20 changed files with 754 additions and 34 deletions

View File

@@ -21,7 +21,8 @@ const DEFAULT_FIELDS = [
'location.postal_code',
'location.country',
'location.latitude',
'location.longitude'
'location.longitude',
'verified'
]
const DETAIL_FIELDS = [
@@ -49,7 +50,13 @@ const DETAIL_FIELDS = [
'location.name',
'location.postal_code',
'location.country',
'contact_public_key'
'monero_address',
'contact_public_key',
'views',
'verified',
'verification_code',
'verification_date',
'verification_image'
]
export async function getListings(options = {}) {

View File

@@ -0,0 +1,49 @@
import { directus } from './directus.js'
const CODE_VALIDITY_MS = 10 * 60 * 1000
class VerificationService {
generateCode() {
const array = new Uint32Array(1)
crypto.getRandomValues(array)
const code = String(array[0] % 1000000).padStart(6, '0')
const generatedAt = new Date()
const expiresAt = new Date(generatedAt.getTime() + CODE_VALIDITY_MS)
return { code, generatedAt, expiresAt }
}
isCodeValid(generatedAt) {
return Date.now() - new Date(generatedAt).getTime() < CODE_VALIDITY_MS
}
getRemainingTime(generatedAt) {
const elapsed = Date.now() - new Date(generatedAt).getTime()
const remaining = Math.max(0, CODE_VALIDITY_MS - elapsed)
return Math.ceil(remaining / 1000)
}
async verify(listingId, code, imageFile) {
try {
const uploaded = await directus.uploadFile(imageFile)
await directus.patch('/items/listings/' + listingId, {
verification_code: code,
verification_image: uploaded.id,
verification_date: new Date().toISOString(),
verified: true
})
return true
} catch (e) {
console.error('Verification failed:', e)
return false
}
}
isVerified(listing) {
return listing.verified === true
}
}
export const verificationService = new VerificationService()