import { defineStore } from 'pinia'; import { ref } from 'vue'; import { api } from '@/plugins/axios'; import type { GetZkUploadCiphertextResult } from '@/types/upload/GetZkUploadCiphertextResult'; import { base64ToBytes } from '@/utils/encoding/base64ToBytes'; import { toArrayBuffer } from '@/utils/toArrayBuffer'; import { decryptPasswordProtectedZkUpload } from '@/utils/upload/decryptPasswordProtectedZkUpload'; import { decryptZkUpload } from '@/utils/upload/decryptZkUpload'; export const useViewStore = defineStore('view', () => { const imageObjectUrl = ref(null); const clearImage = (): void => { if (imageObjectUrl.value) { URL.revokeObjectURL(imageObjectUrl.value); imageObjectUrl.value = null; } }; const fetchZkCiphertext = async (uploadId: string): Promise => { const { data } = await api.get(`/uploads/${uploadId}`); return data; }; const loadZk = async ( payload: GetZkUploadCiphertextResult, fragmentKey: string, password?: string ): Promise => { clearImage(); const iv = base64ToBytes(payload.iv); const ciphertext = base64ToBytes(payload.ciphertext); let plaintext: Uint8Array; if (payload.passwordProtected) { if (!password) { throw new Error('Password required'); } if (!payload.wrappedDek || !payload.wrapIv || !payload.salt) { throw new Error('Incomplete password protection data'); } const wrappedDek = base64ToBytes(payload.wrappedDek); const wrapIv = base64ToBytes(payload.wrapIv); const salt = base64ToBytes(payload.salt); plaintext = await decryptPasswordProtectedZkUpload( ciphertext, iv, fragmentKey, password, wrappedDek, wrapIv, salt ); } else { plaintext = await decryptZkUpload(ciphertext, iv, fragmentKey); } const buffer = toArrayBuffer(plaintext); if (!buffer) { throw new Error('Could not build image blob'); } imageObjectUrl.value = URL.createObjectURL(new Blob([buffer])); }; return { imageObjectUrl, fetchZkCiphertext, loadZk, clearImage }; });