FileUpload: add support for encrypting.host (#1139)
* FileUpload: add support for encrypting.host * so you can throw me to the wolves tomorrow i will come back leader of the whole pack beat me black and blueee every word will shape me every scar will build my throoone
This commit is contained in:
parent
03b6c19441
commit
7aebbe9707
3 changed files with 217 additions and 0 deletions
|
|
@ -24,6 +24,7 @@ const serviceOptions = [
|
||||||
{ label: "Zipline", value: ServiceType.ZIPLINE, default: true },
|
{ label: "Zipline", value: ServiceType.ZIPLINE, default: true },
|
||||||
{ label: "E-Z Host", value: ServiceType.EZHOST },
|
{ label: "E-Z Host", value: ServiceType.EZHOST },
|
||||||
{ label: "Nest", value: ServiceType.NEST },
|
{ label: "Nest", value: ServiceType.NEST },
|
||||||
|
{ label: "Encrypting.host", value: ServiceType.ENCRYPTINGHOST },
|
||||||
{ label: "S3-Compatible", value: ServiceType.S3 },
|
{ label: "S3-Compatible", value: ServiceType.S3 },
|
||||||
{ label: "Catbox.moe", value: ServiceType.CATBOX },
|
{ label: "Catbox.moe", value: ServiceType.CATBOX },
|
||||||
...(IS_DISCORD_DESKTOP ? [{ label: "0x0.st", value: ServiceType.ZEROX0 }] : []),
|
...(IS_DISCORD_DESKTOP ? [{ label: "0x0.st", value: ServiceType.ZEROX0 }] : []),
|
||||||
|
|
@ -50,6 +51,13 @@ const embedProxyOptions = [
|
||||||
{ label: "discord.nfp.is", value: "nfp" }
|
{ label: "discord.nfp.is", value: "nfp" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const encryptingHostUrlStyleOptions = [
|
||||||
|
{ label: "Query", value: "query", default: true },
|
||||||
|
{ label: "Param", value: "param" },
|
||||||
|
{ label: "Fake Link", value: "fakelink" },
|
||||||
|
{ label: "Embed", value: "embed" }
|
||||||
|
];
|
||||||
|
|
||||||
export const settings = definePluginSettings({
|
export const settings = definePluginSettings({
|
||||||
serviceType: {
|
serviceType: {
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
|
|
@ -87,6 +95,43 @@ export const settings = definePluginSettings({
|
||||||
default: "",
|
default: "",
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
encryptingHostKey: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "Encrypting.host API key",
|
||||||
|
default: "",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
encryptingHostUrlStyle: {
|
||||||
|
type: OptionType.SELECT,
|
||||||
|
description: "Encrypting.host URL style",
|
||||||
|
options: encryptingHostUrlStyleOptions,
|
||||||
|
default: "query",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
encryptingHostDomains: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "Encrypting.host domains JSON list",
|
||||||
|
default: "[\"offensive\"]",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
encryptingHostTitle: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "Optional Encrypting.host embed title",
|
||||||
|
default: "",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
encryptingHostColor: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "Optional Encrypting.host embed color",
|
||||||
|
default: "",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
encryptingHostFakelink: {
|
||||||
|
type: OptionType.STRING,
|
||||||
|
description: "Optional Encrypting.host fake link",
|
||||||
|
default: "",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
s3Endpoint: {
|
s3Endpoint: {
|
||||||
type: OptionType.STRING,
|
type: OptionType.STRING,
|
||||||
description: "S3-compatible endpoint URL",
|
description: "S3-compatible endpoint URL",
|
||||||
|
|
@ -421,6 +466,7 @@ export function SettingsComponent() {
|
||||||
const sharexFileInputRef = React.useRef<HTMLInputElement>(null);
|
const sharexFileInputRef = React.useRef<HTMLInputElement>(null);
|
||||||
const isNest = store.serviceType === ServiceType.NEST;
|
const isNest = store.serviceType === ServiceType.NEST;
|
||||||
const isEzHost = store.serviceType === ServiceType.EZHOST;
|
const isEzHost = store.serviceType === ServiceType.EZHOST;
|
||||||
|
const isEncryptingHost = store.serviceType === ServiceType.ENCRYPTINGHOST;
|
||||||
const isS3 = store.serviceType === ServiceType.S3;
|
const isS3 = store.serviceType === ServiceType.S3;
|
||||||
const isZipline = store.serviceType === ServiceType.ZIPLINE;
|
const isZipline = store.serviceType === ServiceType.ZIPLINE;
|
||||||
const isCatbox = store.serviceType === ServiceType.CATBOX;
|
const isCatbox = store.serviceType === ServiceType.CATBOX;
|
||||||
|
|
@ -527,6 +573,59 @@ export function SettingsComponent() {
|
||||||
</SettingGroup>
|
</SettingGroup>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isEncryptingHost && (
|
||||||
|
<SettingGroup name="Encrypting.host" description="Connection details for Encrypting.host uploads.">
|
||||||
|
<SettingTextInput
|
||||||
|
name="Encrypting.host API Key"
|
||||||
|
description="Your Encrypting.host API key"
|
||||||
|
value={(store as { encryptingHostKey?: string; }).encryptingHostKey || ""}
|
||||||
|
onChange={v => (store as { encryptingHostKey?: string; }).encryptingHostKey = v}
|
||||||
|
placeholder="Your Encrypting.host API key"
|
||||||
|
/>
|
||||||
|
<SettingsSection name="URL Style" description="How Encrypting.host should format returned links.">
|
||||||
|
<Select
|
||||||
|
options={encryptingHostUrlStyleOptions}
|
||||||
|
isSelected={v => v === (store as { encryptingHostUrlStyle?: string; }).encryptingHostUrlStyle}
|
||||||
|
select={v => {
|
||||||
|
(store as { encryptingHostUrlStyle?: string; }).encryptingHostUrlStyle = v;
|
||||||
|
update();
|
||||||
|
}}
|
||||||
|
serialize={v => v}
|
||||||
|
placeholder="Select URL style"
|
||||||
|
/>
|
||||||
|
</SettingsSection>
|
||||||
|
<SettingsSection name="Domains JSON" description={"JSON array of domains to use, for example [\"offensive\"]."}>
|
||||||
|
<TextArea
|
||||||
|
value={(store as { encryptingHostDomains?: string; }).encryptingHostDomains || ""}
|
||||||
|
rows={3}
|
||||||
|
placeholder='["offensive"]'
|
||||||
|
onChange={v => (store as { encryptingHostDomains?: string; }).encryptingHostDomains = v}
|
||||||
|
/>
|
||||||
|
</SettingsSection>
|
||||||
|
<SettingTextInput
|
||||||
|
name="Embed Title"
|
||||||
|
description="Optional title for embed style responses."
|
||||||
|
value={(store as { encryptingHostTitle?: string; }).encryptingHostTitle || ""}
|
||||||
|
onChange={v => (store as { encryptingHostTitle?: string; }).encryptingHostTitle = v}
|
||||||
|
placeholder="Optional title"
|
||||||
|
/>
|
||||||
|
<SettingTextInput
|
||||||
|
name="Embed Color"
|
||||||
|
description="Optional color for embed style responses."
|
||||||
|
value={(store as { encryptingHostColor?: string; }).encryptingHostColor || ""}
|
||||||
|
onChange={v => (store as { encryptingHostColor?: string; }).encryptingHostColor = v}
|
||||||
|
placeholder="Optional color"
|
||||||
|
/>
|
||||||
|
<SettingTextInput
|
||||||
|
name="Fake Link"
|
||||||
|
description="Optional fake link value for fakelink style responses."
|
||||||
|
value={(store as { encryptingHostFakelink?: string; }).encryptingHostFakelink || ""}
|
||||||
|
onChange={v => (store as { encryptingHostFakelink?: string; }).encryptingHostFakelink = v}
|
||||||
|
placeholder="Optional fake link"
|
||||||
|
/>
|
||||||
|
</SettingGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
{isS3 && (
|
{isS3 && (
|
||||||
<SettingGroup name="S3-Compatible Storage" description="Connection details and object naming for your bucket.">
|
<SettingGroup name="S3-Compatible Storage" description="Connection details and object naming for your bucket.">
|
||||||
<SettingTextInput
|
<SettingTextInput
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export enum ServiceType {
|
||||||
ZIPLINE = "zipline",
|
ZIPLINE = "zipline",
|
||||||
NEST = "nest",
|
NEST = "nest",
|
||||||
EZHOST = "ezhost",
|
EZHOST = "ezhost",
|
||||||
|
ENCRYPTINGHOST = "encryptinghost",
|
||||||
S3 = "s3",
|
S3 = "s3",
|
||||||
CATBOX = "catbox",
|
CATBOX = "catbox",
|
||||||
ZEROX0 = "0x0",
|
ZEROX0 = "0x0",
|
||||||
|
|
@ -26,6 +27,7 @@ export const serviceLabels: Record<ServiceType, string> = {
|
||||||
[ServiceType.ZIPLINE]: "Zipline",
|
[ServiceType.ZIPLINE]: "Zipline",
|
||||||
[ServiceType.NEST]: "Nest",
|
[ServiceType.NEST]: "Nest",
|
||||||
[ServiceType.EZHOST]: "E-Z Host",
|
[ServiceType.EZHOST]: "E-Z Host",
|
||||||
|
[ServiceType.ENCRYPTINGHOST]: "Encrypting.host",
|
||||||
[ServiceType.S3]: "S3-Compatible",
|
[ServiceType.S3]: "S3-Compatible",
|
||||||
[ServiceType.CATBOX]: "Catbox",
|
[ServiceType.CATBOX]: "Catbox",
|
||||||
[ServiceType.ZEROX0]: "0x0.st",
|
[ServiceType.ZEROX0]: "0x0.st",
|
||||||
|
|
@ -44,6 +46,7 @@ export const fallbackServiceOrder: ServiceType[] = [
|
||||||
ServiceType.ZIPLINE,
|
ServiceType.ZIPLINE,
|
||||||
ServiceType.EZHOST,
|
ServiceType.EZHOST,
|
||||||
ServiceType.NEST,
|
ServiceType.NEST,
|
||||||
|
ServiceType.ENCRYPTINGHOST,
|
||||||
ServiceType.S3,
|
ServiceType.S3,
|
||||||
ServiceType.CATBOX,
|
ServiceType.CATBOX,
|
||||||
ServiceType.ZEROX0,
|
ServiceType.ZEROX0,
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,117 @@ async function uploadToNest(fileBlob: Blob, filename: string): Promise<string> {
|
||||||
throw new Error("No URL returned from upload");
|
throw new Error("No URL returned from upload");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EncryptingHostUrlStyle = "query" | "param" | "fakelink" | "embed";
|
||||||
|
|
||||||
|
function parseEncryptingHostDomains(raw: string): string[] {
|
||||||
|
let parsed: unknown;
|
||||||
|
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(raw);
|
||||||
|
} catch {
|
||||||
|
throw new Error("Encrypting.host domains must be a JSON array of non-empty strings");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(parsed) || parsed.some(domain => typeof domain !== "string" || !domain.trim())) {
|
||||||
|
throw new Error("Encrypting.host domains must be a JSON array of non-empty strings");
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed.map(domain => domain.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEncryptingHostConfig(): {
|
||||||
|
key: string;
|
||||||
|
urlStyle: EncryptingHostUrlStyle;
|
||||||
|
domains: string[];
|
||||||
|
title: string;
|
||||||
|
color: string;
|
||||||
|
fakelink: string;
|
||||||
|
} {
|
||||||
|
const {
|
||||||
|
encryptingHostKey,
|
||||||
|
encryptingHostUrlStyle,
|
||||||
|
encryptingHostDomains,
|
||||||
|
encryptingHostTitle,
|
||||||
|
encryptingHostColor,
|
||||||
|
encryptingHostFakelink
|
||||||
|
} = settings.store as {
|
||||||
|
encryptingHostKey?: string;
|
||||||
|
encryptingHostUrlStyle?: string;
|
||||||
|
encryptingHostDomains?: string;
|
||||||
|
encryptingHostTitle?: string;
|
||||||
|
encryptingHostColor?: string;
|
||||||
|
encryptingHostFakelink?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const key = encryptingHostKey?.trim() || "";
|
||||||
|
if (!key) {
|
||||||
|
throw new Error("Encrypting.host API key is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = encryptingHostUrlStyle || "query";
|
||||||
|
if (style !== "query" && style !== "param" && style !== "fakelink" && style !== "embed") {
|
||||||
|
throw new Error("Invalid Encrypting.host URL style");
|
||||||
|
}
|
||||||
|
|
||||||
|
const domainsRaw = encryptingHostDomains?.trim() || "[\"offensive\"]";
|
||||||
|
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
urlStyle: style,
|
||||||
|
domains: parseEncryptingHostDomains(domainsRaw),
|
||||||
|
title: encryptingHostTitle?.trim() || "",
|
||||||
|
color: encryptingHostColor?.trim() || "",
|
||||||
|
fakelink: encryptingHostFakelink?.trim() || ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadToEncryptingHost(fileBlob: Blob, filename: string): Promise<string> {
|
||||||
|
const config = getEncryptingHostConfig();
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("password", makeRandomHex(16));
|
||||||
|
formData.append("userKey", config.key);
|
||||||
|
formData.append("urlStyle", config.urlStyle);
|
||||||
|
formData.append("domains", JSON.stringify(config.domains));
|
||||||
|
if (config.title) {
|
||||||
|
formData.append("title", config.title);
|
||||||
|
}
|
||||||
|
if (config.color) {
|
||||||
|
formData.append("color", config.color);
|
||||||
|
}
|
||||||
|
if (config.fakelink) {
|
||||||
|
formData.append("fakelink", config.fakelink);
|
||||||
|
}
|
||||||
|
formData.append("file", fileBlob, filename);
|
||||||
|
|
||||||
|
const response = await uploadRequestWithTimeout("https://encrypting.host/upload", {
|
||||||
|
method: "POST",
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = await response.text();
|
||||||
|
let data: { url?: string; error?: string; } | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = text ? JSON.parse(text) as { url?: string; error?: string; } : null;
|
||||||
|
} catch {
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Upload failed: ${response.status} ${text}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedUrl = data?.url?.trim() || "";
|
||||||
|
const fallbackUrl = text.trim().startsWith("http") ? text.trim() : "";
|
||||||
|
const url = parsedUrl || fallbackUrl;
|
||||||
|
if (!url) {
|
||||||
|
throw new Error("No URL returned from upload");
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
export function isConfigured(): boolean {
|
export function isConfigured(): boolean {
|
||||||
const {
|
const {
|
||||||
serviceType,
|
serviceType,
|
||||||
|
|
@ -465,6 +576,8 @@ export function isConfigured(): boolean {
|
||||||
return Boolean(nestToken);
|
return Boolean(nestToken);
|
||||||
case ServiceType.EZHOST:
|
case ServiceType.EZHOST:
|
||||||
return Boolean((settings.store as { ezHostKey?: string; }).ezHostKey);
|
return Boolean((settings.store as { ezHostKey?: string; }).ezHostKey);
|
||||||
|
case ServiceType.ENCRYPTINGHOST:
|
||||||
|
return Boolean((settings.store as { encryptingHostKey?: string; }).encryptingHostKey);
|
||||||
case ServiceType.S3:
|
case ServiceType.S3:
|
||||||
return isS3Configured();
|
return isS3Configured();
|
||||||
case ServiceType.CATBOX:
|
case ServiceType.CATBOX:
|
||||||
|
|
@ -867,6 +980,8 @@ async function uploadToService(serviceType: ServiceType, fileBlob: Blob, filenam
|
||||||
return uploadToNest(fileBlob, filename);
|
return uploadToNest(fileBlob, filename);
|
||||||
case ServiceType.EZHOST:
|
case ServiceType.EZHOST:
|
||||||
return uploadToEzHost(fileBlob, filename);
|
return uploadToEzHost(fileBlob, filename);
|
||||||
|
case ServiceType.ENCRYPTINGHOST:
|
||||||
|
return uploadToEncryptingHost(fileBlob, filename);
|
||||||
case ServiceType.S3:
|
case ServiceType.S3:
|
||||||
return uploadToS3(fileBlob, filename, Native, uploadRequestWithTimeout);
|
return uploadToS3(fileBlob, filename, Native, uploadRequestWithTimeout);
|
||||||
case ServiceType.CATBOX:
|
case ServiceType.CATBOX:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue