diff --git a/src/bip39.js b/src/bip39.js index f12f5ec..f5cffeb 100644 --- a/src/bip39.js +++ b/src/bip39.js @@ -1,9 +1,9 @@ -var CryptoJS = require('crypto-js') -var crypto = require('crypto') +var CryptoJS = require('crypto-js'); +var crypto = require('crypto'); function BIP39(language) { - language = language || 'en' + language = language || 'en'; this.wordlist = [ "abandon", "ability", @@ -2057,101 +2057,101 @@ function BIP39(language) { } BIP39.prototype.mnemonicToSeed = function(mnemonic, password) { - var options = {iterations: 2048, hasher: CryptoJS.algo.SHA512, keySize: 512/32} + var options = {iterations: 2048, hasher: CryptoJS.algo.SHA512, keySize: 512/32}; return CryptoJS.PBKDF2(mnemonic, salt(password), options).toString(CryptoJS.enc.Hex) -} +}; BIP39.prototype.entropyToMnemonic = function(entropy) { - var entropyBuffer = new Buffer(entropy, 'hex') - var entropyBits = bytesToBinary([].slice.call(entropyBuffer)) - var checksum = checksumBits(entropyBuffer) + var entropyBuffer = new Buffer(entropy, 'hex'); + var entropyBits = bytesToBinary([].slice.call(entropyBuffer)); + var checksum = checksumBits(entropyBuffer); - var bits = entropyBits + checksum - var chunks = bits.match(/(.{1,11})/g) + var bits = entropyBits + checksum; + var chunks = bits.match(/(.{1,11})/g); var words = chunks.map(function(binary) { - var index = parseInt(binary, 2) + var index = parseInt(binary, 2); return this.wordlist[index] - }, this) + }, this); return words.join(' ') -} +}; BIP39.prototype.mnemonicToHex = function (mnemonic) { - var words = mnemonic.split(' ') + var words = mnemonic.split(' '); - if (words.length % 3 !== 0) return false + if (words.length % 3 !== 0) return false; - var wordlist = this.wordlist + var wordlist = this.wordlist; var belongToList = words.every(function (word) { return wordlist.indexOf(word) > -1 - }) + }); - if (!belongToList) return false + if (!belongToList) return false; // convert word indices to 11 bit binary strings var bits = words.map(function (word) { - var index = wordlist.indexOf(word) + var index = wordlist.indexOf(word); return lpad(index.toString(2), '0', 11) - }).join('') + }).join(''); // split the binary string into ENT/CS - var dividerIndex = Math.floor(bits.length / 33) * 32 - var entropy = bits.slice(0, dividerIndex) - var checksum = bits.slice(dividerIndex) + var dividerIndex = Math.floor(bits.length / 33) * 32; + var entropy = bits.slice(0, dividerIndex); + var checksum = bits.slice(dividerIndex); // calculate the checksum and compare var entropyBytes = entropy.match(/(.{1,8})/g).map(function (bin) { return parseInt(bin, 2) - }) - var entropyBuffer = new Buffer(entropyBytes) + }); + var entropyBuffer = new Buffer(entropyBytes); return entropyBuffer.toString('hex'); -} +}; BIP39.prototype.validate = function(mnemonic) { - var words = mnemonic.split(' ') + var words = mnemonic.split(' '); - if (words.length % 3 !== 0) return false + if (words.length % 3 !== 0) return false; - var wordlist = this.wordlist + var wordlist = this.wordlist; var belongToList = words.every(function(word) { return wordlist.indexOf(word) > -1 - }) + }); - if (!belongToList) return false + if (!belongToList) return false; // convert word indices to 11 bit binary strings var bits = words.map(function(word) { - var index = wordlist.indexOf(word) + var index = wordlist.indexOf(word); return lpad(index.toString(2), '0', 11) - }).join('') + }).join(''); // split the binary string into ENT/CS - var dividerIndex = Math.floor(bits.length / 33) * 32 - var entropy = bits.slice(0, dividerIndex) - var checksum = bits.slice(dividerIndex) + var dividerIndex = Math.floor(bits.length / 33) * 32; + var entropy = bits.slice(0, dividerIndex); + var checksum = bits.slice(dividerIndex); // calculate the checksum and compare var entropyBytes = entropy.match(/(.{1,8})/g).map(function(bin) { return parseInt(bin, 2) - }) - var entropyBuffer = new Buffer(entropyBytes) - var newChecksum = checksumBits(entropyBuffer) + }); + var entropyBuffer = new Buffer(entropyBytes); + var newChecksum = checksumBits(entropyBuffer); return newChecksum === checksum -} +}; function checksumBits(entropyBuffer) { - var hash = crypto.createHash('sha256').update(entropyBuffer).digest() + var hash = crypto.createHash('sha256').update(entropyBuffer).digest(); // Calculated constants from BIP39 - var ENT = entropyBuffer.length * 8 - var CS = ENT / 32 + var ENT = entropyBuffer.length * 8; + var CS = ENT / 32; return bytesToBinary([].slice.call(hash)).slice(0, CS) } @@ -2177,4 +2177,4 @@ function lpad(str, padString, length) { return str; } -module.exports = BIP39 +module.exports = BIP39; diff --git a/src/common.js b/src/common.js index 3636450..019efa7 100644 --- a/src/common.js +++ b/src/common.js @@ -5,7 +5,7 @@ var assert = function(condition, message) { if (!condition) { throw message || "Assertion failed"; } -} +}; //Checks if GUID is valid. Only takes lowercase, non-bracketed GUIDs. var isRealGuid = function(potentialGuidAsString){ @@ -13,10 +13,10 @@ var isRealGuid = function(potentialGuidAsString){ if (typeof potentialGuidAsString != 'string') return false; if (potentialGuidAsString.length==0) return false; - var guidRegex=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/ + var guidRegex=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; var match = potentialGuidAsString.match(guidRegex); return match ? true:false; -} +}; var encrypt = function (valueToEncrypt, passphrase) { assert(valueToEncrypt, "valueToEncrypt invalid"); diff --git a/src/config.js b/src/config.js index cea8c41..570a3b6 100644 --- a/src/config.js +++ b/src/config.js @@ -11,7 +11,7 @@ var config = { port:"1111", basePath:"" } -} +}; config.thisServer.baseUrl=config.thisServer.protocol+'://'+ config.thisServer.hostname+':'+config.thisServer.port+ diff --git a/src/index-mobile.js b/src/index-mobile.js index 4cddf3b..a73a4ed 100644 --- a/src/index-mobile.js +++ b/src/index-mobile.js @@ -3,4 +3,4 @@ module.exports = { API: require('./ninki-api'), Engine: require('./ninki-engine'), UI: require('./ninki-ui-mobile') -} +}; diff --git a/src/index.js b/src/index.js index b8532ed..df00506 100644 --- a/src/index.js +++ b/src/index.js @@ -3,4 +3,4 @@ module.exports = { API: require('./ninki-api'), Engine: require('./ninki-engine'), UI: require('./ninki-ui') -} +}; diff --git a/src/ninki-api.js b/src/ninki-api.js index e0966cf..734ef9d 100644 --- a/src/ninki-api.js +++ b/src/ninki-api.js @@ -1,30 +1,29 @@ -var jQuery = require('jquery-browserify'); -var $ = require('jquery-browserify'); var sanitizer = require('sanitizer'); var common = require('./common'); var config = require('./config'); +var localStorage = require('browser-storage'); +var crypto = require('crypto'); + + function API() { } -//Implementing the GET and POST JQuery functions in a Node style. +var apiToken = ""; -var CSRF_HEADER = 'X-CSRF-Token'; +API.registerToken = function registerToken(token) { -var setCSRFToken = function (securityToken) { - jQuery.ajaxPrefilter(function (options, _, xhr) { - if (!xhr.crossDomain) - xhr.setRequestHeader(CSRF_HEADER, securityToken); - }); -}; + apiToken = token; + +} -//setCSRFToken($('meta[name="token"]').attr('content')); API.get = function (url, querydata, callback) { return this.get(url, querydata, callback); -} +}; + function get(url, querydata, callback) { @@ -40,21 +39,118 @@ function get(url, querydata, callback) { }); } + API.post = function (url, postData, callback) { return lpost(url, postData, callback); -} +}; function lpost(url, postData, callback) { - var sessionToken = $('#API-Token').val(); - // + if (typeof window === 'undefined') { // Running in NodeJS + + var tunnel = require('tunnel'); + var querystring = require('querystring'); + + var tunnelingAgent = tunnel.httpsOverHttp({ + proxy: { + host: '', + port: '' + } + }); + + + } + + if (typeof window === 'undefined') { + + //call node + var data = querystring.stringify(postData); + + var https = require('https'); + + var options = { + host: 'testnet.ninkip2p.com', + port: 443, + //agent: tunnelingAgent, + path: url, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': Buffer.byteLength(data), + 'api-token': apiToken + } + }; + + var req = https.request(options, function (res) { + + var body = ''; + + + res.on('data', function (chunk) { + + body += chunk; + + }); + + res.on('end', function () { + + body = sanitizer.sanitize(body); + + //console.log(body) + try { + body = JSON.parse(body); + body = JSON.parse(body); + } catch (err) { + console.log(err) + } + + if ((typeof body === "string")) { + return callback(true, body); + } + + + if (body.error) { + return callback(true, body.message); + } + if (!(typeof body.message === "undefined")) { + return callback(false, body.message); + } + + return callback(false, JSON.stringify(body)); + + + }); + + req.on('error', function (e) { + + console.log('problem with request: ' + e.message); + + }); + + }); + + req.write(data); + + req.end(); + + + + } else { + + + + //https://10.0.1.42:1111 + + //https://testnet.ninkip2p.com:443 + $.ajax({ url: "https://api.ninkip2p.com:443" + url, type: "POST", + timeout: 10000, data: JSON.stringify(postData), contentType: "application/json; charset=utf-8", dataType: "json", - headers: { 'api-token': sessionToken }, + headers: { 'api-token': apiToken }, success: function (data) { data = sanitizer.sanitize(data); @@ -65,8 +161,11 @@ function lpost(url, postData, callback) { return callback(true, jdata.message); } if (!(typeof jdata.message === "undefined")) { + return callback(false, jdata.message); + } + return callback(false, JSON.stringify(jdata)); }, fail: function (data, textStatus) { @@ -81,6 +180,12 @@ function lpost(url, postData, callback) { }, error: function (data) { + if (data.statusText == "timeout") { + + return callback(true, "Could not connect."); + + } + if (data.status == 403) { //session has been lost @@ -117,6 +222,8 @@ function lpost(url, postData, callback) { } }); + + } } @@ -130,7 +237,7 @@ API.emailGUID = function (userName, callback) { }); -} +}; @@ -159,7 +266,7 @@ API.getMasterPublicKeyFromUpstreamServer = function (guid, callback) { } } }); -} +}; //function doesUsernameExist //verifies that the requested username does not already exist on our database @@ -174,7 +281,7 @@ API.doesAccountExist = function (username, email, callback) { return callback(null, JSON.parse(response)); } }); -} +}; API.sendWelcomeDetails = function (guid, sharedid, callback) { @@ -184,7 +291,7 @@ API.sendWelcomeDetails = function (guid, sharedid, callback) { lpost("/api/1/sendwelcomedetails", postData, function (err, response) { return callback(err, response); }); -} +}; API.getEmailValidation = function (guid, sharedid, token, callback) { @@ -200,7 +307,7 @@ API.getEmailValidation = function (guid, sharedid, token, callback) { }); -} +}; API.getResetToken = function (guid, callback) { @@ -211,7 +318,7 @@ API.getResetToken = function (guid, callback) { callback(err, response); }); -} +}; API.validateSecret = function (guid, secret, callback) { @@ -226,7 +333,7 @@ API.validateSecret = function (guid, secret, callback) { return callback(err, data); } }); -} +}; API.updateSecretPacket = function (guid, sharedid, vc, iv, callback) { @@ -234,7 +341,7 @@ API.updateSecretPacket = function (guid, sharedid, vc, iv, callback) { return lpost("/api/1/u/updatesecretpacket", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.unlockaccount = function (guid, token, callback) { @@ -242,7 +349,7 @@ API.unlockaccount = function (guid, token, callback) { return lpost("/api/1/u/unlockaccount", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getWalletFromServer = function (guid, secret, twoFactorCode, rememberTwoFactor, callback) { @@ -254,20 +361,13 @@ API.getWalletFromServer = function (guid, secret, twoFactorCode, rememberTwoFact return callback(err, dataStr); } else { var data = JSON.parse(dataStr); - var currentToken = $("#API-Token").val(); - //if (currentToken.length == 0) { - if (data.SessionToken) { - $("#API-Token").val(data.SessionToken); - } else { - $("#API-Token").val(''); - } - //} + apiToken = data.SessionToken; return callback(err, data); } }); -} +}; //function getBalance gets the summary balance for all the account's outputs @@ -281,7 +381,7 @@ API.getBalance = function (guid, sharedid, callback) { return callback(err, data); } }); -} +}; //function getBalance gets the summary balance for all the account's outputs @@ -296,14 +396,14 @@ API.getusernetworkcategory = function (callback) { return callback(err, data); } }); -} +}; API.updateusernetworkcategory = function (guid, sharedid, username, category, callback) { var postData = { guid: guid, sharedid: sharedid, username: username, category: category }; return lpost("/api/1/updateusernetworkcategory", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; @@ -314,7 +414,7 @@ API.getUnconfirmedBalance = function (guid, sharedid, callback) { return lpost("/api/1/u/getunconfirmedbalance", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; //function for increased performance on login API.getAccountData = function (guid, sharedid, callback) { @@ -322,14 +422,14 @@ API.getAccountData = function (guid, sharedid, callback) { return lpost("/api/1/u/getaccountdata", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getUserData = function (guid, sharedid, callback) { var postData = { guid: guid, sharedid: sharedid }; return lpost("/api/1/u/getuserdata", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; //gets the username associated with the wallet @@ -338,21 +438,21 @@ API.getNickname = function (guid, sharedid, callback) { return lpost("/api/1/u/getnickname", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getUserProfile = function (guid, sharedid, callback) { var postData = { guid: guid, sharedid: sharedid }; return lpost("/api/1/u/getuserprofile", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.updateUserProfile = function (guid, sharedid, profileImage, status, tax, callback) { var postData = { guid: guid, sharedid: sharedid, profileImage: profileImage, status: status, tax: tax }; return lpost("/api/1/u/updateuserprofile", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; //function returns all outputs unspent by the wallet @@ -367,7 +467,7 @@ API.getUnspentOutputs = function (guid, sharedid, callback) { return callback(err, response); } }); -} +}; //function returns all outputs unspent by the wallet API.getCoinProfile = function (guid, sharedid, callback) { @@ -381,7 +481,7 @@ API.getCoinProfile = function (guid, sharedid, callback) { return callback(err, response); } }); -} +}; API.getPrice = function (guid, ccy, callback) { @@ -394,7 +494,7 @@ API.getPrice = function (guid, ccy, callback) { return callback(err, response); } }); -} +}; API.getPendingUserRequests = function (guid, sharedid, callback) { @@ -408,7 +508,7 @@ API.getPendingUserRequests = function (guid, sharedid, callback) { return callback(err, data); } }); -} +}; API.getFriendRequests = function (guid, sharedid, callback) { @@ -421,7 +521,7 @@ API.getFriendRequests = function (guid, sharedid, callback) { return callback(err, dataStr); } }); -} +}; API.getUserPacket = function (guid, sharedid, callback) { @@ -434,7 +534,7 @@ API.getUserPacket = function (guid, sharedid, callback) { return callback(err, dataStr); } }); -} +}; API.isNetworkExist = function (guid, sharedid, username, callback) { var postData = { guid: guid, sharedid: sharedid, username: username }; @@ -447,14 +547,14 @@ API.isNetworkExist = function (guid, sharedid, username, callback) { } }); -} +}; API.rejectFriendRequest = function (guid, sharedid, username, callback) { var postData = { guid: guid, sharedid: sharedid, username: username }; lpost("/api/1/u/rejectfriend", postData, function (err, result) { return callback(err, result); }); -} +}; API.getTransactionRecords = function (guid, sharedid, callback) { @@ -471,7 +571,7 @@ API.getTransactionRecords = function (guid, sharedid, callback) { }); -} +}; API.getInvoiceList = function (guid, sharedid, callback) { @@ -489,7 +589,7 @@ API.getInvoiceList = function (guid, sharedid, callback) { }); -} +}; API.getInvoiceByUserList = function (guid, sharedid, callback) { @@ -506,7 +606,7 @@ API.getInvoiceByUserList = function (guid, sharedid, callback) { }); -} +}; @@ -515,42 +615,42 @@ API.updateInvoice = function (guid, sharedid, username, invoiceId, transactionId return lpost("/api/1/u/updateinvoice", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getVersion = function (callback) { var postData = {}; return lpost("/api/1/u/getversion", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.registerDevice = function (guid, deviceName, deviceId, deviceModel, devicePIN, regToken, secret, callback) { var postData = { guid: guid, deviceName: deviceName, deviceId: deviceId, deviceModel: deviceModel, devicePIN: devicePIN, regToken: regToken, secret: secret }; return lpost("/api/1/u/registerdevice", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getDeviceKey = function (guid, devicePIN, regToken, callback) { var postData = { guid: guid, devicePIN: devicePIN, regToken: regToken }; return lpost("/api/1/u/getdevicekey", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.destroyDevice = function (guid, regToken, callback) { var postData = { guid: guid, regToken: regToken }; return lpost("/api/1/u/destroydevice", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.destroyDevice2fa = function (guid, sharedid, deviceName, twoFactorCode, callback) { var postData = { guid: guid, sharedid: sharedid, deviceName: deviceName, twoFactorCode: twoFactorCode }; return lpost("/api/1/u/destroydevice2fa", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; @@ -559,7 +659,7 @@ API.createDevice = function (guid, sharedid, deviceName, callback) { return lpost("/api/1/u/createdevice", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; API.getDevices = function (guid, sharedid, callback) { @@ -572,14 +672,14 @@ API.getDevices = function (guid, sharedid, callback) { return callback(err, dataStr); } }); -} +}; API.getDeviceToken = function (guid, sharedid, deviceName, twoFactorCode, callback) { var postData = { guid: guid, sharedid: sharedid, deviceName: deviceName, twoFactorCode: twoFactorCode }; return lpost("/api/1/u/getdevicetoken", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; @@ -588,6 +688,21 @@ API.getRecoveryPacket = function (guid, callback) { return lpost("/api/1/getrecoverypacket", postData, function (err, dataStr) { return callback(err, dataStr); }); -} +}; + +API.getLimitStatus = function (guid, sharedid, callback) { + var postData = { guid: guid, sharedid: sharedid }; + return lpost("/api/1/u/getlimitstatus", postData, function (err, dataStr) { + return callback(err, dataStr); + }); +}; + +API.createBackupCodes = function (guid, sharedid, twoFactorCode, callback) { + var postData = { guid: guid, sharedid: sharedid, twoFactorCode: twoFactorCode }; + return lpost("/api/1/u/createbackupcodes", postData, function (err, dataStr) { + return callback(err, dataStr); + }); +}; + module.exports = API; \ No newline at end of file diff --git a/src/ninki-device.js b/src/ninki-device.js new file mode 100644 index 0000000..d2e8411 --- /dev/null +++ b/src/ninki-device.js @@ -0,0 +1,159 @@ +var localStorage = require('browser-storage'); + +function Device() { + + + this.isChromeApp = isChromeApp; + function isChromeApp() { + + + if (typeof window === 'undefined') { + + return false; + + } + + if (isCordova()) { + return false; + } + + var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; + if (is_chrome) { + if (chrome) { + if (chrome.app) { + if (chrome.app.runtime) { + return true; + } + } + } + } + return false; + } + + this.isNode = isNode; + function isNode() { + + if (typeof window === 'undefined') { + + return true; + + } else { + return false; + } + + } + + this.isCordova = isCordova; + function isCordova() { + + if (typeof window === 'undefined') { + return false; + } else { + if (typeof window.cordova === 'undefined') { + return false; + } + else { + return true; + } + } + + } + + this.isBrowser = isBrowser; + function isBrowser() { + + if (typeof window === 'undefined') { + + return false; + + } else { + + if (typeof window.cordova === 'undefined') { + + return true; + + } else { + + return false; + } + + } + + } + + this.getStorageItem = getStorageItem; + function getStorageItem(cname, callback) { + + + if (isChromeApp()) { + + chrome.storage.local.get(cname, function (result) { + + if (result[cname]) { + result = result[cname]; + } else { + result = ""; + } + + return callback(result); + + }); + + } else { + + if (localStorage.getItem(cname)) { + return callback(localStorage.getItem(cname)); + } else { + return callback(''); + } + + } + + } + + this.setStorageItem = setStorageItem; + function setStorageItem(cname, cvalue) { + + + if (isChromeApp()) { + + var obj = {}; + obj[cname] = cvalue; + chrome.storage.local.set(obj, function () { + + console.log("saved"); + + }); + + } + else { + + localStorage.setItem(cname, cvalue); + + } + + + } + + this.deleteStorageItem = deleteStorageItem; + function deleteStorageItem(cname) { + + + if (isChromeApp()) { + + chrome.storage.local.remove(cname, function () { + + console.log("deleted"); + + }); + + } else { + + localStorage.removeItem(cname); + + } + } + +} + +module.exports = Device; diff --git a/src/ninki-engine.js b/src/ninki-engine.js index e7cba68..3b850bb 100644 --- a/src/ninki-engine.js +++ b/src/ninki-engine.js @@ -4,14 +4,16 @@ var Bitcoin = require('bitcoinjs-lib'); var openpgp = require('openpgp'); var CryptoJS = require('crypto-js'); var API = require('./ninki-api'); +var device = require('./ninki-device'); var BIP39 = require('./bip39'); var uuid = require('node-uuid'); var sjcl = require('sjcl'); var sanitizer = require('sanitizer'); - +var crypto = require('crypto'); function Engine() { + this.m_network = "mainnet"; this.m_walletinfo = {}; this.m_sharedid = ''; this.m_twoFactorOnLogin = false; @@ -33,74 +35,31 @@ function Engine() { this.m_appInitialised = false; this.m_watchOnly = false; - m_this = this; - - - this.appHasLoaded = appHasLoaded; - function appHasLoaded() { - // m_this.m_password = ''; + m_this = this; - } + this.Device = new device(); - function isChromeApp() { + this.appHasInit = appHasInit; + function appHasInit() { - if (window.cordova) { + if (m_this.m_sharedid.length > 0) { + return true; + } else { return false; } - var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; - if (is_chrome) { - if (chrome) { - if (chrome.app) { - if (chrome.app.runtime) { - return true; - } - } - } - } - return false; } - function isBrowser() { + this.appHasLoaded = appHasLoaded; + function appHasLoaded() { - if (window.cordova) { - return false; - } + // m_this.m_password = ''; - return !isChromeApp(); } - function getCookie(cname, callback) { - - - if (isChromeApp()) { - - chrome.storage.local.get(cname, function (result) { - - if (result[cname]) { - result = result[cname]; - } else { - result = ""; - } - - return callback(result); - - }); - - } else { - - if (localStorage[cname]) { - return callback(localStorage[cname]); - } else { - return callback(''); - } - - } - - } this.isRealGuid = isRealGuid; //Checks if GUID is valid. Only takes lowercase, non-bracketed GUIDs. @@ -110,7 +69,7 @@ function Engine() { if (typeof potentialGuidAsString != 'string') return false; if (potentialGuidAsString.length == 0) return false; - var guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/ + var guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; var match = potentialGuidAsString.match(guidRegex); return match ? true : false; } @@ -130,6 +89,32 @@ function Engine() { } + function getRandomValues(b) { + + var rng = new Uint8Array(b); + if (typeof window === 'undefined') { + + try { + var buf = crypto.randomBytes(256); + + rng = new Uint8Array(buf); + + } catch (ex) { + // handle error + // most likely, entropy sources are drained + + console.log(ex); + } + + } else { + + window.crypto.getRandomValues(rng); + } + + return rng; + } + + this.encrypt = encrypt; function encrypt(valueToEncrypt, passphrase) { @@ -137,9 +122,9 @@ function Engine() { var key = CryptoJS.enc.Hex.parse(passphrase); - var iv = new Uint8Array(32); + var iv = getRandomValues(32); + var ivbytes = []; - window.crypto.getRandomValues(iv); for (var i = 0; i < iv.length; ++i) { ivbytes[i] = iv[i]; } @@ -159,9 +144,10 @@ function Engine() { var key = CryptoJS.enc.Hex.parse(passphrase); - var iv = new Uint8Array(32); + var iv = getRandomValues(32); + + var ivbytes = []; - window.crypto.getRandomValues(iv); for (var i = 0; i < iv.length; ++i) { ivbytes[i] = iv[i]; } @@ -198,7 +184,6 @@ function Engine() { return decrypthex; }; - var hmac = function (key) { var hasher = new sjcl.misc.hmac(key, sjcl.hash.sha1); this.encrypt = function () { @@ -228,40 +213,32 @@ function Engine() { this.getEncHotHash = getEncHotHash; function getEncHotHash(callback) { - var isWeb = isBrowser(); - if (isChromeApp()) { + m_this.Device.getStorageItem("hk" + m_this.m_guid, function (hk) { - chrome.storage.local.get("hk" + m_this.m_guid, function (result) { - - if (result["hk" + m_this.m_guid]) { + if (hk) { - var hk = result["hk" + m_this.m_guid]; + m_this.Device.getStorageItem("hkiv" + m_this.m_guid, function (hkiv) { - chrome.storage.local.get("hkiv" + m_this.m_guid, function (resultiv) { + if (hkiv) { - if (resultiv["hkiv" + m_this.m_guid]) { + var data = "{\"enc\":\"" + hk + "\", \"iv\":\"" + hkiv + "\"}"; - var hkiv = resultiv["hkiv" + m_this.m_guid]; + return callback(false, data); - var data = "{\"enc\":\"" + hk + "\", \"iv\":\"" + hkiv + "\"}"; - return callback(false, data); - } else { - return callback(true, "ErrMissing"); - } + } else { - }); + return callback(true, "ErrMissing"); + } - } else { - return callback(true, "ErrMissing"); - } + }); - }); + } else { - } else { + return callback(true, "ErrMissing"); - return callback(true, "ErrInvalid"); - } + } + }); } @@ -271,12 +248,10 @@ function Engine() { function restoreHotHash(hothash, callback) { - - //validate against loaded hot public key var validseed = true; try { - var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash); + var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash, m_this.m_network); if (m_this.m_walletinfo.hotPub != bipHot.toString()) { validseed = false; } @@ -304,186 +279,135 @@ function Engine() { } - - } this.getHotHash = getHotHash; function getHotHash(key, callback) { - var isWeb = isBrowser(); //to do: validate key against stored public key //needs to be done incase user changed their password on a different machine - if (isChromeApp()) { - - chrome.storage.local.get("hk" + m_this.m_guid, function (result) { - - if (result["hk" + m_this.m_guid]) { - var hk = result["hk" + m_this.m_guid]; - - chrome.storage.local.get("hkiv" + m_this.m_guid, function (resultiv) { - - if (resultiv["hkiv" + m_this.m_guid]) { - var hkiv = resultiv["hkiv" + m_this.m_guid]; - var hothash = ''; - var iserror = false; - try { - hothash = decryptNp(hk, m_this.m_password, hkiv); - } catch (error) { - iserror = true; - } - if (!iserror) { - - //validate against loaded hot public key - var validseed = true; - try { - var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash); - if (m_this.m_walletinfo.hotPub != bipHot.toString()) { - validseed = false; - } - } catch (error) { + if (m_this.Device.isChromeApp() || m_this.Device.isBrowser() || m_this.Device.isNode()) { - validseed = false; - } + m_this.Device.getStorageItem("hk" + m_this.m_guid, function (result) { - if (validseed) { + var hk = result; - return callback(false, hothash); + m_this.Device.getStorageItem("hkiv" + m_this.m_guid, function (resultiv) { - } else { + var hkiv = resultiv - return callback(true, "invalid"); + var hothash = ''; - } + var iserror = false; + try { + hothash = decryptNp(hk, m_this.m_password, hkiv); + } catch (error) { + iserror = true; + } - } else { + if (!iserror) { - return callback(true, "missing"); + //validate against loaded hot public key + var validseed = true; + try { + var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash, m_this.m_network); + if (m_this.m_walletinfo.hotPub != bipHot.toString()) { + validseed = false; } + } catch (error) { - } else { - - return callback(true, "missing"); + validseed = false; } - }); - - } else { - return callback(true, "missing"); - } - - }); - - } else if (isWeb) { + if (validseed) { - var hk = localStorage["hk" + m_this.m_guid]; - var hkiv = localStorage["hkiv" + m_this.m_guid]; + return callback(false, hothash); - var hothash = ''; - var iserror = false; - try { - hothash = decryptNp(hk, m_this.m_password, hkiv); - } catch (error) { - iserror = true; - } - if (!iserror) { + } else { - //validate against loaded hot public key - var validseed = true; - try { - var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash); - if (m_this.m_walletinfo.hotPub != bipHot.toString()) { - validseed = false; - } - } catch (error) { + return callback(true, "invalid"); - validseed = false; - } + } - if (validseed) { - return callback(false, hothash); + } else { - } else { + return callback(true, "missing"); + } - return callback(true, "invalid"); + }); - } - } else { - return callback(true, "missing"); - } + }); } else { - //not using the chrome app so must be mobile - - //use html5 localstorage + m_this.Device.getStorageItem("ninki_h", function (hk) { - // localStorage - var hk = localStorage["ninki_h"]; + if (hk) { + var hothash = ''; + var iserror = false; + try { - if (hk) { - - var hothash = ''; - var iserror = false; - try { + var enc = JSON.parse(hk); + hothash = decryptNp(enc.ct, key, enc.iv); - var enc = JSON.parse(hk); - hothash = decryptNp(enc.ct, key, enc.iv); + } catch (error) { + iserror = true; + } + if (!iserror) { - } catch (error) { - iserror = true; - } - if (!iserror) { + //validate against loaded hot public key + var validseed = true; + try { + var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash, m_this.m_network); + if (m_this.m_walletinfo.hotPub != bipHot.toString()) { + validseed = false; + } + } catch (error) { - //validate against loaded hot public key - var validseed = true; - try { - var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash); - if (m_this.m_walletinfo.hotPub != bipHot.toString()) { validseed = false; } - } catch (error) { - validseed = false; - } + if (validseed) { + + //get the two factor code also - if (validseed) { + m_this.Device.getStorageItem("ninki_rem", function (tft) { + var jtft = JSON.parse(tft); - //get the two factor code also + var fatoken = decryptNp(jtft.ct, key, jtft.iv); - var tft = localStorage["ninki_rem"]; - var jtft = JSON.parse(tft); + return callback(false, hothash, fatoken); - var fatoken = decryptNp(jtft.ct, key, jtft.iv); + }); + + } else { - return callback(false, hothash, fatoken); + return callback(true, "invalid"); - } else { + } - return callback(true, "invalid"); + } else { + return callback(true, "missing"); } } else { return callback(true, "missing"); - } - - } else { - return callback(true, "missing"); + } - } + }); } @@ -492,45 +416,25 @@ function Engine() { this.saveHotHash = saveHotHash; function saveHotHash(hotHash, callback) { - //before we encrypt validate the hash matches the logged in public key var validseed = true; try { - var bipHot = Bitcoin.HDWallet.fromSeedHex(hotHash); + var bipHot = Bitcoin.HDWallet.fromSeedHex(hotHash, m_this.m_network); if (m_this.m_walletinfo.hotPub != bipHot.toString()) { validseed = false; } } catch (error) { - validseed = false; } if (validseed) { var encHotHash = encryptNp(hotHash, m_this.m_password); - var objhk = {}; - - if (isChromeApp()) { - objhk['hk' + m_this.m_guid] = encHotHash.toString(); - chrome.storage.local.set(objhk, function () { - //console.log("saved"); - var objhkiv = {}; - objhkiv['hkiv' + m_this.m_guid] = encHotHash.iv.toString(); - chrome.storage.local.set(objhkiv, function () { - //console.log("saved"); - callback(false, "ok"); - }); - }); - } else { - - - localStorage.setItem('hk' + m_this.m_guid, encHotHash.toString()); - localStorage.setItem('hkiv' + m_this.m_guid, encHotHash.iv.toString()); - - callback(false, "ok"); - } + m_this.Device.setStorageItem('hk' + m_this.m_guid, encHotHash.toString()); + m_this.Device.setStorageItem('hkiv' + m_this.m_guid, encHotHash.iv.toString()); + callback(false, "ok"); } else { @@ -554,11 +458,6 @@ function Engine() { } - // createprog - // textMessageCreate - // createprogstatus - - //create wallet //create a new wallet and save to the server this.createWallet = createWallet; @@ -589,7 +488,7 @@ function Engine() { } else { - $('#textMessageCreate').text('stretching password...'); + //$('#textMessageCreate').text('stretching password...'); setTimeout(function () { @@ -623,7 +522,7 @@ function Engine() { walletInformation.wallet.recPacketIV = recpacket.iv.toString(); //save the wallet to the server - $('#textMessageCreate').text('saving data...'); + //$('#textMessageCreate').text('saving data...'); setTimeout(function () { @@ -662,7 +561,7 @@ function Engine() { //rename this function setTimeout(function () { - $('#textMessageCreate').text('creating account...'); + //$('#textMessageCreate').text('creating account...'); API.getMasterPublicKeyFromUpstreamServer(m_this.m_oguid, function (err, ninkiPubKey, userToken, secret) { if (err) { @@ -670,7 +569,7 @@ function Engine() { } else { makeNewWalletPacket(nickname, email, ninkiPubKey, userToken, secret, function (err, walletInformation) { if (err) { - return callback(err, response); + return callback(err, walletInformation); } else { return callback(err, walletInformation, userToken); } @@ -684,15 +583,14 @@ function Engine() { function makeNewWalletPacket(nickname, emailAddress, ninkiPubKey, userToken, secret, callback) { - var network = "mainnet"; + //$('#textMessageCreate').text('getting entropy...'); + setTimeout(function () { - $('#textMessageCreate').text('getting entropy...'); - setTimeout(function () { - //get some random data for the cold key - var rngcold = new Uint8Array(32); - window.crypto.getRandomValues(rngcold); + //what to do if running in node + // crypto provider module + var rngcold = getRandomValues(32); var coldKeyBytes = []; for (var i = 0; i < rngcold.length; ++i) { @@ -700,8 +598,7 @@ function Engine() { } //get some random data for the hot key - var rnghot = new Uint8Array(32); - window.crypto.getRandomValues(rnghot); + var rnghot = getRandomValues(32); var hotKeyBytes = []; for (var i = 0; i < rnghot.length; ++i) { @@ -714,7 +611,7 @@ function Engine() { //var seedtest = bip39.mnemonicToSeed(hotmnem, ''); - $('#textMessageCreate').text('creating cold keys...'); + //$('#textMessageCreate').text('creating cold keys...'); setTimeout(function () { @@ -722,12 +619,12 @@ function Engine() { //Cold key space var coldHash = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(coldKeyBytes)).toString(); - var coldWallet = Bitcoin.HDWallet.fromSeedHex(coldHash); + var coldWallet = Bitcoin.HDWallet.fromSeedHex(coldHash, m_this.m_network); //get the keys as strings var coldPriv = coldWallet.toString(" "); var coldPub = coldWallet.toString(); - $('#textMessageCreate').text('creating hot keys...'); + //$('#textMessageCreate').text('creating hot keys...'); setTimeout(function () { @@ -736,7 +633,7 @@ function Engine() { //Hot key space var hotHash = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(hotKeyBytes)).toString(); - var hotWallet = Bitcoin.HDWallet.fromSeedHex(hotHash); + var hotWallet = Bitcoin.HDWallet.fromSeedHex(hotHash, m_this.m_network); //get the keys as strings var hotPriv = hotWallet.toString(" "); var hotPub = hotWallet.toString(); @@ -750,7 +647,7 @@ function Engine() { var hcbkey = Bitcoin.convert.hexToBytes(hckey); var hchkey = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(hcbkey)).toString(); - $('#textMessageCreate').text('creating pgp keys...'); + //$('#textMessageCreate').text('creating pgp keys...'); setTimeout(function () { @@ -767,7 +664,7 @@ function Engine() { setTimeout(function () { - $('#textMessageCreate').text('encrypting data...'); + //$('#textMessageCreate').text('encrypting data...'); //save the wallet keys and user token in an encrypted packet //AES256 using PBKDF2 on the password and a unique salt @@ -844,7 +741,7 @@ function Engine() { hotWalletPhrase: bip39.entropyToMnemonic(hotHash), sharedid: userToken, hckey: hchkey - } + }; //console.log(coldHash, hotHash); @@ -945,7 +842,13 @@ function Engine() { var packet = encrypt(walletInformation, m_this.m_password); //now save the packet back to the server - var postData = { twoFactorCode: twoFactCode, guid: m_this.m_guid, sharedid: walletInformation.userToken, accountPacket: packet.toString(), IVA: packet.iv.toString() }; + var postData = { + twoFactorCode: twoFactCode, + guid: m_this.m_guid, + sharedid: walletInformation.userToken, + accountPacket: packet.toString(), + IVA: packet.iv.toString() + }; API.post("/api/1/u/migratepacket", postData, function (err, dataStr) { return callback(false, "ok"); @@ -1077,7 +980,6 @@ function Engine() { }); - } @@ -1175,7 +1077,7 @@ function Engine() { //walletInformation.hotHash = ''; //walletInformation.hchkey = ''; - + m_this.m_APIToken = wallet.SessionToken; m_this.m_twoFactorOnLogin = wallet.TwoFactorOnLogin; m_this.m_walletinfo = walletInformation; m_this.m_sharedid = walletInformation.userToken; @@ -1192,6 +1094,10 @@ function Engine() { } else { + m_this.m_settings = {}; + m_this.m_settings.BackupIndex = secvalid.BackupIndex; + m_this.m_settings.HasBackupCodes = secvalid.HasBackupCodes; + //is a migrated account with 2fa enabled //return to get the user to enter the 2fa code return callback(err, secvalid); @@ -1365,7 +1271,6 @@ function Engine() { } - function deriveChild(path, hdwallet) { var e = path.split('/'); @@ -1394,8 +1299,6 @@ function Engine() { } - - //function aMultiSigHashForSigning //TODO: rename function aMultiSigHashForSigning3(publickey1, publickey2, publickey3, index, outputsToSpend, outputsToSend, addressToSend) { @@ -1561,35 +1464,96 @@ function Engine() { return addrValid; } - this.sendTransaction = sendTransaction; - function sendTransaction(sendType, friendUserName, addressTo, amount, twoFactorCode, callback) { + var corNodesDone = 0; + var corNodesToProcess = 0; + function deriveKeys(mpk, nodes, cdcallback) { - //setup handles to report back progress - var progressel = ''; - var messel = ''; - var progresselnum = '' + if (m_this.Device.isCordova()) { - if (sendType == 'friend') { - messel = '#textMessageSend'; - progressel = '#sendfriendprogstatus'; - progresselnum = '#sendstdprognum'; - } + var mkpder = []; + + corNodesToProcess = nodes.length; + cordovaDeriveKey(mpk, nodes, mkpder, function (result) { + + console.log(mkpder); + + return cdcallback(mkpder); + + }); + } else { + + var ret = []; + for (var i = 0; i < nodes.length; i++) { + ret.push(deriveChild(nodes[i], mpk).priv); + } + return cdcallback(ret); - if (sendType == 'standard') { - messel = '#textMessageSendStd'; - progressel = '#sendstdprogstatus'; - progresselnum = '#sendstdprognum'; } - if (sendType == 'invoice') { - messel = '#textMessageSendInv'; - progressel = '#sendinvprogstatus'; - progresselnum = '#sendstdprognum'; + } + + function cordovaDeriveKey(mpk, nodes, mkpder, derfinished) { + + console.log("entered cordoveDeriveKey..."); + console.log(mkpder); + + if (corNodesDone == corNodesToProcess) { + + console.log("returning..."); + return derfinished(mkpder) + + } else { + + + var nls = nodes[corNodesDone].split("/"); + var tnode = nls[2] * 1; + var leaf = nls[3] * 1; + + + console.log("calling exec..."); + + cordova.exec( + function callback(data) { + + + corNodesDone++; + + console.log("pushing data..."); + + mkpder.push(data); + + console.log(mkpder); + + console.log("key added..."); + + cordovaDeriveKey(mpk, nodes, mkpder, derfinished); + + + }, + function errorHandler(err) { + //alert('Error'); + console.log("error"); + }, + 'ECPlugin', + 'cordovaECDerKey', + [mpk.toString(" "), tnode, leaf] + ); } + + } + + + this.sendTransaction = sendTransaction; + function sendTransaction(sendType, friendUserName, addressTo, amount, twoFactorCode, callback, statuscallback) { + + var debug = true; + var debugtime = 5; + corNodesDone = 0; + corNodesToProcess = 0; var minersFee = 10000; - //?? + amount = Math.round(amount); if (m_this.m_settings.MinersFee) { @@ -1600,16 +1564,23 @@ function Engine() { //in the case of mobile the twoFactorCode is actually the device key //and will return a twofactor override code + + getHotHash(twoFactorCode, function (err, hothash, twoFactorOverride) { if (twoFactorOverride) { twoFactorCode = twoFactorOverride; } + + + //initialise the hot private key space - var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash); + var bipHot = Bitcoin.HDWallet.fromSeedHex(hothash, m_this.m_network); + + // + - //initialise the 3 public keys var bipHotPub = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.hotPub); var bipCold = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.coldPub); var bipNinki = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.ninkiPubKey); @@ -1617,15 +1588,19 @@ function Engine() { var pdata = { guid: m_this.m_guid, sharedid: m_this.m_sharedid }; - - $(messel).text('Getting unspent outputs...'); - + statuscallback('Preparing transaction...', '10%'); API.post("/api/1/u/getunspentoutputs", pdata, function (err, outputs) { if (!err) { + + if (debug) { + console.log('getunspentoutputs...success'); + } + + var outputs = JSON.parse(outputs); var outputsToSpend = []; var amountsToSend = []; @@ -1634,14 +1609,18 @@ function Engine() { var nodeLevels = []; var publicKeys = []; - var packet = { addressToSend: addressToSend, amountsToSend: amountsToSend, outputsToSpend: outputsToSpend, userHotPrivKeys: userHotPrivKeys, guid: m_this.m_guid, paths: nodeLevels, publicKeys: publicKeys }; + var packet = { + addressToSend: addressToSend, + amountsToSend: amountsToSend, + outputsToSpend: outputsToSpend, + userHotPrivKeys: userHotPrivKeys, + guid: m_this.m_guid, + paths: nodeLevels, + publicKeys: publicKeys + }; //get outputs to spend, calculate change amount minus miners fee - $(progressel).width('20%'); - if ($(progresselnum)) { - $(progresselnum).text('20%'); - } //iterate the unspent outputs and select the first n that equal the amount to spend //TO DO: do this before doing any key derivation @@ -1649,14 +1628,23 @@ function Engine() { for (var i = 0; i < outputs.length; i++) { var pitem = outputs[i]; - var pout = { transactionId: pitem.TransactionId, outputIndex: pitem.OutputIndex, amount: pitem.Amount, address: pitem.Address } + var pout = { + transactionId: pitem.TransactionId, + outputIndex: pitem.OutputIndex, + amount: pitem.Amount, + address: pitem.Address + }; nodeLevels.push(pitem.NodeLevel); outputsToSpend.push(pout); //derive the private key to use for signing - userHotPrivKeys.push(deriveChild(pitem.NodeLevel, bipHot).priv); + + if (debug) { + console.log('derive the private key to use for signing ' + i); + } + //derive the public keys to use for script generation //this could be cached on the server as no privacy or hand-off issue that I can see @@ -1665,14 +1653,23 @@ function Engine() { var dbipColdPub = ""; var dbipNinkiPub = ""; + if (pitem.PK1.length > 0) { + if (debug) { + console.log('using cached public key ' + i); + } + dbipHotPub = Bitcoin.convert.hexToBytes(pitem.PK1); dbipColdPub = Bitcoin.convert.hexToBytes(pitem.PK2); dbipNinkiPub = Bitcoin.convert.hexToBytes(pitem.PK3); } else { + if (debug) { + console.log('no cache - deriving ' + i); + } + dbipHotPub = deriveChild(pitem.NodeLevel, bipHotPub).pub.toBytes(); dbipColdPub = deriveChild(pitem.NodeLevel, bipCold).pub.toBytes(); dbipNinkiPub = deriveChild(pitem.NodeLevel, bipNinki).pub.toBytes(); @@ -1690,6 +1687,11 @@ function Engine() { } + + console.log("resume now..."); + //call to cordova plugin for private key derivation + + amountsToSend.push(amount); //now create the change @@ -1707,274 +1709,370 @@ function Engine() { amountsToSend.push(changeAmount); } - //create a new address for my change to be sent back to me + if (debug) { + console.log('change amount...' + changeAmount); + } + + //create a new address for my change to be sent back to me + statuscallback('Preparing transaction...', '20%'); //if we are sending money to a contact or paying an invoice //we need to derive addresses on their behalf - if (sendType == 'friend' || sendType == 'invoice') { - var params = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: friendUserName, amount: amount }; + console.log(nodeLevels); - //generate the address for the contact - //this must be done on the client - $(messel).text('Creating address...'); - createAddressForFriend(friendUserName, function (err, address) { - if (!err) { + deriveKeys(bipHot, nodeLevels, function (ret) { - $(progressel).width('40%'); - if ($(progresselnum)) { - $(progresselnum).text('40%'); - } + console.log("got here..."); + console.log(ret); - addressToSend.push(address); + if (m_this.Device.isCordova()) { + console.log("is cordova..."); + for (var i = 0; i < ret.length; i++) { + console.log("new key..."); + var nkey = new Bitcoin.ECKey(ret[i]); + console.log(nkey); + userHotPrivKeys.push(nkey); + console.log(userHotPrivKeys); + } - //create the change address, this must be done on the client - $(messel).text('Creating change address...'); + } else { - createAddress('m/0/1', changeAmount, function (err, changeaddress) { + packet.userHotPrivKeys = ret; + } - if (!err) { - $(progressel).width('60%'); - if ($(progresselnum)) { - $(progresselnum).text('60%'); - } + console.log(userHotPrivKeys); - if (changeAmount > 0) { - addressToSend.push(changeaddress); - } - //now get the transaction data - $(messel).text('Creating transaction...'); - aGetTransactionData(packet, function (err, hashesForSigning, rawTransaction) { - $(progressel).width('80%'); - if ($(progresselnum)) { - $(progresselnum).text('80%'); - } + if (sendType == 'friend' || sendType == 'invoice') { + var params = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: friendUserName, + amount: amount + }; + //generate the address for the contact + //this must be done on the client - var jsonSend = { guid: m_this.m_guid, hashesForSigning: hashesForSigning, rawTransaction: rawTransaction, pathsToSignWith: nodeLevels } - var jsonp1 = { guid: m_this.m_guid, jsonPacket: JSON.stringify(jsonSend), sharedid: m_this.m_sharedid, twoFactorCode: twoFactorCode, userName: friendUserName }; - $(messel).text('Counter-signing transaction...'); + console.log('Creating address...'); + statuscallback('creating address...', '30%'); + createAddressForFriend(friendUserName, function (err, address) { - //send the transaction to the service for countersigning and broadcast to the network + if (!err) { - //requires 2 factor authentication + //statuscallback(null, '40%'); - API.post("/api/1/u/sendtransaction", jsonp1, function (err, result) { + addressToSend.push(address); - if (!err) { - $(progressel).width('100%'); - if ($(progresselnum)) { - $(progresselnum).text('100%'); - } + //create the change address, this must be done on the client + statuscallback('Creating change address...', '40%'); + console.log("start create address.."); + createAddress('m/0/1', changeAmount, function (err, changeaddress) { - $(messel).text('Transaction broadcast...'); - //error handling? + if (!err) { + console.log("end create address..."); - //we have a transaction id so lets make a note of the transaction in the database - var params = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: friendUserName, transactionid: result, address: address, amount: amount }; - API.post("/api/1/u/createtransactionrecord", params, function (err, result) { - return callback(err, params.transactionid); - }); - } else { - //handle error messages returned from the server - if (result == 'ErrSingleTransactionLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Single limit exceeded'); - return callback(err, result); - } + if (changeAmount > 0) { + addressToSend.push(changeaddress); + } - if (result == 'ErrDailyTransactionLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Daily limit exceeded'); - return callback(err, result); - } + //now get the transaction data + statuscallback('Building transaction...', '60%'); + setTimeout(function () { + aGetTransactionData(packet, function (err, hashesForSigning, rawTransaction) { - if (result == 'ErrTransactionsPerDayLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Daily number limit exceeded'); - return callback(err, result); - } + if (!err) { - if (result == 'ErrTransactionsPerHourLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Hourly number limit exceeded'); - return callback(err, result); - } + statuscallback(null, '80%'); - if (result == 'ErrInvalidRequest') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Invalid request'); - return callback(err, result); - } + var jsonSend = { + guid: m_this.m_guid, + hashesForSigning: hashesForSigning, + rawTransaction: rawTransaction, + pathsToSignWith: nodeLevels + }; + var jsonp1 = { + guid: m_this.m_guid, + jsonPacket: JSON.stringify(jsonSend), + sharedid: m_this.m_sharedid, + twoFactorCode: twoFactorCode, + userName: friendUserName + }; - if (result == 'ErrLocked') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Account is unavailable'); - return callback(err, result); - } + statuscallback('Counter-signing transaction...', '80%'); - if (result == 'ErrBroadcastFailed') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Not accepted'); - return callback(err, result); - } + //send the transaction to the service for countersigning and broadcast to the network + + + //requires 2 factor authentication + + API.post("/api/1/u/sendtransaction", jsonp1, function (err, result) { + + if (!err) { + + + statuscallback('Transaction broadcast...', '100%'); + + return callback(err, result); + + + } else { + + //handle error messages returned from the server + if (result == 'ErrSingleTransactionLimit') { + + statuscallback('Transaction Failed: Single limit exceeded', '0%'); + + return callback(err, result); + + } + + if (result == 'ErrDailyTransactionLimit') { + + statuscallback('Transaction Failed: Daily limit exceeded', '0%'); + + return callback(err, result); + } + + if (result == 'ErrTransactionsPerDayLimit') { + + statuscallback('Transaction Failed: Daily number limit exceeded', '0%'); + + return callback(err, result); + } + + if (result == 'ErrTransactionsPerHourLimit') { + + statuscallback('Transaction Failed: Hourly number limit exceeded', '0%'); + + return callback(err, result); + } + + if (result == 'ErrInvalidRequest') { + + statuscallback('Transaction Failed: Invalid request', '0%'); + + return callback(err, result); + } + + + if (result == 'ErrBroadcastFailed') { + + statuscallback('Transaction Failed: Not accepted', '0%'); + + return callback(err, result); + } + + if (result == "Invalid two factor code") { + + statuscallback("Invalid two factor code", '0%'); + + return callback(err, result); + } + + if (result == "ErrInsufficientFunds") { + statuscallback("Transaction Failed: Insufficient funds", '0%'); + + return callback(err, result); + } + + if (result == "ErrLocked") { + + statuscallback("Contact account is unavailable", '0%'); + + return callback(err, result); + } + + statuscallback('Transaction Failed:' + result, '0%'); + + return callback(err, result); + + } + }); - if (result == "Invalid two factor code") { - $(progressel).width('100%'); - $(messel).text("Invalid two factor code"); - return callback(err, result); } - } - }); - }); - } else { - //create address error - if (changeaddress == 'ErrInvalidRequest') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Invalid request'); + + }); + }, debugtime); + } else { + //create address error + + statuscallback(changeaddress, '0%'); return callback(err, changeaddress); + } - } - }); - } else { + }); + } else { + - if (address == 'ErrInvalidRequest') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Invalid request'); + statuscallback(address, '0%'); return callback(err, address); + + } + }); + } else { + + statuscallback('Creating change address...', '20%'); + addressToSend.push(addressTo); + + if (debug) { + console.log("start creating change address"); } - }); - } else { + //create the change address, this must be done on the client + createAddress('m/0/1', changeAmount, function (err, changeaddress) { + if (!err) { - $(messel).text('Creating address...'); + if (debug) { + console.log("finished creating change address"); + } - addressToSend.push(addressTo); - //create the change address, this must be done on the client - createAddress('m/0/1', changeAmount, function (err, changeaddress) { + if (changeAmount > 0) { + addressToSend.push(changeaddress); + } - if (!err) { + //now get the transaction - $(progressel).width('40%'); + statuscallback('Creating transaction...', '40%'); + setTimeout(function () { - if ($(progresselnum)) { - $(progresselnum).text('40%'); - } + aGetTransactionData(packet, function (err, hashesForSigning, rawTransaction) { - if (changeAmount > 0) { - addressToSend.push(changeaddress); - } + if (!err) { - //now get the transaction - $(messel).text('Creating transaction...'); - aGetTransactionData(packet, function (err, hashesForSigning, rawTransaction) { - $(progressel).width('60%'); + statuscallback('Counter-signing transaction...', '60%'); - if ($(progresselnum)) { - $(progresselnum).text('60%'); - } + var jsonSend = { + guid: m_this.m_guid, + hashesForSigning: hashesForSigning, + rawTransaction: rawTransaction, + pathsToSignWith: nodeLevels + }; + var jsonp1 = { + guid: m_this.m_guid, + jsonPacket: JSON.stringify(jsonSend), + sharedid: m_this.m_sharedid, + twoFactorCode: twoFactorCode, + userName: '' + }; - var jsonSend = { guid: m_this.m_guid, hashesForSigning: hashesForSigning, rawTransaction: rawTransaction, pathsToSignWith: nodeLevels } - var jsonp1 = { guid: m_this.m_guid, jsonPacket: JSON.stringify(jsonSend), sharedid: m_this.m_sharedid, twoFactorCode: twoFactorCode, userName: '' }; - $(messel).text('Counter-signing transaction...'); - API.post("/api/1/u/sendtransaction", jsonp1, function (err, result) { - $(progressel).width('80%'); + API.post("/api/1/u/sendtransaction", jsonp1, function (err, result) { - if ($(progresselnum)) { - $(progresselnum).text('80%'); - } + statuscallback(null, '80%'); + if (!err) { - if (!err) { + statuscallback('Transaction broadcast', '100%'); + return callback(err, result); - if ($(progresselnum)) { - $(progresselnum).text('100%'); - } - $(progressel).width('100%'); - $(messel).text('Transaction broadcast...'); + } else { - //we have a transaction id so lets make a note of the transaction in the database - var params = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: 'External', transactionid: result, address: addressTo, amount: amount }; - API.post("/api/1/u/createtransactionrecord", params, function (err, result) { - return callback(err, result); - }); - } else { - if (result == 'ErrSingleTransactionLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Single limit exceeded'); - return callback(err, result); - } + if (result == 'ErrSingleTransactionLimit') { - if (result == 'ErrDailyTransactionLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Daily limit exceeded'); - return callback(err, result); - } + statuscallback('Transaction Failed: Single limit exceeded', '0%'); - if (result == 'ErrTransactionsPerDayLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Daily number limit exceeded'); - return callback(err, result); - } + return callback(err, result); - if (result == 'ErrTransactionsPerHourLimit') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Hourly number limit exceeded'); - return callback(err, result); - } + } - if (result == 'ErrInvalidRequest') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Invalid request'); - return callback(err, result); - } + if (result == 'ErrDailyTransactionLimit') { + statuscallback('Transaction Failed: Daily limit exceeded', '0%'); - if (result == 'ErrBroadcastFailed') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Not accepted'); - return callback(err, result); - } + return callback(err, result); + } + + if (result == 'ErrTransactionsPerDayLimit') { + + statuscallback('Transaction Failed: Daily number limit exceeded', '0%'); + + return callback(err, result); + } + + if (result == 'ErrTransactionsPerHourLimit') { + + statuscallback('Transaction Failed: Hourly number limit exceeded', '0%'); + + return callback(err, result); + } + + if (result == 'ErrInvalidRequest') { + + statuscallback('Transaction Failed: Invalid request', '0%'); + + return callback(err, result); + } + + + if (result == 'ErrBroadcastFailed') { + + statuscallback('Transaction Failed: Not accepted', '0%'); + + return callback(err, result); + } + + if (result == "Invalid two factor code") { + + statuscallback("Invalid two factor code", '0%'); + + return callback(err, result); + } + + if (result == "ErrInsufficientFunds") { + + statuscallback("Transaction Failed: Insufficient funds", '0%'); + + return callback(err, result); + } + + statuscallback('Transaction Failed:' + result, '0%'); + + return callback(err, result); + + } + }); + + } else { + + statuscallback('error creating transaction', '0%'); + + return callback(err, 'error creating transaction'); - if (result == "Invalid two factor code") { - $(progressel).width('100%'); - $(messel).text("Invalid two factor code"); - return callback(err, result); } + }); + }, 50); + } else { - } - }); - }); - } else { + //create address error + + statuscallback(changeaddress, '0%'); - //create address error - if (changeaddress == 'ErrInvalidRequest') { - $(progressel).width('100%'); - $(messel).text('Transaction Failed: Invalid request'); return callback(err, changeaddress); - } - } - }); - } + } + }); + } + }); } else { + statuscallback(outputs, '0%'); + return callback(err, outputs); } @@ -1984,64 +2082,196 @@ function Engine() { }); + } //function createAddress //this function creates an address for the user this.createAddress = createAddress; - function createAddress(nodePath, changeamount, callback) { + function createAddress(nodePath, changeamount, cacallback) { if (changeamount > 0) { + + var snode = nodePath.split('/'); + var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, pathToUse: nodePath }; //get the next leaf from the user's node space API.post("/api/1/u/getnextleaf", postData, function (err, leaf) { - var path = nodePath + '/' + leaf; + if (!err) { - //derive the 3 public keys for the new address - //TODO: possible to use an encrypted cache for performance improvements + var path = nodePath + '/' + leaf; - var bipHot = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.hotPub); - var bipCold = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.coldPub); - var bipNinki = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.ninkiPubKey); - var hotKey = deriveChild(path, bipHot); - var coldKey = deriveChild(path, bipCold); - var ninkiKey = deriveChild(path, bipNinki); - - //now create the multisig address - var script = [0x52]; - script.push(33); - script = script.concat(hotKey.pub.toBytes()); - script.push(33); - script = script.concat(coldKey.pub.toBytes()); - script.push(33); - script = script.concat(ninkiKey.pub.toBytes()); - script.push(0x53); - script.push(0xae); - var address = multiSig(script); - - //post the address back to the server - //this allows the server to monitor for balances etc. - var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, path: path, address: address, pk1: hotKey.pub.toString(), pk2: coldKey.pub.toString(), pk3: ninkiKey.pub.toString() }; - API.post("/api/1/u/createaddress", postData, function (err, result) { - if (!err) { - return callback(err, address); + if (m_this.Device.isCordova()) { + + var tnode = snode[2] * 1; + + var hotKey = []; + var coldKey = []; + var ninkiKey = []; + + var hhotKey = ''; + var hcoldKey = ''; + var hninkiKey = ''; + + cordova.exec( + function callback(data) { + + hhotKey = data; + console.log("hot key=" + data); + + hotKey = Bitcoin.convert.hexToBytes(data); + + + cordova.exec( + function callback(data) { + + hcoldKey = data; + console.log("cold key=" + data); + + coldKey = Bitcoin.convert.hexToBytes(data); + + cordova.exec( + function callback(data) { + + hninkiKey = data; + + console.log("ninki key=" + data); + + ninkiKey = Bitcoin.convert.hexToBytes(data); + + + var script = [0x52]; + + script.push(33); + script = script.concat(hotKey); + script.push(33); + script = script.concat(coldKey); + script.push(33); + script = script.concat(ninkiKey); + script.push(0x53); + script.push(0xae); + + var address = multiSig(script); + + //post the address back to the server + //this allows the server to monitor for balances etc. + var postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + path: path, + address: address, + pk1: hhotKey, + pk2: hcoldKey, + pk3: hninkiKey + }; + API.post("/api/1/u/createaddress", postData, function (err, result) { + console.log(result); + if (!err) { + return cacallback(err, address); + } else { + return cacallback(err, result); + } + + }); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMult', + [m_this.m_walletinfo.ninkiPubKey, tnode, leaf] + ); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMult', + [m_this.m_walletinfo.coldPub, tnode, leaf] + ); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMult', + [m_this.m_walletinfo.hotPub, tnode, leaf] + ); + } else { - return callback(err, result); + + + //derive the 3 public keys for the new address + //TODO: possible to use an encrypted cache for performance improvements + + var bipHot = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.hotPub); + var bipCold = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.coldPub); + var bipNinki = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.ninkiPubKey); + + console.log("deriving hot"); + var hotKey = deriveChild(path, bipHot); + console.log("deriving cold"); + var coldKey = deriveChild(path, bipCold); + console.log("deriving ninki"); + var ninkiKey = deriveChild(path, bipNinki); + console.log("keys derived"); + //now create the multisig address + var script = [0x52]; + + script.push(33); + script = script.concat(hotKey.pub.toBytes()); + script.push(33); + script = script.concat(coldKey.pub.toBytes()); + script.push(33); + script = script.concat(ninkiKey.pub.toBytes()); + script.push(0x53); + script.push(0xae); + + var address = multiSig(script); + + //post the address back to the server + //this allows the server to monitor for balances etc. + var postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + path: path, + address: address, + pk1: hotKey.pub.toString(), + pk2: coldKey.pub.toString(), + pk3: ninkiKey.pub.toString() + }; + API.post("/api/1/u/createaddress", postData, function (err, result) { + + if (!err) { + return cacallback(err, address); + } else { + return cacallback(err, result); + } + + }); + } - }); + } else { + + return cacallback(err, leaf); + + } //now update the address to the server }); } else { - return callback(false, "skipped"); + return cacallback(false, "skipped"); } } @@ -2049,7 +2279,7 @@ function Engine() { //function createAddress //this function creates an address on behalf of a user's contact this.createAddressForFriend = createAddressForFriend; - function createAddressForFriend(username, callback) { + function createAddressForFriend(username, cacallback) { var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username }; @@ -2069,56 +2299,185 @@ function Engine() { //only allow address to be created if the packet has been validated if (pubkeys.validated) { //get the next leaf on the contacts address space node assigned to this user + API.post("/api/1/u/getnextleafforfriend", postData, function (err, leaf) { - //derive the public keys - var path = 'm/' + leaf; + if (!err) { - var bipHot = Bitcoin.HDWallet.fromBase58(pubkeys.hotPub); - var bipCold = Bitcoin.HDWallet.fromBase58(pubkeys.coldPub); - var bipNinki = Bitcoin.HDWallet.fromBase58(pubkeys.ninkiPub); + //derive the public keys + var path = 'm/' + leaf; - var hotKey = deriveChild(path, bipHot); - var coldKey = deriveChild(path, bipCold); - var ninkiKey = deriveChild(path, bipNinki); - //now create the multisig address - var script = [0x52]; - script.push(33); - script = script.concat(hotKey.pub.toBytes()); - script.push(33); - script = script.concat(coldKey.pub.toBytes()); - script.push(33); - script = script.concat(ninkiKey.pub.toBytes()); - script.push(0x53); - script.push(0xae); - var address = multiSig(script); + if (m_this.Device.isCordova()) { + + + var nleaf = leaf * 1; + + var hotKey = []; + var coldKey = []; + var ninkiKey = []; + + var hhotKey = ''; + var hcoldKey = ''; + var hninkiKey = ''; + + cordova.exec( + function callback(data) { + + hhotKey = data; + console.log("hot key=" + data); + + hotKey = Bitcoin.convert.hexToBytes(data); + + + cordova.exec( + function callback(data) { + + hcoldKey = data; + console.log("cold key=" + data); + + coldKey = Bitcoin.convert.hexToBytes(data); + + cordova.exec( + function callback(data) { + + hninkiKey = data; + + console.log("ninki key=" + data); + + ninkiKey = Bitcoin.convert.hexToBytes(data); + + + var script = [0x52]; + + script.push(33); + script = script.concat(hotKey); + script.push(33); + script = script.concat(coldKey); + script.push(33); + script = script.concat(ninkiKey); + script.push(0x53); + script.push(0xae); + + var address = multiSig(script); + + //post the address back to the server + //this allows the server to monitor for balances etc. + //register the address with the server + var postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + address: address, + leaf: leaf, + pk1: hhotKey, + pk2: hcoldKey, + pk3: hninkiKey + }; + API.post("/api/1/u/createaddressforfriend", postData, function (err, result) { + + if (!err) { + return cacallback(err, address); + } else { + return cacallback(err, result); + } + + }); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMultCached', + [pubkeys.ninkiPub, nleaf] + ); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMultCached', + [pubkeys.coldPub, nleaf] + ); + + }, + function errorHandler(err) { + //alert('Error'); + }, + 'ECPlugin', + 'cordovaECMultCached', + [pubkeys.hotPub, nleaf] + ); - //register the address with the server - var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username, address: address, leaf: leaf, pk1: hotKey.pub.toString(), pk2: coldKey.pub.toString(), pk3: ninkiKey.pub.toString() }; - API.post("/api/1/u/createaddressforfriend", postData, function (err, result) { - if (!err) { - return callback(err, address); } else { - return callback(err, result); + + + var bipHot = Bitcoin.HDWallet.fromBase58(pubkeys.hotPub); + var bipCold = Bitcoin.HDWallet.fromBase58(pubkeys.coldPub); + var bipNinki = Bitcoin.HDWallet.fromBase58(pubkeys.ninkiPub); + + var hotKey = deriveChild(path, bipHot); + var coldKey = deriveChild(path, bipCold); + var ninkiKey = deriveChild(path, bipNinki); + + //now create the multisig address + var script = [0x52]; + script.push(33); + script = script.concat(hotKey.pub.toBytes()); + script.push(33); + script = script.concat(coldKey.pub.toBytes()); + script.push(33); + script = script.concat(ninkiKey.pub.toBytes()); + script.push(0x53); + script.push(0xae); + var address = multiSig(script); + + //register the address with the server + var postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + address: address, + leaf: leaf, + pk1: hotKey.pub.toString(), + pk2: coldKey.pub.toString(), + pk3: ninkiKey.pub.toString() + }; + API.post("/api/1/u/createaddressforfriend", postData, function (err, result) { + + if (!err) { + return cacallback(err, address); + } else { + return cacallback(err, result); + } + + }); } - }); + } else { + + return cacallback(err, leaf); + + } //now update the address to the server - }); + }); + + } else { //something very bad has happened //attempting to derive an address for a non validated contact - return callback(true, "ErrInvalid"); + return cacallback(true, "ErrInvalid"); } } else { - return callback(true, "ErrInvalid"); + return cacallback(true, "ErrInvalid"); } @@ -2130,7 +2489,11 @@ function Engine() { function multiSig(rs) { var x = Bitcoin.Crypto.RIPEMD160(Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(rs))); x = Bitcoin.convert.wordArrayToBytes(x); - x.unshift(0x5); + if (m_this.m_network == "testnet") { + x.unshift(196); + } else { + x.unshift(0x5); + } var r = x; r = Bitcoin.Crypto.SHA256(Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(r))); var checksum = Bitcoin.convert.wordArrayToBytes(r).slice(0, 4); @@ -2139,8 +2502,6 @@ function Engine() { } - - this.signMessage = signMessage; function signMessage(key, guid, callback) { @@ -2154,7 +2515,7 @@ function Engine() { } var message = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - var skey = Bitcoin.HDWallet.fromSeedHex(mkey); + var skey = Bitcoin.HDWallet.fromSeedHex(mkey, m_this.m_network); var sig = Bitcoin.convert.bytesToHex(skey.priv.sign(Bitcoin.convert.hexToBytes(message))); @@ -2233,82 +2594,211 @@ function Engine() { this.createFriend = createFriend; - function createFriend(username, uimessage, callback) { + function createFriend(username, uimessage, cbcallback) { //get the next friend node var node = ""; var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username }; - if ($(uimessage)) { - $(uimessage).text('Assigning node...'); - } - API.post("/api/1/u/getnextnodeforfriend", postData, function (err, node) { - var bipHot = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.hotPub); + if (m_this.Device.isCordova()) { - var bipCold = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.coldPub); + var nls = node.split("/"); + var tnode = nls[2] * 1; - var bipNinki = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.ninkiPubKey); - setTimeout(function () { + var hotKey = ''; + var coldKey = ''; + var ninkiKey = ''; - var hotKey = deriveChild(node, bipHot).toString(); + cordova.exec(function callback(data) { - if ($(uimessage)) { - $(uimessage).text('Deriving address.'); - } + hotKey = Bitcoin.HDWallet.fromHex(data).toString(); - setTimeout(function () { + console.log(hotKey); - var coldKey = deriveChild(node, bipCold).toString(); - if ($(uimessage)) { - $(uimessage).text('Deriving address..'); - } + cordova.exec(function callback(data) { - setTimeout(function () { + coldKey = Bitcoin.HDWallet.fromHex(data).toString(); - var ninkiKey = deriveChild(node, bipNinki).toString(); - if ($(uimessage)) { - $(uimessage).text('Deriving address...'); - } - //get the friends public RSA key - var rsaKey = ''; + console.log(coldKey); - $(uimessage).text('Get PGP keys...'); - API.post("/api/1/u/getrsakey", postData, function (err, rsaKey) { + cordova.exec(function callback(data) { - var publicKeys = openpgp.key.readArmored(rsaKey); - if ($(uimessage)) { - $(uimessage).text('Encrypting data...'); - } + ninkiKey = Bitcoin.HDWallet.fromHex(data).toString(); - var pubKey = publicKeys.keys[0]; + console.log(ninkiKey); - var message = hotKey + coldKey + ninkiKey; + console.log("getting rsa key"); - var encrypted = openpgp.signAndEncryptMessage([pubKey], m_this.m_privKey, message); + API.post("/api/1/u/getrsakey", postData, function (err, rsaKey) { - var result = ""; + console.log("got rsa key"); - var postFriendData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username, node: node, packetForFriend: encrypted, validationHash: '' }; - API.post("/api/1/u/createfriend", postFriendData, function (err, result) { + var publicKeys = openpgp.key.readArmored(rsaKey); - return callback(err, result); + var pubKey = publicKeys.keys[0]; + + var message = hotKey + coldKey + ninkiKey; + + console.log("encrypting"); + + var encrypted = openpgp.signAndEncryptMessage([pubKey], m_this.m_privKey, message); + + console.log("encrypting done"); + + var result = ""; + + var postFriendData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + node: node, + packetForFriend: encrypted, + validationHash: '' + }; + + console.log(postFriendData); + + console.log("calling createfriend"); + + API.post("/api/1/u/createfriend", postFriendData, function (err, result) { + + console.log("done"); + + console.log(err); + console.log(result); + + return cbcallback(err, result); + + }); }); + }, + function errorHandler(err) { + alert(err); + }, + 'ECPlugin', + 'cordovaDerMPK', + [m_this.m_walletinfo.ninkiPubKey, tnode] + ); + + }, function errorHandler(err) { + alert(err); + }, + 'ECPlugin', + 'cordovaDerMPK', + [m_this.m_walletinfo.coldPub, tnode] + ); + + }, function errorHandler(err) { + alert(err); + }, + 'ECPlugin', + 'cordovaDerMPK', + [m_this.m_walletinfo.hotPub, tnode] + ); + + + } else { + + + var bipHot = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.hotPub); + + var bipCold = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.coldPub); + + var bipNinki = Bitcoin.HDWallet.fromBase58(m_this.m_walletinfo.ninkiPubKey); + + var hotKey = deriveChild(node, bipHot).toString(); + + var coldKey = deriveChild(node, bipCold).toString(); + + var ninkiKey = deriveChild(node, bipNinki).toString(); + + //get the friends public RSA key + var rsaKey = ''; + + API.post("/api/1/u/getrsakey", postData, function (err, rsaKey) { + + var publicKeys = openpgp.key.readArmored(rsaKey); + + var pubKey = publicKeys.keys[0]; + + var message = hotKey + coldKey + ninkiKey; + + var encrypted = openpgp.signAndEncryptMessage([pubKey], m_this.m_privKey, message); + + var result = ""; + + var postFriendData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + node: node, + packetForFriend: encrypted, + validationHash: '' + }; + API.post("/api/1/u/createfriend", postFriendData, function (err, result) { + + return cbcallback(err, result); + + }); + + }); + + } + + }); + } + + + this.acceptFriend = acceptFriend; + function acceptFriend(username, callback) { + + + //need to add error handling and messages here + + m_this.acceptFriendRequest(username, function (err, secret) { + + if (err) { + + return callback(err, secret); + + } else { + + m_this.isNetworkExist(username, function (err, result) { + + if (!result) { + + m_this.createFriend(username, '', function (err, result) { + + if (err) { + + return callback(err, result); + } else { + + return callback(err, result); + } }); - }, 50); - }, 50); - }, 50); + } else { + + return callback(err, result); + } + }); + } }); + + } + + this.acceptFriendRequest = acceptFriendRequest; function acceptFriendRequest(username, callback) { @@ -2356,7 +2846,13 @@ function Engine() { var encrypted = openpgp.signAndEncryptMessage([m_this.m_pubKey], m_this.m_privKey, JSON.stringify(packet)); - postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username, packet: encrypted, validationHash: '' }; + postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + packet: encrypted, + validationHash: '' + }; API.post("/api/1/u/updatefriend", postData, function (err, result) { return callback(err, result); @@ -2369,8 +2865,6 @@ function Engine() { } - - this.getFingerPrint = getFingerPrint; function getFingerPrint(callback) { @@ -2390,11 +2884,6 @@ function Engine() { var postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username }; API.post("/api/1/u/getfriendpacket", postData, function (err, packet) { - - //this is set to a fixed value, i wanted it to be set as blank as we encrypt these keys aes256 anyway - //there was no easy way to change this password in the library so i opted to go with a fixed password - //instead of a blank one - if (!err) { var msg = openpgp.message.readArmored(packet); @@ -2420,7 +2909,13 @@ function Engine() { var encryptedPayload = openpgp.signAndEncryptMessage([m_this.m_pubKey], m_this.m_privKey, JSON.stringify(reencrypt)); - postData = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, username: username, packet: encryptedPayload, validationHash: code }; + postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + username: username, + packet: encryptedPayload, + validationHash: code + }; API.post("/api/1/u/updatefriend", postData, function (err, result) { @@ -2429,7 +2924,6 @@ function Engine() { }); - } else { return callback(err, false); @@ -2439,15 +2933,15 @@ function Engine() { } } else { - return callback(err, result); + return callback(err, packet); } + }); } - //status //0 pending //1 paid @@ -2491,7 +2985,13 @@ function Engine() { var result = ""; - var pdata = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, userName: username, packetForMe: packetForMe, packetForThem: encrypted }; + var pdata = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + userName: username, + packetForMe: packetForMe, + packetForThem: encrypted + }; API.post("/api/1/u/createinvoice", pdata, function (err, invoiceid) { return callback(err, invoiceid); @@ -2559,7 +3059,6 @@ function Engine() { }); - } @@ -2578,18 +3077,10 @@ function Engine() { if (!err) { - var bytes = []; - for (var i = 0; i < m_this.m_sharedid.length; ++i) { - bytes.push(m_this.m_sharedid.charCodeAt(i)); - } - - var dpacket = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - - API.post("/api/1/verifyrecoverpacket", { guid: m_this.m_oguid, token: dpacket }, function (err, response) { + API.registerToken(result); + m_this.m_APIToken = result; - callback(err, response); - - }); + callback(false, result); } else { @@ -2601,7 +3092,7 @@ function Engine() { } - this.SetupTwoFactor = SaveTwoFactor; + this.SetupTwoFactor = SetupTwoFactor; function SetupTwoFactor(twoFactorCode, callback) { var postData = { @@ -2613,7 +3104,7 @@ function Engine() { API.post("/api/1/u/updatetwofactor", postData, function (err, result) { - $('#API-Token').val(result); + API.registerToken(result); callback(err, result); @@ -2671,9 +3162,8 @@ function Engine() { } - this.ChangePassword = ChangePassword; - function ChangePassword(twoFactorCode, oldpassword, newpassword, progbar, progmess, reset, message1, message2, callback) { + function ChangePassword(twoFactorCode, oldpassword, newpassword, callback, statusUpdate) { API.getWalletFromServer(m_this.m_guid, m_this.m_secret, twoFactorCode, false, function (err, wallet) { @@ -2687,8 +3177,10 @@ function Engine() { getHotHash("", function (err, hothash) { - $(progbar).width('40%'); - $(progmess).text('Securing password...'); + + statusUpdate('Securing password...', '20%'); + + setTimeout(function () { //if password reset do not pbkdf the password @@ -2696,11 +3188,9 @@ function Engine() { oldpassword = pbkdf2(oldpassword, m_this.m_oguid); //get the two packets - $(progbar).width('40%'); - $(progmess).text('Getting packets...'); - // $("#chngpwdprogbar").width('50%'); - //$("#chngpwdprogmess").text('Decrypting account packet...'); + statusUpdate('Getting packets...', '40%'); + //decrypt with the old password var decryptedWithOld = true; var decryptedPayload = ''; @@ -2712,8 +3202,9 @@ function Engine() { if (decryptedWithOld) { - $(progbar).width('80%'); - $(progmess).text('Securing new password...'); + + statusUpdate('Securing new password...', '80%'); + API.getUserPacket(m_this.m_guid, m_this.m_sharedid, function (err, encpacket) { var decryptedUsrWithOld = true; @@ -2757,8 +3248,8 @@ function Engine() { newpassword = pbkdf2(newpassword, m_this.m_oguid); - $(progbar).width('80%'); - $(progmess).text('Encrypting account packet...'); + statusUpdate('Encrypting account packet...', '80%'); + var newpayloadsuccess = true; var newpayload = ''; @@ -2768,7 +3259,7 @@ function Engine() { var newAIV = ''; var newUIV = ''; var newRIV = ''; - var newPIV = '' + var newPIV = ''; try { newpayload = encrypt(decryptedPayload, newpassword); @@ -2819,9 +3310,8 @@ function Engine() { if (testsuccess) { //save to the server - $(progbar).width('95%'); - $(progmess).text('Saving...'); + statusUpdate('Saving...', '95%'); //TO DO: //add in the re-encryption of the verification @@ -2831,12 +3321,23 @@ function Engine() { //if reset password then provide signed message and call reset function - //need to add two factor here //so 1. add two factor //2. add way to save only the main packet - var postData = { twoFactorCode: twoFactorCode, guid: m_this.m_guid, sharedid: m_this.m_sharedid, accountPacket: newpayload.toString(), userPacket: newusrpayload.toString(), verifyPacket: newveripacket.toString(), passPacket: newpasspacket.toString(), IVA: newAIV, IVU: newUIV, IVR: newRIV, PIV: newPIV }; + var postData = { + twoFactorCode: twoFactorCode, + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + accountPacket: newpayload.toString(), + userPacket: newusrpayload.toString(), + verifyPacket: newveripacket.toString(), + passPacket: newpasspacket.toString(), + IVA: newAIV, + IVU: newUIV, + IVR: newRIV, + PIV: newPIV + }; API.post("/api/1/u/updatepackets", postData, function (err, dataStr) { if (err) { callback(true, "Error: Password not changed"); @@ -2844,19 +3345,45 @@ function Engine() { if (dataStr == "ok") { - m_this.m_password = newpassword; - //if something goes wrong here - //the worst case scenario is the - //user has to reenter their hot key - saveHotHash(hothash, function (err, result) { + m_this.Device.getStorageItem("tfso" + m_this.m_guid, function (tfso) { + + if (tfso != "") { + var enc = JSON.parse(tfso); + var token = decryptNp(enc.ct, m_this.m_password, enc.iv); + tfso = encryptNp(token, newpassword); + + var ctok = {}; + ctok.ct = tfso.toString(); + ctok.iv = tfso.iv.toString(); + m_this.Device.setStorageItem("tfso" + m_this.m_guid, JSON.stringify(ctok)); + + } + + m_this.m_password = newpassword; + + //if something goes wrong here + //the worst case scenario is the + //user has to reenter their hot key + + saveHotHash(hothash, function (err, result) { - callback(false, ''); + callback(false, ''); + + }); }); + + + + + + + + } else { callback(true, "Error: Password not changed"); @@ -2866,7 +3393,6 @@ function Engine() { }); - } else { callback(true, "Error: Password not changed"); @@ -2990,8 +3516,6 @@ function Engine() { $(progmess).text('Getting packets...'); - - // $("#chngpwdprogbar").width('50%'); //$("#chngpwdprogmess").text('Decrypting account packet...'); //decrypt with the old password @@ -3061,7 +3585,7 @@ function Engine() { var newAIV = ''; var newUIV = ''; var newRIV = ''; - var newPIV = '' + var newPIV = ''; try { newpayload = encrypt(decryptedPayload, newpassword); @@ -3115,7 +3639,18 @@ function Engine() { //if reset password then provide signed message and call reset function - var postData = { guid: guid, sharedid: sharedid, accountPacket: newpayload.toString(), userPacket: newusrpayload.toString(), verifyPacket: newveripacket.toString(), passPacket: newpasspacket.toString(), IVA: newAIV, IVU: newUIV, IVR: newRIV, PIV: newPIV }; + var postData = { + guid: guid, + sharedid: sharedid, + accountPacket: newpayload.toString(), + userPacket: newusrpayload.toString(), + verifyPacket: newveripacket.toString(), + passPacket: newpasspacket.toString(), + IVA: newAIV, + IVU: newUIV, + IVR: newRIV, + PIV: newPIV + }; API.post("/api/1/u/updatepackets", postData, function (err, dataStr) { if (err) { callback(true, "Error: Password not changed"); @@ -3136,7 +3671,6 @@ function Engine() { }); - } else { callback(true, "Error: Password not changed"); @@ -3192,7 +3726,6 @@ function Engine() { } - //////////////////////////////////////////////////////////////////////////////////////////// this.EmailValidationForTwoFactor = EmailValidationForTwoFactor; @@ -3223,40 +3756,61 @@ function Engine() { } this.updateAccountSettings = updateAccountSettings; - function updateAccountSettings(jsonPacket, twoFactorCode, callback) { + function updateAccountSettings(jsonPacket, twoFactorCode, twoFactorSend, callback) { + + + + //only request a new token + var postdata = { guid: m_this.m_guid, sharedid: m_this.m_sharedid, jsonPacket: JSON.stringify(jsonPacket), - twoFactorCode: twoFactorCode + twoFactorCode: twoFactorCode, + twoFactorSend: twoFactorSend }; - API.post("/api/1/u/updateaccountsettings", postdata - , function (err, response) { + API.post("/api/2/u/updateaccountsettings", postdata + , function (err, response) { - if (!err) { + if (!err) { - getAccountSettings(function (err, res) { + if (response != "ok") { - if (!err) { + var ret = JSON.parse(response); - var settingsObject = JSON.parse(res); - m_this.m_settings = settingsObject; - callback(err, response); - } else { + if (ret.Token) { + + var enc = encryptNp(ret.Token, m_this.m_password); + var ctok = {}; + ctok.ct = enc.toString(); + ctok.iv = enc.iv.toString(); + m_this.Device.setStorageItem("tfso" + m_this.m_guid, JSON.stringify(ctok)); - callback(err, res); + } } - }); + getAccountSettings(function (err, res) { - } else { - callback(err, response); - } + if (!err) { + var settingsObject = JSON.parse(res); + m_this.m_settings = settingsObject; + callback(err, response); + } else { - }); + callback(err, res); + } + + }); + + } else { + callback(err, response); + } + + + }); } @@ -3277,6 +3831,23 @@ function Engine() { } + this.getNewTwoFactorImg = getNewTwoFactorImg; + function getNewTwoFactorImg(twoFactorCode, callback) { + + var postData = { + guid: m_this.m_guid, + sharedid: m_this.m_sharedid, + twoFactorCode: twoFactorCode + }; + + API.post("/api/1/getnewtwofactorimg", postData, function (err, twoFactorQrImgUrl) { + + callback(err, twoFactorQrImgUrl) + + }); + + } + this.getBackup = getBackup; function getBackup(twoFactorCode, callback) { @@ -3504,7 +4075,7 @@ function Engine() { function getDeviceKey(devicePIN, callback) { var deviceid = "DEVICE123456789"; - if (window.cordova) { + if (m_this.Device.isCordova()) { deviceid = window.device.uuid; } @@ -3517,7 +4088,7 @@ function Engine() { pinhash = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - getCookie("ninki_reg", function (regToken) { + m_this.Device.getStorageItem("ninki_reg", function (regToken) { API.getDeviceKey(m_this.m_guid, pinhash, regToken, function (err, ekey) { @@ -3526,7 +4097,14 @@ function Engine() { if (jekey.DeviceKey.length > 0) { - callback(err, jekey); + + if (jekey.SessionToken) { + API.registerToken(jekey.SessionToken); + m_this.m_APIToken = jekey.SessionToken; + callback(err, jekey); + } + + } else { @@ -3546,7 +4124,7 @@ function Engine() { this.destroyDevice = destroyDevice; function destroyDevice(callback) { - getCookie("ninki_reg", function (regToken) { + m_this.Device.getStorageItem("ninki_reg", function (regToken) { API.destroyDevice(m_this.m_guid, regToken, function (err, ekey) { @@ -3585,6 +4163,103 @@ function Engine() { function getDeviceToken(deviceName, twoFactorCode, callback) { API.getDeviceToken(m_this.m_guid, m_this.m_sharedid, deviceName, twoFactorCode, callback); } + + this.getLimitStatus = getLimitStatus; + function getLimitStatus(callback) { + API.getLimitStatus(m_this.m_guid, m_this.m_sharedid, function (err, res) { + + if (!err) { + var jlimits = JSON.parse(res); + return callback(err, jlimits); + + } else { + return callback(err, res); + } + + }); + } + + + this.createBackupCodes = createBackupCodes; + function createBackupCodes(twoFactorCode, callback) { + API.createBackupCodes(m_this.m_guid, m_this.m_sharedid, twoFactorCode, function (err, res) { + + if (!err) { + var jcodes = JSON.parse(res); + return callback(err, jcodes); + + } else { + return callback(err, res); + } + + }); + } + + + + + this.get2faOverride = get2faOverride; + function get2faOverride(amount, callback) { + + m_this.Device.getStorageItem("tfso" + m_this.m_guid, function (res) { + + if (res == "") { + + return callback(false,""); + + } + + getLimitStatus(function (err, limits) { + + if (!err) { + + var twofareq = false; + if ((limits.No24hr + 1) > limits.NoOfTransactionsPerDay) { + twofareq = true; + } + if ((limits.No1hr + 1) > limits.NoOfTransactionsPerHour) { + twofareq = true; + } + + if ((amount) > limits.SingleTransactionLimit) { + twofareq = true; + } + if ((limits.TotalAmount24hr + amount) > limits.DailyTransactionLimit) { + twofareq = true; + } + + if (twofareq) { + + callback(err, ""); + + } else { + + if (res.length > 0) { + var enc = JSON.parse(res); + twoFactorCode = decryptNp(enc.ct, m_this.m_password, enc.iv); + callback(err, twoFactorCode); + + } else { + + callback(err, ""); + } + + } + } else { + + callback(err, limits); + + } + + + }); + + }); + + + } + } -module.exports = Engine \ No newline at end of file +module.exports = Engine; + diff --git a/src/ninki-ui-mobile.js b/src/ninki-ui-mobile.js index 5e242da..e9d936a 100644 --- a/src/ninki-ui-mobile.js +++ b/src/ninki-ui-mobile.js @@ -8,16 +8,7 @@ function UI() { var Engine = new Ninki.Engine(); - // var WALLETINFORMATION = {}; - // var SHAREDID = ''; - - // var TWOFACTORONLOGIN = false; - // var NICKNAME = ''; - // var guid = ''; - // var oguid = ''; - // var password = ''; - - + var currentBalance = 0; var FRIENDSLIST = {}; var COINUNIT = 'BTC'; var price = 0; @@ -55,10 +46,15 @@ function UI() { var contactPhraseCache = {}; + var isPairing = false; + var ua = window.navigator.userAgent; var msie = ua.indexOf("MSIE"); + var pintaps = 0; + var prevpin = ''; + if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) { @@ -95,7 +91,7 @@ function UI() { var match = r.exec(url); if (!match) return null; - var parsed = { url: url } + var parsed = { url: url }; if (match[2]) { var queries = match[2].split('&'); @@ -111,96 +107,6 @@ function UI() { return parsed; } - function setCookie(cname, cvalue) { - - - if (isChromeApp()) { - - var obj = {}; - obj[cname] = cvalue; - chrome.storage.local.set(obj, function () { - - console.log("saved"); - - }); - - } - else { - - localStorage[cname] = cvalue; - - } - - - } - - function isChromeApp() { - - if (window.cordova) { - return false; - } - - - var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; - if (is_chrome) { - if (chrome) { - if (chrome.app) { - if (chrome.app.runtime) { - return true; - } - } - } - } - return false; - } - - - function getCookie(cname, callback) { - - - if (isChromeApp()) { - - chrome.storage.local.get(cname, function (result) { - - if (result[cname]) { - result = result[cname]; - } else { - result = ""; - } - - return callback(result); - - }); - - } else { - - if (localStorage[cname]) { - return callback(localStorage[cname]); - } else { - return callback(''); - } - - } - - } - - function deleteCookie(cname) { - - - if (isChromeApp()) { - - chrome.storage.local.remove(cname, function () { - - console.log("deleted"); - - }); - - } else { - - localStorage.removeItem(cname); - - } - } function getLocalTime(datetime) { @@ -225,6 +131,7 @@ function UI() { } + var pinlock = false; function loginPIN() { @@ -232,9 +139,11 @@ function UI() { $("#enterpinalert").hide(); - if (pin.length == 4) { + if (pin.length == 4 && !pinlock) { - getCookie("guid", function (guid) { + pinlock = true; + + Engine.Device.getStorageItem("guid", function (guid) { if (!Engine.m_appInitialised) { @@ -255,46 +164,70 @@ function UI() { if (!err) { - if (Engine.m_appInitialised) { $('.numdone').attr("style", "background-color:white"); - if (ekeyv.SessionToken) { - $("#API-Token").val(ekeyv.SessionToken); - } - - //check state and display correct headers - - //set new session key $("#paddel").hide(); $('.numdone').attr("style", "background-color:white"); $("#loginpin").hide(); + $("#pinloginmessage").text("Enter your PIN number"); $("#nonlogin").show(); - $(".footer").show(); + $("#loginpinno").val(''); + pinlock = false; + + //do we show the footer or not? + + if ($("#footermode").val() == 1) { + $(".footer").show(); + } else { + $(".footer").hide(); + } + + //double check footer + //bug workaround + + if (menustate == "profile" && profilepagestate == "") { + + $(".footer").show(); + + } + + + + $("#isactive").val(1); - //initialiseDashboard(); setTimeout(updateUI(), 200); } else { - $("#pinspinner").show(); - var target = document.getElementById('pinspinner'); + $("#pairspinner").show(); + var target = document.getElementById('pairspinner'); var spinner = new Spinner(spinneropts).spin(target); - getCookie("ninki_p", function (result) { + $("#pinspinner").hide(); + $('.numdone').attr("style", "background-color:white"); + $("#loginpin").hide(); + $("#loginpinno").val(''); + pinlock = false; + $("#paddel").hide(); + $("#pinloginmessage").text("Enter your PIN number"); + + + + Engine.Device.getStorageItem("ninki_p", function (result) { var enc = JSON.parse(result); result = ''; Engine.setStretchPass(Engine.decryptNp(enc.ct, ekeyv.DeviceKey, enc.iv)); - getCookie("ninki_rem", function (res) { + Engine.Device.getStorageItem("ninki_rem", function (res) { if (res.length > 0) { var enc = JSON.parse(res); @@ -310,22 +243,31 @@ function UI() { if (result.TwoFactorOnLogin) { - $("#pinspinner").hide(); + $("#pairspinner").hide(); $("#loginpinno").val(''); - $("#enterpinalert").show(); - $("#enterpinalertmessage").text('Token has expired'); + pinlock = false; + //$("#enterpinalert").show(); + //$("#enterpinalertmessage").text('Token has expired'); + bootbox.alert("Your token has expired. Please repair your device", function () { + + Engine.Device.deleteStorageItem("ninki_reg"); + Engine.Device.deleteStorageItem("ninki_p"); + Engine.Device.deleteStorageItem("ninki_rem"); + Engine.Device.deleteStorageItem("guid"); + + location.reload(); + + }); } else { - $("#pinspinner").hide(); - $('.numdone').attr("style", "background-color:white"); - $("#loginpin").hide(); - $("#loginpinno").val(''); - $("#paddel").hide(); - getCookie("currency", function (res) { + $("#footermode").val(1); + $(".footer").show(); + + Engine.Device.getStorageItem("currency", function (res) { if (res) { @@ -333,16 +275,20 @@ function UI() { } else { - setCookie("currency", Engine.m_settings.LocalCurrency); + Engine.Device.setStorageItem("currency", Engine.m_settings.LocalCurrency); } + console.log(Engine.m_settings.LocalCurrency); + console.log(Engine.m_settings.CoinUnit); + var t = Engine.m_settings.LocalCurrency; + $('.sccy').filter(function () { return $(this).text().trim() == t; }).find("label").html(''); - getCookie("coinunit", function (res) { + Engine.Device.getStorageItem("coinunit", function (res) { if (res) { @@ -350,7 +296,7 @@ function UI() { } else { - setCookie("coinunit", Engine.m_settings.CoinUnit); + Engine.Device.setStorageItem("coinunit", Engine.m_settings.CoinUnit); } @@ -364,14 +310,50 @@ function UI() { }); - initialiseDashboard(); - Engine.m_appInitialised = true; + + initialiseDashboard(function () { + + + Engine.m_appInitialised = true; + $("#isactive").val(1); + + $("#pairspinner").hide(); + + $('#dashboard').show(); + $('#dashheader').show(); + + $("#mainWallet").show(); + $(".footer").show(); + + $("#nonlogin").show(); + + + }); + + } } else { - $("#pinspinner").hide(); + + if (result == "ErrLocked") { + + bootbox.alert("Your account is locked. Please unlock your account using the Chrome App"); + + } else { + + bootbox.alert(result); + + } + + + $("#pairspinner").hide(); $('.numdone').attr("style", "background-color:white"); + $("#loginpin").show(); + $("#loginpinno").val(''); + pinlock = false; + $("#paddel").hide(); + $("#pinloginmessage").text("Enter your PIN number"); } @@ -391,22 +373,44 @@ function UI() { if (ekeyv == "ErrDeviceDestroyed") { - deleteCookie("ninki_reg"); - deleteCookie("ninki_p"); - deleteCookie("ninki_rem"); - deleteCookie("guid"); - $("#loginpin").hide(); - $("#mainWallet").hide(); - $("#pairDevice").show(); + Engine.Device.deleteStorageItem("ninki_reg"); + Engine.Device.deleteStorageItem("ninki_p"); + Engine.Device.deleteStorageItem("ninki_rem"); + Engine.Device.deleteStorageItem("guid"); - location.reload(); - } + bootbox.alert("Too many failed attempts. The device has been unpaired.", function () { + + $("#loginpin").hide(); + $("#mainWallet").hide(); + $("#pairDevice").show(); + + location.reload(); + + }); - $("#loginpinno").val(''); - $("#enterpinalert").show(); - $("#enterpinalertmessage").text(ekeyv); + } else { + + $("#loginpinno").val(''); + pinlock = false; + $('.numdone').attr("style", "background-color:white"); + $("#paddel").hide(); + + if (ekeyv.substring(0, 6) == "ErrPIN") { + + var attempts = ekeyv.substring(7, 8); + + $("#pinloginmessage").text("Incorrect PIN " + attempts + "/3 attempts"); - $('.numdone').attr("style", "background-color:white"); + $("#pincounter").effect("shake"); + + } else { + + bootbox.alert(ekeyv); + + } + + + } } @@ -424,2735 +428,3160 @@ function UI() { - function closeSendNet() { + //device paring + var deviceName = ''; + var regToken = ''; + var secret = ''; + var enck = ''; + var iv = ''; - //$("#dashprofile").show(); - $("#dashsend").hide(); - $("#dashsendamt").hide(); - $("#mainWallet").show(); - if (sendmode == "net") { - $("#friendheader").show(); - } + function pairDevice() { - $(".footer").show(); - $("#dashreceive").hide(); - $("#dashcontact").hide(); + var blob = $('#pairdeviceblob').val(); + var pwd = $('#pairpwd').val(); - $("#pinconfirm").hide(); + var splitBlob = blob.split('|'); - $("#btnStdSndDone").hide(); + console.log(splitBlob.length); + if (splitBlob.length == 5) { - $('#toAddress').val(''); - $('#amount').text(''); + var guid = splitBlob[2]; - updateStdAmount(); + enck = splitBlob[0]; + iv = splitBlob[1]; + deviceName = splitBlob[3]; + regToken = splitBlob[4]; - } + Engine.setPass(pwd, guid); + var bytes = []; + for (var i = 0; i < guid.length; ++i) { + bytes.push(guid.charCodeAt(i)); + } - function closeSendStd() { + var hashguid = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - //$("#dashprofile").show(); - $("#dashsend").hide(); - $("#dashsendamt").hide(); - $("#dashheader").show(); - $("#mainWallet").show(); - $(".footer").show(); - $("#dashreceive").hide(); - $("#dashcontact").hide(); + Engine.m_guid = hashguid; + Engine.m_oguid = guid; - $("#pinconfirm").hide(); + //first validate the password with the secret - $("#addrfade").hide(); + Engine.getRecoveryPacket(function (err, response) { - $("#btnStdSndDone").hide(); + if (err) { + bootbox.alert("There was an error, please try again."); - //profilepagestate = "send"; - //menustate = "profile" - $('#toAddress').val(''); - $('#amount').text(''); - updateStdAmount(); + } else { - } + //decrypt packet - var stdAmountConvCoin = true; - var netAmountConvCoin = true; + var jpacket = JSON.parse(response); - function convertToLocalCurrency(amount) { + secret = Engine.decryptNp(jpacket.packet, Engine.m_password, jpacket.IV); - var conv = amount; - conv = conv * 1.0; + Engine.validateSecret(secret, function (err, secvalid) { - var sats = convertToSatoshis(conv, COINUNIT); - var btc = convertFromSatoshis(sats, "BTC"); + if (!err) { - var cbtc = btc * price; + if (secvalid) { + //show pin screen + $('#pairDevice').hide(); + $('#loginpin').show(); - var loc = "en-US"; - var ires = cbtc; + } + + } else { + + if (secvalid == "ErrAccount") { + bootbox.alert("Password not correct"); + } else if (secvalid == "ErrLocked") { + bootbox.alert("The account is locked"); + } else { + bootbox.alert("There was an error, please try again"); + } + + } + + }); + + } + + }); - if (Engine.m_settings.LocalCurrency == "JPY") { - ires = (cbtc * 1.0).toFixed(0) * 1.0; } else { - ires = (cbtc * 1.0).toFixed(2) * 1.0; + + bootbox.alert("There was a pairing error, please try again."); + + // $('#pairdevicealertmessage').text("There was a pairing error"); + //$('#pairdevicealert').show(); } + } - var cprc = ires.toLocaleString(loc, { style: "currency", currency: Engine.m_settings.LocalCurrency }); - return cprc; + function regPIN() { - } - function convertFromLocalCurrency(amount) { + $("#pairspinner").show(); + var target = document.getElementById('pairspinner'); + var spinner = new Spinner(spinneropts).spin(target); - var conv = amount; - conv = conv * 1.0; + $('#loginpin').hide(); - //convert to bitcoin - if (price > 0) { - var cbtc = conv / price; - var sats = convertToSatoshis(cbtc, "BTC"); - var btc = convertFromSatoshis(sats, COINUNIT); - return btc; - } else { - return 0; + //hash the pin and device id + var deviceid = "DEVICE123456789"; + if (window.cordova) { + deviceid = window.device.uuid; } - } - function updateStdAmount() { + var pin = $("#loginpinno").val(); - var asamt = $('#amount').text(); - if (asamt == '' || asamt == '.') { - asamt = 0; + var pinhash = deviceid + pin; + bytes = []; + for (var i = 0; i < pinhash.length; ++i) { + bytes.push(pinhash.charCodeAt(i)); } - if (stdAmountConvCoin) { - $('#ccystdamt').text(convertToLocalCurrency(asamt)); - $('#hdamount').val(asamt); - } - else { - var amt = convertFromLocalCurrency(asamt); - $('#hdamount').val(amt); - $('#ccystdamt').text(amt + ' ' + COINUNIT); - } + pinhash = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - } + //new register device - var profilepagestate = ''; - var networkpagestate = ''; - var friendpagestate = ''; - var menustate = ''; - var cl = ''; + //enter password + //stretch + //get validate + //if valid + //choose a PIN + //register - jQuery(document).ready(function () { - var $body = jQuery('body'); + var devplatform = "platform"; + var devmodel = "model"; + if (window.cordova) { + devplatform = window.device.platform; + devmodel = window.device.model; + } - //guid - //ninki_reg - //if device is paired then + Engine.registerDevice(Engine.m_guid, deviceName, devplatform, devmodel, pinhash, regToken, secret, function (err, result) { + if (!err) { - getCookie("ninki_reg", function (reg) { + var dk = JSON.parse(result); - if (reg) { - $("#loginpin").show(); - } else { - $("#pairDevice").show(); - } + if (dk.DeviceKey.length > 0) { - }); + var decblob = Engine.decryptNp(enck, dk.DeviceKey, iv); + //slice it up + //64 64 64 + var hk = decblob.substring(0, 64); + var fatoken = decblob.substring(64, 128); - $("#mainWallet").hide(); - $("#dashreceive").hide(); - $("#dashcontact").hide(); + var encp = Engine.encryptNp(Engine.m_password, dk.DeviceKey); + result = ''; + var ptok = {}; + ptok.ct = encp.toString(); + ptok.iv = encp.iv.toString(); + var ptoken = JSON.stringify(ptok); - $("#addcontactmodal").hide(); + var enc = Engine.encryptNp(fatoken, dk.DeviceKey); + var ctok = {}; + ctok.ct = enc.toString(); + ctok.iv = enc.iv.toString(); - $('#stdselcu').click(function () { + var ctoken = JSON.stringify(ctok); - var amttarget = '#amount'; - $('#stdselunit').text(COINUNIT); - stdAmountConvCoin = true; - $(amttarget).text(''); - updateStdAmount(); + var ench = Engine.encryptNp(hk, dk.DeviceKey); + var htok = {}; + htok.ct = ench.toString(); + htok.iv = ench.iv.toString(); - }); + var hkey = JSON.stringify(htok); - $('#stdsellc').click(function () { + dk.DeviceKey = ''; + //login using the credentials + //get a session + //then call register PIN + //this will return the encryption key + //encrypt the password and store in local storage - var amttarget = '#amount'; + Engine.Device.setStorageItem("guid", Engine.m_oguid); - $('#stdselunit').text(Engine.m_settings.LocalCurrency); - stdAmountConvCoin = false; - $(amttarget).text(''); - updateStdAmount(); + Engine.openWallet(Engine.m_oguid, fatoken, function (err, result) { + if (!err) { - }); + if (!result.TwoFactorOnLogin) { + Engine.Device.setStorageItem("ninki_rem", ctoken); + Engine.Device.setStorageItem("ninki_p", ptoken); + Engine.Device.setStorageItem("ninki_reg", regToken); + Engine.Device.setStorageItem("ninki_h", hkey); - // $('.numc').bind('touchstart', function () { - // $(this).removeClass('numtapoff'); + $("#loginpinno").val(''); + pinlock = false; + $("#paddel").hide(); + $('.numdone').attr("style", "background-color:white"); - // cl = 'b' + (Math.floor(Math.random() * 6) + 1) + ''; - // //alert(cl); - // $(this).addClass(cl); + var t = Engine.m_settings.LocalCurrency; - // }); + $('.sccy').filter(function () { + return $(this).text().trim() == t; + }).find("label").html(''); + var tc = Engine.m_settings.CoinUnit; + $('.scoinunit').filter(function () { + return $(this).text().trim() == tc; + }).find("label").html(''); - $('.scoinunit').bind('click', function () { - $('.scoinunit').find("label").html(''); + isPairing = false; - $(this).find("label").html(''); + //callback here before displaying - var sel = $.trim($(this).text()); - setCookie("coinunit", sel); - Engine.m_settings.CoinUnit = sel; + initialiseDashboard(function () { - COINUNIT = sel; + Engine.m_appInitialised = true; - updateUI(); + $("#pairspinner").hide(); + $('#dashboard').show(); + $('#dashheader').show(); - }); + $("#footermode").val(1); + $("#mainWallet").show(); + $(".footer").show(); + }); + } else { + $("#pairspinner").hide(); + bootbox.alert("Could not pair", function () { + location.reload(); + }); - $('.sccy').bind('click', function () { + } - $('.sccy').find("label").html(''); + } else { + $("#pairspinner").hide(); + bootbox.alert(result, function () { - $(this).find("label").html(''); + location.reload(); - var sel = $.trim($(this).text()); + }); - setCookie("currency", sel); + } - Engine.m_settings.LocalCurrency = sel; + }); + } else { + $("#pairspinner").hide(); + bootbox.alert("The pairing token has expired", function () { - updateUI(); + location.reload(); - }); + }); + } - $('.numc').bind('touchend', function () { + } else { - var num = $(this); - var text = $.trim(num.find('.txt').clone().children().remove().end().text()); + $("#pairspinner").hide(); + bootbox.alert(result, function () { - var amttarget = '#amount'; + location.reload(); - var amt = $(amttarget).text(); + }); - if (!(amt.indexOf(".") > -1 && text == '.')) { + } - var prev = amt.substring(0, amt.length - 1); + }); - if (text.length > 0) { - $(amttarget).text($(amttarget).text() + text); - } else { - $(amttarget).text(prev); - } + secret = ''; - updateStdAmount(); + } - } - }); - var pintaps = 0; - var prevpin = ''; - //touchend - $('#loginpin .num').bind('touchstart', function () { + function closeSendNet() { - var num = $(this); - var text = $.trim(num.find('.txt').clone().children().remove().end().text()); - if (text.length > 0) { - pintaps++; + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - if (pintaps == 1) { - $('#loginpin #pin1').attr("style", "background-color:Gray"); + $("#dashsendamt").addClass("invis"); + $("#dashsendamt").removeClass("slideUp"); + $("#dashsendamt").hide(); - } + $("#mainWallet").show(); - if (pintaps == 2) { + if (sendmode == "net" || sendmode == "inv") { + $("#friendheader").show(); + } else { + $('#dashboard').show(); + $('#dashheader').show(); - $('#loginpin #pin2').attr("style", "background-color:Gray"); + } - } + $(".footer").show(); - if (pintaps == 3) { - $('#loginpin #pin3').attr("style", "background-color:Gray"); + $("#dashreceive").addClass("invis"); + $("#dashreceive").removeClass("slideUp"); - } + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); - if (pintaps == 4) { + //$("#dashreceive").hide(); + //$("#dashcontact").hide(); - $('#loginpin #pin4').attr("style", "background-color:Gray"); + $("#pinconfirm").hide(); - } + $("#btnStdSndDone").hide(); - } + $('#toAddress').val(''); + sendAmount = ''; + updateStdAmount(); - var loginpinno = $('#loginpinno'); - var lpin = loginpinno.val(); - prevpin = lpin.substring(0, lpin.length - 1) + } - if (text.length > 0) { - $('#paddel').show(); + function closeSendStd() { + $("#dashsend").removeClass("slideUp"); + $("#dashsend").addClass("invis"); - $(loginpinno).val(loginpinno.val() + text); + $("#dashsendamt").removeClass("slideUp"); + $("#dashsendamt").addClass("invis"); + $("#dashsendamt").hide(); - if (pintaps == 4) { + $('#dashboard').show(); + $('#dashheader').show(); - pintaps = 0; + $("#mainWallet").show(); + $(".footer").show(); - loginPIN(); - //only if fail + $("#dashreceive").removeClass("slideUp"); + $("#dashreceive").addClass("invis"); - } + $("#dashcontact").removeClass("slideUp"); + $("#dashcontact").addClass("invis"); + //$("#dashreceive").hide(); - } else { + //$("#dashcontact").hide(); + $("#pinconfirm").hide(); + $("#addrfade").hide(); - if (pintaps == 1) { + $("#btnStdSndDone").hide(); - $('#loginpin #pin1').attr("style", "background-color:White"); - $('#loginpin #paddel').hide(); - } + //profilepagestate = "send"; + //menustate = "profile" - if (pintaps == 2) { + $('#toAddress').val(''); - $('#loginpin #pin2').attr("style", "background-color:White"); + sendAmount = ''; - } + updateStdAmount(); - if (pintaps == 3) { + } - $('#loginpin #pin3').attr("style", "background-color:White"); + var stdAmountConvCoin = true; + var netAmountConvCoin = true; - } + function convertToLocalCurrency(amount) { - if (pintaps == 4) { + var conv = amount; + conv = conv * 1.0; - $('#loginpin #pin4').attr("style", "background-color:White"); + var sats = convertToSatoshis(conv, COINUNIT); + var btc = convertFromSatoshis(sats, "BTC"); - } + var cbtc = btc * price; - $(loginpinno).val(prevpin); + var loc = "en-US"; + var ires = cbtc; - if (pintaps > 0) { - pintaps--; - } + if (Engine.m_settings.LocalCurrency == "JPY") { + ires = (cbtc * 1.0).toFixed(0) * 1.0; + } else { + ires = (cbtc * 1.0).toFixed(2) * 1.0; + } - } + var loc = "en-US"; + var cprc = ""; + if (Engine.m_settings.LocalCurrency == "JPY" || Engine.m_settings.LocalCurrency == "CNY") { + cprc = accounting.formatMoney(ires, "¥", 0); + } else if (Engine.m_settings.LocalCurrency == "GBP") { + cprc = accounting.formatMoney(ires, "£", 2); + } else if (Engine.m_settings.LocalCurrency == "EUR") { + cprc = accounting.formatMoney(ires, "€", 2); + } else if (Engine.m_settings.LocalCurrency == "USD") { + cprc = accounting.formatMoney(ires, "$", 2); + } else if (Engine.m_settings.LocalCurrency == "CNY") { + cprc = accounting.formatMoney(ires, "¥", 2); + } + return cprc; - }); + } - $('#pinconfirm .num').bind('touchend', function () { + function convertFromLocalCurrency(amount, format) { - var num = $(this); - var text = $.trim(num.find('.txt').clone().children().remove().end().text()); - var loginpinno = $('#sendstdpin'); - var lpin = loginpinno.val(); - prevpin = lpin.substring(0, lpin.length - 1) + var conv = amount; + conv = conv * 1.0; - if (text.length > 0) { - $('#paddelconf').show(); - pintaps++; - if (pintaps == 1) { + //convert to bitcoin + if (price > 0) { + var cbtc = conv / price; - $('#pinconfirm #cpin1').attr("style", "background-color:Gray"); + var sats = convertToSatoshis(cbtc, "BTC"); - } + var dp = 4; + if (sats > 0 && sats < 10000) { + dp = 8; + } - if (pintaps == 2) { - $('#pinconfirm #cpin2').attr("style", "background-color:Gray"); + var btc = convertFromSatoshis(sats, COINUNIT); - } - if (pintaps == 3) { + if (format) { + if (COINUNIT == "BTC") { - $('#pinconfirm #cpin3').attr("style", "background-color:Gray"); + btc = accounting.formatMoney(btc, "", dp); } - if (pintaps == 4) { + if (COINUNIT == "Bits") { - $('#pinconfirm #cpin4').attr("style", "background-color:Gray"); + btc = accounting.formatMoney(btc, "", 0); } + } else { + if (COINUNIT == "BTC") { + var dpr = 4; + if (sats > 0 && sats < 10000) { + dpr = 8; + } - $(loginpinno).val(loginpinno.val() + text); + btc = accounting.toFixed(btc, dpr); + } - if (pintaps == 4) { + if (COINUNIT == "Bits") { + var dpr = 0; + if (sats > 0 && sats < 10000) { + dpr = 2; + } + btc = accounting.toFixed(btc, dpr); + } + } - pintaps = 0; + return btc; - if (sendmode == 'std') { + } else { - sendMoneyStd(); + return 0; - } else if (sendmode == 'net') { + } - sendMoney(SELECTEDFRIEND, 0); - } else if (sendmode == 'inv') { + } - payInvoice(selectedInvoiceUserName, selectedInvoiceAmount, selectedInvoiceId); - } + var sendAmount = ''; + function updateStdAmount() { + //vamout will track the value + //hdamount.val is the value actually used as an + // input to the transaction - //only if fail - } + //if the input value is decimal . or empty + //set to 0 + + var vAmount = 0; + if (sendAmount == '' || sendAmount == '.') { + vAmount = 0; + } else { + vAmount = sendAmount; + } + vAmount = vAmount * 1; + if (sendAmount == '') { + + //default entry box and actual value in the case of no input + $('#amount').text('Enter amount'); + if (stdAmountConvCoin) { + $('#ccystdamt').html(convertToLocalCurrency(0)); } else { + $('#ccystdamt').html(convertFromLocalCurrency(0) + ' ' + COINUNIT); + } + $('#hdamount').val('0'); + } else { + if (stdAmountConvCoin) { - if (pintaps == 1) { + //amounts are being input in a Bitcoin denomination + //so we convert to local currenct - $('#pinconfirm #cpin1').attr("style", "background-color:White"); - $('#pinconfirm #paddelconf').hide(); + $('#ccystdamt').html(convertToLocalCurrency(vAmount)); + //convert bitcoin amount to number + $('#hdamount').val(vAmount * 1.0); - } + var cprc = 0; + if (COINUNIT == "Bits") { - if (pintaps == 2) { + //default bits to 0 decimal places + cprc = accounting.formatMoney(sendAmount, "", 0); - $('#pinconfirm #cpin2').attr("style", "background-color:White"); + } else { - } - if (pintaps == 3) { + var indot = sendAmount.indexOf('.'); - $('#pinconfirm #cpin3').attr("style", "background-color:White"); + //if the input is the beginning of input entry + //apply no formatting + if (sendAmount == '.' || sendAmount == '0.' || sendAmount == '0') { - } + cprc = sendAmount; - if (pintaps == 4) { + } + else if (indot == sendAmount.length - 1) { + //if the user has just enetered a decimal point + //format the number and add on the decimal for display + cprc = accounting.formatMoney(sendAmount, "", 0) + '.'; + } + else { + //if there is no decimal point apply formatting + //with 0 dp + if (indot == -1) { + + cprc = accounting.formatMoney(sendAmount, "", 0); + + } else { + + //allow bitcoin entry up to 6 decimal places + var ramt = Math.min(sendAmount.length - indot, 6); + ramt = ramt - 1; + cprc = accounting.formatMoney(sendAmount, "", ramt); + } + + } - $('#pinconfirm #cpin4').attr("style", "background-color:White"); } - $(loginpinno).val(prevpin); + var fee = convertFromSatoshis(Engine.m_settings.MinersFee, COINUNIT); + if (currentBalance >= (vAmount + fee) && vAmount > 0) { - if (pintaps > 0) { - pintaps--; + $('#btnsendmoneystd').removeClass("disabled"); + + } else { + + $('#btnsendmoneystd').removeClass("disabled"); + $('#btnsendmoneystd').addClass("disabled"); } + $('#amount').text(cprc); } + else { - }); + //entry is in local currency + //so we need to convert to coin units and also format + //the currency input + + var amt = convertFromLocalCurrency(vAmount); + var amtfmt = convertFromLocalCurrency(vAmount, true); + amt = amt * 1.0; + + $('#hdamount').val(amt); + + $('#ccystdamt').text(amtfmt + ' ' + COINUNIT); + + var symb = ''; + if (Engine.m_settings.LocalCurrency == "JPY" || Engine.m_settings.LocalCurrency == "CNY") { + symb = "¥"; + } else if (Engine.m_settings.LocalCurrency == "GBP") { + symb = "£"; + } else if (Engine.m_settings.LocalCurrency == "EUR") { + symb = "€"; + } else if (Engine.m_settings.LocalCurrency == "USD") { + symb = "$"; + } else if (Engine.m_settings.LocalCurrency == "CNY") { + symb = "¥"; + } - $("#btnmenuprofile").bind('touchstart', function () { + var cprc = ''; - displayProfile(); + var indot = sendAmount.indexOf('.'); - }); + if (sendAmount == '.' || sendAmount == '0.' || sendAmount == '0') { + cprc = symb + sendAmount; + } + else if (indot == sendAmount.length - 1) { - function displayProfile() { + cprc = accounting.formatMoney(sendAmount, symb, 0) + '.'; + } + else { + if (indot == -1) { - if (menustate != 'profile') { - menustate = 'profile'; - $("#settings").hide(); - $("#settingsheader").hide(); + cprc = accounting.formatMoney(sendAmount, symb, 0); + } else { - $("#network").hide(); - $("#networklistheader").hide(); - $("#friendheader").hide(); - $("#dashboard").show(); + var ramt = Math.min(sendAmount.length - indot, 2); - $('#dashheader').show(); - //$("#invoices").hide(); + cprc = symb + sendAmount - } else { - profilehome(); - } + } - $("#btnmenusettings").attr('style', 'background-color:#ffffff'); - $("#btnmenunetwork").attr('style', 'background-color:#ffffff'); - $("#btnmenuprofile").attr('style', 'background-color:#eaeef1'); + } - } + var fee = convertFromSatoshis(Engine.m_settings.MinersFee, COINUNIT); + if (currentBalance >= (amt + fee) && amt > 0) { - var hastouched = false; - $("#btnmenunetwork").bind('touchstart', function () { + $('#btnsendmoneystd').removeClass("disabled"); - if (!hastouched) { + } else { - hastouched = true; + $('#btnsendmoneystd').removeClass("disabled"); + $('#btnsendmoneystd').addClass("disabled"); + } - var target = document.getElementById('myfrndspin'); - var spinner = new Spinner(spinneropts).spin(target); - $("#myfrndspin").show(); - updateFriends(function (err, res) { - $("#myfrndspin").hide(); + $('#amount').html(cprc); + } + } - }); + } - loadInvoices(); - } + var profilepagestate = ''; + var networkpagestate = ''; + var friendpagestate = ''; + var menustate = ''; - displayNetwork(); + var cl = ''; + var scrolling = false; + var scrollingnettran = false; + var scrollingnetlist = false; - }); + jQuery(document).ready(function () { + var $body = jQuery('body'); - function displayNetwork() { - if (menustate != "network") { + $("#dashboard").on("scroll", function () { + scrolling = true; + }); - menustate = "network"; - $("#settings").hide(); - $("#settingsheader").hide(); - $("#dashboard").hide(); - $('#dashheader').hide(); - //$("#pnlfriend").hide(); - $("#network").show(); + $("#dashboard").on("touchstart", function () { + scrolling = false; - if ($("#networklist").is(':visible')) { - $("#networklistheader").show(); - } + }); - if ($("#pnlfriend").is(':visible')) { - $("#friendheader").show(); - } + $("#pnlfriend").on("scroll", function () { + scrollingnettran = true; + }); - //$("#networklist").show(); + $("#pnlfriend").on("touchstart", function () { - if (networkpagestate == "invoice") { + scrollingnettran = false; + }); - //$("#invoices").show(); - } + $("#networklist").on("scroll", function () { + scrollingnetlist = true; + }); - } else { + $("#networklist").on("touchstart", function () { - networkhome(); - } + scrollingnetlist = false; - $("#btnmenusettings").attr('style', 'background-color:#ffffff'); - $("#btnmenuprofile").attr('style', 'background-color:#ffffff'); - $("#btnmenunetwork").attr('style', 'background-color:#eaeef1'); - } + }); - $("#invformelink").hammer(null).bind("tap", function () { + bootbox.setDefaults({ 'backdrop': false, 'animate': true }); - sendmode = "inv"; - $("#invformetab").show(); - $("#invbymetab").hide(); - $("#liby").removeClass('active'); - $("#lifor").addClass('active'); - }); + //guid + //ninki_reg - $("#invbymelink").hammer(null).bind("tap", function () { - $("#invbymetab").show(); - $("#invformetab").hide(); - $("#lifor").removeClass('active'); - $("#liby").addClass('active'); - }); + //if device is paired then - //tapsendfriend - //tapinvoicefriend + Engine.Device.getStorageItem("ninki_reg", function (reg) { - //tapnetpayments + if (reg) { + isPairing = false; + $("#loginpin").show(); + $("#pinimage").show(); - $("#tapnetpayments").hammer(null).bind("tap", function () { - $("#pnlfriendinv").hide(); - $("#networkpayments").show(); - $("#networksend").hide(); - networkpagestate = "friend"; - friendpagestate = "payments"; + } else { + isPairing = true; + $("#pairDevice").show(); + $("#pinpair").show(); + } }); - $("#tapinvoicefriend").hammer(null).bind("tap", function () { + $("#mainWallet").hide(); - $("#pnlfriendinv").show(); - $("#networkpayments").hide(); - $("#networksend").hide(); - networkpagestate = "friend"; - friendpagestate = "invoice"; + //$("#dashreceive").hide(); + //$("#dashcontact").hide(); - }); - function networkhome() { - if (networkpagestate == "invoice") { + $("#addcontactmodal").hide(); - $('#network').show(); - $("#pnlfriend").show(); - $("#friendheader").show(); - $('#invoices').hide(); - networkpagestate = "friend"; - friendpagestate = "invoice"; + $('#stdselcu').click(function () { - } else { + sendAmount = ''; - $("#pnlfriend").hide(); - $("#friendheader").hide(); - $("#network").show(); - $("#networklist").show(); - $("#networklistheader").show(); + $('#stdselunit').text(COINUNIT); - networkpagestate = ""; - } - } + stdAmountConvCoin = true; - function profilehome() { + updateStdAmount(); + }); - $("#dashprofile").show(); - $("#dashsend").hide(); - $("#dashreceive").hide(); - $("#dashcontact").hide(); - $('#invoices').hide(); - $("#dashboard").show(); - $('#dashheader').show(); - $("#network").hide(); - profilepagestate = ""; - } + $('#stdsellc').click(function () { - $("#btnmenusettings").bind('touchstart', function () { + sendAmount = ''; - menustate = "settings"; + $('#stdselunit').text(Engine.m_settings.LocalCurrency); + stdAmountConvCoin = false; + + updateStdAmount(); - $("#settings").show(); - $("#settingsheader").show(); - $("#network").hide(); - $("#dashboard").hide(); - $('#dashheader').hide(); - $('#friendheader').hide(); - $('#networklistheader').hide(); - $("#btnmenusettings").attr('style', 'background-color:#eaeef1'); - $("#btnmenuprofile").attr('style', 'background-color:#ffffff'); - $("#btnmenunetwork").attr('style', 'background-color:#ffffff'); }); - $('#toAddress').change(function () { + // $('.numc').bind('touchstart', function () { + // $(this).removeClass('numtapoff'); - //if a valid bitcoin address then - //next stage - var addr = $('#toAddress').val(); + // cl = 'b' + (Math.floor(Math.random() * 6) + 1) + ''; + // //alert(cl); + // $(this).addClass(cl); - var paddr = parseBitcoinURL(addr); + // }); - if (addr.length > 25) { - if (Engine.isAddressValid(paddr.address)) { - //next stage - //if amount is included in the URL set the amount and go straight to the - //pay screen - $('#toAddress').val(paddr.address) + $('.scoinunit').bind('click', function () { - $("#dashsend").hide(); - $("#addrfade").hide(); - $("#dashsendamt").show(); + $('.scoinunit').find("label").html(''); + $(this).find("label").html(''); - } - } - }); + var sel = $.trim($(this).text()); + Engine.Device.setStorageItem("coinunit", sel); - $("#btnCloseContact").bind('touchstart', function () { + Engine.m_settings.CoinUnit = sel; - //closeSendStd(); - $("#dashcontact").hide(); - $("#mainWallet").show(); - $("#networklistheader").show(); - $(".footer").show(); + COINUNIT = sel; - }); + prevtransfeed = -1; + prevNetworkTransCount = -1; + updateUI(); - $("#btnAddContactDone").bind('touchstart', function () { + }); - $("#addcontactmodal").hide(); - $("#dashcontact").show(); - }); - $("#btnCloseStdSndAmt").bind('touchstart', function () { - closeSendNet(); + $('.sccy').bind('click', function () { - }); + $('.sccy').find("label").html(''); - $("#btnCloseStdSndPIN").bind('touchstart', function () { + $(this).find("label").html(''); - if (sendmode == "std") { - closeSendStd(); - } else { - closeSendNet(); - } + var sel = $.trim($(this).text()); - }); + Engine.Device.setStorageItem("currency", sel); - $("#btnCloseStdSnd").bind('touchstart', function () { + Engine.m_settings.LocalCurrency = sel; - closeSendStd(); + updateUI(); }); - $("#btnCloseRec").bind('touchstart', function () { - - closeSendStd(); - }); + $('.numc').bind('touchend', function () { - $("#btnStdSndDone").bind('touchstart', function () { + var num = $(this); + var text = $.trim(num.find('.txt').clone().children().remove().end().text()); - $('#sendprogress').hide(); + //check the number of decimal places and if more than 8 for btc + if (text.length > 0) { - if (sendmode == "std") { - closeSendStd(); - } else { - closeSendNet(); - } + if (stdAmountConvCoin) { - }); + if (sendAmount.indexOf(".") > -1) { - //$("#btnStdSndDone") + var ind = sendAmount.indexOf("."); - $("#btnsendmoneystd").bind('touchstart', function () { + if (COINUNIT == "BTC") { + if ((sendAmount.length - ind) == 7) { - if (sendmode == 'std') { - $("#sendstds2add").text($('#toAddress').val()); - } else if (sendmode == 'net') { - $("#sendstds2add").text(SELECTEDFRIEND); - } - $("#sendstds2amt").text($("#hdamount").val() + ' ' + COINUNIT); + return; - $("#dashsend").hide(); - $("#dashsendamt").hide(); - $("#pinconfirm").show(); + } + } - //sendMoneyStd(); + } - }); + } else { + if (sendAmount.indexOf(".") > -1) { + var ind = sendAmount.indexOf("."); - $("#btnCloseValidate").bind('touchstart', function () { + if ((sendAmount.length - ind) == 3) { - $("#friendheader").show(); - $("#mainWallet").show(); - $(".footer").show(); - $("#networkvalidate").hide(); + return; - }); + } - $("#tapvalidatefriend").bind('touchstart', function () { - $("#friendheader").hide(); - $("#mainWallet").hide(); - $(".footer").hide(); - $("#networkvalidate").show(); + } - }); + } - $("#tapsendfriend").bind('touchstart', function () { - sendmode = "net"; + } - $("#sendsubheading").text("send to " + SELECTEDFRIEND); - $("#btnStdSndDone").hide(); - $("#dashsend").hide(); - $("#addrfade").hide(); + if (!(sendAmount.indexOf(".") > -1 && text == '.')) { - $("#friendheader").hide(); - $("#dashsendamt").show(); + var prev = sendAmount.substring(0, sendAmount.length - 1); + if (text.length > 0) { + sendAmount = (sendAmount + '' + text); + } else { + sendAmount = prev; + } - $("#mainWallet").hide(); - $(".footer").hide(); + updateStdAmount(); + } - networkpagestate = "friend"; - friendpagestate = "send"; }); - $("#tapsend").bind('touchstart', function () { - - sendmode = "std" - - $("#dashheader").hide(); - $("#dashprofile").hide(); - $("#dashsend").show(); - - - setTimeout(function () { - $("#addrfade").fadeIn(500); - }, 500); - $("#dashsendamt").hide(); - $("#mainWallet").hide(); - $(".footer").hide(); + window.resetPin = function () { - $("#dashreceive").hide(); - $("#dashcontact").hide(); - $("#toAddress").blur(); - $("#qr").focus(); - $("#btnStdSndDone").hide(); + pintaps = 0; + prevpin = ''; - profilepagestate = "send"; - menustate = "profile" + }; + window.hasSession = function () { - }); + if (Engine.m_APIToken.length > 0) { - $("#tapreceive").bind('touchstart', function () { + return true; + } + return false; - //dashreceive - $("#dashheader").hide(); - $("#dashprofile").hide(); - $("#dashsend").hide(); - $("#mainWallet").hide(); - $("#dashreceive").show(); - $(".footer").hide(); - $("#dashcontact").hide(); - profilepagestate = "receive"; - menustate = "profile" + }; - }); - $("#taprequest").bind('touchstart', function () { - //$("#dashprofile").hide(); - //$("#dashsend").hide(); - //$("#dashreceive").hide(); - $("#mainWallet").hide(); - $("#networklistheader").hide(); - $("#dashcontact").show(); - $(".footer").hide(); - //checkAndValidateTimer = setInterval(function () { checkAndValidateFriendRequests() }, 2000); - //profilepagestate = "contact"; - //menustate = "profile" - }); + //touchend + $('#loginpin .num').bind('touchstart', function () { - $('#imgProfileContainer').show(); - $("#dropzone").hide(); - $("#btnSaveProfile").hide(); - $("#btnCancelProfile").hide(); - $("#statusedit").hide(); - $("#imgreset").hide(); + if (!pinlock) { - $("#btnEditProfile").bind('touchstart', function () { + if (pintaps < 4) { - key = ''; + var num = $(this); + var text = $.trim(num.find('.txt').clone().children().remove().end().text()); - $('#imgProfileContainer').hide(); - $("#dropzone").show(); - $("#btnSaveProfile").show(); - $("#btnCancelProfile").show(); - $("#btnEditProfile").hide(); - $("#statusedit").show(); - $("#profnmests").hide(); - $("#imgreset").show(); - $("#txtStatusText").val(Engine.m_statusText); + if (text.length > 0) { - }); + pintaps++; - $("#imgreset").bind('touchstart', function () { + if (pintaps == 1) { - Engine.m_profileImage = ""; - imgReset = true; + $('#loginpin #pin1').attr("style", "background-color:Gray"); - var imageSrc = "images/avatar/256px/Avatar-" + pad(Engine.m_nickname.length) + ".png"; + } - document.getElementById('imgProfile').src = imageSrc; - $('#imgProfileContainer').show(); - $('#dropzone').hide(); - $('progressNumber').text(''); - $("#imgreset").hide(); + if (pintaps == 2) { - }); + $('#loginpin #pin2').attr("style", "background-color:Gray"); - var imgReset = false; - $("#btnSaveProfile").bind('touchstart', function () { + } - //updateUserProfile + if (pintaps == 3) { - var statusText = $("#txtStatusText").val(); + $('#loginpin #pin3').attr("style", "background-color:Gray"); - if (key == '' && !imgReset) { - key = Engine.m_profileImage; - } + } - Engine.updateUserProfile(key, statusText, Engine.m_invoiceTax, function (err, result) { + if (pintaps == 4) { - if (!err) { + $('#loginpin #pin4').attr("style", "background-color:Gray"); - var imageSrc = "images/avatar/256px/Avatar-" + pad(Engine.m_nickname.length) + ".png"; - var imageSrcSmall = "images/avatar/64px/Avatar-" + pad(Engine.m_nickname.length) + ".png"; + } - if (key != '' && !imgReset) { - imageSrc = "https://ninkip2p.imgix.net/" + key + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - imageSrcSmall = "https://ninkip2p.imgix.net/" + key + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; } - $("#imgProfile").attr("src", imageSrc); - $("#imgtoprightprofile").attr("src", imageSrcSmall); - - $('#imgProfileContainer').show(); - $("#dropzone").hide(); - $("#btnSaveProfile").hide(); - $("#btnCancelProfile").hide(); - $("#btnEditProfile").show(); - $("#statusedit").hide(); - $("#mystatus").text(statusText); - $("#txtStatusText").val(statusText); - $("#profnmests").show(); - $("#imgreset").hide(); - imgReset = false; - $("#profileimgfile").val(''); - $("#progressNumber").val(''); - - } - - }); - }); - $("#btnCancelProfile").bind('touchstart', function () { - $('#imgProfileContainer').show(); - $("#dropzone").hide(); - $("#btnSaveProfile").hide(); - $("#btnCancelProfile").hide(); - $("#btnEditProfile").show(); + var loginpinno = $('#loginpinno'); + var lpin = loginpinno.val(); + prevpin = lpin.substring(0, lpin.length - 1); - //reset profile image + //if not delete + if (text.length > 0) { - var imageSrc = "images/avatar/256px/Avatar-" + pad(Engine.m_nickname.length) + ".png"; + $('#paddel').show(); - if (Engine.m_profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + Engine.m_profileImage + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - } + $(loginpinno).val(loginpinno.val() + text); - $("#imgProfile").attr("src", imageSrc); + if (pintaps == 4) { - $("#statusedit").hide(); - $("#profnmests").show(); - $("#imgreset").hide(); - }); + pintaps = 0; - var obj = $("#dropzone"); + if (!isPairing) { + loginPIN(); + } else { + regPIN(); + } - obj.click(function () { - $("#profileimgfile").click(); - }); + //only if fail - $("#profileimgfile").change(function (e) { + } - var control = document.getElementById("profileimgfile"); - var files = control.files; - //alert(files[0]); - //We need to send dropped files to Server - handleFileUpload(files, obj); - }); + } else { - obj.on('dragenter', function (e) { - e.stopPropagation(); - e.preventDefault(); - $(this).css('border', '2px solid #0B85A1'); - }); - obj.on('dragover', function (e) { - e.stopPropagation(); - e.preventDefault(); - }); - obj.on('drop', function (e) { + if (pintaps == 1) { - $(this).addClass("b-dashed"); - $(this).addClass("b-light"); - e.preventDefault(); - var files = e.originalEvent.dataTransfer.files; - //alert(files[0]); - //We need to send dropped files to Server - handleFileUpload(files, obj); - }); + $('#loginpin #pin1').attr("style", "background-color:White"); + $('#loginpin #paddel').hide(); + } - $(document).on('dragenter', function (e) { - e.stopPropagation(); - e.preventDefault(); - }); + if (pintaps == 2) { - $(document).on('dragover', function (e) { - e.stopPropagation(); - e.preventDefault(); - obj.css('border', '2px dotted #0B85A1'); - }); + $('#loginpin #pin2').attr("style", "background-color:White"); - $(document).on('drop', function (e) { - e.stopPropagation(); - e.preventDefault(); - }); + } - var key = ''; - function handleFileUpload(files, obj) { + if (pintaps == 3) { - if (files.length > 0) { - var file = files[0]; - var fd = new FormData(); + $('#loginpin #pin3').attr("style", "background-color:White"); - key = "images\/" + Engine.m_nickname + '_' + (new Date).getTime() + } - Ninki.API.post("/api/1/u/createS3Policy", { test: 'test' }, function (err, result) { + if (pintaps == 4) { - var policy = JSON.parse(result); + $('#loginpin #pin4').attr("style", "background-color:White"); - fd.append('key', key); - fd.append('acl', 'public-read'); - fd.append('Content-Type', file.type); - fd.append('bucket', 'ninkip2pimgstore'); - fd.append('AWSAccessKeyId', 'AKIAINOU56ATQFS3CLFQ'); - fd.append('policy', policy.s3Policy); - fd.append('signature', policy.s3Signature); - fd.append("file", file); - //fd.append("success_action_redirect", "https://localhost:1111/ok"); + } + $(loginpinno).val(prevpin); - var xhr = new XMLHttpRequest(); + if (pintaps > 0) { + pintaps--; + } - xhr.upload.addEventListener("progress", uploadProgress, false); - xhr.addEventListener("load", uploadComplete, false); - xhr.addEventListener("error", uploadFailed, false); - xhr.addEventListener("abort", uploadCanceled, false); + } + } - xhr.open('POST', 'https://ninkip2pimgstore.s3-us-west-1.amazonaws.com/', true); //MUST BE LAST LINE BEFORE YOU SEND + } + }); - xhr.send(fd); - }); - } - } + $('#pinconfirm .num').bind('touchend', function () { - function uploadProgress(evt) { - if (evt.lengthComputable) { - var percentComplete = Math.round(evt.loaded * 100 / evt.total); - document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%'; - } - else { - document.getElementById('progressNumber').innerHTML = 'unable to compute'; - } - } + //; - function uploadComplete(evt) { - /* This event is raised when the server send back a response */ - //alert("Done - " + evt.target.responseText); - document.getElementById('imgProfile').src = 'https://ninkip2p.imgix.net/' + key + "?fit=crop&crop=faces&h=128&w=128&mask=ellipse&border=1,d0d0d0"; - $('#imgProfileContainer').show(); - $('#dropzone').hide(); - $('progressNumber').text(''); - $("#imgreset").hide(); - } + var num = $(this); - function uploadFailed(evt) { - alert("There was an error attempting to upload the file." + evt); - } + var text = $.trim(num.find('.txt').clone().children().remove().end().text()); + var loginpinno = $('#sendstdpin'); + var lpin = loginpinno.val(); + prevpin = lpin.substring(0, lpin.length - 1); - function uploadCanceled(evt) { - alert("The upload has been canceled by the user or the browser dropped the connection."); - } + if (text.length > 0) { - }); + $('#paddelconf').show(); + pintaps++; + if (pintaps == 1) { - $(document).ready(function () { + $('#pinconfirm #cpin1').attr("style", "background-color:Gray"); + } - $("#pairdeviceblob").change(function () { + if (pintaps == 2) { - $("#loginpin").hide(); - $("#pairstep1").hide(); - $("#pairstep2").show(); + $('#pinconfirm #cpin2').attr("style", "background-color:Gray"); + } - }); + if (pintaps == 3) { + $('#pinconfirm #cpin3').attr("style", "background-color:Gray"); - $("#btnUnpair").click(function () { + } - //return; - getCookie("guid", function (guid) { + if (pintaps == 4) { - Engine.m_oguid = guid; + $('#pinconfirm #cpin4').attr("style", "background-color:Gray"); - var bytes = []; - for (var i = 0; i < guid.length; ++i) { - bytes.push(guid.charCodeAt(i)); } - Engine.m_guid = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); + $(loginpinno).val(loginpinno.val() + text); - Engine.destroyDevice(function (err, res) { - - deleteCookie("ninki_rem"); - deleteCookie("ninki_p"); - deleteCookie("ninki_reg"); - deleteCookie("ninki_h"); + if (pintaps == 4) { - //call to server - location.reload(); - }); + pintaps = 0; - }); + if (sendmode == 'std') { + sendMoneyStd(); - }); + } else if (sendmode == 'net') { + sendMoney(SELECTEDFRIEND, 0); - $("#btnPairDevice").bind('click', function () { + } else if (sendmode == 'inv') { - var deviceid = "DEVICE123456789"; + payInvoice(selectedInvoiceUserName, selectedInvoiceAmount, selectedInvoiceId); - if (window.cordova) { - deviceid = window.device.uuid; - } + } - var blob = $('#pairdeviceblob').val(); - var pin = $('#pairdevicepinnumber').val(); - var pwd = $('#pairpwd').val(); + //only if fail - var splitBlob = blob.split('|'); + } - var enck = splitBlob[0]; - var iv = splitBlob[1]; - var guid = splitBlob[2]; - var deviceName = splitBlob[3]; - var regToken = splitBlob[4]; + } else { - Engine.setPass(pwd, guid); - pwd = Engine.m_password; - var bytes = []; - for (var i = 0; i < guid.length; ++i) { - bytes.push(guid.charCodeAt(i)); - } + if (pintaps == 1) { - var hashguid = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); + $('#pinconfirm #cpin1').attr("style", "background-color:White"); + $('#pinconfirm #paddelconf').hide(); + } - Engine.m_guid = hashguid; - Engine.m_oguid = guid; + if (pintaps == 2) { - //first validate the password with the secret - Engine.getRecoveryPacket(function (err, response) { + $('#pinconfirm #cpin2').attr("style", "background-color:White"); - if (err) { + } - $('#pairdevicealertmessage').text(response); + if (pintaps == 3) { - } else { + $('#pinconfirm #cpin3').attr("style", "background-color:White"); - //decrypt packet + } - var jpacket = JSON.parse(response); + if (pintaps == 4) { - var secret = Engine.decryptNp(jpacket.packet, pwd, jpacket.IV); + $('#pinconfirm #cpin4').attr("style", "background-color:White"); - Engine.validateSecret(secret, function (err, secvalid) { + } - if (!err) { + $(loginpinno).val(prevpin); + if (pintaps > 0) { + pintaps--; + } - //hash the pin and device id - var pinhash = deviceid + pin; - bytes = []; - for (var i = 0; i < pinhash.length; ++i) { - bytes.push(pinhash.charCodeAt(i)); - } + } - pinhash = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); + }); - //new register device + $("#btnmenuprofile").bind('touchstart', function () { + displayProfile(); - //enter password - //stretch - //get validate - //if valid - //choose a PIN - //register + }); - var devplatform = "platform"; - var devmodel = "model"; - if (window.cordova) { - devplatform = window.device.platform; - devmodel = window.device.model; - } + function displayProfile() { - Engine.registerDevice(hashguid, deviceName, devplatform, devmodel, pinhash, regToken, secret, function (err, result) { + if (menustate != 'profile') { + menustate = 'profile'; + $("#settings").hide(); + $("#settingsheader").hide(); - if (!err) { - var dk = JSON.parse(result); + $("#network").hide(); + $("#networklistheader").hide(); + $("#friendheader").hide(); + $("#dashboard").show(); - if (dk.DeviceKey.length > 0) { + $('#dashheader').show(); + //$("#invoices").hide(); - var decblob = Engine.decryptNp(enck, dk.DeviceKey, iv); + } else { + profilehome(); + } - //slice it up - //64 64 64 - var hk = decblob.substring(0, 64); - var fatoken = decblob.substring(64, 128); + $("#btnmenusettings").attr('style', 'background-color:#ffffff'); + $("#btnmenunetwork").attr('style', 'background-color:#ffffff'); + $("#btnmenuprofile").attr('style', 'background-color:#eaeef1'); - var encp = Engine.encryptNp(pwd, dk.DeviceKey); - result = ''; + } - var ptok = {}; - ptok.ct = encp.toString(); - ptok.iv = encp.iv.toString(); - var ptoken = JSON.stringify(ptok); + var hastouched = false; + $("#btnmenunetwork").bind('touchstart', function () { - var enc = Engine.encryptNp(fatoken, dk.DeviceKey); - var ctok = {}; - ctok.ct = enc.toString(); - ctok.iv = enc.iv.toString(); + if (!hastouched) { - var ctoken = JSON.stringify(ctok); + hastouched = true; + var target = document.getElementById('myfrndspin'); + var spinner = new Spinner(spinneropts).spin(target); + $("#myfrndspin").show(); + updateFriends(function (err, res) { - var ench = Engine.encryptNp(hk, dk.DeviceKey); - var htok = {}; - htok.ct = ench.toString(); - htok.iv = ench.iv.toString(); + $("#myfrndspin").hide(); - var hkey = JSON.stringify(htok); + }); - dk.DeviceKey = ''; + loadInvoices(); - //login using the credentials - //get a session - //then call register PIN - //this will return the encryption key - //encrypt the password and store in local storage + } - setCookie("guid", guid); + displayNetwork(); - Engine.openWallet(guid, fatoken, function (err, result) { - if (!err) { + }); - if (!result.TwoFactorOnLogin) { - setCookie("ninki_rem", ctoken); - setCookie("ninki_p", ptoken); - setCookie("ninki_reg", regToken); - setCookie("ninki_h", hkey); + function displayNetwork() { - $('#pairDevice').hide(); + if (menustate != "network") { - initialiseDashboard(); + menustate = "network"; + $("#settings").hide(); + $("#settingsheader").hide(); + $("#dashboard").hide(); + $('#dashheader').hide(); + //$("#pnlfriend").hide(); + $("#network").show(); - } else { + if ($("#networklist").is(':visible')) { + $("#networklistheader").show(); + } - $('#pairdevicealertmessage').text("could not pair"); - $('#pairdevicealert').show(); - } + if ($("#pnlfriend").is(':visible')) { + $("#friendheader").show(); + } + //$("#networklist").show(); - } else { + if (networkpagestate == "invoice") { - $('#pairdevicealertmessage').text(result); - $('#pairdevicealert').show(); - } - }); - } else { + //$("#invoices").show(); + } - $('#pairdevicealertmessage').text("The pairing token has expired"); - $('#pairdevicealert').show(); - } + } else { + networkhome(); + } - } else { + $("#btnmenusettings").attr('style', 'background-color:#ffffff'); + $("#btnmenuprofile").attr('style', 'background-color:#ffffff'); + $("#btnmenunetwork").attr('style', 'background-color:#eaeef1'); + } - $('#pairdevicealertmessage').text(result); - $('#pairdevicealert').show(); - } + $("#invformelink").hammer(null).bind("tap", function () { - }); + sendmode = "inv"; + $("#invformetab").show(); + $("#invbymetab").hide(); + $("#liby").removeClass('active'); + $("#lifor").addClass('active'); + }); - } else { + $("#invbymelink").hammer(null).bind("tap", function () { + $("#invbymetab").show(); + $("#invformetab").hide(); + $("#lifor").removeClass('active'); + $("#liby").addClass('active'); + }); - $('#pairdevicealertmessage').text(secvalid); - $('#pairdevicealert').show(); - } + $("#tapnetpayments").hammer(null).bind("tap", function () { + $("#pnlfriendinv").hide(); + $("#networkpayments").show(); + $("#networksend").hide(); + networkpagestate = "friend"; + friendpagestate = "payments"; - }); + }); - } - }); + $("#tapinvoicefriend").hammer(null).bind("tap", function () { + $("#pnlfriendinv").show(); + $("#networkpayments").hide(); + $("#networksend").hide(); + networkpagestate = "friend"; + friendpagestate = "invoice"; }); + function networkhome() { + if (networkpagestate == "invoice") { - $("#btnaddfriend").bind('touchstart', function () { + $('#network').show(); + $("#pnlfriend").show(); + $("#friendheader").show(); + $('#invoices').hide(); + networkpagestate = "friend"; + friendpagestate = "invoice"; - addFriend($('input#friend').val()); - }); + } else { - $("#btngenaddr").bind('touchstart', function () { + $("#pnlfriend").hide(); + $("#friendheader").hide(); + $("#network").show(); + $("#networklist").show(); + $("#networklistheader").show(); - generateAddressClient(); + networkpagestate = ""; + } - }); + } + function profilehome() { - //wallet security wizard + $("#dashprofile").show(); - //$("#balance").text("... BTC"); + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - $("#btnSendToFriend").bind('touchstart', function () { + $("#dashreceive").addClass("invis"); + $("#dashreceive").removeClass("slideUp"); - sendMoney(SELECTEDFRIEND, 0); + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + //$("#dashreceive").hide(); + //$("#dashcontact").hide(); - }); + $('#invoices').hide(); + $("#dashboard").show(); + $('#dashheader').show(); + $("#network").hide(); + profilepagestate = ""; - $("#sendfriendprog").hide(); + } - $("#hdvalcontact").change(function () { + $("#btnmenusettings").bind('touchstart', function () { - console.log('caught event...'); + menustate = "settings"; - var res = $("#hdvalcontact").val(); - var sres = res.split(','); - var phrase = sres[0]; - var username = sres[1]; + $("#settings").show(); + $("#settingsheader").show(); + $("#network").hide(); + $("#dashboard").hide(); + $('#dashheader').hide(); + $('#friendheader').hide(); + $('#networklistheader').hide(); + $("#btnmenusettings").attr('style', 'background-color:#eaeef1'); + $("#btnmenuprofile").attr('style', 'background-color:#ffffff'); + $("#btnmenunetwork").attr('style', 'background-color:#ffffff'); + }); - $("#netvalidprognum").text('30%'); - $("#netvalidprogmess").text('Validating contact...'); - $("#netvalidprog").width('30%'); - setTimeout(function () { - var bip39 = new BIP39(); - code = bip39.mnemonicToHex(phrase); + $('#toAddress').change(function () { - console.log(code); + //if a valid bitcoin address then + //next stage + var addr = $('#toAddress').val(); + if (addr.indexOf('bitcoin:') == -1) { + addr = 'bitcoin:' + addr; + } - if (code.length != 40) { + var paddr = parseBitcoinURL(addr); - return; - } + if (addr.length > 25) { + if (Engine.isAddressValid(paddr.address)) { + //next stage + //if amount is included in the URL set the amount and go straight to the + //pay screen - //console.log(SELECTEDFRIEND); - //console.log(username); + $('#toAddress').val(paddr.address); - if (SELECTEDFRIEND == username) { + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - $("#netvalidp2").show(); - $("#netvalidp1").hide(); + $("#addrfade").hide(); - $("#netvalidprognum").text('50%'); - $("#netvalidprogmess").text('Validating contact...'); - $("#netvalidprog").width('50%'); + $("#dashsendamt").show(); + $("#dashsendamt").removeClass("invis"); + $("#dashsendamt").addClass("slideUp"); - setTimeout(function () { - Engine.verifyFriendData(SELECTEDFRIEND, code, function (err, result) { + } + } + }); - console.log(result); - if (result) { - $("#netvalidprognum").text('100%'); - $("#netvalidprogmess").text('Contact validated'); - $("#netvalidprog").width('100%'); + $("#btnCloseTran").bind('touchstart', function () { - //$("#validateform").hide(); - //$("#validatesuccess").show(); - $("#txtCode").val(''); - selectedFriend.validated = true; - FRIENDSLIST[selectedFriend.userName].validated = true; - updateSelectedFriend(); - $("#networkvalidate").hide(); - $("#friendheader").show(); - $("#mainWallet").show(); - $(".footer").show(); + $("#transview").removeClass("slideUp"); + $("#transview").addClass("invis"); - $("#netvalidp2").hide(); - $("#netvalidp1").show(); - //update list also + $("#mainWallet").show(); + $(".footer").show(); - //find friend in list and update the validated icon - $("#myfriends #seltarget" + selectedFriend.userName).html('
'); + if (transactionDetailMode == 'dashboard') { + $('#dashboard').show(); + $('#dashheader').show(); + } else { + $("#friendheader").show(); + } + }); - } else { - $("#netvalidp2").hide(); - $("#netvalidp1").show(); - $("#validatefail").show(); - } + $("#btnCloseContact").bind('touchstart', function () { - }); + //closeSendStd(); - }, 100); - } + //$("#dashcontact").hide(); + $("#dashcontact").removeClass("slideUp"); + $("#dashcontact").addClass("invis"); - }, 100); + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); }); - $("#btnVerify").bind('touchstart', function () { + $("#btnAddContactDone").bind('touchstart', function () { - var code = $("#txtCode").val(); + $("#addcontactmodal").hide(); + $("#dashcontact").show(); - $("#txtCode").css("border-color", "#ccc"); - $("#validatefail").hide(); - $("#validatesuccess").hide(); - var bip39 = new BIP39(); - code = bip39.mnemonicToHex(code); + }); - if (code.length != 40) { - $("#txtCode").css("border-color", "#ffaaaa"); - return; - } + $("#btnCloseStdSndAmt").bind('touchstart', function () { - //get the hash to validate against - //this will confirm that my friend has the same keys - //i orginally packaged for him + closeSendNet(); - Engine.verifyFriendData(SELECTEDFRIEND, code, function (err, result) { + }); - if (result) { + $("#btnCloseStdSndPIN").bind('touchstart', function () { - $("#txtCode").val(''); - selectedFriend.validated = true; - FRIENDSLIST[selectedFriend.userName].validated = true; - updateSelectedFriend(); - $("#networkvalidate").hide(); - $("#friendheader").show(); - $("#mainWallet").show(); - $(".footer").show(); - //update list also + if (sendmode == "std") { + closeSendStd(); + } else if (sendmode == "net") { + closeSendNet(); + } else { + $("#pinconfirm").hide(); + $("#invoices").show(); + } - //find friend in list and update the validated icon - $("#myfriends #seltarget" + selectedFriend.userName).html('
'); + }); + $("#btnCloseStdSnd").bind('touchstart', function () { - } else { - $("#validatefail").show(); - } + closeSendStd(); - }); }); + $("#btnCloseRec").bind('touchstart', function () { - //INVOICE STUFF START------------------------------------------ + closeSendStd(); - $("#friendselector").hide(); - $("#invoice").hide(); - $("#invoicedisplay").hide(); + }); - $("#btnpayinvoice").bind('touchstart', function () { + $("#btnStdSndDone").bind('touchstart', function () { + $('#sendprogress').hide(); - $(".footer").hide(); + $('#textMessageSendStd').text(''); + $('#textMessageSendStd').hide(); + $('#sendstdprogstatus').width('0'); + $('#sendstdprognum').text('0%'); + $('#sendstdprog').hide(); - $("#sendstds2add").text(SELECTEDFRIEND); + if (sendmode == "std") { + closeSendStd(); + } else if (sendmode == "net") { + closeSendNet(); + } else { + $("#mainWallet").show(); + $("#invoices").hide(); + $("#network").show(); + $("#pnlfriend").show(); + $("#friendheader").show(); + $(".footer").show(); + } - $("#sendstds2amt").text(convertFromSatoshis(selectedInvoiceAmount, COINUNIT) + ' ' + COINUNIT); + }); - sendmode = 'inv'; - $("#mainWallet").hide(); + $("#btnsendmoneystd").bind('touchstart', function () { + + + $('#paddelconf').hide(); + + $("#dashsendamt").hide(); $("#pinconfirm").show(); + if (sendmode == 'std') { + $("#sendstds2add").text($('#toAddress').val()); + } else if (sendmode == 'net') { + $("#sendstds2add").text(SELECTEDFRIEND); + } - }); + if (COINUNIT == "BTC") { + $("#sendstds2amt").text(accounting.formatNumber($("#hdamount").val(), 8, ",", ".") + ' ' + COINUNIT); + } else { + $("#sendstds2amt").text(accounting.formatNumber($("#hdamount").val(), 2, ",", ".") + ' ' + COINUNIT); + } - $("#btnrejectinvoice").bind('touchstart', function () { - Engine.updateInvoice(selectedInvoiceUserName, selectedInvoiceId, '', 2, function (err, result) { - loadInvoices(function (err, res) { + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - lastInvoiceToPayCount = 0; - showInvoiceListNetwork(); + $("#dashsendamt").addClass("invis"); + $("#dashsendamt").removeClass("slideUp"); - $("#invoicedisplay").hide(); - $("#invoicestopay").show(); - $("#createinv").show(); - updateSelectedFriend(); - }); - }); + //sendMoneyStd(); }); - $("#payinvoicecancel").bind('touchstart', function () { - + $("#btnCloseValidate").bind('touchstart', function () { - $("#invoices").hide(); - $("#network").show(); - $("#pnlfriend").show(); $("#friendheader").show(); - //if (uiInvoiceReturnToNetwork) { - //$("#hnetwork").click(); - //uiInvoiceReturnToNetwork = false; - //} + $("#mainWallet").show(); + $(".footer").show(); + $("#networkvalidate").hide(); + + }); + + $("#tapvalidatefriend").bind('touchstart', function () { + $("#friendheader").hide(); + $("#mainWallet").hide(); + $(".footer").hide(); + $("#networkvalidate").show(); }); - }); + $("#tapsendfriend").bind('touchstart', function () { + sendmode = "net"; - var lastInvoiceToPayNetCount = 0; - var uiInvoiceReturnToNetwork = false; + $("#sendsubheading").text("send to " + SELECTEDFRIEND); - var cachedInvoices = []; - var cachedInvoicesByUser = []; + $("#btnStdSndDone").hide(); + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - function showInvoiceListNetwork() { + $("#addrfade").hide(); - var invoices = _.filter(cachedInvoices, function (inv) { return inv.InvoiceFrom == SELECTEDFRIEND; }); + $("#friendheader").hide(); + $("#dashsendamt").show(); + $("#dashsendamt").removeClass("invis"); + $("#dashsendamt").addClass("slideUp"); - if (invoices.length == 0) { - $('#invfornet').empty(); - $('#invfornet').hide(); - } - //if (lastInvoiceToPayNetCount < invoices.length) { + $("#mainWallet").hide(); + $(".footer").hide(); - lastInvoiceToPayNetCount = invoices.length; - var s = ''; - $('#invfornet').empty(); + networkpagestate = "friend"; + friendpagestate = "send"; - for (var i = 0; i < invoices.length; i++) { + updateStdAmount(); - var invdate = new Date(invoices[i].InvoiceDate.match(/\d+/)[0] * 1); + }); - var timeLabel = prettydate.format(invdate); + $("#tapsend").bind('touchstart', function () { - var statusbox = ''; - if (invoices[i].InvoiceStatus == 0) { - statusbox = ' Pending'; - } - else if (invoices[i].InvoiceStatus == 1) { - statusbox = ' Paid'; - } - else if (invoices[i].InvoiceStatus == 2) { - statusbox = ' Rejected'; - } - - s += "
" + _.escape(timeLabel) + "
" + - "
" + statusbox + "
"; - } - - $('#invfornet').append(s); - - for (var i = 0; i < invoices.length; i++) { - - $("#invfornet #viewinvoicenetfrom" + invoices[i].InvoiceFrom + invoices[i].InvoiceId).hammer(null).bind("tap", { - index: invoices[i].InvoiceId, username: invoices[i].InvoiceFrom - }, function (event) { - - $("#invtapspinner").show(); - var target = document.getElementById('invtapspinner'); - var spinner = new Spinner(spinneropts).spin(target); + sendmode = "std"; + $("#sendsubheading").text(''); + $("#dashheader").hide(); + $("#dashprofile").hide(); + $("#dashboard").hide(); - displayInvoice(event.data.index, event.data.username, 'forme', function (err, res) { - uiInvoiceReturnToNetwork = true; + $("#dashsend").addClass("slideUp"); - networkpagestate = "invoice"; - friendpagestate = "invoice"; + //$("#dashsend").removeClass("invis"); - $("#invtapspinner").hide(); - $('#pnlfriend').hide(); - $("#friendheader").hide(); - $('#invoices').show(); - }); - }); - } + setTimeout(function () { + $("#addrfade").fadeIn(500); - $('#invfornet').show(); + }, 500); - //} + $("#dashsendamt").addClass("invis"); + $("#dashsendamt").removeClass("slideUp"); + $("#dashsendamt").hide(); - // $('#pnlfriendinv').show(); + $("#mainWallet").hide(); + $(".footer").hide(); + //$("#dashreceive").hide(); + //$("#dashcontact").hide(); - } + $("#toAddress").blur(); + $("#qr").focus(); + $("#btnStdSndDone").hide(); - var lastInvoiceByMeNetCount = 0; - function showInvoiceByMeListNetwork() { + profilepagestate = "send"; + menustate = "profile" - var invoices = _.filter(cachedInvoicesByUser, function (inv) { return inv.InvoiceFrom == SELECTEDFRIEND; }); - if (invoices.length == 0) { - $('#invbynet').empty(); - $('#invbynet').hide(); - } + }); + $("#tapreceive").bind('touchstart', function () { - if (lastInvoiceByMeNetCount < invoices.length) { - lastInvoiceByMeNetCount = invoices.length; - var s = ''; - $('#invbynet').empty(); + //dashreceive + $("#dashheader").hide(); + $("#dashprofile").hide(); - for (var i = 0; i < invoices.length; i++) { - var invdate = new Date(invoices[i].InvoiceDate.match(/\d+/)[0] * 1); + $("#mainWallet").hide(); - var timeLabel = prettydate.format(invdate); + $("#dashreceive").addClass("slideUp"); + $(".footer").hide(); - var statusbox = ''; - if (invoices[i].InvoiceStatus == 0) { - statusbox = ' Pending'; - } - else if (invoices[i].InvoiceStatus == 1) { - statusbox = ' Paid'; - } - else if (invoices[i].InvoiceStatus == 2) { - statusbox = ' Rejected'; - } + profilepagestate = "receive"; + menustate = "profile" - s += "
" + _.escape(timeLabel) + "
" + - "
" + statusbox + "
"; - } + setTimeout(generateAddressClient(), 1000); - $('#invbynet').append(s); - for (var i = 0; i < invoices.length; i++) { + }); - $("#invbynet #viewinvoicenetby" + invoices[i].InvoiceFrom + invoices[i].InvoiceId).hammer(null).bind("tap", { - index: invoices[i].InvoiceId, username: invoices[i].InvoiceFrom - }, function (event) { + $("#taprequest").bind('touchstart', function () { + $("#mainWallet").hide(); + $("#networklistheader").hide(); - $("#invtapspinner").show(); - var target = document.getElementById('invtapspinner'); - var spinner = new Spinner(spinneropts).spin(target); + $("#dashcontact").addClass("slideUp"); - displayInvoice(event.data.index, event.data.username, 'byme', function (err, res) { + //$("#dashcontact").show(); - networkpagestate = "invoice"; - friendpagestate = "invoice"; - $("#invtapspinner").hide(); - $('#pnlfriend').hide(); - $("#friendheader").hide(); - $('#invoices').show(); + $(".footer").hide(); - }); - }); - } + //checkAndValidateTimer = setInterval(function () { checkAndValidateFriendRequests() }, 2000); - $('#invbynet').show(); + //profilepagestate = "contact"; + //menustate = "profile" + }); - } + }); - // $('#pnlfriendinv').show(); + $(document).ready(function () { - } + $("#pairdeviceblob").change(function () { + if ($("#pairdeviceblob").val().length > 10) { - var selectedInvoiceAmount = 0; - var selectedInvoiceId = 0; - var selectedInvoiceUserName = ''; + var check = $("#pairdeviceblob").val().split('|'); + $("#pairdevicealert").hide(); - function displayInvoiceDetails(invoice, json, invtype, callback) { + if (check.length == 5) { + $("#loginpin").hide(); + $("#pairstep1").hide(); - var invdate = new Date(invoice.InvoiceDate.match(/\d+/)[0] * 1).toLocaleString(); - $("#createinv").hide(); - $("#invoicestopay").hide(); + $("#pairstep2").show(); + $("#pairpwd").focus(); - $('#tblinvdisplay tbody').empty(); - var s = ''; - for (var i = 0; i < json.invoicelines.length; i++) { - s += "" + _.escape(json.invoicelines[i].description) + "" + _.escape(json.invoicelines[i].quantity) + "" + _.escape(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT)) + "" + _.escape(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT) * json.invoicelines[i].quantity) + ""; - } + } else { - $('#tblinvdisplay tbody').append(s); + bootbox.alert("There was a pairing error, please try again."); - if (invtype == 'forme') { - $("#dinvusername").text('Invoice from ' + invoice.InvoiceFrom); - } else { - $("#dinvusername").text('Invoice to ' + invoice.InvoiceFrom); - } + } + } else { - $("#dinvdate").text(invdate); - $("#tblinvdisplay tfoot th #dsubtotal").text(convertFromSatoshis(json.summary.subtotal, COINUNIT)); - $("#tblinvdisplay tfoot th #dtax").text(convertFromSatoshis(json.summary.tax, COINUNIT)); - $("#tblinvdisplay tfoot th #dtotal").text(convertFromSatoshis(json.summary.total, COINUNIT)); + bootbox.alert("There was a pairing error, please try again."); - selectedInvoiceAmount = convertFromSatoshis(json.summary.total); - selectedInvoiceId = invoice.InvoiceId; - selectedInvoiceUserName = invoice.InvoiceFrom; + } - $("#sendinvprog").hide(); - $("#textMessageSendInv").hide(); - $("#btnokinvoice").hide(); - $("#invvalmess").hide(); - if (invtype == 'forme') { - if (invoice.InvoiceStatus == 0) { - $("#payinvoicecancel").show(); - $("#btnpayinvoice").show(); - $("#btnrejectinvoice").show(); + }); - if (!FRIENDSLIST[invoice.InvoiceFrom].validated) { - $("#btnpayinvoice").addClass("disabled"); - $("#invvalt").text(invoice.InvoiceFrom); - $("#invvalmess").show(); - } else { - $("#btnpayinvoice").removeClass("disabled"); - $("#invvalmess").hide(); - } - } + $("#btnUnpair").click(function () { - if (invoice.InvoiceStatus == 1 || invoice.InvoiceStatus == 2) { - $("#btnokinvoice").show(); - $("#payinvoicecancel").hide(); - $("#btnpayinvoice").hide(); - $("#btnrejectinvoice").hide(); - } - } else { - $("#btnokinvoice").show(); - $("#payinvoicecancel").hide(); - $("#btnpayinvoice").hide(); - $("#btnrejectinvoice").hide(); - } + bootbox.confirm("Are you sure?", function (result) { - var statusbox = ''; - if (invoice.InvoiceStatus == 0) { - statusbox = ' Pending'; - } - else if (invoice.InvoiceStatus == 1) { - statusbox = ' Paid'; - } - else if (invoice.InvoiceStatus == 2) { - statusbox = ' Rejected'; - } + if (result) { - $("#invdisstatus").html(statusbox); - $("#invdisid").text(invoice.InvoiceFrom.toUpperCase() + invoice.InvoiceId); + Engine.Device.getStorageItem("guid", function (guid) { + Engine.m_oguid = guid; - $("#invoicedisplay").show(); + var bytes = []; + for (var i = 0; i < guid.length; ++i) { + bytes.push(guid.charCodeAt(i)); + } - return callback(false, "ok"); - } + Engine.m_guid = Bitcoin.Crypto.SHA256(Bitcoin.convert.bytesToWordArray(bytes)).toString(); - function displayInvoiceByUser(invoiceid, username, invtype, callback) { + Engine.destroyDevice(function (err, res) { - var invoice = _.find(cachedInvoicesByUser, function (inv) { return inv.InvoiceId == invoiceid; }); + //call to server + location.reload(); - //here decrypt the invoice with my private key + }); - Engine.UnpackInvoiceByMe(invoice, username, function (err, unpacked) { + //always destroy locally + Engine.Device.deleteStorageItem("ninki_rem"); + Engine.Device.deleteStorageItem("ninki_p"); + Engine.Device.deleteStorageItem("ninki_reg"); + Engine.Device.deleteStorageItem("ninki_h"); + Engine.Device.deleteStorageItem("guid"); + Engine.Device.deleteStorageItem("coinunit"); + Engine.Device.deleteStorageItem("currency"); - displayInvoiceDetails(invoice, unpacked, invtype, function (err, res) { + }); - callback(false, "ok"); + } }); }); - } - + $("#btnPairDevice").bind('touchstart', function () { + $("#pairpwd").blur(); - function displayInvoice(invoiceid, username, invtype, callback) { + pairDevice(); - var invoice; - //find by invoicefrom and invoice id + }); - if (invtype == 'forme') { - invoice = _.find(cachedInvoices, function (inv) { return inv.InvoiceFrom == username && inv.InvoiceId == invoiceid; }); - } else { - invoice = _.find(cachedInvoicesByUser, function (inv) { return inv.InvoiceFrom == username && inv.InvoiceId == invoiceid; }); - } + $("#btnaddfriend").bind('touchstart', function () { - Engine.UnpackInvoiceForMe(invoice, username, invtype, function (err, unpacked) { + addFriend($('input#friend').val()); - displayInvoiceDetails(invoice, unpacked, invtype, function (err, res) { + }); - callback(false, "ok"); + $("#btngenaddr").bind('touchstart', function () { - }); + generateAddressClient(); }); - } + $("#btnSendToFriend").bind('touchstart', function () { - function payInvoice(friend, amount, invoiceNumber) { + sendMoney(SELECTEDFRIEND, 0); - var pin = $('#sendstdpin').val(); - Engine.getDeviceKey(pin, function (err, ekey) { + }); - if (!err) { + $("#sendfriendprog").hide(); - $('#sendprogress').show(); - $('#pinconfirm').hide(); + $("#btnVerify").bind('touchstart', function () { + var code = $("#txtCode").val(); - $('#textMessageSendStd').text('Creating transaction...'); - $('#textMessageSendStd').show(); - $('#sendstdprogstatus').width('3%') - $('#sendstdprog').show(); - $('#sendstdprogstatus').width('10%'); + $("#txtCode").css("border-color", "#ccc"); + $("#validatefail").hide(); + $("#validatesuccess").hide(); - $('#sendstdprognum').text('10%'); + var bip39 = new BIP39(); + code = bip39.mnemonicToHex(code); + if (code.length != 40) { + $("#txtCode").css("border-color", "#ffaaaa"); + return; + } - Engine.sendTransaction('invoice', friend, '', amount, ekey.DeviceKey, function (err, transactionid) { + //get the hash to validate against + //this will confirm that my friend has the same keys + //i orginally packaged for him - if (!err) { + Engine.verifyFriendData(SELECTEDFRIEND, code, function (err, result) { - Engine.updateInvoice(friend, invoiceNumber, transactionid, 1, function (err, result) { + if (result) { - if (!err) { + $("#txtCode").val(''); + selectedFriend.validated = true; + FRIENDSLIST[selectedFriend.userName].validated = true; + updateSelectedFriend(); + $("#networkvalidate").hide(); + $("#friendheader").show(); + $("#mainWallet").show(); + $(".footer").show(); + //update list also - $('#textMessageSend').text('You paid invoice: ' + friend.toUpperCase() + invoiceNumber); - $('input#amount').text(''); + //find friend in list and update the validated icon + $("#myfriends #seltarget" + selectedFriend.userName).html('
'); - updateStdAmount(); - setTimeout(function () { - $("#btnStdSndDone").show(); - }, 100); + } else { + $("#validatefail").show(); + } - $("#sendstdpin").val(''); - $('.numdone').attr("style", "background-color:white"); + }); + }); - updateBalance(); + //INVOICE STUFF START------------------------------------------ + + $("#friendselector").hide(); + $("#invoice").hide(); + $("#invoicedisplay").hide(); + $("#btnpayinvoice").bind('touchstart', function () { - //change status - var statusbox = ' Paid'; - $("#invdisstatus").html(statusbox); + $(".footer").hide(); - //hide buttons - $("#payinvoicecancel").hide(); - $("#btnpayinvoice").hide(); - $("#btnrejectinvoice").hide(); - } + $("#sendstds2add").text(SELECTEDFRIEND); - }); + $("#sendstds2amt").text(convertFromSatoshis(selectedInvoiceAmount, COINUNIT) + ' ' + COINUNIT); + sendmode = 'inv'; - } else { + $('.numdone').attr("style", "background-color:white"); + $("#sendstdpin").val(''); + pintaps = 0; + prevpin = ''; - $('#textMessageSend').addClass('alert alert-danger'); - $('#sendstdprogstatus').width('0%') + $("#invoices").hide(); + $("#mainWallet").hide(); + $("#pinconfirm").show(); - if (transactionid == "ErrInsufficientFunds") { - $('#textMessageSend').text('Transaction Failed: Waiting for funds to clear'); - } - } + }); - }); + $("#btnrejectinvoice").bind('touchstart', function () { - } else { + Engine.updateInvoice(selectedInvoiceUserName, selectedInvoiceId, '', 2, function (err, result) { - //display pin error - $('.numdone').attr("style", "background-color:white"); - $("#sendstdpin").val(''); - $('#confpinalert').show(); - $('#confpinalertmess').text(ekey); + loadInvoices(function (err, res) { - } + lastInvoiceToPayCount = 0; + + showInvoiceListNetwork(); + + $("#invoices").hide(); + $("#mainWallet").show(); + $("#network").show(); + $("#pnlfriend").show(); + $("#friendheader").show(); + $(".footer").show(); + + updateSelectedFriend(); + + }); + }); }); - } + $("#payinvoicecancel").bind('touchstart', function () { - //INVOICE FUNCTIONS END------------------------------------------ + $("#invoices").hide(); + $("#mainWallet").show(); + $("#network").show(); + $("#pnlfriend").show(); + $("#friendheader").show(); + $(".footer").show(); + //if (uiInvoiceReturnToNetwork) { + //$("#hnetwork").click(); + //uiInvoiceReturnToNetwork = false; + //} - function initialiseDashboard() { - $("#dashsend").hide(); - $("#dashreceive").hide(); - $("#dashcontact").hide(); - $('#invoices').hide(); - $('#network').hide(); - $('#networklist').hide(); - $("#networklistheader").hide(); - $('#settings').hide(); - $("#settingsheader").hide(); + }); - var length = Engine.m_nickname.length; - if (length > 20) { - length = 20; - } + }); - COINUNIT = Engine.m_settings.CoinUnit; - $("#mynickname").text(Engine.m_nickname); - $("#usernameProfile").text(Engine.m_nickname); - $("#mystatus").text(Engine.m_statusText); + var lastInvoiceToPayNetCount = 0; + var uiInvoiceReturnToNetwork = false; + + var cachedInvoices = []; + var cachedInvoicesByUser = []; + function showInvoiceListNetwork() { - var imageSrc = "images/avatar/128px/Avatar-" + pad(length) + ".png"; - var imageSrcSmall = "images/avatar/64px/Avatar-" + pad(length) + ".png"; + var invoices = _.filter(cachedInvoices, function (inv) { return inv.InvoiceFrom == SELECTEDFRIEND; }); - if (Engine.m_profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + Engine.m_profileImage + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; - imageSrcSmall = "https://ninkip2p.imgix.net/" + Engine.m_profileImage + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; + + if (invoices.length == 0) { + $('#invfornet').empty(); + $('#invfornet').hide(); } - $("#imgProfile").attr("src", imageSrc); - $("#imgtoprightprofile").attr("src", imageSrcSmall); + //if (lastInvoiceToPayNetCount < invoices.length) { - $("#codeForFriend").text(Engine.m_fingerprint); + lastInvoiceToPayNetCount = invoices.length; + var s = ''; + $('#invfornet').empty(); - Engine.getUserNetwork(function (err, friends) { + for (var i = 0; i < invoices.length; i++) { - FRIENDSLIST = {}; + var invdate = new Date(invoices[i].InvoiceDate.match(/\d+/)[0] * 1); - for (var i = 0; i < friends.length; i++) { - FRIENDSLIST[friends[i].userName] = friends[i]; + var timeLabel = prettydate.format(invdate); + + var statusbox = ''; + if (invoices[i].InvoiceStatus == 0) { + statusbox = ' Pending'; + } + else if (invoices[i].InvoiceStatus == 1) { + statusbox = ' Paid'; + } + else if (invoices[i].InvoiceStatus == 2) { + statusbox = ' Rejected'; } - //prep the network tab - $("#networklist").show(); - //$("#networklistheader").show(); + s += "
" + _.escape(timeLabel) + "
" + + "
" + statusbox + "
"; + } - showTransactionFeed(function (err, res) { + $('#invfornet').append(s); - $('#dashboard').show(); - $('#dashheader').show(); + for (var i = 0; i < invoices.length; i++) { - $("#mainWallet").show(); - $(".footer").show(); + $("#invfornet #viewinvoicenetfrom" + invoices[i].InvoiceFrom + invoices[i].InvoiceId).hammer(null).bind("tap", { + index: invoices[i].InvoiceId, username: invoices[i].InvoiceFrom + }, function (event) { - updateUI(); + $("#invtapspinner").show(); + var target = document.getElementById('invtapspinner'); + var spinner = new Spinner(spinneropts).spin(target); - var data = Engine.m_fingerprint + ',' + Engine.m_nickname; - var options = { text: data, width: 172, height: 172 }; + displayInvoice(event.data.index, event.data.username, 'forme', function (err, res) { + uiInvoiceReturnToNetwork = true; - $('#fingerprintqr').text(''); - $('#fingerprintqr').qrcode(options); + networkpagestate = "invoice"; + friendpagestate = "invoice"; + $("#invtapspinner").hide(); + $('#pnlfriend').hide(); + $("#friendheader").hide(); + $(".footer").hide(); + $('#invoices').show(); - setInterval(function () { - updateUI(); + }); + }); + } - }, 10000); + $('#invfornet').show(); - }); + //} - }); + // $('#pnlfriendinv').show(); } + var lastInvoiceByMeNetCount = 0; + function showInvoiceByMeListNetwork() { - function loadInvoices(callback) { + var invoices = _.filter(cachedInvoicesByUser, function (inv) { return inv.InvoiceFrom == SELECTEDFRIEND; }); - //load the invoices into the cache - cachedInvoices = []; + if (invoices.length == 0) { + $('#invbynet').empty(); + $('#invbynet').hide(); + } - Engine.getInvoiceList(function (err, invoices) { + if (lastInvoiceByMeNetCount < invoices.length) { - for (var i = 0; i < invoices.length; i++) { - var d1 = new Date(invoices[i].InvoiceDate); - invoices[i].JsDate = d1; - } + lastInvoiceByMeNetCount = invoices.length; - invoices = _.sortBy(invoices, function (inv) { return -inv.JsDate; }); - for (var i = 0; i < invoices.length; i++) { + var s = ''; + $('#invbynet').empty(); - cachedInvoices.push(invoices[i]); + for (var i = 0; i < invoices.length; i++) { - } + var invdate = new Date(invoices[i].InvoiceDate.match(/\d+/)[0] * 1); - cachedInvoicesByUser = []; + var timeLabel = prettydate.format(invdate); - Engine.getInvoiceByUserList(function (err, invoices) { - for (var i = 0; i < invoices.length; i++) { - var d1 = new Date(invoices[i].InvoiceDate); - invoices[i].JsDate = d1; + var statusbox = ''; + if (invoices[i].InvoiceStatus == 0) { + statusbox = ' Pending'; + } + else if (invoices[i].InvoiceStatus == 1) { + statusbox = ' Paid'; + } + else if (invoices[i].InvoiceStatus == 2) { + statusbox = ' Rejected'; } - invoices = _.sortBy(invoices, function (inv) { return -inv.JsDate; }); + s += "
" + _.escape(timeLabel) + "
" + + "
" + statusbox + "
"; + } - for (var i = 0; i < invoices.length; i++) { - cachedInvoicesByUser.push(invoices[i]); - } + $('#invbynet').append(s); - if (callback) { - return callback(false, "ok"); - } + for (var i = 0; i < invoices.length; i++) { - }); + $("#invbynet #viewinvoicenetby" + invoices[i].InvoiceFrom + invoices[i].InvoiceId).hammer(null).bind("tap", { + index: invoices[i].InvoiceId, username: invoices[i].InvoiceFrom + }, function (event) { - }); - } + $("#invtapspinner").show(); + var target = document.getElementById('invtapspinner'); + var spinner = new Spinner(spinneropts).spin(target); + displayInvoice(event.data.index, event.data.username, 'byme', function (err, res) { - function initialiseUI() { + networkpagestate = "invoice"; + friendpagestate = "invoice"; + + $("#invtapspinner").hide(); + $('#pnlfriend').hide(); + $("#friendheader").hide(); + $('.footer').hide(); + $('#invoices').show(); + + }); + }); + } + $('#invbynet').show(); - //updateFriends(function (err, res) { + } + // $('#pnlfriendinv').show(); - //}); } + var selectedInvoiceAmount = 0; + var selectedInvoiceId = 0; + var selectedInvoiceUserName = ''; + function displayInvoiceDetails(invoice, json, invtype, callback) { - //OPEN/CREATE WALLET FUNCTIONS END--------------------------------------------- + var invdate = new Date(invoice.InvoiceDate.match(/\d+/)[0] * 1).toString("yyyy-MM-dd HH:mm tt"); - function pad(n) { - return (n < 10) ? ("0" + n) : n; - } - - function logout() { - location.reload(); - } - UI.updateUITimer = function () { - updateUI(); - } - var prevBlock = 0; + $("#createinv").hide(); + $("#invoicestopay").hide(); - function updateUI(callback) { + $('#tblinvdisplay tbody').empty(); + var dp = 4; - //All background UI activity controlled from here - //The focus is on minimizing any activity + if (COINUNIT == "Bits") { + if (json.summary.total < 10000) { + dp = 2; + } else { + dp = 0; + } + } - //get version - //checks all infra - //if error we have a problem + if (COINUNIT == "BTC") { - var newBlock = false; + if (json.summary.total < 10000) { + dp = 8; + } else { + dp = 4; + } + } - Engine.getVersion(function (err, res) { + var s = ''; + for (var i = 0; i < json.invoicelines.length; i++) { + if (COINUNIT == "Bits") { + s += "" + _.escape(json.invoicelines[i].description) + "" + _.escape(json.invoicelines[i].quantity) + "" + _.escape(accounting.formatNumber(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT), dp, ",", ".")) + "" + _.escape(accounting.formatNumber(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT) * json.invoicelines[i].quantity, dp, ",", ".")) + ""; + } else { + s += "" + _.escape(json.invoicelines[i].description) + "" + _.escape(json.invoicelines[i].quantity) + "" + _.escape(accounting.formatNumber(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT), dp, ",", ".")) + "" + _.escape(accounting.formatNumber(convertFromSatoshis(json.invoicelines[i].amount, COINUNIT) * json.invoicelines[i].quantity, dp, ",", ".")) + ""; + } + } - if (!err) { + $('#tblinvdisplay tbody').append(s); - var stats = JSON.parse(res); + if (invtype == 'forme') { + $("#dinvusername").text('Invoice from ' + invoice.InvoiceFrom); + } else { + $("#dinvusername").text('Invoice to ' + invoice.InvoiceFrom); + } - if (prevBlock != stats.BlockNumber) { - newBlock = true; - } + $("#dinvdate").text(invdate); - prevBlock = stats.BlockNumber; - //Always + $("#tblinvdisplay tfoot th #dsubtotal").text(accounting.formatNumber(convertFromSatoshis(json.summary.subtotal, COINUNIT), dp, ",", ".")); + $("#tblinvdisplay tfoot th #dtax").text(accounting.formatNumber(convertFromSatoshis(json.summary.tax, COINUNIT), dp, ",", ".")); + $("#tblinvdisplay tfoot th #dtotal").text(accounting.formatNumber(convertFromSatoshis(json.summary.total, COINUNIT), dp, ",", ".")); - updateBalance(function (err, hasChanged) { - //do we need to update transactions - //1. is our balance different from the last request? - //if it is immediately update transactions - //2. do we have a new block? - //if so then call updatetransactions - //if (hasChanged || newBlock) { + selectedInvoiceAmount = convertFromSatoshis(json.summary.total); + selectedInvoiceId = invoice.InvoiceId; + selectedInvoiceUserName = invoice.InvoiceFrom; - //update transactions? + $("#sendinvprog").hide(); + $("#textMessageSendInv").hide(); + $("#btnokinvoice").hide(); + $("#invvalmess").hide(); - showTransactionFeed(function (err, result) { + if (invtype == 'forme') { + if (invoice.InvoiceStatus == 0) { - loadInvoices(function (err, result) { + $("#payinvoicecancel").show(); + $("#btnpayinvoice").show(); + $("#btnrejectinvoice").show(); - updateSelectedFriend(); + if (!FRIENDSLIST[invoice.InvoiceFrom].validated) { + $("#btnpayinvoice").addClass("disabled"); + $("#invvalt").text(invoice.InvoiceFrom); + $("#invvalmess").show(); + } else { + $("#btnpayinvoice").removeClass("disabled"); + $("#invvalmess").hide(); + } - }); + } + if (invoice.InvoiceStatus == 1 || invoice.InvoiceStatus == 2) { + $("#btnokinvoice").show(); + //$("#payinvoicecancel").hide(); + $("#btnpayinvoice").hide(); + $("#btnrejectinvoice").hide(); + } + } else { + $("#btnokinvoice").show(); + //$("#payinvoicecancel").hide(); + $("#btnpayinvoice").hide(); + $("#btnrejectinvoice").hide(); + } + var statusbox = ''; + if (invoice.InvoiceStatus == 0) { + statusbox = ' Pending'; + } + else if (invoice.InvoiceStatus == 1) { + statusbox = ' Paid'; + } + else if (invoice.InvoiceStatus == 2) { + statusbox = ' Rejected'; + } - }); + $("#invdisstatus").html(statusbox); + $("#invdisid").text(invoice.InvoiceFrom.toUpperCase() + invoice.InvoiceId); - updateFriendRequests(function (err, res) { + $("#invoicedisplay").show(); + return callback(false, "ok"); + } + function displayInvoiceByUser(invoiceid, username, invtype, callback) { - }); + var invoice = _.find(cachedInvoicesByUser, function (inv) { return inv.InvoiceId == invoiceid; }); + //here decrypt the invoice with my private key - updateFriends(function (err, res) { + Engine.UnpackInvoiceByMe(invoice, username, function (err, unpacked) { + displayInvoiceDetails(invoice, unpacked, invtype, function (err, res) { + callback(false, "ok"); - }); + }); + }); + } - //update selected friend transactions also - //} + function displayInvoice(invoiceid, username, invtype, callback) { - }); + var invoice; + //find by invoicefrom and invoice id + if (invtype == 'forme') { + invoice = _.find(cachedInvoices, function (inv) { return inv.InvoiceFrom == username && inv.InvoiceId == invoiceid; }); + } else { + invoice = _.find(cachedInvoicesByUser, function (inv) { return inv.InvoiceFrom == username && inv.InvoiceId == invoiceid; }); + } + if (invoice) { - //Always - Ninki.API.getPrice(Engine.m_guid, Engine.m_settings.LocalCurrency, function (err, result) { - - - result = _.escape(result); - price = result * 1.0; - - var loc = "en-US"; - var cprc = ""; - if (Engine.m_settings.LocalCurrency == "JPY" || Engine.m_settings.LocalCurrency == "CNY") { - cprc = accounting.formatMoney(result, "¥", 0); - } else if (Engine.m_settings.LocalCurrency == "GBP") { - cprc = accounting.formatMoney(result, "£", 2); - } else if (Engine.m_settings.LocalCurrency == "EUR") { - cprc = accounting.formatMoney(result, "€", 2); - } else if (Engine.m_settings.LocalCurrency == "USD") { - cprc = accounting.formatMoney(result, "$", 2); - } else if (Engine.m_settings.LocalCurrency == "CNY") { - cprc = accounting.formatMoney(result, "¥", 2); - } + Engine.UnpackInvoiceForMe(invoice, username, invtype, function (err, unpacked) { + displayInvoiceDetails(invoice, unpacked, invtype, function (err, res) { + callback(false, "ok"); + }); - $('#homeprice').html(cprc); + }); + } else { - // + ' / BTC' + $("#invtapspinner").hide(); - }); + } - } + } - }); + function payInvoice(friend, amount, invoiceNumber) { + var pin = $('#sendstdpin').val(); + Engine.getDeviceKey(pin, function (err, ekey) { - } + if (!err) { - function convertFromSatoshis(amount, toUnit) { + $("#btnStdSndDone").hide(); - if (toUnit == 'BTC') { - amount = amount / 100000000; - } + $('#sendprogress').show(); + $('#pinconfirm').hide(); + $('#invoices').hide(); - if (toUnit == 'mBTC') { - amount = amount / 100000; - } + $('#textMessageSendStd').text('Creating transaction...'); + $('#textMessageSendStd').show(); + $('#sendstdprogstatus').width('3%'); + $('#sendstdprog').show(); + $('#sendstdprogstatus').width('10%'); - if (toUnit == 'uBTC') { - amount = amount / 100; - } + $('#sendstdprognum').text('10%'); - if (toUnit == 'Bits') { - amount = amount / 100; - } + setTimeout(function () { + Engine.sendTransaction('invoice', friend, '', amount, ekey.DeviceKey, function (err, transactionid) { - return amount; - } - - function convertToSatoshis(amount, fromUnit) { + if (!err) { - if (fromUnit == 'BTC') { - amount = amount * 100000000; - } + Engine.updateInvoice(friend, invoiceNumber, transactionid, 1, function (err, result) { - if (fromUnit == 'mBTC') { - amount = amount * 100000; - } + if (!err) { - if (fromUnit == 'uBTC') { - amount = amount * 100; - } + $('#textMessageSendStd').text('You paid invoice: ' + friend.toUpperCase() + invoiceNumber); - if (fromUnit == 'Bits') { - amount = amount * 100; - } + updateStdAmount(); - amount = Math.round(amount) - return amount; - } + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); + $("#sendstdpin").val(''); + $('.numdone').attr("style", "background-color:white"); + pintaps = 0; + prevpin = ''; - var previousBalance = 0; + updateBalance(); - function updateBalance(callback) { - Engine.getBalance(function (err, result) { + //change status + var statusbox = ' Paid'; + $("#invdisstatus").html(statusbox); - if (!err) { - //get in BTC units - var balance = convertFromSatoshis(result.TotalBalance, COINUNIT); + //hide buttons + //$("#payinvoicecancel").hide(); + $("#btnpayinvoice").hide(); + $("#btnrejectinvoice").hide(); - $("#homebalance").text(balance); - $("#homecoinunit").text(COINUNIT); - $("#calcbalance").text(balance); - $("#calccoinunit").text(COINUNIT); + } - var template = ''; - if (result.UnconfirmedBalance > 0) { - template += ''; - } else { - template += ''; - } + }); - var templatecalc = ''; - if (result.UnconfirmedBalance > 0) { - templatecalc += ''; - } else { - templatecalc += ''; - } - $("#hometimer").html(template); - $("#calctimer").html(templatecalc); + } else { + $('#sendstdprogstatus').width('0%'); + $('#sendstdprognum').text('0%'); - if (previousBalance != result.TotalBalance || result.UnconfirmedBalance > 0) { + if (transactionid == "ErrInsufficientFunds") { + $('#textMessageSendStd').text('Transaction Failed: Waiting for funds to clear'); + } - previousBalance = result.TotalBalance; + //return to send screen + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); - if (callback) { - callback(err, true); - } + } - } else { + }, function (message, progress) { - if (result.UnconfirmedBalance == 0) { - if (callback) { - callback(err, false); + if (message) { + $('#textMessageSendStd').text(message); } - } else { - if (callback) { - callback(err, true); + + if (progress) { + $('#sendstdprogstatus').width(progress); + $('#sendstdprognum').text(progress); } - } - } + }); + }, 50); } else { - callback(true, "Error"); + //display pin error + $('.numdone').attr("style", "background-color:white"); + $("#sendstdpin").val(''); + pintaps = 0; + prevpin = ''; + + $('#confpinalert').show(); + $('#confpinalertmess').text(ekey); } }); - - } - function updateNetwork() { - // getNewFriends(); - //updateFriendRequests(); - getNewFriends(); - } + //INVOICE FUNCTIONS END------------------------------------------ + function initialiseDashboard(callback) { + $("#dashsend").addClass("invis"); + $("#dashsend").removeClass("slideUp"); - var previousReqByMe = 0; - function updateRequestsMadeByMe(callback) { + $("#dashreceive").addClass("invis"); + $("#dashreceive").removeClass("slideUp"); - Engine.getPendingUserRequests(function (err, friends) { + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + //$("#dashreceive").hide(); + //$("#dashcontact").hide(); - if (friends.length != previousReqByMe) { - previousReqByMe = friends.length; - $("#requestssent").text(''); - for (var i = 0; i < friends.length; i++) { - var length = friends[i].userName.length; - if (length > 20) { - length = 20; - } + $('#invoices').hide(); + $('#network').hide(); + $('#networklist').hide(); + $("#networklistheader").hide(); + $('#settings').hide(); + $("#settingsheader").hide(); - var template = '
  • ' + - '
    ' + - '' + - '
    ' + - '' + - '
    ' + - '
    ' + - '
    ' + friends[i].userName + '
    ' + - 'I love Ninki!' + - '
    ' + - '
    ' + - '
  • '; + var length = Engine.m_nickname.length; + if (length > 20) { + length = 20; + } - $("#requestssent").append(template); - } - } + COINUNIT = Engine.m_settings.CoinUnit; - if (friends.length > 0) { - $("#requestsentpanel").show(); - } else { - $("#requestsentpanel").hide(); - } + $("#mynickname").text(Engine.m_nickname); + $("#usernameProfile").text(Engine.m_nickname); + $("#mystatus").text(Engine.m_statusText); - if (callback) { - callback(); + var imageSrc = "images/avatar/128px/Avatar-" + pad(length) + ".png"; + var imageSrcSmall = "images/avatar/64px/Avatar-" + pad(length) + ".png"; - } + if (Engine.m_profileImage != '') { + imageSrc = "https://ninkip2p.imgix.net/" + Engine.m_profileImage + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; + imageSrcSmall = "https://ninkip2p.imgix.net/" + Engine.m_profileImage + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; + } - }); + $("#imgProfile").attr("src", imageSrc); + $("#imgtoprightprofile").attr("src", imageSrcSmall); + $("#codeForFriend").text(Engine.m_fingerprint); - } + Engine.getUserNetwork(function (err, friends) { + FRIENDSLIST = {}; - var lastNoOfFriends = 0; - var invoiceSelectedUser = ''; - var invoiceSelectedAmount = 0; - var selectedFriend = null; + for (var i = 0; i < friends.length; i++) { + FRIENDSLIST[friends[i].userName] = friends[i]; + } - function updateFriends(callback) { + //prep the network tab + $("#networklist").show(); + //$("#networklistheader").show(); - if (!noAlert == true) { + showTransactionFeed(function (err, res) { - Engine.getUserNetwork(function (err, friends) { + updateBalance(function (err, hasChanged) { - //$("#nfriends").text(friends.length); + updatePrice(function () { - if (friends.length > lastNoOfFriends) { + if (callback) { - lastNoOfFriends = friends.length; + callback(); - FRIENDSLIST = {}; + } - for (var i = 0; i < friends.length; i++) { - FRIENDSLIST[friends[i].userName] = friends[i]; - } + }); + + }); - //if selected friend is not isend and isreceive - //then find in list and update - // if (selectedFriend != null) { + updateUI(); - // if (!selectedFriend.ICanSend || !selectedFriend.ICanReceive) { - // selectedFriend = FRIENDSLIST[selectedFriend.userName]; - // updateSelectedFriend(); - // } + var data = Engine.m_fingerprint + ',' + Engine.m_nickname; + var options = { text: data, width: 172, height: 172 }; - // } + $('#fingerprintqr').text(''); + $('#fingerprintqr').qrcode(options); + $('#qrcontscan').text(''); + $('#qrcontscan').qrcode(options); - $("#nfriends").text(friends.length); - $("#myfriends").text(''); + setInterval(function () { - var grouptemplate = ''; + updateUI(); - var friendsgroup = _.groupBy(friends, function (item) { return item.category; }) + }, 10000); - grouptemplate += '
    '; - var k = 0; - var g = 1; - for (var key in friendsgroup) { + }); - friends = friendsgroup[key]; + }); - grouptemplate += '
    '; - grouptemplate += '
    '; - grouptemplate += ''; - grouptemplate += _.escape(key); - grouptemplate += ''; - grouptemplate += '
    '; - grouptemplate += '
    '; + } - for (var i = 0; i < friendsgroup[key].length; i++) { + function loadInvoices(callback) { - var frnd = FRIENDSLIST[friends[i].userName]; + //load the invoices into the cache + //cachedInvoices = []; - var length = frnd.userName.length; - if (length > 20) { - length = 20; - } + var tmpCachedInvoices = []; + Engine.getInvoiceList(function (err, invoices) { - var imageSrc = "images/avatar/64px/Avatar-" + pad(length) + ".png"; + for (var i = 0; i < invoices.length; i++) { + var d1 = new Date(invoices[i].InvoiceDate); + invoices[i].JsDate = d1; + } - if (frnd.profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + _.escape(frnd.profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(frnd.profileImage) + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; - } + invoices = _.sortBy(invoices, function (inv) { return -inv.JsDate; }); + for (var i = 0; i < invoices.length; i++) { + tmpCachedInvoices.push(invoices[i]); - var template = '
    ' + - '
    '; + } - if (frnd.validated) { - template += '
    ' + - '' + - '
    '; - } + cachedInvoices = tmpCachedInvoices; - template += '
    ' + - '
    ' + _.escape(friends[i].userName) + '
    ' + - '' + _.escape(frnd.status) + '' + - '
    ' + - '
    '; + var tmpCachedInvoicesByUser = []; - grouptemplate += template; + Engine.getInvoiceByUserList(function (err, invoices) { + + for (var i = 0; i < invoices.length; i++) { + var d1 = new Date(invoices[i].InvoiceDate); + invoices[i].JsDate = d1; + } + invoices = _.sortBy(invoices, function (inv) { return -inv.JsDate; }); + for (var i = 0; i < invoices.length; i++) { + tmpCachedInvoicesByUser.push(invoices[i]); + } - k++; - } + cachedInvoicesByUser = tmpCachedInvoicesByUser; + if (callback) { + return callback(false, "ok"); + } - grouptemplate += '
    '; - grouptemplate += '
    '; - g++; - } + }); - grouptemplate += '
    '; + }); - $("#myfriends").html(grouptemplate); + } + function initialiseUI() { - $('#myfriends #accordion2').on('touchstart.collapse.data-api', '[data-toggle=collapse]', function (e) { - var $this = $(this); + //updateFriends(function (err, res) { - $this.click(); - //href, target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) //strip for ie7 - //, - //option = $(target).data('collapse') ? 'show' : $this.data() - //$(target).collapse(option) - }); + //}); + } - var k = 0; - var g = 1; - for (var key in friendsgroup) { - friends = friendsgroup[key]; - for (var i = 0; i < friendsgroup[key].length; i++) { + //OPEN/CREATE WALLET FUNCTIONS END--------------------------------------------- - friends = friendsgroup[key]; + function pad(n) { + return (n < 10) ? ("0" + n) : n; + } + function logout() { + location.reload(); + } - //var btnfriend = $("#myfriends #friend" + k).get(); - //var hammertime = new Hammer(btnfriend[0]); + UI.updateUITimer = function () { + updateUI(); + }; - $("#myfriends #friend" + k).hammer(null).bind("tap", { userName: friends[i].userName }, function (ev) { - SELECTEDFRIEND = ev.data.userName; - selectedFriend = FRIENDSLIST[ev.data.userName]; - prevNetworkTransCount = 0; + var prevBlock = 0; - networkpagestate = "friend"; - friendpagestate = "send" - $("#networklistheader").hide(); - $("#friendheader").show(); - $("#pnlfriend").show(); + function updateUI(callback) { - $('#netpayfeed').html(''); - $("#networkpayments").show(); - $("#networklist").hide(); + //All background UI activity controlled from here + //The focus is on minimizing any activity - $("#pnlfriendinv").hide(); - window.scrollTo(0, 0); + //get version + //checks all infra + //if error we have a problem - updateSelectedFriend(); + var newBlock = false; - }); + Engine.getVersion(function (err, res) { - //console.log("added click " + k + " for " + friends[i].userName); + if (!err) { - k++; - } - g++; - } + var stats = JSON.parse(res); + if (prevBlock != stats.BlockNumber) { + newBlock = true; } - if (callback) { - return callback(false, "done"); + + prevBlock = stats.BlockNumber; + + + + if (stdAmountConvCoin) { + $('#stdselunit').text(COINUNIT); + } else { + $('#stdselunit').text(Engine.m_settings.LocalCurrency); } - }); - } - } - function showSecret() { + $('#stdsendcunit').text(COINUNIT); - } + $('#stdsendlcurr').text(Engine.m_settings.LocalCurrency); - function refreshSelectedFriend(callback) { - if (SELECTEDFRIEND.length > 0) { + //Always - Engine.getFriend(SELECTEDFRIEND, function (err, friend) { - if (!norefresh) { - if (SELECTEDFRIEND == friend.userName) { - selectedFriend = friend; - FRIENDSLIST[SELECTEDFRIEND] = friend; + updateBalance(function (err, hasChanged) { - if (selectedFriend.ICanSend) { - $("#issend").show(); - //$("#networksend").show(); - } else { - $("#issend").hide(); - //$("#networksend").hide(); - } - if (selectedFriend.ICanReceive) { - $("#isreceive").show(); - } else { - $("#isreceive").hide(); - } - var imageSrc = "images/avatar/256px/Avatar-" + pad(SELECTEDFRIEND.length) + ".png"; + //do we need to update transactions + //1. is our balance different from the last request? + //if it is immediately update transactions - if (selectedFriend.profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + selectedFriend.profileImage + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - } - if (selectedFriend.status != '') { - $("#friendSelectedStatus").text(selectedFriend.status); - } + //2. do we have a new block? + //if so then call updatetransactions - $("#imgSelectedFriend").attr("src", imageSrc); + //if (hasChanged || newBlock) { + //update transactions? + showTransactionFeed(function (err, result) { + loadInvoices(function (err, result) { - callback(err, friend); + updateSelectedFriend(); - //updateSelectedFriend(function (err, res) { - // selFriendBkgUpdate = false; - // callback(err, res); - //}); - } - } - }); + }); - } - } + }); + updateFriendRequests(function (err, res) { - function updateSelectedFriend(callback) { - //can optimise futher - norefresh = true; - if (SELECTEDFRIEND.length > 0) { + + }); - $('input#friendAmount').val(''); + updateFriends(function (err, res) { + + + + }); + + + + //update selected friend transactions also + //} + + }); + + + updatePrice(); + - var length = selectedFriend.userName.length; - if (length > 20) { - length = 20; } - //$("#nselnetcat").val(selectedFriend.category); + }); - $('#friendempty').hide(); - //$('#textMessageSend').removeClass('alert alert-danger'); + } - $('#textMessageSend').hide(); - $('#sendfriendprog').hide(); + function updatePrice(callback) { + //Always + Ninki.API.getPrice(Engine.m_guid, Engine.m_settings.LocalCurrency, function (err, result) { - $("#friendSelectedName").text(selectedFriend.userName); - $("#friendSelectedNameTo").text(selectedFriend.userName); - $("#validateusername2").text(selectedFriend.userName); + + result = _.escape(result); + price = result * 1.0; + + var loc = "en-US"; + var cprc = ""; + if (Engine.m_settings.LocalCurrency == "JPY" || Engine.m_settings.LocalCurrency == "CNY") { + cprc = accounting.formatMoney(result, "¥", 0); + } else if (Engine.m_settings.LocalCurrency == "GBP") { + cprc = accounting.formatMoney(result, "£", 2); + } else if (Engine.m_settings.LocalCurrency == "EUR") { + cprc = accounting.formatMoney(result, "€", 2); + } else if (Engine.m_settings.LocalCurrency == "USD") { + cprc = accounting.formatMoney(result, "$", 2); + } else if (Engine.m_settings.LocalCurrency == "CNY") { + cprc = accounting.formatMoney(result, "¥", 2); + } + + $('#homeprice').html(cprc); + + if (callback) { + callback(); + } + + // + ' / BTC' + + }); + + + } + + function convertFromSatoshis(amount, toUnit) { + + if (toUnit == 'BTC') { + amount = amount / 100000000; + } + + if (toUnit == 'mBTC') { + amount = amount / 100000; + } + + if (toUnit == 'uBTC') { + amount = amount / 100; + } + + if (toUnit == 'Bits') { + amount = amount / 100; + } + + + return amount; + } + + function convertToSatoshis(amount, fromUnit) { + + if (fromUnit == 'BTC') { + amount = amount * 100000000; + } + + if (fromUnit == 'mBTC') { + amount = amount * 100000; + } + + if (fromUnit == 'uBTC') { + amount = amount * 100; + } + + if (fromUnit == 'Bits') { + amount = amount * 100; + } + + amount = Math.round(amount); + return amount; + } + + + var previousBalance = 0; + + function updateBalance(callback) { + + Engine.getBalance(function (err, result) { + + if (!err) { + + //get in BTC units + var balance = convertFromSatoshis(result.TotalBalance, COINUNIT); + + currentBalance = balance; + + var fbal = ''; + if (COINUNIT == "BTC") { + fbal = accounting.formatMoney(balance, "", 4); + } else if (COINUNIT == "Bits") { + fbal = accounting.formatMoney(balance, "", 0); + } else { + fbal = accounting.formatMoney(balance, "", 2); + } + + $("#homebalance").text(fbal); + $("#homecoinunit").text(COINUNIT); + + $("#calcbalance").text(fbal); + $("#calccoinunit").text(COINUNIT); + + var template = ''; + if (result.UnconfirmedBalance > 0) { + template += ''; + } else { + template += ''; + } + + var templatecalc = ''; + if (result.UnconfirmedBalance > 0) { + templatecalc += ''; + } else { + templatecalc += ''; + } + + $("#hometimer").html(template); + $("#calctimer").html(templatecalc); + + + if (previousBalance != result.TotalBalance || result.UnconfirmedBalance > 0) { + + previousBalance = result.TotalBalance; + + if (callback) { + callback(err, true); + } + + } else { + + if (result.UnconfirmedBalance == 0) { + if (callback) { + callback(err, false); + } + } else { + if (callback) { + callback(err, true); + } + } + + } + + } else { + + callback(true, "Error"); + + } + + }); + + + + } + + function updateNetwork() { + + // getNewFriends(); + //updateFriendRequests(); + getNewFriends(); + } + + + var previousReqByMe = 0; + function updateRequestsMadeByMe(callback) { + + + Engine.getPendingUserRequests(function (err, friends) { + + + if (friends.length != previousReqByMe) { + previousReqByMe = friends.length; + $("#requestssent").text(''); + for (var i = 0; i < friends.length; i++) { + + var length = friends[i].userName.length; + if (length > 20) { + length = 20; + } + + var template = '
  • ' + + '
    ' + + '' + + '
    ' + + '' + + '
    ' + + '
    ' + + '
    ' + friends[i].userName + '
    ' + + 'I love Ninki!' + + '
    ' + + '
    ' + + '
  • '; + + $("#requestssent").append(template); + } + } + + if (friends.length > 0) { + $("#requestsentpanel").show(); + } else { + $("#requestsentpanel").hide(); + } + + if (callback) { + + callback(); + + } + + }); + + + + + } + + + var lastNoOfFriends = 0; + var invoiceSelectedUser = ''; + var invoiceSelectedAmount = 0; + var selectedFriend = null; + + function updateFriends(callback) { + + if (!noAlert == true) { + + + Engine.getUserNetwork(function (err, friends) { + + + if (!err) { + + //$("#nfriends").text(friends.length); + + if (friends.length > lastNoOfFriends) { + + lastNoOfFriends = friends.length; + + FRIENDSLIST = {}; + + for (var i = 0; i < friends.length; i++) { + FRIENDSLIST[friends[i].userName] = friends[i]; + } + + //if selected friend is not isend and isreceive + //then find in list and update + + // if (selectedFriend != null) { + + // if (!selectedFriend.ICanSend || !selectedFriend.ICanReceive) { + // selectedFriend = FRIENDSLIST[selectedFriend.userName]; + // updateSelectedFriend(); + // } + + // } + + + $("#nfriends").text(friends.length); + $("#myfriends").text(''); + + + var grouptemplate = ''; + + var friendsgroup = _.groupBy(friends, function (item) { return item.category; }); + + grouptemplate += '
    '; + + var k = 0; + var g = 1; + for (var key in friendsgroup) { + + friends = friendsgroup[key]; + + grouptemplate += '
    '; + grouptemplate += '
    '; + grouptemplate += ''; + grouptemplate += _.escape(key); + grouptemplate += ''; + grouptemplate += '
    '; + grouptemplate += '
    '; + + + for (var i = 0; i < friendsgroup[key].length; i++) { + + var frnd = FRIENDSLIST[friends[i].userName]; + + var length = frnd.userName.length; + if (length > 20) { + length = 20; + } + + + var imageSrc = "images/avatar/64px/Avatar-" + pad(length) + ".png"; + + if (frnd.profileImage != '') { + imageSrc = "https://ninkip2p.imgix.net/" + _.escape(frnd.profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; + imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(frnd.profileImage) + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; + } + + + var template = '
    ' + + '
    '; + + if (frnd.validated) { + template += '
    ' + + '' + + '
    '; + } + + template += '
    ' + + '
    ' + _.escape(friends[i].userName) + '
    ' + + '' + _.escape(frnd.status) + '' + + '
    ' + + '
    '; + + + grouptemplate += template; + + + + k++; + } + + + grouptemplate += '
    '; + grouptemplate += '
    '; + g++; + } + + grouptemplate += '
    '; + + $("#myfriends").html(grouptemplate); + + + + $('#myfriends #accordion2').on('touchstart.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this); + + $this.click(); + + //href, target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) //strip for ie7 + //, + //option = $(target).data('collapse') ? 'show' : $this.data() + //$(target).collapse(option) + }); + + + + var k = 0; + var g = 1; + for (var key in friendsgroup) { + + friends = friendsgroup[key]; + for (var i = 0; i < friendsgroup[key].length; i++) { + + friends = friendsgroup[key]; + + + //var btnfriend = $("#myfriends #friend" + k).get(); + //var hammertime = new Hammer(btnfriend[0]); + + $("#myfriends #friend" + k).hammer(null).bind("tap", { userName: friends[i].userName }, function (ev) { + + + if (!scrollingnetlist) { + + SELECTEDFRIEND = ev.data.userName; + selectedFriend = FRIENDSLIST[ev.data.userName]; + prevNetworkTransCount = 0; + + networkpagestate = "friend"; + friendpagestate = "send"; + $("#networklistheader").hide(); + $("#friendheader").show(); + $("#pnlfriend").show(); + + $('#netpayfeed').html(''); + $("#networkpayments").show(); + $("#networklist").hide(); + + $("#pnlfriendinv").hide(); + + //window.scrollTo(0, 0); + + updateSelectedFriend(); + + } + + }); + + //console.log("added click " + k + " for " + friends[i].userName); + + k++; + } + g++; + } + + } + + if (callback) { + return callback(false, "done"); + } + + } else { + + if (callback) { + return callback(true, "done"); + } + + } + }); + } + + } + + function showSecret() { + + + } + + function refreshSelectedFriend(callback) { + + if (SELECTEDFRIEND.length > 0) { + + Engine.getFriend(SELECTEDFRIEND, function (err, friend) { + if (!norefresh) { + if (SELECTEDFRIEND == friend.userName) { + selectedFriend = friend; + FRIENDSLIST[SELECTEDFRIEND] = friend; + + if (selectedFriend.ICanSend) { + $("#issend").show(); + //$("#networksend").show(); + } else { + $("#issend").hide(); + //$("#networksend").hide(); + } + if (selectedFriend.ICanReceive) { + $("#isreceive").show(); + } else { + $("#isreceive").hide(); + } + + var imageSrc = "images/avatar/256px/Avatar-" + pad(SELECTEDFRIEND.length) + ".png"; + + if (selectedFriend.profileImage != '') { + imageSrc = "https://ninkip2p.imgix.net/" + selectedFriend.profileImage + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; + } + if (selectedFriend.status != '') { + $("#friendSelectedStatus").text(selectedFriend.status); + } + + $("#imgSelectedFriend").attr("src", imageSrc); + + + + + callback(err, friend); + + //updateSelectedFriend(function (err, res) { + // selFriendBkgUpdate = false; + // callback(err, res); + //}); + } + } + }); + + } + + } + + function updateSelectedFriend(callback) { + + //can optimise futher + norefresh = true; + if (SELECTEDFRIEND.length > 0) { + + + $('input#friendAmount').val(''); + + + var length = selectedFriend.userName.length; + if (length > 20) { + length = 20; + } + + //$("#nselnetcat").val(selectedFriend.category); + + $('#friendempty').hide(); + + //$('#textMessageSend').removeClass('alert alert-danger'); + + + + $('#textMessageSend').hide(); + $('#sendfriendprog').hide(); + + + $("#friendSelectedName").text(selectedFriend.userName); + $("#friendSelectedNameTo").text(selectedFriend.userName); + $("#validateusername2").text(selectedFriend.userName); $("#validateusername3").text(selectedFriend.userName); $("#validateusername4").text(selectedFriend.userName); $("#validateusername5").text(selectedFriend.userName); @@ -3160,788 +3589,1071 @@ function UI() { $("#validatefail").hide(); - var imageSrc = "images/avatar/256px/Avatar-" + pad(length) + ".png"; + var imageSrc = "images/avatar/256px/Avatar-" + pad(length) + ".png"; + + if (selectedFriend.profileImage != '') { + imageSrc = "https://ninkip2p.imgix.net/" + selectedFriend.profileImage + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; + } + $("#friendSelectedStatus").text(''); + if (selectedFriend.status != '') { + $("#friendSelectedStatus").text(selectedFriend.status); + } + + $("#imgSelectedFriend").attr("src", imageSrc); + + + if (selectedFriend.validated) { + + $("#tapvalidatefriend").hide(); + $("#tapsendfriend").show(); + + } else { + + $("#tapvalidatefriend").show(); + $("#tapsendfriend").hide(); + } + + $('#tblnetinvbyme tbody').empty(); + $('#tblnetinvforme tbody').empty(); + + + + + lastInvoiceToPayNetCount = 0; + lastInvoiceByMeNetCount = 0; + + showInvoiceListNetwork(); + showInvoiceByMeListNetwork(); + + showTransactionNetwork(); + + //$("#pnlfriend").show(); + //$("#friendheader").show(); + + + } + + norefresh = false; + + + + + if (callback) { + callback(false, "ok"); + } + + } + + var lastNoOfFriendsReq = 0; + var selectedFriendRequest = ''; + + function updateFriendRequests(callback) { + + //if there are any new friends + //fade in the button + + //to do, move to handlebars templates + Engine.getFriendRequests(function (err, ofriends) { + + + //if origin of friend request is qrcode + //and no phrase cache + //delay for 60 seconds + //add accept with scan button + //then return to standard after 5 minutes + + var friends = []; + for (var i = 0; i < ofriends.length; i++) { + + if (contactPhraseCache[ofriends[i].userName]) { + //acceptAndValidateFriend(ofriends[i].userName); + } else { + friends.push(ofriends[i]); + } + + } + + + if (friends.length > 0) { + $("#dashrequests").show(); + + } else { + $("#dashrequests").hide(); + } + + //$("#notifications").text(friends.length); + //$("#notificationsright").text(friends.length); + //$("#nfriendreq").text(friends.length); + + + if (lastNoOfFriendsReq != friends.length || friends.length == 0) { + + lastNoOfFriendsReq = friends.length; + + if (friends.length > 0) { + $("#notifications").attr("class", "badge bg-danger pull-right"); + } else { + $("#notifications").attr("class", "badge pull-right"); + } + $("#nfriendreq").text(friends.length); + $("#friendreq").text(''); + for (var i = 0; i < friends.length; i++) { + + var length = friends[i].userName.length; + if (length > 20) { + length = 20; + } + + var template = '
  • ' + + 'John said' + + '' + + '
    ' + + '' + _.escape(friends[i].userName) + '' + + '
  • '; + + $("#friendreq").append(template); + + } + + for (var i = 0; i < friends.length; i++) { + + $("#friendreq #tapfriendreq" + i).hammer(null).bind("tap", { userName: friends[i].userName }, function (ev) { + + selectedFriendRequest = ev.data.userName; + + $("#friendrequestusername").text(selectedFriendRequest); + + + $("#mainWallet").hide(); + $("#networklistheader").hide(); + $(".footer").hide(); + $("#contactrequest").show(); + + + }); + + } + + } + if (callback) { + callback(false, "done"); + } + }); + + } + + $('#btnContactRequestClose').bind('touchstart', function () { + + $("#contactrequest").hide(); + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + + }); + + + $('#btnAcceptContactDone').bind('touchstart', function () { + + $("#contactrequest").hide(); + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + + }); + + + $('#btnContactReject').bind('touchstart', function () { + + rejectFriend(event.data.userName, function (err, res) { + + if (!err) { + + selectedFriendRequest = ''; + updateFriendRequests(); + + $("#friendrequestusername").text(''); + $("#contactrequest").hide(); + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + } + + }); + + }); + + + + var prevtransfeed = -1; + var transactionCache = []; + + function showTransactionFeed(callback) { + + Engine.getTransactionRecords(function (err, transactions) { + + + allTransactions = transactions; + transactionCache = transactions; + + if (transactions.length != prevtransfeed) { + + + for (var i = 0; i < allTransactions.length; i++) { + var d1 = new Date(allTransactions[i].TransDateTime); + allTransactions[i].JsDate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); + transactionIndex[allTransactions[i].TransactionId] = i; + } + + + + prevtransfeed = transactions.length; + + $('#transfeed').empty(); + + var template = ''; + + for (var i = 0; i < transactions.length && i < 51; i++) { + + var length = transactions[i].UserName.length; + if (length > 20) { + length = 20; + } + + var imageSrcSmall = "images/avatar/32px/Avatar-" + pad(length) + ".png"; + + if (transactions[i].UserName != 'External') { + if (FRIENDSLIST[transactions[i].UserName]) { + if (FRIENDSLIST[transactions[i].UserName].profileImage != '') { + imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(FRIENDSLIST[transactions[i].UserName].profileImage) + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; + } + } + } + + var amountLabel = ""; + var friendLabel = ""; + + if (transactions[i].TransType == 'S') { + amountLabel = "sent " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); + friendLabel = "to " + _.escape(transactions[i].UserName); + } + + if (transactions[i].TransType == 'R') { + amountLabel = "received " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); + friendLabel = "from " + _.escape(transactions[i].UserName); + } + + + var trdate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); + var timeLabel = prettydate.format(trdate); + + template += ''; + template += ''; + template += '...'; + + template += ''; + template += ''; + template += '' + template += amountLabel; + template += ''; + + template += ''; + template += '
    '; + template += timeLabel; + template += '
    '; + template += '
    '; + + template += ''; + template += '
    '; + if (transactions[i].Confirmations < 6) { + template += ''; + template += transactions[i].Confirmations; + template += ''; + } + template += '
    '; + template += ''; + template += friendLabel; + template += ''; + template += '
    '; + template += '
    '; + + } + + $('#transfeed').html(template); + + for (var i = 0; i < transactions.length && i < 51; i++) { + + + $('#dtran' + i).hammer(null).bind("tap", { + index: i + }, function (event) { + + if (!scrolling) { + + displayTransactionDetails(transactions[event.data.index], "dashboard"); + + + } + + }); + } + + + } else { + + //optimise + + $('#transfeed .conf').each(function (index, elem) { + + var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + + var template = ''; + if (tran.Confirmations < 6) { + template += ''; + template += _.escape(tran.Confirmations); + template += ''; + } + + $(elem).html(template); + + }); + + $('#transfeed .trntime').each(function (index, elem) { + + var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + + var trdate = new Date(tran.TransDateTime.match(/\d+/)[0] * 1); + + var timeLabel = prettydate.format(trdate); - if (selectedFriend.profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + selectedFriend.profileImage + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - } - $("#friendSelectedStatus").text(''); - if (selectedFriend.status != '') { - $("#friendSelectedStatus").text(selectedFriend.status); - } + $(elem).html(timeLabel); - $("#imgSelectedFriend").attr("src", imageSrc); + }); + } - if (selectedFriend.validated) { + return callback(err, "ok"); - $("#tapvalidatefriend").hide(); - $("#tapsendfriend").show(); + }); - } else { + } - $("#tapvalidatefriend").show(); - $("#tapsendfriend").hide(); - } - $('#tblnetinvbyme tbody').empty(); - $('#tblnetinvforme tbody').empty(); + var prevNetworkTransCount = 0; + function showTransactionNetwork(callback) { + var transactions = _.filter(transactionCache, function (tran) { return tran.UserName == SELECTEDFRIEND; }); + if (prevNetworkTransCount < transactions.length) { - lastInvoiceToPayNetCount = 0; - lastInvoiceByMeNetCount = 0; + prevNetworkTransCount = transactions.length; - showInvoiceListNetwork(); - showInvoiceByMeListNetwork(); + var template = ''; - showTransactionNetwork(); + for (var i = 0; i < transactions.length; i++) { - //$("#pnlfriend").show(); - //$("#friendheader").show(); + var amountLabel = ""; + var friendLabel = ""; + if (transactions[i].TransType == 'S') { + amountLabel = "sent " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); + friendLabel = "to " + _.escape(transactions[i].UserName); + } - } + if (transactions[i].TransType == 'R') { + amountLabel = "received " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); + friendLabel = "from " + _.escape(transactions[i].UserName); + } - norefresh = false; + var trdate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); + var timeLabel = prettydate.format(trdate); + template += ''; + template += ''; + template += ''; + template += amountLabel; + template += ''; - if (callback) { - callback(false, "ok"); - } + template += ''; + template += '
    '; + template += timeLabel; + template += '
    '; + template += '
    '; - } + template += ''; + template += '
    '; + if (transactions[i].Confirmations < 6) { + template += ''; + template += transactions[i].Confirmations; + template += ''; + } + template += '
    '; + template += ''; + template += friendLabel; + template += ''; + template += '
    '; + template += '
    '; + } + $('#netpayfeed').html(template); + for (var i = 0; i < transactions.length && i < 51; i++) { + $('#ntran' + i).hammer(null).bind("tap", { + index: i + }, function (event) { - var lastNoOfFriendsReq = 0; - var selectedFriendRequest = ''; + if (!scrollingnettran) { - function updateFriendRequests(callback) { + displayTransactionDetails(transactions[event.data.index], "network"); - //if there are any new friends - //fade in the button + } - //to do, move to handlebars templates - Engine.getFriendRequests(function (err, ofriends) { + }); + } + } else { - //if origin of friend request is qrcode - //and no phrase cache - //delay for 60 seconds - //add accept with scan button - //then return to standard after 5 minutes - var friends = []; - for (var i = 0; i < ofriends.length; i++) { + $('#netpayfeed .conf').each(function (index, elem) { - if (contactPhraseCache[ofriends[i].userName]) { - //acceptAndValidateFriend(ofriends[i].userName); - } else { - friends.push(ofriends[i]); + var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + + var template = ''; + if (tran.Confirmations < 6) { + template += ''; + template += _.escape(tran.Confirmations); + template += ''; } - } + $(elem).html(template); + console.log('updating 1'); - if (friends.length > 0) { - $("#dashrequests").show(); + }); - } else { - $("#dashrequests").hide(); - } + $('#netpayfeed .trntime').each(function (index, elem) { - //$("#notifications").text(friends.length); - //$("#notificationsright").text(friends.length); - //$("#nfriendreq").text(friends.length); + var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + + var trdate = new Date(tran.TransDateTime.match(/\d+/)[0] * 1); + var timeLabel = prettydate.format(trdate); + $(elem).html(timeLabel); + console.log('updating 2'); - if (lastNoOfFriendsReq != friends.length || friends.length == 0) { + }); - lastNoOfFriendsReq = friends.length; + } - if (friends.length > 0) { - $("#notifications").attr("class", "badge bg-danger pull-right"); - } else { - $("#notifications").attr("class", "badge pull-right"); - } - $("#nfriendreq").text(friends.length); - $("#friendreq").text(''); - for (var i = 0; i < friends.length; i++) { + } - var length = friends[i].userName.length; - if (length > 20) { - length = 20; - } - var template = '
  • ' + - 'John said' + - '' + - '
    ' + - '' + _.escape(friends[i].userName) + '' + - '
  • '; + var transactionDetailMode = 'dashboard'; - $("#friendreq").append(template); + function displayTransactionDetails(tran, mode) { - } + transactionDetailMode = mode; - for (var i = 0; i < friends.length; i++) { + var trdate = new Date(tran.TransDateTime.match(/\d+/)[0] * 1).toString("yyyy-MM-dd HH:mm tt"); - $("#friendreq #tapfriendreq" + i).hammer(null).bind("tap", { userName: friends[i].userName }, function (ev) { - selectedFriendRequest = ev.data.userName; + var tranhtml = ''; - $("#friendrequestusername").text(selectedFriendRequest); - $("#mainWallet").hide(); - $("#networklistheader").hide(); - $(".footer").hide(); - $("#contactrequest").show(); + tranhtml += '
    Date:'; + tranhtml += '
    '; + tranhtml += '
    '; + tranhtml += _.escape(trdate); + tranhtml += '
    '; + tranhtml += '
    '; + tranhtml += '
    Transaction Id:
    '; + tranhtml += '
    '; - }); + tranhtml += '
    '; + tranhtml += _.escape(tran.TransactionId); + tranhtml += '
    '; - } - } - if (callback) { - callback(false, "done"); - } - }); + tranhtml += '
    '; + tranhtml += '
    Address:
    '; + tranhtml += '
    '; - } + tranhtml += '
    '; + tranhtml += _.escape(tran.Address); + tranhtml += '
    '; + tranhtml += '
    Amount:' + tranhtml += '
    '; + tranhtml += '
    '; + tranhtml += convertFromSatoshis(tran.Amount, COINUNIT) + ' ' + COINUNIT; + tranhtml += '
    '; + tranhtml += '
    '; + tranhtml += 'Send/Receive:' + tranhtml += '
    '; - $('#btnContactRequestClose').bind('touchstart', function () { + tranhtml += '
    '; + tranhtml += _.escape(tran.TransType); + tranhtml += '
    '; - $("#contactrequest").hide(); - $("#mainWallet").show(); - $("#networklistheader").show(); - $(".footer").show(); - $("friendrequestp1").show(); - $("friendrequestp2").hide(); - }); + if (transactionDetailMode == 'dashboard') { + $("#dashheader").hide(); + } else { + $("#friendheader").hide(); + } - $('#btnAcceptContactDone').bind('touchstart', function () { + $("#mainWallet").hide(); + $(".footer").hide(); + $("#transview").addClass("slideUp"); + $('#transdets').html(tranhtml); - $("#contactrequest").hide(); - $("#mainWallet").show(); - $("#networklistheader").show(); - $(".footer").show(); - $("friendrequestp1").show(); - $("friendrequestp2").hide(); + } - }); + function generateAddressClient() { - $('#btnContactReject').bind('touchstart', function () { - rejectFriend(event.data.userName, function (err, res) { + $("#newaddrspinner").show(); + var target = document.getElementById('newaddrspinner'); + var spinner = new Spinner(spinneropts).spin(target); + + Engine.createAddress('m/0/0', 1, function (err, newAddress, path) { if (!err) { - selectedFriendRequest = ''; - updateFriendRequests(); + var options = { text: newAddress, width: 172, height: 172 }; - $("#friendrequestusername").text(''); - $("#contactrequest").hide(); - $("#mainWallet").show(); - $("#networklistheader").show(); - $(".footer").show(); - } + $('#requestaddressqr').show(); + $('#requestaddressqr').text(''); + $('#requestaddressqr').qrcode(options); - }); + $('#requestaddresstxt').text(newAddress); - }); + //$('#requestaddress').text(tempate); + $("#newaddrspinner").hide(); + $('#requestaddress').show(); - function acceptAndValidateFriend(username, message, callback) { + } else { + $('#requestaddressqr').hide(); + $('#requestaddress').show(); + $("#newaddrspinner").hide(); + $('#requestaddresstxt').text(newAddress); + } + }); - if ($(message)) { - $(message).text('Accepting friend request...'); - } + } - acceptFriend(username, message, function (err, res) { - //handle here instead + function sendMoney(friend, index) { - console.log('accept contact'); + $('#textMessageSend').removeClass('alert alert-danger'); - console.log(contactPhraseCache[username]); - console.log(err); + if (friend == null) { + return; + } - if (!err) { + var pin = $('#sendstdpin').val(); - console.log('accepted request'); + var amount = $('#hdamount').val(); - lastNoOfFriendsReq = 0; - updateFriendRequests(); + amount = convertToSatoshis(amount, COINUNIT); - //$("#imgrequestwaiting").hide(); + if (amount > 0) { - if (contactPhraseCache[username]) { - if ($(message)) { - $(message).text('Validating contact...'); - } + Engine.getDeviceKey(pin, function (err, ekey) { - console.log('found phrase'); + if (!err) { - console.log('found phrase'); - console.log(contactPhraseCache[username]) - var code = contactPhraseCache[username]; - var bip39 = new BIP39(); - code = bip39.mnemonicToHex(code); + $('#sendprogress').show(); + $('#pinconfirm').hide(); - if (code.length == 40) { + $('.numdone').attr("style", "background-color:white"); + $("#sendstdpin").val(''); + pintaps = 0; + prevpin = ''; - Engine.verifyFriendData(username, code, function (err, result) { - if (result) { + $('#textMessageSendStd').text('Creating transaction...'); + $('#textMessageSendStd').show(); + $('#sendstdprogstatus').width('10%'); + $('#sendstdprognum').text('10%'); + $('#sendstdprog').show(); - if ($(message)) { - $(message).text('Validated...'); - } - console.log('verified'); - console.log(result); - lastNoOfFriends = 0; - updateFriends(); + setTimeout(function () { - if (callback) { + Engine.sendTransaction('friend', friend, "", amount, ekey.DeviceKey, function (err, transactionid) { - callback(false, "ok"); + if (!err) { - } + $('#textMessageSendStd').text('You sent ' + convertFromSatoshis(amount, COINUNIT) + ' ' + COINUNIT + ' to ' + friend); - //updateSelectedFriend(); - //update list also + updateUI(); - //find friend in list and update the validated icon - //$("#myfriends #seltarget" + selectedFriend.userName).text('
    '); + sendAmount = ''; - } + updateStdAmount(); - }); + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); - } + $("#sendstdpin").val(''); + $('.numdone').attr("style", "background-color:white"); + pintaps = 0; + prevpin = ''; - //get the hash to validate against - //this will confirm that my friend has the same keys - //i orginally packaged for him + } else { - } else { + $('#sendstdprogstatus').width('0%'); + $('#sendstdprognum').text('0%'); - if (callback) { + if (transactionid == "ErrInsufficientFunds") { + $('#textMessageSendStd').text('Transaction Failed: Waiting for funds to clear'); + } - callback(false, "ok"); + //return to send screen + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); - } + } + // alert(transactionid); + }, function (message, progress) { - } + if (message) { + $('#textMessageSendStd').text(message); + } - } + if (progress) { + $('#sendstdprogstatus').width(progress); + $('#sendstdprognum').text(progress); + } + }); + }, 50); - }); - } + } else { - var prevtransfeed = -1; - var transactionCache = []; - function showTransactionFeed(callback) { + $('.numdone').attr("style", "background-color:white"); - Engine.getTransactionRecords(function (err, transactions) { + $("#sendstdpin").val(''); + pintaps = 0; + prevpin = ''; - allTransactions = transactions; - transactionCache = transactions; + if (ekey.substring(0, 6) == "ErrPIN") { - if (transactions.length != prevtransfeed) { + var attempts = ekey.substring(7, 8); + //$("#pinconfmessage").text("Incorrect PIN " + attempts + "/3 attempts"); - for (var i = 0; i < allTransactions.length; i++) { - var d1 = new Date(allTransactions[i].TransDateTime); - allTransactions[i].JsDate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); - transactionIndex[allTransactions[i].TransactionId] = i; - } + $("#pinconfcount").effect("shake"); + } else { + bootbox.alert(ekey); - prevtransfeed = transactions.length; + } - $('#transfeed').empty(); + } - var template = ''; + }); - for (var i = 0; i < transactions.length && i < 11; i++) { + } else { + $('input#friendAmount').css("border-color", "#ffaaaa"); + } - var length = transactions[i].UserName.length; - if (length > 20) { - length = 20; - } - var imageSrcSmall = "images/avatar/32px/Avatar-" + pad(length) + ".png"; + } - if (transactions[i].UserName != 'External') { - if (FRIENDSLIST[transactions[i].UserName]) { - if (FRIENDSLIST[transactions[i].UserName].profileImage != '') { - imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(FRIENDSLIST[transactions[i].UserName].profileImage) + "?crop=faces&fit=crop&h=128&w=128&mask=ellipse&border=1,d0d0d0"; - } - } - } - var amountLabel = ""; - var friendLabel = ""; - if (transactions[i].TransType == 'S') { - amountLabel = "sent " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); - friendLabel = "to " + _.escape(transactions[i].UserName); - } - if (transactions[i].TransType == 'R') { - amountLabel = "received " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); - friendLabel = "from " + _.escape(transactions[i].UserName); - } + function sendMoneyStd() { - var trdate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); - var timeLabel = prettydate.format(trdate); - template += ''; - template += ''; - template += '...'; + //get pin from user + //get device key + //pass the device key as the 2fa code - template += ''; - template += ''; - template += ''; - template += amountLabel; - template += ''; + var amount = $('#hdamount').val(); + amount = convertToSatoshis(amount, COINUNIT); - template += ''; - template += '
    ' - template += timeLabel; - template += '
    '; - template += '
    '; + var address = $('input#toAddress').val(); - template += ''; - template += '
    '; - if (transactions[i].Confirmations < 6) { - template += ''; - template += transactions[i].Confirmations; - template += ''; - } - template += '
    '; - template += ''; - template += friendLabel; - template += ''; - template += '
    '; - template += '
    '; + //$('#textMessageSendStd').removeClass('alert alert-danger'); + //check for valid bitcoin address - } + var allok = true; - $('#transfeed').html(template); + var pin = $('#sendstdpin').val(); - } else { + if (allok) { - //optimise + Engine.getDeviceKey(pin, function (err, ekey) { - $('#transfeed .conf').each(function (index, elem) { + if (!err) { - var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + $('#sendprogress').show(); + $('#pinconfirm').hide(); - var template = '' - if (tran.Confirmations < 6) { - template += ''; - template += _.escape(tran.Confirmations); - template += ''; - } - $(elem).html(template); + $('#textMessageSendStd').text('Creating transaction...'); + $('#textMessageSendStd').show(); + $('#sendstdprogstatus').width('3%'); + $('#sendstdprog').show(); + $('#sendstdprogstatus').width('10%'); - }); + $('#sendstdprognum').text('10%'); - $('#transfeed .trntime').each(function (index, elem) { + setTimeout(function () { - var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + Engine.sendTransaction('standard', '', address, amount, ekey.DeviceKey, function (err, transactionid) { - var trdate = new Date(tran.TransDateTime.match(/\d+/)[0] * 1); + if (!err) { - var timeLabel = prettydate.format(trdate); + $('#textMessageSendStd').html('You sent ' + _.escape(convertFromSatoshis(amount, COINUNIT)) + ' ' + _.escape(COINUNIT) + ' to ' + address + ''); - $(elem).html(timeLabel); + updateUI(); - }); + sendAmount = ''; + updateStdAmount(); - } + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); - return callback(err, "ok"); + $("#sendstdpin").val(''); + $('.numdone').attr("style", "background-color:white"); - }); + pintaps = 0; + prevpin = ''; - } + } else { + $('#sendstdprogstatus').width('0%'); + $('#sendstdprognum').text('0%'); - // + if (transactionid == "ErrInsufficientFunds") { + $('#textMessageSendStd').text('Transaction Failed: Waiting for funds to clear'); + } - var prevNetworkTransCount = 0; + setTimeout(function () { + $("#btnStdSndDone").show(); + }, 100); - function showTransactionNetwork(callback) { + $("#sendstdpin").val(''); + $('.numdone').attr("style", "background-color:white"); - var transactions = _.filter(transactionCache, function (tran) { return tran.UserName == SELECTEDFRIEND; }); + pintaps = 0; + prevpin = ''; - if (prevNetworkTransCount < transactions.length) { + } - prevNetworkTransCount = transactions.length; + }, function (message, progress) { - var template = ''; + if (message) { + $('#textMessageSendStd').text(message); + } - for (var i = 0; i < transactions.length; i++) { + if (progress) { + $('#sendstdprogstatus').width(progress); + $('#sendstdprognum').text(progress); + } - var amountLabel = ""; - var friendLabel = ""; + }); - if (transactions[i].TransType == 'S') { - amountLabel = "sent " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); - friendLabel = "to " + _.escape(transactions[i].UserName); - } + }, 50); - if (transactions[i].TransType == 'R') { - amountLabel = "received " + convertFromSatoshis(transactions[i].Amount, COINUNIT) + " " + _.escape(COINUNIT); - friendLabel = "from " + _.escape(transactions[i].UserName); - } + } else { - var trdate = new Date(transactions[i].TransDateTime.match(/\d+/)[0] * 1); - var timeLabel = prettydate.format(trdate); - template += ''; - template += ''; + $('.numdone').attr("style", "background-color:white"); - template += ''; - template += amountLabel; - template += ''; + $("#sendstdpin").val(''); - template += ''; - template += '
    ' - template += timeLabel; - template += '
    '; - template += '
    '; + pintaps = 0; + prevpin = ''; - template += ''; - template += '
    '; - if (transactions[i].Confirmations < 6) { - template += ''; - template += transactions[i].Confirmations; - template += ''; - } - template += '
    '; - template += ''; - template += friendLabel; - template += ''; - template += '
    '; - template += '
    '; - } + if (ekey.substring(0, 6) == "ErrPIN") { - $('#netpayfeed').html(template); + var attempts = ekey.substring(7, 8); - } else { + //$("#pinconfmessage").text("Incorrect PIN " + attempts + "/3 attempts"); + $("#pinconfcount").effect("shake"); - $('#netpayfeed .conf').each(function (index, elem) { + } else { - var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; + bootbox.alert(ekey); - var template = '' - if (tran.Confirmations < 6) { - template += ''; - template += _.escape(tran.Confirmations); - template += ''; + } } - $(elem).html(template); - console.log('updating 1'); }); + } - $('#netpayfeed .trntime').each(function (index, elem) { - - var tran = allTransactions[transactionIndex[transactions[index].TransactionId]]; - - var trdate = new Date(tran.TransDateTime.match(/\d+/)[0] * 1); + } - var timeLabel = prettydate.format(trdate); - $(elem).html(timeLabel); + function acceptAndValidateFriend(username, message, callback) { - console.log('updating 2'); + var needToAccept = false; + if (FRIENDSLIST[username]) { - }); + if (!FRIENDSLIST[username].ICanSend) { + needToAccept = true; + } + } else { + needToAccept = true; } + if (needToAccept) { + acceptFriend(username, message, function (err, res) { - } - - - function generateAddressClient() { + if (!err) { - $("#newaddrspinner").show(); - var target = document.getElementById('newaddrspinner'); - var spinner = new Spinner(spinneropts).spin(target); + lastNoOfFriendsReq = 0; + updateFriendRequests(); - Engine.createAddress('m/0/0', 1, function (err, newAddress, path) { + if (contactPhraseCache[username]) { - var options = { text: newAddress, width: 172, height: 172 }; + message("ValidateContact"); - $('#requestaddressqr').text(''); - $('#requestaddressqr').qrcode(options); + var code = contactPhraseCache[username]; - $('#requestaddresstxt').text(newAddress); + validateContact(username, code, function (err, result) { - //$('#requestaddress').text(tempate); - $("#newaddrspinner").hide(); - $('#requestaddress').show(); + lastNoOfFriends = 0; + updateFriends(function (err, result) { + return callback(err, result); - }); + }); - } + }); + } else { - function sendMoney(friend, index) { + if (callback) { - $('#textMessageSend').removeClass('alert alert-danger'); + return callback(false, "ok"); - if (friend == null) { - return; - } + } - var pin = $('#sendstdpin').val(); - var amount = $('#amount').text(); - amount = convertToSatoshis(amount, COINUNIT); + } - if (amount > 0) { + } + }); - Engine.getDeviceKey(pin, function (err, ekey) { + } else { - if (!err) { + if (contactPhraseCache[username]) { + message("ValidateContact"); - $('#sendprogress').show(); - $('#pinconfirm').hide(); + var code = contactPhraseCache[username]; + validateContact(username, code, function (err, result) { - $('#textMessageSendStd').text('Creating transaction...'); - $('#textMessageSendStd').show(); - $('#sendstdprogstatus').width('3%') - $('#sendstdprog').show(); - $('#sendstdprogstatus').width('10%'); + return callback(err, result); - $('#sendstdprognum').text('10%'); + }); + } else { + if (callback) { - Engine.sendTransaction('friend', friend, "", amount, ekey.DeviceKey, function (err, transactionid) { + return callback(false, "ok"); - if (!err) { + } - $('#textMessageSend').text('You sent ' + convertFromSatoshis(amount, COINUNIT) + ' ' + COINUNIT + ' to ' + friend); - $('input#amount').text(''); + } - updateUI(); - updateStdAmount(); + } + } - setTimeout(function () { - $("#btnStdSndDone").show(); - }, 100); + function registerCode(username, phrase) { - $("#sendstdpin").val(''); - $('.numdone').attr("style", "background-color:white"); + var bip39 = new BIP39(); + var code = bip39.mnemonicToHex(phrase); + contactPhraseCache[username] = code; - } else { - $('#textMessageSend').addClass('alert alert-danger'); - $('#sendfriendprogstatus').width('0%') + } - if (transactionid == "ErrInsufficientFunds") { - $('#textMessageSend').text('Transaction Failed: Waiting for funds to clear'); - } - } - // alert(transactionid); - }); + function validateContact(username, code, callback) { - } else { + if (code.length == 40) { - $('.numdone').attr("style", "background-color:white"); - $("#sendstdpin").val(''); - $('#confpinalert').show(); - $('#confpinalertmess').text(ekey) + Engine.verifyFriendData(username, code, function (err, result) { - } + callback(err, result); }); } else { - $('input#friendAmount').css("border-color", "#ffaaaa"); - } - - - } + callback(true, "invalid code"); - function sendMoneyStd() { + } + } - //get pin from user - //get device key - //pass the device key as the 2fa code - var amount = $('#amount').text(); - amount = convertToSatoshis(amount, COINUNIT); - var address = $('input#toAddress').val(); + var checkAndValidateTimer = null; - $('#textMessageSendStd').removeClass('alert alert-danger'); - //check for valid bitcoin address - var allok = true; - if (Engine.isAddressValid(address)) { - $('input#toAddress').css("border-color", "#ccc"); - } else { - $('input#toAddress').css("border-color", "#ffaaaa"); - allok = false; - } - if (amount > 0) { - $('#amount').css("border-color", "#ccc"); - } else { - $('#amount').css("border-color", "#ffaaaa"); - allok = false; - } + function clearCheckAndValidateTimer() { + console.log('clearing timer'); + clearInterval(checkAndValidateTimer); + } - var pin = $('#sendstdpin').val(); - if (allok) { + function checkAndValidateFriendRequests() { - Engine.getDeviceKey(pin, function (err, ekey) { + console.log('checking...'); - if (!err) { + $("#textAddContact").text('Verifying request...'); + $("#addcontactprognum").text("10%"); + $("#addcontactprogstatus").width("10%"); + Engine.getFriendRequests(function (err, ofriends) { - $('#sendprogress').show(); - $('#pinconfirm').hide(); + console.log('found ' + ofriends.length); + if (ofriends.length > 0) { + $("#contaddprog").show(); + $("#contaddscan").hide(); + } - $('#textMessageSendStd').text('Creating transaction...'); - $('#textMessageSendStd').show(); - $('#sendstdprogstatus').width('3%') - $('#sendstdprog').show(); - $('#sendstdprogstatus').width('10%'); + var targetFriend = null; - $('#sendstdprognum').text('10%'); + var friends = []; + for (var i = 0; i < ofriends.length; i++) { - Engine.sendTransaction('standard', '', address, amount, ekey.DeviceKey, function (err, transactionid) { + if (ofriends[i].userName == currentContactExchange) { + targetFriend = ofriends[i]; + } + } - if (!err) { + if (targetFriend) { - $('#textMessageSendStd').html('You sent ' + _.escape(convertFromSatoshis(amount, COINUNIT)) + ' ' + _.escape(COINUNIT) + ' to ' + address + ''); - $('input#amount').text(''); + if (contactPhraseCache[targetFriend.userName]) { - updateUI(); - updateStdAmount(); + clearCheckAndValidateTimer(); - setTimeout(function () { - $("#btnStdSndDone").show(); - }, 100); + $("#addcontactprognum").text("20%"); + $("#addcontactprogstatus").width("20%"); - $("#sendstdpin").val(''); - $('.numdone').attr("style", "background-color:white"); + acceptAndValidateFriend(targetFriend.userName, - } else { + function (message) { - if (transactionid == "ErrInsufficientFunds") { - $('#textMessageSendStd').text('Transaction Failed: Waiting for funds to clear'); - } + var prog = ""; + var mess = ""; - $('#sendstdprogstatus').width('0%') - $('#textMessageSendStd').addClass('alert alert-danger'); - $("#sendstdpin").val(''); + if (message == "AcceptFriendRequest") { + mess = "Accepting request..."; + prog = "50%"; } - }); + if (message == "CreateFriend") { + mess = "Creating contact..."; + prog = "60%"; + } + if (message == "ValidateContact") { + mess = "Validating contact..."; + prog = "80%"; + } - } else { + $("#addcontactprognum").text(prog); + $("#addcontactprogstatus").width(prog); + $("#textAddContact").text(mess) - //display pin error - $('.numdone').attr("style", "background-color:white"); - $("#sendstdpin").val(''); - $('#confpinalert').show(); - $('#confpinalertmess').text(ekey); - } + } + , function (err, result) { + if (!err) { - }); - } + $("#addcontactprognum").text("100%"); + $("#addcontactprogstatus").width("100%"); - } + setTimeout(function () { + $("#addcontactmodal").hide(); - var checkAndValidateTimer = null; + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + $("#contactrequest").hide(); - function clearCheckAndValidateTimer() { - clearInterval(checkAndValidateTimer); - } + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + }, 1000); - function checkAndValidateFriendRequests() { - Engine.getFriendRequests(function (err, ofriends) { - var friends = []; - for (var i = 0; i < ofriends.length; i++) { - if (contactPhraseCache[ofriends[i].userName]) { + } else { - clearCheckAndValidateTimer(); + $("#textAddContact").text(result); + } - console.log('found request...accepting and validating'); - acceptAndValidateFriend(ofriends[i].userName); + }); - return; } + } + + }); } @@ -3951,23 +4663,43 @@ function UI() { $("#btnAcceptContactDone").hide(); $("#friendrequestp1").hide(); $("#friendrequestp2").show(); - $("#acceptcontactprognum").text('10%'); - $("#acceptcontactprog").width('10%'); + $("#acceptcontactprognum").text('5%'); + $("#acceptcontactprog").width('5%'); + acceptAndValidateFriend(selectedFriendRequest, function (message) { - acceptAndValidateFriend(selectedFriendRequest, "#acceptcontactprogmess", function (err, result) { + var prog = ""; + var mess = ""; - if (!err) { + if (message == "AcceptFriendRequest") { + mess = "Accepting request..."; + prog = "20%"; + } + + if (message == "CreateFriend") { + mess = "Creating contact..."; + prog = "70%"; + } + + if (message == "ValidateContact") { + mess = "Validating contact..."; + prog = "90%"; + } + + $("#acceptcontactprognum").text(prog); + $("#acceptcontactprog").width(prog); + $("#acceptcontactprogmess").text(mess) + }, function (err, result) { + + if (!err) { - $("#acceptcontactprognum").text('70%'); - $("#acceptcontactprog").width('70%'); updateFriendRequests(function (err, result) { - $("#acceptcontactprognum").text('80%'); - $("#acceptcontactprog").width('80%'); + $("#acceptcontactprognum").text('90%'); + $("#acceptcontactprog").width('90%'); updateFriends(function (err, result) { @@ -3996,6 +4728,8 @@ function UI() { }); + var currentContactExchange = ''; + //function when connecting from main add contact screen $("#hdqrcontact").change(function () { @@ -4010,10 +4744,14 @@ function UI() { console.log(phrase); console.log(username); - contactPhraseCache[username] = phrase; + currentContactExchange = username; + + registerCode(username, phrase); $("#addcontactmodal").show(); - $("#dashcontact").hide(); + + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); //$("#imgaddcontactwaiting").show(); @@ -4054,13 +4792,16 @@ function UI() { Engine.getFriendRequests(function (err, ofriends) { - var friends = _.filter(ofriends, function (frn) { return frn.UserName == username; }); + console.log("logging friend request filter..."); + console.log(ofriends); - if (friends.length == 0) { + var friends = _.filter(ofriends, function (frn) { return frn.userName == username; }); - console.log('network not exists'); + console.log(friends); + if (friends.length == 0) { + console.log('friend request does not exist'); //if network doesnt exist create friend @@ -4071,11 +4812,14 @@ function UI() { if (!result) { + console.log('network does not exist'); + $("#textAddContact").text('Deriving addresses...'); $("#addcontactprognum").text("60%"); $("#addcontactprogstatus").width("60%"); + console.log('creating friend...'); Engine.createFriend(username, "#qrcontactmess", function (err, result) { @@ -4092,110 +4836,184 @@ function UI() { } else { + + //if there is a pending friend request + //skip this bit + console.log('added timer for check and validate'); //here we go to - now you friend should scan this code - checkAndValidateTimer = setInterval(function () { checkAndValidateFriendRequests() }, 2000); + checkAndValidateTimer = setInterval(function () { + checkAndValidateFriendRequests(); + } + , 2000); //listen for 2 minutes - setTimeout(clearCheckAndValidateTimer(), 120000); + setTimeout(function () { + clearCheckAndValidateTimer(); + + //timed out so return the user to screen + + + $("#addcontactmodal").hide(); + + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + + $("#contactrequest").hide(); + + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + + + }, 60000); $("#addcontactprognum").text("100%"); $("#addcontactprogstatus").width("100%"); //$("#imgaddcontactwaiting").hide(); //$("#addcontactmodal").hide(); - $("#textAddContact").text("Successfully added " + username + " as a contact"); - } - }); - } else { + setTimeout(function () { - $("#textAddContact").text('validating...'); + $("#contaddprog").hide(); + $("#contaddscan").show(); - $("#addcontactprognum").text("80%"); - $("#addcontactprogstatus").width("80%"); + $("#scancontqrmess").text("Now ask " + username + " to scan the QR code below:"); + }, 1000); + + //$("#textAddContact").text("Now scan the QR code from " + username); + } + }); + } else { - //if already accepted validate only + acceptAndValidateFriend(username, function (message) { - var needToAccept = false; - if (FRIENDSLIST[username]) { + var prog = ""; + var mess = ""; - if (!FRIENDSLIST[username].ICanSend) { - needToAccept = true; + if (message == "AcceptFriendRequest") { + mess = "Accepting request..."; + prog = "50%"; } - } else { - needToAccept = true; - } - + if (message == "CreateFriend") { + mess = "Creating contact..."; + prog = "60%"; + } - if (needToAccept) { + if (message == "ValidateContact") { + mess = "Validating contact..."; + prog = "80%"; + } - acceptAndValidateFriend(username, "", function (err, result) { + $("#addcontactprognum").text(prog); + $("#addcontactprogstatus").width(prog); + $("#textAddContact").text(mess) - if (!err) { + }, function (err, result) { - $("#addcontactprognum").text("100%"); - $("#addcontactprogstatus").width("100%"); - $("#textAddContact").text("Successfully added " + username + " as a contact"); - } + if (!err) { + setTimeout(function () { + $("#addcontactmodal").hide(); - }); + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + $("#contactrequest").hide(); - } else { + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); - console.log('caught event...'); + }, 1000); - var bip39 = new BIP39(); - code = bip39.mnemonicToHex(phrase); - console.log(code); + } else { - if (code.length != 40) { + $("#textAddContact").text(result); + $("#btnAddContactDone").show(); - return; } - Engine.verifyFriendData(username, code, function (err, result) { + }); - $("#addcontactprognum").text("100%"); - $("#addcontactprogstatus").width("100%"); + } - $("#textAddContact").text("Successfully verified " + username + " as a contact"); + } - //update contact list - updateFriends(); + }); - }); + } else if (friends.length == 1) { - } + //validate using the fingerprint + acceptAndValidateFriend(username, function (message) { - } + var prog = ""; + var mess = ""; + if (message == "AcceptFriendRequest") { + mess = "Accepting request..."; + prog = "50%"; } - }); + if (message == "CreateFriend") { + mess = "Creating contact..."; + prog = "60%"; + } - } else if (friends.length == 1) { + if (message == "ValidateContact") { + mess = "Validating contact..."; + prog = "80%"; + } + $("#addcontactprognum").text(prog); + $("#addcontactprogstatus").width(prog); + $("#textAddContact").text(mess) - //validate using the fingerprint - acceptAndValidateFriend(username, "#textAddContact", function (err, result) { + + }, function (err, result) { if (!err) { $("#addcontactprognum").text("100%"); $("#addcontactprogstatus").width("100%"); - $("#textAddContact").text("Successfully added " + username + " as a contact"); + setTimeout(function () { + + $("#addcontactmodal").hide(); + + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + + $("#contactrequest").hide(); + + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + + }, 1000); + + + + } else { + + $("#textAddContact").text(result); + $("#btnAddContactDone").show(); + } @@ -4212,9 +5030,90 @@ function UI() { } }); + }); + + + + $("#hdvalcontact").change(function () { + + console.log('caught event...'); + + var res = $("#hdvalcontact").val(); + var sres = res.split(','); + var phrase = sres[0]; + var username = sres[1]; + + $("#netvalidp2").show(); + $("#netvalidp1").hide(); + + + registerCode(username, phrase); + + acceptAndValidateFriend(username, function (message) { + var prog = ""; + var mess = ""; + if (message == "AcceptFriendRequest") { + mess = "Accepting request..."; + prog = "30%"; + } + + if (message == "CreateFriend") { + mess = "Creating contact..."; + prog = "60%"; + } + + if (message == "ValidateContact") { + mess = "Validating contact..."; + prog = "80%"; + } + + $("#netvalidprognum").text(prog); + $("#netvalidprog").width(prog); + $("#netvalidprogmess").text(mess) + + + }, function (err, result) { + + if (!err) { + + selectedFriend.validated = true; + FRIENDSLIST[selectedFriend.userName].validated = true; + updateSelectedFriend(); + + $("#netvalidprognum").text('100%'); + $("#netvalidprogmess").text('Contact validated'); + $("#netvalidprog").width('100%'); + + setTimeout(function () { + + //$("#validateform").hide(); + //$("#validatesuccess").show(); + $("#txtCode").val(''); + + $("#networkvalidate").hide(); + $("#friendheader").show(); + $("#mainWallet").show(); + $(".footer").show(); + + $("#netvalidp2").hide(); + $("#netvalidp1").show(); + //update list also + + //find friend in list and update the validated icon + $("#myfriends #seltarget" + selectedFriend.userName).html('
    '); + + }, 1000); + + } else { + $("#netvalidprogmess").text(result); + $("#btnNetValidDone").show(); + + } + + }); }); @@ -4251,8 +5150,9 @@ function UI() { if (!result) { $("#addcontactmodal").show(); - $("#dashcontact").hide(); + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); //$("#imgaddcontactwaiting").show(); //var target = document.getElementById('imgaddcontactwaiting'); @@ -4273,38 +5173,51 @@ function UI() { $("#textAddContact").text('Deriving addresses...'); + Engine.createFriend(username, "", function (err, result) { - Engine.createFriend(username, "#textAddContact", function (err, result) { if (err) { - //$("#friend").css("border-color", "#ffaaaa"); + $("#friend").css("border-color", "#ffaaaa"); - //$("#addcontactalert").show(); - //$("#addcontactalertmessage").text("Error adding contact"); - //$("#imgaddcontactwaiting").hide(); + $("#addcontactalert").show(); + $("#addcontactalertmessage").text("Error adding contact"); + $("#imgaddcontactwaiting").hide(); } else { $("#addcontactprognum").text("100%"); $("#addcontactprogstatus").width("100%"); - - //$("#addcontactmodal").hide(); $("#friend").val(''); - //$("#imgaddcontactwaiting").hide(); - //$("#addcontactsuccess").show(); $("#textAddContact").text("You requested " + username + " as a contact"); - //$("#addcontactsuccess").fadeOut(5000); + + setTimeout(function () { + $("#addcontactmodal").hide(); + + $("#dashcontact").addClass("invis"); + $("#dashcontact").removeClass("slideUp"); + + $("#contactrequest").hide(); + + $("#mainWallet").show(); + $("#networklistheader").show(); + $(".footer").show(); + $("#friendrequestp1").show(); + $("#friendrequestp2").hide(); + + }, 2000); //updateRequestsMadeByMe(); } + + }); } else { $("#friend").css("border-color", "#ffaaaa"); $("#addcontactalert").show(); - $("#textAddContact").text("You have already requested " + username + " as a contact"); + $("#addcontactalertmessage").text("You have already requested " + username + " as a contact"); //$("#imgaddcontactwaiting").hide(); } @@ -4323,7 +5236,6 @@ function UI() { } - function rejectFriend(username) { Engine.rejectFriendRequest(username, function (err, result) { @@ -4336,36 +5248,44 @@ function UI() { function acceptFriend(username, message, callback) { - console.log('calling accept acceptFriend'); + message("AcceptFriendRequest"); - // $("#imgrequestwaiting").show(); - //var target = document.getElementById('imgrequestwaiting'); - // var spinner = new Spinner(spinneropts).spin(target); + Engine.acceptFriendRequest(username, function (err, result) { - //$('#friendreq').fadeOut(1000); - Engine.acceptFriendRequest(username, function (err, secret) { if (err) { - //alert("Wallet could not be opened.\n\n" + err); + + return callback(err, result); + } else { - console.log('accepted'); + + Engine.isNetworkExist(username, function (err, result) { - if (!result) { + if (!err) { - Engine.createFriend(username, message, function (err, result) { + if (!result) { - if (err) { + message("CreateFriend"); - } else { + Engine.createFriend(username, message, function (err, result) { - return callback(err, result); - } - }); + if (err) { + + } else { + + return callback(err, result); + } + }); + + } else { + + return callback(err, result); + + } } else { return callback(err, result); - } }); diff --git a/src/ninki-ui.js b/src/ninki-ui.js index 9a5a5e6..b10a1a7 100644 --- a/src/ninki-ui.js +++ b/src/ninki-ui.js @@ -1,20 +1,13 @@ var Bitcoin = require('bitcoinjs-lib'); var BIP39 = require('./bip39'); -function UI() { - var Engine = new Ninki.Engine(); +function UI() { - // var WALLETINFORMATION = {}; - // var SHAREDID = ''; + var Engine = new Ninki.Engine(); - // var TWOFACTORONLOGIN = false; - // var NICKNAME = ''; - // var guid = ''; - // var oguid = ''; - // var password = ''; var FRIENDSLIST = {}; var COINUNIT = 'BTC'; @@ -85,97 +78,6 @@ function UI() { }; - - function setCookie(cname, cvalue) { - - - if (isChromeApp()) { - - var obj = {}; - obj[cname] = cvalue; - chrome.storage.local.set(obj, function () { - - console.log("saved"); - - }); - - } - else { - - localStorage[cname] = cvalue; - - } - - - } - - function isChromeApp() { - - var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; - if (is_chrome) { - if (chrome) { - if (chrome.app) { - if (chrome.app.runtime) { - return true; - } - } - } - } - return false; - } - - - function getCookie(cname, callback) { - - - if (isChromeApp()) { - - chrome.storage.local.get(cname, function (result) { - - if (result[cname]) { - result = result[cname]; - } else { - result = ""; - } - - return callback(result); - - }); - - } else { - - if (localStorage[cname]) { - return callback(localStorage[cname]); - } else { - return callback(''); - } - - } - - } - - function deleteCookie(cname) { - - - if (isChromeApp()) { - - chrome.storage.local.remove(cname, function () { - - console.log("deleted"); - - }); - - } else { - - localStorage.removeItem(cname); - - } - } - - - - - function getLocalTime(datetime) { var timestamp = datetime, @@ -233,6 +135,48 @@ function UI() { jQuery(document).ready(function () { + + + $("#btnBackupCodes").click(function () { + + $("#txt2faForBackupError").hide(); + + var twoFactorCode = $("#txt2faForBackup").val(); + + var codes = Engine.createBackupCodes(twoFactorCode, function (err, codes) { + + if (!err) { + + for (var i = 0; i < codes.length; i++) { + + $("#bc" + (i + 1)).text(codes[i].Code.substring(0, 5) + ' ' + codes[i].Code.substring(5, 8)); + } + + Engine.m_settings.BackupIndex = 1; + + $("#pnlBackupCodes").show(); + $("#btnPrintCodes").show(); + $("#btnBackupCodes").addClass('disabled'); + + } else { + + $("#txt2faForBackupError").show(); + + } + }); + + }); + + $("#btnPairUseBackups").click(function () { + + $("#pairerror").hide(); + $("#pairqr2fa").hide(); + $("#pairusebackup").show(); + + }); + + + $("#btnBackupBeta").click(function () { backupHotKey('#errbackupbeta'); @@ -242,7 +186,7 @@ function UI() { $('#openWalletStart input#password').focus(); - var fatokk = getCookie("ninki_rem", function (res) { + var fatokk = Engine.Device.getStorageItem("ninki_rem", function (res) { if (res.length > 0) { $('#twofacenable').show(); @@ -252,8 +196,8 @@ function UI() { var tmpContent = {}; $("#btnBrowseRestore").click(function () { - - chrome.fileSystem.chooseEntry({ type: 'openFile', accepts: [{ extensions: ['json']}] }, function (readOnlyEntry) { + //, accepts: [{ extensions: ['json']}] + chrome.fileSystem.chooseEntry({ type: 'openFile' }, function (readOnlyEntry) { readOnlyEntry.file(function (file) { var reader = new FileReader(); @@ -266,7 +210,7 @@ function UI() { if (e.target.result) { var json = JSON.parse(e.target.result); tmpContent = json; - restoreFromFile(m_this.m_password, json); + restoreFromFile(Engine.m_password, json); } else { $("#restoreerror").text('The file was empty'); } @@ -384,7 +328,7 @@ function UI() { $("#hunlock").click(function () { - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { chrome.app.window.create('recover_v1.html', { 'state': 'maximized' }); @@ -406,7 +350,7 @@ function UI() { $("#twofacenable").click(function () { - deleteCookie("ninki_rem"); + Engine.Device.deleteStorageItem("ninki_rem"); $('#twofacenable').hide(); }); @@ -442,7 +386,7 @@ function UI() { var imageSrc = "images/avatar/256px/Avatar-" + pad(Engine.m_nickname.length) + ".png"; - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -487,7 +431,7 @@ function UI() { } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -545,7 +489,7 @@ function UI() { imageSrc = "https://ninkip2p.imgix.net/" + _.escape(Engine.m_profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -625,7 +569,7 @@ function UI() { var file = files[0]; var fd = new FormData(); - key = "images\/" + Engine.m_nickname + '_' + (new Date).getTime() + key = "images\/" + Engine.m_nickname + '_' + (new Date).getTime(); Engine.createS3Policy(function (err, result) { @@ -653,7 +597,7 @@ function UI() { xhr.open('POST', 'https://ninkip2pimgstore.s3-us-west-1.amazonaws.com/', true); //MUST BE LAST LINE BEFORE YOU SEND xhr.send(fd); - } + } }); } @@ -678,7 +622,7 @@ function UI() { var imageSrc = 'https://ninkip2p.imgix.net/' + _.escape(key) + "?fit=crop&crop=faces&h=128&w=128&mask=ellipse&border=1,d0d0d0"; - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -1038,7 +982,7 @@ function UI() { var data = encdata.toString() + '|' + encdata.iv.toString() + '|' + Engine.m_oguid + '|' + currentDevice.DeviceName + '|' + jresult.RegToken; - var options = { text: data, width: 256, height: 256 }; + var options = { text: data, width: 256, height: 256, ecLevel: 'H' }; $('#qrdevice').text(data); $('#qrdevice').qrcode(options); @@ -1107,11 +1051,71 @@ function UI() { $("#pairdevicemodal").modal('hide'); $("#pairdeviceqr").hide(); + + }); + + $("#btnUnpairBackupCancel").click(function () { + $("#pairdevicemodal").modal('hide'); + $("#pairdeviceqr").hide(); + $("#unpairbackupcode").val(); + $("#pairerror").hide(); + $("#pairqr2fa").show(); + $("#pairusebackup").hide(); + }); + + + $("#btnUnpairBackupDone").click(function () { + + + $("#pairerror").hide(); + + var backupCode = $("#unpairbackupcode").val(); + + + if (backupCode.length == 8) { + + Engine.destroyDevice2fa(currentDevice.DeviceName, backupCode, function (err, result) { + + if (!err) { + + $('#upb' + Engine.m_settings.BackupIndex).removeAttr("style"); + + Engine.m_settings.BackupIndex = Engine.m_settings.BackupIndex + 1; + + lastNoOfDevices = 0; + updateDeviceList(); + + $("#pairdevicemodal").modal('hide'); + $("#pairdeviceqr").hide(); + + $("#pairerror").hide(); + $("#pairqr2fa").show(); + $("#pairusebackup").hide(); + + + } else { + + $('#pairerror').show(); + $('#pairerrormess').text(result); + + $('#upb' + Engine.m_settings.BackupIndex).removeAttr("style"); + + Engine.m_settings.BackupIndex = Engine.m_settings.BackupIndex + 1; + + $('#upb' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + } + + }); + + } + }); + $("#btnLogin").click(function () { if (!ensureOpenWalletGuidAndPasswordValid()) return; @@ -1131,14 +1135,14 @@ function UI() { Engine.setPass(password, guid); - getCookie("ninki_rem", function (res) { + Engine.Device.getStorageItem("ninki_rem", function (res) { if (res.length > 0) { var enc = JSON.parse(res); twoFactorCode = Engine.decryptNp(enc.ct, Engine.m_password, enc.iv); } - setCookie('guid', guid); + Engine.Device.setStorageItem('guid', guid); @@ -1154,35 +1158,42 @@ function UI() { $("#openwalletalert").hide(); + if (!Engine.m_settings.HasBackupCodes) { + $("#btnPairUseBackups").hide(); + $("#btnBackupCode2fa").hide(); + $("#lost2fa").hide(); + } else { + $("#lost2fa").show(); + $("#btnPairUseBackups").show(); + $("#btnBackupCode2fa").show(); + } + if (result.TwoFactorOnLogin) { //delete any old 2 factor tokens - deleteCookie("ninki_rem"); + Engine.Device.deleteStorageItem("ninki_rem"); if (!result.Beta12fa) { $('#openWalletStart input#password').val(''); - if (result.TwoFactorOnLogin) { - - $("#siguid").hide(); - $("#silguid").hide(); - $("#sipwd").hide(); - $("#si2fa").show(); - $("#sib1").hide(); - $("#sib2").show(); - $("#signdiff").hide(); - $("#crwallet").hide(); + $("#siguid").hide(); + $("#silguid").hide(); + $("#sipwd").hide(); + $("#si2fa").show(); + $("#sib1").hide(); + $("#sib2").show(); + $("#signdiff").hide(); + $("#crwallet").hide(); + $('#openWalletStart input#twoFactorCode').focus(); - $('#openWalletStart input#twoFactorCode').focus(); + $("#btnLogin").prop('disabled', false); + $("#btnLogin").removeClass('disabled'); + $("#imgopenwaiting").hide(); - $("#btnLogin").prop('disabled', false); - $("#btnLogin").removeClass('disabled'); - $("#imgopenwaiting").hide(); - } } else { @@ -1204,13 +1215,13 @@ function UI() { //initiate 2fa setup modal - if (!m_this.m_twoFactorOnLogin) { + if (!Engine.m_twoFactorOnLogin) { $("#twofactorsettings").show(); $("#2famodal").modal('show'); $("#twofactorsettings").show(); - $("#btnSetupTwoFactor").hide(); + //$("#btnSetupTwoFactor").hide(); $("#savetwofactorerror").hide(); $("#setup2faemail").hide(); $("#setup2faqr").show(); @@ -1218,7 +1229,9 @@ function UI() { $("#btnLogin").removeClass('disabled'); $("#imgopenwaiting").hide(); - showSettingsTwoFactorQr(); + + + showMissingTwoFactorQr(); } else { @@ -1227,8 +1240,8 @@ function UI() { initialiseUI(function (err, result) { - setCookie("user", Engine.m_nickname); - setCookie("userimg", Engine.m_profileImage); + Engine.Device.setStorageItem("user", Engine.m_nickname); + Engine.Device.setStorageItem("userimg", Engine.m_profileImage); $("#btnLogin").prop('disabled', false); $("#btnLogin").removeClass('disabled'); @@ -1364,19 +1377,20 @@ function UI() { $("#openwalletalertmessage").text(result); $("#btn2faLogin").prop('disabled', false); $("#btn2faLogin").removeClass('disabled'); + } else { if (result.CookieToken) { - setCookie("ninki_rem", result.CookieToken); + Engine.Device.setStorageItem("ninki_rem", result.CookieToken); } if (Engine.m_walletinfo.hotHash == '') { initialiseUI(function (err, result) { - setCookie("user", Engine.m_nickname); - setCookie("userimg", Engine.m_profileImage); + Engine.Device.setStorageItem("user", Engine.m_nickname); + Engine.Device.setStorageItem("userimg", Engine.m_profileImage); }); @@ -1411,6 +1425,52 @@ function UI() { }); + $("#btnLoginBackupDone").click(function () { + + + + var twoFactorCode = $('#txtLoginBackupCode').val(); + + if (twoFactorCode.length == 8) { + + Engine.openWallet2fa(twoFactorCode, false, function (err, result) { + + if (err) { + + $('#log' + Engine.m_settings.BackupIndex).removeAttr("style"); + + Engine.m_settings.BackupIndex = Engine.m_settings.BackupIndex + 1; + + $('#log' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + } else { + + initialiseUI(function (err, result) { + + $("#loginbackup").hide(); + + Engine.Device.setStorageItem("user", Engine.m_nickname); + Engine.Device.setStorageItem("userimg", Engine.m_profileImage); + + $('#log' + Engine.m_settings.BackupIndex).removeAttr("style"); + + //increment not required as login will update settings + + }); + + } + + }); + + } else { + + } + + + + }); + + $("#btnEmailGuid").click(function () { @@ -1506,13 +1566,73 @@ function UI() { if (allok) { - $('#sendstds2amt').text($('#hdamount').val() + ' ' + COINUNIT); - $('#sendstds2add').text($('#toAddress').val()); + Engine.Device.getStorageItem("tfso" + Engine.m_guid, function (res) { + + if (res == "") { + //get the current limit status from the server + //and determine if we need 2fa or not + + $('#sendstds2amt').text($('#hdamount').val() + ' ' + COINUNIT); + $('#sendstds2add').text($('#toAddress').val()); + + //$("#sendstds1").hide(); + $("#sendstds3").hide(); + $("#sendstds2").show(); + $("#sendstdmodal").modal('show'); + + } else { + + Engine.getLimitStatus(function (err, limits) { + + var twofareq = false; + if ((limits.No24hr + 1) > limits.NoOfTransactionsPerDay) { + twofareq = true; + } + if ((limits.No1hr + 1) > limits.NoOfTransactionsPerHour) { + twofareq = true; + } + + var amount = convertToSatoshis($('#hdamount').val(), COINUNIT); + + if ((amount) > limits.SingleTransactionLimit) { + twofareq = true; + } + if ((limits.TotalAmount24hr + amount) > limits.DailyTransactionLimit) { + twofareq = true; + } + + if (twofareq) { + + + $('#twofactreq').show(); + $('#sendstds2amt').text($('#hdamount').val() + ' ' + COINUNIT); + $('#sendstds2add').text($('#toAddress').val()); + + //$("#sendstds1").hide(); + $("#sendstds3").hide(); + $("#sendstds2").show(); + $("#sendstdmodal").modal('show'); + + } else { + + + $('#twofactreq').hide(); + $('#sendstds2amt').text($('#hdamount').val() + ' ' + COINUNIT); + $('#sendstds2add').text($('#toAddress').val()); - //$("#sendstds1").hide(); - $("#sendstds3").hide(); - $("#sendstds2").show(); - $("#sendstdmodal").modal('show'); + //$("#sendstds1").hide(); + $("#sendstds3").hide(); + $("#sendstds2").show(); + $("#sendstdmodal").modal('show'); + + } + + + }); + + } + + }); } }); @@ -1561,13 +1681,79 @@ function UI() { allok = false; } if (allok) { - $('#sendnets2amt').text($('#hdfriendAmount').val() + ' ' + COINUNIT); - $('#sendnets2add').text(SELECTEDFRIEND); - //$("#networksend").hide(); - $("#sendnets3").hide(); - $("#sendnetmodal").modal('show'); - $("#sendnets2").show(); + Engine.Device.getStorageItem("tfso" + Engine.m_guid, function (res) { + + if (res == "") { + + + $('#sendnets2amt').text($('#hdfriendAmount').val() + ' ' + COINUNIT); + $('#sendnets2add').text(SELECTEDFRIEND); + + //$("#networksend").hide(); + $("#sendnets3").hide(); + $("#sendnetmodal").modal('show'); + $("#sendnets2").show(); + + $("#twofactreqnet").show(); + + } else { + + Engine.getLimitStatus(function (err, limits) { + + var twofareq = false; + if ((limits.No24hr + 1) > limits.NoOfTransactionsPerDay) { + twofareq = true; + } + if ((limits.No1hr + 1) > limits.NoOfTransactionsPerHour) { + twofareq = true; + } + + var amount = convertToSatoshis($('#hdfriendAmount').val(), COINUNIT); + + if ((amount) > limits.SingleTransactionLimit) { + twofareq = true; + } + if ((limits.TotalAmount24hr + amount) > limits.DailyTransactionLimit) { + twofareq = true; + } + + if (twofareq) { + + + $('#sendnets2amt').text($('#hdfriendAmount').val() + ' ' + COINUNIT); + $('#sendnets2add').text(SELECTEDFRIEND); + + //$("#networksend").hide(); + $("#sendnets3").hide(); + $("#sendnetmodal").modal('show'); + $("#sendnets2").show(); + + $("#twofactreqnet").show(); + + } else { + + + $('#sendnets2amt').text($('#hdfriendAmount').val() + ' ' + COINUNIT); + $('#sendnets2add').text(SELECTEDFRIEND); + + //$("#networksend").hide(); + $("#sendnets3").hide(); + $("#sendnetmodal").modal('show'); + $("#sendnets2").show(); + + $("#twofactreqnet").hide(); + + + } + + }); + + } + + }); + + } }); @@ -1730,7 +1916,7 @@ function UI() { $("#imgphrasewaiting").show(); - setCookie('guid', Engine.m_oguid); + Engine.Device.setStorageItem('guid', Engine.m_oguid); Engine.openWalletAfterCreate(twoFactorCodeChk, function (err, result) { @@ -1756,8 +1942,8 @@ function UI() { $(".next").hide(); $(".previous").hide(); - setCookie("user", Engine.m_nickname); - setCookie("userimg", Engine.m_profileImage); + Engine.Device.setStorageItem("user", Engine.m_nickname); + Engine.Device.setStorageItem("userimg", Engine.m_profileImage); } @@ -2267,7 +2453,7 @@ function UI() { }); - getCookie('guid', function (res) { + Engine.Device.getStorageItem('guid', function (res) { $("#openWalletStart #guid").val(res); @@ -2276,14 +2462,14 @@ function UI() { $("#guidsec").hide(); - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { - getCookie('user', function (uname) { + Engine.Device.getStorageItem('user', function (uname) { //console.write(res); $("#loginuser").text(uname); - getCookie('userimg', function (res) { + Engine.Device.getStorageItem('userimg', function (res) { var imageSrcSmall = "images/avatar/64px/Avatar-" + pad(uname.length) + ".png"; @@ -2335,8 +2521,8 @@ function UI() { // $("#coldWalletPhrase").printElement(); chrome.app.window.create('printwindow.html', { 'bounds': { - 'width': Math.round(window.screen.availWidth * 0.8), - 'height': Math.round(window.screen.availHeight * 0.8) + 'width': Math.round(window.screen.availWidth * 0.25), + 'height': Math.round(window.screen.availHeight * 0.25) } }, function (createdWindow) { @@ -2351,8 +2537,28 @@ function UI() { }); - $("#btnCreateInit").click(function () { - $("#introduction").hide(); + $("#btnPrintCodes").click(function () { + // $("#coldWalletPhrase").printElement(); + + chrome.app.window.create('printwindow.html', { 'bounds': { + 'width': Math.round(window.screen.availWidth * 0.2), + 'height': Math.round(window.screen.availHeight * 0.5) + } + }, + function (createdWindow) { + var win = createdWindow.contentWindow; + win.onload = function () { + win.document.querySelector('#content').innerHTML = $("#codeprintarea").html(); + win.print(); + } + } + ); + + }); + + + $("#btnCreateInit").click(function () { + $("#introduction").hide(); showCreateWalletStart(); }); @@ -2431,14 +2637,24 @@ function UI() { $("#hlost2fa").click(function () { - $("#createWalletStart").hide(); + $("#logusebackup").show(); $("#openWalletStart").hide(); - $("#lostguid").hide(); - $("#reset2fa").show(); + $("#loginbackup").show(); + + $('#log' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + }); + + $("#btnLoginBackupCancel").click(function () { + + $("#logusebackup").hide(); + $("#openWalletStart").show(); + $("#loginbackup").hide(); }); + $("#emailresend").click(function () { Engine.sendWelcomeDetails(function (err, result) { @@ -2500,7 +2716,7 @@ function UI() { setTimeout(function () { - Engine.ChangePassword(twoFactorCode, oldpassword, newpassword, "#chngpwdprogbar", "#chngpwdprogmess", false, '', '', function (err, results) { + Engine.ChangePassword(twoFactorCode, oldpassword, newpassword, function (err, results) { if (err) { $("#chngpwerr").show(); @@ -2512,24 +2728,6 @@ function UI() { password = results; - - // Engine.getEncHotHash(function (err, data) { - - // var bb = new Blob([data], { type: 'text/plain' }); - - // var a = document.getElementById('btnSaveBackupP'); - - // var d = new Date(); - // var fdate = "" + (d.getDate()) + (d.getMonth() + 1) + (d.getFullYear()); - - // a.download = "ninki_backup_" + _.escape(Engine.m_nickname) + "_" + fdate + ".json"; - // a.href = window.URL.createObjectURL(bb); - - // a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':'); - - // }); - - $("#pwdchangemain").hide(); $("#chngpwerr").hide(); @@ -2546,6 +2744,11 @@ function UI() { } + }, function (message, progress) { + + $("#chngpwdprogmess").text(message); + $("#chngpwdprogbar").width(progress); + }); @@ -2553,6 +2756,7 @@ function UI() { } } else { + $("#chngpwerr").show(); $("#chngpwerrmess").text("Passwords are the same. Password not updated"); $("#chngpwdprogmess").hide(); @@ -2664,18 +2868,41 @@ function UI() { }); + + $("#btnBackupCode2fa").click(function () { + + $('#fab' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + $("#tfausebackup").show(); + $("#tfamove").hide(); + + }); + + $("#btn2faBackupCancel").click(function () { + + $("#tfausebackup").hide(); + $("#tfamove").show(); + + }); + + + $("#btnSetupTwoFactor").click(function () { - $("#twofactorsettings").show(); - $("#btnSetupTwoFactor").hide(); - $("#savetwofactorerror").hide(); - $("#setup2faemail").hide(); - $("#setup2faqr").show(); + showSettingsTwoFactorQr(); }); + $("#btn2faBackupDone").click(function () { + + + showSettingsBackupTwoFactorQr(); + + }); + + $("#btnSaveTwoFactor").click(function () { //validate authenticator code @@ -2691,7 +2918,13 @@ function UI() { if (!err) { //ok - logout(); + //logout(); + + $("#twofactorsettings").hide(); + $("#2famodal").modal('hide'); + + $("#twoFactorCodeFor2fa").val(''); + $("#txtsettings2fa").val(''); } else { @@ -2804,15 +3037,82 @@ function UI() { $("#btnpayinvoice").click(function () { - $('input#txtInvoice2FA').css("border-color", "#ccc"); - $('input#txtInvoice2FA').val(''); - $("#sendinvprog").hide(); - $("#textMessageSendInv").hide(); + Engine.Device.getStorageItem("tfso" + Engine.m_guid, function (res) { + + if (res == "") { + + $('input#txtInvoice2FA').css("border-color", "#ccc"); + $('input#txtInvoice2FA').val(''); + + $("#sendinvprog").hide(); + $("#textMessageSendInv").hide(); + + $("#sendinvs2").hide(); + $("#sendinvs2").show(); + $("#invmodal").modal('show'); + + $("#twofactreqinv").show(); + + } else { + + + Engine.getLimitStatus(function (err, limits) { + + var twofareq = false; + if ((limits.No24hr + 1) > limits.NoOfTransactionsPerDay) { + twofareq = true; + } + if ((limits.No1hr + 1) > limits.NoOfTransactionsPerHour) { + twofareq = true; + } + + var amount = selectedInvoiceAmount; + + if ((amount) > limits.SingleTransactionLimit) { + twofareq = true; + } + if ((limits.TotalAmount24hr + amount) > limits.DailyTransactionLimit) { + twofareq = true; + } + + if (twofareq) { + + $('input#txtInvoice2FA').css("border-color", "#ccc"); + $('input#txtInvoice2FA').val(''); + + $("#sendinvprog").hide(); + $("#textMessageSendInv").hide(); + + $("#sendinvs2").hide(); + $("#sendinvs2").show(); + $("#invmodal").modal('show'); + + $("#twofactreqinv").show(); + + + } else { + + $('input#txtInvoice2FA').css("border-color", "#ccc"); + $('input#txtInvoice2FA').val(''); + + $("#sendinvprog").hide(); + $("#textMessageSendInv").hide(); + + $("#sendinvs2").hide(); + $("#sendinvs2").show(); + $("#invmodal").modal('show'); - $("#sendinvs2").hide(); - $("#sendinvs2").show(); - $("#invmodal").modal('show'); + $("#twofactreqinv").hide(); + + } + + }); + + + } + + }); }); @@ -2822,35 +3122,48 @@ function UI() { var allok = true; var twoFactorCode = $('#txtInvoice2FA').val(); - if (twoFactorCode.length == 6) { - $('input#txtInvoice2FA').css("border-color", "#ccc"); - } else { - $('input#txtInvoice2FA').css("border-color", "#ffaaaa"); - allok = false; - } + Engine.get2faOverride(amount, function (err, result) { - if (allok) { + if (result == "") { + if (twoFactorCode.length == 6) { + $('input#txtSendTwoFactor').css("border-color", "#ccc"); + } else { + $('input#txtSendTwoFactor').css("border-color", "#ffaaaa"); + allok = false; + } + } else { + twoFactorCode = result; - $('#textMessageSendInv').removeClass('alert alert-danger'); - $('#textMessageSendInv').text('Creating transaction...'); - $('#textMessageSendInv').show(); - $('#sendinvprogstatus').width('3%') - $('#sendinvprog').show(); - $('#sendinvprogstatus').width('10%'); + } - payInvoice(selectedInvoiceUserName, selectedInvoiceAmount, selectedInvoiceId, twoFactorCode, function (err, result) { + if (allok) { - if (!err) { + $('#textMessageSendInv').removeClass('alert alert-danger'); + $('#textMessageSendInv').text('Creating transaction...'); + $('#textMessageSendInv').show(); + $('#sendinvprogstatus').width('3%'); + $('#sendinvprog').show(); + $('#sendinvprogstatus').width('10%'); - $("#sendinvs2").hide(); - $("#sendinvs3").show(); - } + payInvoice(selectedInvoiceUserName, selectedInvoiceAmount, selectedInvoiceId, twoFactorCode, function (err, result) { + if (!err) { + + $("#sendinvs2").hide(); + $("#sendinvs3").show(); + } + + + }); + + } + + + + }); - }); - } }); @@ -2997,7 +3310,7 @@ function UI() { $("#invoicedisplay").hide(); uiInvoiceReturnToNetwork = true; invoiceSelectedUser = SELECTEDFRIEND; - lineCount = 0 + lineCount = 0; $("#createinvoiceforlabel").text('Create an Invoice for ' + SELECTEDFRIEND); $("#tblinvoice tbody").empty(); @@ -3132,8 +3445,7 @@ function UI() { $("#tax").text((subTotal * tax).toFixed(4)); $("#total").text((subTotal + (subTotal * tax)).toFixed(4)); - }; - + } function validateInvoice() { var subTotal = 0; @@ -3228,10 +3540,7 @@ function UI() { return isValid; - }; - - - + } var lineCount = 0; function getRowTempate() { var template = '' + @@ -3394,7 +3703,7 @@ function UI() { } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrcSmall, true); xhrsm.responseType = 'blob'; @@ -3688,7 +3997,7 @@ function UI() { - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrcSmall, true); xhrsm.responseType = 'blob'; @@ -3795,7 +4104,7 @@ function UI() { $("#tblinvdisplay tfoot th #dtax").text(convertFromSatoshis(json.summary.tax, COINUNIT)); $("#tblinvdisplay tfoot th #dtotal").text(convertFromSatoshis(json.summary.total, COINUNIT)); - selectedInvoiceAmount = convertFromSatoshis(json.summary.total); + selectedInvoiceAmount = json.summary.total; selectedInvoiceId = invoice.InvoiceId; selectedInvoiceUserName = invoice.InvoiceFrom; @@ -3918,8 +4227,6 @@ function UI() { function payInvoice(friend, amount, invoiceNumber, twoFactorCode, callback) { - - Engine.sendTransaction('invoice', friend, '', amount, twoFactorCode, function (err, transactionid) { if (!err) { @@ -3964,8 +4271,10 @@ function UI() { } else { + + $('#textMessageSendInv').addClass('alert alert-danger'); - $('#sendinvprogstatus').width('0%') + $('#sendinvprogstatus').width('0%'); if (transactionid == "ErrInsufficientFunds") { $('#textMessageSendInv').text('Transaction Failed: Not enough funds are currently available to send this transaction'); @@ -3979,6 +4288,16 @@ function UI() { + }, function (message, progress) { + + if (message) { + $('#textMessageSendInv').text(message); + } + + if (progress) { + $('#sendinvprogstatus').width(progress); + } + }); @@ -4042,7 +4361,7 @@ function UI() { imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(Engine.m_profileImage) + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhr = new XMLHttpRequest(); xhr.open('GET', imageSrc, true); @@ -4107,7 +4426,7 @@ function UI() { if (!err) { - document.onAway = function () { logout(); } + document.onAway = function () { logout(); }; setInterval(function () { updateUI(); @@ -4117,7 +4436,7 @@ function UI() { refreshSelectedFriend(); }, 30000); - + $('#showPhrases').hide(); @@ -4202,7 +4521,7 @@ function UI() { UI.updateUITimer = function () { updateUI(); - } + }; @@ -4320,22 +4639,125 @@ function UI() { function showSettingsTwoFactorQr() { - $("#setup2faqr").show(); - $("#setting2fa").show(); - $("#settings2fa").show(); - $("#btnSetupTwoFactor").hide(); + $("#twoFactorCodeFor2faError").hide(); + + var twoFactorCode = $("#twoFactorCodeFor2fa").val(); + + if (twoFactorCode.length == 6) { + + Engine.getNewTwoFactorImg(twoFactorCode, function (err, twoFASecret) { + + if (!err) { + + var data = "otpauth://totp/Ninki:" + Engine.m_nickname + "?secret=" + twoFASecret + "&issuer=Ninki"; + var options = { text: data, width: 172, height: 172 }; + + $('#imgsettings2fa').text(''); + $('#imgsettings2fa').qrcode(options); + + $("#setup2faqr").show(); + $("#twofactorsettings").show(); + $("#2famodal").modal('show'); + + $("#savetwofactorerror").hide(); + $("#setup2faemail").hide(); + + } else { + + $("#twoFactorCodeFor2faError").show(); + + } + }); + + } else { + + $("#twoFactorCodeFor2faError").show(); + + } + + + } + + function showSettingsBackupTwoFactorQr() { + + //$("#twoFactorCodeFor2faError").hide(); + + var twoFactorCode = $("#txtTFABackupCode").val(); + + if (twoFactorCode.length == 8) { + Engine.getNewTwoFactorImg(twoFactorCode, function (err, twoFASecret) { + + if (!err) { + + var data = "otpauth://totp/Ninki:" + Engine.m_nickname + "?secret=" + twoFASecret + "&issuer=Ninki"; + var options = { text: data, width: 172, height: 172 }; + + $('#imgsettings2fa').text(''); + $('#imgsettings2fa').qrcode(options); + + $("#setup2faqr").show(); + $("#twofactorsettings").show(); + $("#2famodal").modal('show'); + + //$("#savetwofactorerror").hide(); + $("#setup2faemail").hide(); + + $("#tfausebackup").hide(); + $("#tfamove").show(); + + $('#fab' + Engine.m_settings.BackupIndex).removeAttr("style"); + + Engine.m_settings.BackupIndex = Engine.m_settings.BackupIndex + 1; + + } else { + + $('#fab' + Engine.m_settings.BackupIndex).removeAttr("style"); + + Engine.m_settings.BackupIndex = Engine.m_settings.BackupIndex + 1; + + $('#fab' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + //$("#twoFactorCodeFor2faError").show(); + + } + }); + + } else { + + // $("#twoFactorCodeFor2faError").show(); + + } + } + function showMissingTwoFactorQr() { + Engine.getTwoFactorImg(function (err, twoFASecret) { - var data = "otpauth://totp/Ninki:" + Engine.m_nickname + "?secret=" + twoFASecret + "&issuer=Ninki"; - var options = { text: data, width: 172, height: 172 }; + if (!err) { + + var data = "otpauth://totp/Ninki:" + Engine.m_nickname + "?secret=" + twoFASecret + "&issuer=Ninki"; + var options = { text: data, width: 172, height: 172 }; + + $('#imgsettings2fa').text(''); + $('#imgsettings2fa').qrcode(options); + + $("#setup2faqr").show(); + $("#twofactorsettings").show(); + $("#2famodal").modal('show'); + + $("#savetwofactorerror").hide(); + $("#setup2faemail").hide(); + + } else { + + $("#twoFactorCodeFor2faError").show(); + + } - $('#imgsettings2fa').text(''); - $('#imgsettings2fa').qrcode(options); - }); + }); } @@ -4353,7 +4775,7 @@ function UI() { $("#SingleTransactionLimit").prop('disabled', false); $("#NoOfTransactionsPerDay").prop('disabled', false); $("#NoOfTransactionsPerHour").prop('disabled', false); - $("#btnSetupTwoFactor").hide(); + //$("#btnSetupTwoFactor").hide(); } else { $("#settings2faok").hide(); @@ -4421,12 +4843,52 @@ function UI() { $('#lcCNY').prop('checked', true); } + Engine.Device.getStorageItem("tfso" + Engine.m_guid, function (res) { + + if (res == "") { + + $('#chkTwoFactorLimits').prop('checked', false); + + } else { + + $('#chkTwoFactorLimits').prop('checked', true); + } + + }); + + + $('#pnlBackupCodes').hide(); + if (!settingsObject.HasBackupCodes) { + $('#pnlBackupBtn').show(); + $('#pnlBackupIsSetup').hide(); + $('#libackupcodes').show(); + } else { + + if (settingsObject.BackupIndex > 7) { + $('#pnlBackupBtn').show(); + $('#pnlBackupIsSetup').hide(); + $('#libackupcodes').show(); + } else { + + $('#pnlBackupBtn').show(); + $('#pnlBackupIsSetup').show(); + $('#libackupcodes').hide(); + } + } + + + } }); } function saveAccountSettingsToServer() { + + + $("#savesettingssuccess").hide(); + $("#savesettingserror").hide(); + var jsonPacket = { guid: Engine.m_guid }; @@ -4461,68 +4923,88 @@ function UI() { $("#amount").val(''); } + var twoFactorSend = false; - Engine.updateAccountSettings(jsonPacket, $("#txtTwoFactorCodeForSettings").val(), function (err, response) { - if (err) { - $("#savesettingserror").show(); - $("#savesettingssuccess").hide(); - $("#savesettingserrormessage").text(response); - } else { + Engine.Device.getStorageItem("tfso" + Engine.m_guid, function (res) { - var stdcoinunitsel = false; - if ($("#stdselunit").text() == COINUNIT) { - stdcoinunitsel = true; - } + if (res == "" && $('#chkTwoFactorLimits')[0].checked) { - var netcoinunitsel = false; - if ($("#netselunit").text() == COINUNIT) { - netcoinunitsel = true; - } + twoFactorSend = true; - if (jsonPacket['CoinUnit'] != COINUNIT) { - COINUNIT = jsonPacket['CoinUnit']; - lastNoOfTrans = -1; - readAccountSettings(); - $("#stdsendcunit").text(COINUNIT); - $("#amount").val(''); - $("#friendAmount").val(''); - } + } - $("#stdsendlcurr").text(Engine.m_settings.LocalCurrency); + if (res.length > 0 && !$('#chkTwoFactorLimits')[0].checked) { + + Engine.Device.deleteStorageItem("tfso" + Engine.m_guid); + + } - if (stdcoinunitsel) { + Engine.updateAccountSettings(jsonPacket, $("#txtTwoFactorCodeForSettings").val(), twoFactorSend, function (err, response) { - $("#stdselunit").text(COINUNIT); + if (err) { + $("#savesettingserror").show(); + $("#savesettingssuccess").hide(); + $("#savesettingserrormessage").text(response); } else { - $("#stdselunit").text(Engine.m_settings.LocalCurrency); - } + var stdcoinunitsel = false; + if ($("#stdselunit").text() == COINUNIT) { + stdcoinunitsel = true; + } - if (netcoinunitsel) { + var netcoinunitsel = false; + if ($("#netselunit").text() == COINUNIT) { + netcoinunitsel = true; + } - $("#netselunit").text(COINUNIT); + if (jsonPacket['CoinUnit'] != COINUNIT) { + COINUNIT = jsonPacket['CoinUnit']; + lastNoOfTrans = -1; + readAccountSettings(); + $("#stdsendcunit").text(COINUNIT); + $("#amount").val(''); + $("#friendAmount").val(''); + } - } else { + $("#stdsendlcurr").text(Engine.m_settings.LocalCurrency); - $("#netselunit").text(Engine.m_settings.LocalCurrency); + if (stdcoinunitsel) { - } + $("#stdselunit").text(COINUNIT); - $("#amount").keyup(); - $("#friendAmount").keyup(); + } else { + $("#stdselunit").text(Engine.m_settings.LocalCurrency); - updateUI(); + } - $("#savesettingssuccess").show(); - $("#savesettingserror").hide(); - $("#savesettingssuccessmessage").text("Settings saved successfully"); + if (netcoinunitsel) { + + $("#netselunit").text(COINUNIT); + + } else { + + $("#netselunit").text(Engine.m_settings.LocalCurrency); + + } + + $("#amount").keyup(); + $("#friendAmount").keyup(); + + + updateUI(); + + $("#savesettingssuccess").show(); + $("#savesettingserror").hide(); + $("#savesettingssuccessmessage").text("Settings saved successfully"); + + //alert(response.body); + } + }); - //alert(response.body); - } }); } else { @@ -4575,7 +5057,7 @@ function UI() { amount = amount * 100; } - amount = Math.round(amount) + amount = Math.round(amount); return amount; } @@ -4756,14 +5238,17 @@ function UI() { $('#qrdevice').text(''); - + $('#pairerror').hide(); if (!event.data.device.IsPaired) { + $('#pairqrscan').hide(); $("#pairdevicemodal").modal('show'); $("#pairdeviceqr").show(); $('#pairqr2fa').show(); $("#pairheading").text("Pair " + event.data.device.DeviceName); + $("#btnShowPairQr").text("Pair"); + $('#btnPairUseBackups').hide(); } else { @@ -4773,6 +5258,12 @@ function UI() { $("#pairheading").text("Unpair " + event.data.device.DeviceName); $("#btnShowPairQr").text("Unpair"); $('#qrdevice').text(''); + $('#btnPairUseBackups').show(); + + + $('#upb' + Engine.m_settings.BackupIndex).attr("style", "border-color:red"); + + //$('#qrdevice').qrcode(''); } @@ -4836,12 +5327,11 @@ function UI() { } }); + } - } - var lastNoOfFriends = 0; var invoiceSelectedUser = ''; @@ -4855,156 +5345,165 @@ function UI() { Engine.getUserNetwork(function (err, friends) { - $("#nfriends").text(friends.length); - if (friends.length > lastNoOfFriends) { + if (!err) { - lastNoOfFriends = friends.length; - FRIENDSLIST = {}; + $("#nfriends").text(friends.length); - for (var i = 0; i < friends.length; i++) { - FRIENDSLIST[friends[i].userName] = friends[i]; - } + if (friends.length > lastNoOfFriends) { - //if selected friend is not isend and isreceive - //then find in list and update + lastNoOfFriends = friends.length; - if (selectedFriend != null) { + FRIENDSLIST = {}; - if (!selectedFriend.ICanSend || !selectedFriend.ICanReceive) { - selectedFriend = FRIENDSLIST[selectedFriend.userName]; - updateSelectedFriend(); + for (var i = 0; i < friends.length; i++) { + FRIENDSLIST[friends[i].userName] = friends[i]; } - } + //if selected friend is not isend and isreceive + //then find in list and update + if (selectedFriend != null) { - $("#nfriends").text(friends.length); - $("#myfriends").text(''); + if (!selectedFriend.ICanSend || !selectedFriend.ICanReceive) { + selectedFriend = FRIENDSLIST[selectedFriend.userName]; + updateSelectedFriend(); + } + } - var grouptemplate = ''; - var friendsgroup = _.groupBy(friends, function (item) { return item.category; }) + $("#nfriends").text(friends.length); + $("#myfriends").text(''); - grouptemplate += '
    '; - var k = 0; - var g = 1; - for (var key in friendsgroup) { + var grouptemplate = ''; - friends = friendsgroup[key]; + var friendsgroup = _.groupBy(friends, function (item) { return item.category; }); - grouptemplate += '
    '; - grouptemplate += '
    '; - grouptemplate += ''; - grouptemplate += key; - grouptemplate += ''; - grouptemplate += '
    '; - grouptemplate += '
    '; - grouptemplate += '
    '; + grouptemplate += '
    '; + + var k = 0; + var g = 1; + for (var key in friendsgroup) { + + friends = friendsgroup[key]; + + grouptemplate += '
    '; + grouptemplate += '
    '; + grouptemplate += ''; + grouptemplate += key; + grouptemplate += ''; + grouptemplate += '
    '; + grouptemplate += '
    '; + grouptemplate += '
    '; - for (var i = 0; i < friendsgroup[key].length; i++) { + for (var i = 0; i < friendsgroup[key].length; i++) { - var frnd = FRIENDSLIST[friends[i].userName]; + var frnd = FRIENDSLIST[friends[i].userName]; - var template = ''; + grouptemplate += '
    '; + g++; } grouptemplate += '
    '; - grouptemplate += '
    '; - grouptemplate += '
    '; - g++; - } - - grouptemplate += '
    '; - - $("#myfriends").html(grouptemplate); + $("#myfriends").html(grouptemplate); - var k = 0; - var g = 1; - for (var key in friendsgroup) { - friends = friendsgroup[key]; - for (var i = 0; i < friendsgroup[key].length; i++) { + var k = 0; + var g = 1; + for (var key in friendsgroup) { friends = friendsgroup[key]; + for (var i = 0; i < friendsgroup[key].length; i++) { + friends = friendsgroup[key]; - var length = friends[i].userName.length; - if (length > 20) { - length = 20; - } - var imageSrc = "images/avatar/64px/Avatar-" + pad(length) + ".png"; + var length = friends[i].userName.length; + if (length > 20) { + length = 20; + } - if (friends[i].profileImage != '') { - imageSrc = "https://ninkip2p.imgix.net/" + _.escape(friends[i].profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; - imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(friends[i].profileImage) + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; - } + var imageSrc = "images/avatar/64px/Avatar-" + pad(length) + ".png"; - //$("#myfriends #imgfriend" + k) - - if (isChromeApp()) { - var xhrsm = new XMLHttpRequest(); - xhrsm.open('GET', imageSrc, true); - xhrsm.responseType = 'blob'; - xhrsm.index = k; - xhrsm.onload = function (e) { - $("#myfriends #imgfriend" + this.index).attr("src", window.URL.createObjectURL(this.response)); - }; - xhrsm.send(); - } else { - $("#myfriends #imgfriend" + k).attr("src", imageSrc); - } + if (friends[i].profileImage != '') { + imageSrc = "https://ninkip2p.imgix.net/" + _.escape(friends[i].profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; + imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(friends[i].profileImage) + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; + } + //$("#myfriends #imgfriend" + k) + + if (Engine.Device.isChromeApp()) { + var xhrsm = new XMLHttpRequest(); + xhrsm.open('GET', imageSrc, true); + xhrsm.responseType = 'blob'; + xhrsm.index = k; + xhrsm.onload = function (e) { + $("#myfriends #imgfriend" + this.index).attr("src", window.URL.createObjectURL(this.response)); + }; + xhrsm.send(); + } else { + $("#myfriends #imgfriend" + k).attr("src", imageSrc); + } - $("#myfriends #friend" + k).click({ userName: friends[i].userName }, function (event) { - SELECTEDFRIEND = event.data.userName; - selectedFriend = FRIENDSLIST[event.data.userName]; + $("#myfriends #friend" + k).click({ userName: friends[i].userName }, function (event) { - //depreciate + SELECTEDFRIEND = event.data.userName; + selectedFriend = FRIENDSLIST[event.data.userName]; + //depreciate - updateSelectedFriend(); - $("#friendAmount").keyup(); + updateSelectedFriend(); + $("#friendAmount").keyup(); - }); - console.log("added click " + k + " for " + friends[i].userName); - k++; + }); + console.log("added click " + k + " for " + friends[i].userName); + + k++; + } + g++; } - g++; + } - } + return callback(false, "done"); - return callback(false, "done"); + } else { + + return callback(true, "done"); + } }); } @@ -5044,7 +5543,7 @@ function UI() { imageSrc = "https://ninkip2p.imgix.net/" + _.escape(selectedFriend.profileImage) + "?crop=faces&fit=crop&h=256&w=256&mask=ellipse&border=1,d0d0d0"; } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -5168,7 +5667,7 @@ function UI() { $("#friendSelectedStatus").text(selectedFriend.status); //} - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrc, true); xhrsm.responseType = 'blob'; @@ -5550,7 +6049,7 @@ function UI() { imageSrcSmall = "https://ninkip2p.imgix.net/" + _.escape(FRIENDSLIST[transactions[i].UserName].profileImage) + "?crop=faces&fit=crop&h=64&w=64&mask=ellipse&border=1,d0d0d0"; } } - if (isChromeApp()) { + if (Engine.Device.isChromeApp()) { var xhrsm = new XMLHttpRequest(); xhrsm.open('GET', imageSrcSmall, true); xhrsm.responseType = 'blob'; @@ -5582,6 +6081,7 @@ function UI() { function generateAddressClient() { + Engine.createAddress('m/0/0', 1, function (err, newAddress, path) { var options = { text: newAddress, width: 172, height: 172 }; @@ -5621,54 +6121,77 @@ function UI() { allok = false; } - if (twoFactorCode.length == 6) { - $('input#txtFriendSend2FA').css("border-color", "#ccc"); - } else { - $('input#txtFriendSend2FA').css("border-color", "#ffaaaa"); - allok = false; - } - if (allok) { - $('input#friendAmount').css("border-color", "#ccc"); - $('#textMessageSend').text('Creating transaction...'); - $('#textMessageSend').show(); - $('#sendfriendprogstatus').width('3%') - $('#sendfriendprog').show(); - $('#sendfriendprogstatus').width('10%'); - Engine.sendTransaction('friend', friend, '', amount, twoFactorCode, function (err, transactionid) { + Engine.get2faOverride(amount, function (err, result) { - if (!err) { - updateBalance(); - $('#textCompleteSendNet').text('You sent ' + convertFromSatoshis(amount, COINUNIT) + ' ' + COINUNIT + ' to ' + friend); - $('input#friendAmount').val(''); + if (result == "") { + + if (twoFactorCode.length == 6) { + $('input#txtSendTwoFactor').css("border-color", "#ccc"); + } else { + $('input#txtSendTwoFactor').css("border-color", "#ffaaaa"); + allok = false; + } + } else { + + twoFactorCode = result; + + } + if (allok) { + $('input#friendAmount').css("border-color", "#ccc"); + $('#textMessageSend').text('Creating transaction...'); + $('#textMessageSend').show(); + $('#sendfriendprogstatus').width('3%'); + $('#sendfriendprog').show(); + $('#sendfriendprogstatus').width('10%'); + Engine.sendTransaction('friend', friend, '', amount, twoFactorCode, function (err, transactionid) { - $("#sendnets2").hide(); - $("#sendnets3").show(); + if (!err) { + updateBalance(); + $('#textCompleteSendNet').text('You sent ' + convertFromSatoshis(amount, COINUNIT) + ' ' + COINUNIT + ' to ' + friend); + $('input#friendAmount').val(''); - //$('#textMessageSend').fadeOut(5000); - //$('#sendfriendprog').fadeOut(5000); - } else { - $('#textMessageSend').addClass('alert alert-danger'); - $('#sendfriendprogstatus').width('0%') + $("#sendnets2").hide(); + $("#sendnets3").show(); + + + //$('#textMessageSend').fadeOut(5000); + //$('#sendfriendprog').fadeOut(5000); - if (transactionid == "ErrInsufficientFunds") { - $('#textMessageSend').text('Transaction Failed: Not enough funds are currently available to send this transaction'); - } else if (result == 'ErrLocked') { - $('#textMessageSend').text('Transaction Failed: Account is unavailable'); } else { - $('#textMessageSend').text(transactionid); + $('#textMessageSend').addClass('alert alert-danger'); + $('#sendfriendprogstatus').width('0%'); + + if (transactionid == "ErrInsufficientFunds") { + $('#textMessageSend').text('Transaction Failed: Not enough funds are currently available to send this transaction'); + } else if (result == 'ErrLocked') { + $('#textMessageSend').text('Transaction Failed: Account is unavailable'); + } else { + $('#textMessageSend').text(transactionid); + } + + } + // alert(transactionid); + }, function (message, progress) { + if (message) { + $('#textMessageSend').text(message); + } - } - // alert(transactionid); - }); + if (progress) { + $('#sendfriendprogstatus').width(progress); + } - } + }); + + } + + }); } @@ -5700,52 +6223,72 @@ function UI() { allok = false; } - if (twoFactorCode.length == 6) { - $('input#txtSendTwoFactor').css("border-color", "#ccc"); - } else { - $('input#txtSendTwoFactor').css("border-color", "#ffaaaa"); - allok = false; - } + Engine.get2faOverride(amount, function (err, result) { + if (result == "") { + + if (twoFactorCode.length == 6) { + $('input#txtSendTwoFactor').css("border-color", "#ccc"); + } else { + $('input#txtSendTwoFactor').css("border-color", "#ffaaaa"); + allok = false; + } + } else { + twoFactorCode = result; - if (allok) { + } - $('#textMessageSendStd').text('Creating transaction...'); - $('#textMessageSendStd').show(); - $('#sendstdprogstatus').width('3%') - $('#sendstdprog').show(); - $('#sendstdprogstatus').width('10%'); + if (allok) { + $('#textMessageSendStd').text('Creating transaction...'); + $('#textMessageSendStd').show(); + $('#sendstdprogstatus').width('3%'); + $('#sendstdprog').show(); + $('#sendstdprogstatus').width('10%'); - Engine.sendTransaction('standard', '', address, amount, twoFactorCode, function (err, transactionid) { - if (!err) { + Engine.sendTransaction('standard', '', address, amount, twoFactorCode, function (err, transactionid) { - var confmess = 'You sent ' + _.escape(convertFromSatoshis(amount, COINUNIT)) + ' ' + _.escape(COINUNIT) + ' to ' + _.escape(address) + ''; + if (!err) { - $('#textCompleteSendStd').html(confmess); - $('input#amount').val(''); - $('input#toAddress').val(''); - //$('#textMessageSendStd').fadeOut(5000); - //$('#sendstdprog').fadeOut(5000); + var confmess = 'You sent ' + _.escape(convertFromSatoshis(amount, COINUNIT)) + ' ' + _.escape(COINUNIT) + ' to ' + _.escape(address) + ''; - $('#sendstds2').hide(); - $('#sendstds3').show(); + $('#textCompleteSendStd').html(confmess); + $('input#amount').val(''); + $('input#toAddress').val(''); + //$('#textMessageSendStd').fadeOut(5000); + //$('#sendstdprog').fadeOut(5000); - } else { + $('#sendstds2').hide(); + $('#sendstds3').show(); - if (transactionid == "ErrInsufficientFunds") { - $('#textMessageSendStd').text('Transaction Failed: Not enough funds are currently available to send this transaction'); } else { - $('#textMessageSendStd').text(transactionid) + + if (transactionid == "ErrInsufficientFunds") { + $('#textMessageSendStd').text('Transaction Failed: Not enough funds are currently available to send this transaction'); + } else { + $('#textMessageSendStd').text(transactionid) + } + + $('#sendstdprogstatus').width('0%'); + $('#textMessageSendStd').addClass('alert alert-danger'); } + }, function (message, progress) { + + if (message) { + $('#textMessageSendStd').text(message); + } + + if (progress) { + $('#sendstdprogstatus').width(progress); + } + + }); + } + + }); - $('#sendstdprogstatus').width('0%') - $('#textMessageSendStd').addClass('alert alert-danger'); - } - }); - } } @@ -5909,6 +6452,7 @@ function UI() { } + function ensureOpenWalletGuidAndPasswordValid() { if (Engine.isRealGuid($("#openWalletStart input#guid").val())) { diff --git a/tests/test-accept-contact-request-1.js b/tests/test-accept-contact-request-1.js new file mode 100644 index 0000000..21b37a1 --- /dev/null +++ b/tests/test-accept-contact-request-1.js @@ -0,0 +1,133 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var BIP39 = require('../src/bip39.js'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid2"); +var guid2 = bs.getItem("testguid"); + +var phrase = bs.getItem("fp" + guid2); + + +var username2 = guid2.substring(0, 7); + +var password = "12345678"; +var FASecret = bs.getItem("tfasec2"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('accept contact request', function () { + + this.timeout(5000); + + it("Adds a contact", function (done) { + + console.log(username2); + + engine.acceptFriendRequest(username2, function (err, result) { + + console.log(result); + + var bip39 = new BIP39(); + var code = bip39.mnemonicToHex(phrase); + + engine.verifyFriendData(username2, code, function (err, result) { + + engine.isNetworkExist(username2, function (err, result) { + + console.log(result); + + if (!result) { + + engine.createFriend(username2, '', function (err, result) { + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + + }); + + } + + }); + + + }); + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-accept-contact-request-2.js b/tests/test-accept-contact-request-2.js new file mode 100644 index 0000000..abdc0fb --- /dev/null +++ b/tests/test-accept-contact-request-2.js @@ -0,0 +1,121 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var BIP39 = require('../src/bip39.js'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var guid2 = bs.getItem("testguid2"); + +var phrase = bs.getItem("fp" + guid2); + + +var username2 = guid2.substring(0, 7); + +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('accept contact request', function () { + + this.timeout(5000); + + it("Adds a contact", function (done) { + + console.log(username2); + + + engine.acceptFriendRequest(username2, function (err, result) { + + var bip39 = new BIP39(); + var code = bip39.mnemonicToHex(phrase); + + engine.verifyFriendData(username2, code, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-add-contact.js b/tests/test-add-contact.js new file mode 100644 index 0000000..f73a9d3 --- /dev/null +++ b/tests/test-add-contact.js @@ -0,0 +1,111 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var guid2 = bs.getItem("testguid2"); + + +var username2 = guid2.substring(0, 7); + +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('add contact', function () { + + this.timeout(5000); + + it("Adds a contact", function (done) { + + console.log(username2); + + + engine.createFriend(username2, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-change-password.js b/tests/test-change-password.js new file mode 100644 index 0000000..10ea808 --- /dev/null +++ b/tests/test-change-password.js @@ -0,0 +1,127 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + bs.setItem('fp' + guid, engine.m_fingerprint); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + describe('User Functions', function () { + + describe('Change Password', function () { + + this.timeout(10000); + + it("Changes the user's password", function (done) { + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + + engine.ChangePassword(twoFactorCode, password, "123456789", function (err, result) { + + + expect(err).to.equal(false); + expect(result).to.exist; + //console.log(result); + + engine.ChangePassword(twoFactorCode, password, "12345678", function (err, result) { + + + expect(err).to.equal(false); + expect(result).to.exist; + //console.log(result); + + done(); + + + }, function (message, progress) { + + + console.log(message + '(' + progress + ')'); + + + }); + + + }, function (message, progress) { + + + console.log(message + '(' + progress + ')'); + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-create-account-1.js b/tests/test-create-account-1.js new file mode 100644 index 0000000..66a66fe --- /dev/null +++ b/tests/test-create-account-1.js @@ -0,0 +1,254 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); +var engine = new Engine(); + + +var guid = engine.getguid(); +var password = "12345678"; +var username = guid.substring(0,7); +var emailAddress = guid + '@ninkip2p.com'; +var FASecret = ''; + +bs.setItem('testguid', guid); + +describe('Account Utilities', function () { + + describe('doesUsernameExist', function () { + + it("username=testnet", function (done) { + engine.doesUsernameExist("testnet", function (err, res) { + expect(res).to.equal(true); + done(); + }); + }); + + it("username=xyxyxyxy", function (done) { + engine.doesUsernameExist("xyxyxyxy", function (err, res) { + expect(res).to.equal(false); + done(); + }); + }); + + }); + + describe('doesAccountExist', function () { + it("username=testnet,emailAddress=testnet@ninkip2p.com", function (done) { + API.doesAccountExist("testnet", "testnet@ninkip2p.com", function (err, accExists) { + + expect(accExists.UserExists).to.equal(true); + expect(accExists.EmailExists).to.equal(true); + done(); + + }); + }); + it("username=gobxysgydu,emailAddress=ojihygjgrj@ninkip2p.com", function (done) { + API.doesAccountExist("gobxysgydu", "ojihygjgrj@ninkip2p.com", function (err, accExists) { + + expect(accExists.UserExists).to.equal(false); + expect(accExists.EmailExists).to.equal(false); + done(); + + }); + }); + + it("username=gobxysgydu,emailAddress=testnet@ninkip2p.com", function (done) { + API.doesAccountExist("gobxysgydu", "testnet@ninkip2p.com", function (err, accExists) { + + expect(accExists.UserExists).to.equal(false); + expect(accExists.EmailExists).to.equal(true); + done(); + + }); + }); + + it("username=testnet,emailAddress=ojihygjgrj@ninkip2p.com", function (done) { + API.doesAccountExist("testnet", "ojihygjgrj@ninkip2p.com", function (err, accExists) { + + expect(accExists.UserExists).to.equal(true); + expect(accExists.EmailExists).to.equal(false); + done(); + + }); + }); + + }); + + + describe('Create Account Function', function () { + + + describe('createWallet', function () { + + this.timeout(10000); + + it("Creates a new account", function (done) { + + + engine.createWallet(guid, password, username, emailAddress, function (err, result) { + + + expect(err).to.equal(false); + expect(result.wallet).to.exist; + + + engine.getTwoFactorImg(function (err, twoFASecret) { + + + FASecret = twoFASecret; + + bs.setItem('tfasec', twoFASecret); + + console.log(twoFASecret); + + expect(err).to.equal(false); + expect(twoFASecret).to.exist; + + //generate an opt code from the secret + var twoFactorCode = speakeasy.totp({ key: twoFASecret, encoding: 'base32' }); + + + bs["tfasec"] = twoFASecret; + + console.log(twoFactorCode); + + engine.SetupTwoFactor(twoFactorCode, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var token = "test"; + + engine.getEmailValidation(token, function (err, response) { + + console.log(response); + + expect(err).to.equal(true); + expect(response).to.exist; + + done(); + + }); + + + + }); + + + }); + + + }); + + }); + + }); + + }); + +}); + + +guid = bs.getItem("testguid"); +var password = "12345678"; +FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + bs.setItem('fp' + guid, engine.m_fingerprint); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + + describe('User Functions', function () { + + describe('createAddress', function () { + + this.timeout(5000); + + it("Creates a receive address", function (done) { + + engine.createAddress('m/0/0', 1, function (err, newAddress, path) { + + + console.log("Send 2* 0.01 Testnet coins to :" + newAddress); + + expect(err).to.equal(false); + expect(newAddress).to.exist; + expect(path).to.exist; + + done(); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-create-account-2.js b/tests/test-create-account-2.js new file mode 100644 index 0000000..6398c59 --- /dev/null +++ b/tests/test-create-account-2.js @@ -0,0 +1,189 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); +var engine = new Engine(); + + +var guid = engine.getguid(); +var password = "12345678"; +var username = guid.substring(0,7); +var emailAddress = guid + '@ninkip2p.com'; +var FASecret = ''; + +bs.setItem('testguid2', guid); + + +describe('Create Account Function', function () { + + + describe('createWallet', function () { + + this.timeout(10000); + + it("Creates a new account", function (done) { + + engine.createWallet(guid, password, username, emailAddress, function (err, result) { + + + expect(err).to.equal(false); + expect(result.wallet).to.exist; + + + engine.getTwoFactorImg(function (err, twoFASecret) { + + + FASecret = twoFASecret; + + bs.setItem('tfasec2', twoFASecret); + + console.log(twoFASecret); + + expect(err).to.equal(false); + expect(twoFASecret).to.exist; + + //generate an opt code from the secret + var twoFactorCode = speakeasy.totp({ key: twoFASecret, encoding: 'base32' }); + + + bs["tfasec2"] = twoFASecret; + + console.log(twoFactorCode); + + engine.SetupTwoFactor(twoFactorCode, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var token = "test"; + + engine.getEmailValidation(token, function (err, response) { + + console.log(response); + + expect(err).to.equal(true); + expect(response).to.exist; + + done(); + + }); + + + + }); + + + }); + + + }); + + }); + + }); + +}); + + +guid = bs.getItem("testguid2"); +password = "12345678"; +FASecret = bs.getItem("tfasec2"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + bs.setItem('fp' + guid, engine.m_fingerprint); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + + describe('User Functions', function () { + + describe('createAddress', function () { + + this.timeout(5000); + + it("Creates a receive address", function (done) { + + engine.createAddress('m/0/0', 1, function (err, newAddress, path) { + + + console.log("Send 2* 0.01 Testnet coins to :" + newAddress); + + expect(err).to.equal(false); + expect(newAddress).to.exist; + expect(path).to.exist; + + done(); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-create-address-for-contact.js b/tests/test-create-address-for-contact.js new file mode 100644 index 0000000..fe03ce1 --- /dev/null +++ b/tests/test-create-address-for-contact.js @@ -0,0 +1,105 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var guid2 = bs.getItem("testguid2"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +var username2 = guid2.substring(0, 7); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('createAddressForContact', function () { + + this.timeout(5000); + + it("Creates a receive address for contact", function (done) { + + engine.createAddressForFriend(username2, function (err, newAddress) { + + + console.log("Send 2* 0.01 Testnet coins to :" + newAddress); + + expect(err).to.equal(false); + expect(newAddress).to.exist; + done(); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-open-wallet.js b/tests/test-open-wallet.js new file mode 100644 index 0000000..9ae3fee --- /dev/null +++ b/tests/test-open-wallet.js @@ -0,0 +1,107 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + bs.setItem('fp' + guid, engine.m_fingerprint); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + + describe('User Functions', function () { + + describe('createAddress', function () { + + this.timeout(5000); + + it("Creates a receive address", function (done) { + + engine.createAddress('m/0/0', 1, function (err, newAddress, path) { + + + console.log("Send 2* 0.01 Testnet coins to :" + newAddress); + + expect(err).to.equal(false); + expect(newAddress).to.exist; + expect(path).to.exist; + + done(); + + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-send-transaction-contact.js b/tests/test-send-transaction-contact.js new file mode 100644 index 0000000..7ba59b5 --- /dev/null +++ b/tests/test-send-transaction-contact.js @@ -0,0 +1,106 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var guid2 = bs.getItem("testguid2"); + +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +var username2 = guid2.substring(0,7); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('sendTransaction to contact', function () { + + this.timeout(20000); + + it("Sends transaction to contact amount <= sum(outputs)-miners fee", function (done) { + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + engine.sendTransaction("friend", username2, "", 90000, twoFactorCode, function (err, transactionid) { + + console.log(transactionid); + + expect(err).to.equal(false); + expect(transactionid).to.exist; + + done(); + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-send-transaction.js b/tests/test-send-transaction.js new file mode 100644 index 0000000..80072c0 --- /dev/null +++ b/tests/test-send-transaction.js @@ -0,0 +1,137 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('sendTransaction', function () { + + this.timeout(5000); + + it("Sends transaction to address amount > sum(outputs)-miners fee", function (done) { + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + engine.sendTransaction("standard", "", "mkLqdjeJy5iQDyzFHESNYdb25c5ePLJqgM", 200000, twoFactorCode, function (err, transactionid) { + + console.log(transactionid); + + expect(err).to.equal(true); + expect(transactionid).to.equal("ErrInsufficientFunds"); + + done(); + + }, + + function (status, progress) { + + console.log(progress); + + }); + + }); + + }); + + describe('sendTransaction', function () { + + this.timeout(20000); + + it("Sends transaction to address amount <= sum(outputs)-miners fee", function (done) { + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + engine.sendTransaction("standard", "", "mkLqdjeJy5iQDyzFHESNYdb25c5ePLJqgM", 70000, twoFactorCode, function (err, transactionid) { + + console.log(transactionid); + + expect(err).to.equal(false); + expect(transactionid).to.exist; + + done(); + + }, + + function (status, progress) { + + console.log(progress); + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-update-settings.js b/tests/test-update-settings.js new file mode 100644 index 0000000..1e70c63 --- /dev/null +++ b/tests/test-update-settings.js @@ -0,0 +1,116 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + engine.setPass(password, guid); + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('updateAccountSettings', function () { + + this.timeout(5000); + + it("updates account settings", function (done) { + + var jsonPacket = { + guid: Engine.m_guid + }; + + jsonPacket['DailyTransactionLimit'] = 10000000; + jsonPacket['SingleTransactionLimit'] = 1000000; + jsonPacket['NoOfTransactionsPerDay'] = 4; + jsonPacket['NoOfTransactionsPerHour'] = 2; + jsonPacket['Inactivity'] = 10; + jsonPacket['MinersFee'] = 10000; + jsonPacket['CoinUnit'] = "BTC"; + jsonPacket['Email'] = "isthislive@ninkip2p.com"; + jsonPacket['EmailNotification'] = true; + jsonPacket['LocalCurrency'] = "USD" + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + engine.updateAccountSettings(jsonPacket, twoFactorCode, function (err, res) { + + console.log(res); + + expect(err).to.equal(false); + expect(res).to.equal('ok'); + + done(); + + + }); + + }); + + }); + + + }); + + +}); diff --git a/tests/test-user-details.js b/tests/test-user-details.js new file mode 100644 index 0000000..2e451c0 --- /dev/null +++ b/tests/test-user-details.js @@ -0,0 +1,124 @@ +var request = require('superagent'); +var expect = require('expect.js'); +var Engine = require('../src/ninki-engine'); +var API = require('../src/ninki-api'); +var speakeasy = require('speakeasy'); +var bs = require('browser-storage'); + +var engine = new Engine(); + +var guid = bs.getItem("testguid"); +var password = "12345678"; +var FASecret = bs.getItem("tfasec"); + +console.log(guid); +console.log(FASecret); + + +describe('Account Utilities', function () { + + + describe('Login Functions', function () { + + + describe('openWallet', function () { + + + this.timeout(10000); + + it("Verifies the users login details", function (done) { + + + engine.setPass(password, guid); + + + console.log(guid); + + engine.openWallet(guid, "", function (err, result) { + + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + var twoFactorCode = speakeasy.totp({ key: FASecret, encoding: 'base32' }); + + console.log(twoFactorCode); + + console.log("calling openWallet2fa"); + + + engine.openWallet2fa(twoFactorCode, true, function (err, result) { + + console.log(result); + + expect(err).to.equal(false); + expect(result).to.exist; + + done(); + + }); + + + }); + + }); + + }); + + }); + + + describe('User Functions', function () { + + describe('getBalance', function () { + + this.timeout(5000); + + it("Get's users balance", function (done) { + + engine.getBalance(function (err, result) { + + console.log(result.ConfirmedBalance); + console.log(result.UnconfirmedBalance); + console.log(result.TotalBalance); + + expect(err).to.equal(false); + + expect(result).to.exist; + expect(result.ConfirmedBalance).to.exist; + expect(result.UnconfirmedBalance).to.exist; + expect(result.TotalBalance).to.exist; + + done(); + + }); + + }); + + + it("Get's users transactions", function (done) { + + engine.getTransactionRecords(function (err, transactions) { + + console.log(transactions); + + expect(err).to.equal(false); + + expect(transactions).to.exist; + + + done(); + + }); + + }); + + }); + + + }); + + +});