diff --git a/src/components/icons/GlobeIcon.tsx b/src/components/icons/GlobeIcon.tsx
new file mode 100644
index 0000000..4577619
--- /dev/null
+++ b/src/components/icons/GlobeIcon.tsx
@@ -0,0 +1,5 @@
+import { Globe } from 'react-feather';
+
+export default function GlobeIcon({ ...props }) {
+ return ;
+}
diff --git a/src/components/icons/index.tsx b/src/components/icons/index.tsx
index b3d6839..4287ed3 100644
--- a/src/components/icons/index.tsx
+++ b/src/components/icons/index.tsx
@@ -38,6 +38,7 @@ import InfoIcon from './InfoIcon';
import FolderIcon from './FolderIcon';
import FolderMinusIcon from './FolderMinusIcon';
import FolderPlusIcon from './FolderPlusIcon';
+import GlobeIcon from './GlobeIcon';
export {
ActivityIcon,
@@ -80,4 +81,5 @@ export {
FolderIcon,
FolderMinusIcon,
FolderPlusIcon,
+ GlobeIcon,
};
diff --git a/src/components/pages/Manage/Flameshot.tsx b/src/components/pages/Manage/Flameshot.tsx
index 806d7b5..fb94614 100644
--- a/src/components/pages/Manage/Flameshot.tsx
+++ b/src/components/pages/Manage/Flameshot.tsx
@@ -61,6 +61,12 @@ export default function Flameshot({ user, open, setOpen }) {
delete extraHeaders['Original-Name'];
}
+ if (values.overrideDomain && values.overrideDomain.trim() !== '') {
+ extraHeaders['Override-Domain'] = values.overrideDomain;
+ } else {
+ delete extraHeaders['Override-Domain'];
+ }
+
for (const [key, value] of Object.entries(extraHeaders)) {
curl.push('-H');
curl.push(`"${key}: ${value}"`);
diff --git a/src/components/pages/Manage/GeneratorModal.tsx b/src/components/pages/Manage/GeneratorModal.tsx
index 9312732..e3bf311 100644
--- a/src/components/pages/Manage/GeneratorModal.tsx
+++ b/src/components/pages/Manage/GeneratorModal.tsx
@@ -10,13 +10,16 @@ import {
Stack,
Switch,
Text,
+ TextInput,
Title,
} from '@mantine/core';
import { useForm } from '@mantine/form';
-import { DownloadIcon } from 'components/icons';
+import { DownloadIcon, GlobeIcon } from 'components/icons';
import Link from 'components/Link';
import MutedText from 'components/MutedText';
-import { useState } from 'react';
+import { useReducer, useState } from 'react';
+
+const DEFAULT_OD_DESC = 'Override the default domain(s). Type in a URL, e.g https://example.com';
export function GeneratorModal({ opened, onClose, title, onSubmit, ...other }) {
const form = useForm({
@@ -30,6 +33,7 @@ export function GeneratorModal({ opened, onClose, title, onSubmit, ...other }) {
wlCompositorNotSupported: false,
noJSON: false,
originalName: false,
+ overrideDomain: null,
},
});
@@ -40,6 +44,42 @@ export function GeneratorModal({ opened, onClose, title, onSubmit, ...other }) {
form.setFieldValue('type', value);
};
+ const [odState, setODState] = useReducer((state, newState) => ({ ...state, ...newState }), {
+ description: DEFAULT_OD_DESC,
+ error: '',
+ domain: '',
+ });
+
+ const handleOD = (e) => {
+ setODState({ error: '' });
+
+ if (e.currentTarget.value === '') {
+ setODState({ description: DEFAULT_OD_DESC, error: '', domain: null });
+ form.setFieldValue('overrideDomain', null);
+ return;
+ }
+
+ try {
+ const url = new URL(e.currentTarget.value);
+ setODState({
+ description: (
+ <>
+ {DEFAULT_OD_DESC}
+
+
+ Using domain "{url.hostname}"
+ >
+ ),
+ error: '',
+ domain: url.hostname,
+ });
+ form.setFieldValue('overrideDomain', url.hostname);
+ } catch (e) {
+ setODState({ error: 'Invalid URL', domain: '' });
+ form.setFieldValue('overrideDomain', null);
+ }
+ };
+
return (
{title}} size='lg'>
{other.desc && (
@@ -85,6 +125,14 @@ export function GeneratorModal({ opened, onClose, title, onSubmit, ...other }) {
{...form.getInputProps('imageCompression')}
/>
+ }
+ description={odState.description}
+ error={odState.error}
+ />
+
-
+ {OptionsModal}
Upload Files
setFiles([...files, ...f])}>
diff --git a/src/components/pages/Upload/Text.tsx b/src/components/pages/Upload/Text.tsx
index bd661a4..381183e 100644
--- a/src/components/pages/Upload/Text.tsx
+++ b/src/components/pages/Upload/Text.tsx
@@ -71,13 +71,14 @@ export default function Text() {
options.zeroWidth && req.setRequestHeader('Zws', 'true');
options.format !== 'default' && req.setRequestHeader('Format', options.format);
options.originalName && req.setRequestHeader('Original-Name', 'true');
+ options.overrideDomain && req.setRequestHeader('Override-Domain', options.overrideDomain);
req.send(body);
};
return (
<>
-
+ {OptionsModal}
Upload Text
diff --git a/src/components/pages/Upload/useUploadOptions.tsx b/src/components/pages/Upload/useUploadOptions.tsx
index 1ecd557..39311d0 100644
--- a/src/components/pages/Upload/useUploadOptions.tsx
+++ b/src/components/pages/Upload/useUploadOptions.tsx
@@ -7,52 +7,72 @@ import {
Select,
Stack,
Switch,
+ TextInput,
Title,
} from '@mantine/core';
-import { ClockIcon, ImageIcon, KeyIcon, TypeIcon, UserIcon } from 'components/icons';
+import { ClockIcon, ImageIcon, KeyIcon, TypeIcon, UserIcon, GlobeIcon } from 'components/icons';
import React, { Dispatch, SetStateAction, useReducer, useState } from 'react';
-export default function useUploadOptions(): [
- {
- expires: string;
- password: string;
- maxViews: number;
- compression: string;
- zeroWidth: boolean;
- embedded: boolean;
- format: string;
- originalName: boolean;
- },
- Dispatch>,
- React.FC
-] {
- const [state, setState] = useReducer((state, newState) => ({ ...state, ...newState }), {
- expires: 'never',
- password: '',
- maxViews: 0,
- compression: 'none',
- zeroWidth: false,
- embedded: false,
- format: 'default',
- originalName: false,
+export type UploadOptionsState = {
+ expires: string;
+ password: string;
+ maxViews: number;
+ compression: string;
+ zeroWidth: boolean;
+ embedded: boolean;
+ format: string;
+ originalName: boolean;
+ overrideDomain: string;
+};
+
+const DEFAULT_OD_DESC = 'Override the default domain(s). Type in a URL, e.g https://example.com';
+
+export function OptionsModal({
+ opened,
+ setOpened,
+ state,
+ setState,
+ reset,
+}: {
+ opened: boolean;
+ setOpened: Dispatch>;
+ state: UploadOptionsState;
+ setState: Dispatch>;
+ reset: () => void;
+}) {
+ const [odState, setODState] = useReducer((state, newState) => ({ ...state, ...newState }), {
+ description: DEFAULT_OD_DESC,
+ error: '',
});
- const [opened, setOpened] = useState(false);
+ const handleOD = (e) => {
+ setODState({ error: '' });
- const reset = () => {
- setState({
- expires: 'never',
- password: '',
- maxViews: 0,
- compression: 'none',
- zeroWidth: false,
- embedded: false,
- format: 'default',
- originalName: false,
- });
+ if (e.currentTarget.value === '') {
+ setODState({ description: DEFAULT_OD_DESC, error: '' });
+ setState({ overrideDomain: '' });
+ return;
+ }
+
+ try {
+ const url = new URL(e.currentTarget.value);
+ setODState({
+ description: (
+ <>
+ {DEFAULT_OD_DESC}
+
+
+ Using domain "{url.hostname}"
+ >
+ ),
+ });
+ setState({ overrideDomain: url.hostname });
+ } catch (e) {
+ setODState({ error: 'Invalid URL' });
+ }
};
- const OptionsModal: React.FC = () => (
+ return (
Upload Options} size='lg' opened={opened} onClose={() => setOpened(false)}>
setState({ password: e.currentTarget.value })}
icon={}
/>
+ }
+ description={odState.description}
+ error={odState.error}
+ />
);
-
- return [state, setOpened, OptionsModal];
+}
+
+export default function useUploadOptions(): [UploadOptionsState, Dispatch>, any] {
+ const [state, setState] = useReducer((state, newState) => ({ ...state, ...newState }), {
+ expires: 'never',
+ password: '',
+ maxViews: 0,
+ compression: 'none',
+ zeroWidth: false,
+ embedded: false,
+ format: 'default',
+ originalName: false,
+ overrideDomain: '',
+ } as UploadOptionsState);
+
+ const [opened, setOpened] = useState(false);
+
+ const reset = () => {
+ setState({
+ expires: 'never',
+ password: '',
+ maxViews: 0,
+ compression: 'none',
+ zeroWidth: false,
+ embedded: false,
+ format: 'default',
+ originalName: false,
+ overrideDomain: '',
+ });
+ };
+
+ return [
+ state,
+ setOpened,
+ ,
+ ];
}
diff --git a/src/pages/api/shorten.ts b/src/pages/api/shorten.ts
index a074898..e90c0e5 100644
--- a/src/pages/api/shorten.ts
+++ b/src/pages/api/shorten.ts
@@ -56,27 +56,31 @@ async function handler(req: NextApiReq, res: NextApiRes) {
logger.info(`User ${user.username} (${user.id}) shortenned a url ${url.destination} (${url.id})`);
- if (config.discord?.shorten) {
- await sendShorten(
- user,
- url,
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.urls.route === '/' ? '/' : `${zconfig.urls.route}/`
- }${req.body.vanity ? req.body.vanity : invis ? invis.invis : url.id}`
- );
+ let domain;
+ if (req.headers['override-domain']) {
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers['override-domain']}`;
+ } else if (user.domains.length) {
+ const randomDomain = user.domains[Math.floor(Math.random() * user.domains.length)];
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${randomDomain}`;
+ } else {
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}`;
}
- const fullUrl = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.urls.route === '/' ? '/' : zconfig.urls.route
- }/${req.body.vanity ? req.body.vanity : invis ? invis.invis : url.id}`;
+ const responseUrl = `${domain}${zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route}${
+ req.body.vanity ? req.body.vanity : invis ? invis.invis : url.id
+ }`;
+
+ if (config.discord?.shorten) {
+ await sendShorten(user, url, responseUrl);
+ }
if (req.headers['no-json']) {
res.setHeader('Content-Type', 'text/plain');
- return res.end(fullUrl);
+ return res.end(responseUrl);
}
return res.json({
- url: fullUrl,
+ url: responseUrl,
});
}
diff --git a/src/pages/api/upload.ts b/src/pages/api/upload.ts
index f31e036..8ec357c 100644
--- a/src/pages/api/upload.ts
+++ b/src/pages/api/upload.ts
@@ -171,32 +171,24 @@ async function handler(req: NextApiReq, res: NextApiRes) {
await datasource.save(file.name, Buffer.from(chunks));
logger.info(`User ${user.username} (${user.id}) uploaded ${file.name} (${file.id}) (chunked)`);
- if (user.domains.length) {
- const domain = user.domains[Math.floor(Math.random() * user.domains.length)];
- response.files.push(
- `${domain}${zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route}/${
- invis ? invis.invis : file.name
- }`
- );
+ let domain;
+ if (req.headers['override-domain']) {
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers['override-domain']}`;
+ } else if (user.domains.length) {
+ const randomDomain = user.domains[Math.floor(Math.random() * user.domains.length)];
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${randomDomain}`;
} else {
- response.files.push(
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route
- }/${invis ? invis.invis : file.name}`
- );
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}`;
}
+ const responseUrl = `${domain}${zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route}${
+ invis ? invis.invis : file.name
+ }`;
+
+ response.files.push(responseUrl);
+
if (zconfig.discord?.upload) {
- await sendUpload(
- user,
- file,
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}/r/${
- invis ? invis.invis : file.name
- }`,
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route
- }/${invis ? invis.invis : file.name}`
- );
+ await sendUpload(user, file, `${domain}/r/${invis ? invis.invis : file.name}`, responseUrl);
}
if (zconfig.exif.enabled && zconfig.exif.remove_gps && mimetype.startsWith('image/')) {
@@ -318,34 +310,24 @@ async function handler(req: NextApiReq, res: NextApiRes) {
}
logger.info(`User ${user.username} (${user.id}) uploaded ${fileUpload.name} (${fileUpload.id})`);
- if (user.domains.length) {
- const domain = user.domains[Math.floor(Math.random() * user.domains.length)];
- response.files.push(
- `${domain}${zconfig.uploader.route === '/' ? '' : zconfig.uploader.route}/${
- invis ? invis.invis : fileUpload.name
- }`
- );
+ let domain;
+ if (req.headers['override-domain']) {
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers['override-domain']}`;
+ } else if (user.domains.length) {
+ const randomDomain = user.domains[Math.floor(Math.random() * user.domains.length)];
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${randomDomain}`;
} else {
- response.files.push(
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.uploader.route === '/' ? '' : zconfig.uploader.route
- }/${invis ? invis.invis : fileUpload.name}`
- );
+ domain = `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}`;
}
- logger.debug(`sent response: ${JSON.stringify(response)}`);
+ const responseUrl = `${domain}${zconfig.uploader.route === '/' ? '/' : zconfig.uploader.route}${
+ invis ? invis.invis : fileUpload.name
+ }`;
+
+ response.files.push(responseUrl);
if (zconfig.discord?.upload) {
- await sendUpload(
- user,
- fileUpload,
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}/r/${
- invis ? invis.invis : fileUpload.name
- }`,
- `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}${
- zconfig.uploader.route === '/' ? '' : zconfig.uploader.route
- }/${invis ? invis.invis : fileUpload.name}`
- );
+ await sendUpload(user, fileUpload, `${domain}/r/${invis ? invis.invis : fileUpload.name}`, responseUrl);
}
if (zconfig.exif.enabled && zconfig.exif.remove_gps && fileUpload.mimetype.startsWith('image/')) {