import * as Y from 'yjs'; // server/api/polls/[id].ts export default defineEventHandler(async (event) => { const method = event.node.req.method; const pollId = getRouterParam(event, 'id'); // We use Nitro's built-in storage. // 'polls' is the storage namespace. const storage = useStorage('polls'); if (!pollId) { throw createError({ statusCode: 400, statusMessage: 'Poll ID required' }); } // GET: Fetch the saved Yjs document state if (method === 'GET') { const data = await storage.getItem(`poll:${pollId}`); // Return the array of numbers (or null if it doesn't exist yet) return { update: data || null }; } // POST: Save a new Yjs document state if (method === 'POST') { const body = await readBody(event); if (body.update && Array.isArray(body.update)) { // create a temp Y.Doc to encode the Data const tempDoc = new Y.Doc(); Y.applyUpdate(tempDoc, new Uint8Array(body.update)); const yMap = tempDoc.getMap('shared-poll'); const pollData = yMap.toJSON(); // verify pollData for(var option in pollData){ const votes = pollData[option] || []; var pubKeys: CryptoKey[] = []; const verifyAllVotesForOption = async (votes: SignedData[]) => { console.log("verifying votes for option " + option,votes); // check last votes first. if there is something wrong, its likely in the last vote. for (let i = votes.length-1; i >= 0 ; i--) { const userStorage = useStorage('users'); const votePubKeyString = await userStorage.getItem(`user:${votes[i]?.data.userid}`); //console.log("Using public key: "+votePubKeyString) const votePubKey = await stringToCryptoKey(String(votePubKeyString),'public') const isValid = await verifyChainedVote(votes, i,votePubKey); if(!isValid){ console.error("Error! Invalid Vote at: " + i,votes) return false; } } return true; }; const verified = await verifyAllVotesForOption(votes); if(!verified){ console.error("Failed to verify option: "+option) throw createError({ statusCode: 400, statusMessage: 'PollData contains unverifyable content!' }); } } // Save the binary update (sent as an array of numbers) to storage await storage.setItem(`poll:${pollId}`, body.update); return { success: true }; } throw createError({ statusCode: 400, statusMessage: 'Invalid update payload' }); } });