From 1a982ae9aa51081f12c34c5dd68857bfbb4f312e Mon Sep 17 00:00:00 2001 From: rini Date: Mon, 15 Jan 2024 23:51:12 -0300 Subject: [PATCH] feat(anonymisefilenames): add icon to toggle anonymising (#2087) Co-authored-by: V Co-authored-by: fawn --- src/plugins/anonymiseFileNames/index.ts | 94 ---------------- src/plugins/anonymiseFileNames/index.tsx | 130 +++++++++++++++++++++++ 2 files changed, 130 insertions(+), 94 deletions(-) delete mode 100644 src/plugins/anonymiseFileNames/index.ts create mode 100644 src/plugins/anonymiseFileNames/index.tsx diff --git a/src/plugins/anonymiseFileNames/index.ts b/src/plugins/anonymiseFileNames/index.ts deleted file mode 100644 index 9e69d7a9..00000000 --- a/src/plugins/anonymiseFileNames/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { Settings } from "@api/Settings"; -import { Devs } from "@utils/constants"; -import definePlugin, { OptionType } from "@utils/types"; - -const enum Methods { - Random, - Consistent, - Timestamp, -} - -const tarExtMatcher = /\.tar\.\w+$/; - -export default definePlugin({ - name: "AnonymiseFileNames", - authors: [Devs.obscurity], - description: "Anonymise uploaded file names", - patches: [ - { - find: "instantBatchUpload:function", - replacement: { - match: /uploadFiles:(.{1,2}),/, - replace: - "uploadFiles:(...args)=>(args[0].uploads.forEach(f=>f.filename=$self.anonymise(f.filename)),$1(...args)),", - }, - }, - ], - - options: { - method: { - description: "Anonymising method", - type: OptionType.SELECT, - options: [ - { label: "Random Characters", value: Methods.Random, default: true }, - { label: "Consistent", value: Methods.Consistent }, - { label: "Timestamp (4chan-like)", value: Methods.Timestamp }, - ], - }, - randomisedLength: { - description: "Random characters length", - type: OptionType.NUMBER, - default: 7, - disabled: () => Settings.plugins.AnonymiseFileNames.method !== Methods.Random, - }, - consistent: { - description: "Consistent filename", - type: OptionType.STRING, - default: "image", - disabled: () => Settings.plugins.AnonymiseFileNames.method !== Methods.Consistent, - }, - }, - - anonymise(file: string) { - let name = "image"; - const tarMatch = tarExtMatcher.exec(file); - const extIdx = tarMatch?.index ?? file.lastIndexOf("."); - const ext = extIdx !== -1 ? file.slice(extIdx) : ""; - - switch (Settings.plugins.AnonymiseFileNames.method) { - case Methods.Random: - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - name = Array.from( - { length: Settings.plugins.AnonymiseFileNames.randomisedLength }, - () => chars[Math.floor(Math.random() * chars.length)] - ).join(""); - break; - case Methods.Consistent: - name = Settings.plugins.AnonymiseFileNames.consistent; - break; - case Methods.Timestamp: - // UNIX timestamp in nanos, i could not find a better dependency-less way - name = `${Math.floor(Date.now() / 1000)}${Math.floor(window.performance.now())}`; - break; - } - return name + ext; - }, -}); diff --git a/src/plugins/anonymiseFileNames/index.tsx b/src/plugins/anonymiseFileNames/index.tsx new file mode 100644 index 00000000..845aa756 --- /dev/null +++ b/src/plugins/anonymiseFileNames/index.tsx @@ -0,0 +1,130 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { Upload } from "@api/MessageEvents"; +import { definePluginSettings } from "@api/Settings"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; +import { findByCodeLazy, findByPropsLazy } from "@webpack"; + +type AnonUpload = Upload & { anonymise?: boolean; }; + +const ActionBarIcon = findByCodeLazy(".actionBarIcon)"); +const UploadDraft = findByPropsLazy("popFirstFile", "update"); + +const enum Methods { + Random, + Consistent, + Timestamp, +} + +const tarExtMatcher = /\.tar\.\w+$/; + +const settings = definePluginSettings({ + anonymiseByDefault: { + description: "Whether to anonymise file names by default", + type: OptionType.BOOLEAN, + default: true, + }, + method: { + description: "Anonymising method", + type: OptionType.SELECT, + options: [ + { label: "Random Characters", value: Methods.Random, default: true }, + { label: "Consistent", value: Methods.Consistent }, + { label: "Timestamp", value: Methods.Timestamp }, + ], + }, + randomisedLength: { + description: "Random characters length", + type: OptionType.NUMBER, + default: 7, + disabled: () => settings.store.method !== Methods.Random, + }, + consistent: { + description: "Consistent filename", + type: OptionType.STRING, + default: "image", + disabled: () => settings.store.method !== Methods.Consistent, + }, +}); + +export default definePlugin({ + name: "AnonymiseFileNames", + authors: [Devs.obscurity], + description: "Anonymise uploaded file names", + patches: [ + { + find: "instantBatchUpload:function", + replacement: { + match: /uploadFiles:(.{1,2}),/, + replace: + "uploadFiles:(...args)=>(args[0].uploads.forEach(f=>f.filename=$self.anonymise(f)),$1(...args)),", + }, + }, + { + find: ".Messages.ATTACHMENT_UTILITIES_SPOILER", + replacement: { + match: /(?<=children:\[)(?=.{10,80}tooltip:\i\.\i\.Messages\.ATTACHMENT_UTILITIES_SPOILER)/, + replace: "arguments[0].canEdit!==false?$self.renderIcon(arguments[0]):null," + }, + }, + ], + settings, + + renderIcon: ErrorBoundary.wrap(({ upload, channelId, draftType }: { upload: AnonUpload; draftType: unknown; channelId: string; }) => { + const anonymise = upload.anonymise ?? settings.store.anonymiseByDefault; + return ( + { + upload.anonymise = !anonymise; + UploadDraft.update(channelId, upload.id, draftType, {}); // dummy update so component rerenders + }} + > + {anonymise + ? + : + } + + ); + }, { noop: true }), + + anonymise(upload: AnonUpload) { + if ((upload.anonymise ?? settings.store.anonymiseByDefault) === false) return upload.filename; + + const file = upload.filename; + const tarMatch = tarExtMatcher.exec(file); + const extIdx = tarMatch?.index ?? file.lastIndexOf("."); + const ext = extIdx !== -1 ? file.slice(extIdx) : ""; + + switch (settings.store.method) { + case Methods.Random: + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + return Array.from( + { length: settings.store.randomisedLength }, + () => chars[Math.floor(Math.random() * chars.length)] + ).join("") + ext; + case Methods.Consistent: + return settings.store.consistent + ext; + case Methods.Timestamp: + return Date.now() + ext; + } + }, +});