Sign in with google

This commit is contained in:
Gilbert
2024-04-23 21:22:11 -05:00
parent c395be82b5
commit d2daed4cac
10 changed files with 222 additions and 70 deletions
+7 -7
View File
@@ -21,14 +21,14 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
"@snowballtools/auth": "0.1.0",
"@snowballtools/auth-lit": "0.1.0",
"@snowballtools/js-sdk": "0.1.0",
"@snowballtools/link-lit-alchemy-light": "0.1.0",
"@snowballtools/auth": "^0.1.0",
"@snowballtools/auth-lit": "^0.1.0",
"@snowballtools/js-sdk": "^0.1.0",
"@snowballtools/link-lit-alchemy-light": "^0.1.0",
"@snowballtools/material-tailwind-react-fork": "^2.1.10",
"@snowballtools/smartwallet-alchemy-light": "0.1.0",
"@snowballtools/types": "0.1.0",
"@snowballtools/utils": "0.1.0",
"@snowballtools/smartwallet-alchemy-light": "^0.1.0",
"@snowballtools/types": "^0.1.0",
"@snowballtools/utils": "^0.1.0",
"@tanstack/react-query": "^5.22.2",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
+3 -5
View File
@@ -64,10 +64,8 @@ function App() {
}).then((res) => {
if (res.status !== 200) {
localStorage.clear();
if (
window.location.pathname !== '/login' &&
window.location.pathname !== '/signup'
) {
const path = window.location.pathname;
if (path !== '/login' && path !== '/signup') {
window.location.pathname = '/login';
}
}
@@ -76,7 +74,7 @@ function App() {
return (
<Web3Provider>
<RouterProvider router={router} />;
<RouterProvider router={router} />
</Web3Provider>
);
}
+81 -13
View File
@@ -9,12 +9,15 @@ import {
import { GoogleIcon } from 'components/shared/CustomIcon/GoogleIcon';
import { DotBorder } from 'components/shared/DotBorder';
import { WavyBorder } from 'components/shared/WavyBorder';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { CreatePasskey } from './CreatePasskey';
import { AppleIcon } from 'components/shared/CustomIcon/AppleIcon';
import { KeyIcon } from 'components/shared/CustomIcon/KeyIcon';
import { useToast } from 'components/shared/Toast';
import { Link } from 'react-router-dom';
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
import { signInWithEthereum } from 'utils/siwe';
import { useSnowball } from 'utils/use-snowball';
type Provider = 'google' | 'github' | 'apple' | 'email' | 'passkey';
@@ -23,6 +26,8 @@ type Props = {
};
export const Login = ({ onDone }: Props) => {
const snowball = useSnowball();
const [error, setError] = useState<string>('');
const [provider, setProvider] = useState<Provider | false>(false);
// const loading = snowball.auth.state.loading && provider;
@@ -33,6 +38,59 @@ export const Login = ({ onDone }: Props) => {
return <CreatePasskey onDone={onDone} />;
}
async function handleSigninRedirect() {
let wallet: PKPEthersWallet | undefined;
const { google } = snowball.auth;
if (google.canHandleOAuthRedirectBack()) {
setProvider('google');
console.log('Handling google redirect back');
try {
await google.handleOAuthRedirectBack();
wallet = await google.getEthersWallet();
const result = await signInWithEthereum(1, 'login', wallet);
if (result.error) {
setError(result.error);
setProvider(false);
wallet = undefined;
return;
}
} catch (err: any) {
setError(err.message);
console.log(err.message, err.name, err.details);
setProvider(false);
return;
}
}
// if (apple.canHandleOAuthRedirectBack()) {
// setProvider('apple');
// console.log('Handling apple redirect back');
// try {
// await apple.handleOAuthRedirectBack();
// wallet = await apple.getEthersWallet();
// const result = await signInWithEthereum(1, 'login', wallet);
// if (result.error) {
// setError(result.error);
// setProvider(false);
// wallet = undefined;
// return;
// }
// } catch (err: any) {
// setError(err.message);
// console.log(err.message, err.name, err.details);
// setProvider(false);
// return;
// }
// }
if (wallet) {
window.location.pathname = '/';
}
}
useEffect(() => {
handleSigninRedirect();
}, []);
return (
<div>
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
@@ -114,7 +172,7 @@ export const Login = ({ onDone }: Props) => {
}
onClick={() => {
setProvider('google');
// snowball.auth.createPasskey();
snowball.auth.google.startOAuthRedirect();
}}
className="flex-1 self-stretch"
variant={'tertiary'}
@@ -157,6 +215,7 @@ export const Login = ({ onDone }: Props) => {
}
onClick={async () => {
setProvider('apple');
// snowball.auth.apple.startOAuthRedirect();
await new Promise((resolve) => setTimeout(resolve, 800));
setProvider(false);
toast({
@@ -175,17 +234,26 @@ export const Login = ({ onDone }: Props) => {
Continue with Apple
</Button>
</div>
<div className="h-5 justify-center items-center gap-2 inline-flex">
<div className="text-center text-slate-600 text-sm font-normal font-['Inter'] leading-tight">
Don't have an account?
</div>
<div className="justify-center items-center gap-1.5 flex">
<Link
to="/signup"
className="text-sky-950 text-sm font-normal font-['Inter'] underline leading-tight"
>
Sign up now
</Link>
<div className="flex flex-col gap-3">
{error && (
<div className="justify-center items-center gap-2 inline-flex">
<div className="text-red-500 text-sm">Error: {error}</div>
</div>
)}
<div className="h-5 justify-center items-center gap-2 inline-flex">
<div className="text-center text-slate-600 text-sm font-normal font-['Inter'] leading-tight">
Don't have an account?
</div>
<div className="justify-center items-center gap-1.5 flex">
<Link
to="/signup"
className="text-sky-950 text-sm font-normal font-['Inter'] underline leading-tight"
>
Sign up now
</Link>
</div>
</div>
</div>
</div>
+64 -16
View File
@@ -19,12 +19,15 @@ import { signInWithEthereum } from 'utils/siwe';
type Provider = 'google' | 'github' | 'apple' | 'email';
type Err = { type: 'email' | 'provider'; message: string };
type Props = {
onDone: () => void;
};
export const SignUp = ({ onDone }: Props) => {
const [email, setEmail] = useState('');
const [error, setError] = useState<Err | null>();
const [provider, setProvider] = useState<Provider | false>(false);
const { toast } = useToast();
@@ -32,13 +35,43 @@ export const SignUp = ({ onDone }: Props) => {
async function handleSignupRedirect() {
let wallet: PKPEthersWallet | undefined;
const google = snowball.auth.google;
const { google } = snowball.auth;
if (google.canHandleOAuthRedirectBack()) {
setProvider('google');
await google.handleOAuthRedirectBack();
wallet = await google.getEthersWallet();
await signInWithEthereum(wallet);
try {
await google.handleOAuthRedirectBack();
wallet = await google.getEthersWallet();
const result = await signInWithEthereum(1, 'signup', wallet);
if (result.error) {
setError({ type: 'provider', message: result.error });
setProvider(false);
wallet = undefined;
return;
}
} catch (err: any) {
setError({ type: 'provider', message: err.message });
setProvider(false);
return;
}
}
// if (apple.canHandleOAuthRedirectBack()) {
// setProvider('apple');
// try {
// await apple.handleOAuthRedirectBack();
// wallet = await apple.getEthersWallet();
// const result = await signInWithEthereum(1, 'signup', wallet);
// if (result.error) {
// setError({ type: 'provider', message: result.error });
// setProvider(false);
// wallet = undefined;
// return;
// }
// } catch (err: any) {
// setError({ type: 'provider', message: err.message });
// setProvider(false);
// return;
// }
// }
if (wallet) {
onDone();
@@ -118,6 +151,7 @@ export const SignUp = ({ onDone }: Props) => {
}
onClick={async () => {
setProvider('apple');
// snowball.auth.apple.startOAuthRedirect();
await new Promise((resolve) => setTimeout(resolve, 800));
setProvider(false);
toast({
@@ -137,6 +171,12 @@ export const SignUp = ({ onDone }: Props) => {
</Button>
</div>
{error && error.type === 'provider' && (
<div className="-mt-3 justify-center items-center inline-flex">
<div className="text-red-500 text-sm">Error: {error.message}</div>
</div>
)}
<div className="self-stretch justify-start items-center gap-8 inline-flex">
<DotBorder className="flex-1" />
<div className="text-center text-slate-400 text-xs font-normal font-['JetBrains Mono'] leading-none">
@@ -166,18 +206,26 @@ export const SignUp = ({ onDone }: Props) => {
>
Continue with Email
</Button>
<div className="h-5 justify-center items-center gap-2 inline-flex">
<div className="text-center text-slate-600 text-sm font-normal font-['Inter'] leading-tight">
Already an user?
</div>
<div className="justify-center items-center gap-1.5 flex">
<Link
to="/login"
className="text-sky-950 text-sm font-normal font-['Inter'] underline leading-tight"
>
Sign in now
</Link>
<div className="flex flex-col gap-3">
{error && error.type === 'email' && (
<div className="justify-center items-center gap-2 inline-flex">
<div className="text-red-500 text-sm">
Error: {error.message}
</div>
</div>
)}
<div className="justify-center items-center gap-2 inline-flex">
<div className="text-center text-slate-600 text-sm font-normal font-['Inter'] leading-tight">
Already an user?
</div>
<div className="justify-center items-center gap-1.5 flex">
<Link
to="/login"
className="text-sky-950 text-sm font-normal font-['Inter'] underline leading-tight"
>
Sign in now
</Link>
</div>
</div>
</div>
</div>
+14 -5
View File
@@ -5,8 +5,13 @@ import { v4 as uuid } from 'uuid';
const domain = window.location.host;
const origin = window.location.origin;
export async function signInWithEthereum(wallet: PKPEthersWallet) {
export async function signInWithEthereum(
chainId: number,
action: 'signup' | 'login',
wallet: PKPEthersWallet,
) {
const message = await createSiweMessage(
chainId,
await wallet.getAddress(),
'Sign in with Ethereum to the app.',
);
@@ -17,20 +22,24 @@ export async function signInWithEthereum(wallet: PKPEthersWallet) {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message, signature }),
body: JSON.stringify({ action, message, signature }),
credentials: 'include',
});
console.log(await res.text());
return (await res.json()) as { success: boolean; error?: string };
}
async function createSiweMessage(address: string, statement: string) {
async function createSiweMessage(
chainId: number,
address: string,
statement: string,
) {
const message = new SiweMessage({
domain,
address,
statement,
uri: origin,
version: '1',
chainId: 1,
chainId,
nonce: uuid().replace(/[^a-z0-9]/g, ''),
});
return message.prepareMessage();
+8 -1
View File
@@ -1,11 +1,18 @@
import { useEffect, useState } from 'react';
import { Snowball, SnowballChain } from '@snowballtools/js-sdk';
import { LitGoogleAuth, LitPasskeyAuth } from '@snowballtools/auth-lit';
import {
// LitAppleAuth,
LitGoogleAuth,
LitPasskeyAuth,
} from '@snowballtools/auth-lit';
export const snowball = Snowball.withAuth({
google: LitGoogleAuth.configure({
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
}),
// apple: LitAppleAuth.configure({
// litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
// }),
passkey: LitPasskeyAuth.configure({
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
}),