143 lines
3.6 KiB
JavaScript
143 lines
3.6 KiB
JavaScript
const express = require('express');
|
|
const crypto = require('crypto');
|
|
const db = require('../db');
|
|
|
|
const router = express.Router();
|
|
|
|
// Create share link
|
|
router.post('/', (req, res) => {
|
|
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
if (!token) return res.status(401).json({ error: 'No token' });
|
|
|
|
try {
|
|
const jwt = require('jsonwebtoken');
|
|
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'clouddisk-secret-key');
|
|
|
|
const { fileId, password, expiresIn } = req.body;
|
|
|
|
// Verify file ownership
|
|
const file = db.query(
|
|
'SELECT * FROM files WHERE id = ? AND user_id = ?',
|
|
[fileId, decoded.userId]
|
|
);
|
|
|
|
if (file.length === 0) {
|
|
return res.status(404).json({ error: 'File not found' });
|
|
}
|
|
|
|
// Generate share token
|
|
const shareToken = crypto.randomBytes(16).toString('hex');
|
|
|
|
// Calculate expiration
|
|
const expiresAt = expiresIn
|
|
? new Date(Date.now() + expiresIn * 1000).toISOString()
|
|
: null;
|
|
|
|
const result = db.run(
|
|
'INSERT INTO shares (file_id, share_token, password, expires_at) VALUES (?, ?, ?, ?)',
|
|
[fileId, shareToken, password || null, expiresAt]
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
shareToken,
|
|
shareUrl: `/share/${shareToken}`
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// Get share info
|
|
router.get('/:token', (req, res) => {
|
|
try {
|
|
const share = db.query(
|
|
'SELECT * FROM shares WHERE share_token = ?',
|
|
[req.params.token]
|
|
);
|
|
|
|
if (share.length === 0) {
|
|
return res.status(404).json({ error: 'Share not found' });
|
|
}
|
|
|
|
// Check expiration
|
|
if (share[0].expires_at && new Date(share[0].expires_at) < new Date()) {
|
|
return res.status(410).json({ error: 'Share expired' });
|
|
}
|
|
|
|
// Get file info
|
|
const file = db.query(
|
|
'SELECT id, name, type, size FROM files WHERE id = ?',
|
|
[share[0].file_id]
|
|
);
|
|
|
|
// Increment view count
|
|
db.run(
|
|
'UPDATE shares SET view_count = view_count + 1 WHERE id = ?',
|
|
[share[0].id]
|
|
);
|
|
|
|
res.json({
|
|
file: file[0],
|
|
requiresPassword: !!share[0].password,
|
|
expiresAt: share[0].expires_at,
|
|
viewCount: share[0].view_count
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// Verify share password
|
|
router.post('/:token/verify', (req, res) => {
|
|
const { password } = req.body;
|
|
|
|
const share = db.query(
|
|
'SELECT * FROM shares WHERE share_token = ?',
|
|
[req.params.token]
|
|
);
|
|
|
|
if (share.length === 0) {
|
|
return res.status(404).json({ error: 'Share not found' });
|
|
}
|
|
|
|
if (share[0].password && share[0].password !== password) {
|
|
return res.status(401).json({ error: 'Invalid password' });
|
|
}
|
|
|
|
res.json({ success: true });
|
|
});
|
|
|
|
// Download shared file
|
|
router.get('/:token/download', (req, res) => {
|
|
const share = db.query(
|
|
'SELECT * FROM shares WHERE share_token = ?',
|
|
[req.params.token]
|
|
);
|
|
|
|
if (share.length === 0) {
|
|
return res.status(404).json({ error: 'Share not found' });
|
|
}
|
|
|
|
// Check if password protected
|
|
if (share[0].password) {
|
|
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
if (!token) {
|
|
return res.status(401).json({ error: 'Password required' });
|
|
}
|
|
}
|
|
|
|
const file = db.query(
|
|
'SELECT * FROM files WHERE id = ?',
|
|
[share[0].file_id]
|
|
);
|
|
|
|
if (file.length === 0) {
|
|
return res.status(404).json({ error: 'File not found' });
|
|
}
|
|
|
|
res.download(file[0].path, file[0].name);
|
|
});
|
|
|
|
module.exports = router;
|