Skip to content

Commit

Permalink
Merge pull request #10 from fiit-tp7-2023/#288-login
Browse files Browse the repository at this point in the history
#288 Login connect
  • Loading branch information
Kesuera authored Mar 25, 2024
2 parents 734ea81 + feb2536 commit 69a74ab
Show file tree
Hide file tree
Showing 15 changed files with 159 additions and 42 deletions.
1 change: 0 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"recommendations": [
"Vue.volar",
"Vue.vscode-typescript-vue-plugin",
"tal7aouy.icons",
"dbaeumer.vscode-eslint",
"rvest.vs-code-prettier-eslint",
Expand Down
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"*.css": "tailwindcss"
},
"cSpell.words": [
"composables",
"consola",
"dtos",
"FIIT",
"Josefin",
"Lato",
Expand All @@ -19,8 +22,7 @@
"sidebase",
"tailwindcss",
"vueuc",
"wght",
"dtos"
"wght"
],
"files.eol": "\n",
"[typescript]": {
Expand Down
6 changes: 5 additions & 1 deletion components/SignTest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import TextInput from './controls/TextInput.vue';
import ConfirmButton from './controls/ConfirmButton.vue';
import { useAccountStore } from '~/store';
const logger = useLogger('sign-test::');
const { $web3 } = useNuxtApp();
const accountStore = useAccountStore();
Expand All @@ -21,10 +23,12 @@ const signature = ref('');
const signMessage = async () => {
if (window.ethereum && account.value) {
try {
logger.info('Signing message');
const result = await $web3?.eth.personal.sign($web3.utils.utf8ToHex(message.value), account.value, '');
logger.info('Message signed');
signature.value = result?.toString() ?? '';
} catch (error) {
console.error(error);
logger.error(error);
}
}
};
Expand Down
59 changes: 53 additions & 6 deletions components/layout/NavigationComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,85 @@
</template>
<script lang="ts" setup>
import SearchBar from '../controls/SearchBar.vue';
import type { VerifyNonce } from '~/types/auth';
import { useAccountStore } from '~/store';
const { $web3 } = useNuxtApp();
const logger = useLogger('wallet::');
const accountStore = useAccountStore();
const account = computed(() => accountStore.account);
onMounted(async () => {
const accounts = await $web3?.eth.getAccounts();
accountStore.setAccount(accounts?.[0] ?? null);
if (account.value) {
logger.info('Account connected:', account);
}
logger.info('Refresh tokens');
const { accessToken, refreshToken } = await $fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ jwt: accountStore.accessToken, refreshToken: accountStore.refreshToken }),
});
accountStore.setToken(accessToken, refreshToken);
});
const signMessage = async (message: string): Promise<string> => {
if (!window.ethereum || !account.value) {
throw new Error('No account or web3 provider');
}
const result = await $web3?.eth.personal.sign($web3.utils.utf8ToHex(message), account.value, '');
if (!result) {
throw new Error('Could not sign message');
}
return result.toString();
};
const connectWallet = async () => {
if (window.ethereum) {
try {
logger.info('Requesting accounts');
await window.ethereum.request({ method: 'eth_requestAccounts' });
const accounts = await $web3?.eth.getAccounts();
accountStore.setAccount(accounts?.[0] ?? null);
const address = accounts?.[0];
if (!address) {
throw new Error('No account connected');
}
accountStore.setAccount(address);
logger.info('Account connected');
logger.info('Requesting nonce');
const query = new URLSearchParams({ address });
const nonce = await $fetch(`/api/auth/nonce?${query.toString()}`);
logger.info('Signing nonce');
const signature = await signMessage(nonce);
logger.info('Signed nonce:', signature);
logger.info('Requesting tokens');
const { accessToken, refreshToken } = await $fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ address, signature } as VerifyNonce),
});
logger.info('Saving tokens');
accountStore.setToken(accessToken, refreshToken);
} catch (error) {
console.error(error);
logger.error(error);
}
}
};
const disconnectWallet = async () => {
if (window.ethereum) {
try {
logger.info('Disconnecting account');
await window.ethereum.request({ method: 'eth_accounts' });
accountStore.setAccount(null);
accountStore.disconnect();
} catch (error) {
console.error(error);
logger.error(error);
}
}
};
Expand Down
3 changes: 1 addition & 2 deletions components/posts/NftPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="border-gray-300 border-2 p-4 height-300 m-4 flex justify-center items-center rounded">
<p>image here</p>
</div>
<div class="flex flex-row grid-colls-2 gap-3 mx-4 my-2">
<div class="flex flex-row grid-cols-2 gap-3 mx-4 my-2">
<div>
<p>pfp</p>
</div>
Expand All @@ -24,7 +24,6 @@
</template>

<script setup lang="ts">
import { defineProps } from 'vue';
import type { NFTPost } from '~/types/dtos';
defineProps<{
Expand Down
6 changes: 6 additions & 0 deletions composables/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createConsola } from 'consola';

export const useLogger = (namespace: string) => {
const consola = createConsola({ defaults: { tag: namespace } });
return consola;
};
1 change: 1 addition & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default defineNuxtConfig({
'@nuxt/image',
'@bg-dev/nuxt-naiveui',
'@pinia/nuxt',
'@pinia-plugin-persistedstate/nuxt',
],
googleFonts: {
families: {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@pinia/nuxt": "^0.5.1",
"add": "^2.0.6",
"consola": "^3.2.3",
"pinia": "^2.1.7",
"web3": "^4.5.0"
},
Expand All @@ -27,6 +28,7 @@
"@nuxtjs/eslint-module": "^4.1.0",
"@nuxtjs/google-fonts": "^3.1.3",
"@nuxtjs/tailwindcss": "^6.11.4",
"@pinia-plugin-persistedstate/nuxt": "^1.2.0",
"commitlint-config-gitmoji": "^2.3.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<script lang="ts" setup>
import NftPost from '~/components/posts/NftPost.vue';
import SignTest from '~/components/SignTest.vue';
import type { TokenPost } from '~/types';
import type { NFTPost as TokenPost } from '~/types/dtos';
const mockPosts: TokenPost[] = [
{
Expand Down
2 changes: 1 addition & 1 deletion plugins/web3.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Web3 } from 'web3';

export default defineNuxtPlugin(() => {
if (!process.client) return; // don't run on serverside
if (!process.client) return; // don't run on server side
return {
provide: {
web3: window.ethereum ? new Web3(window.ethereum) : null,
Expand Down
32 changes: 29 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useAuthService } from '~/server/services/auth.service';
import { GetNonceDTO } from '~/types/auth';

export default defineEventHandler(async (event) => {
const { address } = await readBody<GetNonceDTO>(event);
const { address } = getQuery<GetNonceDTO>(event);
const service = useAuthService();
return await service.getNonce(address);
});
61 changes: 38 additions & 23 deletions server/services/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,52 @@
import { useApi } from '../utils/api';
import { GetNonceDTO, RefreshTokenDTO, RefreshTokenRequestDTO, VerifyNonce } from '~/types/auth';
import { useLogger } from '~/composables/logger';
import { NonceMessageDTO, RefreshTokenDTO, RefreshTokenRequestDTO, VerifyNonce } from '~/types/auth';

export function useAuthService(token?: string) {
const getNonce = async (address: string): Promise<string> =>
await useApi<string, GetNonceDTO>('auth/nonce-message', undefined, {
method: 'POST',
body: {
address,
},
});
const logger = useLogger('auth_service::');
const getNonce = async (address: string): Promise<string> => {
const query = new URLSearchParams({ address });
try {
const { message } = await useApi<NonceMessageDTO>(`auth/nonce-message?${query.toString()}`);
return message;
} catch (e) {
logger.error(e);
throw e;
}
};

const verifyNonce = async (signature: string, address: string): Promise<RefreshTokenDTO> => {
const response = await useApi<RefreshTokenDTO, VerifyNonce>('auth/login', undefined, {
method: 'POST',
body: {
signature,
address,
},
});
return response;
try {
logger.info('Verifying nonce', { signature, address });
return await useApi<RefreshTokenDTO, VerifyNonce>('auth/login', undefined, {
method: 'POST',
body: {
signature,
address,
},
});
} catch (e) {
logger.error(e);
throw e;
}
};

const refreshToken = async (refreshToken: string): Promise<RefreshTokenDTO> => {
if (!token) {
logger.error('Missing user token');
throw new Error('Missing user token');
}
const response = await useApi<RefreshTokenDTO, RefreshTokenRequestDTO>('auth/refresh', token, {
method: 'POST',
body: {
refreshToken,
},
});
return response;
try {
return await useApi<RefreshTokenDTO, RefreshTokenRequestDTO>('auth/refresh', token, {
method: 'POST',
body: {
refreshToken,
},
});
} catch (e) {
logger.error(e);
throw e;
}
};

return {
Expand Down
Loading

0 comments on commit 69a74ab

Please sign in to comment.