Plugin
AnonymiseFileNames
Anonymise uploaded file names
1
import { definePluginSettings } from "@api/Settings";2
import ErrorBoundary from "@components/ErrorBoundary";3
import { Devs } from "@utils/constants";4
import definePlugin, { OptionType } from "@utils/types";5
import { CloudUpload } from "@vencord/discord-types";6
import { findByCodeLazy } from "@webpack";7
import { useState } from "@webpack/common";8
9
const ActionBarIcon = findByCodeLazy("Children.map", "isValidElement", "dangerous:");10
11
const enum Methods {12
Random,13
Consistent,14
Timestamp,15
}16
17
const ANONYMISE_UPLOAD_SYMBOL = Symbol("vcAnonymise");18
const tarExtMatcher = /\.tar\.\w+$/;19
20
const settings = definePluginSettings({21
anonymiseByDefault: {22
description: "Whether to anonymise file names by default",23
type: OptionType.BOOLEAN,24
default: true,25
},26
method: {27
description: "Anonymising method",28
type: OptionType.SELECT,29
options: [30
{ label: "Random Characters", value: Methods.Random, default: true },31
{ label: "Consistent", value: Methods.Consistent },32
{ label: "Timestamp", value: Methods.Timestamp },33
],34
},35
randomisedLength: {36
description: "Random characters length",37
type: OptionType.NUMBER,38
default: 739
},40
consistent: {41
description: "Consistent filename",42
type: OptionType.STRING,43
default: "image"44
},45
}, {46
randomisedLength: {47
disabled() { return this.store.method !== Methods.Random; },48
},49
consistent: {50
disabled() { return this.store.method !== Methods.Consistent; },51
}52
});53
54
export default definePlugin({55
name: "AnonymiseFileNames",56
authors: [Devs.fawn],57
description: "Anonymise uploaded file names",58
tags: ["Privacy", "Utility"],59
settings,60
61
patches: [62
{63
find: "async uploadFiles(",64
replacement: [65
{66
match: /async uploadFiles\((\i)\){/,67
replace: "$&$1.forEach($self.anonymise);"68
}69
],70
},71
{72
find: "#{intl::ATTACHMENT_UTILITIES_SPOILER}",73
replacement: {74
match: /(?<=children:\[)(?=.{10,80}tooltip:.{0,100}#{intl::ATTACHMENT_UTILITIES_SPOILER})/,75
replace: "arguments[0].canEdit!==false?$self.AnonymiseUploadButton(arguments[0]):null,"76
},77
},78
],79
80
AnonymiseUploadButton: ErrorBoundary.wrap(({ upload }: { upload: CloudUpload; }) => {81
const [anonymise, setAnonymise] = useState(upload[ANONYMISE_UPLOAD_SYMBOL] ?? settings.store.anonymiseByDefault);82
83
function onToggleAnonymise() {84
upload[ANONYMISE_UPLOAD_SYMBOL] = !anonymise;85
setAnonymise(!anonymise);86
}87
88
return (89
<ActionBarIcon90
tooltip={anonymise ? "Using anonymous file name" : "Using normal file name"}91
onClick={onToggleAnonymise}92
>93
{anonymise94
? <svg xmlns="http:class="ts-cmt">//www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M17.06 13C15.2 13 13.64 14.33 13.24 16.1C12.29 15.69 11.42 15.8 10.76 16.09C10.35 14.31 8.79 13 6.94 13C4.77 13 3 14.79 3 17C3 19.21 4.77 21 6.94 21C9 21 10.68 19.38 10.84 17.32C11.18 17.08 12.07 16.63 13.16 17.34C13.34 19.39 15 21 17.06 21C19.23 21 21 19.21 21 17C21 14.79 19.23 13 17.06 13M6.94 19.86C5.38 19.86 4.13 18.58 4.13 17S5.39 14.14 6.94 14.14C8.5 14.14 9.75 15.42 9.75 17S8.5 19.86 6.94 19.86M17.06 19.86C15.5 19.86 14.25 18.58 14.25 17S15.5 14.14 17.06 14.14C18.62 14.14 19.88 15.42 19.88 17S18.61 19.86 17.06 19.86M22 10.5H2V12H22V10.5M15.53 2.63C15.31 2.14 14.75 1.88 14.22 2.05L12 2.79L9.77 2.05L9.72 2.04C9.19 1.89 8.63 2.17 8.43 2.68L6 9H18L15.56 2.68L15.53 2.63Z" /></svg>95
: <svg xmlns="http:class="ts-cmt">//www.w3.org/2000/svg" viewBox="0 0 24 24" style={{ transform: "scale(-1,1)" }}><path fill="currentColor" d="M22.11 21.46L2.39 1.73L1.11 3L6.31 8.2L6 9H7.11L8.61 10.5H2V12H10.11L13.5 15.37C13.38 15.61 13.3 15.85 13.24 16.1C12.29 15.69 11.41 15.8 10.76 16.09C10.35 14.31 8.79 13 6.94 13C4.77 13 3 14.79 3 17C3 19.21 4.77 21 6.94 21C9 21 10.68 19.38 10.84 17.32C11.18 17.08 12.07 16.63 13.16 17.34C13.34 19.39 15 21 17.06 21C17.66 21 18.22 20.86 18.72 20.61L20.84 22.73L22.11 21.46M6.94 19.86C5.38 19.86 4.13 18.58 4.13 17C4.13 15.42 5.39 14.14 6.94 14.14C8.5 14.14 9.75 15.42 9.75 17C9.75 18.58 8.5 19.86 6.94 19.86M17.06 19.86C15.5 19.86 14.25 18.58 14.25 17C14.25 16.74 14.29 16.5 14.36 16.25L17.84 19.73C17.59 19.81 17.34 19.86 17.06 19.86M22 12H15.2L13.7 10.5H22V12M17.06 13C19.23 13 21 14.79 21 17C21 17.25 20.97 17.5 20.93 17.73L19.84 16.64C19.68 15.34 18.66 14.32 17.38 14.17L16.29 13.09C16.54 13.03 16.8 13 17.06 13M12.2 9L7.72 4.5L8.43 2.68C8.63 2.17 9.19 1.89 9.72 2.04L9.77 2.05L12 2.79L14.22 2.05C14.75 1.88 15.32 2.14 15.54 2.63L15.56 2.68L18 9H12.2Z" /></svg>96
}97
</ActionBarIcon>98
);99
}, { noop: true }),100
101
anonymise(upload: CloudUpload) {102
if ((upload[ANONYMISE_UPLOAD_SYMBOL] ?? settings.store.anonymiseByDefault) === false) {103
return;104
}105
106
const originalFileName = upload.filename;107
const tarMatch = tarExtMatcher.exec(originalFileName);108
const extIdx = tarMatch?.index ?? originalFileName.lastIndexOf(".");109
const ext = extIdx !== -1 ? originalFileName.slice(extIdx) : "";110
111
const newFilename = (() => {112
switch (settings.store.method) {113
case Methods.Random:114
const chars = "0123456789bdfhjkmnpqrstvwxz";115
return Array.from(116
{ length: settings.store.randomisedLength },117
() => chars[Math.floor(Math.random() * chars.length)]118
).join("") + ext;119
case Methods.Consistent:120
return settings.store.consistent + ext;121
case Methods.Timestamp:122
return Date.now() + ext;123
}124
})();125
126
upload.filename = newFilename;127
}128
});129