issue-166-open-timestamps #220
@ -20,7 +20,7 @@ import {
|
||||
CreateSignatureEventContent,
|
||||
Meta,
|
||||
ProfileMetadata,
|
||||
Timestamp,
|
||||
SignedEvent,
|
||||
User,
|
||||
UserRole
|
||||
} from '../../types'
|
||||
@ -62,7 +62,7 @@ import {
|
||||
faUpload
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { SigitFile } from '../../utils/file.ts'
|
||||
import { generateTimestamps } from '../../utils/opentimestamps.ts'
|
||||
import { generateTimestamp } from '../../utils/opentimestamps.ts'
|
||||
|
||||
export const CreatePage = () => {
|
||||
const navigate = useNavigate()
|
||||
@ -560,8 +560,7 @@ export const CreatePage = () => {
|
||||
fileHashes: {
|
||||
[key: string]: string
|
||||
},
|
||||
zipUrl: string,
|
||||
timestamps?: Timestamp[]
|
||||
zipUrl: string
|
||||
) => {
|
||||
const content: CreateSignatureEventContent = {
|
||||
signers: signers.map((signer) => hexToNpub(signer.pubkey)),
|
||||
@ -569,8 +568,7 @@ export const CreatePage = () => {
|
||||
fileHashes,
|
||||
markConfig,
|
||||
zipUrl,
|
||||
title,
|
||||
...(timestamps && { timestamps })
|
||||
title
|
||||
}
|
||||
|
||||
setLoadingSpinnerDesc('Signing nostr event for create signature')
|
||||
@ -602,6 +600,11 @@ export const CreatePage = () => {
|
||||
return receivers.map((receiver) => sendNotification(receiver, meta))
|
||||
}
|
||||
|
||||
const extractNostrId = (stringifiedEvent: string): string => {
|
||||
const e = JSON.parse(stringifiedEvent) as SignedEvent
|
||||
return e.id
|
||||
}
|
||||
|
||||
const handleCreate = async () => {
|
||||
try {
|
||||
if (!validateInputs()) return
|
||||
@ -611,10 +614,6 @@ export const CreatePage = () => {
|
||||
const fileHashes = await generateFileHashes()
|
||||
if (!fileHashes) return
|
||||
|
||||
setLoadingSpinnerDesc('Timestamping your files')
|
||||
const timestamps = await generateTimestamps(Object.values(fileHashes))
|
||||
if (!timestamps) return
|
||||
|
||||
setLoadingSpinnerDesc('Generating encryption key')
|
||||
const encryptionKey = await generateEncryptionKey()
|
||||
|
||||
@ -639,8 +638,7 @@ export const CreatePage = () => {
|
||||
const createSignature = await generateCreateSignature(
|
||||
markConfig,
|
||||
fileHashes,
|
||||
fileUrl,
|
||||
timestamps
|
||||
fileUrl
|
||||
)
|
||||
if (!createSignature) return
|
||||
|
||||
@ -656,6 +654,10 @@ export const CreatePage = () => {
|
||||
const keys = await generateKeys(pubkeys, encryptionKey)
|
||||
if (!keys) return
|
||||
|
||||
const timestamp = await generateTimestamp(
|
||||
extractNostrId(createSignature)
|
||||
)
|
||||
|
||||
const meta: Meta = {
|
||||
createSignature,
|
||||
keys,
|
||||
@ -663,6 +665,10 @@ export const CreatePage = () => {
|
||||
docSignatures: {}
|
||||
}
|
||||
|
||||
if (timestamp) {
|
||||
meta.timestamps = [timestamp]
|
||||
}
|
||||
|
||||
setLoadingSpinnerDesc('Updating user app data')
|
||||
const event = await updateUsersAppData(meta)
|
||||
if (!event) return
|
||||
|
@ -18,6 +18,7 @@ export interface Meta {
|
||||
docSignatures: { [key: `npub1${string}`]: string }
|
||||
exportSignature?: string
|
||||
keys?: { sender: string; keys: { [user: `npub1${string}`]: string } }
|
||||
timestamps?: Timestamp[]
|
||||
}
|
||||
|
||||
export interface CreateSignatureEventContent {
|
||||
@ -27,13 +28,11 @@ export interface CreateSignatureEventContent {
|
||||
markConfig: Mark[]
|
||||
title: string
|
||||
zipUrl: string
|
||||
timestamps?: Timestamp[]
|
||||
}
|
||||
|
||||
export interface SignedEventContent {
|
||||
prevSig: string
|
||||
marks: Mark[]
|
||||
timestamps: Timestamp[]
|
||||
}
|
||||
|
||||
export interface Sigit {
|
||||
@ -42,7 +41,7 @@ export interface Sigit {
|
||||
}
|
||||
|
||||
export interface Timestamp {
|
||||
fileHash: string
|
||||
nostrId: string
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,26 @@
|
||||
import { Timestamp } from '../types'
|
||||
import { isPromiseFulfilled } from './utils.ts'
|
||||
import { retryAll } from './retry.ts'
|
||||
import { retry } from './retry.ts'
|
||||
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
|
||||
|
||||
/**
|
||||
* Generates a timestamp for the provided document hashes.
|
||||
* @returns Timestamp in a hex string format
|
||||
* Generates a timestamp for the provided nostr event ID.
|
||||
* @returns Timestamp with its value and the nostr event ID.
|
||||
*/
|
||||
export const generateTimestamps = async (
|
||||
fileHashes: string[]
|
||||
): Promise<Timestamp[] | undefined> => {
|
||||
const promises = fileHashes.map((fileHash) => () => timestamp(fileHash))
|
||||
const resolvedPromises = await retryAll(promises)
|
||||
if (resolvedPromises.every(isPromiseFulfilled)) {
|
||||
return resolvedPromises.map(({ value }, index) => {
|
||||
export const generateTimestamp = async (
|
||||
nostrId: string
|
||||
): Promise<Timestamp | undefined> => {
|
||||
try {
|
||||
return {
|
||||
fileHash: fileHashes[index],
|
||||
timestamp: value
|
||||
timestamp: await retry(() => timestamp(nostrId)),
|
||||
nostrId: nostrId
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const timestamp = async (hash: string) => {
|
||||
const timestamp = async (hash: string): Promise<string> => {
|
||||
const detachedTimestamp =
|
||||
window.OpenTimestamps.DetachedTimestampFile.fromHash(
|
||||
new window.OpenTimestamps.Ops.OpSHA256(),
|
||||
|
Loading…
Reference in New Issue
Block a user