WIP bunch of stuff

This commit is contained in:
strNophix 2022-10-16 15:58:23 +02:00
parent b4ff0c8f77
commit ea603804a2
9 changed files with 187 additions and 103 deletions

View File

@ -10,7 +10,6 @@
"email": {
"type": "string",
"format": "email",
"title": "E-Mail",
"minLength": 3,
"ory.sh/kratos": {
"credentials": {
@ -27,11 +26,12 @@
}
},
"username": {
"title": "Username",
"type": "string",
"title": "Username"
"minLength": 3
}
},
"required": ["email", "username"],
"required": ["email"],
"additionalProperties": false
}
}

View File

@ -11,42 +11,42 @@ serve:
base_url: http://kratos:4434/
selfservice:
default_browser_return_url: http://127.0.0.1:5173/
default_browser_return_url: http://127.0.0.1:3000/
allowed_return_urls:
- http://127.0.0.1:5173/
- http://127.0.0.1:3000/
methods:
password:
enabled: true
flows:
error:
ui_url: http://127.0.0.1:5173/error
ui_url: http://127.0.0.1:3000/error
settings:
ui_url: http://127.0.0.1:5173/settings
ui_url: http://127.0.0.1:3000/settings
privileged_session_max_age: 15m
recovery:
enabled: false
ui_url: http://127.0.0.1:5173/recovery
ui_url: http://127.0.0.1:3000/recovery
verification:
enabled: false
ui_url: http://127.0.0.1:5173/verification
ui_url: http://127.0.0.1:3000/verification
after:
default_browser_return_url: http://127.0.0.1:5173/
default_browser_return_url: http://127.0.0.1:3000/
logout:
after:
default_browser_return_url: http://127.0.0.1:5173/login
default_browser_return_url: http://127.0.0.1:3000/login
login:
ui_url: http://127.0.0.1:5173/login
ui_url: http://127.0.0.1:3000/login
lifespan: 10m
registration:
lifespan: 10m
ui_url: http://127.0.0.1:5173/signup
ui_url: http://127.0.0.1:3000/signup
after:
password:
hooks:
@ -75,7 +75,7 @@ identity:
default_schema_id: default
schemas:
- id: default
url: file:///etc/config/kratos/identity.schema.json
url: file:///etc/config/kratos/default.schema.json
courier:
smtp:

View File

@ -1,25 +1,25 @@
import { forwardRef, ReactNode } from 'react';
/* eslint-disable react/display-name */
import { forwardRef, ReactNode } from "react"
import Input from './Input';
import Input from "./Input"
interface FormFieldProps extends React.ComponentPropsWithoutRef<'input'> {
label: string;
bottomElement?: ReactNode;
interface FormFieldProps extends React.ComponentPropsWithoutRef<"input"> {
label?: string
bottomElement?: ReactNode
}
const FormField = forwardRef<HTMLInputElement, FormFieldProps>(
({ label, bottomElement, ...inputProps }, ref) => {
({ label, bottomElement, hidden, ...inputProps }, ref) => {
return (
<div className="space-y-1">
<label htmlFor={inputProps.id} className="font-semibold text-sm">
{label}
</label>
<br />
<Input {...inputProps} ref={ref} />
{bottomElement}
</div>
);
}
);
)
},
)
export default FormField;
export default FormField

View File

@ -1,19 +1,22 @@
import clsx from 'clsx';
import { forwardRef } from 'react';
/* eslint-disable react/display-name */
import clsx from "clsx"
import { forwardRef } from "react"
type InputProps = React.ComponentPropsWithoutRef<'input'>;
type InputProps = React.ComponentPropsWithoutRef<"input">
const Input = forwardRef<HTMLInputElement, InputProps>(({ className, ...rest }, ref) => {
return (
<input
className={clsx(
'bg-zinc-700 rounded-md box-border focus:outline outline-violet-400 text-sm',
className
)}
{...rest}
ref={ref}
/>
);
});
const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, ...rest }, ref) => {
return (
<input
className={clsx(
"bg-zinc-700 rounded-md box-border focus:outline outline-violet-400 text-sm",
className,
)}
{...rest}
ref={ref}
/>
)
},
)
export default Input;
export default Input

View File

@ -1,73 +1,135 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { SelfServiceRegistrationFlow } from '@ory/client';
import { FC, useEffect, useState } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from "@hookform/resolvers/zod"
import { SelfServiceRegistrationFlow } from "@ory/client"
import { useRouter } from "next/router"
import { useMemo } from "react"
import { FC, useEffect, useState } from "react"
import { SubmitHandler, useForm } from "react-hook-form"
import { z } from "zod"
import ory from "../services/ory"
import FormField from "./FormField"
import InlineLink from "./InlineLink"
import Input from "./Input"
import SubmitButton from "./SubmitButton"
import FormField from './FormField';
import InlineLink from './InlineLink';
import SubmitButton from './SubmitButton';
const PASSWORD_REGEX = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,64}$/;
const PASSWORD_REGEX =
/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,64}$/
const SignupFormSchema = z
.object({
username: z.string().trim().min(1).max(16),
password: z.string().trim().regex(PASSWORD_REGEX),
csrfToken: z.string(),
username: z
.string()
.trim()
.min(1, { message: "Username must be at least 1 character long." })
.max(16, { message: "Username can't be longer than 16 characters.." }),
password: z
.string()
.trim()
.regex(
PASSWORD_REGEX,
"Password must be 8-64 long and must contain a number, uppercase, lowercase and special character.",
),
passwordRepeat: z.string().trim(),
email: z.string().email().trim(),
email: z.string().email({ message: "Not a valid email address" }).trim(),
})
.refine((data) => data.password === data.passwordRepeat, {
message: "Passwords don't match",
path: ['passwordRepeat'],
});
message: "Passwords do not match.",
path: ["passwordRepeat"],
})
type SignupFormValues = z.infer<typeof SignupFormSchema>;
type SignupFormValues = z.infer<typeof SignupFormSchema>
const formFields = [
{ id: "username", label: "Username", type: "text" },
{ id: "password", label: "Password", type: "password" },
{ id: "passwordRepeat", label: "Confirm Password", type: "password" },
{ id: "email", label: "Email", type: "email" },
]
const SignupForm: FC = () => {
// const navigate = useNavigate();
// const { flow: flowId, return_to: returnTo } = useParams<{ flow?: string; return_to?: string }>();
// const [flow, setFlow] = useState<SelfServiceRegistrationFlow>();
const { register, handleSubmit } = useForm<SignupFormValues>({
const router = useRouter()
const [flow, setFlow] = useState<SelfServiceRegistrationFlow>()
const { flow: flowId, return_to: returnTo } = router.query
const { register, handleSubmit, formState } = useForm<SignupFormValues>({
resolver: zodResolver(SignupFormSchema),
});
})
useEffect(() => {
const func = async () => {
if (!router.isReady || flow) {
return
}
let serviceFlow
if (flowId) {
serviceFlow = await ory.getSelfServiceRegistrationFlow(String(flowId))
} else {
serviceFlow =
await ory.initializeSelfServiceRegistrationFlowForBrowsers(
returnTo ? String(returnTo) : undefined,
)
}
setFlow(serviceFlow.data)
}
func()
}, [flowId, router, router.isReady, returnTo, flow])
const onSubmit: SubmitHandler<SignupFormValues> = async (data) => {
console.log({data})
};
await router.push(`/signup?flow=${flow?.id}`, undefined, {
shallow: true,
})
try {
const resp = await ory.submitSelfServiceRegistrationFlow(
String(flow?.id),
{
csrf_token: data.csrfToken,
method: "password",
password: data.password,
traits: {
email: data.email,
// username: data.username,
},
},
)
console.log(resp)
} catch (e) {
console.log(e)
}
}
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
{flow && (
<Input
hidden={true}
value={flow.ui.nodes[0].attributes.value}
{...register("csrfToken")}
/>
)}
<p className="text-sm">
Creating an account allows you to participate in chat, follow your favorite channels, and
broadcast from your own channel.
Creating an account allows you to participate in chat, follow your
favorite channels, and broadcast from your own channel.
</p>
<FormField
label="Username"
{...register('username')}
className="py-2 px-2 outline-2 w-full"
/>
<FormField
label="Password"
{...register('password')}
type="password"
className="py-2 px-2 outline-2 w-full"
/>
<FormField
label="Confirm Password"
{...register('passwordRepeat')}
type="password"
className="py-2 px-2 outline-2 w-full"
/>
<FormField
label="Email"
{...register('email')}
type="email"
className="py-2 px-2 outline-2 w-full"
/>
{formFields.map((field) => (
<FormField
key={field.id}
id={field.id}
type={field.type}
label={field.label}
{...register(field.id as any)}
className="py-2 px-2 outline-2 w-full"
bottomElement={
<p className="text-xs">
{formState.errors[(field.id as any) || ""]?.message}
</p>
}
/>
))}
<p className="text-sm text-center">
By clicking Sign Up, you are agreeing to twitch-clone&apos;s{' '}
By clicking Sign Up, you are agreeing to twitch-clone&apos;s{" "}
<InlineLink to="https://tosdr.org/en/service/200">
Terms of Service
</InlineLink>
@ -75,7 +137,7 @@ const SignupForm: FC = () => {
</p>
<SubmitButton className="w-full" value="Sign Up" />
</form>
);
};
)
}
export default SignupForm;
export default SignupForm

View File

@ -1,16 +1,19 @@
import clsx from 'clsx';
import { FC } from 'react';
import clsx from "clsx"
import { FC } from "react"
type ButtonProps = React.ComponentPropsWithoutRef<'input'>;
type ButtonProps = React.ComponentPropsWithoutRef<"input">
const SubmitButton: FC<ButtonProps> = ({ className, ...rest }) => {
return (
<input
type="submit"
className={clsx('rounded-md bg-violet-500 font-semibold py-2 text-sm', className)}
className={clsx(
"cursor-pointer rounded-md bg-violet-500 font-semibold py-2 text-sm",
className,
)}
{...rest}
/>
);
};
)
}
export default SubmitButton;
export default SubmitButton

View File

@ -1,2 +1 @@
export const API_URL = 'http://localhost:5000';
export const KRATOS_URL = 'http://127.0.0.1:4433';
export const KRATOS_URL = "http://127.0.0.1:4433"

View File

@ -0,0 +1,13 @@
// @ory/integrations offers a package for integrating with NextJS.
import { config, createApiHandler } from "@ory/integrations/next-edge"
// We need to export the config.
export { config }
// And create the Ory Cloud API "bridge".
export default createApiHandler({
fallbackToPlayground: true,
// Because vercel.app is a public suffix and setting cookies for
// vercel.app is not possible.
dontUseTldForCookieDomain: true,
})

View File

@ -0,0 +1,4 @@
import { Configuration, V0alpha2Api } from "@ory/client"
import { edgeConfig } from "@ory/integrations/next"
export default new V0alpha2Api(new Configuration(edgeConfig))