From 3d86957e9f37b396dba436a1ba4dc2ff12a9485f Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Tue, 11 Mar 2025 09:59:01 -0400 Subject: [PATCH] Fully switch to bun / remove slack / update package list --- .env.example | 6 - .gitignore | 1 - bun.lockb | Bin 0 -> 72498 bytes index.js | 29 ---- logger.js | 9 -- package.json | 8 +- src/api/upload.js | 2 +- src/api/utils.js | 2 - src/config/messages.js | 137 ------------------- src/fileUpload.js | 302 ----------------------------------------- src/storage.js | 1 - 11 files changed, 4 insertions(+), 493 deletions(-) create mode 100755 bun.lockb delete mode 100644 logger.js delete mode 100644 src/config/messages.js delete mode 100644 src/fileUpload.js diff --git a/.env.example b/.env.example index 77c617d..08b5fc6 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,3 @@ -# Slack -SLACK_BOT_TOKEN=xoxb- # From OAuth & Permissions -SLACK_SIGNING_SECRET= # From Basic Information -SLACK_APP_TOKEN=xapp- # From Basic Information (for Socket Mode) -SLACK_CHANNEL_ID=channel-id # Channel where bot operates - # S3 Config CF in this example AWS_ACCESS_KEY_ID=1234567890abcdef AWS_SECRET_ACCESS_KEY=abcdef1234567890 diff --git a/.gitignore b/.gitignore index a3b3a54..adb25e2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ /splitfornpm/ /.idea/ /.env -/bun.lockb /package-lock.json /.history \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..d91efc8be1aab456d8f96720e2c666975d3f9567 GIT binary patch literal 72498 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 (1+GOcp_DAz-1abFa31F@Xr9T8Sq5V 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 oAvl2oRjq;qY_dQBHOmmtbHO@~2gI1_ { res.status(404).json({ error: 'Not found' }); }); -// Event listener for file_shared events -// app.event('file_shared', async ({event, client}) => { -// if (parseFloat(event.event_ts) < BOT_START_TIME) return; -// if (event.channel_id !== process.env.SLACK_CHANNEL_ID) return; - -// try { -// await fileUpload.handleFileUpload(event, client); -// } catch (error) { -// logger.error(`Upload failed: ${error.message}`); -// } -// }); - // Startup LOGs (async () => { try { - await fileUpload.initialize(); - // await app.start(); const port = parseInt(process.env.PORT || '4553', 10); expressApp.listen(port, () => { logger.info('CDN started successfully 🔥', { - slackMode: 'Socket Mode', apiPort: port, startTime: new Date().toISOString() }); diff --git a/logger.js b/logger.js deleted file mode 100644 index 2be320d..0000000 --- a/logger.js +++ /dev/null @@ -1,9 +0,0 @@ -const winston = require('winston'); - -const logger = winston.createLogger({ - level: 'info', - format: winston.format.combine(winston.format.colorize(), winston.format.simple()), - transports: [new winston.transports.Console()], -}); - -module.exports = logger; \ No newline at end of file diff --git a/package.json b/package.json index 9003d87..aac87c0 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,15 @@ { "name": "cdn-v2-hackclub", "version": "1.0.0", - "description": "Slack app and API to upload files to S3-compatible storage with unique URLs", + "description": "API to upload files to S3-compatible storage with unique URLs", "main": "index.js", "scripts": { - "start": "node index.js" + "start": "bun index.js", + "dev": "bun --watch index.js" }, "dependencies": { "@aws-sdk/client-s3": "^3.478.0", - "@slack/bolt": "^4.2.0", - "@slack/web-api": "^7.8.0", "cors": "^2.8.5", - "dotenv": "^10.0.0", "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.1", "p-limit": "^6.2.0", diff --git a/src/api/upload.js b/src/api/upload.js index cd8c3df..03b3c13 100644 --- a/src/api/upload.js +++ b/src/api/upload.js @@ -1,7 +1,7 @@ const fetch = require('node-fetch'); const crypto = require('crypto'); const {uploadToStorage} = require('../storage'); -const {generateUrl, getCdnUrl} = require('./utils'); +const {generateUrl} = require('./utils'); const logger = require('../config/logger'); // Sanitize file name for storage diff --git a/src/api/utils.js b/src/api/utils.js index 4ce7c20..1dacc59 100644 --- a/src/api/utils.js +++ b/src/api/utils.js @@ -1,5 +1,3 @@ -const logger = require('../config/logger'); - const getCdnUrl = () => process.env.AWS_CDN_URL; const generateUrl = (version, fileName) => { diff --git a/src/config/messages.js b/src/config/messages.js deleted file mode 100644 index cb579e3..0000000 --- a/src/config/messages.js +++ /dev/null @@ -1,137 +0,0 @@ -const messages = { - success: { - singleFile: "Hey <@{userId}>, here's your link:", - multipleFiles: "Hey <@{userId}>, here are your links:", - alternateSuccess: [ - "thanks!", - "thanks, i'm gonna sell these to adfly!", - "tysm!", - "file away!" - ] - }, - fileTypes: { - gif: [ - "_gif_ that file to me and i'll upload it", - "_gif_ me all all your files!" - ], - heic: [ - "What the heic???" - ], - mov: [ - "I'll _mov_ that to a permanent link for you" - ], - html: [ - "Oh, launching a new website?", - "uwu, what's this site?", - "WooOOAAah hey! Are you serving a site?", - "h-t-m-ello :wave:" - ], - rar: [ - ".rawr xD", - "i also go \"rar\" sometimes!" - ] - }, - errors: { - tooBig: { - messages: [ - "File too big!", - "That's a chonky file!", - "_orpheus struggles to lift the massive file_", - "Sorry, that file's too thicc for me to handle!" - ], - images: [ - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/2too_big_4.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/3too_big_2.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/4too_big_1.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/6too_big_5.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/7too_big_3.png" - ] - }, - generic: { - messages: [ - "_orpheus sneezes and drops the files on the ground before blowing her nose on a blank jpeg._", - "_orpheus trips and your files slip out of her hands and into an inconveniently placed sewer grate._", - "_orpheus accidentally slips the files into a folder in her briefcase labeled \"homework\". she starts sweating profusely._" - ], - images: [ - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/0generic_3.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/1generic_2.png", - "https://cloud-3tq9t10za-hack-club-bot.vercel.app/5generic_1.png" - ] - } - } -}; - -function getRandomItem(array) { - return array[Math.floor(Math.random() * array.length)]; -} - -function getFileTypeMessage(fileExtension) { - const ext = fileExtension.toLowerCase(); - return messages.fileTypes[ext] ? getRandomItem(messages.fileTypes[ext]) : null; -} - -function formatErrorMessage(failedFiles, isSizeError = false) { - const errorType = isSizeError ? messages.errors.tooBig : messages.errors.generic; - const errorMessage = getRandomItem(errorType.messages); - const errorImage = getRandomItem(errorType.images); - - return [ - errorMessage, - `Failed files: ${failedFiles.join(', ')}`, - '', - `<${errorImage}|image>` - ].join('\n'); -} - -function formatSuccessMessage(userId, files, failedFiles = [], sizeFailedFiles = []) { - const messageLines = []; - - const baseMessage = files.length === 1 ? - messages.success.singleFile : - messages.success.multipleFiles; - messageLines.push(baseMessage.replace('{userId}', userId), ''); - - const fileGroups = new Map(); - files.forEach(file => { - const ext = file.originalName.split('.').pop(); - const typeMessage = getFileTypeMessage(ext); - const key = typeMessage || 'noType'; - - if (!fileGroups.has(key)) { - fileGroups.set(key, []); - } - fileGroups.get(key).push(file); - }); - - fileGroups.forEach((groupFiles, typeMessage) => { - if (typeMessage !== 'noType') { - messageLines.push('', typeMessage); - } - - groupFiles.forEach(file => { - messageLines.push(`• ${file.originalName}: ${file.url}`); - }); - }); - - if (sizeFailedFiles.length > 0) { - messageLines.push(formatErrorMessage(sizeFailedFiles, true)); - } - if (failedFiles.length > 0) { - messageLines.push(formatErrorMessage(failedFiles, false)); - } - - if (files.length > 0) { - messageLines.push('', `_${getRandomItem(messages.success.alternateSuccess)}_`); - } - - return messageLines.join('\n'); -} - -module.exports = { - messages, - getFileTypeMessage, - formatSuccessMessage, - formatErrorMessage, - getRandomItem -}; diff --git a/src/fileUpload.js b/src/fileUpload.js deleted file mode 100644 index 3a3e616..0000000 --- a/src/fileUpload.js +++ /dev/null @@ -1,302 +0,0 @@ -const fetch = require('node-fetch'); -const crypto = require('crypto'); -const logger = require('./config/logger'); -const storage = require('./storage'); -const {generateFileUrl} = require('./utils'); -const path = require('path'); -const { - messages, - formatSuccessMessage, - formatErrorMessage, - getFileTypeMessage -} = require('./config/messages'); - -const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB in bytes -const CONCURRENT_UPLOADS = 3; // Max concurrent uploads (messages) - -const processedMessages = new Map(); -let uploadLimit; - -async function initialize() { - const pLimit = (await import('p-limit')).default; - uploadLimit = pLimit(CONCURRENT_UPLOADS); -} - -// Basic stuff -function isMessageTooOld(eventTs) { - const eventTime = parseFloat(eventTs) * 1000; - return (Date.now() - eventTime) > 24 * 60 * 60 * 1000; -} - -function isMessageProcessed(messageTs) { - return processedMessages.has(messageTs); -} - -function markMessageAsProcessing(messageTs) { - processedMessages.set(messageTs, true); -} - -// File processing -function sanitizeFileName(fileName) { - let sanitized = fileName.replace(/[^a-zA-Z0-9.-]/g, '_'); - return sanitized || `upload_${Date.now()}`; -} - -function generateUniqueFileName(fileName) { - return `${Date.now()}-${crypto.randomBytes(16).toString('hex')}-${sanitizeFileName(fileName)}`; -} - -// upload functionality -async function processFiles(fileMessage, client) { - const uploadedFiles = []; - const failedFiles = []; - const sizeFailedFiles = []; - const fileTypeResponses = new Set(); - - logger.info(`Processing ${fileMessage.files?.length || 0} files`); - - for (const file of fileMessage.files || []) { - try { - if (file.size > MAX_FILE_SIZE) { - sizeFailedFiles.push(file.name); - continue; - } - - // Get file extension message if applicable - const ext = path.extname(file.name).slice(1); - const typeMessage = getFileTypeMessage(ext); - if (typeMessage) fileTypeResponses.add(typeMessage); - - const response = await fetch(file.url_private, { - headers: {Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}`} - }); - - if (!response.ok) throw new Error('Download failed'); - - const buffer = await response.buffer(); - const uniqueFileName = generateUniqueFileName(file.name); - const userDir = `s/${fileMessage.user}`; - - const success = await uploadLimit(() => - storage.uploadToStorage(userDir, uniqueFileName, buffer, file.mimetype) - ); - - if (!success) throw new Error('Upload failed'); - - uploadedFiles.push({ - name: uniqueFileName, - originalName: file.name, - url: generateFileUrl(userDir, uniqueFileName), - contentType: file.mimetype - }); - - } catch (error) { - logger.error(`Failed: ${file.name} - ${error.message}`); - failedFiles.push(file.name); - } - } - - return { - uploadedFiles, - failedFiles, - sizeFailedFiles, - isSizeError: sizeFailedFiles.length > 0 - }; -} - -// Slack interaction -async function addProcessingReaction(client, event, fileMessage) { - try { - await client.reactions.add({ - name: 'beachball', - timestamp: fileMessage.ts, - channel: event.channel_id - }); - } catch (error) { - logger.error('Failed to add reaction:', error.message); - } -} - -async function updateReactions(client, event, fileMessage, totalFiles, failedCount) { - try { - await client.reactions.remove({ - name: 'beachball', - timestamp: fileMessage.ts, - channel: event.channel_id - }); - - // Choose reaction based on how many files failed or well succeded - let reactionName; - if (failedCount === totalFiles) { - reactionName = 'x'; // All files failed - } else if (failedCount > 0) { - reactionName = 'warning'; // Some files failed - } else { - reactionName = 'white_check_mark'; // All files succeeded - } - - await client.reactions.add({ - name: reactionName, - timestamp: fileMessage.ts, - channel: event.channel_id - }); - } catch (error) { - logger.error('Failed to update reactions:', error.message); - } -} - -async function findFileMessage(event, client) { - try { - const fileInfo = await client.files.info({ - file: event.file_id, - include_shares: true - }); - - if (!fileInfo.ok || !fileInfo.file) { - throw new Error('Could not get file info'); - } - - const channelShare = fileInfo.file.shares?.public?.[event.channel_id] || - fileInfo.file.shares?.private?.[event.channel_id]; - - if (!channelShare || !channelShare.length) { - throw new Error('No share info found for this channel'); - } - - // Get the EXACT message using the ts from share info (channelShare) - const messageTs = channelShare[0].ts; - - const messageInfo = await client.conversations.history({ - channel: event.channel_id, - latest: messageTs, - limit: 1, - inclusive: true - }); - - if (!messageInfo.ok || !messageInfo.messages.length) { - throw new Error('Could not find original message'); - } - - return messageInfo.messages[0]; - } catch (error) { - logger.error('Error finding file message:', error); - return null; - } -} - -async function sendResultsMessage(client, channelId, fileMessage, uploadedFiles, failedFiles, sizeFailedFiles) { - try { - let message; - if (uploadedFiles.length === 0 && (failedFiles.length > 0 || sizeFailedFiles.length > 0)) { - // All files failed - use appropriate error type - message = formatErrorMessage( - [...failedFiles, ...sizeFailedFiles], - sizeFailedFiles.length > 0 && failedFiles.length === 0 // Only use size error if all failures are size-related (i hope this is how it makes most sense) - ); - } else { - // Mixed success/failure or all success - message = formatSuccessMessage( - fileMessage.user, - uploadedFiles, - failedFiles, - sizeFailedFiles - ); - } - - const lines = message.split('\n'); - const attachments = []; - let textBuffer = ''; - - for (const line of lines) { - if (line.match(/^<.*\|image>$/)) { - const imageUrl = line.replace(/^<|>$/g, '').replace('|image', ''); - attachments.push({ - image_url: imageUrl, - fallback: 'Error image' - }); - } else { - textBuffer += line + '\n'; - } - } - - await client.chat.postMessage({ - channel: channelId, - thread_ts: fileMessage.ts, - text: textBuffer.trim(), - attachments: attachments.length > 0 ? attachments : undefined - }); - } catch (error) { - logger.error('Failed to send results message:', error); - throw error; - } -} - -async function handleError(client, channelId, fileMessage, reactionAdded) { - if (fileMessage && reactionAdded) { - try { - await client.reactions.remove({ - name: 'beachball', - timestamp: fileMessage.ts, - channel: channelId - }); - } catch (cleanupError) { - if (cleanupError.data.error !== 'no_reaction') { - logger.error('Cleanup error:', cleanupError); - } - } - try { - await client.reactions.add({ - name: 'x', - timestamp: fileMessage.ts, - channel: channelId - }); - } catch (cleanupError) { - logger.error('Cleanup error:', cleanupError); - } - } -} - -async function handleFileUpload(event, client) { - let fileMessage = null; - let reactionAdded = false; - - try { - if (isMessageTooOld(event.event_ts)) return; - - fileMessage = await findFileMessage(event, client); - if (!fileMessage || isMessageProcessed(fileMessage.ts)) return; - - markMessageAsProcessing(fileMessage.ts); - await addProcessingReaction(client, event, fileMessage); - reactionAdded = true; - - const {uploadedFiles, failedFiles, sizeFailedFiles} = await processFiles(fileMessage, client); - - const totalFiles = uploadedFiles.length + failedFiles.length + sizeFailedFiles.length; - const failedCount = failedFiles.length + sizeFailedFiles.length; - - await sendResultsMessage( - client, - event.channel_id, - fileMessage, - uploadedFiles, - failedFiles, - sizeFailedFiles - ); - - await updateReactions( - client, - event, - fileMessage, - totalFiles, - failedCount - ); - - } catch (error) { - logger.error(`Upload failed: ${error.message}`); - await handleError(client, event.channel_id, fileMessage, reactionAdded); - throw error; - } -} - -module.exports = { handleFileUpload, initialize }; diff --git a/src/storage.js b/src/storage.js index 0968212..655f76e 100644 --- a/src/storage.js +++ b/src/storage.js @@ -1,5 +1,4 @@ const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3'); -const path = require('path'); const crypto = require('crypto'); const logger = require('./config/logger'); const {generateFileUrl} = require('./utils');