${this.groupInfo && this.groupInfo.groupName}
+${this.groupInfo && this.groupInfo.groupName}
${translate("blockpage.bcchange16")}
${translate("chatpage.cchange38")}
++ ${this.forwardActiveChatHeadUrl.name} +
++ Forwarding... +
+diff --git a/qortal-ui-core/font/KoHo.ttf b/qortal-ui-core/font/KoHo.ttf new file mode 100644 index 00000000..72841e9d Binary files /dev/null and b/qortal-ui-core/font/KoHo.ttf differ diff --git a/qortal-ui-core/font/Livvic.ttf b/qortal-ui-core/font/Livvic.ttf new file mode 100644 index 00000000..f477b285 Binary files /dev/null and b/qortal-ui-core/font/Livvic.ttf differ diff --git a/qortal-ui-core/font/Montserrat.ttf b/qortal-ui-core/font/Montserrat.ttf new file mode 100644 index 00000000..656db666 Binary files /dev/null and b/qortal-ui-core/font/Montserrat.ttf differ diff --git a/qortal-ui-core/font/Raleway.ttf b/qortal-ui-core/font/Raleway.ttf new file mode 100644 index 00000000..424fb0e8 Binary files /dev/null and b/qortal-ui-core/font/Raleway.ttf differ diff --git a/qortal-ui-core/font/material-icons.css b/qortal-ui-core/font/material-icons.css index 2270c09d..0363d4ee 100644 --- a/qortal-ui-core/font/material-icons.css +++ b/qortal-ui-core/font/material-icons.css @@ -2,19 +2,49 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: url(MaterialIcons-Regular.eot); /* For IE6-8 */ + src: url(MaterialIcons-Regular.eot); + /* For IE6-8 */ src: local('Material Icons'), - local('MaterialIcons-Regular'), - url(MaterialIcons-Regular.woff2) format('woff2'), - url(MaterialIcons-Regular.woff) format('woff'), - url(MaterialIcons-Regular.ttf) format('truetype'); + local('MaterialIcons-Regular'), + url(MaterialIcons-Regular.woff2) format('woff2'), + url(MaterialIcons-Regular.woff) format('woff'), + url(MaterialIcons-Regular.ttf) format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + src: local('Montserrat'), + local('Montserrat'), + url(Montserrat.ttf) format('truetype'); +} + +@font-face { + font-family: 'Raleway'; + src: local('Raleway'), + local('Raleway'), + url(Raleway.ttf) format('truetype'); +} + +@font-face { + font-family: 'KoHo'; + src: local('KoHo'), + local('KoHo'), + url(KoHo.ttf) format('truetype'); +} + +@font-face { + font-family: 'Livvic'; + src: local('Livvic'), + local('Livvic'), + url(Livvic.ttf) format('truetype'); } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; - font-size: 24px; /* Preferred icon size */ + font-size: 24px; + /* Preferred icon size */ display: inline-block; line-height: 1; text-transform: none; @@ -33,4 +63,4 @@ /* Support for IE. */ font-feature-settings: 'liga'; -} +} \ No newline at end of file diff --git a/qortal-ui-core/font/switch-theme.css b/qortal-ui-core/font/switch-theme.css index b9eeee64..110700a3 100644 --- a/qortal-ui-core/font/switch-theme.css +++ b/qortal-ui-core/font/switch-theme.css @@ -48,6 +48,8 @@ html { --chatHeadText: #080808; --chatHeadTextActive: #080808; --lightChatHeadHover: #1e1f201a; + --group-header: #929292; + --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; } html[theme="dark"] { @@ -100,4 +102,6 @@ html[theme="dark"] { --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; --lightChatHeadHover: #e0e1e31a; + --group-header: #c8c8c8; + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px } \ No newline at end of file diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index c2bc9565..efeca99f 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -465,8 +465,8 @@ "cchange3": "Blocked Users", "cchange4": "New Message", "cchange5": "(Click to scroll down)", - "cchange6": "Type the name or address of who you want to chat with to send a private message!", - "cchange7": "Name / Address", + "cchange6": "Type the name or address of who you want to chat with to send a private message! You can validate the person's name by clicking on the book icon.", + "cchange7": "Username / Address", "cchange8": "Message...", "cchange9": "Send", "cchange10": "Blocked Users List", @@ -478,7 +478,7 @@ "cchange16": "Successfully unblocked this user.", "cchange17": "Error occurred when trying to unblock this user. Please try again!", "cchange18": "unblock", - "cchange19": "Invalid Name / Address, Check the name / address and retry...", + "cchange19": "Invalid Username / Address, Check the name / address and retry...", "cchange20": "Message Sent Successfully!", "cchange21": "Sending failed, Please retry...", "cchange22": "Loading Messages...", @@ -492,7 +492,13 @@ "cchange30": "Uploading image. This may take up to one minute.", "cchange31": "Deleting image. This may take up to one minute.", "cchange33": "Cancel", - "cchange34": "This chat message is using an older message version and cannot use this feature." + "cchange34": "This chat message is using an older message version and cannot use this feature.", + "cchange35": "Error when trying to fetch the user's name. Please try again!", + "cchange36": "Search Results", + "cchange37": "No Results Found", + "cchange38": "User Verified", + "cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.", + "cchange40": "IMAGE (click to view)" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -521,7 +527,7 @@ "bcchange13": "Reaction", "bcchange14": "Forward", "bcchange15": "Message Forwarded", - "bcchange16": "Choose recipient", + "bcchange16": "Choose Recipient or Search for One Below", "bcchange17": "FORWARDED" }, "grouppage": { diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index b293210f..1e00ccfb 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -77,7 +77,8 @@ "rollup-plugin-postcss": "4.0.2", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", - "rollup-plugin-terser": "7.0.2" + "rollup-plugin-terser": "7.0.2", + "rollup-plugin-web-worker-loader": "^1.6.1" }, "engines": { "node": ">=16.15.0" diff --git a/qortal-ui-core/src/components/app-info.js b/qortal-ui-core/src/components/app-info.js index 06bedc8a..e7372515 100644 --- a/qortal-ui-core/src/components/app-info.js +++ b/qortal-ui-core/src/components/app-info.js @@ -3,6 +3,8 @@ import { connect } from 'pwa-helpers' import { store } from '../store.js' import { doPageUrl } from '../redux/app/app-actions.js' import { translate, translateUnsafeHTML } from 'lit-translate' +import WebWorker from 'web-worker:./computePowWorker.js'; +import { routes } from '../plugins/routes.js'; import '@material/mwc-icon' import '@material/mwc-button' @@ -94,6 +96,8 @@ class AppInfo extends connect(store)(LitElement) { this.nodeStatus = {} this.pageUrl = '' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.publicKeyisOnChainConfirmation = false + this.interval } render() { @@ -107,10 +111,110 @@ class AppInfo extends connect(store)(LitElement) { ` } + async confirmPublicKeyOnChain(address) { + const _computePow2 = async (chatBytes) => { + const difficulty = 15; + const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full' + const worker = new WebWorker(); + let nonce = null + let chatBytesArray = null + await new Promise((res, rej) => { + worker.postMessage({chatBytes, path, difficulty}); + + worker.onmessage = e => { + worker.terminate() + chatBytesArray = e.data.chatBytesArray + nonce = e.data.nonce + res() + + } + }) + + let _response = await routes.sign_chat({ + data: { + nonce: store.getState().app.selectedAddress.nonce, + chatBytesArray: chatBytesArray, + chatNonce: nonce + }, + + }); + return _response + }; + + + let stop = false + const checkPublicKey = async () => { + if (!stop) { + stop = true; + try { + const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const url = `${nodeUrl}/addresses/publickey/${address}`; + const res = await fetch(url) + let data = '' + try { + data = await res.text(); + } catch (error) { + data = { + error: 'error' + } + } + if(data === 'false' && this.nodeInfo.isSynchronizing !== true){ + let _reference = new Uint8Array(64); + window.crypto.getRandomValues(_reference); + let reference = window.parent.Base58.encode(_reference); + const chatRes = await routes.chat({ + data: { + type: 19, + nonce: store.getState().app.selectedAddress.nonce, + params: { + lastReference: reference, + proofOfWorkNonce: 0, + fee: 0, + timestamp: Date.now(), + + }, + disableModal: true + }, + disableModal: true, + }); + + try { + const powRes = await _computePow2(chatRes) + if(powRes === true){ + clearInterval(this.interval) + + this.publicKeyisOnChainConfirmation = true + } + } catch (error) { + console.error(error) + } + } + + if (!data.error && data !== 'false' && data) { + clearInterval(this.interval) + + this.publicKeyisOnChainConfirmation = true + } + + } catch (error) { + } + stop = false + } + }; + this.interval = setInterval(checkPublicKey, 5000); + } + firstUpdated() { this.getNodeInfo() this.getCoreInfo() - + try { + this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address) + } catch (error) { + console.error(error) + } + + setInterval(() => { this.getNodeInfo() this.getCoreInfo() diff --git a/qortal-ui-core/src/components/computePowWorker.js b/qortal-ui-core/src/components/computePowWorker.js new file mode 100644 index 00000000..2ed60a20 --- /dev/null +++ b/qortal-ui-core/src/components/computePowWorker.js @@ -0,0 +1,82 @@ +import { Sha256 } from 'asmcrypto.js' + + +function sbrk(size, heap){ + let brk = 512 * 1024 // stack top + let old = brk + brk += size + + if (brk > heap.length) + throw new Error('heap exhausted') + + return old +} + + + +self.addEventListener('message', async e => { + const response = await computePow(e.data.chatBytes, e.data.path, e.data.difficulty) + postMessage(response) + +}) + + +const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 }) +const heap = new Uint8Array(memory.buffer) + + + +const computePow = async (chatBytes, path, difficulty) => { + + let response = null + + await new Promise((resolve, reject)=> { + + const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }); + const chatBytesArray = new Uint8Array(_chatBytesArray); + const chatBytesHash = new Sha256().process(chatBytesArray).finish().result; + const hashPtr = sbrk(32, heap); + const hashAry = new Uint8Array(memory.buffer, hashPtr, 32); + hashAry.set(chatBytesHash); + + + const workBufferLength = 8 * 1024 * 1024; + const workBufferPtr = sbrk(workBufferLength, heap); + + + + const importObject = { + env: { + memory: memory + }, + }; + + function loadWebAssembly(filename, imports) { + // Fetch the file and compile it + return fetch(filename) + .then(response => response.arrayBuffer()) + .then(buffer => WebAssembly.compile(buffer)) + .then(module => { + + // Create the instance. + return new WebAssembly.Instance(module, importObject); + }); +} + + +loadWebAssembly(path) + .then(wasmModule => { + response = { + nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty), + chatBytesArray + } + + resolve() + + }); + + + }) + + return response +} \ No newline at end of file diff --git a/qortal-ui-core/src/styles/switch-theme.css b/qortal-ui-core/src/styles/switch-theme.css index a3108823..72dfa151 100644 --- a/qortal-ui-core/src/styles/switch-theme.css +++ b/qortal-ui-core/src/styles/switch-theme.css @@ -46,6 +46,8 @@ html { --chatHeadBgActive: #ebebeb; --chatHeadText: #080808; --chatHeadTextActive: #080808; + --group-header: #929292; + --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; } html[theme="dark"] { @@ -96,4 +98,6 @@ html[theme="dark"] { --chatHeadBgActive: #0f1a2e; --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; + --group-header: #c8c8c8; + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px } \ No newline at end of file diff --git a/qortal-ui-core/tooling/generateBuildConfig.js b/qortal-ui-core/tooling/generateBuildConfig.js index e8beb2b8..6d163ae9 100644 --- a/qortal-ui-core/tooling/generateBuildConfig.js +++ b/qortal-ui-core/tooling/generateBuildConfig.js @@ -7,6 +7,8 @@ const commonjs = require('@rollup/plugin-commonjs') const alias = require('@rollup/plugin-alias') const { terser } = require('rollup-plugin-terser') const scss = require('rollup-plugin-scss') +const webWorkerLoader = require('rollup-plugin-web-worker-loader'); + const generateES5BuildConfig = require('./generateES5BuildConfig') @@ -61,6 +63,7 @@ const generateBuildConfig = ({ elementComponents, functionalComponents, otherOut commonjs(), globals(), progress(), + webWorkerLoader(), scss({ output: options.sassOutputDir }), diff --git a/qortal-ui-core/tooling/generateES5BuildConfig.js b/qortal-ui-core/tooling/generateES5BuildConfig.js index 2b5d15b1..a746a6c1 100644 --- a/qortal-ui-core/tooling/generateES5BuildConfig.js +++ b/qortal-ui-core/tooling/generateES5BuildConfig.js @@ -6,6 +6,7 @@ const progress = require('rollup-plugin-progress'); const { terser } = require("rollup-plugin-terser"); const path = require('path'); const alias = require('@rollup/plugin-alias'); +const webWorkerLoader = require('rollup-plugin-web-worker-loader'); const generateRollupConfig = (file, { outputDir, aliases }) => { @@ -36,6 +37,7 @@ const generateRollupConfig = (file, { outputDir, aliases }) => { }), commonjs(), progress(), + webWorkerLoader(), babel.babel({ babelHelpers: 'bundled', exclude: 'node_modules/**' diff --git a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js index d4982bcb..20dd0ebc 100644 --- a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js +++ b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js @@ -1,5 +1,6 @@ "use strict"; import ChatBase from "./chat/ChatBase.js" +import { QORT_DECIMALS } from "../constants.js" export default class PublicizeTransaction extends ChatBase { constructor() { @@ -11,13 +12,17 @@ export default class PublicizeTransaction extends ChatBase { set proofOfWorkNonce(proofOfWorkNonce) { this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) } - + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } get params() { const params = super.params; params.push( this._proofOfWorkNonce, this._feeBytes ) + console.log({params}) return params; } } diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index 59282688..cde55b60 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -51,12 +51,12 @@ "@rollup/plugin-commonjs": "23.0.0", "@rollup/plugin-node-resolve": "15.0.0", "@rollup/plugin-replace": "5.0.0", + "@vaadin/avatar": "23.2.5", "@vaadin/button": "23.2.5", "@vaadin/grid": "23.2.5", + "@vaadin/horizontal-layout": "23.2.5", "@vaadin/icons": "23.2.5", "@vaadin/tabs": "23.2.5", - "@vaadin/avatar": "23.2.5", - "@vaadin/horizontal-layout": "23.2.5", "epml": "0.3.3", "file-saver": "2.0.5", "html-escaper": "3.0.3", diff --git a/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js b/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js index da5f951d..ac50df20 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js +++ b/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js @@ -43,9 +43,11 @@ class ChatGroupSettings extends LitElement { width: 18px; transition: .2s all; } + .top-bar-icon:hover { color: var(--black) } + .modal-button { font-family: Roboto, sans-serif; font-size: 16px; diff --git a/qortal-ui-plugins/plugins/core/components/ChatModals.js b/qortal-ui-plugins/plugins/core/components/ChatModals.js index c9daf3b4..a41f6748 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatModals.js +++ b/qortal-ui-plugins/plugins/core/components/ChatModals.js @@ -366,7 +366,6 @@ class ChatModals extends LitElement {
${this.groupInfo && this.groupInfo.groupName}
+${this.groupInfo && this.groupInfo.groupName}
${translate("blockpage.bcchange16")}
${translate("chatpage.cchange38")}
++ ${this.forwardActiveChatHeadUrl.name} +
++ Forwarding... +
+${this.leaveGroupObj && this.leaveGroupObj.groupName}
-${this.leaveGroupObj && this.leaveGroupObj.description}
-Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}
- -Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}
-Group Owner
- ${owner.map((item) => { - return html`Admins
- ${this.groupAdmin.map((item) => { - return html`Members
- ${this.groupMembers.map((item) => { - return html`${this.leaveGroupObj && this.leaveGroupObj.groupName}
+${this.leaveGroupObj && this.leaveGroupObj.description}
+Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}
+ +Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}
GROUP OWNER
+ ${owner.map((item) => { + return html`ADMINS
+ ${this.groupAdmin.map((item) => { + return html`MEMBERS
+ ${this.groupMembers.map((item) => { + return html`Are you sure you want to delete this image?
+