177 lines
5.6 KiB
Vue
177 lines
5.6 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
useTokenClient,
|
|
type TokenClientSuccessResponse,
|
|
type TokenClientErrorResponse
|
|
} from "vue3-google-signin";
|
|
|
|
const authStore = useAuthStore();
|
|
const listStore = useListStore();
|
|
const crypto = useCryptoStore()
|
|
|
|
/**
|
|
* Logique Google Drive (appDataFolder)
|
|
*/
|
|
const handleDriveKey = async (accessToken: string) => {
|
|
const fileName = 'list_master_key';
|
|
const baseUrl = 'https://www.googleapis.com/drive/v3/files';
|
|
const authHeader = { Authorization: `Bearer ${accessToken}` };
|
|
|
|
try {
|
|
const searchParams = new URLSearchParams({
|
|
q: `name = '${fileName}'`,
|
|
spaces: 'appDataFolder',
|
|
fields: 'files(id, name)'
|
|
});
|
|
|
|
const searchRes = await $fetch<any>(`${baseUrl}?${searchParams}`, { headers: authHeader });
|
|
|
|
if (searchRes.files && searchRes.files.length > 0) {
|
|
const fileId = searchRes.files[0].id;
|
|
|
|
// 1. Récupérer le contenu en tant que Blob ou ArrayBuffer pour préserver les bytes
|
|
const blob = await $fetch<Blob>(`${baseUrl}/${fileId}?alt=media`, {
|
|
headers: authHeader,
|
|
responseType: 'blob'
|
|
});
|
|
|
|
// Convertir le Blob en Uint8Array
|
|
const arrayBuffer = await blob.arrayBuffer();
|
|
const keyUint8 = new Uint8Array(arrayBuffer);
|
|
|
|
listStore.setMasterKey(keyUint8);
|
|
console.log("Clé binaire récupérée du Drive : " + keyUint8);
|
|
} else {
|
|
// 2. Création avec le type Uint8Array
|
|
const newKey = crypto.generateMasterKey();
|
|
|
|
const metadata = {
|
|
name: fileName,
|
|
parents: ['appDataFolder']
|
|
};
|
|
|
|
const formData = new FormData();
|
|
// On spécifie explicitement 'application/octet-stream' pour la clé binaire
|
|
formData.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
|
|
formData.append('file', new Blob([newKey as any], { type: 'application/octet-stream' }));
|
|
|
|
await $fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {
|
|
method: 'POST',
|
|
headers: authHeader,
|
|
body: formData
|
|
});
|
|
|
|
listStore.setMasterKey(newKey);
|
|
console.log("Nouvelle clé binaire générée et stockée : " + newKey);
|
|
}
|
|
} catch (err) {
|
|
console.error("Erreur Google Drive:", err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Succès de l'authentification Google
|
|
*/
|
|
const handleSuccess = async (response: TokenClientSuccessResponse) => {
|
|
const accessToken = response.access_token;
|
|
console.log(response.access_token)
|
|
|
|
try {
|
|
// // A. Vérification côté WordPress (Login)
|
|
// // Note : On envoie l'accessToken ou on utilise l'ID Token si configuré.
|
|
// // Si ton API WP attendait un 'code', il faudra l'adapter pour vérifier l'access_token ou l'email.
|
|
const data = await $fetch<any>('/api-fastify/auth/google', {
|
|
method: 'POST',
|
|
body: { access_token: accessToken }
|
|
});
|
|
|
|
// Stockage des infos WP
|
|
authStore.setTokenCookie(data.token);
|
|
authStore.setUserCookie(data.user);
|
|
|
|
// B. Gestion de la clé sur Google Drive (Entièrement géré par le Front)
|
|
await handleDriveKey(accessToken);
|
|
listStore.processRawData(data.lists);
|
|
|
|
} catch (error) {
|
|
console.error("Erreur login WordPress:", error);
|
|
}
|
|
};
|
|
|
|
const handleError = (error: TokenClientErrorResponse) => {
|
|
console.error("Erreur Google:", error);
|
|
};
|
|
|
|
// Initialisation du Token Client (Implicit Flow - Pas de secret nécessaire)
|
|
const { login } = useTokenClient({
|
|
scope: 'openid email profile https://www.googleapis.com/auth/drive.appdata',
|
|
onSuccess: handleSuccess,
|
|
onError: handleError,
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<button @click="() => login()" class="g-signin-button">
|
|
<div class="g-logo-wrapper">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" class="g-logo">
|
|
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/>
|
|
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/>
|
|
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/>
|
|
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/>
|
|
<path fill="none" d="M0 0h48v48H0z"/>
|
|
</svg>
|
|
</div>
|
|
<span class="g-button-text">{{ $t('googleBtnTxt') }}</span>
|
|
</button>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.g-signin-button {
|
|
margin:auto;
|
|
margin-top:1em;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
background-color: #ffffff;
|
|
color: #757575;
|
|
height: 40px;
|
|
width: auto;
|
|
border: 1px solid #dadce0;
|
|
border-radius: 4px;
|
|
padding: 0em;
|
|
font-family: 'Roboto', arial, sans-serif;
|
|
font-weight: 500;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
box-shadow: 0 1px 2px 0 rgba(60,64,67,0.302), 0 1px 3px 1px rgba(60,64,67,0.149);
|
|
transition: background-color .218s, border-color .218s, box-shadow .218s;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.g-signin-button:hover {
|
|
background-color: hsl(210, 17%, 90%);
|
|
border-color: #d2d2d2;
|
|
box-shadow: 0 1px 2px 0 rgba(60,64,67,0.302), 0 1px 3px 1px rgba(60,64,67,0.149);
|
|
}
|
|
|
|
.g-signin-button:active {
|
|
background-color: #eeeeee;
|
|
}
|
|
|
|
.g-logo-wrapper {
|
|
padding: 11px;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.g-logo {
|
|
width: 18px;
|
|
height: 18px;
|
|
}
|
|
|
|
.g-button-text {
|
|
padding: 0 12px 0 10px;
|
|
white-space: nowrap;
|
|
}
|
|
</style> |