Skip to content

Commit d58b77a

Browse files
authored
Merge pull request #24 from ethersphere/multiple_references_from_zip
feat: Multiple references from
2 parents 6b5816c + ce53bd4 commit d58b77a

5 files changed

Lines changed: 1177 additions & 98 deletions

File tree

backend/index.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,29 @@ const express = require('express');
44
const { createProxyMiddleware } = require('http-proxy-middleware');
55
const { createPublicClient, http } = require('viem');
66
const { gnosis } = require('viem/chains');
7+
const crypto = require('crypto');
78

89
// Add this near the top with other environment variables
910
const PORT = process.env.PORT || 3333;
1011
const PROXY_TARGET = process.env.PROXY_TARGET || 'http://localhost:1633';
1112
const REGISTRY_ADDRESS =
1213
process.env.REGISTRY_ADDRESS || '0x5EBfBeFB1E88391eFb022d5d33302f50a46bF4f3';
1314

15+
// Session management for multi-file uploads
16+
const uploadSessions = new Map();
17+
const SESSION_DURATION = 15 * 60 * 1000; // 15 minutes
18+
const SESSION_CLEANUP_INTERVAL = 5 * 60 * 1000; // 5 minutes
19+
20+
// Clean up expired sessions periodically
21+
setInterval(() => {
22+
const now = Date.now();
23+
for (const [sessionId, session] of uploadSessions.entries()) {
24+
if (now - session.createdAt > SESSION_DURATION) {
25+
uploadSessions.delete(sessionId);
26+
}
27+
}
28+
}, SESSION_CLEANUP_INTERVAL);
29+
1430
const BATCH_REGISTRY_ABI = [
1531
{
1632
name: 'getBatchPayer',
@@ -28,6 +44,35 @@ const gnosisPublicClient = createPublicClient({
2844
transport: http(),
2945
});
3046

47+
// Generate a secure session token
48+
const generateSessionToken = (uploaderAddress, batchId) => {
49+
const data = `${uploaderAddress}:${batchId}:${Date.now()}:${crypto.randomBytes(16).toString('hex')}`;
50+
return crypto.createHash('sha256').update(data).digest('hex');
51+
};
52+
53+
// Check if there's a valid session for this upload
54+
const checkExistingSession = (uploaderAddress, batchId, sessionToken) => {
55+
if (!sessionToken) return null;
56+
57+
const session = uploadSessions.get(sessionToken);
58+
if (!session) return null;
59+
60+
const now = Date.now();
61+
if (now - session.createdAt > SESSION_DURATION) {
62+
uploadSessions.delete(sessionToken);
63+
return null;
64+
}
65+
66+
if (
67+
session.uploaderAddress.toLowerCase() !== uploaderAddress.toLowerCase() ||
68+
session.batchId !== batchId
69+
) {
70+
return null;
71+
}
72+
73+
return session;
74+
};
75+
3176
const verifySignature = async (req, res, next) => {
3277
console.log('Processing request at path:', req.path);
3378

@@ -39,15 +84,38 @@ const verifySignature = async (req, res, next) => {
3984
const fileName = req.headers['x-file-name'];
4085
const batchId = req.headers['swarm-postage-batch-id'];
4186
const messageContent = req.headers['x-message-content'];
87+
const sessionToken = req.headers['x-upload-session-token']; // New header for session token
88+
const isMultiFileUpload = req.headers['x-multi-file-upload'] === 'true'; // New header to indicate multi-file upload
4289

4390
console.log('Headers received:', {
4491
signedMessage: signedMessage ? 'exists' : 'missing',
4592
uploaderAddress,
4693
fileName,
4794
batchId,
4895
messageContent,
96+
sessionToken: sessionToken ? 'exists' : 'missing',
97+
isMultiFileUpload,
4998
});
5099

100+
// Check for existing session first (for multi-file uploads)
101+
if (sessionToken && uploaderAddress && batchId) {
102+
const existingSession = checkExistingSession(uploaderAddress, batchId, sessionToken);
103+
if (existingSession) {
104+
console.log('Valid session found, skipping detailed verification');
105+
// Update session last used time
106+
existingSession.lastUsed = Date.now();
107+
existingSession.fileCount += 1;
108+
109+
// Add session info to response headers for client
110+
res.setHeader('x-session-token', sessionToken);
111+
res.setHeader('x-session-valid', 'true');
112+
return next();
113+
} else {
114+
console.log('Invalid or expired session token provided');
115+
}
116+
}
117+
118+
// Full verification required (first file or no valid session)
51119
if (!signedMessage || !uploaderAddress || !fileName || !batchId) {
52120
return res.status(401).json({
53121
error: 'Missing required headers',
@@ -118,6 +186,27 @@ const verifySignature = async (req, res, next) => {
118186
}
119187

120188
console.log('Verification successful');
189+
190+
// Create session token for multi-file uploads
191+
if (isMultiFileUpload) {
192+
const newSessionToken = generateSessionToken(uploaderAddress, batchId);
193+
uploadSessions.set(newSessionToken, {
194+
uploaderAddress,
195+
batchId,
196+
createdAt: Date.now(),
197+
lastUsed: Date.now(),
198+
fileCount: 1,
199+
});
200+
201+
console.log(
202+
`Created new session token for multi-file upload: ${newSessionToken.substring(0, 8)}...`
203+
);
204+
205+
// Add session token to response headers
206+
res.setHeader('x-session-token', newSessionToken);
207+
res.setHeader('x-session-created', 'true');
208+
}
209+
121210
next();
122211
} catch (error) {
123212
console.error('Verification Error:', error);

0 commit comments

Comments
 (0)