From 67a2f508d87e68a86b29db0e53166952ee8567ce Mon Sep 17 00:00:00 2001 From: onsightit Date: Sun, 23 Jul 2017 07:59:00 -0600 Subject: [PATCH] new structure --- README.md | 59 ++++------ coin.conf.template | 4 - lib/coin-client.js | 8 +- lib/coin.conf | 8 -- lib/coinapi.js | 108 +++--------------- lib/database.js | 37 +++--- lib/init-wallet.js | 28 ++--- lib/passport.js | 21 ++-- lib/settings.js | 33 ++++-- .../wallet/js/viewmodels/history/history.js | 16 +-- .../js/viewmodels/receive/receive-address.js | 2 +- .../wallet/js/viewmodels/receive/receive.js | 102 +++++++++++------ public/wallet/js/viewmodels/wallet.js | 61 ++++++---- public/wallet/views/receive.html | 4 +- routes/coin.js | 79 +++++++------ routes/user.js | 2 +- settings.json.template | 28 +++-- views/home.ejs | 2 +- wallet.js | 24 ++-- 19 files changed, 298 insertions(+), 328 deletions(-) delete mode 100644 coin.conf.template delete mode 100644 lib/coin.conf diff --git a/README.md b/README.md index d1cd8d3..561b587 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # Web-Wallet -Web-Wallet for altcoin daemons. +A Web-Wallet for altcoin daemons. + ## Prerequisites: -A running RPC coin daemon. See: https://github.com/YourApp/YourCoin +A running RPC coin daemon. See: https://github.com/Web-Wallet/YourCoin Mongo DB for storing account info. See: https://www.mongodb.com/ @@ -12,7 +13,7 @@ Mongo DB for storing account info. See: https://www.mongodb.com/ > use database-name > db.createUser( { user: "{user}", pwd: "{password}", roles: [ { role: "readWrite" } ] } ) -Node.js 6.x for running YourApp. For debian installations: +Node.js 6.x for running Web-Wallet. For debian installations: If running 4.x: > sudo apt-get purge nodejs npm @@ -21,7 +22,7 @@ Node.js 6.x for running YourApp. For debian installations: > curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - > sudo apt-get install -y nodejs -If YourApp is not running locally, https is the default protocol. To set up a self-signed SSL certificate in debian/apache2 environments, run: +If Web-Wallet is not running locally, https is the default protocol. To set up a self-signed SSL certificate in debian/apache2 environments, run: > sudo mkdir /etc/apache2/certs > sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/certs/{domain name}.key -out /etc/apache2/certs/{domain name}.crt @@ -31,11 +32,11 @@ If YourApp is not running locally, https is the default protocol. To set up a s ## Configuring: -Configure the database connection parameters, localizations and features of YourApp by copying 'settings.json.template' to 'settings.json' and making your changes in 'settings.json'. +Configure the database connection parameters, localizations and features of Web-Wallet by copying 'settings.json.template' to 'settings.json' and making your changes in 'settings.json'. -Configure YourApp and daemon for local or non-local operation, or a combination of both. For instance: +Configure Web-Wallet and daemon for local or non-local operation, or a combination of both. For instance: -If the coin daemon is running on the same machine as YourApp, the daemon's config file will be used. It can be found at: +If the coin daemon is running on the same machine as Web-Wallet, the daemon's config file will be used. It can be found at: // Mac OS '$HOME/Library/Application Support/YourCoin/yourcoin.conf' @@ -48,55 +49,39 @@ If the coin daemon is running on the same machine as YourApp, the daemon's confi (Substitute your coin's name for 'YourCoin' above.) -If the daemon is running on another machine, you will need to configure node.js's coin.conf file to match the daemon's config file. coin.conf is found in: lib/coin.conf - -Either way, the config file will need at a minimum the following parameters: +You will need to configure wallet params in settings.conf to match the wallet daemon's config file. The wallet daemon's config file will need the following parameters: - > rpcuser=rpcuser + > rpcuser=rpcuser # Change me. > rpcpassword=password # Change me! - > rpcconnect=localhost # RPC daemon - > rpcport=18181 - > server=1 # If not running a daemon - -Local vs Not-Local configuration: - -The config file parameter 'rpcconnect' determines whether the daemon is local or not-local, even if the daemon and YourApp are both running on the same machine. YourApp's boolean flag 'isLocal' is determined to be true if 'rpcconnect' is one of the following: - - > rpcconnect=127.0.0.1 - > rpcconnect=localhost - > rpcconnect=192.168.x.x - > rpcconnect=hostname_with_no_tld - -The last two examples allow for YourApp to be considered 'local', even though the node and daemon may be running on different machines on the same local network. - -If the daemon and YourApp are both running on the same machine, you can still define YourApp as NOT-local by setting the 'rpcconnect' parameter to a fully qualified domain name (i.e. myhost.homelan.net), which requirs a simple modification to the machine's hosts file. (e.g. 192.168.1.246 myhost.homelan.net) - -If 'isLocal' is true, more control over YourApp is allowed. (i.e. encrypting the wallet, locking/unlocking the wallet for sending/staking, and more wallet stats and features are available.) - -[See 'rpcconnect' in the coin's source code, init.cpp, for more information.] + > rpcport=19184 + > server=1 + > listen=1 + > daemon=1 + > staking=1 + > rpcallowip= -If you need to run YourApp app from a "sub directory" of the main web-site (e.g. https://example.com/wallet/), change the settings.json parameter, chRoot to: "". +If you need to run Web-Wallet app from a "sub directory" of the main web-site (e.g. https://example.com/web-wallet/), change the settings.json parameter, chRoot to: "". ## Running: Windows: - > YourApp.bat + > Web-Wallet.bat (If supervisor is not installed, run 'npm install supervisor'.) Linux: - > YourApp.sh + > Web-Wallet.sh (If 'daemon' is not installed, please consult your Linux distro's documentation for installing 'daemon'.) -YourApp has an admin account pre-defined which you can login with: +Web-Wallet has an admin account pre-defined which you can login with: > Login: MASTER_ACCOUNT > Password: password (you will be required to change this) -The MASTER_ACOUNT always sees YourApp as 'local' and has views into the wallet as if you were running a Qt wallet (i.e. the full wallet balance). +The MASTER_ACOUNT always sees Web-Wallet as 'local' and has views into the wallet as if you were running a Qt wallet (i.e. the full wallet balance). -To setup individual accounts, use YourApp's Signup page, or login with a social media account. +To setup individual accounts, use Web-Wallet's Signup page, or login with a social media account. diff --git a/coin.conf.template b/coin.conf.template deleted file mode 100644 index b6cea25..0000000 --- a/coin.conf.template +++ /dev/null @@ -1,4 +0,0 @@ -rpcuser=rpcuser -rpcpassword=password -rpcconnect=localhost # RPC Node -rpcport=19184 diff --git a/lib/coin-client.js b/lib/coin-client.js index 8a7a071..b9d3ce6 100644 --- a/lib/coin-client.js +++ b/lib/coin-client.js @@ -7,7 +7,7 @@ var api = require('./commands'), function Client(options) { this.opts = { host: 'localhost', - port: 18181, + port: 19184, method: 'POST', user: 'rpcuser', pass: 'rpcpass', @@ -16,7 +16,8 @@ function Client(options) { 'Authorization': '' }, https: false, - rejectUnauthorized: true, + strictSSL: false, + rejectUnauthorized: false, ca: null, passphrasecallback: null, account: '' @@ -75,7 +76,7 @@ Client.prototype = { data = JSON.parse(data); } catch(exception) { var errMsg = (res.statusCode !== 200 ? 'Invalid params ' + res.statusCode : 'Failed to parse JSON'); - // statusCode 403 is rpc auth failed. check local coin.conf params. + // statusCode 403 is rpc auth failed. Check local wallet params in settings.conf. errMsg += ' : '+JSON.stringify(data); return fn(new Error(errMsg)); } @@ -162,6 +163,7 @@ Client.prototype = { } else if (key === 'passphrasecallback' || key === 'account' || key === 'https' || + key === 'strictSSL' || key === 'rejectUnauthorized' || key === 'ca') { opts[key] = v; diff --git a/lib/coin.conf b/lib/coin.conf deleted file mode 100644 index ce41f79..0000000 --- a/lib/coin.conf +++ /dev/null @@ -1,8 +0,0 @@ -rpcuser=rpcuser -rpcpassword=password -rpcconnect=localhost # RPC Node -rpcport=18181 - -server=1 - -addnode=node.yourcoin.com diff --git a/lib/coinapi.js b/lib/coinapi.js index 05ce251..b0d45bb 100644 --- a/lib/coinapi.js +++ b/lib/coinapi.js @@ -1,104 +1,22 @@ -fs = require('fs-extra'); - -// Get the user defined application settings. -settings = require('./settings'); - -// You will need to configure the config file found in: coin.conf -// Otherwise, if the daemon is running on the same machine as the node, its config file will be used. +// Get the user defined application / database / wallet configurable parameters from settings.json. // See README.md for more information. -filepath = 'coin.conf'; -console.log("Reading " + filepath + " parameters..."); -if (fs.existsSync(filepath) === false){ - console.log("WARNING: " + filepath + " does not exists. Using the coin's config file..."); - if (process.platform == 'darwin'){ - // Mac OS - filepath = process.env.HOME + '/Library/Application Support/' + settings.coinName + '/' + settings.coinName + '.conf'; - } else if (process.platform == 'linux'){ - // Linux - filepath = process.env.HOME + '/.' + settings.coinName.toLowerCase() + '/' + settings.coinName.toLowerCase() + '.conf'; - } else { - // Windows - filepath = process.env.APPDATA + '/' + settings.coinName + '/' + settings.coinName + '.conf'; - } - if (fs.existsSync(filepath) === false){ - console.log("ERROR: " + filepath + " does not exists. Exiting."); - process.exit(3); - } -} - -conf_data = fs.readFileSync(filepath, 'utf8', function (err) { - if (err) { - return console.log(err); - } -}); - -function wordTrim(str){ - str.trim(); - var idx = str.search(/\s/); // look for whitespace after first word (ie. comments) - if (idx !== -1){ - str = str.substring(0, idx); - } - return str; -} - -arrayFromConf = conf_data.match(/[^\r\n]+/g); // Turn lines into array - -var rpcUser = ""; -var rpcPass = ""; -var rpcHost = ""; -var rpcPort = ""; - -for (var k in arrayFromConf){ - if (arrayFromConf.hasOwnProperty(k)){ - // Get specific parm and value before and after '=' - var p = wordTrim(arrayFromConf[k].substring(0, arrayFromConf[k].indexOf("="))); - var v = wordTrim(arrayFromConf[k].substring(arrayFromConf[k].indexOf("=") + 1)); - switch(p){ - case ("rpcuser"): - rpcUser = v; - break; - case ("rpcpassword"): - rpcPass = v; - break; - case ("rpcconnect"): - rpcHost = v.toLowerCase(); - break; - case ("rpcport"): - rpcPort = v; - break; - default: - break; - } - } -} -// Validation checks -if (rpcHost === "") - console.log("WARNING: " + filepath + " does not contain rpcconnect setting!"); -if (rpcPort === "") - console.log("WARNING: " + filepath + " does not contain rpcport setting!"); -if (rpcUser === "") - console.log("WARNING: " + filepath + " does not contain rpcuser setting!"); -if (rpcPass === "") - console.log("WARNING: " + filepath + " does not contain rpcpassword setting!"); - -var isLocal = false; -if (rpcHost === "localhost" || rpcHost === "127.0.0.1" || rpcHost.indexOf("192.168.") === 0 || rpcHost.indexOf(".") === -1){ - isLocal = true; -} +var settings = require('./settings'); var Client = require('./coin-client'); var client = new Client(); -client.set('host', rpcHost); -client.set('port', rpcPort); -client.set('user', rpcUser); -client.set('pass', rpcPass); -if (!isLocal) client.set('https', true); -if (!isLocal) client.set('rejectUnauthorized', false); // Use false if using a self-signed certificate. +client.set('user', settings.wallet.rpcuser); +client.set('pass', settings.wallet.rpcpassword); +client.set('host', settings.wallet.rpchost); +client.set('port', settings.wallet.rpcport); +client.set('https', settings.wallet.ssl); // Use true if wallet is not local. +client.set('strictSSL', settings.wallet.strictSSL); // Use false if using a self-signed certificate. +client.set('rejectUnauthorized', settings.wallet.rejectUnauthorized); // Use false if using a self-signed certificate. client.auth(); +// Clear from settings which gets passed to the client. +settings.wallet.rpcuser = "XXXXXXXX"; +settings.wallet.rpcpassword = "XXXXXXXX"; + module.exports.api = client; module.exports.settings = settings; -module.exports.isLocal = isLocal; -module.exports.rpcHost = rpcHost; -module.exports.rpcPort = rpcPort; diff --git a/lib/database.js b/lib/database.js index 450e643..3204ab8 100644 --- a/lib/database.js +++ b/lib/database.js @@ -11,21 +11,21 @@ var opts = {server: { }; mongoose.Promise = global.Promise; -mongoose.connection.on('close', function (){ +mongoose.connection.on('close', function () { console.log('Database closed.'); }); -mongoose.connection.on('error', function (err){ +mongoose.connection.on('error', function (err) { mongoose.disconnect(); console.log('Database error:' + err); process.emit('database_error', "Database error."); }); -mongoose.connection.on('disconnected', function (){ +mongoose.connection.on('disconnected', function () { process.emit('database_disconnected', "Database disconnected."); }); -mongoose.connection.on('reconnected', function (){ // If: auto_reconnect === true +mongoose.connection.on('reconnected', function () { // If: auto_reconnect === true process.emit('database_reconnected', "Database reconnected."); }); -mongoose.connection.on('connected', function (){ // If: auto_reconnect === false +mongoose.connection.on('connected', function () { // If: auto_reconnect === false process.emit('database_connected', "Database connected."); }); @@ -33,10 +33,10 @@ module.exports = { // Save the user's profile saveUserProfile: function(id, profile, cb) { //console.log("DEBUG: " + JSON.stringify(profile)); - User.findOne({'_id': id}, function(err, user){ - if (user){ + User.findOne({'_id': id}, function(err, user) { + if (user) { user.profile = profile; - user.save(function(err){ + user.save(function(err) { if(err) cb(err, "Save Error!"); else @@ -50,14 +50,17 @@ module.exports = { // Save the user's wallet saveUserWallet: function(id, node_id, account, addresses, cb) { - User.findOne({'_id': id}, function(err, user){ - if (user){ - for (var i = 0; i < user.wallet.length; i++){ - if (user.wallet[i].node_id === node_id && user.wallet[i].account === account){ - user.wallet[i].addresses = addresses; + User.findOne({'_id': id}, function(err, user) { + if (user) { + for (var i = 0; i < user.wallet.length; i++) { + if (user.wallet[i].node_id === node_id && user.wallet[i].account === account) { + user.wallet[i].addresses = []; // Re-init addresses + for (var j = 0; j < addresses.length; j++) { + user.wallet[i].addresses.push(addresses[j].address); + } } } - user.save(function(err){ + user.save(function(err) { if(err) cb(err, "Save Error!"); else @@ -83,9 +86,9 @@ module.exports = { // Close DB close: function(cb) { // mongoose.connection.readyState: 0 = disconnected, 1 = connected, 2 = connecting, 3 = disconnecting - if (mongoose.connection && mongoose.connection.readyState && mongoose.connection.readyState < 3){ - mongoose.connection.close(function (){ - mongoose.disconnect(function (){ + if (mongoose.connection && mongoose.connection.readyState && mongoose.connection.readyState < 3) { + mongoose.connection.close(function () { + mongoose.disconnect(function () { return cb(); }).catch(function (e) { console.log("Unable to disconnect from database: " + e); diff --git a/lib/init-wallet.js b/lib/init-wallet.js index b5da953..c6bf39e 100644 --- a/lib/init-wallet.js +++ b/lib/init-wallet.js @@ -5,7 +5,7 @@ var atob = require('atob'); var btoa = require('btoa'); -var coin = require('../streamspace.js'); +var coin = require('../wallet.js'); var User = require('./user'); // Globals @@ -20,9 +20,11 @@ function SetAccountAddresses(account, accountAddresses) { // Create a copy as accountAddresses will get nulled later var addresses = accountAddresses; // Foreach address: setaccount
- if (addresses && addresses.length) { + // NOTE: The wallet likes to have one blank ("") account address, + // so only do this if more than one address was found for "". + if (addresses && addresses.length > 1) { for (var k in addresses) { - if (addresses.hasOwnProperty(k) && addresses[k].substring(0,1) === coin.settings.coinChar) { + if (addresses.hasOwnProperty(k)) { coin.api.exec('setaccount', addresses[k], account, function(err, res) { if (err) { console.log("Init-Wallet: Error: err:" + err + " res:" + res); @@ -37,7 +39,7 @@ function GetAccountAddresses(account) { accountAddresses = []; // Null it out every call doneGetAccountAddresses = 30; // Reset interval counter every call coin.api.exec('getaddressesbyaccount', account, function(err, res) { - //console.log("DEBUG: Account '" + account + "' node_id: " + coin.rpcHost); + //console.log("DEBUG: Account '" + account + "' node_id: " + coin.settings.wallet.rpchost); if (typeof res !== 'undefined') { accountAddresses = res; @@ -57,7 +59,7 @@ function GetAccountAddresses(account) { } } else { - console.log("Error: No addresses for account: " + account + " node_id: " + coin.rpcHost); + console.log("Error: No addresses for account: " + account + " node_id: " + coin.settings.wallet.rpchost); console.log(err); doneGetAccountAddresses = 0; // set global flag-counter to break out of interval } @@ -75,10 +77,10 @@ function Init() { SetAccountAddresses(coin.settings.masterAccount, accountAddresses); // Find existing node_id for masterAccount. - User.findOne({'local.id': coin.settings.masterAccount, 'wallet.node_id': coin.rpcHost}, function(err, user) { + User.findOne({'local.id': coin.settings.masterAccount, 'wallet.node_id': coin.settings.wallet.rpchost}, function(err, user) { if (user) { foundUserWallet = true; - console.log("Init-Wallet: Found " + coin.settings.masterAccount + "'s wallet for the " + coin.settings.coinName + " node_id on: " + coin.rpcHost); + console.log("Init-Wallet: Found " + coin.settings.masterAccount + "'s wallet for the " + coin.settings.coinName + " node_id on: " + coin.settings.wallet.rpchost); // Get addresses for masterAccount. GetAccountAddresses(coin.settings.masterAccount); var interval = setInterval(function() { @@ -95,7 +97,7 @@ function Init() { },1000); // end timeout } else { doneFindUserWallet = 0; // set global flag-counter break out of interval - console.log("Init-Wallet: " + coin.settings.masterAccount + "'s wallet was NOT found for node_id: " + coin.rpcHost); + console.log("Init-Wallet: " + coin.settings.masterAccount + "'s wallet was NOT found for node_id: " + coin.settings.wallet.rpchost); } }); @@ -111,7 +113,7 @@ function Init() { if (err) return err; if (user) { - console.log("Init-Wallet: Creating a new wallet for " + coin.settings.masterAccount + " for node_id: " + coin.rpcHost); + console.log("Init-Wallet: Creating a new wallet for " + coin.settings.masterAccount + " for node_id: " + coin.settings.wallet.rpchost); // Get addresses for masterAccount. GetAccountAddresses(coin.settings.masterAccount); var interval = setInterval(function() { @@ -121,7 +123,7 @@ function Init() { // If the node is down, addresses will be null. if (accountAddresses && accountAddresses.length) { // Push the new wallet to user. - user.wallet.push( { node_id: coin.rpcHost, account: coin.settings.masterAccount, addresses: accountAddresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: coin.settings.masterAccount, addresses: accountAddresses }); user.save(function(err) { if (err) throw err; @@ -134,7 +136,7 @@ function Init() { },1000); // end timeout } else { // Create the masterAccount. - console.log("Init-Wallet: Creating a new account for " + coin.settings.masterAccount + " for node_id: " + coin.rpcHost); + console.log("Init-Wallet: Creating a new account for " + coin.settings.masterAccount + " for node_id: " + coin.settings.wallet.rpchost); // Get addresses for masterAccount. GetAccountAddresses(coin.settings.masterAccount); var interval = setInterval(function() { @@ -159,8 +161,6 @@ function Init() { newUser.local.id = coin.settings.masterAccount; newUser.local.password = newUser.local.generateHash("password"); newUser.local.changeme = true; - // This is temporarily set for logging into the Storj bridge. - newUser.profile.bridge_password = btoa("password"); newUser.profile.login_type = "local"; newUser.profile.last_login = Date.now(); newUser.profile.role = "Admin"; @@ -174,7 +174,7 @@ function Init() { newUser.profile.country = ""; newUser.profile.terms = false; newUser.profile.credit = 0; - newUser.wallet.push( { node_id: coin.rpcHost, account: coin.settings.masterAccount, addresses: accountAddresses }); + newUser.wallet.push( { node_id: coin.settings.wallet.rpchost, account: coin.settings.masterAccount, addresses: accountAddresses }); newUser.save(function(err) { if (err) diff --git a/lib/passport.js b/lib/passport.js index 6c7fc45..d66fee2 100644 --- a/lib/passport.js +++ b/lib/passport.js @@ -58,7 +58,6 @@ module.exports = function(passport) { User.findOne({'local.id': email}, function(err, user) { if (err) return done(err); - // TODO: If user exists, redirect to login page immediately and do not create a new address!!! if (user) { return done(null, false, req.flash('signupMessage', 'You already have an account. Please login, instead.')); } else { @@ -84,7 +83,7 @@ module.exports = function(passport) { // If we created a new address. Capture it. if (new_address) { - user.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); // sendfrom [minconf=1] [comment] [comment-to] [txcomment] coin.api.exec('sendfrom', coin.settings.masterAccount, addresses[0], coin.settings.newUserAmount, 1, "New Account", addresses[0], "Welcome to " + coin.settings.appTitle + "!", function(err, res) { if (err) console.log("Error: err:" + err + " res:" + res); @@ -108,7 +107,7 @@ module.exports = function(passport) { newUser.profile.country = ""; newUser.profile.terms = false; newUser.profile.credit = 0; - newUser.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + newUser.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); newUser.save(function(err) { if (err) @@ -146,7 +145,7 @@ module.exports = function(passport) { } else { new_address = true; user.wallet.filter(function(wal) { - if (wal.node_id === coin.rpcHost) { + if (wal.node_id === coin.settings.wallet.rpchost) { if (wal.addresses && wal.addresses.length) { new_address = false; // Found it } @@ -162,7 +161,7 @@ module.exports = function(passport) { addresses.push(res); } // push new wallet node/account/addresses - user.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); }); } @@ -287,7 +286,7 @@ module.exports = function(passport) { if (user) { // If we created a new address. Capture it. if (new_address) { - user.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); // sendfrom [minconf=1] [comment] [comment-to] [txcomment] coin.api.exec('sendfrom', coin.settings.masterAccount, addresses[0], coin.settings.newUserAmount, 1, "New Account", addresses[0], "Welcome to " + coin.settings.appTitle + "!", function(err, res) { if (err) console.log("Error: err:" + err + " res:" + res); @@ -323,7 +322,7 @@ module.exports = function(passport) { newUser.profile.country = ""; newUser.profile.terms = false; newUser.profile.credit = 0; - newUser.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + newUser.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); newUser.save(function(err) { if (err) @@ -382,7 +381,7 @@ module.exports = function(passport) { if (user) { // If we created a new address. Capture it. if (new_address) { - user.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); // sendfrom [minconf=1] [comment] [comment-to] [txcomment] coin.api.exec('sendfrom', coin.settings.masterAccount, addresses[0], coin.settings.newUserAmount, 1, "New Account", addresses[0], "Welcome to " + coin.settings.appTitle + "!", function(err, res) { if (err) console.log("Error: err:" + err + " res:" + res); @@ -418,7 +417,7 @@ module.exports = function(passport) { newUser.profile.country = ""; newUser.profile.terms = false; newUser.profile.credit = 0; - newUser.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + newUser.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); newUser.save(function(err) { if (err) @@ -477,7 +476,7 @@ module.exports = function(passport) { if (user) { // If we created a new address. Capture it. if (new_address) { - user.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + user.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); // sendfrom [minconf=1] [comment] [comment-to] [txcomment] coin.api.exec('sendfrom', coin.settings.masterAccount, addresses[0], coin.settings.newUserAmount, 1, "New Account", addresses[0], "Welcome to " + coin.settings.appTitle + "!", function(err, res) { if (err) console.log("Error: err:" + err + " res:" + res); @@ -513,7 +512,7 @@ module.exports = function(passport) { newUser.profile.country = ""; newUser.profile.terms = false; newUser.profile.credit = 0; - newUser.wallet.push( { node_id: coin.rpcHost, account: account, addresses: addresses }); + newUser.wallet.push( { node_id: coin.settings.wallet.rpchost, account: account, addresses: addresses }); newUser.save(function(err) { if (err) diff --git a/lib/settings.js b/lib/settings.js index f2bf9e3..c9f1738 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -12,7 +12,7 @@ var jsonminify = require("jsonminify"); // NOTE: rpcuser/pass/host/port is pulled from the coin's config file. // Version -exports.version = "2.1.0"; +exports.version = "2.0.0"; // Runtime environment: 'development' or 'production' exports.env = "development"; @@ -21,13 +21,13 @@ exports.env = "development"; exports.appHost = "localhost"; // The app title, visible in browser window -exports.appTitle = "YourApp"; +exports.appTitle = "YourCoin App"; // The app slogan -exports.appSlogan = "Explore YourApp!"; +exports.appSlogan = "Explore YourCoin!"; // The app description -exports.appDescription = "YourApp description goes here."; +exports.appDescription = "YourCoin App description goes here."; // The copyright for the footer exports.copyRight = "Copyright (c) " + moment().utc().format("YYYY") + ", The " + this.appTitle + " developers. All rights reserved."; @@ -44,8 +44,8 @@ exports.favicon = "./public/wallet/favicon.ico"; // Coin name / page heading exports.coinName = "YourCoin"; -// Coin symbol, e.g. BTC, VRC, SPCD, HCN, ... -exports.coinSymbol = "SPCD"; +// Coin symbol, e.g. BTC, VRC, SSH, HCN, ... +exports.coinSymbol = "SSH"; // Coin addresses start with this character exports.coinChar = "S"; @@ -64,7 +64,7 @@ exports.txComment = false; // # ORIGINAL RewriteRule . /index.php [L] // RewriteRule ./ /index.php [L] // Set to "" to allow the sub-folder 'wallet' to be exposed for proxying. -// Set to "/wallet" to chroot the node to /public/wallet/ (Normal for stand-alone YourApp). +// Set to "/wallet" to chroot the node to /public/wallet/ (Normal for stand-alone YourCoin). exports.chRoot = "/wallet"; // Show stats in navigation @@ -102,12 +102,23 @@ exports.mdb = { "port" : 27017 }; +// This setting is used to make RPC calls to the wallet daemon. +exports.wallet = { + "rpcuser": "rpcuser", + "rpcpassword": "rpcpassword", + "rpchost": "127.0.0.1", + "rpcport": 19184, + "ssl": false, + "rejectUnauthorized": false, + "strictSSL": false +}; + // MASTER_ACCOUNT will become an address label in the wallet. // *** DO NOT CHANGE THE ACCOUNT/PASSWORD AFTER FIRST RUN! *** -exports.masterAccount = "MASTER_ACCOUNT"; // Master login account, and Label to assign to "" wallet accounts. -exports.masterPassword = "SecretPassword"; // Master password for UI. -exports.masterEmail = "info@example.com"; // Master email account for UI. -exports.masterCanEncrypt = false; // Allow wallet encryption by MASTER_ACCOUNT +exports.masterAccount = "MASTER_ACCOUNT"; // Master login account, and Label to assign to "" wallet accounts. +exports.masterPassword = "SecretPassword"; // Master password for UI. +exports.masterEmail = "info@stream.space"; // Master email account for UI. +exports.masterCanEncrypt = true; // Allow wallet encryption by MASTER_ACCOUNT // Secret used for keyring and cookies exports.supersecret = "super secret pass phrase"; diff --git a/public/wallet/js/viewmodels/history/history.js b/public/wallet/js/viewmodels/history/history.js index 700de8b..c380b87 100644 --- a/public/wallet/js/viewmodels/history/history.js +++ b/public/wallet/js/viewmodels/history/history.js @@ -30,34 +30,34 @@ define(['knockout', } } if (!timerRefresh){ - self.getTransactions(self.wallet.account(), self.page()); + self.listTransactions(self.wallet.account(), self.page()); } }; historyType.prototype.firstPage = function(){ var self = this; - this.getTransactions(self.wallet.account(), self.pageFirst()); + this.listTransactions(self.wallet.account(), self.pageFirst()); }; historyType.prototype.prevPage = function(){ var self = this; - this.getTransactions(self.wallet.account(), self.pagePrev()); + this.listTransactions(self.wallet.account(), self.pagePrev()); }; historyType.prototype.nextPage = function(){ var self = this; - this.getTransactions(self.wallet.account(), self.pageNext()); + this.listTransactions(self.wallet.account(), self.pageNext()); }; historyType.prototype.lastPage = function(){ var self = this; - this.getTransactions(self.wallet.account(), self.pageLast()); + this.listTransactions(self.wallet.account(), self.pageLast()); }; - historyType.prototype.getTransactions = function(account, page){ + historyType.prototype.listTransactions = function(account, page){ var self = this, - getTransactionsCommand = new Command('listtransactions', [account, page], + listTransactionsCommand = new Command('listtransactions', [account, page], self.wallet.settings().chRoot, self.wallet.settings().env); // For pagination self.isLoadingTransactions(true); - var historyPromise = getTransactionsCommand.execute() + var historyPromise = listTransactionsCommand.execute() .done(function(data){ var i = 0, maxRows = self.wallet.settings().historyRowsPP; //var descendingTxns = data.reverse(); diff --git a/public/wallet/js/viewmodels/receive/receive-address.js b/public/wallet/js/viewmodels/receive/receive-address.js index 8d8d702..08142ec 100644 --- a/public/wallet/js/viewmodels/receive/receive-address.js +++ b/public/wallet/js/viewmodels/receive/receive-address.js @@ -1,8 +1,8 @@ define(['knockout'], function(){ var receiveAddressType = function(options){ var addressObj = options.addressObj || {}; - this.address = addressObj.address || ''; this.account = addressObj.account || ''; + this.address = addressObj.address || ''; this.amount = addressObj.amount || 0.0; this.confirmations = addressObj.confirmations || 0; }; diff --git a/public/wallet/js/viewmodels/receive/receive.js b/public/wallet/js/viewmodels/receive/receive.js index e5efbe1..c707606 100644 --- a/public/wallet/js/viewmodels/receive/receive.js +++ b/public/wallet/js/viewmodels/receive/receive.js @@ -2,8 +2,8 @@ define(['knockout', 'common/dialog', 'viewmodels/receive/receive-address', 'viewmodels/common/command', - 'viewmodels/receive/new-address-dialog'], function(ko,dialog,ReceiveAddress,Command,NewAddressDialog){ - var receiveType = function(options){ + 'viewmodels/receive/new-address-dialog'], function(ko,dialog,ReceiveAddress,Command,NewAddressDialog) { + var receiveType = function(options) { var self = this; self.wallet = options.parent || {}; @@ -11,7 +11,7 @@ define(['knockout', self.addresses = ko.observableArray([]); self.isLoadingReceiveAddresses = ko.observable(false); - self.isLoading = ko.computed(function(){ + self.isLoading = ko.computed(function() { var trans = self.isLoadingReceiveAddresses(); return trans; }); @@ -19,41 +19,78 @@ define(['knockout', self.showNewAddressDialog = ko.observable(false); }; - receiveType.prototype.refresh = function(timerRefresh){ + receiveType.prototype.refresh = function(timerRefresh) { var self = this; - if (self.wallet.account() !== ""){ - if (self.wallet.account() === self.wallet.settings().masterAccount){ + if (self.wallet.account() !== "") { + if (self.wallet.account() === self.wallet.settings().masterAccount) { self.statusMessage("Master Account Receive Addresses"); } } - if (!timerRefresh){ - self.getReceiveAddresses(); + if (!timerRefresh) { + self.statusMessage(""); + self.getAddressesByAccount(self.wallet.account()); } }; - receiveType.prototype.newAddress = function(){ + receiveType.prototype.getAddressesByAccount = function(account) { + var self = this, + getAddressesByAccountCommand = new Command('getaddressesbyaccount', [account], + self.wallet.settings().chRoot, + self.wallet.settings().env); + self.isLoadingReceiveAddresses(true); + var receivePromise = getAddressesByAccountCommand.execute() + .done(function(data) { + var addresses = []; + for (var k in data) { + //console.log("data[k]:" + JSON.stringify(data[k])); + addresses.push(new ReceiveAddress({ addressObj: { account: account, address: data[k] } })); + } + addresses.sort(function(a, b) {return b.amount - a.amount;}); // Sort by amount descending + if (addresses.length > self.addresses().length) { + self.addresses(ko.utils.arrayMap(addresses, function(addressObj) { + return new ReceiveAddress({addressObj: addressObj}); + })); + var saveUserWalletCommand = new Command('saveuserwallet', + [encodeURIComponent(btoa(self.wallet.account())), + encodeURIComponent(btoa(JSON.stringify(addresses)))], + self.wallet.settings().chRoot, + self.wallet.settings().env); + saveUserWalletCommand.execute() + .done(function(data) { + self.wallet.initUser(); // wallet needs updating. + }) + .fail(function() { + self.statusMessage("Addresses Save Error!"); + }); + } + self.isLoadingReceiveAddresses(false); + }); + return receivePromise; + }; + + receiveType.prototype.newAddress = function() { dialog.openDialog(this.newAddressDialog, 'modals/new-address'); }; - receiveType.prototype.newAddressConfirm = function(){ + receiveType.prototype.newAddressConfirm = function() { var self = this, getNewAddressCommand = new Command('getnewaddress', [self.wallet.account()], self.wallet.settings().chRoot, self.wallet.settings().env); getNewAddressCommand.execute() - .done(function(address){ - if (address && address.length === 34){ + .done(function(address) { + if (address && address.length === 34) { var addresses = []; - for (var k in self.addresses()){ - if (self.addresses()[k].account === self.wallet.account()){ + for (var k in self.addresses()) { + if (self.addresses()[k].account === self.wallet.account()) { // Save the address object addresses.push(self.addresses()[k]); } } - addresses.push(new ReceiveAddress({addressObj:{address: address, account: self.wallet.account()}})); - addresses.sort(function(a, b){return b.amount - a.amount;}); // Sort by amount descending - self.addresses(ko.utils.arrayMap(addresses, function(addressObj){ + addresses.push(new ReceiveAddress({ addressObj: { account: self.wallet.account(), address: address } })); + addresses.sort(function(a, b) {return b.amount - a.amount;}); // Sort by amount descending + self.addresses(ko.utils.arrayMap(addresses, function(addressObj) { return new ReceiveAddress({addressObj: addressObj}); })); var saveUserWalletCommand = new Command('saveuserwallet', @@ -62,48 +99,47 @@ define(['knockout', self.wallet.settings().chRoot, self.wallet.settings().env); saveUserWalletCommand.execute() - .done(function(data){ - self.statusMessage(data); + .done(function(data) { + self.statusMessage("New Address Added!"); self.wallet.initUser(); // wallet needs updating. }) - .fail(function(){ - self.statusMessage("Save Error!"); + .fail(function() { + self.statusMessage("New Address Save Error!"); }); } else { self.statusMessage("There was a problem creating a new address."); } }) - .fail(function(){ + .fail(function() { }) - .always(function(){ + .always(function() { }); dialog.closeDialog(); }; - receiveType.prototype.newAddressCancel = function(){ - dialog.closeDialog(); + receiveType.prototype.newAddressCancel = function() { + dialog.closeDialog(); }; - receiveType.prototype.getReceiveAddresses = function(){ + receiveType.prototype.listReceivedByAddresses = function() { var self = this, masterAccount = (self.wallet.account() === self.wallet.settings().masterAccount), - listEmpty = (masterAccount ? "true" : "false"), - listReceivedByAddressesCommand = new Command('listreceivedbyaddress', ['1',listEmpty], + listReceivedByAddressesCommand = new Command('listreceivedbyaddress', ['1', true], self.wallet.settings().chRoot, self.wallet.settings().env); self.isLoadingReceiveAddresses(true); var receivePromise = listReceivedByAddressesCommand.execute() - .done(function(data){ + .done(function(data) { var addresses = []; - for (var k in data){ + for (var k in data) { //console.log("data[k]:" + JSON.stringify(data[k])); - if (masterAccount || data[k].account === self.wallet.account()){ + if (masterAccount || data[k].account === self.wallet.account()) { addresses.push(data[k]); } } - addresses.sort(function(a, b){return b.amount - a.amount;}); // Sort by amount descending - self.addresses(ko.utils.arrayMap(addresses, function(addressObj){ + addresses.sort(function(a, b) {return b.amount - a.amount;}); // Sort by amount descending + self.addresses(ko.utils.arrayMap(addresses, function(addressObj) { return new ReceiveAddress({addressObj: addressObj}); })); self.isLoadingReceiveAddresses(false); diff --git a/public/wallet/js/viewmodels/wallet.js b/public/wallet/js/viewmodels/wallet.js index cd40fec..6acf4a1 100644 --- a/public/wallet/js/viewmodels/wallet.js +++ b/public/wallet/js/viewmodels/wallet.js @@ -13,6 +13,8 @@ define(['knockout', 'common/dialog', 'viewmodels/wallet-status', 'viewmodels/home/home', + 'viewmodels/streams/streams', + 'viewmodels/upload/upload', 'viewmodels/send/send', 'viewmodels/receive/receive', 'viewmodels/history/history', @@ -21,7 +23,8 @@ define(['knockout', 'viewmodels/profile/profile', 'bindinghandlers/modal', 'viewmodels/common/wallet-passphrase', - 'viewmodels/common/command'], function(ko, dialog, WalletStatus, Home, Send, Receive, History, Explore, Console, Profile, Modal, WalletPassphrase, Command){ + 'viewmodels/common/command', + 'viewmodels/nodestats/nodestats'], function(ko, dialog, WalletStatus, Home, Streams, Upload, Send, Receive, History, Explore, Console, Profile, Modal, WalletPassphrase, Command, NodeStats){ var walletType = function(){ var self = this; @@ -39,7 +42,6 @@ define(['knockout', self.account = ko.observable(""); self.addresses = ko.observableArray([]); - self.isLocalWallet = ko.observable(false); // Is the node local? self.settings = ko.observable({}); // Some settings from settings.json // Get node_id and settings, and User account @@ -52,12 +54,15 @@ define(['knockout', self.showStats = ko.observable(true); this.home = new Home({parent: self}); + this.streams = new Streams({parent: self}); + this.upload = new Upload({parent: self}); this.send = new Send({parent: self}); this.receive = new Receive({parent: self}); this.history = new History({parent: self}); this.explore = new Explore({parent: self}); this.console = new Console({parent: self}); this.profile = new Profile({parent: self}); + this.nodestats = new NodeStats({parent: self}); self.currentView.subscribe(function (view){ self.sessionExpires(Date.now() + self.sessionTimeout()); @@ -65,6 +70,12 @@ define(['knockout', case ("home"): self.home.refresh(false); break; + case ("streams"): + self.streams.refresh(false); + break; + case ("upload"): + self.upload.refresh(false); + break; case ("send"): self.send.refresh(false); break; @@ -83,6 +94,9 @@ define(['knockout', case ("profile"): self.profile.refresh(false); break; + case ("nodestats"): + self.nodestats.refresh(false); + break; default: break; } @@ -107,7 +121,6 @@ define(['knockout', self.isLoadingStatus = ko.observable(true); self.timeout = 1000; - self.timerRefresh = false; // Start polling! self.pollWalletStatus(); @@ -116,7 +129,7 @@ define(['knockout', // Called once at startup. walletType.prototype.initNode = function(chRoot){ var self = this; - // Catch-22: We don't know if YourApp is chRoot'd to /public or /public/wallet, + // Catch-22: We don't know if YourCoin is chRoot'd to /public or /public/wallet, // because 'settings' has not been set yet, so we need to test for a failure first // to determine if settings().chRoot is "" or "/wallet". var getNodeInfoCommand = new Command('getnodeinfo', [], @@ -124,9 +137,8 @@ define(['knockout', 'production'); // Gets the wallet info and settings quietly $.when(getNodeInfoCommand.execute()) .done(function(getNodeInfoData){ - if (typeof getNodeInfoData.node_id !== 'undefined'){ - self.node_id(getNodeInfoData.node_id); - self.isLocalWallet(getNodeInfoData.isLocal); + if (typeof getNodeInfoData.settings.wallet.rpchost !== 'undefined'){ + self.node_id(getNodeInfoData.settings.wallet.rpchost); self.settings(getNodeInfoData.settings); self.showStats(self.settings().showStats || false); if (self.settings().env !== 'production'){ @@ -137,10 +149,11 @@ define(['knockout', console.log("ERROR: Aborting! Node_ID not found."); window.location = chRoot + '/logout'; } + //console.log("DEBUG: node_id: " + self.node_id()); self.initUser(); }).fail(function(jqXHR){ // If the second call to initNode fails, we bail. - if (chRoot === '/wallet'){ + if (chRoot !== '') { self.initNode(''); // Set unknown chRoot to normal '' mode. } else { // Bailing... @@ -156,7 +169,7 @@ define(['knockout', var self = this; var getUserAccountCommand = new Command('getuseraccount', [], self.settings().chRoot, - 'production'); // Gets the User from the session quietly + self.settings().env); $.when(getUserAccountCommand.execute()) .done(function(getUserAccountData){ if (typeof getUserAccountData.User !== 'undefined'){ @@ -207,10 +220,9 @@ define(['knockout', } else { // Normal polling if (Date.now() <= self.sessionExpires()){ - $.when(self.refresh(self.timerRefresh)).done(function(){ + $.when(self.refresh(true)).done(function(){ if (self.timeout < 60000){ // First timeout self.timeout = 60000; - self.timerRefresh = false; // NOTE: self.walletUp() is set true when the socket server sends the message. // (see /public/../js/app.js). if (self.walletUp()) { @@ -245,6 +257,7 @@ define(['knockout', self.explore.refresh(timerRefresh); self.console.refresh(timerRefresh); self.profile.refresh(timerRefresh); + self.nodestats.refresh(timerRefresh); }); return refreshPromise; }; @@ -252,7 +265,7 @@ define(['knockout', walletType.prototype.checkEncryptionStatus = function(){ var self = this; // Do not allow non-local wallets to be encrypted except by MASTER_ACCOUNT! - if (self.isLocalWallet() || (self.account() === self.settings().masterAccount && self.settings().masterCanEncrypt === true)){ + if (self.account() === self.settings().masterAccount && self.settings().masterCanEncrypt === true){ switch(self.walletStatus.unlockedUntil()){ case -1: // wallet is unencrypted self.promptToEncrypt(); @@ -268,7 +281,7 @@ define(['knockout', walletType.prototype.unlockWallet = function(){ var self = this; - if (self.isLocalWallet() || self.account() === self.settings().masterAccount){ + if (self.account() === self.settings().masterAccount){ new WalletPassphrase({canSpecifyStaking: true}).userPrompt(false, 'Unlock Wallet', 'This action will unlock the wallet for sending or staking','OK') .done(function(result){ //console.log(result); @@ -276,16 +289,18 @@ define(['knockout', result.passphrase = "XXXXXXXX"; // Clear password in memory }) .fail(function(error){ - console.log(error); - dialog.notification(error.message); - self.walletStatus.refresh(); + if (error) { + console.log(error); + dialog.notification(error.message); + self.walletStatus.refresh(); + } }); } }; walletType.prototype.lockWallet = function(){ var self = this; - if (self.isLocalWallet() || self.account() === self.settings().masterAccount){ + if (self.account() === self.settings().masterAccount){ var walletLockCommand = new Command('walletlock', [], self.settings().chRoot, self.settings().env).execute() @@ -308,8 +323,10 @@ define(['knockout', dialog.notification("Wallet successfully encrypted. Restart your coin daemon to continue."); }) .fail(function(error){ - console.log(error); - dialog.notification(error.message); + if (error) { + console.log(error); + dialog.notification(error.message); + } }); }; @@ -320,8 +337,10 @@ define(['knockout', console.log(result); }) .fail(function(error){ - console.log(error); - dialog.notification(error.message); + if (error) { + console.log(error); + dialog.notification(error.message); + } }); }; diff --git a/public/wallet/views/receive.html b/public/wallet/views/receive.html index 9df044f..b952595 100644 --- a/public/wallet/views/receive.html +++ b/public/wallet/views/receive.html @@ -10,7 +10,6 @@

Receive Account Address - Amount @@ -19,7 +18,6 @@

Receive - @@ -27,7 +25,7 @@

Receive
-
+