Skip to content

Commit

Permalink
Merge pull request #35 from openfort-xyz/unity-bridge
Browse files Browse the repository at this point in the history
fix: linter
  • Loading branch information
jamalavedra authored Jun 20, 2024
2 parents 0cf34f6 + e438cea commit 1f07375
Show file tree
Hide file tree
Showing 35 changed files with 1,076 additions and 307 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.9] - 2024-06-20
### Fix
- Fix Shield authentication

## [0.7.8] - 2024-06-11
### Added
- Add new linking/unlink methods
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/auth-sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@heroicons/react": "^2.0.13",
"@openfort/openfort-js": "0.7.7",
"@openfort/openfort-js": "0.7.9",
"@openfort/openfort-node": "^0.6.47",
"@radix-ui/react-toast": "^1.1.2",
"@rainbow-me/rainbowkit": "^2.1.1",
Expand Down
1 change: 1 addition & 0 deletions examples/apps/auth-sample/public/walletconnect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion examples/apps/auth-sample/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const variantStyles = {
filled: 'rounded-md bg-zinc-900 py-1 px-3 text-white hover:bg-zinc-700',
outline:
'rounded-md py-1 px-3 text-zinc-700 ring-1 ring-inset ring-zinc-900/10 hover:bg-zinc-900/2.5 hover:text-zinc-900',
text: 'text-orange-600 hover:text-zinc-900',
text: 'text-blue-600 hover:text-zinc-900',
};

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function AuthLayout({
children: React.ReactNode;
}) {
return (
<main className="flex min-h-full overflow-hidden pt-16 sm:py-28">
<main className="flex min-h-full overflow-hidden pt-8 sm:py-12">
<div className="mx-auto flex w-full max-w-2xl flex-col px-4 sm:px-6">
<div className="flex pl-4 md:mb-4 md:pl-8">
<Link href="/" aria-label="Home">
Expand Down
4 changes: 3 additions & 1 deletion examples/apps/auth-sample/src/components/Logout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react';
import {useOpenfort} from '../hooks/useOpenfort';
import {useRouter} from 'next/router';

const LogoutButton: React.FC = () => {
const {logout} = useOpenfort();

const router = useRouter();
const handleLogout = async () => {
try {
await logout();
router.push('/login');
} catch (error) {
console.error('Logout failed:', error);
alert('Logout failed. Please try again.');
Expand Down
46 changes: 33 additions & 13 deletions examples/apps/auth-sample/src/components/NFT/MintNFTButton.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
import React, {useState} from 'react';
import React, {useCallback, useState} from 'react';
import {useOpenfort} from '../../hooks/useOpenfort';
import {EmbeddedState} from '@openfort/openfort-js';
import Loading from '../Loading';
import openfort from '../../utils/openfortConfig';

const MintNFTButton: React.FC<{
handleSetMessage: (message: string) => void;
}> = ({handleSetMessage}) => {
const {mintNFT, state} = useOpenfort();
const {state} = useOpenfort();
const [loading, setLoading] = useState(false);

const mintNFT = useCallback(async (): Promise<string | null> => {
const collectResponse = await fetch(`/api/protected-collect`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${openfort.getAccessToken()}`,
},
});

if (!collectResponse.ok) {
alert('Failed to mint NFT status: ' + collectResponse.status);
return null;
}
const collectResponseJSON = await collectResponse.json();

if (collectResponseJSON.data?.nextAction) {
const response = await openfort.sendSignatureTransactionIntentRequest(
collectResponseJSON.data.id,
collectResponseJSON.data.nextAction.payload.userOperationHash
);
return response?.response?.transactionHash ?? null;
} else {
return collectResponseJSON.response?.transactionHash;
}
}, []);

const handleMintNFT = async () => {
try {
setLoading(true);
const transactionHash = await mintNFT();
setLoading(false);
if (!transactionHash) {
throw new Error('Failed to mint NFT');
}
setLoading(true);
const transactionHash = await mintNFT();
setLoading(false);
if (transactionHash) {
handleSetMessage(`https://www.oklink.com/amoy/tx/${transactionHash}`);
} catch (err) {
// Handle errors from minting process
console.error('Failed to mint NFT:', err);
alert('Failed to mint NFT. Please try again.');
}
};

Expand Down
51 changes: 51 additions & 0 deletions examples/apps/auth-sample/src/components/OAuth/LinkOAuthButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, {useMemo, useState} from 'react';
import {useOpenfort} from '../../hooks/useOpenfort';
import {AuthPlayerResponse, OAuthProvider} from '@openfort/openfort-js';
import Loading from '../Loading';
import openfort from '../../utils/openfortConfig';
import {getURL} from '../../utils/getUrl';

const LinkOAuthButton: React.FC<{
provider: OAuthProvider;
user: AuthPlayerResponse | null;
}> = ({provider, user}) => {
const {state} = useOpenfort();
const [loading, setLoading] = useState(false);
const handleLinkOAuth = async () => {
try {
setLoading(true);
const accessToken = openfort.getAccessToken() as string;
const {url} = await openfort.initLinkOAuth({
authToken: accessToken,
provider: provider,
options: {
redirectTo: getURL() + '/login',
},
});
setLoading(false);
window.location.href = url;
} catch (err) {
console.error('Failed to sign message:', err);
alert('Failed to sign message. Please try again.');
}
};

const isLinked = useMemo(() => {
if (!user) return false;
return user.linkedAccounts.some((account) => account.provider === provider);
}, [user]);

return (
<div>
<button
onClick={handleLinkOAuth}
disabled={isLinked}
className={`mt-2 w-44 px-4 py-2 bg-black text-white font-semibold rounded-lg shadow-md hover:bg-gray-800 disabled:bg-gray-400 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50`}
>
{loading ? <Loading /> : `${isLinked ? 'Linked' : 'Link'} ${provider}`}
</button>
</div>
);
};

export default LinkOAuthButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React, {useCallback, useState} from 'react';
import {useOpenfort} from '../../hooks/useOpenfort';
import {EmbeddedState} from '@openfort/openfort-js';
import Loading from '../Loading';
import openfort from '../../utils/openfortConfig';
import {ethers} from 'ethers';
import MintNFTSessionButton from './MintNFTButtoSession';

const sessionMethods = [
{id: '1hour', title: '1 Hour'},
{id: '1day', title: '1 Day'},
{id: '1month', title: '1 Month'},
];

const CreateSessionButton: React.FC<{
handleSetMessage: (message: string) => void;
}> = ({handleSetMessage}) => {
const {state, signMessage} = useOpenfort();
const [loading, setLoading] = useState(false);
const [sessionKey, setSessionKey] = useState<string | null>(null);

const createSession = useCallback(async (): Promise<{
address: string;
privateKey: string;
} | null> => {
const sessionKey = ethers.Wallet.createRandom();
const sessionResponse = await fetch(`/api/protected-create-session`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${openfort.getAccessToken()}`,
},
body: JSON.stringify({
sessionDuration: document.querySelector(
'input[name="session-method"]:checked'
)?.id,
sessionAddress: sessionKey.address,
}),
});

if (!sessionResponse.ok) {
alert('Failed to create session: ' + sessionResponse.status);
return null;
}
const sessionResponseJSON = await sessionResponse.json();

if (sessionResponseJSON.data?.nextAction) {
const signature = await signMessage(
sessionResponseJSON.data?.nextAction.payload.userOperationHash,
{
hashMessage: true,
arrayifyMessage: true,
}
);
if (signature?.error) {
throw new Error(`Failed to sign message. ${signature?.error}`);
}
const response = await openfort.sendRegisterSessionRequest(
sessionResponseJSON.data.id,
signature.data as string
);
if (!response?.isActive) {
throw new Error('Session key registration failed');
}
setSessionKey(sessionKey.privateKey);
return {address: sessionKey.address, privateKey: sessionKey.privateKey};
} else {
return null;
}
}, []);

const handleCreateSession = async () => {
setLoading(true);
const session = await createSession();
setLoading(false);
if (session) {
handleSetMessage(
`Session key registered successfully:\n Address: ${session.address}\n Private Key: ${session.privateKey}`
);
}
};

return (
<div>
<div>
<fieldset>
<legend className="font-medium leading-6 text-black">
Session duration
</legend>
<p className="mt-1 text-sm leading-6 text-gray-600">
How long should the session last?
</p>
<div className="mt-3 space-y-1">
{sessionMethods.map((sessionMethod) => (
<div key={sessionMethod.id} className="flex items-center">
<input
id={sessionMethod.id}
name="session-method"
type="radio"
defaultChecked={sessionMethod.id === '1day'}
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-600"
/>
<label
htmlFor={sessionMethod.id}
className="ml-3 block text-sm font-medium leading-6 text-gray-900"
>
{sessionMethod.title}
</label>
</div>
))}
</div>
</fieldset>
<button
onClick={handleCreateSession}
disabled={state !== EmbeddedState.READY}
className={`mt-4 w-44 px-4 py-2 bg-black text-white font-semibold rounded-lg shadow-md hover:bg-gray-800 disabled:bg-gray-400 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50`}
>
{loading ? <Loading /> : 'Create session'}
</button>
</div>
<MintNFTSessionButton
handleSetMessage={handleSetMessage}
sessionKey={sessionKey}
/>
</div>
);
};

export default CreateSessionButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, {useCallback, useState} from 'react';
import Loading from '../Loading';
import openfort from '../../utils/openfortConfig';
import {ethers} from 'ethers';
import {arrayify} from 'ethers/lib/utils';

const MintNFTSessionButton: React.FC<{
handleSetMessage: (message: string) => void;
sessionKey: string | null;
}> = ({handleSetMessage, sessionKey}) => {
const [loading, setLoading] = useState(false);

const mintNFT = useCallback(async (): Promise<string | null> => {
if (!sessionKey) {
return null;
}
const collectResponse = await fetch(`/api/protected-collect`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${openfort.getAccessToken()}`,
},
});

if (!collectResponse.ok) {
alert('Failed to mint NFT status: ' + collectResponse.status);
return null;
}
const collectResponseJSON = await collectResponse.json();

if (collectResponseJSON.data?.nextAction) {
const message = arrayify(
collectResponseJSON.data.nextAction.payload.userOperationHash
);
const sessionSigner = new ethers.Wallet(sessionKey);
const signature = await sessionSigner?.signMessage(message);
if (!signature) {
throw new Error('Failed to sign message with session key');
}

const response = await openfort.sendSignatureTransactionIntentRequest(
collectResponseJSON.data.id,
null,
signature
);
return response?.response?.transactionHash ?? null;
} else {
return collectResponseJSON.response?.transactionHash;
}
}, [sessionKey]);

const handleMintNFT = async () => {
setLoading(true);
const transactionHash = await mintNFT();
setLoading(false);
if (transactionHash) {
handleSetMessage(`https://www.oklink.com/amoy/tx/${transactionHash}`);
}
};

return (
<div>
<button
onClick={handleMintNFT}
disabled={!sessionKey}
className={`mt-4 w-32 px-4 py-2 bg-black text-white font-semibold rounded-lg shadow-md hover:bg-gray-800 disabled:bg-gray-400 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50`}
>
{loading ? <Loading /> : 'Mint NFT'}
</button>
{!sessionKey && (
<p className="text-red-400 text-xs mt-2">
Create a session before minting an NFT signed with a session key.
</p>
)}
</div>
);
};

export default MintNFTSessionButton;
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const SignMessageButton: React.FC<{
}
handleSetMessage(signature.data!);
} catch (err) {
// Handle errors from minting process
console.error('Failed to sign message:', err);
alert('Failed to sign message. Please try again.');
}
Expand Down
Loading

0 comments on commit 1f07375

Please sign in to comment.