Skip to content

Commit

Permalink
Merge pull request #274 from theQRL/testnet
Browse files Browse the repository at this point in the history
Version 1.0.3 Release
  • Loading branch information
jplomas authored Sep 13, 2018
2 parents 5a22f5f + bc443b0 commit 4c6ba59
Show file tree
Hide file tree
Showing 18 changed files with 568 additions and 359 deletions.
412 changes: 195 additions & 217 deletions .electrify/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions .electrify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"name": "QRLWallet",
"productName": "QRLWallet",
"projectName": "qrl-wallet",
"version": "1.0.2",
"version": "1.0.3",
"main": "index.js",
"dependencies": {
"electrify-qrl": "0.0.1",
"grpc": "^1.13.0",
"electrify-qrl": "0.0.3",
"grpc": "^1.14.0",
"grpc-promise": "^1.1.0"
},
"electronPackager": {
Expand Down
2 changes: 1 addition & 1 deletion .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ juliancwirko:postcss
[email protected]
[email protected]
qrl:browser-policy
underscore
underscore@1.0.10
2 changes: 1 addition & 1 deletion .meteor/release
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[email protected].4
[email protected].5
53 changes: 52 additions & 1 deletion imports/startup/both/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,58 @@ import './nodes.js'
SHOR_PER_QUANTA=1000000000

// qrl-wallet Version
WALLET_VERSION="1.0.2"
WALLET_VERSION="1.0.3"

// qrl.proto sha256 sum for each release of QRL Node
QRLPROTO_SHA256 = [
{
version: "1.0.0",
protoSha256: "4565ecb1a7e3852bd46a8e357bbcc95dfc7a81bec761df50550d567a71bf6ed6",
objectSha256: "d538cc0164f26cdda4e082cca548f531038d70a4b879495a4483f66e4c53cae9",
},
{
version: "1.1.0",
protoSha256: "9daaa59da125167ae825bf182a65c7f12a3af78f2cc351991a5faae03fb99892",
objectSha256: "7e841e796be583d30066e33f8d9b344ffe8160eb02fecc6cb4df80f7823e932c",
},
{
version: "1.1.1",
protoSha256: "9daaa59da125167ae825bf182a65c7f12a3af78f2cc351991a5faae03fb99892",
objectSha256: "7e841e796be583d30066e33f8d9b344ffe8160eb02fecc6cb4df80f7823e932c",
},
{
version: "1.1.2",
protoSha256: "9daaa59da125167ae825bf182a65c7f12a3af78f2cc351991a5faae03fb99892",
objectSha256: "7e841e796be583d30066e33f8d9b344ffe8160eb02fecc6cb4df80f7823e932c",
},
{
version: "1.1.3",
protoSha256: "9daaa59da125167ae825bf182a65c7f12a3af78f2cc351991a5faae03fb99892",
objectSha256: "7e841e796be583d30066e33f8d9b344ffe8160eb02fecc6cb4df80f7823e932c",
},
{
version: "1.1.4",
protoSha256: "71a51e5222c50a7575f1a92c365f6674bae938cebae678416da80f22fa8327b9",
objectSha256: "6589d425a16741104bbeceaa9ab2a1dbb33ff47453b90e29c3ee540dbad22df5",
},
]

// function to get shasum of qrl node version
getQrlProtoShasum = (nodeVersion, callback) => {
let itemsProcessed
QRLPROTO_SHA256.forEach((qrlnode, index, array) => {
itemsProcessed++
// Only look at health of userNetwork
if (qrlnode.version == nodeVersion) {
callback(qrlnode)
}
// If we got to the end, and didn't callback above, the version was not found.
// Return null
if(itemsProcessed === array.length) {
callback(null)
}
})
}

// Function to cleanly represent large decimal numbers without exponentional formatting.
numberToString = (num) => {
Expand Down
12 changes: 12 additions & 0 deletions imports/startup/client/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ getBalance = (getAddress, callBack) => {
LocalStore.set('address', 'Error')
LocalStore.set('otsKeyEstimate', 0)
LocalStore.set('otsKeysRemaining', 0)
LocalStore.set('otsBitfield', {})
} else {
if (res.state.address !== '') {
LocalStore.set('transferFromBalance', res.state.balance / SHOR_PER_QUANTA)
Expand All @@ -239,12 +240,22 @@ getBalance = (getAddress, callBack) => {
// Set keys remaining
LocalStore.set('otsKeysRemaining', keysRemaining)

// Store OTS Bitfield in LocalStorage
LocalStore.set('otsBitfield', res.ots.keys)

// Callback if set
callBack()
}
})
}

otsIndexUsed = (otsBitfield, index) => {
if(otsBitfield[index] === 1) {
return true
}
return false
}

loadAddressTransactions = (txArray) => {
const request = {
tx: txArray,
Expand Down Expand Up @@ -409,6 +420,7 @@ resetLocalStorageState = () => {
LocalStore.set('otsKeyEstimate', '')
LocalStore.set('balanceAmount', '')
LocalStore.set('balanceSymbol', '')
LocalStore.set('otsBitfield', '')
}

function logRequestResponse(request, response) {
Expand Down
1 change: 0 additions & 1 deletion imports/startup/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ XMSS_OBJECT = null
POLL_TXN_RATE = 5000 // 5seconds
POLL_MAX_CHECKS = 120 // max 10 minutes checking status


// Reset wallet status
resetWalletStatus()

Expand Down
112 changes: 85 additions & 27 deletions imports/startup/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import grpc from 'grpc'
import tmp from 'tmp'
import fs from 'fs'
import async from 'async'
import CryptoJS from 'crypto-js'
import util from 'util'

// Apply BrowserPolicy
BrowserPolicy.content.disallowInlineScripts()
Expand All @@ -37,36 +39,92 @@ const errorCallback = (error, message, alert) => {

// Load the qrl.proto gRPC client into qrlClient from a remote node.
const loadGrpcClient = (endpoint, callback) => {
// Load qrlbase.proto and fetch current qrl.proto from node
const baseGrpcObject = grpc.load(Assets.absoluteFilePath('qrlbase.proto'))
const client = new baseGrpcObject.qrl.Base(endpoint, grpc.credentials.createInsecure())

client.getNodeInfo({}, (err, res) => {
if (err) {
console.log(`Error fetching qrl.proto from ${endpoint}`)
callback(err, null)
} else {
// Write a new temp file for this grpc connection
const qrlProtoFilePath = tmp.fileSync({ mode: '0644', prefix: 'qrl-', postfix: '.proto' }).name

fs.writeFile(qrlProtoFilePath, res.grpcProto, (fsErr) => {
if (fsErr) {
console.log(fsErr)
throw fsErr
}
try {
// Load qrlbase.proto and fetch current qrl.proto from node
const baseGrpcObject = grpc.load(Assets.absoluteFilePath('qrlbase.proto'))
const client = new baseGrpcObject.qrl.Base(endpoint, grpc.credentials.createInsecure())

const grpcObject = grpc.load(qrlProtoFilePath)
client.getNodeInfo({}, (err, res) => {
if (err) {
console.log(`Error fetching qrl.proto from ${endpoint}`)
callback(err, null)
} else {
// Write a new temp file for this grpc connection
const qrlProtoFilePath = tmp.fileSync({ mode: '0644', prefix: 'qrl-', postfix: '.proto' }).name
fs.writeFile(qrlProtoFilePath, res.grpcProto, (fsErr) => {
if (fsErr) {
console.log(fsErr)
throw fsErr
}

// Create the gRPC Connection
qrlClient[endpoint] =
new grpcObject.qrl.PublicAPI(endpoint, grpc.credentials.createInsecure())
// Validate proto file matches node version
getQrlProtoShasum(res.version, (verifiedProtoSha256Hash) => {
// If we get null back, we were unable to identify a verified sha256 hash against this qrl node verison.
if(verifiedProtoSha256Hash.protoSha256 == null) {
console.log(`Cannot verify QRL node version on: ${endpoint} - Version: ${res.version}`)
const myError = errorCallback(err, `Cannot verify QRL node version on: ${endpoint} - Version: ${res.version}`, '**ERROR/connect**')
callback(myError, null)
}

console.log(`qrlClient loaded for ${endpoint}`)
// Now read the saved qrl.proto file so we can calculate a hash from it
fs.readFile(qrlProtoFilePath, function(err, contents) {
if (fsErr) {
console.log(fsErr)
throw fsErr
}

callback(null, true)
})
}
})
// Calculate the hash of the qrl.proto file contents
const protoFileWordArray = CryptoJS.lib.WordArray.create(contents)
const calculatedProtoHash = CryptoJS.SHA256(protoFileWordArray).toString(CryptoJS.enc.Hex)

// If the calculated qrl.proto hash matches the verified one for this version,
// continue to verify the grpc object loaded from the proto also matches the correct
// shasum.
if (calculatedProtoHash == verifiedProtoSha256Hash.protoSha256) {
// Load gRPC object
const grpcObject = grpc.load(qrlProtoFilePath)

// Inspect the object and convert to string.
const grpcObjectString = JSON.stringify(util.inspect(grpcObject, {showHidden: true, depth: 4}))

// Calculate the hash of the grpc object string returned
const protoObjectWordArray = CryptoJS.lib.WordArray.create(grpcObjectString)
const calculatedObjectHash = CryptoJS.SHA256(protoObjectWordArray).toString(CryptoJS.enc.Hex)

// If the grpc object shasum matches, establish the grpc connection.
if (calculatedObjectHash == verifiedProtoSha256Hash.objectSha256) {
// Create the gRPC Connection
qrlClient[endpoint] =
new grpcObject.qrl.PublicAPI(endpoint, grpc.credentials.createInsecure())

console.log(`qrlClient loaded for ${endpoint}`)

callback(null, true)
} else {
// grpc object shasum does not match verified known shasum
// Could be local side attack changing the proto file in between validation
// and grpc connection establishment
console.log(`Invalid qrl.proto grpc object shasum - node version: ${res.version}, qrl.proto object sha256: ${calculatedObjectHash}, expected: ${verifiedProtoSha256Hash.objectSha256}`)
const myError = errorCallback(err, `Invalid qrl.proto shasum - node version: ${res.version}, qrl.proto sha256: ${calculatedObjectHash}, expected: ${verifiedProtoSha256Hash.objectSha256}`, '**ERROR/connect**')
callback(myError, null)
}
} else {
// qrl.proto file shasum does not match verified known shasum
// Could be node acting in bad faith.
console.log(`Invalid qrl.proto shasum - node version: ${res.version}, qrl.proto sha256: ${calculatedProtoHash}, expected: ${verifiedProtoSha256Hash.protoSha256}`)
const myError = errorCallback(err, `Invalid qrl.proto shasum - node version: ${res.version}, qrl.proto sha256: ${calculatedProtoHash}, expected: ${verifiedProtoSha256Hash.protoSha256}`, '**ERROR/connect**')
callback(myError, null)
}
})
})
})
}
})
} catch(err) {
console.log('node connection error exception')
const myError = errorCallback(err, `Cannot access node: ${endpoint}`, '**ERROR/connect**')
callback(myError, null)
}
}

// Establish a connection with a remote node.
Expand Down Expand Up @@ -1057,7 +1115,7 @@ Meteor.methods({
thisTxn = {
type: output.transaction.tx.transactionType,
txhash: arr.txhash,
amount: output.transaction.tx.coinbase.amount,
amount: output.transaction.tx.coinbase.amount / SHOR_PER_QUANTA,
from: output.transaction.explorer.from,
to: output.transaction.tx.coinbase.addr_to,
ots_key: '',
Expand Down
19 changes: 19 additions & 0 deletions imports/ui/pages/tokens/tokenCreate.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,25 @@
</div>
</div>

<div class="small ui modal" id="otsKeyReuseDetected">
<div class="header">OTS Key Reuse</div>
<div class="content">
<div class="ui warning icon message">
<i class="warning icon"></i>
<div class="content">
<div class="header">
You have attempted to create a transaction using an OTS Key Index that has previously been used on the QRL Network.
<br /><br />
Please recreate your transaction using a unique OTS Key Index.
</div>
<p></p>
</div>
</div>
</div>
<div class="actions">
<div class="ui approve green button">Okay</div>
</div>
</div>

<h4 class="ui header pageHeader">
<i class="tags icon"></i>
Expand Down
8 changes: 8 additions & 0 deletions imports/ui/pages/tokens/tokenCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BigNumber } from 'bignumber.js'
/* global SHOR_PER_QUANTA */
/* global wrapMeteorCall */
/* global nodeReturnedValidResponse */
/* global otsIndexUsed */

let countRecipientsForValidation = 1

Expand All @@ -30,6 +31,13 @@ function createTokenTxn() {

let tokenHolders = []

// Fail if OTS Key reuse is detected
if(otsIndexUsed(LocalStore.get('otsBitfield'), otsKey)) {
$('#generating').hide()
$('#otsKeyReuseDetected').modal('show')
return
}

// Convert strings to bytes
const pubKey = hexToBytes(XMSS_OBJECT.getPK())
const symbolBytes = stringToBytes(symbol)
Expand Down
19 changes: 19 additions & 0 deletions imports/ui/pages/tools/message/messageCreate.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@
</div>
</div>

<div class="small ui modal" id="otsKeyReuseDetected">
<div class="header">OTS Key Reuse</div>
<div class="content">
<div class="ui warning icon message">
<i class="warning icon"></i>
<div class="content">
<div class="header">
You have attempted to create a transaction using an OTS Key Index that has previously been used on the QRL Network.
<br /><br />
Please recreate your transaction using a unique OTS Key Index.
</div>
<p></p>
</div>
</div>
</div>
<div class="actions">
<div class="ui approve green button">Okay</div>
</div>
</div>

<h2 class="ui header pageHeader">
<i class="envelope icon"></i>
Expand Down
8 changes: 8 additions & 0 deletions imports/ui/pages/tools/message/messageCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ import './messageCreate.html'
/* global SHOR_PER_QUANTA */
/* global wrapMeteorCall */
/* global nodeReturnedValidResponse */
/* global otsIndexUsed */

function createMessageTxn() {
// Get to/amount details
const userMessage = document.getElementById('message').value
const txnFee = document.getElementById('fee').value
const otsKey = document.getElementById('otsKey').value

// Fail if OTS Key reuse is detected
if(otsIndexUsed(LocalStore.get('otsBitfield'), otsKey)) {
$('#generating').hide()
$('#otsKeyReuseDetected').modal('show')
return
}

// Convert strings to bytes
const pubKey = hexToBytes(XMSS_OBJECT.getPK())
const messageBytes = stringToBytes(userMessage)
Expand Down
Loading

0 comments on commit 4c6ba59

Please sign in to comment.