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