From d9d678be612df112ff5b55017c16090071f59a21 Mon Sep 17 00:00:00 2001
From: xisi
Date: Wed, 15 Jan 2014 09:58:00 -0500
Subject: [PATCH] retooled most of the email confirmation setup
---
public/include/classes/payout.class.php | 28 +---
public/include/classes/token.class.php | 16 ++-
public/include/classes/user.class.php | 93 ++++++------
public/include/config/global.inc.dist.php | 2 +-
public/include/pages/account/edit.inc.php | 133 +++++++++++++-----
public/include/smarty_globals.inc.php | 1 +
public/include/version.inc.php | 4 +-
public/site_assets/mpos/css/layout.css | 11 ++
.../templates/mpos/account/edit/default.tpl | 75 ++++++++--
sql/000_base_structure.sql | 6 +-
sql/013_tokentype_update.sql | 2 +-
11 files changed, 248 insertions(+), 123 deletions(-)
diff --git a/public/include/classes/payout.class.php b/public/include/classes/payout.class.php
index 02c7ae84..c8298668 100644
--- a/public/include/classes/payout.class.php
+++ b/public/include/classes/payout.class.php
@@ -37,29 +37,14 @@ class Payout Extends Base {
* @return data mixed Inserted ID or false
**/
public function createPayout($account_id=NULL, $strToken) {
- // twofactor - if cashout enabled we need to create/check the token
+ // twofactor - consume the token if it is enabled and valid
if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['withdraw']) {
- $tData = $this->token->getToken($strToken, 'withdraw_funds');
- $tExists = $this->token->doesTokenExist('withdraw_funds', $account_id);
- if (!is_array($tData) && $tExists == false) {
- // token doesn't exist, let's create one, send an email with a link to use it, and error out
- $token = $this->token->createToken('withdraw_funds', $account_id);
- $aData['token'] = $token;
- $aData['username'] = $this->getUserName($account_id);
- $aData['email'] = $this->getUserEmail($aData['username']);
- $aData['subject'] = 'Manual payout request confirmation';
- $this->mail->sendMail('notifications/withdraw_funds', $aData);
- $this->setErrorMessage("A confirmation has been sent to your e-mail");
- return true;
+ $tValid = $this->token->isTokenValid($account_id, $strToken, 7);
+ if ($tValid) {
+ $this->token->deleteToken($strToken);
} else {
- // already exists, if it's valid delete it and allow this edit
- if ($strToken === $tData['token']) {
- $this->token->deleteToken($tData['token']);
- } else {
- // token exists for this type, but this is not the right token
- $this->setErrorMessage("A confirmation was sent to your e-mail, follow that link to cash out");
- return false;
- }
+ $this->setErrorMessage('Invalid token');
+ return false;
}
}
$stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id) VALUES (?)");
@@ -86,7 +71,6 @@ $oPayout = new Payout();
$oPayout->setDebug($debug);
$oPayout->setMysql($mysqli);
$oPayout->setConfig($config);
-$oPayout->setMail($mail);
$oPayout->setToken($oToken);
$oPayout->setErrorCodes($aErrorCodes);
diff --git a/public/include/classes/token.class.php b/public/include/classes/token.class.php
index ca68ebc7..bb947005 100644
--- a/public/include/classes/token.class.php
+++ b/public/include/classes/token.class.php
@@ -22,6 +22,20 @@ class Token Extends Base {
return $this->sqlError();
}
+ /**
+ * Check if a token we're passing in is completely valid
+ * @param account_id int Account id of user
+ * @param token string Token to check
+ * @param type int Type of token
+ * @return int 0 or 1
+ */
+ public function isTokenValid($account_id, $token, $type) {
+ $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? AND token = ? AND type = ? AND time < NOW() LIMIT 1");
+ if ($stmt && $stmt->bind_param('isi', $account_id, $token, $type) && $stmt->execute())
+ return $stmt->get_result()->num_rows;
+ return $this->sqlError();
+ }
+
/**
* Check if a token of this type already exists for a given account_id
* @param strType string Name of the type of token
@@ -35,7 +49,7 @@ class Token Extends Base {
}
$stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? AND type = ? LIMIT 1");
if ($stmt && $stmt->bind_param('ii', $account_id, $iToken_id) && $stmt->execute())
- return $stmt->num_rows;
+ return $stmt->get_result()->num_rows;
return $this->sqlError();
}
diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php
index 99275636..7e36b54a 100644
--- a/public/include/classes/user.class.php
+++ b/public/include/classes/user.class.php
@@ -255,6 +255,43 @@ class User extends Base {
return $dPercent;
}
+ /**
+ * Send e-mail to confirm a change for 2fa
+ * @param strType string Token type name
+ * @param userID int User ID
+ * @return bool
+ */
+ public function sendChangeConf($strType, $userID) {
+ $exists = $this->token->doesTokenExist($strType, $userID);
+ if ($exists == 0) {
+ $token = $this->token->createToken($strType, $userID);
+ $aData['token'] = $token;
+ $aData['username'] = $this->getUserName($userID);
+ $aData['email'] = $this->getUserEmail($aData['username']);
+ switch ($strType) {
+ case 'account_edit':
+ $aData['subject'] = 'Account detail change confirmation';
+ break;
+ case 'change_pw':
+ $aData['subject'] = 'Account password change confirmation';
+ break;
+ case 'withdraw_funds':
+ $aData['subject'] = 'Manual payout request confirmation';
+ break;
+ default:
+ $aData['subject'] = '';
+ }
+ if ($this->mail->sendMail('notifications/'.$strType, $aData)) {
+ return true;
+ } else {
+ $this->setErrorMessage('Failed to send the notification');
+ return false;
+ }
+ }
+ $this->setErrorMessage('A request has already been sent to your e-mail address. Please wait 10 minutes for it to expire.');
+ return false;
+ }
+
/**
* Update the accounts password
* @param userID int User ID
@@ -274,29 +311,14 @@ class User extends Base {
$this->setErrorMessage( 'New password is too short, please use more than 8 chars' );
return false;
}
- // twofactor - if changepw is enabled we need to create/check the token
+ // twofactor - consume the token if it is enabled and valid
if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['changepw']) {
- $tData = $this->token->getToken($strToken, 'change_pw');
- $tExists = $this->token->doesTokenExist('change_pw', $userID);
- if (!is_array($tData) && $tExists == false) {
- // token doesn't exist, let's create one, send an email with a link to use it, and error out
- $token = $this->token->createToken('change_pw', $userID);
- $aData['token'] = $token;
- $aData['username'] = $this->getUserName($userID);
- $aData['email'] = $this->getUserEmail($aData['username']);
- $aData['subject'] = 'Account password change confirmation';
- $this->mail->sendMail('notifications/change_pw', $aData);
- $this->setErrorMessage("A confirmation has been sent to your e-mail");
- return true;
+ $tValid = $this->token->isTokenValid($userID, $strToken, 6);
+ if ($tValid) {
+ $this->token->deleteToken($strToken);
} else {
- // already exists, if it's valid delete it and allow this edit
- if ($strToken === $tData['token']) {
- $this->token->deleteToken($tData['token']);
- } else {
- // token exists for this type, but this is not the right token
- $this->setErrorMessage("A confirmation was sent to your e-mail, follow that link to change your password");
- return false;
- }
+ $this->setErrorMessage('Invalid token');
+ return false;
}
}
$current = $this->getHash($current);
@@ -313,7 +335,7 @@ class User extends Base {
$this->setErrorMessage( 'Unable to update password, current password wrong?' );
return false;
}
-
+
/**
* Update account information from the edit account page
* @param userID int User ID
@@ -373,29 +395,14 @@ class User extends Base {
$threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold)));
$donate = min(100, max(0, floatval($donate)));
- // twofactor - if details enabled we need to create/check the token
+ // twofactor - consume the token if it is enabled and valid
if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['details']) {
- $tData = $this->token->getToken($strToken, 'account_edit');
- $tExists = $this->token->doesTokenExist('account_edit', $userID);
- if (!is_array($tData) && $tExists == false) {
- // token doesn't exist, let's create one, send an email with a link to use it, and error out
- $token = $this->token->createToken('account_edit', $userID);
- $aData['token'] = $token;
- $aData['username'] = $this->getUserName($userID);
- $aData['email'] = $this->getUserEmail($aData['username']);
- $aData['subject'] = 'Account detail change confirmation';
- $this->mail->sendMail('notifications/account_edit', $aData);
- $this->setErrorMessage("A confirmation has been sent to your e-mail");
- return true;
+ $tValid = $this->token->isTokenValid($userID, $strToken, 5);
+ if ($tValid) {
+ $this->token->deleteToken($strToken);
} else {
- // already exists, if it's valid delete it and allow this edit
- if ($strToken === $tData['token']) {
- $this->token->deleteToken($tData['token']);
- } else {
- // token exists for this type, but this is not the right token
- $this->setErrorMessage("A confirmation was sent to your e-mail, follow that link to edit your account details");
- return false;
- }
+ $this->setErrorMessage('Invalid token');
+ return false;
}
}
diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php
index 07c20eb0..13daf7da 100644
--- a/public/include/config/global.inc.dist.php
+++ b/public/include/config/global.inc.dist.php
@@ -7,7 +7,7 @@ if (!defined('SECURITY')) die('Hacking attempt');
* This is used in the version check to ensure you run the latest version of the configuration file.
* Once you upgraded your config, change the version here too.
**/
-$config['version'] = '0.0.3';
+$config['version'] = '0.0.4';
// Our include directory for additional features
define('INCLUDE_DIR', BASEPATH . 'include');
diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php
index b69baebd..95bbf74f 100644
--- a/public/include/pages/account/edit.inc.php
+++ b/public/include/pages/account/edit.inc.php
@@ -4,7 +4,44 @@
if (!defined('SECURITY'))
die('Hacking attempt');
+// 2fa tpl stuff
+$cp_editable = $wf_editable = $ea_editable = $wf_sent = $ea_sent = $cp_sent = 0;
+$ea_token = (!isset($_GET['ea_token'])) ? '' : $_GET['ea_token'];
+$cp_token = (!isset($_GET['cp_token'])) ? '' : $_GET['cp_token'];
+$wf_token = (!isset($_GET['wf_token'])) ? '' : $_GET['wf_token'];
if ($user->isAuthenticated()) {
+ // update 2f tpl stuff
+ if ($config['twofactor']['enabled']) {
+ $popupmsg = 'E-mail confirmations are required for ';
+ $popuptypes = array();
+ if ($config['twofactor']['options']['details']) {
+ $popuptypes[] = 'editing your details';
+ $ea_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $ea_token, 5);
+ $ea_sent = $user->token->doesTokenExist('account_edit', $_SESSION['USERDATA']['id']);
+ }
+ if ($config['twofactor']['options']['changepw']) {
+ $popuptypes[] = 'changing your password';
+ $cp_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $cp_token, 6);
+ $cp_sent = $user->token->doesTokenExist('change_pw', $_SESSION['USERDATA']['id']);
+ }
+ if ($config['twofactor']['options']['withdraw']) {
+ $popuptypes[] = 'withdrawals';
+ $wf_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $wf_token, 7);
+ $wf_sent = $user->token->doesTokenExist('withdraw_funds', $_SESSION['USERDATA']['id']);
+ }
+ $ptc = 0;
+ $ptcn = count($popuptypes);
+ foreach ($popuptypes as $pt) {
+ if ($ptcn == 1) { $popupmsg.= $popuptypes[$ptc]; continue; }
+ if ($ptc !== ($ptcn-1)) {
+ $popupmsg.= $popuptypes[$ptc].', ';
+ } else {
+ $popupmsg.= 'and '.$popuptypes[$ptc];
+ }
+ $ptc++;
+ }
+ $_SESSION['POPUP'][] = array('CONTENT' => $popupmsg, 'TYPE' => 'info');
+ }
if (isset($_POST['do']) && $_POST['do'] == 'genPin') {
if ($user->generatePin($_SESSION['USERDATA']['id'], $_POST['currentPassword'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Your PIN # has been sent to your email.', 'TYPE' => 'success');
@@ -13,54 +50,78 @@ if ($user->isAuthenticated()) {
}
}
else {
- if ( @$_POST['do'] && (! $user->checkPin($_SESSION['USERDATA']['id'], @$_POST['authPin']))) {
+ if ( @$_POST['do'] && (!$checkpin = $user->checkPin($_SESSION['USERDATA']['id'], @$_POST['authPin']))) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN. ' . ($config['maxfailed']['pin'] - $user->getUserPinFailed($_SESSION['USERDATA']['id'])) . ' attempts remaining.', 'TYPE' => 'errormsg');
} else {
- switch (@$_POST['do']) {
- case 'cashOut':
- if ($setting->getValue('disable_payouts') == 1 || $setting->getValue('disable_manual_payouts') == 1) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Manual payouts are disabled.', 'TYPE' => 'info');
- } else {
- $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
- $dBalance = $aBalance['confirmed'];
- if ($dBalance > $config['txfee_manual']) {
- if (!$oPayout->isPayoutActive($_SESSION['USERDATA']['id'])) {
- $wf_token = (!isset($_POST['wf_token'])) ? '' : $_POST['wf_token'];
- if ($iPayoutId = $oPayout->createPayout($_SESSION['USERDATA']['id'], $wf_token)) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Created new manual payout request with ID #' . $iPayoutId);
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $iPayoutId->getError(), 'TYPE' => 'errormsg');
- }
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'You already have one active manual payout request.', 'TYPE' => 'errormsg');
- }
+ if (isset($_POST['unlock']) && isset($_POST['utype']) && $checkpin) {
+ $validtypes = array('account_edit','change_pw','withdraw_funds');
+ $isvalid = in_array($_POST['utype'],$validtypes);
+ if ($isvalid) {
+ $ctype = strip_tags($_POST['utype']);
+ $send = $user->sendChangeConf($ctype, $_SESSION['USERDATA']['id']);
+ // set to sent for this pageload
+ if ($ctype == 'account_edit') $ea_sent = 1;
+ if ($ctype == 'change_pw') $cp_sent = 1;
+ if ($ctype == 'withdraw_funds') $wf_sent = 1;
+ if ($send) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'A confirmation was sent to your e-mail, follow that link to continue', 'TYPE' => 'success');
} else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee_manual'] . ' ' . $config['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
+ $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
}
}
- break;
-
- case 'updateAccount':
+ } else {
$ea_token = (!isset($_POST['ea_token'])) ? '' : $_POST['ea_token'];
- if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'], $_POST['is_anonymous'], $ea_token)) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
- }
- break;
-
- case 'updatePassword':
$cp_token = (!isset($_POST['cp_token'])) ? '' : $_POST['cp_token'];
- if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'], $cp_token)) {
- $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
- } else {
- $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
+ $wf_token = (!isset($_POST['wf_token'])) ? '' : $_POST['wf_token'];
+ switch (@$_POST['do']) {
+ case 'cashOut':
+ if ($setting->getValue('disable_payouts') == 1 || $setting->getValue('disable_manual_payouts') == 1) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Manual payouts are disabled.', 'TYPE' => 'info');
+ } else {
+ $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
+ $dBalance = $aBalance['confirmed'];
+ if ($dBalance > $config['txfee']) {
+ if (!$oPayout->isPayoutActive($_SESSION['USERDATA']['id'])) {
+ if ($iPayoutId = $oPayout->createPayout($_SESSION['USERDATA']['id'], $wf_token)) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Created new manual payout request with ID #' . $iPayoutId);
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $iPayoutId->getError(), 'TYPE' => 'errormsg');
+ }
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'You already have one active manual payout request.', 'TYPE' => 'errormsg');
+ }
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee'] . ' ' . $config['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
+ }
+ }
+ break;
+
+ case 'updateAccount':
+ if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'], $_POST['is_anonymous'], $ea_token)) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
+
+ case 'updatePassword':
+ if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'], $cp_token)) {
+ $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
+ } else {
+ $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
+ }
+ break;
}
- break;
}
}
}
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
+$smarty->assign("CHANGEPASSUNLOCKED", $cp_editable);
+$smarty->assign("WITHDRAWUNLOCKED", $wf_editable);
+$smarty->assign("DETAILSUNLOCKED", $ea_editable);
+$smarty->assign("CHANGEPASSSENT", $cp_sent);
+$smarty->assign("WITHDRAWSENT", $wf_sent);
+$smarty->assign("DETAILSSENT", $ea_sent);
?>
diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php
index 01eeacbf..21fbcf2a 100644
--- a/public/include/smarty_globals.inc.php
+++ b/public/include/smarty_globals.inc.php
@@ -64,6 +64,7 @@ $aGlobal = array(
'confirmations' => $config['confirmations'],
'reward' => $config['reward'],
'price' => $setting->getValue('price'),
+ 'twofactor' => $config['twofactor'],
'config' => array(
'disable_navbar' => $setting->getValue('disable_navbar'),
'disable_navbar_api' => $setting->getValue('disable_navbar_api'),
diff --git a/public/include/version.inc.php b/public/include/version.inc.php
index ffc53d5c..6db42c6c 100644
--- a/public/include/version.inc.php
+++ b/public/include/version.inc.php
@@ -3,8 +3,8 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
-define('CONFIG_VERSION', '0.0.3');
-define('MPOS_VERSION', '0.0.1');
+define('DB_VERSION', '0.0.4');
+define('CONFIG_VERSION', '0.0.4');
// Fetch installed database version
$db_version = $setting->getValue('DB_VERSION');
diff --git a/public/site_assets/mpos/css/layout.css b/public/site_assets/mpos/css/layout.css
index f28a2a70..d44651ee 100644
--- a/public/site_assets/mpos/css/layout.css
+++ b/public/site_assets/mpos/css/layout.css
@@ -580,6 +580,17 @@ text-shadow: 0 1px 0 #6CDCF9;
cursor: pointer;
}
+input[type=submit].alt_btn:disabled,input[type=submit].alt_btn:readonly {
+background: #D0D1D4 url(../images/btn_submit.png) repeat-x;
+border: 1px solid#aaa;
+text-shadow: none;
+color: #999;
+}
+
+input[type=submit].alt_btn:disabled:hover {
+color: #999;
+}
+
input[type=submit].alt_btn:hover {
color: #001217;
}
diff --git a/public/templates/mpos/account/edit/default.tpl b/public/templates/mpos/account/edit/default.tpl
index 1134ec2f..c63e6ccc 100644
--- a/public/templates/mpos/account/edit/default.tpl
+++ b/public/templates/mpos/account/edit/default.tpl
@@ -7,11 +7,11 @@
@@ -77,11 +92,11 @@