fix: profiles matadata and verify page offline flow #202
@ -1,16 +1,11 @@
|
||||
import { Box, Button, Tooltip, Typography } from '@mui/material'
|
||||
import { Box, Button, Typography } from '@mui/material'
|
||||
import JSZip from 'jszip'
|
||||
import { MuiFileInput } from 'mui-file-input'
|
||||
import { Event, verifyEvent } from 'nostr-tools'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { LoadingSpinner } from '../../components/LoadingSpinner'
|
||||
import { NostrController } from '../../controllers'
|
||||
import {
|
||||
CreateSignatureEventContent,
|
||||
DocSignatureEvent,
|
||||
Meta
|
||||
} from '../../types'
|
||||
import { DocSignatureEvent, Meta } from '../../types'
|
||||
import {
|
||||
decryptArrayBuffer,
|
||||
extractMarksFromSignedMeta,
|
||||
@ -20,7 +15,6 @@ import {
|
||||
parseJson,
|
||||
readContentOfZipEntry,
|
||||
signEventForMetaFile,
|
||||
shorten,
|
||||
getCurrentUserFiles
|
||||
} from '../../utils'
|
||||
import styles from './style.module.scss'
|
||||
@ -42,9 +36,6 @@ import { Container } from '../../components/Container'
|
||||
import { useSigitMeta } from '../../hooks/useSigitMeta.tsx'
|
||||
import { StickySideColumns } from '../../layouts/StickySideColumns.tsx'
|
||||
import { UsersDetails } from '../../components/UsersDetails.tsx/index.tsx'
|
||||
import { UserAvatar } from '../../components/UserAvatar/index.tsx'
|
||||
import { useSigitProfiles } from '../../hooks/useSigitProfiles.tsx'
|
||||
import { TooltipChild } from '../../components/TooltipChild.tsx'
|
||||
import FileList from '../../components/FileList'
|
||||
import { CurrentUserFile } from '../../types/file.ts'
|
||||
import { Mark } from '../../types/mark.ts'
|
||||
@ -163,12 +154,26 @@ const SlimPdfView = ({
|
||||
|
||||
export const VerifyPage = () => {
|
||||
const location = useLocation()
|
||||
const usersPubkey = useSelector((state: State) => state.auth.usersPubkey)
|
||||
|
||||
const nostrController = NostrController.getInstance()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
|
||||
|
||||
/**
|
||||
* uploadedZip will be received from home page when a user uploads a sigit zip wrapper that contains meta.json
|
||||
* meta will be received in navigation from create & home page in online mode
|
||||
*/
|
||||
const { uploadedZip, meta } = location.state || {}
|
||||
const { uploadedZip, meta: metaInNavState } = location.state || {}
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
||||
useEffect(() => {
|
||||
if (uploadedZip) {
|
||||
setSelectedFile(uploadedZip)
|
||||
}
|
||||
}, [uploadedZip])
|
||||
|
||||
const [meta, setMeta] = useState<Meta>(metaInNavState)
|
||||
const {
|
||||
submittedBy,
|
||||
zipUrl,
|
||||
@ -179,44 +184,22 @@ export const VerifyPage = () => {
|
||||
parsedSignatureEvents
|
||||
} = useSigitMeta(meta)
|
||||
|
||||
const profiles = useSigitProfiles([
|
||||
...(submittedBy ? [submittedBy] : []),
|
||||
...signers,
|
||||
...viewers
|
||||
])
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
|
||||
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
||||
const [files, setFiles] = useState<{ [filename: string]: SigitFile }>({})
|
||||
|
||||
const [currentFile, setCurrentFile] = useState<CurrentUserFile | null>(null)
|
||||
const [currentFileHashes, setCurrentFileHashes] = useState<{
|
||||
[key: string]: string | null
|
||||
}>({})
|
||||
const [files, setFiles] = useState<{ [filename: string]: SigitFile }>({})
|
||||
const [currentFile, setCurrentFile] = useState<CurrentUserFile | null>(null)
|
||||
const [signatureFileHashes, setSignatureFileHashes] = useState<{
|
||||
[key: string]: string
|
||||
}>(fileHashes)
|
||||
|
||||
useEffect(() => {
|
||||
setSignatureFileHashes(fileHashes)
|
||||
}, [fileHashes])
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.entries(files).length > 0) {
|
||||
const tmp = getCurrentUserFiles(files, fileHashes, signatureFileHashes)
|
||||
const tmp = getCurrentUserFiles(files, currentFileHashes, fileHashes)
|
||||
setCurrentFile(tmp[0])
|
||||
}
|
||||
}, [signatureFileHashes, fileHashes, files])
|
||||
|
||||
const usersPubkey = useSelector((state: State) => state.auth.usersPubkey)
|
||||
const nostrController = NostrController.getInstance()
|
||||
}, [currentFileHashes, fileHashes, files])
|
||||
|
||||
useEffect(() => {
|
||||
if (uploadedZip) {
|
||||
setSelectedFile(uploadedZip)
|
||||
} else if (meta && encryptionKey) {
|
||||
if (metaInNavState && encryptionKey) {
|
||||
const processSigit = async () => {
|
||||
setIsLoading(true)
|
||||
|
||||
@ -301,7 +284,7 @@ export const VerifyPage = () => {
|
||||
|
||||
processSigit()
|
||||
}
|
||||
}, [encryptionKey, meta, uploadedZip, zipUrl])
|
||||
}, [encryptionKey, metaInNavState, zipUrl])
|
||||
|
||||
const handleVerify = async () => {
|
||||
if (!selectedFile) return
|
||||
@ -315,6 +298,7 @@ export const VerifyPage = () => {
|
||||
|
||||
if (!zip) return
|
||||
|
||||
const files: { [filename: string]: SigitFile } = {}
|
||||
const fileHashes: { [key: string]: string | null } = {}
|
||||
const fileNames = Object.values(zip.files)
|
||||
.filter((entry) => entry.name.startsWith('files/') && !entry.dir)
|
||||
@ -322,24 +306,27 @@ export const VerifyPage = () => {
|
||||
|
||||
// generate hashes for all entries in files folder of zipArchive
|
||||
// these hashes can be used to verify the originality of files
|
||||
for (const fileName of fileNames) {
|
||||
for (const zipFilePath of fileNames) {
|
||||
const arrayBuffer = await readContentOfZipEntry(
|
||||
zip,
|
||||
fileName,
|
||||
zipFilePath,
|
||||
'arraybuffer'
|
||||
)
|
||||
|
||||
const fileName = zipFilePath.replace(/^files\//, '')
|
||||
if (arrayBuffer) {
|
||||
files[fileName] = await convertToSigitFile(arrayBuffer, fileName)
|
||||
const hash = await getHash(arrayBuffer)
|
||||
|
||||
if (hash) {
|
||||
fileHashes[fileName.replace(/^files\//, '')] = hash
|
||||
fileHashes[fileName] = hash
|
||||
}
|
||||
} else {
|
||||
fileHashes[fileName.replace(/^files\//, '')] = null
|
||||
fileHashes[fileName] = null
|
||||
}
|
||||
}
|
||||
|
||||
setFiles(files)
|
||||
setCurrentFileHashes(fileHashes)
|
||||
|
||||
setLoadingSpinnerDesc('Parsing meta.json')
|
||||
@ -368,43 +355,7 @@ export const VerifyPage = () => {
|
||||
|
||||
if (!parsedMetaJson) return
|
||||
|
||||
const createSignatureEvent = await parseJson<Event>(
|
||||
parsedMetaJson.createSignature
|
||||
).catch((err) => {
|
||||
console.log('err in parsing the createSignature event:>> ', err)
|
||||
toast.error(
|
||||
err.message || 'error occurred in parsing the create signature event'
|
||||
)
|
||||
setIsLoading(false)
|
||||
return null
|
||||
})
|
||||
|
||||
if (!createSignatureEvent) return
|
||||
|
||||
const isValidCreateSignature = verifyEvent(createSignatureEvent)
|
||||
|
||||
if (!isValidCreateSignature) {
|
||||
toast.error('Create signature is invalid')
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
const createSignatureContent = await parseJson<CreateSignatureEventContent>(
|
||||
createSignatureEvent.content
|
||||
).catch((err) => {
|
||||
console.log(
|
||||
`err in parsing the createSignature event's content :>> `,
|
||||
err
|
||||
)
|
||||
toast.error(
|
||||
err.message ||
|
||||
`error occurred in parsing the create signature event's content`
|
||||
)
|
||||
setIsLoading(false)
|
||||
return null
|
||||
})
|
||||
|
||||
if (!createSignatureContent) return
|
||||
setMeta(parsedMetaJson)
|
||||
|
||||
setIsLoading(false)
|
||||
}
|
||||
@ -479,47 +430,6 @@ export const VerifyPage = () => {
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
const displayExportedBy = () => {
|
||||
if (!meta || !meta.exportSignature) return null
|
||||
|
||||
const exportSignatureString = meta.exportSignature
|
||||
|
||||
try {
|
||||
const exportSignatureEvent = JSON.parse(exportSignatureString) as Event
|
||||
|
||||
if (verifyEvent(exportSignatureEvent)) {
|
||||
const exportedBy = exportSignatureEvent.pubkey
|
||||
const profile = profiles[exportedBy]
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
profile?.display_name ||
|
||||
profile?.name ||
|
||||
shorten(hexToNpub(exportedBy))
|
||||
}
|
||||
placement="top"
|
||||
arrow
|
||||
disableInteractive
|
||||
>
|
||||
<TooltipChild>
|
||||
<UserAvatar pubkey={exportedBy} image={profile?.picture} />
|
||||
</TooltipChild>
|
||||
</Tooltip>
|
||||
)
|
||||
} else {
|
||||
toast.error(`Invalid export signature!`)
|
||||
return (
|
||||
<Typography component="label" sx={{ color: 'red' }}>
|
||||
Invalid export signature
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`An error occurred wile parsing exportSignature`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
|
||||
@ -554,22 +464,19 @@ export const VerifyPage = () => {
|
||||
{meta && (
|
||||
<StickySideColumns
|
||||
left={
|
||||
<>
|
||||
{currentFile !== null && (
|
||||
currentFile !== null && (
|
||||
<FileList
|
||||
files={getCurrentUserFiles(
|
||||
files,
|
||||
currentFileHashes,
|
||||
signatureFileHashes
|
||||
fileHashes
|
||||
)}
|
||||
currentFile={currentFile}
|
||||
setCurrentFile={setCurrentFile}
|
||||
handleDownload={handleExport}
|
||||
downloadLabel="Download Sigit"
|
||||
/>
|
||||
)}
|
||||
{displayExportedBy()}
|
||||
</>
|
||||
)
|
||||
}
|
||||
right={<UsersDetails meta={meta} />}
|
||||
leftIcon={faFileDownload}
|
||||
@ -578,11 +485,7 @@ export const VerifyPage = () => {
|
||||
>
|
||||
<SlimPdfView
|
||||
currentFile={currentFile}
|
||||
files={getCurrentUserFiles(
|
||||
files,
|
||||
currentFileHashes,
|
||||
signatureFileHashes
|
||||
)}
|
||||
files={getCurrentUserFiles(files, currentFileHashes, fileHashes)}
|
||||
parsedSignatureEvents={parsedSignatureEvents}
|
||||
/>
|
||||
</StickySideColumns>
|
||||
|
Loading…
Reference in New Issue
Block a user