fix(verify): offline flow

This commit is contained in:
enes 2024-09-13 17:53:22 +02:00
parent bf1b3beb63
commit 759a40a4f9

View File

@ -1,16 +1,11 @@
import { Box, Button, Tooltip, Typography } from '@mui/material' import { Box, Button, Typography } from '@mui/material'
import JSZip from 'jszip' import JSZip from 'jszip'
import { MuiFileInput } from 'mui-file-input' import { MuiFileInput } from 'mui-file-input'
import { Event, verifyEvent } from 'nostr-tools'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { LoadingSpinner } from '../../components/LoadingSpinner' import { LoadingSpinner } from '../../components/LoadingSpinner'
import { NostrController } from '../../controllers' import { NostrController } from '../../controllers'
import { import { DocSignatureEvent, Meta } from '../../types'
CreateSignatureEventContent,
DocSignatureEvent,
Meta
} from '../../types'
import { import {
decryptArrayBuffer, decryptArrayBuffer,
extractMarksFromSignedMeta, extractMarksFromSignedMeta,
@ -20,7 +15,6 @@ import {
parseJson, parseJson,
readContentOfZipEntry, readContentOfZipEntry,
signEventForMetaFile, signEventForMetaFile,
shorten,
getCurrentUserFiles getCurrentUserFiles
} from '../../utils' } from '../../utils'
import styles from './style.module.scss' import styles from './style.module.scss'
@ -42,9 +36,6 @@ import { Container } from '../../components/Container'
import { useSigitMeta } from '../../hooks/useSigitMeta.tsx' import { useSigitMeta } from '../../hooks/useSigitMeta.tsx'
import { StickySideColumns } from '../../layouts/StickySideColumns.tsx' import { StickySideColumns } from '../../layouts/StickySideColumns.tsx'
import { UsersDetails } from '../../components/UsersDetails.tsx/index.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 FileList from '../../components/FileList'
import { CurrentUserFile } from '../../types/file.ts' import { CurrentUserFile } from '../../types/file.ts'
import { Mark } from '../../types/mark.ts' import { Mark } from '../../types/mark.ts'
@ -163,12 +154,26 @@ const SlimPdfView = ({
export const VerifyPage = () => { export const VerifyPage = () => {
const location = useLocation() 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 * 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 * 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 { const {
submittedBy, submittedBy,
zipUrl, zipUrl,
@ -179,44 +184,22 @@ export const VerifyPage = () => {
parsedSignatureEvents parsedSignatureEvents
} = useSigitMeta(meta) } = useSigitMeta(meta)
const profiles = useSigitProfiles([ const [files, setFiles] = useState<{ [filename: string]: SigitFile }>({})
...(submittedBy ? [submittedBy] : []),
...signers,
...viewers
])
const [isLoading, setIsLoading] = useState(false)
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
const [selectedFile, setSelectedFile] = useState<File | null>(null)
const [currentFile, setCurrentFile] = useState<CurrentUserFile | null>(null)
const [currentFileHashes, setCurrentFileHashes] = useState<{ const [currentFileHashes, setCurrentFileHashes] = useState<{
[key: string]: string | null [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(() => { useEffect(() => {
if (Object.entries(files).length > 0) { if (Object.entries(files).length > 0) {
const tmp = getCurrentUserFiles(files, fileHashes, signatureFileHashes) const tmp = getCurrentUserFiles(files, currentFileHashes, fileHashes)
setCurrentFile(tmp[0]) setCurrentFile(tmp[0])
} }
}, [signatureFileHashes, fileHashes, files]) }, [currentFileHashes, fileHashes, files])
const usersPubkey = useSelector((state: State) => state.auth.usersPubkey)
const nostrController = NostrController.getInstance()
useEffect(() => { useEffect(() => {
if (uploadedZip) { if (metaInNavState && encryptionKey) {
setSelectedFile(uploadedZip)
} else if (meta && encryptionKey) {
const processSigit = async () => { const processSigit = async () => {
setIsLoading(true) setIsLoading(true)
@ -301,7 +284,7 @@ export const VerifyPage = () => {
processSigit() processSigit()
} }
}, [encryptionKey, meta, uploadedZip, zipUrl]) }, [encryptionKey, metaInNavState, zipUrl])
const handleVerify = async () => { const handleVerify = async () => {
if (!selectedFile) return if (!selectedFile) return
@ -315,6 +298,7 @@ export const VerifyPage = () => {
if (!zip) return if (!zip) return
const files: { [filename: string]: SigitFile } = {}
const fileHashes: { [key: string]: string | null } = {} const fileHashes: { [key: string]: string | null } = {}
const fileNames = Object.values(zip.files) const fileNames = Object.values(zip.files)
.filter((entry) => entry.name.startsWith('files/') && !entry.dir) .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 // generate hashes for all entries in files folder of zipArchive
// these hashes can be used to verify the originality of files // 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( const arrayBuffer = await readContentOfZipEntry(
zip, zip,
fileName, zipFilePath,
'arraybuffer' 'arraybuffer'
) )
const fileName = zipFilePath.replace(/^files\//, '')
if (arrayBuffer) { if (arrayBuffer) {
files[fileName] = await convertToSigitFile(arrayBuffer, fileName)
const hash = await getHash(arrayBuffer) const hash = await getHash(arrayBuffer)
if (hash) { if (hash) {
fileHashes[fileName.replace(/^files\//, '')] = hash fileHashes[fileName] = hash
} }
} else { } else {
fileHashes[fileName.replace(/^files\//, '')] = null fileHashes[fileName] = null
} }
} }
setFiles(files)
setCurrentFileHashes(fileHashes) setCurrentFileHashes(fileHashes)
setLoadingSpinnerDesc('Parsing meta.json') setLoadingSpinnerDesc('Parsing meta.json')
@ -368,43 +355,7 @@ export const VerifyPage = () => {
if (!parsedMetaJson) return if (!parsedMetaJson) return
const createSignatureEvent = await parseJson<Event>( setMeta(parsedMetaJson)
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
setIsLoading(false) setIsLoading(false)
} }
@ -479,47 +430,6 @@ export const VerifyPage = () => {
setIsLoading(false) 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 ( return (
<> <>
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />} {isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
@ -554,22 +464,19 @@ export const VerifyPage = () => {
{meta && ( {meta && (
<StickySideColumns <StickySideColumns
left={ left={
<> currentFile !== null && (
{currentFile !== null && ( <FileList
<FileList files={getCurrentUserFiles(
files={getCurrentUserFiles( files,
files, currentFileHashes,
currentFileHashes, fileHashes
signatureFileHashes )}
)} currentFile={currentFile}
currentFile={currentFile} setCurrentFile={setCurrentFile}
setCurrentFile={setCurrentFile} handleDownload={handleExport}
handleDownload={handleExport} downloadLabel="Download Sigit"
downloadLabel="Download Sigit" />
/> )
)}
{displayExportedBy()}
</>
} }
right={<UsersDetails meta={meta} />} right={<UsersDetails meta={meta} />}
leftIcon={faFileDownload} leftIcon={faFileDownload}
@ -578,11 +485,7 @@ export const VerifyPage = () => {
> >
<SlimPdfView <SlimPdfView
currentFile={currentFile} currentFile={currentFile}
files={getCurrentUserFiles( files={getCurrentUserFiles(files, currentFileHashes, fileHashes)}
files,
currentFileHashes,
signatureFileHashes
)}
parsedSignatureEvents={parsedSignatureEvents} parsedSignatureEvents={parsedSignatureEvents}
/> />
</StickySideColumns> </StickySideColumns>