Création d'un composable pour la gestion de la crypto, mise en place de l'initialisation de la première liste et sauvegarde de celle-ci. TODO NEXT : Récupération de la liste en la déchiffrant, mise en place d'une masterKey dérivée du mot de passe pour les utilisateurs non google, basculement vers la page des listes après connexion google etc.
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { List } from '~/types/lists'
|
||||
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: {
|
||||
@@ -15,8 +22,11 @@ export const useListStore = defineStore('lists', {
|
||||
resetLists(){
|
||||
this.lists = []
|
||||
},
|
||||
setMasterKey(key: Uint8Array){
|
||||
this.masterKey = key
|
||||
},
|
||||
|
||||
async fetchLists() {
|
||||
async fetchLists() {
|
||||
// On récupère notre plugin API injecté
|
||||
const { $api } = useNuxtApp();
|
||||
this.loading = true;
|
||||
@@ -33,7 +43,107 @@ export const useListStore = defineStore('lists', {
|
||||
} 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();
|
||||
@@ -57,6 +167,26 @@ export const useListStore = defineStore('lists', {
|
||||
// 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'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
Reference in New Issue
Block a user