From 64d6510c4b653fc67ce2732f97545efc0bab330c Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 5 May 2023 01:11:43 +0300 Subject: [PATCH] added multiple publish encryption --- qortal-ui-core/language/us.json | 3 +- .../core/components/qdn-action-types.js | 5 +- .../plugins/core/qdn/browser/browser.src.js | 141 ++++++++---------- 3 files changed, 65 insertions(+), 84 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index b998e557..bd762aa2 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -645,7 +645,8 @@ "bchange42": "Items", "bchange43": "Do you give this application permission to add to this list?", "bchange44": "Do you give this application permission to delete from this list?", - "bchange45": "Encrypt" + "bchange45": "Encrypt", + "bchange46": "Do you give this application permission to save the following file:" }, "datapage": { "dchange1": "Data Management", diff --git a/qortal-ui-plugins/plugins/core/components/qdn-action-types.js b/qortal-ui-plugins/plugins/core/components/qdn-action-types.js index 48ea7214..666d67f2 100644 --- a/qortal-ui-plugins/plugins/core/components/qdn-action-types.js +++ b/qortal-ui-plugins/plugins/core/components/qdn-action-types.js @@ -41,4 +41,7 @@ export const DELETE_LIST_ITEM = 'DELETE_LIST_ITEM' export const ENCRYPT_DATA = 'ENCRYPT_DATA' // DECRYPT_DATA -export const DECRYPT_DATA = 'DECRYPT_DATA' \ No newline at end of file +export const DECRYPT_DATA = 'DECRYPT_DATA' + +// SAVE_FILE +export const SAVE_FILE = 'SAVE_FILE' \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js index 5b8ee326..50f0b4c1 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -24,7 +24,7 @@ import { QORT_DECIMALS } from 'qortal-ui-crypto/api/constants'; import nacl from '../../../../../qortal-ui-crypto/api/deps/nacl-fast.js' import ed2curve from '../../../../../qortal-ui-crypto/api/deps/ed2curve.js' import { mimeToExtensionMap } from '../../components/qdn-action-constants'; -import { encryptData } from '../../components/qdn-action-encryption'; +import { base64ToUint8Array, encryptData, uint8ArrayToBase64 } from '../../components/qdn-action-encryption'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); class WebBrowser extends LitElement { @@ -561,79 +561,9 @@ class WebBrowser extends LitElement { break; } } - case actions.ENCRYPT_DATA: { - const requiredFields = ['Uint8ArrayData', 'destinationPublicKey']; - const missingFields = []; - - requiredFields.forEach((field) => { - if (!data[field]) { - missingFields.push(field); - } - }); - - if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(', '); - const errorMsg = `Missing fields: ${missingFieldsString}` - let data = {}; - data['error'] = errorMsg; - response = JSON.stringify(data); - break - } - const { Uint8ArrayData, destinationPublicKey } = data - - const uint8Array = new Uint8Array(Object.values(Uint8ArrayData)); - if (!(uint8Array instanceof Uint8Array)) { - data['error'] = "The Uint8ArrayData you've submitted is invalid"; - response = JSON.stringify(data); - break - } - try { - const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - if (!privateKey) { - data['error'] = "Unable to retrieve keys" - response = JSON.stringify(data); - break - } - const publicKeyUnit8Array = window.parent.Base58.decode(destinationPublicKey) - const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(publicKeyUnit8Array) - const sharedSecret = new Uint8Array(32) - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - - const chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result - - const nonce = new Uint8Array(24); - window.crypto.getRandomValues(nonce); - const encryptedData = nacl.secretbox(uint8Array, nonce, chatEncryptionSeed) - - const str = "qortalEncryptedData"; - const strEncoder = new TextEncoder(); - const strUint8Array = strEncoder.encode(str); - - const combinedData = new Uint8Array(strUint8Array.length + nonce.length + encryptedData.length); - - combinedData.set(strUint8Array); - - combinedData.set(nonce, strUint8Array.length); - combinedData.set(encryptedData, strUint8Array.length + nonce.length); - - - let data = {}; - data['encryptedData'] = combinedData - data['destinationPublicKey'] = destinationPublicKey - response = JSON.stringify(data); - break; - } catch (error) { - const data = {}; - const errorMsg = error.message || "Error in encrypting data" - data['error'] = errorMsg; - response = JSON.stringify(data); - break - } - } case actions.DECRYPT_DATA: { - const requiredFields = ['encryptedData', 'senderPublicKey']; + const requiredFields = ['encryptedData', 'publicKey']; const missingFields = []; requiredFields.forEach((field) => { @@ -650,11 +580,11 @@ class WebBrowser extends LitElement { response = JSON.stringify(data); break } - const { encryptedData, senderPublicKey } = data + const { encryptedData, publicKey } = data try { - const uint8Array = new Uint8Array(Object.values(encryptedData)); + const uint8Array = base64ToUint8Array(encryptedData) const combinedData = uint8Array const str = "qortalEncryptedData"; const strEncoder = new TextEncoder(); @@ -665,26 +595,27 @@ class WebBrowser extends LitElement { const _encryptedData = combinedData.slice(strUint8Array.length + 24); const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey - const publicKey = window.parent.Base58.decode(senderPublicKey) + const _publicKey = window.parent.Base58.decode(publicKey) - if (!privateKey || !publicKey) { + if (!privateKey || !_publicKey) { data['error'] = "Unable to retrieve keys" response = JSON.stringify(data); break } const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(publicKey) + const convertedPublicKey = ed2curve.convertPublicKey(_publicKey) const sharedSecret = new Uint8Array(32); nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) const _chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result const _decryptedData = nacl.secretbox.open(_encryptedData, nonce, _chatEncryptionSeed) - let data = {}; - data['decryptedData'] = _decryptedData - response = JSON.stringify(data); + const decryptedDataToBase64 = uint8ArrayToBase64(_decryptedData) + response = JSON.stringify(decryptedDataToBase64); + break; } catch (error) { + console.log({ error }) const data = {}; const errorMsg = error.message || "Error in decrypting data" data['error'] = errorMsg; @@ -1059,6 +990,12 @@ class WebBrowser extends LitElement { response = JSON.stringify(data); break } + if (data.encrypt && !data.recipientPublicKey) { + let data = {}; + data['error'] = "Encrypting data requires the recipient's public key"; + response = JSON.stringify(data); + break + } const res2 = await showModalAndWait( actions.PUBLISH_MULTIPLE_QDN_RESOURCES, { @@ -1091,7 +1028,7 @@ class WebBrowser extends LitElement { const service = resource.service; const name = resource.name; let identifier = resource.identifier; - const data64 = resource.data64; + let data64 = resource.data64; const filename = resource.filename; const title = resource.title; const description = resource.description; @@ -1105,6 +1042,24 @@ class WebBrowser extends LitElement { identifier = 'default'; } + if (data.encrypt) { + try { + const encryptDataResponse = encryptData({ + data64, recipientPublicKey: data.recipientPublicKey + }) + if (encryptDataResponse.encryptedData) { + data64 = encryptDataResponse.encryptedData + } + + } catch (error) { + const errorMsg = error.message || 'Upload failed due to failed encryption' + throw new Error(errorMsg) + } + + } + + + const worker = new WebWorker(); try { @@ -1422,8 +1377,9 @@ class WebBrowser extends LitElement { // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` break; } - case 'DOWNLOAD': { + case actions.SAVE_FILE: { try { + const requiredFields = ['filename', 'blob']; const missingFields = []; @@ -1442,9 +1398,24 @@ class WebBrowser extends LitElement { break } + + const filename = data.filename const blob = data.blob + const res = await showModalAndWait( + actions.SAVE_FILE, + { + filename + } + ); + + if (res.action === 'reject') { + response = '{"error": "User declined request"}'; + break + + } + const mimeType = blob.type || data.mimeType let backupExention = filename.split('.').pop() if (backupExention) { @@ -2952,6 +2923,12 @@ async function showModalAndWait(type, data) { ` : ''} + ${type === actions.SAVE_FILE ? ` + + ` : ''} + ${type === actions.DELETE_LIST_ITEM ? `