From 8287105c84adb4b219ce48cd1db3c54d45af6a88 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:52:17 +0200 Subject: [PATCH 01/26] Add discord.js and fs to dependencies --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 479478c..c6de15d 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,10 @@ "@fastify/auth": "^4.2.0", "@fastify/multipart": "^7.3.0", "@fastify/static": "^6.6.0", + "discord.js": "^13.17.1", "dotenv": "^16.0.3", "fastify": "^4.11.0", + "fs": "^0.0.1-security", "knex": "^2.4.0", "lodash": "^4.17.21", "mime-types": "^2.1.35", From 2de2bbb1493d7d4efed985d9448e82c3becfa04d Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:53:00 +0200 Subject: [PATCH 02/26] Init discord bot --- src/DFs/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index a80083c..1ec3eca 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -12,6 +12,9 @@ const DEFAULT_CHUNK_SIZE = 25165824 // 24MB const DEFAULT_ENCRYPTION = 'aes-256-ctr' const DEFAULT_REST_OPTS = { version: 10, timeout: 60000 } const DEFAULT_MAX_UPLOAD_CONCURRENCY = 3 +const { Client, Intents } = require('discord.js'); +const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); +const { Collection } = require('discord.js'); class DiscordFileSystem { constructor(opts) { From 8ab5d042866d52fe3f8354ce71eda3bc07fbe6c0 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:53:22 +0200 Subject: [PATCH 03/26] Login to BOT --- src/DFs/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index 1ec3eca..c60876d 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -15,6 +15,8 @@ const DEFAULT_MAX_UPLOAD_CONCURRENCY = 3 const { Client, Intents } = require('discord.js'); const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); const { Collection } = require('discord.js'); +client.login(process.env.BOT_TOKEN) + class DiscordFileSystem { constructor(opts) { From a502c7bf5eaaf1bec87844f59bced42243001ade Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:53:52 +0200 Subject: [PATCH 04/26] Essential function for fetching files from Discord server --- src/DFs/index.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index c60876d..f54bd3c 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -17,6 +17,39 @@ const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_ const { Collection } = require('discord.js'); client.login(process.env.BOT_TOKEN) +async function fetchMore(channel, limit = 15000) { + if (!channel) { + throw new Error(`Expected channel, got ${typeof channel}.`); + } + if (limit <= 100) { + return channel.messages.fetch({ limit }); + } + + let collection = new Collection(); + let lastId = null; + let options = {}; + let remaining = limit; + + while (remaining > 0) { + options.limit = remaining > 100 ? 100 : remaining; + remaining = remaining > 100 ? remaining - 100 : 0; + + if (lastId) { + options.before = lastId; + } + + let messages = await channel.messages.fetch(options); + + if (!messages.last()) { + break; + } + + collection = collection.concat(messages); + lastId = messages.last().id; + } + + return collection; +} class DiscordFileSystem { constructor(opts) { From a345cf3beaacbb8254e99f46564d2574caf3c34e Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:54:25 +0200 Subject: [PATCH 05/26] Add event ready --- src/DFs/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index f54bd3c..07d3d1e 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -15,6 +15,11 @@ const DEFAULT_MAX_UPLOAD_CONCURRENCY = 3 const { Client, Intents } = require('discord.js'); const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); const { Collection } = require('discord.js'); +let channel_msg_fetched = new Collection(); + +client.on('ready', async () => { + console.log(`Logged in as ${client.user.tag}!`,); + const channel = client.guilds.cache.get(process.env.GUILD_ID).channels.cache.get(process.env.CHANNEL_ID) client.login(process.env.BOT_TOKEN) async function fetchMore(channel, limit = 15000) { From 8cc77c1dcafd6f7e895d7f883b76cf5cf2efdc1d Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:56:14 +0200 Subject: [PATCH 06/26] Verify if cache exist, create it if not, and update var :channel_msg_fetched --- src/DFs/index.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/DFs/index.js b/src/DFs/index.js index 07d3d1e..b9ed9de 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -15,11 +15,44 @@ const DEFAULT_MAX_UPLOAD_CONCURRENCY = 3 const { Client, Intents } = require('discord.js'); const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); const { Collection } = require('discord.js'); -let channel_msg_fetched = new Collection(); +let channel_msg_fetched = [] client.on('ready', async () => { console.log(`Logged in as ${client.user.tag}!`,); const channel = client.guilds.cache.get(process.env.GUILD_ID).channels.cache.get(process.env.CHANNEL_ID) + // Vérifier si le fichier de cache existe et s'il contient des données + let cacheExists = true; + try { + fs.accessSync('cache.json'); + const cacheContent = fs.readFileSync('cache.json', 'utf8'); + if (!cacheContent || cacheContent.length <= 2) { + cacheExists = false; + console.log('The cache file is empty.'); + } + } catch (err) { + cacheExists = false; + console.error('Cache file does not exist, create ... (this operation may take some time depending on the number of files in the ddrive, patience)'); + } + + // If no cache file is found, run update + if (!cacheExists) { + try { + const list = await fetchMore(channel, 1000); //increase if older files are not downloadable + + // Save list to cache file + const messagesToCache = []; + list.forEach((value, key) => { + if (value.attachments.first()) messagesToCache.push(value.attachments.first()) + }); + + channel_msg_fetched = messagesToCache + fs.writeFileSync('cache.json', JSON.stringify(messagesToCache, null, 2), 'utf8'); + + console.log('Initial list loaded from discord server and saved in cache file.'); + } catch (err) { + console.error('Error during initial message retrieval :', err); + } + } else { client.login(process.env.BOT_TOKEN) async function fetchMore(channel, limit = 15000) { From e723cd16ecd134336677dee3cf9a3e0c175bb62f Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:57:00 +0200 Subject: [PATCH 07/26] if cache exist load it to the var: channel_msg_fetched --- src/DFs/index.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index b9ed9de..23b0114 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -53,6 +53,19 @@ client.on('ready', async () => { console.error('Error during initial message retrieval :', err); } } else { + // If it exists, load its contents + try { + const cacheContent = fs.readFileSync('cache.json', 'utf8'); + if (cacheContent) { + const cachedMessages = JSON.parse(cacheContent); + channel_msg_fetched = cachedMessages + + console.log('Initial list loaded from cache file.'); + } + } catch (err) { + console.error('Error reading cache file :', err); + } + } client.login(process.env.BOT_TOKEN) async function fetchMore(channel, limit = 15000) { From 74ed0eee71e0ace3376ea79277181c0e21fb47c4 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:57:21 +0200 Subject: [PATCH 08/26] require fs and dotenv here --- src/DFs/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index 23b0114..01cebc0 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -1,9 +1,11 @@ /* eslint-disable no-restricted-syntax,no-await-in-loop */ +require('dotenv').config({ path: './config/.env' }) const https = require('https') const crypto = require('crypto') const { REST } = require('@discordjs/rest') const _ = require('lodash') const uuid = require('uuid').v4 +const fs = require('fs'); const AsyncStreamProcessorWithConcurrency = require('./lib/AsyncStreamProcessorWithConcurrency') const AsyncStreamProcessor = require('./lib/AsyncStreamProcessor') const StreamChunker = require('./lib/StreamChunker') From ab01b7c089d300825bdccefd1cd3fecd9efa24c3 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:57:52 +0200 Subject: [PATCH 09/26] Update cache every 40min from Discord server --- src/DFs/index.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/DFs/index.js b/src/DFs/index.js index 01cebc0..876758a 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -68,6 +68,26 @@ client.on('ready', async () => { console.error('Error reading cache file :', err); } } + // Update every 40 minutes + setInterval(async () => { + try { + const list = await fetchMore(channel, 15000); //increase if older files are not downloadable + + // Save list to cache file + const messagesToCache = []; + list.forEach((value, key) => { + if (value.attachments.first()) messagesToCache.push(value.attachments.first()) + }); + channel_msg_fetched = messagesToCache + + fs.writeFileSync('cache.json', JSON.stringify(messagesToCache, null, 2), 'utf8'); + + console.log('List updated and saved in cache file.'); + } catch (err) { + console.error('Error updating the list :', err); + } + }, 40 * 60 * 1000); // 40 minutes in milliseconds +}); client.login(process.env.BOT_TOKEN) async function fetchMore(channel, limit = 15000) { From 2140f76431257e8a6755f43c65e8129dc78e535b Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 00:58:35 +0200 Subject: [PATCH 10/26] Get Url of each part from cache --- src/DFs/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DFs/index.js b/src/DFs/index.js index 876758a..7f10d4e 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -220,7 +220,8 @@ class DiscordFileSystem { let headers = {} if (part.start || part.end) headers = { Range: `bytes=${part.start || 0}-${part.end || ''}` } await new Promise((resolve, reject) => { - https.get(part.url, { headers }, (res) => { + let attachment_fix = channel_msg_fetched.find(m => part.url.includes(m.name)) + https.get(attachment_fix.url, { headers }, (res) => { // Handle incoming data chunks from discord server const handleData = async (data) => { // https://nodejs.org/docs/latest-v16.x/api/stream.html#writablewritechunk-encoding-callback From 79c0a03c83a3f1d43785c9cec0731625b93dbd7c Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 01:03:16 +0200 Subject: [PATCH 11/26] Add BOT_TOKEN, CHANNEL_ID, GUILD_ID --- config/.env_sample | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/.env_sample b/config/.env_sample index bdaa32b..0ba82b3 100644 --- a/config/.env_sample +++ b/config/.env_sample @@ -10,3 +10,7 @@ SECRET=myrandomsecret // Put here something if you want to encrypt your files. M PUBLIC_ACCESS=READ_ONLY_FILE // ['READ_ONLY_FILE', 'READ_ONLY_PANEL'] Allow public user to access to download link of file or read only access of whole panel AUTH=admin:admin UPLOAD_CONCURRENCY= + +BOT_TOKEN= // Add a bot to your Discord server and retrieve the token from the Developer Portal at https://discord.com/developers/applications. +CHANNEL_ID= // The channel ID where the file will be uploaded, is the same as the webhook's channel. +GUILD_ID= // The GUILD ID where the file will be uploaded \ No newline at end of file From 740baa8ef36c0815be8e55eb75dc68bfa3dac42a Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 01:05:58 +0200 Subject: [PATCH 12/26] Support createdAt sort --- src/http/html/index.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/http/html/index.js b/src/http/html/index.js index 19991a3..0a5e05b 100644 --- a/src/http/html/index.js +++ b/src/http/html/index.js @@ -33,12 +33,15 @@ function makeid(length) { } function sort(arr, key) { - return arr.sort((a, b) => { - if (a[key] < b[key]) return -1 - if (a[key] > b[key]) return 1 - - return 0 - }) + if (key === "createdAt") { + return arr.sort((b, a) => new Date(a[key]) - new Date(b[key])); + } else { + return arr.sort((a, b) => { + if (a[key] < b[key]) return -1 + if (a[key] > b[key]) return 1 + return 0 + }) + } } function download(url) { const a = document.createElement('a') From defa974ad8c23b4622c18515202fc2c58775b321 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 01:06:14 +0200 Subject: [PATCH 13/26] Add support for sorting by createdAt --- src/http/html/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/html/index.js b/src/http/html/index.js index 0a5e05b..d1a7aad 100644 --- a/src/http/html/index.js +++ b/src/http/html/index.js @@ -139,7 +139,7 @@ async function refreshTable() { for (const directory of sort(body.child.directories, 'name')) { tbody.appendChild(prepareFolderTR(directory)) } - for (const file of sort(body.child.files, 'name')) { + for (const file of sort(body.child.files, 'name')) { //replace "name" by "createdAt" to filter by date tbody.appendChild(prepareFileTR(file)) } } From c98a3c62c6fe3317a066e9ec08a4f4ef3bf47c15 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 01:15:51 +0200 Subject: [PATCH 14/26] increase the limit of fetched file on Discord server --- src/DFs/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DFs/index.js b/src/DFs/index.js index 7f10d4e..8e6a53c 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -39,7 +39,7 @@ client.on('ready', async () => { // If no cache file is found, run update if (!cacheExists) { try { - const list = await fetchMore(channel, 1000); //increase if older files are not downloadable + const list = await fetchMore(channel, 15000); //increase if older files are not downloadable // Save list to cache file const messagesToCache = []; From 9a5ba8aa65e80829a60b4e2d3b2046f0269cbf66 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 01:16:52 +0200 Subject: [PATCH 15/26] Update README > Section .env --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 379622b..8733447 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,14 @@ PUBLIC_ACCESS=READ_ONLY_FILE # If you want to give read only access to panel or UPLOAD_CONCURRENCY=3 # ddrive will upload this many chunks in parallel to discord. If you have fast internet increasing it will significantly increase performance at cost of cpu/disk usage +BOT_TOKEN= # Add a bot to your Discord server and retrieve the token from the Developer Portal at https://discord.com/developers/applications. +CHANNEL_ID= # The channel ID where the file will be uploaded, is the same as the webhook's channel. +GUILD_ID= # The GUILD ID where the file will be uploaded ``` +src/DFs/index.js line 42 AND line 74 : +`const list = await fetchMore(channel, 15000); ` + +Increase the number if older files are not downloadable, like 20000 or 30000. **If you change it, delete the cache.json before restart** ### Run using docker ```shell From 6c161a9cf88d8ace4bad139432d15b33a12d607b Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 10:25:54 +0200 Subject: [PATCH 16/26] Other url in case of recently added file --- src/DFs/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DFs/index.js b/src/DFs/index.js index 8e6a53c..1538102 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -221,7 +221,7 @@ class DiscordFileSystem { if (part.start || part.end) headers = { Range: `bytes=${part.start || 0}-${part.end || ''}` } await new Promise((resolve, reject) => { let attachment_fix = channel_msg_fetched.find(m => part.url.includes(m.name)) - https.get(attachment_fix.url, { headers }, (res) => { + https.get(attachment_fix.url || part.url, { headers }, (res) => { // Handle incoming data chunks from discord server const handleData = async (data) => { // https://nodejs.org/docs/latest-v16.x/api/stream.html#writablewritechunk-encoding-callback From b2451c57b0dff2a95db23430e113bfe88fd94fe8 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 17:17:20 +0200 Subject: [PATCH 17/26] Add total size of files, div --- src/http/html/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/http/html/index.html b/src/http/html/index.html index 328a1a7..9723775 100644 --- a/src/http/html/index.html +++ b/src/http/html/index.html @@ -66,6 +66,7 @@ DDrive File Manager +
Total storage:
From 724460224a8bbd658c094a7de0b82c97914e326e Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Sun, 21 Apr 2024 17:18:11 +0200 Subject: [PATCH 18/26] add count systeme for total size of files --- src/http/html/index.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/http/html/index.html b/src/http/html/index.html index 9723775..36c3344 100644 --- a/src/http/html/index.html +++ b/src/http/html/index.html @@ -247,7 +247,14 @@ // // Create dynamic TR for files // + let totalSize = 0 + function prepareFileTR(data) { + totalSize = totalSize + data.size + // Calculate the total size + const totalSizeElement = document.getElementById('totalsize'); + totalSizeElement.innerText = humanReadableSize(totalSize); + const tr = document.createElement('tr') tr.innerHTML = ` From a9a0a61e44108eee4e483cbc33551b6d228a288d Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Tue, 23 Apr 2024 19:23:14 +0200 Subject: [PATCH 19/26] add ? to catch error --- src/DFs/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DFs/index.js b/src/DFs/index.js index 1538102..407fabd 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -221,7 +221,7 @@ class DiscordFileSystem { if (part.start || part.end) headers = { Range: `bytes=${part.start || 0}-${part.end || ''}` } await new Promise((resolve, reject) => { let attachment_fix = channel_msg_fetched.find(m => part.url.includes(m.name)) - https.get(attachment_fix.url || part.url, { headers }, (res) => { + https.get(attachment_fix?.url || part.url, { headers }, (res) => { // Handle incoming data chunks from discord server const handleData = async (data) => { // https://nodejs.org/docs/latest-v16.x/api/stream.html#writablewritechunk-encoding-callback From 93294a14c2590f177c1346fa336ff38d1db22af1 Mon Sep 17 00:00:00 2001 From: Matrixx-Js <62359510+Matrixx-Js@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:01:20 +0200 Subject: [PATCH 20/26] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8733447..c5d7bcf 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,12 @@ src/DFs/index.js line 42 AND line 74 : Increase the number if older files are not downloadable, like 20000 or 30000. **If you change it, delete the cache.json before restart** + +⚠️ You need to enable MESSAGE_INTENT in developer portal of the BOT +![image](https://github.com/user-attachments/assets/aaef7b9f-8055-42eb-87ac-973fcb43799c) +https://discord.com/developers/applications/ + + ### Run using docker ```shell docker run -rm -it -p 8080:8080 \ From 3a151e3f099c563e115974f8eb48f5cbfdcd8585 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Wed, 31 Jul 2024 02:17:51 +0200 Subject: [PATCH 21/26] New VERSION v5.0.1 (faster download process: no bot) --- config/.env_sample | 6 +- package.json | 3 +- src/DFs/cdn-package/Discord/Discord.d.ts | 8 ++ src/DFs/cdn-package/Discord/Discord.js | 58 +++++++++ src/DFs/cdn-package/Discord/Discord.js.map | 1 + .../cdn-package/Discord/Types/ELinkIssue.d.ts | 8 ++ .../cdn-package/Discord/Types/ELinkIssue.js | 12 ++ .../Discord/Types/ELinkIssue.js.map | 1 + .../Discord/Types/ETokenIssue.d.ts | 8 ++ .../cdn-package/Discord/Types/ETokenIssue.js | 12 ++ .../Discord/Types/ETokenIssue.js.map | 1 + .../cdn-package/Discord/Types/ILinkData.d.ts | 6 + .../cdn-package/Discord/Types/ILinkData.js | 3 + .../Discord/Types/ILinkData.js.map | 1 + .../Discord/Types/IParsedLink.d.ts | 7 + .../cdn-package/Discord/Types/IParsedLink.js | 3 + .../Discord/Types/IParsedLink.js.map | 1 + .../Discord/Types/IRefreshUrlsRes.d.ts | 7 + .../Discord/Types/IRefreshUrlsRes.js | 3 + .../Discord/Types/IRefreshUrlsRes.js.map | 1 + .../Discord/Utils/GetUTF8Base64.d.ts | 2 + .../Discord/Utils/GetUTF8Base64.js | 19 +++ .../Discord/Utils/GetUTF8Base64.js.map | 1 + .../cdn-package/Discord/Utils/ParseLink.d.ts | 3 + .../cdn-package/Discord/Utils/ParseLink.js | 30 +++++ .../Discord/Utils/ParseLink.js.map | 1 + .../Discord/Utils/VerifyToken.d.ts | 2 + .../cdn-package/Discord/Utils/VerifyToken.js | 47 +++++++ .../Discord/Utils/VerifyToken.js.map | 1 + src/DFs/index.js | 122 +++--------------- 30 files changed, 268 insertions(+), 110 deletions(-) create mode 100644 src/DFs/cdn-package/Discord/Discord.d.ts create mode 100644 src/DFs/cdn-package/Discord/Discord.js create mode 100644 src/DFs/cdn-package/Discord/Discord.js.map create mode 100644 src/DFs/cdn-package/Discord/Types/ELinkIssue.d.ts create mode 100644 src/DFs/cdn-package/Discord/Types/ELinkIssue.js create mode 100644 src/DFs/cdn-package/Discord/Types/ELinkIssue.js.map create mode 100644 src/DFs/cdn-package/Discord/Types/ETokenIssue.d.ts create mode 100644 src/DFs/cdn-package/Discord/Types/ETokenIssue.js create mode 100644 src/DFs/cdn-package/Discord/Types/ETokenIssue.js.map create mode 100644 src/DFs/cdn-package/Discord/Types/ILinkData.d.ts create mode 100644 src/DFs/cdn-package/Discord/Types/ILinkData.js create mode 100644 src/DFs/cdn-package/Discord/Types/ILinkData.js.map create mode 100644 src/DFs/cdn-package/Discord/Types/IParsedLink.d.ts create mode 100644 src/DFs/cdn-package/Discord/Types/IParsedLink.js create mode 100644 src/DFs/cdn-package/Discord/Types/IParsedLink.js.map create mode 100644 src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.d.ts create mode 100644 src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js create mode 100644 src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js.map create mode 100644 src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.d.ts create mode 100644 src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js create mode 100644 src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js.map create mode 100644 src/DFs/cdn-package/Discord/Utils/ParseLink.d.ts create mode 100644 src/DFs/cdn-package/Discord/Utils/ParseLink.js create mode 100644 src/DFs/cdn-package/Discord/Utils/ParseLink.js.map create mode 100644 src/DFs/cdn-package/Discord/Utils/VerifyToken.d.ts create mode 100644 src/DFs/cdn-package/Discord/Utils/VerifyToken.js create mode 100644 src/DFs/cdn-package/Discord/Utils/VerifyToken.js.map diff --git a/config/.env_sample b/config/.env_sample index 0ba82b3..3d0bc93 100644 --- a/config/.env_sample +++ b/config/.env_sample @@ -1,8 +1,10 @@ # Required + DATABASE_URL=postgres://ddrive:ddrive@127.0.0.1:5429/ddrive // Postgres DB URL WEBHOOKS= // ',' seperated urls # Optional + PORT=3000 // HTTP Server port REQUEST_TIMEOUT=60000 // Request timeout - Increase if you have slow internet connection CHUNK_SIZE=25165824 // 24MB - Can't increase. Webhooks are max allowed to 25MB @@ -11,6 +13,4 @@ PUBLIC_ACCESS=READ_ONLY_FILE // ['READ_ONLY_FILE', 'READ_ONLY_PANEL'] Allow publ AUTH=admin:admin UPLOAD_CONCURRENCY= -BOT_TOKEN= // Add a bot to your Discord server and retrieve the token from the Developer Portal at https://discord.com/developers/applications. -CHANNEL_ID= // The channel ID where the file will be uploaded, is the same as the webhook's channel. -GUILD_ID= // The GUILD ID where the file will be uploaded \ No newline at end of file +USER_TOKEN= // Put real Discord User account Token (see README.md for steps) diff --git a/package.json b/package.json index c6de15d..175019d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@forscht/ddrive", - "version": "4.3.0", + "version": "5.0.1", "description": "A lightweight cloud storage system using discord as storage device written in nodejs", "main": "src/index.js", "author": "Darshan Patel (https://github.com/forscht/ddrive)", @@ -40,7 +40,6 @@ "@fastify/auth": "^4.2.0", "@fastify/multipart": "^7.3.0", "@fastify/static": "^6.6.0", - "discord.js": "^13.17.1", "dotenv": "^16.0.3", "fastify": "^4.11.0", "fs": "^0.0.1-security", diff --git a/src/DFs/cdn-package/Discord/Discord.d.ts b/src/DFs/cdn-package/Discord/Discord.d.ts new file mode 100644 index 0000000..ae0a0e0 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Discord.d.ts @@ -0,0 +1,8 @@ +import IConfig from "../Types/IConfig"; +declare class Discord { + private config; + constructor(config: IConfig); + fetchLatestLink(oldLink: string): Promise; + private getHTTPConfig; +} +export default Discord; diff --git a/src/DFs/cdn-package/Discord/Discord.js b/src/DFs/cdn-package/Discord/Discord.js new file mode 100644 index 0000000..d037154 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Discord.js @@ -0,0 +1,58 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const ELinkIssue_1 = __importDefault(require("./Types/ELinkIssue")); +const ParseLink_1 = __importDefault(require("./Utils/ParseLink")); +const axios_1 = __importDefault(require("axios")); +class Discord { + constructor(config) { + this.config = config; + } + ; + fetchLatestLink(oldLink) { + return __awaiter(this, void 0, void 0, function* () { + if (!oldLink.includes("https://")) + oldLink = `https://cdn.discordapp.com/${oldLink}`; + const linkData = (0, ParseLink_1.default)(oldLink); + if (linkData.error != ELinkIssue_1.default.NONE) { + throw new Error(linkData.error); + } + try { + const { data } = yield axios_1.default.post("https://discord.com/api/v9/attachments/refresh-urls", { + attachment_urls: [oldLink] + }, this.getHTTPConfig()); + let response = data; + if (!response || !response.refreshed_urls || response.refreshed_urls.length == 0) { + console.log("response:", data); + throw new Error("Unexpected Discord response."); + } + let updatedLink = response.refreshed_urls[0].refreshed; + return updatedLink; + } + catch (ex) { + console.log(ex); + } + return ""; + }); + } + getHTTPConfig() { + return { + headers: { + "Authorization": this.config.TOKEN + } + }; + } +} +exports.default = Discord; +//# sourceMappingURL=Discord.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Discord.js.map b/src/DFs/cdn-package/Discord/Discord.js.map new file mode 100644 index 0000000..bd738fa --- /dev/null +++ b/src/DFs/cdn-package/Discord/Discord.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Discord.js","sourceRoot":"","sources":["../../src/Discord/Discord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AACA,oEAA4C;AAE5C,kEAA0C;AAG1C,kDAAiD;AAEjD,MAAM,OAAO;IACT,YAAoB,MAAe;QAAf,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAAA,CAAC;IAU3B,eAAe,CAAC,OAAe;;YACxC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC7B,OAAO,GAAG,8BAA8B,OAAO,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,IAAA,mBAAS,EAAC,OAAO,CAAC,CAAC;YACpC,IAAI,QAAQ,CAAC,KAAK,IAAI,oBAAU,CAAC,IAAI,EAAE;gBACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aACnC;YAED,IAAI;gBACA,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,qDAAqD,EAAE;oBACrF,eAAe,EAAE,CAAC,OAAO,CAAC;iBAC7B,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;gBAEzB,IAAI,QAAQ,GAAG,IAAuB,CAAC;gBACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,cAAc,IAAI,QAAQ,CAAC,cAAc,CAAC,MAAM,IAAI,CAAC,EAAE;oBAC9E,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;iBACnD;gBAED,IAAI,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACvD,OAAO,WAAW,CAAC;aAEtB;YAAC,OAAO,EAAE,EAAE;gBACT,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;aAClB;YAED,OAAO,EAAE,CAAC;QACd,CAAC;KAAA;IAEO,aAAa;QACjB,OAAO;YACH,OAAO,EAAE;gBACL,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;aACrC;SACJ,CAAA;IACL,CAAC;CACJ;AAED,kBAAe,OAAO,CAAC"} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ELinkIssue.d.ts b/src/DFs/cdn-package/Discord/Types/ELinkIssue.d.ts new file mode 100644 index 0000000..d464634 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ELinkIssue.d.ts @@ -0,0 +1,8 @@ +declare enum ELinkIssue { + NONE = "", + INVALID_SLASH_AMOUNT = "Invalid link due to not the right amount of forward slashes", + CHANNEL_ID_NAN = "The Channel ID should be a valid integer.", + FILE_ID_NAN = "The File ID should be a valid integer.", + FILENAME_NO_DOT = "The File Name should include at least one dot." +} +export default ELinkIssue; diff --git a/src/DFs/cdn-package/Discord/Types/ELinkIssue.js b/src/DFs/cdn-package/Discord/Types/ELinkIssue.js new file mode 100644 index 0000000..0b1b056 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ELinkIssue.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ELinkIssue; +(function (ELinkIssue) { + ELinkIssue["NONE"] = ""; + ELinkIssue["INVALID_SLASH_AMOUNT"] = "Invalid link due to not the right amount of forward slashes"; + ELinkIssue["CHANNEL_ID_NAN"] = "The Channel ID should be a valid integer."; + ELinkIssue["FILE_ID_NAN"] = "The File ID should be a valid integer."; + ELinkIssue["FILENAME_NO_DOT"] = "The File Name should include at least one dot."; +})(ELinkIssue || (ELinkIssue = {})); +exports.default = ELinkIssue; +//# sourceMappingURL=ELinkIssue.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ELinkIssue.js.map b/src/DFs/cdn-package/Discord/Types/ELinkIssue.js.map new file mode 100644 index 0000000..232b8d5 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ELinkIssue.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ELinkIssue.js","sourceRoot":"","sources":["../../../src/Discord/Types/ELinkIssue.ts"],"names":[],"mappings":";;AAAA,IAAK,UAMJ;AAND,WAAK,UAAU;IACX,uBAAS,CAAA;IACT,kGAAoF,CAAA;IACpF,0EAA4D,CAAA;IAC5D,oEAAsD,CAAA;IACtD,gFAAkE,CAAA;AACtE,CAAC,EANI,UAAU,KAAV,UAAU,QAMd;AAED,kBAAe,UAAU,CAAC"} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ETokenIssue.d.ts b/src/DFs/cdn-package/Discord/Types/ETokenIssue.d.ts new file mode 100644 index 0000000..9ca8457 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ETokenIssue.d.ts @@ -0,0 +1,8 @@ +declare enum ETokenIssue { + NONE = "", + INVALID_AMOUNT_OF_DOTS = "The Token has an invalid amount of dots.", + NON_BASE64_UTF8 = "The ID part of the token is not valid", + ID_NOT_A_NUMBER = "THe ID part of the token is not a number", + ID_TOO_SHORT = "The ID part of the token is too short" +} +export default ETokenIssue; diff --git a/src/DFs/cdn-package/Discord/Types/ETokenIssue.js b/src/DFs/cdn-package/Discord/Types/ETokenIssue.js new file mode 100644 index 0000000..b8d9fc1 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ETokenIssue.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var ETokenIssue; +(function (ETokenIssue) { + ETokenIssue["NONE"] = ""; + ETokenIssue["INVALID_AMOUNT_OF_DOTS"] = "The Token has an invalid amount of dots."; + ETokenIssue["NON_BASE64_UTF8"] = "The ID part of the token is not valid"; + ETokenIssue["ID_NOT_A_NUMBER"] = "THe ID part of the token is not a number"; + ETokenIssue["ID_TOO_SHORT"] = "The ID part of the token is too short"; +})(ETokenIssue || (ETokenIssue = {})); +exports.default = ETokenIssue; +//# sourceMappingURL=ETokenIssue.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ETokenIssue.js.map b/src/DFs/cdn-package/Discord/Types/ETokenIssue.js.map new file mode 100644 index 0000000..c8ccab0 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ETokenIssue.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ETokenIssue.js","sourceRoot":"","sources":["../../../src/Discord/Types/ETokenIssue.ts"],"names":[],"mappings":";;AAAA,IAAK,WAOJ;AAPD,WAAK,WAAW;IACZ,wBAAS,CAAA;IACT,kFAAmE,CAAA;IACnE,wEAAyD,CAAA;IACzD,2EAA4D,CAAA;IAC5D,qEAAsD,CAAA;AAE1D,CAAC,EAPI,WAAW,KAAX,WAAW,QAOf;AAED,kBAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ILinkData.d.ts b/src/DFs/cdn-package/Discord/Types/ILinkData.d.ts new file mode 100644 index 0000000..7d793cb --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ILinkData.d.ts @@ -0,0 +1,6 @@ +interface ILinkData { + channelID: bigint; + fileID: bigint; + fileName: string; +} +export default ILinkData; diff --git a/src/DFs/cdn-package/Discord/Types/ILinkData.js b/src/DFs/cdn-package/Discord/Types/ILinkData.js new file mode 100644 index 0000000..f2ba6bc --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ILinkData.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=ILinkData.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/ILinkData.js.map b/src/DFs/cdn-package/Discord/Types/ILinkData.js.map new file mode 100644 index 0000000..2c45335 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/ILinkData.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ILinkData.js","sourceRoot":"","sources":["../../../src/Discord/Types/ILinkData.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/IParsedLink.d.ts b/src/DFs/cdn-package/Discord/Types/IParsedLink.d.ts new file mode 100644 index 0000000..c766e5e --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IParsedLink.d.ts @@ -0,0 +1,7 @@ +import ELinkIssue from "./ELinkIssue"; +import ILinkData from "./ILinkData"; +interface IParsedLink { + error: ELinkIssue; + data?: ILinkData; +} +export default IParsedLink; diff --git a/src/DFs/cdn-package/Discord/Types/IParsedLink.js b/src/DFs/cdn-package/Discord/Types/IParsedLink.js new file mode 100644 index 0000000..b28159d --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IParsedLink.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=IParsedLink.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/IParsedLink.js.map b/src/DFs/cdn-package/Discord/Types/IParsedLink.js.map new file mode 100644 index 0000000..68f086f --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IParsedLink.js.map @@ -0,0 +1 @@ +{"version":3,"file":"IParsedLink.js","sourceRoot":"","sources":["../../../src/Discord/Types/IParsedLink.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.d.ts b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.d.ts new file mode 100644 index 0000000..5e1153f --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.d.ts @@ -0,0 +1,7 @@ +interface IRefreshUrlsRes { + refreshed_urls: Array<{ + original: string; + refreshed: string; + }>; +} +export default IRefreshUrlsRes; diff --git a/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js new file mode 100644 index 0000000..94db19d --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=IRefreshUrlsRes.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js.map b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js.map new file mode 100644 index 0000000..ade92a9 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Types/IRefreshUrlsRes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"IRefreshUrlsRes.js","sourceRoot":"","sources":["../../../src/Discord/Types/IRefreshUrlsRes.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.d.ts b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.d.ts new file mode 100644 index 0000000..1de66be --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.d.ts @@ -0,0 +1,2 @@ +declare function GetUTF8Base64(input: string): string | null; +export default GetUTF8Base64; diff --git a/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js new file mode 100644 index 0000000..e9f3d1d --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function hasNonUTF8Characters(str) { + return /[^\x00-\x7F]/.test(str); +} +function GetUTF8Base64(input) { + try { + const buf = Buffer.from(input, "base64"); + const decodedBase64 = buf.toString(); + if (hasNonUTF8Characters(decodedBase64)) + throw new Error("Contains Non UTF-8 character(s)."); + return decodedBase64; + } + catch (ex) { + return null; + } +} +exports.default = GetUTF8Base64; +//# sourceMappingURL=GetUTF8Base64.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js.map b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js.map new file mode 100644 index 0000000..dda2a0a --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/GetUTF8Base64.js.map @@ -0,0 +1 @@ +{"version":3,"file":"GetUTF8Base64.js","sourceRoot":"","sources":["../../../src/Discord/Utils/GetUTF8Base64.ts"],"names":[],"mappings":";;AAAA,SAAS,oBAAoB,CAAC,GAAW;IACvC,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAQD,SAAS,aAAa,CAAC,KAAa;IAChC,IAAI;QACA,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,oBAAoB,CAAC,aAAa,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;QAEvD,OAAO,aAAa,CAAC;KACxB;IAAC,OAAO,EAAE,EAAE;QACT,OAAO,IAAI,CAAC;KACf;AACL,CAAC;AAED,kBAAe,aAAa,CAAC"} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/ParseLink.d.ts b/src/DFs/cdn-package/Discord/Utils/ParseLink.d.ts new file mode 100644 index 0000000..a1400a1 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/ParseLink.d.ts @@ -0,0 +1,3 @@ +import IParsedLink from "../Types/IParsedLink"; +declare function ParseLink(input: string): IParsedLink; +export default ParseLink; diff --git a/src/DFs/cdn-package/Discord/Utils/ParseLink.js b/src/DFs/cdn-package/Discord/Utils/ParseLink.js new file mode 100644 index 0000000..982fd8d --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/ParseLink.js @@ -0,0 +1,30 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const ELinkIssue_1 = __importDefault(require("../Types/ELinkIssue")); +function ParseLink(input) { + if (input.includes("?")) + input = input.split("?")[0]; + if (input.includes("attachments/")) + input = input.split("attachments/")[1]; + let slashParts = input.split("/"); + if (slashParts.length != 3) + return { error: ELinkIssue_1.default.INVALID_SLASH_AMOUNT }; + const [channelID, fileID, fileName] = slashParts; + if (isNaN(Number(channelID))) + return { error: ELinkIssue_1.default.CHANNEL_ID_NAN }; + if (isNaN(Number(fileID))) + return { error: ELinkIssue_1.default.FILE_ID_NAN }; + return { + error: ELinkIssue_1.default.NONE, + data: { + channelID: BigInt(channelID), + fileID: BigInt(fileID), + fileName, + }, + }; +} +exports.default = ParseLink; +//# sourceMappingURL=ParseLink.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/ParseLink.js.map b/src/DFs/cdn-package/Discord/Utils/ParseLink.js.map new file mode 100644 index 0000000..481fb65 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/ParseLink.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ParseLink.js","sourceRoot":"","sources":["../../../src/Discord/Utils/ParseLink.ts"],"names":[],"mappings":";;;;;AAAA,qEAA6C;AAS7C,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,IAAI,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,oBAAU,CAAC,oBAAoB,EAAE,CAAC;IAE9E,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC;IAEjD,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,oBAAU,CAAC,cAAc,EAAE,CAAC;IAE1E,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,oBAAU,CAAC,WAAW,EAAE,CAAC;IAOpE,OAAO;QACL,KAAK,EAAE,oBAAU,CAAC,IAAI;QACtB,IAAI,EAAE;YACJ,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;YAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;YACtB,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED,kBAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/VerifyToken.d.ts b/src/DFs/cdn-package/Discord/Utils/VerifyToken.d.ts new file mode 100644 index 0000000..9a3b991 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/VerifyToken.d.ts @@ -0,0 +1,2 @@ +declare function VerifyToken(token: string, performStatic?: boolean): Promise; +export default VerifyToken; diff --git a/src/DFs/cdn-package/Discord/Utils/VerifyToken.js b/src/DFs/cdn-package/Discord/Utils/VerifyToken.js new file mode 100644 index 0000000..cc1d0c3 --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/VerifyToken.js @@ -0,0 +1,47 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const ETokenIssue_1 = __importDefault(require("../Types/ETokenIssue")); +const GetUTF8Base64_1 = __importDefault(require("./GetUTF8Base64")); +function staticVerifyToken(token) { + let tokenSplitByDots = token.split("."); + if (tokenSplitByDots.length != 3) + return ETokenIssue_1.default.INVALID_AMOUNT_OF_DOTS; + const decodedID = (0, GetUTF8Base64_1.default)(tokenSplitByDots[0]); + if (!decodedID) + return ETokenIssue_1.default.NON_BASE64_UTF8; + if (isNaN(Number(decodedID))) + return ETokenIssue_1.default.ID_NOT_A_NUMBER; + if (decodedID.length < 17) + return ETokenIssue_1.default.ID_TOO_SHORT; + return ETokenIssue_1.default.NONE; +} +function VerifyToken(token, performStatic = true) { + return __awaiter(this, void 0, void 0, function* () { + let isValidToken = true; + if (performStatic) { + const tokenIssue = staticVerifyToken(token); + isValidToken = tokenIssue == ETokenIssue_1.default.NONE; + if (!isValidToken) { + console.log(`[ERROR] VerifyToken(): ${tokenIssue}`); + } + } + else { + throw new Error("Non Static check is not yet implemented."); + } + return isValidToken; + }); +} +exports.default = VerifyToken; +//# sourceMappingURL=VerifyToken.js.map \ No newline at end of file diff --git a/src/DFs/cdn-package/Discord/Utils/VerifyToken.js.map b/src/DFs/cdn-package/Discord/Utils/VerifyToken.js.map new file mode 100644 index 0000000..992e7ef --- /dev/null +++ b/src/DFs/cdn-package/Discord/Utils/VerifyToken.js.map @@ -0,0 +1 @@ +{"version":3,"file":"VerifyToken.js","sourceRoot":"","sources":["../../../src/Discord/Utils/VerifyToken.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,uEAA+C;AAC/C,oEAA4C;AAE5C,SAAS,iBAAiB,CAAC,KAAa;IAEpC,IAAI,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,qBAAW,CAAC,sBAAsB,CAAC;IAG5E,MAAM,SAAS,GAAG,IAAA,uBAAa,EAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,IAAI,CAAC,SAAS;QAAE,OAAO,qBAAW,CAAC,eAAe,CAAC;IAInD,IAAI,KAAK,CAAE,MAAM,CAAC,SAAS,CAAC,CAAE;QAAE,OAAO,qBAAW,CAAC,eAAe,CAAC;IAGnE,IAAI,SAAS,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,qBAAW,CAAC,YAAY,CAAC;IAE3D,OAAO,qBAAW,CAAC,IAAI,CAAC;AAC5B,CAAC;AAWD,SAAe,WAAW,CAAC,KAAa,EAAE,gBAAyB,IAAI;;QACnE,IAAI,YAAY,GAAY,IAAI,CAAC;QAEjC,IAAI,aAAa,EAAE;YACf,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC5C,YAAY,GAAG,UAAU,IAAI,qBAAW,CAAC,IAAI,CAAC;YAC9C,IAAI,CAAC,YAAY,EAAE;gBACf,OAAO,CAAC,GAAG,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAA;aACtD;SACJ;aAAM;YACH,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;SAC/D;QAED,OAAO,YAAY,CAAC;IACxB,CAAC;CAAA;AAED,kBAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/src/DFs/index.js b/src/DFs/index.js index 407fabd..15876ee 100644 --- a/src/DFs/index.js +++ b/src/DFs/index.js @@ -14,115 +14,25 @@ const DEFAULT_CHUNK_SIZE = 25165824 // 24MB const DEFAULT_ENCRYPTION = 'aes-256-ctr' const DEFAULT_REST_OPTS = { version: 10, timeout: 60000 } const DEFAULT_MAX_UPLOAD_CONCURRENCY = 3 -const { Client, Intents } = require('discord.js'); -const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); -const { Collection } = require('discord.js'); -let channel_msg_fetched = [] -client.on('ready', async () => { - console.log(`Logged in as ${client.user.tag}!`,); - const channel = client.guilds.cache.get(process.env.GUILD_ID).channels.cache.get(process.env.CHANNEL_ID) - // Vérifier si le fichier de cache existe et s'il contient des données - let cacheExists = true; - try { - fs.accessSync('cache.json'); - const cacheContent = fs.readFileSync('cache.json', 'utf8'); - if (!cacheContent || cacheContent.length <= 2) { - cacheExists = false; - console.log('The cache file is empty.'); - } - } catch (err) { - cacheExists = false; - console.error('Cache file does not exist, create ... (this operation may take some time depending on the number of files in the ddrive, patience)'); - } +const DiscordCDN = require("./cdn-package/Discord/Discord").default - // If no cache file is found, run update - if (!cacheExists) { - try { - const list = await fetchMore(channel, 15000); //increase if older files are not downloadable - // Save list to cache file - const messagesToCache = []; - list.forEach((value, key) => { - if (value.attachments.first()) messagesToCache.push(value.attachments.first()) - }); - channel_msg_fetched = messagesToCache - fs.writeFileSync('cache.json', JSON.stringify(messagesToCache, null, 2), 'utf8'); +let config = { TOKEN: process.env.USER_TOKEN } +let discord = new DiscordCDN(config); - console.log('Initial list loaded from discord server and saved in cache file.'); - } catch (err) { - console.error('Error during initial message retrieval :', err); - } - } else { - // If it exists, load its contents - try { - const cacheContent = fs.readFileSync('cache.json', 'utf8'); - if (cacheContent) { - const cachedMessages = JSON.parse(cacheContent); - channel_msg_fetched = cachedMessages - - console.log('Initial list loaded from cache file.'); - } - } catch (err) { - console.error('Error reading cache file :', err); - } - } - // Update every 40 minutes - setInterval(async () => { - try { - const list = await fetchMore(channel, 15000); //increase if older files are not downloadable - - // Save list to cache file - const messagesToCache = []; - list.forEach((value, key) => { - if (value.attachments.first()) messagesToCache.push(value.attachments.first()) - }); - channel_msg_fetched = messagesToCache - - fs.writeFileSync('cache.json', JSON.stringify(messagesToCache, null, 2), 'utf8'); - - console.log('List updated and saved in cache file.'); - } catch (err) { - console.error('Error updating the list :', err); - } - }, 40 * 60 * 1000); // 40 minutes in milliseconds -}); -client.login(process.env.BOT_TOKEN) - -async function fetchMore(channel, limit = 15000) { - if (!channel) { - throw new Error(`Expected channel, got ${typeof channel}.`); - } - if (limit <= 100) { - return channel.messages.fetch({ limit }); +async function refreshLink(linkToRefresh) { + try { + let link = await discord.fetchLatestLink(linkToRefresh) + return link; + } catch (ex) { + console.error(ex.message); + return false } +} - let collection = new Collection(); - let lastId = null; - let options = {}; - let remaining = limit; - - while (remaining > 0) { - options.limit = remaining > 100 ? 100 : remaining; - remaining = remaining > 100 ? remaining - 100 : 0; - - if (lastId) { - options.before = lastId; - } - - let messages = await channel.messages.fetch(options); - - if (!messages.last()) { - break; - } - - collection = collection.concat(messages); - lastId = messages.last().id; - } - return collection; -} class DiscordFileSystem { constructor(opts) { @@ -219,9 +129,11 @@ class DiscordFileSystem { for (const part of parts) { let headers = {} if (part.start || part.end) headers = { Range: `bytes=${part.start || 0}-${part.end || ''}` } - await new Promise((resolve, reject) => { - let attachment_fix = channel_msg_fetched.find(m => part.url.includes(m.name)) - https.get(attachment_fix?.url || part.url, { headers }, (res) => { + await new Promise(async (resolve, reject) => { + + let attachment_fixURL = await refreshLink(part.url) + if (!attachment_fixURL) return reject("Can't generate new url for discord-files attachments"); + https.get(attachment_fixURL, { headers }, (res) => { // Handle incoming data chunks from discord server const handleData = async (data) => { // https://nodejs.org/docs/latest-v16.x/api/stream.html#writablewritechunk-encoding-callback @@ -261,7 +173,7 @@ class DiscordFileSystem { // Encrypt the data if secret is provided let iv let encrypted - if (this.secret)({ iv, encrypted } = this._encrypt(this.secret, data)) + if (this.secret) ({ iv, encrypted } = this._encrypt(this.secret, data)) // Upload file to discord const part = { name: uuid(), data: encrypted || data } const { attachments: [attachment] } = await this._uploadFile(part) From 6ad58a431b9df59b7b2f98283ba7165248658635 Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Wed, 31 Jul 2024 02:25:59 +0200 Subject: [PATCH 22/26] New VERSION v5.0.1 (faster download process: no bot) --- README.md | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c5d7bcf..ab1945c 100644 --- a/README.md +++ b/README.md @@ -23,23 +23,30 @@


+# This fork prevents files from becoming unavailable after 24 hours due to Discord's sharing restrictions. 😎 + +What's changing? Just add a user token to the .env ;) +


+ ##### **DDrive** A lightweight cloud storage system using discord as storage device written in nodejs. Supports an unlimited file size and unlimited storage, Implemented using node js streams with multi-part up & download. https://user-images.githubusercontent.com/59018146/167635903-48cdace0-c383-4e7d-a037-4a32eaa4ab69.mp4 + ### Features + - Theoretically unlimited file size, thanks to splitting the file in 24mb chunks using nodejs streams API. -- Simple yet robust HTTP front end +- Simple yet robust HTTP front end - Rest API with OpenAPI 3.1 specifications. - Tested with storing 4000 GB of data on single discord channel (With max file size of 16GB). - Supports basic auth with read only public access to panel. - Easily deployable on heroku/replit and use as private cloud storage. -## New Version 4.0 + ### Requirements + - NodeJS v16.x or Docker - Postgres Database, Discord Webhook URLs - Avg technical knowledge ## Setup Guide + 1. Clone this project 2. Create few webhook urls. For better performance and to avoid rate limit at least create 5 with 1 webhook / text channel. ([How to create webhook url](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks)) 3. Setup postgres using docker, if you already don't have it running @@ -79,12 +88,14 @@ I spent several weeks finalizing this new version. Any support is highly apprec 8. Navigate to `http://localhost:3000` in your browser. ### How to keep it running forever + 1. Install pm2 with `npm install -g pm2` 2. Run - `pm2 start bin/ddrive` 3. Run - `pm2 list` to check status of ddrive 4. Run - `pm2 logs` to check ddrive logs ### Config variables explanation + ```shell # config/.env @@ -108,31 +119,38 @@ PUBLIC_ACCESS=READ_ONLY_FILE # If you want to give read only access to panel or # READ_ONLY_FILE - User will be only access download links of file and not panel # READ_ONLY_PANEL - User will be able to browse the panel for files/directories but won't be able to upload/delete/rename any file/folder. -UPLOAD_CONCURRENCY=3 # ddrive will upload this many chunks in parallel to discord. If you have fast internet increasing it will significantly increase performance at cost of cpu/disk usage +UPLOAD_CONCURRENCY=3 # ddrive will upload this many chunks in parallel to discord. If you have fast internet increasing it will significantly increase performance at cost of cpu/disk usage -BOT_TOKEN= # Add a bot to your Discord server and retrieve the token from the Developer Portal at https://discord.com/developers/applications. -CHANNEL_ID= # The channel ID where the file will be uploaded, is the same as the webhook's channel. -GUILD_ID= # The GUILD ID where the file will be uploaded +USER_TOKEN= # Put real Discord User account Token (see below for steps) ``` -src/DFs/index.js line 42 AND line 74 : -`const list = await fetchMore(channel, 15000); ` - -Increase the number if older files are not downloadable, like 20000 or 30000. **If you change it, delete the cache.json before restart** +## How to get a user Discord token (need to be login to the account) -⚠️ You need to enable MESSAGE_INTENT in developer portal of the BOT -![image](https://github.com/user-attachments/assets/aaef7b9f-8055-42eb-87ac-973fcb43799c) -https://discord.com/developers/applications/ +[](https://github.com/ShufflePerson/Discord_CDN/blob/master/README.md#how-to-get-your-token) +1. Open Discord on your Browser. +2. Open the Dev Tools ( Inspect Element ) +3. Go to the Console Tab and paste in the following command +4. `console.log((webpackChunkdiscord_app.push([[''],{},e=>{m=[];for(let c in e.c)m.push(e.c[c])}]),m).find(m=>m?.exports?.default?.getToken!==void 0).exports.default.getToken());` +5. Copy the output and set it in the `.env` file. (e.g `USER_TOKEN=PASTE_TOKEN_HERE`), _the account does not have to be on your ddrive server_ ### Run using docker + ```shell docker run -rm -it -p 8080:8080 \ -e PORT=8080 \ -e WEBHOOKS={url1},{url2} \ -e DATABASE_URL={database url} \ +-e USER_TOKEN=PASTE_TOKEN_HERE \ --name ddrive forscht/ddrive ``` + +
+
+ +_...see the [original repo](https://github.com/forscht/ddrive/) for the full readme_ + + From ec339b43e00ceea3b446df4dd6f8044b3ddb030c Mon Sep 17 00:00:00 2001 From: Matrixx-Js Date: Wed, 31 Jul 2024 02:27:04 +0200 Subject: [PATCH 23/26] New VERSION v5.0.1 (faster download process: no bot) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ab1945c..f674338 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ docker run -rm -it -p 8080:8080 \
_...see the [original repo](https://github.com/forscht/ddrive/) for the full readme_ +Credit : Copyright 2024 ShufflePerson