diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d0fec..85ee7e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.0.1-alpha.134](https://github.com/DIG-Network/dig-propagation-server/compare/v0.0.1-alpha.133...v0.0.1-alpha.134) (2024-10-10) + + +### Features + +* add promise interval to resetttl every 30 seconds while waiting for promises ([013305c](https://github.com/DIG-Network/dig-propagation-server/commit/013305cd1d0c424b0693722954bab029a8ead612)) + + +### Bug Fixes + +* upload session ttl ([6d12f18](https://github.com/DIG-Network/dig-propagation-server/commit/6d12f18425f185ad91c8b3d2922a42e37b10aab6)) + +### [0.0.1-alpha.133](https://github.com/DIG-Network/dig-propagation-server/compare/v0.0.1-alpha.132...v0.0.1-alpha.133) (2024-10-10) + + +### Features + +* update sdk ([8cbd893](https://github.com/DIG-Network/dig-propagation-server/commit/8cbd89328b8a46c08f352d982cbfc7f18ca4f0e8)) + ### [0.0.1-alpha.132](https://github.com/DIG-Network/dig-propagation-server/compare/v0.0.1-alpha.131...v0.0.1-alpha.132) (2024-10-08) ### [0.0.1-alpha.131](https://github.com/DIG-Network/dig-propagation-server/compare/v0.0.1-alpha.130...v0.0.1-alpha.131) (2024-10-08) diff --git a/package-lock.json b/package-lock.json index 3b1a011..1f0d63b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dig-propagation-server", - "version": "0.0.1-alpha.132", + "version": "0.0.1-alpha.134", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dig-propagation-server", - "version": "0.0.1-alpha.132", + "version": "0.0.1-alpha.134", "license": "ISC", "dependencies": { "@dignetwork/datalayer-driver": "^0.1.28", diff --git a/package.json b/package.json index 64533ef..a9ea979 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dig-propagation-server", - "version": "0.0.1-alpha.132", + "version": "0.0.1-alpha.134", "description": "", "type": "commonjs", "main": "./dist/index.js", diff --git a/src/controllers/merkleTreeController.ts b/src/controllers/merkleTreeController.ts index 35e8cce..f2d05ea 100644 --- a/src/controllers/merkleTreeController.ts +++ b/src/controllers/merkleTreeController.ts @@ -70,6 +70,31 @@ function createSessionWithTTL(): string { return sessionId; } +const withIntervalCallback = ( + promise: Promise, + callback: () => void +): Promise => { + const intervalTime = 30000; // 30 seconds in milliseconds + + let intervalId: NodeJS.Timeout; + + // Start the interval that calls the callback every 30 seconds + intervalId = setInterval(() => { + callback(); + }, intervalTime); + + // Return a new promise that clears the interval when the original promise settles + return promise + .then((result) => { + clearInterval(intervalId); + return result; + }) + .catch((error) => { + clearInterval(intervalId); + throw error; + }); +}; + /** * Cleans up the session directory after the TTL expires or the upload is complete. * @@ -411,6 +436,8 @@ export const generateFileNonce = async ( throw new HttpError(404, "Upload session not found."); } + session.resetTtl(); + // File path in the session's temporary directory const tmpFilePath = path.join(session.tmpDir, filename); const mainFilePath = path.join(digFolderPath, "stores", storeId, filename); @@ -429,6 +456,7 @@ export const generateFileNonce = async ( // Return 200 status with no body, as per HEAD request specification res.status(200).end(); + session.resetTtl(); } catch (error: any) { console.error("Error generating nonce:", error); const statusCode = error instanceof HttpError ? error.statusCode : 500; @@ -468,6 +496,14 @@ export const uploadFile = async ( throw new HttpError(401, "Invalid nonce."); } + // Check if the session exists in the cache and reset the TTL if found + const session = sessionCache[sessionId]; + if (!session) { + throw new HttpError(404, "Session not found or expired."); + } + + session.resetTtl(); + // Validate the key ownership signature using the nonce const isSignatureValid = await Wallet.verifyKeyOwnershipSignature( nonce, @@ -479,20 +515,15 @@ export const uploadFile = async ( throw new HttpError(401, "Invalid key ownership signature."); } - // Check if the session exists in the cache and reset the TTL if found - const session = sessionCache[sessionId]; - if (!session) { - throw new HttpError(404, "Session not found or expired."); - } - // Check if the user has write permissions to the store const cacheKey = `${publicKey}_${storeId}`; let isOwner = ownerCache.get(cacheKey); if (isOwner === undefined) { const dataStore = new DataStore(storeId, { disableInitialize: true }); - isOwner = await dataStore.hasMetaWritePermissions( - Buffer.from(publicKey, "hex") + isOwner = await withIntervalCallback( + dataStore.hasMetaWritePermissions(Buffer.from(publicKey, "hex")), + session.resetTtl ); ownerCache.set(cacheKey, isOwner); } @@ -501,6 +532,8 @@ export const uploadFile = async ( throw new HttpError(403, "You do not have write access to this store."); } + session.resetTtl(); + // Use Busboy to handle file uploads const bb = Busboy({ headers: req.headers }); @@ -568,12 +601,15 @@ export const uploadFile = async ( if (filename.includes("data/")) { if ( - !(await merkleIntegrityCheck( - rootHashDatPath, - session.tmpDir, - filename, - session.roothash || "", - sha256Digest + !(await withIntervalCallback( + merkleIntegrityCheck( + rootHashDatPath, + session.tmpDir, + filename, + session.roothash || "", + sha256Digest + ), + session.resetTtl )) ) { cleanupSession(sessionId); @@ -650,6 +686,7 @@ export const commitUpload = async ( const datFileContent = JSON.parse(fs.readFileSync(datFilePath, "utf-8")); for (const [fileKey, fileData] of Object.entries(datFileContent.files)) { + session.resetTtl(); const dataPath = getFilePathFromSha256( datFileContent.files[fileKey].sha256, "data" @@ -684,10 +721,13 @@ export const commitUpload = async ( } // Merge the session upload directory with the final directory - fsExtra.copySync(sessionUploadDir, finalDir, { - overwrite: false, // Prevents overwriting existing files - errorOnExist: false, // No error if file already exists - }); + await withIntervalCallback( + fsExtra.copy(sessionUploadDir, finalDir, { + overwrite: false, // Prevents overwriting existing files + errorOnExist: false, // No error if file already exists + }), + session.resetTtl + ); // Regenerate the manifest file based on the upload const dataStore = new DataStore(storeId, { disableInitialize: true }); diff --git a/src/utils/nonce.ts b/src/utils/nonce.ts index 3769160..b6bfb57 100644 --- a/src/utils/nonce.ts +++ b/src/utils/nonce.ts @@ -2,7 +2,7 @@ import crypto from "crypto"; import NodeCache from "node-cache"; // Create a new NodeCache instance with a 5-minute TTL for nonces -const nonceCache = new NodeCache({ stdTTL: 5 * 60, checkperiod: 60 }); // Check every minute for expired entries +const nonceCache = new NodeCache({ stdTTL: 10 * 60 }); /** * Function to generate and store nonce in NodeCache.