mirror of
https://github.com/diced/zipline.git
synced 2025-12-06 12:51:13 -08:00
feat: bypass local login & block creation
This commit is contained in:
@@ -52,6 +52,8 @@ export const PROP_TO_ENV: Record<string, string> = {
|
||||
'website.defaultAvatar': 'WEBSITE_DEFAULT_AVATAR',
|
||||
'website.disableMediaPreview': 'WEBSITE_DISABLE_MEDIA_PREVIEW',
|
||||
|
||||
'oauth.bypassLocalLogin': 'OAUTH_BYPASS_LOCAL_LOGIN',
|
||||
'oauth.loginOnly': 'OAUTH_LOGIN_ONLY',
|
||||
'oauth.discord.clientId': 'OAUTH_DISCORD_CLIENT_ID',
|
||||
'oauth.discord.clientSecret': 'OAUTH_DISCORD_CLIENT_SECRET',
|
||||
'oauth.github.clientId': 'OAUTH_GITHUB_CLIENT_ID',
|
||||
@@ -107,6 +109,8 @@ export function readEnv() {
|
||||
env(PROP_TO_ENV['website.defaultAvatar'], 'website.defaultAvatar', 'string'),
|
||||
env(PROP_TO_ENV['website.disableMediaPreview'], 'website.disableMediaPreview', 'boolean'),
|
||||
|
||||
env(PROP_TO_ENV['oauth.bypassLocalLogin'], 'oauth.bypassLocalLogin', 'boolean'),
|
||||
env(PROP_TO_ENV['oauth.loginOnly'], 'oauth.loginOnly', 'boolean'),
|
||||
env(PROP_TO_ENV['oauth.discord.clientId'], 'oauth.discord.clientId', 'string'),
|
||||
env(PROP_TO_ENV['oauth.discord.clientSecret'], 'oauth.discord.clientSecret', 'string'),
|
||||
env(PROP_TO_ENV['oauth.github.clientId'], 'oauth.github.clientId', 'string'),
|
||||
@@ -162,6 +166,8 @@ export function readEnv() {
|
||||
disableMediaPreview: undefined,
|
||||
},
|
||||
oauth: {
|
||||
bypassLocalLogin: undefined,
|
||||
loginOnly: undefined,
|
||||
discord: {
|
||||
clientId: undefined,
|
||||
clientSecret: undefined,
|
||||
|
||||
@@ -4,12 +4,20 @@ import { Config } from './validate';
|
||||
|
||||
export type SafeConfig = Omit<Config, 'oauth' | 'datasource' | 'core'> & {
|
||||
oauthEnabled: ReturnType<typeof enabled>;
|
||||
oauth: {
|
||||
bypassLocalLogin: boolean;
|
||||
loginOnly: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export function safeConfig(): SafeConfig {
|
||||
const { datasource, core, oauth, ...rest } = config;
|
||||
|
||||
(rest as SafeConfig).oauthEnabled = enabled(config);
|
||||
(rest as SafeConfig).oauth = {
|
||||
bypassLocalLogin: oauth.bypassLocalLogin,
|
||||
loginOnly: oauth.loginOnly,
|
||||
};
|
||||
|
||||
return rest as SafeConfig;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,8 @@ export const schema = z.object({
|
||||
disableMediaPreview: z.boolean().default(false),
|
||||
}),
|
||||
oauth: z.object({
|
||||
bypassLocalLogin: z.boolean().default(false),
|
||||
loginOnly: z.boolean().default(false),
|
||||
discord: z
|
||||
.object({
|
||||
clientId: z.string(),
|
||||
|
||||
@@ -175,6 +175,8 @@ export const withOAuth =
|
||||
});
|
||||
|
||||
return res.redirect('/dashboard');
|
||||
} else if (config.oauth.loginOnly) {
|
||||
return res.badRequest('Can\'t create users through oauth.');
|
||||
} else if (existingUser) {
|
||||
return res.badRequest('This username is already taken');
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Response } from '@/lib/api/response';
|
||||
import { config } from '@/lib/config';
|
||||
import { SafeConfig } from '@/lib/config/safe';
|
||||
import { getZipline } from '@/lib/db/models/zipline';
|
||||
import { fetchApi } from '@/lib/fetchApi';
|
||||
import { withSafeConfig } from '@/lib/middleware/next/withSafeConfig';
|
||||
import { eitherTrue, isTruthy } from '@/lib/primitive';
|
||||
import { Button, Center, PasswordInput, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { Button, Center, LoadingOverlay, PasswordInput, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { hasLength, useForm } from '@mantine/form';
|
||||
import {
|
||||
IconBrandDiscordFilled,
|
||||
@@ -22,6 +23,17 @@ export default function Login({ config }: InferGetServerSidePropsType<typeof get
|
||||
const router = useRouter();
|
||||
const { data, isLoading, mutate } = useSWR<Response['/api/user']>('/api/user');
|
||||
|
||||
const showLocalLogin =
|
||||
router.query.local === 'true' ||
|
||||
!(
|
||||
config.oauth.bypassLocalLogin && Object.values(config.oauthEnabled).filter((x) => x === true).length > 0
|
||||
);
|
||||
|
||||
const willRedirect =
|
||||
config.oauth.bypassLocalLogin &&
|
||||
Object.values(config.oauthEnabled).filter((x) => x === true).length === 1 &&
|
||||
router.query.local !== 'true';
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.user) {
|
||||
router.push('/dashboard');
|
||||
@@ -55,14 +67,30 @@ export default function Login({ config }: InferGetServerSidePropsType<typeof get
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (willRedirect) {
|
||||
const provider = Object.keys(config.oauthEnabled).find(
|
||||
(x) => config.oauthEnabled[x as keyof SafeConfig['oauthEnabled']] === true
|
||||
);
|
||||
|
||||
if (provider) {
|
||||
router.push(`/api/auth/oauth/${provider}`);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{willRedirect && !showLocalLogin && <LoadingOverlay visible />}
|
||||
|
||||
<Center h='100vh'>
|
||||
<div>
|
||||
<Title order={1} size={50} align='center'>
|
||||
<b>Zipline</b>
|
||||
</Title>
|
||||
|
||||
{showLocalLogin && (
|
||||
<>
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<Stack my='sm'>
|
||||
<TextInput
|
||||
@@ -84,18 +112,20 @@ export default function Login({ config }: InferGetServerSidePropsType<typeof get
|
||||
</form>
|
||||
|
||||
{eitherTrue(config.features.oauthRegistration, config.features.userRegistration) && (
|
||||
<Text size='sm' align='center' color='dimmed'>
|
||||
<Text size='sm' my='xs' align='center' color='dimmed'>
|
||||
OR
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Stack my='xs'>
|
||||
{config.features.userRegistration && (
|
||||
<Button size='lg' fullWidth variant='outline' color='gray'>
|
||||
Sign up
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Stack my='xs'>
|
||||
{config.oauthEnabled.discord && (
|
||||
<Button
|
||||
size='lg'
|
||||
|
||||
Reference in New Issue
Block a user