mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-03-27 15:55:55 +00:00
added encryption to the publish action
This commit is contained in:
parent
a1240569b8
commit
82bfcc3b28
@ -644,7 +644,8 @@
|
|||||||
"bchange41": "Do you give this application permission to access this list?",
|
"bchange41": "Do you give this application permission to access this list?",
|
||||||
"bchange42": "Items",
|
"bchange42": "Items",
|
||||||
"bchange43": "Do you give this application permission to add to this list?",
|
"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": {
|
"datapage": {
|
||||||
"dchange1": "Data Management",
|
"dchange1": "Data Management",
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
@ -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 nacl from '../../../../../qortal-ui-crypto/api/deps/nacl-fast.js'
|
||||||
import ed2curve from '../../../../../qortal-ui-crypto/api/deps/ed2curve.js'
|
import ed2curve from '../../../../../qortal-ui-crypto/api/deps/ed2curve.js'
|
||||||
import { mimeToExtensionMap } from '../../components/qdn-action-constants';
|
import { mimeToExtensionMap } from '../../components/qdn-action-constants';
|
||||||
|
import { encryptData } from '../../components/qdn-action-encryption';
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
|
||||||
|
|
||||||
class WebBrowser extends LitElement {
|
class WebBrowser extends LitElement {
|
||||||
@ -908,6 +909,7 @@ class WebBrowser extends LitElement {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case actions.PUBLISH_QDN_RESOURCE: {
|
case actions.PUBLISH_QDN_RESOURCE: {
|
||||||
|
// optional fields: encrypt:boolean recipientPublicKey:string
|
||||||
const requiredFields = ['service', 'name', 'data64'];
|
const requiredFields = ['service', 'name', 'data64'];
|
||||||
const missingFields = [];
|
const missingFields = [];
|
||||||
|
|
||||||
@ -929,7 +931,7 @@ class WebBrowser extends LitElement {
|
|||||||
const service = data.service;
|
const service = data.service;
|
||||||
const name = data.name;
|
const name = data.name;
|
||||||
let identifier = data.identifier;
|
let identifier = data.identifier;
|
||||||
const data64 = data.data64;
|
let data64 = data.data64;
|
||||||
const filename = data.filename;
|
const filename = data.filename;
|
||||||
const title = data.title;
|
const title = data.title;
|
||||||
const description = data.description;
|
const description = data.description;
|
||||||
@ -942,12 +944,39 @@ class WebBrowser extends LitElement {
|
|||||||
if (data.identifier == null) {
|
if (data.identifier == null) {
|
||||||
identifier = 'default';
|
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(
|
const res2 = await showModalAndWait(
|
||||||
actions.PUBLISH_QDN_RESOURCE,
|
actions.PUBLISH_QDN_RESOURCE,
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
identifier,
|
identifier,
|
||||||
service
|
service,
|
||||||
|
encrypt: data.encrypt
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (res2.action === 'accept') {
|
if (res2.action === 'accept') {
|
||||||
@ -1034,6 +1063,7 @@ class WebBrowser extends LitElement {
|
|||||||
actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
|
actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
|
||||||
{
|
{
|
||||||
resources,
|
resources,
|
||||||
|
encrypt: data.encrypt
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2852,6 +2882,7 @@ async function showModalAndWait(type, data) {
|
|||||||
${type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES ? `
|
${type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES ? `
|
||||||
<div class="modal-subcontainer">
|
<div class="modal-subcontainer">
|
||||||
<p class="modal-paragraph">${get("browserpage.bchange19")}</p>
|
<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>
|
<table>
|
||||||
${data.resources.map((resource) => `
|
${data.resources.map((resource) => `
|
||||||
<tr>
|
<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.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.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.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">
|
<div class="checkbox-row">
|
||||||
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);">
|
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);">
|
||||||
${get('browserpage.bchange29')}
|
${get('browserpage.bchange29')}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user