192 lines
6.2 KiB
TypeScript
192 lines
6.2 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import type { List, WPListEncrypted } from '~/types/lists'
|
|
import {useCryptoStore} from '~/composables/crypto'
|
|
import sodium from "libsodium-wrappers"
|
|
|
|
|
|
const crypto = useCryptoStore()
|
|
|
|
export const useListStore = defineStore('lists', {
|
|
state: () => ({
|
|
lists: [] as List[],
|
|
loading: false as boolean,
|
|
masterKey: null as Uint8Array | null,
|
|
publicKey: new Uint8Array() as Uint8Array,
|
|
privateKey: new Uint8Array() as Uint8Array,
|
|
}),
|
|
|
|
actions: {
|
|
saveLists(lists:Array<List>){
|
|
this.lists = lists
|
|
},
|
|
resetLists(){
|
|
this.lists = []
|
|
},
|
|
setMasterKey(key: Uint8Array){
|
|
this.masterKey = key
|
|
},
|
|
|
|
async fetchLists() {
|
|
// On récupère notre plugin API injecté
|
|
const { $api } = useNuxtApp();
|
|
this.loading = true;
|
|
|
|
try {
|
|
// L'appel est maintenant ultra simple et typé
|
|
const data = await $api.lists.getAll();
|
|
this.lists = data;
|
|
} catch (error) {
|
|
// La gestion d'erreur est centralisée,
|
|
// mais tu peux ajouter une logique spécifique ici (ex: notification)
|
|
console.error("Erreur lors du chargement des listes:", error);
|
|
throw error;
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
async processRawData(rawData: [WPListEncrypted]){
|
|
const { $api } = useNuxtApp();
|
|
await crypto.init()
|
|
|
|
if (rawData && rawData.length > 0) {
|
|
const item = rawData[0];
|
|
if (item && this.masterKey){
|
|
if (this.isWPListEncrypted(item)) {
|
|
if (item.content_cipher === "initialize-me"){
|
|
/* 1- Création de la paire de clés (TODO : à déporter ailleurs (Key Store ?)) */
|
|
const { publicKey, privateKey } = crypto.generateUserKeyPair()
|
|
this.publicKey = publicKey;
|
|
this.privateKey = privateKey;
|
|
|
|
// On les envoie au BO //
|
|
/* Chiffrage de la private avec la master : */
|
|
const privKeyCipher = crypto.encryptPrivateKey(this.privateKey, this.masterKey)
|
|
|
|
/* empaquetage */
|
|
const payload = {
|
|
'user_id': item.user_id, // pour vérification au BO
|
|
'private_key_cipher': privKeyCipher,
|
|
'public_key': publicKey,
|
|
}
|
|
|
|
/* Et on envoie ! */
|
|
await $api.lists.uploadKeys(JSON.stringify(payload))
|
|
|
|
// On crée la liste //
|
|
/* D'abord la clé AES de la liste */
|
|
const key = crypto.generateListKey();
|
|
|
|
/* Puis la liste */
|
|
const user_id = Number(item.user_id)
|
|
|
|
const data: List = {
|
|
id: Number(item.id),
|
|
user_id: user_id,
|
|
aesKey: key,
|
|
list_title: 'THE VERY première liste',
|
|
list_type: 'basic',
|
|
content: '{[\'vide\']}',
|
|
is_open: true,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
}
|
|
this.lists[0] = data
|
|
|
|
/* Et on envoie au BO */
|
|
this.syncData(data, this.publicKey, this.privateKey)
|
|
}
|
|
else{
|
|
console.log('coucou : ' + rawData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
async syncData(decryptedData: List, userPublicKey: Uint8Array, userPrivateKey: Uint8Array) {
|
|
const { $api } = useNuxtApp();
|
|
|
|
const aesKey = decryptedData.aesKey;
|
|
await crypto.init();
|
|
|
|
// 1. On prépare les données (en excluant la clé elle-même du contenu)
|
|
const { aesKey: _, ...pureData } = decryptedData;
|
|
const stringData = JSON.stringify(pureData);
|
|
|
|
// 2. Chiffrement du contenu par la clé AES (XChaCha20)
|
|
const encryptedContent = crypto.encryptList(stringData, aesKey);
|
|
|
|
// 3. Chiffrement de la clé AES par la clé Publique (Asymétrique)
|
|
// On utilise ici ta fonction de l'étape 11
|
|
const encryptedKeyPayload = crypto.encryptListKeyForUser(
|
|
aesKey,
|
|
userPublicKey,
|
|
userPrivateKey
|
|
);
|
|
|
|
// 4. On empaquette le tout pour le Back-Office
|
|
const dataToBO: WPListEncrypted = {
|
|
id: decryptedData.id.toString(),
|
|
user_id: decryptedData.user_id.toString(),
|
|
|
|
// La clé AES verrouillée pour l'utilisateur
|
|
key_cipher: sodium.to_base64(encryptedKeyPayload.cipher),
|
|
key_nonce: sodium.to_base64(encryptedKeyPayload.nonce),
|
|
|
|
// Le contenu de la liste
|
|
content_cipher: sodium.to_base64(encryptedContent.cipher),
|
|
content_nonce: sodium.to_base64(encryptedContent.nonce),
|
|
created_at: null,
|
|
updated_at: null,
|
|
};
|
|
|
|
await $api.lists.update(dataToBO)
|
|
},
|
|
|
|
// async updateList(id, title, content) {
|
|
// const config = useRuntimeConfig();
|
|
|
|
// try {
|
|
// const data = await $fetch<[]|null>(`${config.public.apiBase}/lists`, {
|
|
// method: 'GET',
|
|
// headers: {
|
|
// // On injecte le token ici
|
|
// 'Authorization': `Bearer ${this.token}`
|
|
// },
|
|
// // Si tu as besoin d'envoyer un corps de message vide ou spécifique
|
|
// // body: {}
|
|
// });
|
|
|
|
// this.lists = data;
|
|
// console.log(data);
|
|
// console.log(this.token);
|
|
// return data;
|
|
// } catch (error) {
|
|
// console.error("Erreur lors de la récupération des listes:", error);
|
|
// }
|
|
// }
|
|
|
|
isWPListEncrypted(obj: any): obj is WPListEncrypted {
|
|
console.log(obj !== null)
|
|
console.log(typeof obj)
|
|
console.log(typeof obj.id)
|
|
console.log(typeof obj.key_cipher )
|
|
console.log(typeof obj.key_nonce )
|
|
console.log(typeof obj.content_cipher)
|
|
console.log(typeof obj.content_nonce)
|
|
|
|
return (
|
|
obj !== null &&
|
|
typeof obj === 'object' &&
|
|
typeof obj.id === 'string' &&
|
|
typeof obj.key_cipher === 'string' &&
|
|
typeof obj.key_nonce === 'string' &&
|
|
typeof obj.content_cipher === 'string' &&
|
|
typeof obj.content_nonce === 'string'
|
|
);
|
|
}
|
|
}
|
|
|
|
}) |