From 3ff215366aeaab1cafa01e499907735ad0683933 Mon Sep 17 00:00:00 2001 From: Jayvin Hernandez Date: Fri, 28 Apr 2023 20:32:51 -0700 Subject: [PATCH 1/8] fix: a lot of things (#386) * @diced forgor * check if proper id * fix(?): await datasource's get * fix (diced/zipline#350): Return size 0 for not found --- src/lib/datasources/S3.ts | 8 ++++---- src/pages/api/auth/image.ts | 1 + src/pages/view/[id].tsx | 2 +- src/scripts/query-size.ts | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/datasources/S3.ts b/src/lib/datasources/S3.ts index 011b5e0..3809d48 100644 --- a/src/lib/datasources/S3.ts +++ b/src/lib/datasources/S3.ts @@ -50,22 +50,22 @@ export class S3 extends Datasource { } public size(file: string): Promise { - return new Promise((res, rej) => { + return new Promise((res) => { this.s3.statObject(this.config.bucket, file, (err, stat) => { - if (err) rej(err); + if (err) res(0); else res(stat.size); }); }); } public async fullSize(): Promise { - return new Promise((res, rej) => { + return new Promise((res) => { const objects = this.s3.listObjectsV2(this.config.bucket, '', true); let size = 0; objects.on('data', (item) => (size += item.size)); objects.on('end', (err) => { - if (err) rej(err); + if (err) res(0); else res(size); }); }); diff --git a/src/pages/api/auth/image.ts b/src/pages/api/auth/image.ts index ff059fd..5db9ac7 100644 --- a/src/pages/api/auth/image.ts +++ b/src/pages/api/auth/image.ts @@ -7,6 +7,7 @@ import { extname } from 'path'; async function handler(req: NextApiReq, res: NextApiRes) { const { id, password } = req.query; + if (isNaN(Number(id))) return res.badRequest('invalid id'); const file = await prisma.file.findFirst({ where: { diff --git a/src/pages/view/[id].tsx b/src/pages/view/[id].tsx index 1f7ed6b..404154a 100644 --- a/src/pages/view/[id].tsx +++ b/src/pages/view/[id].tsx @@ -231,7 +231,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => { if (file.password) file.password = true; return { props: { - image: file, + file, user, pass, prismRender: true, diff --git a/src/scripts/query-size.ts b/src/scripts/query-size.ts index 655210d..5649769 100644 --- a/src/scripts/query-size.ts +++ b/src/scripts/query-size.ts @@ -29,7 +29,7 @@ async function main() { for (let i = 0; i !== files.length; ++i) { const file = files[i]; - if (!datasource.get(file.name)) { + if (!(await datasource.get(file.name))) { if (process.argv.includes('--force-delete')) { console.log(`File ${file.name} does not exist. Deleting...`); await prisma.file.delete({ From 7cbf828f3b69897811fbb39638ad9fc462a2c449 Mon Sep 17 00:00:00 2001 From: Jayvin Hernandez Date: Fri, 28 Apr 2023 20:51:34 -0700 Subject: [PATCH 2/8] fix: properly type the relation field for OAuth (#370) Co-authored-by: dicedtomato <35403473+diced@users.noreply.github.com> --- prisma/schema.prisma | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 49789b5..91269bf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -114,7 +114,7 @@ model OAuth { id Int @id @default(autoincrement()) provider OauthProviders user User @relation(fields: [userId], references: [uuid], onDelete: Cascade) - userId String + userId String @db.Uuid username String oauthId String? token String From d6ce64ae215a0141d2e00640b3a31906345daf33 Mon Sep 17 00:00:00 2001 From: diced Date: Sun, 30 Apr 2023 15:31:19 -0700 Subject: [PATCH 3/8] fix: go back one page (#371) --- src/components/pages/Files/FilePagation.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/pages/Files/FilePagation.tsx b/src/components/pages/Files/FilePagation.tsx index 933ed44..57aba25 100644 --- a/src/components/pages/Files/FilePagation.tsx +++ b/src/components/pages/Files/FilePagation.tsx @@ -40,6 +40,12 @@ export default function FilePagation({ disableMediaPreview, exifEnabled, queryPa const pages = usePaginatedFiles(page, !checked ? 'media' : null); if (pages.isSuccess && pages.data.length === 0) { + if (page > 1 && numPages > 0) { + setPage(page - 1); + + return null; + } + return (
From 4a46f15833a11015f8d3e827d217a28d1323fa45 Mon Sep 17 00:00:00 2001 From: diced Date: Sun, 30 Apr 2023 15:41:27 -0700 Subject: [PATCH 4/8] fix: ext finding (#384) --- src/lib/format/index.ts | 5 ++++- src/pages/api/upload.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/format/index.ts b/src/lib/format/index.ts index 3f676be..b0dc61a 100644 --- a/src/lib/format/index.ts +++ b/src/lib/format/index.ts @@ -2,6 +2,7 @@ import date from './date'; import gfycat from './gfycat'; import random from './random'; import uuid from './uuid'; +import { parse } from 'path'; export type NameFormat = 'random' | 'date' | 'uuid' | 'name' | 'gfycat'; export const NameFormats: NameFormat[] = ['random', 'date', 'uuid', 'name', 'gfycat']; @@ -14,7 +15,9 @@ export default async function formatFileName(nameFormat: NameFormat, originalNam case 'uuid': return uuid(); case 'name': - return originalName.split('.')[0]; + const { name } = parse(originalName); + + return name; case 'gfycat': return gfycat(); default: diff --git a/src/pages/api/upload.ts b/src/pages/api/upload.ts index b3124c7..5e3dc9e 100644 --- a/src/pages/api/upload.ts +++ b/src/pages/api/upload.ts @@ -12,7 +12,7 @@ import { createInvisImage, hashPassword } from 'lib/util'; import { parseExpiry } from 'lib/utils/client'; import { removeGPSData } from 'lib/utils/exif'; import multer from 'multer'; -import { join } from 'path'; +import { join, parse } from 'path'; import sharp from 'sharp'; import { Worker } from 'worker_threads'; @@ -200,7 +200,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { let mimetype = file.mimetype; if (file.mimetype === 'application/octet-stream' && zconfig.uploader.assume_mimetypes) { - const ext = file.originalname.split('.').pop(); + const ext = parse(file.originalname).ext.replace('.', ''); const mime = await guess(ext); if (!mime) response.assumed_mimetype = false; From 5f76e9d3833895bf2ca097e97253a1bbf15b5f8d Mon Sep 17 00:00:00 2001 From: diced Date: Sat, 6 May 2023 10:36:08 -0700 Subject: [PATCH 5/8] refactor: copy errors removed (#344) --- src/components/File/FileModal.tsx | 18 ++++------ src/components/Layout.tsx | 19 +++-------- src/components/pages/Dashboard/index.tsx | 26 ++++++--------- src/components/pages/Folders/index.tsx | 33 ++++++++----------- src/components/pages/Invites.tsx | 18 ++++------ src/components/pages/Manage/index.tsx | 24 ++++++++++++++ src/components/pages/MetadataView.tsx | 18 ++++------ .../pages/Upload/showFilesModal.tsx | 18 ++++------ src/components/pages/Urls/index.tsx | 18 ++++------ 9 files changed, 82 insertions(+), 110 deletions(-) diff --git a/src/components/File/FileModal.tsx b/src/components/File/FileModal.tsx index 1ac01f1..ed57719 100644 --- a/src/components/File/FileModal.tsx +++ b/src/components/File/FileModal.tsx @@ -95,18 +95,12 @@ export default function FileModal({ const handleCopy = () => { clipboard.copy(`${window.location.protocol}//${window.location.host}${file.url}`); setOpen(false); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: '', - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: '', + icon: , + }); }; const handleFavorite = async () => { diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 66859f6..c57a770 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -4,10 +4,8 @@ import { Box, Burger, Button, - Group, Header, Image, - Input, MediaQuery, Menu, Navbar, @@ -220,21 +218,14 @@ export default function Layout({ children, props }) { labels: { confirm: 'Copy', cancel: 'Cancel' }, onConfirm: async () => { clipboard.copy(token); + if (!navigator.clipboard) showNotification({ - title: 'Unable to copy to clipboard', - message: ( - - Zipline is unable to copy to clipboard due to security reasons. However, you can still copy - the token manually. -
- - Your token is: - e.target.select()} type='text' value={token} /> - -
- ), + title: 'Unable to copy token', + message: + "Zipline couldn't copy to your clipboard. Please copy the token manually from the settings page.", color: 'red', + icon: , }); else showNotification({ diff --git a/src/components/pages/Dashboard/index.tsx b/src/components/pages/Dashboard/index.tsx index 7143145..4e0a6f1 100644 --- a/src/components/pages/Dashboard/index.tsx +++ b/src/components/pages/Dashboard/index.tsx @@ -106,22 +106,16 @@ export default function Dashboard({ disableMediaPreview, exifEnabled, compress } const copyFile = async (file) => { clipboard.copy(`${window.location.protocol}//${window.location.host}${file.url}`); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: ( - {`${window.location.protocol}//${window.location.host}${file.url}`} - ), - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: ( + {`${window.location.protocol}//${window.location.host}${file.url}`} + ), + icon: , + }); }; const viewFile = async (file) => { diff --git a/src/components/pages/Folders/index.tsx b/src/components/pages/Folders/index.tsx index 8396484..844df0f 100644 --- a/src/components/pages/Folders/index.tsx +++ b/src/components/pages/Folders/index.tsx @@ -112,7 +112,7 @@ export default function Folders({ disableMediaPreview, exifEnabled, compress }) const makePublic = async (folder) => { const res = await useFetch(`/api/user/folders/${folder.id}`, 'PATCH', { - public: folder.public ? false : true, + public: !folder.public, }); if (!res.error) { @@ -363,25 +363,18 @@ export default function Folders({ disableMediaPreview, exifEnabled, compress }) aria-label='copy link' onClick={() => { clipboard.copy(`${window.location.origin}/folder/${folder.id}`); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied folder link', - message: ( - <> - Copied{' '} - folder link to - clipboard - - ), - color: 'green', - icon: , - }); + + showNotification({ + title: 'Copied folder link', + message: ( + <> + Copied folder link{' '} + to clipboard + + ), + color: 'green', + icon: , + }); }} > diff --git a/src/components/pages/Invites.tsx b/src/components/pages/Invites.tsx index 4145b37..71796b7 100644 --- a/src/components/pages/Invites.tsx +++ b/src/components/pages/Invites.tsx @@ -184,18 +184,12 @@ export default function Invites() { const handleCopy = async (invite) => { clipboard.copy(`${window.location.protocol}//${window.location.host}/auth/register?code=${invite.code}`); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: '', - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: '', + icon: , + }); }; const updateInvites = async () => { diff --git a/src/components/pages/Manage/index.tsx b/src/components/pages/Manage/index.tsx index 5e2555b..d58b67a 100644 --- a/src/components/pages/Manage/index.tsx +++ b/src/components/pages/Manage/index.tsx @@ -1,9 +1,11 @@ import { + ActionIcon, Anchor, Box, Button, Card, ColorInput, + CopyButton, FileInput, Group, Image, @@ -23,6 +25,8 @@ import { IconBrandDiscordFilled, IconBrandGithubFilled, IconBrandGoogle, + IconCheck, + IconClipboardCopy, IconFileExport, IconFiles, IconFilesOff, @@ -89,6 +93,7 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_ const [file, setFile] = useState(null); const [fileDataURL, setFileDataURL] = useState(user.avatar ?? null); const [totpEnabled, setTotpEnabled] = useState(!!user.totpSecret); + const [tokenShown, setTokenShown] = useState(false); const getDataURL = (f: File): Promise => { return new Promise((res, rej) => { @@ -365,6 +370,25 @@ export default function Manage({ oauth_registration, oauth_providers: raw_oauth_ the docs for variables + + + {({ copied, copy }) => ( + + {copied ? : } + + )} + + } + // @ts-ignore (this works even though ts doesn't allow for it) + component='span' + label='Token' + onClick={() => setTokenShown(true)} + > + {tokenShown ? user.token : '[click to reveal]'} + +
onSubmit(v))}> { clipboard.copy(value); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: value, - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: value, + icon: , + }); }; const searchValue = (value) => { diff --git a/src/components/pages/Upload/showFilesModal.tsx b/src/components/pages/Upload/showFilesModal.tsx index d0b6603..7b0205b 100644 --- a/src/components/pages/Upload/showFilesModal.tsx +++ b/src/components/pages/Upload/showFilesModal.tsx @@ -7,18 +7,12 @@ export default function showFilesModal(clipboard, modals, files: string[]) { const open = (idx: number) => window.open(files[idx], '_blank'); const copy = (idx: number) => { clipboard.copy(files[idx]); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: {files[idx]}, - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: {files[idx]}, + icon: , + }); }; modals.openModal({ diff --git a/src/components/pages/Urls/index.tsx b/src/components/pages/Urls/index.tsx index fd128d3..2bda0dc 100644 --- a/src/components/pages/Urls/index.tsx +++ b/src/components/pages/Urls/index.tsx @@ -169,18 +169,12 @@ export default function Urls() { const copyURL = (u) => { clipboard.copy(`${window.location.protocol}//${window.location.host}${u.url}`); - if (!navigator.clipboard) - showNotification({ - title: 'Unable to copy to clipboard', - message: 'Zipline is unable to copy to clipboard due to security reasons.', - color: 'red', - }); - else - showNotification({ - title: 'Copied to clipboard', - message: '', - icon: , - }); + + showNotification({ + title: 'Copied to clipboard', + message: '', + icon: , + }); }; const urlDelete = useURLDelete(); From f71aab2cdea2d00d6d4bf0c92577aac95daea81c Mon Sep 17 00:00:00 2001 From: diced Date: Sat, 6 May 2023 10:37:38 -0700 Subject: [PATCH 6/8] fix: body size limit for pfp (#389) --- src/pages/api/user/index.ts | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/pages/api/user/index.ts b/src/pages/api/user/index.ts index 200b627..e9cc3c1 100644 --- a/src/pages/api/user/index.ts +++ b/src/pages/api/user/index.ts @@ -1,4 +1,4 @@ -import config from 'lib/config'; +import zconfig from 'lib/config'; import Logger from 'lib/logger'; import { discord_auth, github_auth, google_auth } from 'lib/oauth'; import prisma from 'lib/prisma'; @@ -18,7 +18,7 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { return res.json({ error: 'oauth token expired', - redirect_uri: github_auth.oauth_url(config.oauth.github_client_id), + redirect_uri: github_auth.oauth_url(zconfig.oauth.github_client_id), }); } } else if (user.oauth.find((o) => o.provider === 'DISCORD')) { @@ -35,8 +35,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { return res.json({ error: 'oauth token expired', redirect_uri: discord_auth.oauth_url( - config.oauth.discord_client_id, - `${config.core.return_https ? 'https' : 'http'}://${req.headers.host}` + zconfig.oauth.discord_client_id, + `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}` ), }); } @@ -47,8 +47,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ - client_id: config.oauth.discord_client_id, - client_secret: config.oauth.discord_client_secret, + client_id: zconfig.oauth.discord_client_id, + client_secret: zconfig.oauth.discord_client_secret, grant_type: 'refresh_token', refresh_token: provider.refresh, }), @@ -59,8 +59,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { return res.json({ error: 'oauth token expired', redirect_uri: discord_auth.oauth_url( - config.oauth.discord_client_id, - `${config.core.return_https ? 'https' : 'http'}://${req.headers.host}` + zconfig.oauth.discord_client_id, + `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}` ), }); } @@ -90,8 +90,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { return res.json({ error: 'oauth token expired', redirect_uri: google_auth.oauth_url( - config.oauth.google_client_id, - `${config.core.return_https ? 'https' : 'http'}://${req.headers.host}` + zconfig.oauth.google_client_id, + `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}` ), }); } @@ -101,8 +101,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ - client_id: config.oauth.google_client_id, - client_secret: config.oauth.google_client_secret, + client_id: zconfig.oauth.google_client_id, + client_secret: zconfig.oauth.google_client_secret, grant_type: 'refresh_token', refresh_token: provider.refresh, }), @@ -113,8 +113,8 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { return res.json({ error: 'oauth token expired', redirect_uri: google_auth.oauth_url( - config.oauth.google_client_id, - `${config.core.return_https ? 'https' : 'http'}://${req.headers.host}` + zconfig.oauth.google_client_id, + `${zconfig.core.return_https ? 'https' : 'http'}://${req.headers.host}` ), }); } @@ -241,6 +241,14 @@ async function handler(req: NextApiReq, res: NextApiRes, user: UserExtended) { } } +export const config = { + api: { + bodyParser: { + sizeLimit: '50mb', + }, + }, +}; + export default withZipline(handler, { methods: ['GET', 'PATCH'], user: true, From ce26a414ac49cd1e7dc8db54af6c11a6850ff472 Mon Sep 17 00:00:00 2001 From: diced Date: Sat, 6 May 2023 10:41:46 -0700 Subject: [PATCH 7/8] fix: update reference (#392) --- .env.local.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.env.local.example b/.env.local.example index c79c221..a91d28b 100644 --- a/.env.local.example +++ b/.env.local.example @@ -3,7 +3,7 @@ # if using s3/supabase make sure to comment out the other datasources -CORE_HTTPS=true +CORE_RETURN_HTTPS=true CORE_SECRET="changethis" CORE_HOST=0.0.0.0 CORE_PORT=3000 @@ -44,3 +44,5 @@ URLS_LENGTH=6 RATELIMIT_USER=5 RATELIMIT_ADMIN=3 + +# for more variables checkout the docs \ No newline at end of file From 0a34b0cc21693b10cde36d55cceb08bdf26fc4a3 Mon Sep 17 00:00:00 2001 From: Dane Date: Sat, 6 May 2023 14:04:52 -0400 Subject: [PATCH 8/8] feat: bypass local login (#373) * adding option to bypass local login * oops * fix: add descriptive title --------- Co-authored-by: Jayvin Hernandez Co-authored-by: dicedtomato <35403473+diced@users.noreply.github.com> --- src/lib/config/Config.ts | 2 + src/lib/config/readConfig.ts | 2 + src/lib/config/validateConfig.ts | 2 + src/lib/middleware/getServerSideProps.ts | 2 + src/pages/auth/login.tsx | 82 ++++++++++++++---------- 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/src/lib/config/Config.ts b/src/lib/config/Config.ts index ac9bc6d..cb52c31 100644 --- a/src/lib/config/Config.ts +++ b/src/lib/config/Config.ts @@ -123,6 +123,8 @@ export interface ConfigFeatures { } export interface ConfigOAuth { + bypass_local_login: boolean; + github_client_id?: string; github_client_secret?: string; diff --git a/src/lib/config/readConfig.ts b/src/lib/config/readConfig.ts index 7a81d10..f2e94f0 100644 --- a/src/lib/config/readConfig.ts +++ b/src/lib/config/readConfig.ts @@ -136,6 +136,8 @@ export default function readConfig() { map('DISCORD_SHORTEN_EMBED_THUMBNAIL', 'boolean', 'discord.shorten.embed.thumbnail'), map('DISCORD_SHORTEN_EMBED_TIMESTAMP', 'boolean', 'discord.shorten.embed.timestamp'), + map('OAUTH_BYPASS_LOCAL_LOGIN', 'boolean', 'oauth.bypass_local_login'), + map('OAUTH_GITHUB_CLIENT_ID', 'string', 'oauth.github_client_id'), map('OAUTH_GITHUB_CLIENT_SECRET', 'string', 'oauth.github_client_secret'), diff --git a/src/lib/config/validateConfig.ts b/src/lib/config/validateConfig.ts index 272d47e..cbc0f99 100644 --- a/src/lib/config/validateConfig.ts +++ b/src/lib/config/validateConfig.ts @@ -168,6 +168,8 @@ const validator = s.object({ .nullish.default(null), oauth: s .object({ + bypass_local_login: s.boolean.default(false), + github_client_id: s.string.nullable.default(null), github_client_secret: s.string.nullable.default(null), diff --git a/src/lib/middleware/getServerSideProps.ts b/src/lib/middleware/getServerSideProps.ts index 9f2353f..44bf4f6 100644 --- a/src/lib/middleware/getServerSideProps.ts +++ b/src/lib/middleware/getServerSideProps.ts @@ -16,6 +16,7 @@ export type ServerSideProps = { user_registration: boolean; oauth_registration: boolean; oauth_providers: string; + bypass_local_login: boolean; chunks_size: number; max_size: number; totp_enabled: boolean; @@ -60,6 +61,7 @@ export const getServerSideProps: GetServerSideProps = async (ct user_registration: config.features.user_registration, oauth_registration: config.features.oauth_registration, oauth_providers: JSON.stringify(oauth_providers), + bypass_local_login: config.oauth.bypass_local_login, chunks_size: config.chunks.chunks_size, max_size: config.chunks.max_size, totp_enabled: config.mfa.totp_enabled, diff --git a/src/pages/auth/login.tsx b/src/pages/auth/login.tsx index 7106ab2..5203b90 100644 --- a/src/pages/auth/login.tsx +++ b/src/pages/auth/login.tsx @@ -22,7 +22,13 @@ import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; export { getServerSideProps } from 'middleware/getServerSideProps'; -export default function Login({ title, user_registration, oauth_registration, oauth_providers: unparsed }) { +export default function Login({ + title, + user_registration, + oauth_registration, + bypass_local_login, + oauth_providers: unparsed, +}) { const router = useRouter(); // totp modal @@ -34,6 +40,9 @@ export default function Login({ title, user_registration, oauth_registration, oa const oauth_providers = JSON.parse(unparsed); + const show_local_login = + router.query.local === 'true' || !(bypass_local_login && oauth_providers?.length > 0); + const icons = { GitHub: IconBrandGithub, Discord: IconBrandDiscordFilled, @@ -99,6 +108,12 @@ export default function Login({ title, user_registration, oauth_registration, oa useEffect(() => { (async () => { + // if the user includes `local=true` as a query param, show the login form + // otherwise, redirect to the oauth login if there is only one registered provider + if (bypass_local_login && oauth_providers?.length === 1 && router.query.local !== 'true') { + await router.push(oauth_providers[0].url); + } + const a = await fetch('/api/user'); if (a.ok) await router.push('/dashboard'); })(); @@ -152,7 +167,7 @@ export default function Login({ title, user_registration, oauth_registration, oa
- {title} + {bypass_local_login ? ' Login to Zipline with' : 'Zipline'} {oauth_registration && ( @@ -165,7 +180,7 @@ export default function Login({ title, user_registration, oauth_registration, oa variant='outline' radius='md' fullWidth - leftIcon={} + leftIcon={} my='xs' component={Link} href={url} @@ -174,41 +189,42 @@ export default function Login({ title, user_registration, oauth_registration, oa ))} - - + {show_local_login && } )} - onSubmit(v))}> - - + {show_local_login && ( + onSubmit(v))}> + + - - {user_registration && ( - - Don't have an account? Register - - )} + + {user_registration && ( + + Don't have an account? Register + + )} - - - + + + + )}