From ea603804a2de29dc8a54ab5a0a1a1e628993fddd Mon Sep 17 00:00:00 2001
From: strNophix
Date: Sun, 16 Oct 2022 15:58:23 +0200
Subject: [PATCH] WIP bunch of stuff
---
...entity.schema.json => default.schema.json} | 6 +-
.docker/kratos/kratos.yml | 22 +--
client/components/FormField.tsx | 22 +--
client/components/Input.tsx | 35 ++--
client/components/SignupForm.tsx | 168 ++++++++++++------
client/components/SubmitButton.tsx | 17 +-
client/config/index.ts | 3 +-
client/pages/api/.ory/[...paths].ts | 13 ++
client/services/ory/index.ts | 4 +
9 files changed, 187 insertions(+), 103 deletions(-)
rename .docker/kratos/{identity.schema.json => default.schema.json} (89%)
create mode 100644 client/pages/api/.ory/[...paths].ts
create mode 100644 client/services/ory/index.ts
diff --git a/.docker/kratos/identity.schema.json b/.docker/kratos/default.schema.json
similarity index 89%
rename from .docker/kratos/identity.schema.json
rename to .docker/kratos/default.schema.json
index 12222ae..d84cbb0 100644
--- a/.docker/kratos/identity.schema.json
+++ b/.docker/kratos/default.schema.json
@@ -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
}
}
diff --git a/.docker/kratos/kratos.yml b/.docker/kratos/kratos.yml
index 7db6617..5bb6918 100644
--- a/.docker/kratos/kratos.yml
+++ b/.docker/kratos/kratos.yml
@@ -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:
diff --git a/client/components/FormField.tsx b/client/components/FormField.tsx
index fe7e64b..5c3c413 100644
--- a/client/components/FormField.tsx
+++ b/client/components/FormField.tsx
@@ -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(
- ({ label, bottomElement, ...inputProps }, ref) => {
+ ({ label, bottomElement, hidden, ...inputProps }, ref) => {
return (
{label}
-
{bottomElement}
- );
- }
-);
+ )
+ },
+)
-export default FormField;
+export default FormField
diff --git a/client/components/Input.tsx b/client/components/Input.tsx
index 1162805..04f83d8 100644
--- a/client/components/Input.tsx
+++ b/client/components/Input.tsx
@@ -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(({ className, ...rest }, ref) => {
- return (
-
- );
-});
+const Input = forwardRef(
+ ({ className, ...rest }, ref) => {
+ return (
+
+ )
+ },
+)
-export default Input;
+export default Input
diff --git a/client/components/SignupForm.tsx b/client/components/SignupForm.tsx
index 634596f..43fa3b5 100644
--- a/client/components/SignupForm.tsx
+++ b/client/components/SignupForm.tsx
@@ -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;
+type SignupFormValues = z.infer
+
+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();
- const { register, handleSubmit } = useForm({
+ const router = useRouter()
+ const [flow, setFlow] = useState()
+ const { flow: flowId, return_to: returnTo } = router.query
+ const { register, handleSubmit, formState } = useForm({
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 = 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 (
+ }
+ />
+ ))}
- By clicking Sign Up, you are agreeing to twitch-clone's{' '}
+ By clicking Sign Up, you are agreeing to twitch-clone's{" "}
Terms of Service
@@ -75,7 +137,7 @@ const SignupForm: FC = () => {
- );
-};
+ )
+}
-export default SignupForm;
+export default SignupForm
diff --git a/client/components/SubmitButton.tsx b/client/components/SubmitButton.tsx
index 2314bc0..85ef69a 100644
--- a/client/components/SubmitButton.tsx
+++ b/client/components/SubmitButton.tsx
@@ -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 = ({ className, ...rest }) => {
return (
- );
-};
+ )
+}
-export default SubmitButton;
+export default SubmitButton
diff --git a/client/config/index.ts b/client/config/index.ts
index 5421cc1..3a2a2b0 100644
--- a/client/config/index.ts
+++ b/client/config/index.ts
@@ -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"
diff --git a/client/pages/api/.ory/[...paths].ts b/client/pages/api/.ory/[...paths].ts
new file mode 100644
index 0000000..5d4bb31
--- /dev/null
+++ b/client/pages/api/.ory/[...paths].ts
@@ -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,
+})
diff --git a/client/services/ory/index.ts b/client/services/ory/index.ts
new file mode 100644
index 0000000..033ac87
--- /dev/null
+++ b/client/services/ory/index.ts
@@ -0,0 +1,4 @@
+import { Configuration, V0alpha2Api } from "@ory/client"
+import { edgeConfig } from "@ory/integrations/next"
+
+export default new V0alpha2Api(new Configuration(edgeConfig))