Pārlūkot izejas kodu

Работа над ServerStorage

Book Pauk 6 gadi atpakaļ
vecāks
revīzija
cd5d3903fe

+ 62 - 35
client/components/Reader/ServerStorage/ServerStorage.vue

@@ -6,7 +6,6 @@
 //-----------------------------------------------------------------------------
 import Vue from 'vue';
 import Component from 'vue-class-component';
-import {Buffer} from 'safe-buffer';
 import _ from 'lodash';
 
 import bookManager from '../share/bookManager';
@@ -26,8 +25,11 @@ class ServerStorage extends Vue {
             //генерируем новый ключ
             this.generateNewServerStorageKey();
         }
-        //console.log(await this.storageSet({'id1': {rev: 1, data: {test: 123}}}));
-        //console.log(await this.storageGet({'id1': {rev: 1, data: {test: 123}}}));
+        this.hashedStorageKey = utils.toBase58(await cryptoUtils.sha256(this.serverStorageKey));
+        
+        //console.log(await this.storageSet({'id1': {rev: 3, data: {test: 123}}}));
+        //console.log(await this.storageGet({'id1': {}}));
+        //console.log(await this.storageCheck({'id1': {rev: 1, data: {test: 123}}}));
     }
 
     get settings() {
@@ -39,44 +41,60 @@ class ServerStorage extends Vue {
     }
 
     generateNewServerStorageKey() {
-        const key = utils.toBase58(Buffer.from(utils.randomArray(32)));
+        const key = utils.toBase58(utils.randomArray(32));
         this.commit('reader/setServerStorageKey', key);
     }
 
     async storageCheck(items) {
-        return await this.decodeStorageItems(await readerApi.storage({action: 'check', items}));
+        return await this.storageApi('check', items);
     }
 
     async storageGet(items) {
-        return await this.decodeStorageItems(await readerApi.storage({action: 'get', items}));
+        return await this.storageApi('get', items);
     }
 
     async storageSet(items, force) {
-        return await readerApi.storage(await this.encodeStorageItems({action: 'set', force, items}));
+        return await this.storageApi('set', items, force);
+    }
+
+    async storageApi(action, items, force) {
+        const request = {action, items};
+        if (force)
+            request.force = true;
+        const encodedRequest = await this.encodeStorageItems(request);
+        return await this.decodeStorageItems(await readerApi.storage(encodedRequest));
     }
 
     async encodeStorageItems(request) {
+        if (!this.hashedStorageKey)
+            throw new Error('hashedStorageKey is empty');
+
         if (!_.isObject(request.items))
             throw new Error('items is not an object');
 
         let result = Object.assign({}, request);
         let items = {};
         for (const id of Object.keys(request.items)) {
+            if (id.indexOf('.') >= 0)
+                throw new Error(`encodeStorageItems: bad id - ${id}`);
+
             const item = request.items[id];
-            if (!_.isObject(item.data))
+            if (request.action == 'set' && !_.isObject(item.data))
                 throw new Error('encodeStorageItems: data is not an object');
 
             let encoded = Object.assign({}, item);
 
-            const comp = utils.pako.deflate(JSON.stringify(item.data), {level: 1});
-            let encrypted = null;
-            try {
-                encrypted = await cryptoUtils.aesEncrypt(comp, this.serverStorageKey);
-            } catch (e) {
-                throw new Error('encrypt failed');
+            if (item.data) {
+                const comp = utils.pako.deflate(JSON.stringify(item.data), {level: 1});
+                let encrypted = null;
+                try {
+                    encrypted = await cryptoUtils.aesEncrypt(comp, this.serverStorageKey);
+                } catch (e) {
+                    throw new Error('encrypt failed');
+                }
+                encoded.data = '1' + utils.toBase64(encrypted);
             }
-            encoded.data = '1' + utils.toBase64(Buffer.from(encrypted));
-            items[id] = encoded;
+            items[`${this.hashedStorageKey}.${id}`] = encoded;
         }
 
         result.items = items;
@@ -84,30 +102,39 @@ class ServerStorage extends Vue {
     }
 
     async decodeStorageItems(response) {
-        if (!_.isObject(response.items))
-            throw new Error('items is not an object');
+        if (!this.hashedStorageKey)
+            throw new Error('hashedStorageKey is empty');
 
         let result = Object.assign({}, response);
         let items = {};
-        for (const id of Object.keys(response.items)) {
-            const item = response.items[id];
-            let decoded = Object.assign({}, item);
-            if (item.data) {
-                if (!_.isString(item.data) || !item.data.length)
-                    throw new Error('decodeStorageItems: data is not a string');
-                if (item.data[0] !== '1')
-                    throw new Error('decodeStorageItems: unknown data format');
-
-                const a = utils.fromBase64(item.data.substr(1));
-                let decrypted = null;
-                try {
-                    decrypted = await cryptoUtils.aesDecrypt(a, this.serverStorageKey);
-                } catch (e) {
-                    throw new Error('decrypt failed');
+        if (response.items) {
+            if (!_.isObject(response.items))
+                throw new Error('items is not an object');
+
+            for (const id of Object.keys(response.items)) {
+                const item = response.items[id];
+                let decoded = Object.assign({}, item);
+                if (item.data) {
+                    if (!_.isString(item.data) || !item.data.length)
+                        throw new Error('decodeStorageItems: data is not a string');
+                    if (item.data[0] !== '1')
+                        throw new Error('decodeStorageItems: unknown data format');
+
+                    const a = utils.fromBase64(item.data.substr(1));
+                    let decrypted = null;
+                    try {
+                        decrypted = await cryptoUtils.aesDecrypt(a, this.serverStorageKey);
+                    } catch (e) {
+                        throw new Error('decrypt failed');
+                    }
+                    decoded.data = JSON.parse(utils.pako.inflate(decrypted, {to: 'string'}));
                 }
-                decoded.data = JSON.parse(utils.pako.inflate(decrypted, {to: 'string'}));
+
+                const ids = id.split('.');
+                if (!(ids.length == 2) || !(ids[0] == this.hashedStorageKey))
+                    throw new Error(`decodeStorageItems: bad id - ${id}`);
+                items[ids[1]] = decoded;
             }
-            items[id] = decoded;
         }
 
         result.items = items;

+ 5 - 1
client/share/cryptoUtils.js

@@ -63,4 +63,8 @@ export async function aesDecrypt(data, password) {
         key, //from generateKey or importKey above
         data //ArrayBuffer of the data
     );
-}
+}
+
+export async function sha256(data) {
+    return await crypto.subtle.digest("SHA-256", Buffer.from(data));
+}

+ 2 - 2
client/share/utils.js

@@ -78,7 +78,7 @@ export async function copyTextToClipboard(text) {
 }
 
 export function toBase58(data) {
-    return bs58.encode(data);
+    return bs58.encode(Buffer.from(data));
 }
 
 export function fromBase58(data) {
@@ -86,7 +86,7 @@ export function fromBase58(data) {
 }
 
 export function toBase64(data) {
-    return bs64.encode(data);
+    return bs64.encode(Buffer.from(data));
 }
 
 export function fromBase64(data) {