2024-08-06 10:42:21 +00:00
|
|
|
import { useEffect, useState } from 'react'
|
|
|
|
import { CreateSignatureEventContent, Meta } from '../types'
|
2024-08-12 12:26:03 +00:00
|
|
|
import { Mark } from '../types/mark'
|
|
|
|
import {
|
2024-08-13 09:52:05 +00:00
|
|
|
fromUnixTimestamp,
|
2024-08-13 11:32:32 +00:00
|
|
|
hexToNpub,
|
2024-08-12 12:26:03 +00:00
|
|
|
parseCreateSignatureEvent,
|
|
|
|
parseCreateSignatureEventContent,
|
|
|
|
SigitMetaParseError,
|
|
|
|
SigitStatus,
|
|
|
|
SignStatus
|
|
|
|
} from '../utils'
|
|
|
|
import { toast } from 'react-toastify'
|
|
|
|
import { verifyEvent } from 'nostr-tools'
|
2024-08-06 10:42:21 +00:00
|
|
|
import { Event } from 'nostr-tools'
|
2024-08-13 11:32:32 +00:00
|
|
|
import store from '../store/store'
|
|
|
|
import { AuthState } from '../store/auth/types'
|
|
|
|
import { NostrController } from '../controllers'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flattened interface that combines properties `Meta`, `CreateSignatureEventContent`,
|
|
|
|
* and `Event` (event's fields are made optional and pubkey and created_at replaced with our versions)
|
|
|
|
*/
|
|
|
|
interface FlatMeta
|
|
|
|
extends Meta,
|
|
|
|
CreateSignatureEventContent,
|
|
|
|
Partial<Omit<Event, 'pubkey' | 'created_at'>> {
|
|
|
|
// Remove pubkey and use submittedBy as `npub1${string}`
|
|
|
|
submittedBy?: `npub1${string}`
|
|
|
|
|
|
|
|
// Remove created_at and replace with createdAt
|
|
|
|
createdAt?: number
|
2024-08-06 10:42:21 +00:00
|
|
|
|
2024-08-12 12:26:03 +00:00
|
|
|
// Validated create signature event
|
|
|
|
isValid: boolean
|
2024-08-07 12:15:20 +00:00
|
|
|
|
2024-08-13 11:32:32 +00:00
|
|
|
// Decryption
|
|
|
|
encryptionKey: string | null
|
|
|
|
|
2024-08-12 12:26:03 +00:00
|
|
|
// Calculated status fields
|
|
|
|
signedStatus: SigitStatus
|
|
|
|
signersStatus: {
|
|
|
|
[signer: `npub1${string}`]: SignStatus
|
2024-08-07 12:15:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:26:03 +00:00
|
|
|
/**
|
|
|
|
* Custom use hook for parsing the Sigit Meta
|
|
|
|
* @param meta Sigit Meta
|
|
|
|
* @returns flattened Meta object with calculated signed status
|
|
|
|
*/
|
|
|
|
export const useSigitMeta = (meta: Meta): FlatMeta => {
|
|
|
|
const [isValid, setIsValid] = useState(false)
|
|
|
|
const [kind, setKind] = useState<number>()
|
|
|
|
const [tags, setTags] = useState<string[][]>()
|
2024-08-13 11:32:32 +00:00
|
|
|
const [createdAt, setCreatedAt] = useState<number>()
|
|
|
|
const [submittedBy, setSubmittedBy] = useState<`npub1${string}`>() // submittedBy, pubkey from nostr event
|
2024-08-12 12:26:03 +00:00
|
|
|
const [id, setId] = useState<string>()
|
|
|
|
const [sig, setSig] = useState<string>()
|
|
|
|
|
|
|
|
const [signers, setSigners] = useState<`npub1${string}`[]>([])
|
|
|
|
const [viewers, setViewers] = useState<`npub1${string}`[]>([])
|
|
|
|
const [fileHashes, setFileHashes] = useState<{
|
|
|
|
[user: `npub1${string}`]: string
|
|
|
|
}>({})
|
|
|
|
const [markConfig, setMarkConfig] = useState<Mark[]>([])
|
|
|
|
const [title, setTitle] = useState<string>('')
|
|
|
|
const [zipUrl, setZipUrl] = useState<string>('')
|
|
|
|
|
|
|
|
const [signedStatus, setSignedStatus] = useState<SigitStatus>(
|
|
|
|
SigitStatus.Partial
|
2024-08-06 10:42:21 +00:00
|
|
|
)
|
2024-08-12 12:26:03 +00:00
|
|
|
const [signersStatus, setSignersStatus] = useState<{
|
|
|
|
[signer: `npub1${string}`]: SignStatus
|
|
|
|
}>({})
|
2024-08-06 10:42:21 +00:00
|
|
|
|
2024-08-13 11:32:32 +00:00
|
|
|
const [encryptionKey, setEncryptionKey] = useState<string | null>(null)
|
|
|
|
|
2024-08-06 10:42:21 +00:00
|
|
|
useEffect(() => {
|
2024-08-12 12:26:03 +00:00
|
|
|
if (!meta) return
|
|
|
|
;(async function () {
|
|
|
|
try {
|
|
|
|
const createSignatureEvent = await parseCreateSignatureEvent(
|
|
|
|
meta.createSignature
|
|
|
|
)
|
|
|
|
|
|
|
|
const { kind, tags, created_at, pubkey, id, sig, content } =
|
|
|
|
createSignatureEvent
|
|
|
|
|
|
|
|
setIsValid(verifyEvent(createSignatureEvent))
|
|
|
|
setKind(kind)
|
|
|
|
setTags(tags)
|
|
|
|
// created_at in nostr events are stored in seconds
|
2024-08-13 09:52:05 +00:00
|
|
|
setCreatedAt(fromUnixTimestamp(created_at))
|
2024-08-13 11:32:32 +00:00
|
|
|
setSubmittedBy(pubkey as `npub1${string}`)
|
2024-08-12 12:26:03 +00:00
|
|
|
setId(id)
|
|
|
|
setSig(sig)
|
|
|
|
|
|
|
|
const { title, signers, viewers, fileHashes, markConfig, zipUrl } =
|
|
|
|
await parseCreateSignatureEventContent(content)
|
|
|
|
|
|
|
|
setTitle(title)
|
|
|
|
setSigners(signers)
|
|
|
|
setViewers(viewers)
|
|
|
|
setFileHashes(fileHashes)
|
|
|
|
setMarkConfig(markConfig)
|
|
|
|
setZipUrl(zipUrl)
|
|
|
|
|
2024-08-13 11:32:32 +00:00
|
|
|
if (meta.keys) {
|
|
|
|
const { sender, keys } = meta.keys
|
|
|
|
|
|
|
|
// Retrieve the user's public key from the state
|
|
|
|
const usersPubkey = (store.getState().auth as AuthState).usersPubkey!
|
|
|
|
const usersNpub = hexToNpub(usersPubkey)
|
|
|
|
|
|
|
|
// Check if the user's public key is in the keys object
|
|
|
|
if (usersNpub in keys) {
|
|
|
|
// Instantiate the NostrController to decrypt the encryption key
|
|
|
|
const nostrController = NostrController.getInstance()
|
|
|
|
const decrypted = await nostrController
|
|
|
|
.nip04Decrypt(sender, keys[usersNpub])
|
|
|
|
.catch((err) => {
|
|
|
|
console.log(
|
|
|
|
'An error occurred in decrypting encryption key',
|
|
|
|
err
|
|
|
|
)
|
|
|
|
return null
|
|
|
|
})
|
|
|
|
|
|
|
|
setEncryptionKey(decrypted)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:26:03 +00:00
|
|
|
// Parse each signature event and set signer status
|
|
|
|
for (const npub in meta.docSignatures) {
|
|
|
|
try {
|
|
|
|
const event = await parseCreateSignatureEvent(
|
|
|
|
meta.docSignatures[npub as `npub1${string}`]
|
|
|
|
)
|
|
|
|
const isValidSignature = verifyEvent(event)
|
|
|
|
setSignersStatus((prev) => {
|
|
|
|
return {
|
|
|
|
...prev,
|
|
|
|
[npub]: isValidSignature
|
|
|
|
? SignStatus.Signed
|
|
|
|
: SignStatus.Invalid
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
setSignersStatus((prev) => {
|
|
|
|
return {
|
|
|
|
...prev,
|
|
|
|
[npub]: SignStatus.Invalid
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const signedBy = Object.keys(meta.docSignatures) as `npub1${string}`[]
|
|
|
|
const isCompletelySigned = signers.every((signer) =>
|
|
|
|
signedBy.includes(signer)
|
|
|
|
)
|
|
|
|
setSignedStatus(
|
|
|
|
isCompletelySigned ? SigitStatus.Complete : SigitStatus.Partial
|
|
|
|
)
|
|
|
|
} catch (error) {
|
|
|
|
if (error instanceof SigitMetaParseError) {
|
|
|
|
toast.error(error.message)
|
|
|
|
}
|
|
|
|
console.error(error)
|
|
|
|
}
|
|
|
|
})()
|
2024-08-06 10:42:21 +00:00
|
|
|
}, [meta])
|
|
|
|
|
|
|
|
return {
|
2024-08-13 11:32:32 +00:00
|
|
|
modifiedAt: meta?.modifiedAt,
|
|
|
|
createSignature: meta?.createSignature,
|
|
|
|
docSignatures: meta?.docSignatures,
|
|
|
|
keys: meta?.keys,
|
2024-08-12 12:26:03 +00:00
|
|
|
isValid,
|
|
|
|
kind,
|
|
|
|
tags,
|
2024-08-13 11:32:32 +00:00
|
|
|
createdAt,
|
|
|
|
submittedBy,
|
2024-08-12 12:26:03 +00:00
|
|
|
id,
|
|
|
|
sig,
|
2024-08-06 10:42:21 +00:00
|
|
|
signers,
|
2024-08-12 12:26:03 +00:00
|
|
|
viewers,
|
|
|
|
fileHashes,
|
|
|
|
markConfig,
|
|
|
|
title,
|
|
|
|
zipUrl,
|
2024-08-06 10:42:21 +00:00
|
|
|
signedStatus,
|
2024-08-13 11:32:32 +00:00
|
|
|
signersStatus,
|
|
|
|
encryptionKey
|
2024-08-06 10:42:21 +00:00
|
|
|
}
|
|
|
|
}
|