Browse Source

added encryption to the publish action

qortal-ui-dev
Phillip 1 year ago
parent
commit
82bfcc3b28
  1. 3
      qortal-ui-core/language/us.json
  2. 84
      qortal-ui-plugins/plugins/core/components/qdn-action-encryption.js
  3. 36
      qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js

3
qortal-ui-core/language/us.json

@ -644,7 +644,8 @@
"bchange41": "Do you give this application permission to access this list?",
"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?"
"bchange44": "Do you give this application permission to delete from this list?",
"bchange45": "Encrypt"
},
"datapage": {
"dchange1": "Data Management",

84
qortal-ui-plugins/plugins/core/components/qdn-action-encryption.js

@ -0,0 +1,84 @@
import nacl from '../../../../qortal-ui-crypto/api/deps/nacl-fast.js'
import ed2curve from '../../../../qortal-ui-crypto/api/deps/ed2curve.js'
export function uint8ArrayToBase64(uint8Array) {
const length = uint8Array.length;
let base64String = '';
const chunkSize = 1024 * 1024; // Process 1MB at a time
for (let i = 0; i < length; i += chunkSize) {
const chunkEnd = Math.min(i + chunkSize, length);
const chunk = uint8Array.subarray(i, chunkEnd);
const binaryString = chunk.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
base64String += btoa(binaryString);
}
return base64String;
}
export function base64ToUint8Array(base64) {
const binaryString = atob(base64)
const len = binaryString.length
const bytes = new Uint8Array(len)
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
return bytes
}
export const encryptData = ({ data64, recipientPublicKey }) => {
const Uint8ArrayData = base64ToUint8Array(data64)
const uint8Array = Uint8ArrayData
if (!(uint8Array instanceof Uint8Array)) {
throw new Error("The Uint8ArrayData you've submitted is invalid")
}
try {
const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey
if (!privateKey) {
throw new Error("Unable to retrieve keys")
}
const publicKeyUnit8Array = window.parent.Base58.decode(recipientPublicKey)
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);
const uint8arrayToData64 = uint8ArrayToBase64(combinedData)
return {
encryptedData: uint8arrayToData64,
recipientPublicKey
}
} catch (error) {
console.log({ error })
throw new Error("Error in encrypting data")
}
}

36
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js

@ -24,6 +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';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class WebBrowser extends LitElement {
@ -908,6 +909,7 @@ class WebBrowser extends LitElement {
return;
case actions.PUBLISH_QDN_RESOURCE: {
// optional fields: encrypt:boolean recipientPublicKey:string
const requiredFields = ['service', 'name', 'data64'];
const missingFields = [];
@ -929,7 +931,7 @@ class WebBrowser extends LitElement {
const service = data.service;
const name = data.name;
let identifier = data.identifier;
const data64 = data.data64;
let data64 = data.data64;
const filename = data.filename;
const title = data.title;
const description = data.description;
@ -942,12 +944,39 @@ class WebBrowser extends LitElement {
if (data.identifier == null) {
identifier = 'default';
}
if (data.encrypt && !data.recipientPublicKey) {
let data = {};
data['error'] = "Encrypting data requires the recipient's public key";
response = JSON.stringify(data);
break
}
if (data.encrypt) {
try {
const encryptDataResponse = encryptData({
data64, recipientPublicKey: data.recipientPublicKey
})
if (encryptDataResponse.encryptedData) {
data64 = encryptDataResponse.encryptedData
}
} catch (error) {
const obj = {};
const errorMsg = error.message || 'Upload failed due to failed encryption';
obj['error'] = errorMsg;
response = JSON.stringify(obj);
break
}
}
const res2 = await showModalAndWait(
actions.PUBLISH_QDN_RESOURCE,
{
name,
identifier,
service
service,
encrypt: data.encrypt
}
);
if (res2.action === 'accept') {
@ -1034,6 +1063,7 @@ class WebBrowser extends LitElement {
actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
{
resources,
encrypt: data.encrypt
}
);
@ -2852,6 +2882,7 @@ async function showModalAndWait(type, data) {
${type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES ? `
<div class="modal-subcontainer">
<p class="modal-paragraph">${get("browserpage.bchange19")}</p>
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange45")}:</span> ${data.encrypt ? true : false}</p>
<table>
${data.resources.map((resource) => `
<tr>
@ -2877,6 +2908,7 @@ async function showModalAndWait(type, data) {
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange30")}:</span> ${data.service}</p>
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange31")}:</span> ${data.name}</p>
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange32")}:</span> ${data.identifier}</p>
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange45")}:</span> ${data.encrypt ? true : false}</p>
<div class="checkbox-row">
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);">
${get('browserpage.bchange29')}

Loading…
Cancel
Save