From 6652c6519e3384a9f08e725d9c79b7d9c3cc7142 Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 13 Aug 2024 11:52:05 +0200 Subject: [PATCH] refactor(review): add date util functions --- package.json | 2 +- src/controllers/AuthController.ts | 5 +++-- src/controllers/MetadataController.ts | 6 +++--- src/controllers/NostrController.ts | 25 +++++++++++++-------- src/hooks/useSigitMeta.tsx | 3 ++- src/pages/create/index.tsx | 12 +++++------ src/pages/settings/profile/index.tsx | 4 ++-- src/pages/sign/index.tsx | 13 +++++------ src/pages/verify/index.tsx | 6 +++--- src/utils/meta.ts | 4 ++-- src/utils/misc.ts | 8 +++---- src/utils/nostr.ts | 31 ++++++++++++++++++++------- 12 files changed, 69 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index a4ebe6f..5e1619e 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 29", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 25", "lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index e0d2d79..33f5c82 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -12,7 +12,8 @@ import { getAuthToken, getVisitedLink, saveAuthToken, - compareObjects + compareObjects, + unixNow } from '../utils' import { appPrivateRoutes } from '../routes' import { SignedEvent } from '../types' @@ -54,7 +55,7 @@ export class AuthController { }) // Nostr uses unix timestamps - const timestamp = Math.floor(Date.now() / 1000) + const timestamp = unixNow() const { hostname } = window.location const authEvent: EventTemplate = { diff --git a/src/controllers/MetadataController.ts b/src/controllers/MetadataController.ts index 2360275..8f4d190 100644 --- a/src/controllers/MetadataController.ts +++ b/src/controllers/MetadataController.ts @@ -12,7 +12,7 @@ import { import { NostrJoiningBlock, ProfileMetadata, RelaySet } from '../types' import { NostrController } from '.' import { toast } from 'react-toastify' -import { queryNip05 } from '../utils' +import { queryNip05, unixNow } from '../utils' import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk' import { EventEmitter } from 'tseep' import { localCache } from '../services' @@ -194,7 +194,7 @@ export class MetadataController extends EventEmitter { let signedMetadataEvent = event if (event.sig.length < 1) { - const timestamp = Math.floor(Date.now() / 1000) + const timestamp = unixNow() // Metadata event to publish to the wss://purplepag.es relay const newMetadataEvent: Event = { @@ -265,7 +265,7 @@ export class MetadataController extends EventEmitter { // initialize job request const jobEventTemplate: EventTemplate = { content: '', - created_at: Math.round(Date.now() / 1000), + created_at: unixNow(), kind: 68001, tags: [ ['i', `${created_at * 1000}`], diff --git a/src/controllers/NostrController.ts b/src/controllers/NostrController.ts index fa558de..19182b5 100644 --- a/src/controllers/NostrController.ts +++ b/src/controllers/NostrController.ts @@ -42,6 +42,7 @@ import { import { compareObjects, getNsecBunkerDelegatedKey, + unixNow, verifySignedEvent } from '../utils' import { getDefaultRelayMap } from '../utils/relays.ts' @@ -244,7 +245,7 @@ export class NostrController extends EventEmitter { if (!firstSuccessfulPublish) { // If no publish was successful, collect the reasons for failures - const failedPublishes: any[] = [] + const failedPublishes: unknown[] = [] const fallbackRejectionReason = 'Attempt to publish an event has been rejected with unknown reason.' @@ -504,11 +505,13 @@ export class NostrController extends EventEmitter { } else if (loginMethod === LoginMethods.extension) { const nostr = this.getNostrObject() - return (await nostr.signEvent(event as NostrEvent).catch((err: any) => { - console.log('Error while signing event: ', err) + return (await nostr + .signEvent(event as NostrEvent) + .catch((err: unknown) => { + console.log('Error while signing event: ', err) - throw err - })) as Event + throw err + })) as Event } else { return Promise.reject( `We could not sign the event, none of the signing methods are available` @@ -625,8 +628,12 @@ export class NostrController extends EventEmitter { */ capturePublicKey = async (): Promise => { const nostr = this.getNostrObject() - const pubKey = await nostr.getPublicKey().catch((err: any) => { - return Promise.reject(err.message) + const pubKey = await nostr.getPublicKey().catch((err: unknown) => { + if (err instanceof Error) { + return Promise.reject(err.message) + } else { + return Promise.reject(JSON.stringify(err)) + } }) if (!pubKey) { @@ -708,7 +715,7 @@ export class NostrController extends EventEmitter { npub: string, extraRelaysToPublish?: string[] ): Promise => { - const timestamp = Math.floor(Date.now() / 1000) + const timestamp = unixNow() const relayURIs = Object.keys(relayMap) // More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md @@ -810,7 +817,7 @@ export class NostrController extends EventEmitter { // initialize job request const jobEventTemplate: EventTemplate = { content: '', - created_at: Math.round(Date.now() / 1000), + created_at: unixNow(), kind: 68001, tags: [ ['i', `${JSON.stringify(relayURIs)}`], diff --git a/src/hooks/useSigitMeta.tsx b/src/hooks/useSigitMeta.tsx index d8ef9c2..aebd791 100644 --- a/src/hooks/useSigitMeta.tsx +++ b/src/hooks/useSigitMeta.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react' import { CreateSignatureEventContent, Meta } from '../types' import { Mark } from '../types/mark' import { + fromUnixTimestamp, parseCreateSignatureEvent, parseCreateSignatureEventContent, SigitMetaParseError, @@ -68,7 +69,7 @@ export const useSigitMeta = (meta: Meta): FlatMeta => { setKind(kind) setTags(tags) // created_at in nostr events are stored in seconds - setCreatedAt(created_at * 1000) + setCreatedAt(fromUnixTimestamp(created_at)) setPubkey(pubkey) setId(id) setSig(sig) diff --git a/src/pages/create/index.tsx b/src/pages/create/index.tsx index 9218b15..77b7a87 100644 --- a/src/pages/create/index.tsx +++ b/src/pages/create/index.tsx @@ -50,7 +50,7 @@ import { getHash, hexToNpub, isOnline, - now, + unixNow, npubToHex, queryNip05, sendNotification, @@ -407,7 +407,6 @@ export const CreatePage = () => { encryptionKey: string ): Promise => { // Get the current timestamp in seconds - const unixNow = now() const blob = new Blob([encryptedArrayBuffer]) // Create a File object with the Blob data const file = new File([blob], `compressed.sigit`, { @@ -455,10 +454,9 @@ export const CreatePage = () => { const uploadFile = async ( arrayBuffer: ArrayBuffer ): Promise => { - const unixNow = now() const blob = new Blob([arrayBuffer]) // Create a File object with the Blob data - const file = new File([blob], `compressed-${unixNow}.sigit`, { + const file = new File([blob], `compressed-${unixNow()}.sigit`, { type: 'application/sigit' }) @@ -485,7 +483,7 @@ export const CreatePage = () => { return } - saveAs(finalZipFile, `request-${now()}.sigit.zip`) + saveAs(finalZipFile, `request-${unixNow()}.sigit.zip`) setIsLoading(false) } @@ -615,7 +613,7 @@ export const CreatePage = () => { const meta: Meta = { createSignature, keys, - modifiedAt: now(), + modifiedAt: unixNow(), docSignatures: {} } @@ -654,7 +652,7 @@ export const CreatePage = () => { const meta: Meta = { createSignature, - modifiedAt: now(), + modifiedAt: unixNow(), docSignatures: {} } diff --git a/src/pages/settings/profile/index.tsx b/src/pages/settings/profile/index.tsx index 7d6c923..9b2fc2d 100644 --- a/src/pages/settings/profile/index.tsx +++ b/src/pages/settings/profile/index.tsx @@ -26,7 +26,7 @@ import { setMetadataEvent } from '../../../store/actions' import { LoadingSpinner } from '../../../components/LoadingSpinner' import { LoginMethods } from '../../../store/auth/types' import { SmartToy } from '@mui/icons-material' -import { getRoboHashPicture } from '../../../utils' +import { getRoboHashPicture, unixNow } from '../../../utils' import { Container } from '../../../components/Container' export const ProfileSettingsPage = () => { @@ -197,7 +197,7 @@ export const ProfileSettingsPage = () => { // Relay will reject if created_at is too late const updatedMetadataState: UnsignedEvent = { content: content, - created_at: Math.round(Date.now() / 1000), + created_at: unixNow(), kind: kinds.Metadata, pubkey: pubkey!, tags: metadataState?.tags || [] diff --git a/src/pages/sign/index.tsx b/src/pages/sign/index.tsx index 3798863..712ab51 100644 --- a/src/pages/sign/index.tsx +++ b/src/pages/sign/index.tsx @@ -26,7 +26,7 @@ import { hexToNpub, isOnline, loadZip, - now, + unixNow, npubToHex, parseJson, readContentOfZipEntry, @@ -554,7 +554,7 @@ export const SignPage = () => { ...metaCopy.docSignatures, [hexToNpub(signedEvent.pubkey)]: JSON.stringify(signedEvent, null, 2) } - metaCopy.modifiedAt = now() + metaCopy.modifiedAt = unixNow() return metaCopy } @@ -564,7 +564,6 @@ export const SignPage = () => { encryptionKey: string ): Promise => { // Get the current timestamp in seconds - const unixNow = now() const blob = new Blob([encryptedArrayBuffer]) // Create a File object with the Blob data const file = new File([blob], `compressed.sigit`, { @@ -614,7 +613,7 @@ export const SignPage = () => { if (!arraybuffer) return null - return new File([new Blob([arraybuffer])], `${unixNow}.sigit.zip`, { + return new File([new Blob([arraybuffer])], `${unixNow()}.sigit.zip`, { type: 'application/zip' }) } @@ -758,8 +757,7 @@ export const SignPage = () => { if (!arrayBuffer) return const blob = new Blob([arrayBuffer]) - const unixNow = now() - saveAs(blob, `exported-${unixNow}.sigit.zip`) + saveAs(blob, `exported-${unixNow()}.sigit.zip`) setIsLoading(false) @@ -804,8 +802,7 @@ export const SignPage = () => { const finalZipFile = await createFinalZipFile(encryptedArrayBuffer, key) if (!finalZipFile) return - const unixNow = now() - saveAs(finalZipFile, `exported-${unixNow}.sigit.zip`) + saveAs(finalZipFile, `exported-${unixNow()}.sigit.zip`) } /** diff --git a/src/pages/verify/index.tsx b/src/pages/verify/index.tsx index c5a0e8e..1f6bee1 100644 --- a/src/pages/verify/index.tsx +++ b/src/pages/verify/index.tsx @@ -28,7 +28,7 @@ import { extractZipUrlAndEncryptionKey, getHash, hexToNpub, - now, + unixNow, npubToHex, parseJson, readContentOfZipEntry, @@ -239,7 +239,7 @@ export const VerifyPage = () => { } }) } - }, [submittedBy, signers, viewers]) + }, [submittedBy, signers, viewers, metadata]) const handleVerify = async () => { if (!selectedFile) return @@ -445,7 +445,7 @@ export const VerifyPage = () => { if (!arrayBuffer) return const blob = new Blob([arrayBuffer]) - saveAs(blob, `exported-${now()}.sigit.zip`) + saveAs(blob, `exported-${unixNow()}.sigit.zip`) setIsLoading(false) } diff --git a/src/utils/meta.ts b/src/utils/meta.ts index e9e3f13..b3c0c28 100644 --- a/src/utils/meta.ts +++ b/src/utils/meta.ts @@ -1,5 +1,5 @@ import { CreateSignatureEventContent, Meta } from '../types' -import { parseJson } from '.' +import { fromUnixTimestamp, parseJson } from '.' import { Event } from 'nostr-tools' import { toast } from 'react-toastify' @@ -140,7 +140,7 @@ export const extractSigitCardDisplayInfo = async (meta: Meta) => { ) // created_at in nostr events are stored in seconds - sigitInfo.createdAt = createSignatureEvent.created_at * 1000 + sigitInfo.createdAt = fromUnixTimestamp(createSignatureEvent.created_at) const createSignatureContent = await parseCreateSignatureEventContent( createSignatureEvent.content diff --git a/src/utils/misc.ts b/src/utils/misc.ts index 728408c..f427b78 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -13,7 +13,7 @@ import { NostrController } from '../controllers' import { AuthState } from '../store/auth/types' import store from '../store/store' import { CreateSignatureEventContent, Meta } from '../types' -import { hexToNpub, now } from './nostr' +import { hexToNpub, unixNow } from './nostr' import { parseJson } from './string' import { hexToBytes } from '@noble/hashes/utils' @@ -28,10 +28,10 @@ export const uploadToFileStorage = async (file: File) => { const event: EventTemplate = { kind: 24242, content: 'Authorize Upload', - created_at: Math.floor(Date.now() / 1000), + created_at: unixNow(), tags: [ ['t', 'upload'], - ['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now + ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now ['name', file.name], ['size', String(file.size)] ] @@ -78,7 +78,7 @@ export const signEventForMetaFile = async ( const event: EventTemplate = { kind: 27235, // Event type for meta file content: content, // content for event - created_at: Math.floor(Date.now() / 1000), // Current timestamp + created_at: unixNow(), // Current timestamp tags: [['-']] // For understanding why "-" tag is used here see: https://github.com/nostr-protocol/nips/blob/protected-events-tag/70.md } diff --git a/src/utils/nostr.ts b/src/utils/nostr.ts index bec854f..e9ecc8f 100644 --- a/src/utils/nostr.ts +++ b/src/utils/nostr.ts @@ -211,7 +211,22 @@ export const getRoboHashPicture = ( return `https://robohash.org/${npub}.png?set=set${set}` } -export const now = () => Math.round(Date.now() / 1000) +export const unixNow = () => Math.round(Date.now() / 1000) +export const toUnixTimestamp = (date: number | Date) => { + let time + if (typeof date === 'number') { + time = Math.round(date / 1000) + } else if (date instanceof Date) { + time = Math.round(date.getTime() / 1000) + } else { + throw Error('Unsupported type when converting to unix timestamp') + } + + return time +} +export const fromUnixTimestamp = (unix: number) => { + return unix * 1000 +} /** * Generate nip44 conversation key @@ -288,7 +303,7 @@ export const createWrap = (unsignedEvent: UnsignedEvent, receiver: string) => { kind: 1059, // Event kind content, // Encrypted content pubkey, // Public key of the creator - created_at: now(), // Current timestamp + created_at: unixNow(), // Current timestamp tags: [ // Tags including receiver and nonce ['p', receiver], @@ -542,7 +557,7 @@ export const updateUsersAppData = async (meta: Meta) => { const updatedEvent: UnsignedEvent = { kind: kinds.Application, pubkey: usersPubkey!, - created_at: now(), + created_at: unixNow(), tags: [['d', hash]], content: encryptedContent } @@ -608,10 +623,10 @@ const deleteBlossomFile = async (url: string, privateKey: string) => { const event: EventTemplate = { kind: 24242, content: 'Authorize Upload', - created_at: now(), + created_at: unixNow(), tags: [ ['t', 'delete'], - ['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now + ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now ['x', hash] ] } @@ -667,10 +682,10 @@ const uploadUserAppDataToBlossom = async ( const event: EventTemplate = { kind: 24242, content: 'Authorize Upload', - created_at: now(), + created_at: unixNow(), tags: [ ['t', 'upload'], - ['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now + ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now ['name', file.name], ['size', String(file.size)] ] @@ -875,7 +890,7 @@ export const sendNotification = async (receiver: string, meta: Meta) => { pubkey: usersPubkey, content: JSON.stringify(meta), tags: [], - created_at: now() + created_at: unixNow() } // Wrap the unsigned event with the receiver's information