Skip to content

Commit

Permalink
implement native auth
Browse files Browse the repository at this point in the history
  • Loading branch information
juliancwirko committed May 28, 2023
1 parent 17bfdae commit d7bddd8
Show file tree
Hide file tree
Showing 14 changed files with 529 additions and 334 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### [0.5.0](https://github.com/useElven/core/releases/tag/v0.5.0) (2023-05-28)
- Breaking: switch to using sdk-native-auth-client instead passing string-based login tokens. There is no fallback or other option, so it is a breaking change. Native Auth is recommended. The old way of doing that will be deprecated. Please freeze the previous version if you are not ready to switch yet
- update dependencies

### [0.4.0](https://github.com/useElven/core/releases/tag/v0.4.0) (2023-05-14)
- update HW and Web Wallet providers, adjust the code
- fix HW initialization when other provider was used before
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ import { useLogin } from '@useelven/core';

(...)

const { login, isLoggedIn, error } = useLogin({
token: 'some_hash_here',
});
const { login, isLoggedIn, error } = useLogin();
```

Sign and send transaction:
Expand Down
647 changes: 377 additions & 270 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@useelven/core",
"version": "0.4.0",
"version": "0.5.0",
"description": "Core hooks for MultiversX React DApps",
"license": "MIT",
"author": "Julian Ćwirko <julian.io>",
Expand Down Expand Up @@ -48,6 +48,7 @@
"@multiversx/sdk-core": "12.2.1",
"@multiversx/sdk-extension-provider": "2.0.7",
"@multiversx/sdk-hw-provider": "6.0.0",
"@multiversx/sdk-native-auth-client": "^1.0.2",
"@multiversx/sdk-network-providers": "1.4.0",
"@multiversx/sdk-wallet-connect-provider": "3.2.1",
"@multiversx/sdk-web-wallet-provider": "3.0.0",
Expand All @@ -57,18 +58,18 @@
},
"devDependencies": {
"@types/lodash.clonedeep": "4.5.7",
"@types/node": "20.1.4",
"@types/react": "18.2.6",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"@types/node": "20.2.5",
"@types/react": "18.2.7",
"@typescript-eslint/eslint-plugin": "5.59.7",
"@typescript-eslint/parser": "5.59.7",
"esbuild": "0.17.19",
"eslint": "8.40.0",
"eslint": "8.41.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"prettier": "2.8.8",
"rimraf": "5.0.0",
"rimraf": "5.0.1",
"typescript": "5.0.4"
},
"peerDependencies": {
Expand Down
17 changes: 16 additions & 1 deletion src/hooks/common-helpers/useDappProvidersSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useLogout } from '../useLogout';
import { useConfig } from '../useConfig';
import { useAccount } from '../useAccount';
import { useLoginInfo } from '../useLoginInfo';
import { NativeAuthClient } from '@multiversx/sdk-native-auth-client';

export const useDappProvidersSync = (
accountDone: boolean,
Expand All @@ -43,6 +44,7 @@ export const useDappProvidersSync = (
useEffectOnlyOnUpdate(() => {
const askForDappProvider = async () => {
const loginMethod = loginInfoSnap.loginMethod;
const loginToken = loginInfoSnap.loginToken;
const loginExpires = loginInfoSnap.expires;
let dappProvider = dappProviderRef?.current;

Expand Down Expand Up @@ -144,16 +146,29 @@ export const useDappProvidersSync = (
if (signature) {
setLoginInfoState('signature', signature);
}

if (address) {
dappProvider = new WalletProvider(
`${configStateSnap.walletAddress}${DAPP_INIT_ROUTE}`
);
dappProviderRef.current = dappProvider;
network.setNetworkState('dappProvider', dappProvider);
const userAddressInstance = new Address(address);
const userAccountInstance = new Account(userAddressInstance);
setAccountState('address', userAccountInstance.address.bech32());
}

if (signature && address && loginToken) {
const nativeAuthClient = new NativeAuthClient({
apiUrl: configStateSnap.apiAddress,
});
const accessToken = nativeAuthClient.getToken(
address,
loginToken,
signature
);
setLoginInfoState('accessToken', accessToken);
dappProviderRef.current = dappProvider;
}
break;
}
case LoginMethodsEnum.ledger: {
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/common-helpers/useLocalStorageSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const useLocalStorageSync = (
setLoginInfoState('expires', parsedStorage.expires);
setLoginInfoState('loginToken', parsedStorage.loginToken);
setLoginInfoState('signature', parsedStorage.signature);
setLoginInfoState('accessToken', parsedStorage.accessToken);
setLoginInfoDone(true);
}
}, []);
Expand All @@ -64,5 +65,6 @@ export const useLocalStorageSync = (
loginInfoSnap.expires,
loginInfoSnap.loginToken,
loginInfoSnap.signature,
loginInfoSnap.accessToken,
]);
};
32 changes: 23 additions & 9 deletions src/hooks/useExtensionLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,24 @@ import { Login } from '../types/account';
import { useLoggingIn } from './useLoggingIn';
import { errorParse } from '../utils/errorParse';
import { useNetwork } from './useNetwork';
import { useNativeAuthLoginToken } from './useNativeAuthLoginToken';

export const useExtensionLogin = (params?: Login) => {
const { logout } = useLogout();
const { loggedIn, pending, error } = useLoggingIn();
const networkStateSnap = useNetwork();
const { loginToken, nativeAuthClient } = useNativeAuthLoginToken();

const login = async () => {
if (!loginToken) {
setLoggingInState(
'error',
'Login token is not present. Please try again.'
);
setLoggingInState('pending', false);
return;
}

const providerInstance = ExtensionProvider.getInstance();

try {
Expand All @@ -47,7 +58,7 @@ export const useExtensionLogin = (params?: Login) => {
: '/';
const providerLoginData = {
callbackUrl,
...(params?.token && { token: params?.token }),
token: loginToken,
};

try {
Expand Down Expand Up @@ -87,17 +98,20 @@ export const useExtensionLogin = (params?: Login) => {
}
}

if (signature) {
setLoginInfoState('signature', signature);
}
if (params?.token) {
setLoginInfoState('loginToken', String(params.token));
}

setLoginInfoState('loginToken', loginToken);
setLoginInfoState('expires', getNewLoginExpiresTimestamp());

setLoggingInState('loggedIn', Boolean(address));

if (signature && nativeAuthClient) {
setLoginInfoState('signature', signature);
const accessToken = nativeAuthClient.getToken(
address,
loginToken,
signature
);
setLoginInfoState('accessToken', accessToken);
}

optionalRedirect(params?.callbackRoute);
} catch (e) {
const err = errorParse(e);
Expand Down
55 changes: 30 additions & 25 deletions src/hooks/useLedgerLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,24 @@ import { Login } from '../types/account';
import { useLoggingIn } from './useLoggingIn';
import { errorParse } from '../utils/errorParse';
import { useNetwork } from './useNetwork';
import { useNativeAuthLoginToken } from './useNativeAuthLoginToken';

export const useLedgerLogin = (params?: Login) => {
const { logout } = useLogout();
const { loggedIn, pending, error } = useLoggingIn();
const networkStateSnap = useNetwork();
const { loginToken, nativeAuthClient } = useNativeAuthLoginToken();

const login = async (addressIndex = 0) => {
if (!loginToken) {
setLoggingInState(
'error',
'Login token is not present. Please try again.'
);
setLoggingInState('pending', false);
return;
}

const apiNetworkProvider = networkStateSnap.apiNetworkProvider;
const dappProvider = networkStateSnap.dappProvider;

Expand All @@ -38,37 +49,31 @@ export const useLedgerLogin = (params?: Login) => {
}

setLoginInfoState('loginMethod', LoginMethodsEnum.ledger);

if (params?.token) {
setLoginInfoState('loginToken', String(params.token));
}

setLoginInfoState('loginToken', loginToken);
setAccountState('addressIndex', addressIndex);

let userAddress;

try {
if (params?.token) {
if (dappProvider instanceof HWProvider) {
const loginInfo = await dappProvider.tokenLogin({
token: Buffer.from(`${params?.token}{}`),
addressIndex,
});

if (loginInfo.address) {
userAddress = loginInfo.address;
}

if (loginInfo.signature) {
setLoginInfoState('signature', loginInfo.signature.toString('hex'));
}
if (dappProvider instanceof HWProvider) {
const loginInfo = await dappProvider.tokenLogin({
token: Buffer.from(`${loginToken}{}`),
addressIndex,
});

if (loginInfo.address) {
userAddress = loginInfo.address;
}
} else {
if (dappProvider instanceof HWProvider) {
const address = await dappProvider.login({ addressIndex });
if (address) {
userAddress = address;
}

if (loginInfo.signature && nativeAuthClient) {
const sigString = loginInfo.signature.toString('hex');
setLoginInfoState('signature', sigString);
const accessToken = nativeAuthClient.getToken(
loginInfo.address,
loginToken,
sigString
);
setLoginInfoState('accessToken', accessToken);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useLoginInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useProxy } from './useProxy';
import { loginInfoState } from '../store/auth';

export const useLoginInfo = () => {
const { loginMethod, expires, loginToken, signature } =
const { loginMethod, expires, loginToken, signature, accessToken } =
useProxy(loginInfoState);

return { loginMethod, expires, loginToken, signature };
return { loginMethod, expires, loginToken, signature, accessToken };
};
35 changes: 23 additions & 12 deletions src/hooks/useMobileAppLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { DappProvider } from '../types/network';
import { ApiNetworkProvider } from '@multiversx/sdk-network-providers/out';
import { useConfig } from './useConfig';
import { useNetwork } from './useNetwork';
import { useNativeAuthLoginToken } from './useNativeAuthLoginToken';

export const useMobileAppLogin = (params?: Login) => {
const { logout } = useLogout();
Expand All @@ -34,6 +35,7 @@ export const useMobileAppLogin = (params?: Login) => {
>();
const networkStateSnap = useNetwork();
const configStateSnap = useConfig();
const { loginToken, nativeAuthClient } = useNativeAuthLoginToken();

const dappProviderRef = useRef<DappProvider>(
networkStateSnap.dappProvider as DappProvider
Expand All @@ -47,6 +49,15 @@ export const useMobileAppLogin = (params?: Login) => {
};

const login = async () => {
if (!loginToken) {
setLoggingInState(
'error',
'Login token is not present. Please try again.'
);
setLoggingInState('pending', false);
return;
}

const relayAddress = getRelayAddressFromNetwork(
configStateSnap.walletConnectV2RelayAddresses as string[]
);
Expand Down Expand Up @@ -86,12 +97,16 @@ export const useMobileAppLogin = (params?: Login) => {
setAccountState('nonce', account.nonce.valueOf());

setLoggingInState('loggedIn', Boolean(address));
if (signature) {
if (signature && nativeAuthClient) {
setLoginInfoState('signature', signature);
const accessToken = nativeAuthClient.getToken(
address,
loginToken,
signature
);
setLoginInfoState('accessToken', accessToken);
}
if (params?.token) {
setLoginInfoState('loginToken', params?.token);
}
setLoginInfoState('loginToken', loginToken);

setNetworkState('dappProvider', dappProviderRef.current);

Expand All @@ -115,12 +130,8 @@ export const useMobileAppLogin = (params?: Login) => {

if (!hasUri) return;

if (!params?.token) {
setWalletConnectUri(walletConnectUri);
} else {
const wcUriWithToken = `${walletConnectUri}&token=${params.token}`;
setWalletConnectUri(wcUriWithToken);
}
const wcUriWithToken = `${walletConnectUri}&token=${loginToken}`;
setWalletConnectUri(wcUriWithToken);
};

const providerInstance = new WalletConnectV2Provider(
Expand All @@ -146,7 +157,7 @@ export const useMobileAppLogin = (params?: Login) => {
setWalletConnectPairings(providerInstance.pairings);

await providerInstance.login({
token: params?.token,
token: loginToken,
approval,
});

Expand Down Expand Up @@ -174,7 +185,7 @@ export const useMobileAppLogin = (params?: Login) => {
setLoginInfoState('loginMethod', LoginMethodsEnum.walletconnect);

await dappProvider.login({
token: params?.token,
token: loginToken,
approval,
});

Expand Down
28 changes: 28 additions & 0 deletions src/hooks/useNativeAuthLoginToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NativeAuthClient } from '@multiversx/sdk-native-auth-client';
import { useConfig } from './useConfig';
import { useEffect, useState } from 'react';

export const useNativeAuthLoginToken = () => {
const [loginToken, setLoginToken] = useState<string>();
const [nativeAuthClient, setNativeAuthClient] = useState<NativeAuthClient>();
const { apiAddress } = useConfig();

useEffect(() => {
const getToken = async () => {
const client = new NativeAuthClient({ apiUrl: apiAddress });
const loginToken = await client.initialize();

setLoginToken(loginToken);
setNativeAuthClient(client);
};

if (apiAddress) {
getToken();
}
}, [apiAddress]);

return {
loginToken,
nativeAuthClient,
};
};
Loading

0 comments on commit d7bddd8

Please sign in to comment.