PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/give/includes/class-give-email-access.php

https://bitbucket.org/bryanhui/wordpress-wptouchpoc
PHP | 381 lines | 130 code | 58 blank | 193 comment | 17 complexity | 558c14b0fe5769b50c08583f01a4a3d1 MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0, BSD-3-Clause, GPL-3.0
  1. <?php
  2. /**
  3. * Email Access
  4. *
  5. * @package Give
  6. * @subpackage Classes/Give_Email_Access
  7. * @copyright Copyright (c) 2016, WordImpress
  8. * @license https://opensource.org/licenses/gpl-license GNU Public License
  9. * @since 1.4
  10. */
  11. // Exit if accessed directly.
  12. if ( ! defined( 'ABSPATH' ) ) {
  13. exit;
  14. }
  15. /**
  16. * Give_Email_Access class
  17. *
  18. * This class handles email access, allowing donors access to their donation w/o logging in;
  19. *
  20. * Based on the work from Matt Gibbs - https://github.com/FacetWP/edd-no-logins
  21. *
  22. * @since 1.0
  23. */
  24. class Give_Email_Access {
  25. /**
  26. * Token exists
  27. *
  28. * @since 1.0
  29. * @access public
  30. *
  31. * @var bool
  32. */
  33. public $token_exists = false;
  34. /**
  35. * Token email
  36. *
  37. * @since 1.0
  38. * @access public
  39. *
  40. * @var bool
  41. */
  42. public $token_email = false;
  43. /**
  44. * Token
  45. *
  46. * @since 1.0
  47. * @access public
  48. *
  49. * @var bool
  50. */
  51. public $token = false;
  52. /**
  53. * Error
  54. *
  55. * @since 1.0
  56. * @access public
  57. *
  58. * @var string
  59. */
  60. public $error = '';
  61. /**
  62. * Verify throttle
  63. *
  64. * @since 1.0
  65. * @access public
  66. *
  67. * @var
  68. */
  69. public $verify_throttle;
  70. /**
  71. * Limit throttle
  72. *
  73. * @since 1.8.17
  74. * @access public
  75. *
  76. * @var
  77. */
  78. public $limit_throttle;
  79. /**
  80. * Verify expiration
  81. *
  82. * @since 1.0
  83. * @access private
  84. *
  85. * @var string
  86. */
  87. private $token_expiration;
  88. /**
  89. * Class Constructor
  90. *
  91. * Set up the Give Email Access Class.
  92. *
  93. * @since 1.0
  94. * @access public
  95. */
  96. public function __construct() {
  97. // get it started
  98. add_action( 'init', array( $this, 'init' ) );
  99. }
  100. /**
  101. * Init
  102. *
  103. * Register defaults and filters
  104. *
  105. * @since 1.0
  106. * @access public
  107. *
  108. * @return void
  109. */
  110. public function init() {
  111. // Bail Out, if user is logged in.
  112. if ( is_user_logged_in() ) {
  113. return;
  114. }
  115. // Are db columns setup?
  116. $column_exists = Give()->donors->does_column_exist( 'token' );
  117. if ( ! $column_exists ) {
  118. $this->create_columns();
  119. }
  120. // Timeouts.
  121. $this->verify_throttle = apply_filters( 'give_nl_verify_throttle', 300 );
  122. $this->limit_throttle = apply_filters( 'give_nl_limit_throttle', 3 );
  123. $this->token_expiration = apply_filters( 'give_nl_token_expiration', 7200 );
  124. // Setup login.
  125. $this->check_for_token();
  126. if ( $this->token_exists ) {
  127. add_filter( 'give_can_view_receipt', '__return_true' );
  128. add_filter( 'give_user_pending_verification', '__return_false' );
  129. add_filter( 'give_get_users_donations_args', array( $this, 'users_donations_args' ) );
  130. }
  131. }
  132. /**
  133. * Prevent email spamming.
  134. *
  135. * @param int $donor_id Donor ID.
  136. *
  137. * @since 1.0
  138. * @access public
  139. *
  140. * @return bool
  141. */
  142. public function can_send_email( $donor_id ) {
  143. $donor = Give()->donors->get_donor_by( 'id', $donor_id );
  144. if ( is_object( $donor ) ) {
  145. $email_throttle_count = (int) give_get_meta( $donor_id, '_give_email_throttle_count', true );
  146. $cache_key = "give_cache_email_throttle_limit_exhausted_{$donor_id}";
  147. if (
  148. $email_throttle_count < $this->limit_throttle &&
  149. true !== Give_Cache::get( $cache_key )
  150. ) {
  151. give_update_meta( $donor_id, '_give_email_throttle_count', $email_throttle_count + 1 );
  152. } else {
  153. give_update_meta( $donor_id, '_give_email_throttle_count', 0 );
  154. Give_Cache::set( $cache_key, true, $this->verify_throttle );
  155. return false;
  156. }
  157. }
  158. return true;
  159. }
  160. /**
  161. * Send the user's token
  162. *
  163. * @param int $donor_id Donor id.
  164. * @param string $email Donor email.
  165. *
  166. * @since 1.0
  167. * @access public
  168. *
  169. * @return bool
  170. */
  171. public function send_email( $donor_id, $email ) {
  172. return apply_filters( 'give_email-access_email_notification', $donor_id, $email );
  173. }
  174. /**
  175. * Has the user authenticated?
  176. *
  177. * @since 1.0
  178. * @access public
  179. *
  180. * @return bool
  181. */
  182. public function check_for_token() {
  183. $token = isset( $_GET['give_nl'] ) ? give_clean( $_GET['give_nl'] ) : '';
  184. // Check for cookie.
  185. if ( empty( $token ) ) {
  186. $token = isset( $_COOKIE['give_nl'] ) ? give_clean( $_COOKIE['give_nl'] ) : '';
  187. }
  188. // Must have a token.
  189. if ( ! empty( $token ) ) {
  190. if ( ! $this->is_valid_token( $token ) ) {
  191. if ( ! $this->is_valid_verify_key( $token ) ) {
  192. return false;
  193. }
  194. }
  195. // Set Receipt Access Session.
  196. Give()->session->set( 'receipt_access', true );
  197. $this->token_exists = true;
  198. // Set cookie.
  199. $lifetime = current_time( 'timestamp' ) + Give()->session->set_expiration_time();
  200. @setcookie( 'give_nl', $token, $lifetime, COOKIEPATH, COOKIE_DOMAIN, false );
  201. return true;
  202. }
  203. }
  204. /**
  205. * Is this a valid token?
  206. *
  207. * @since 1.0
  208. * @access public
  209. *
  210. * @param $token string The token.
  211. *
  212. * @return bool
  213. */
  214. public function is_valid_token( $token ) {
  215. global $wpdb;
  216. // Make sure token isn't expired.
  217. $expires = date( 'Y-m-d H:i:s', time() - $this->token_expiration );
  218. $email = $wpdb->get_var(
  219. $wpdb->prepare( "SELECT email FROM {$wpdb->donors} WHERE verify_key = %s AND verify_throttle >= %s LIMIT 1", $token, $expires )
  220. );
  221. if ( ! empty( $email ) ) {
  222. $this->token_email = $email;
  223. $this->token = $token;
  224. return true;
  225. }
  226. // Set error only if email access form isn't being submitted.
  227. if ( ! isset( $_POST['give_email'] ) && ! isset( $_POST['_wpnonce'] ) ) {
  228. give_set_error( 'give_email_token_expired', apply_filters( 'give_email_token_expired_message', __( 'Your access token has expired. Please request a new one below:', 'give' ) ) );
  229. }
  230. return false;
  231. }
  232. /**
  233. * Add the verify key to DB
  234. *
  235. * @param int $donor_id Donor id.
  236. * @param string $email Donor email.
  237. * @param string $verify_key The verification key.
  238. *
  239. * @since 1.0
  240. * @access public
  241. *
  242. * @return void
  243. */
  244. public function set_verify_key( $donor_id, $email, $verify_key ) {
  245. global $wpdb;
  246. $now = date( 'Y-m-d H:i:s' );
  247. // Insert or update?
  248. $row_id = (int) $wpdb->get_var(
  249. $wpdb->prepare( "SELECT id FROM {$wpdb->donors} WHERE id = %d LIMIT 1", $donor_id )
  250. );
  251. // Update.
  252. if ( ! empty( $row_id ) ) {
  253. $wpdb->query(
  254. $wpdb->prepare( "UPDATE {$wpdb->donors} SET verify_key = %s, verify_throttle = %s WHERE id = %d LIMIT 1", $verify_key, $now, $row_id )
  255. );
  256. } // Insert.
  257. else {
  258. $wpdb->query(
  259. $wpdb->prepare( "INSERT INTO {$wpdb->donors} ( verify_key, verify_throttle) VALUES (%s, %s)", $verify_key, $now )
  260. );
  261. }
  262. }
  263. /**
  264. * Is this a valid verify key?
  265. *
  266. * @since 1.0
  267. * @access public
  268. *
  269. * @param $token string The token.
  270. *
  271. * @return bool
  272. */
  273. public function is_valid_verify_key( $token ) {
  274. /* @var WPDB $wpdb */
  275. global $wpdb;
  276. // See if the verify_key exists.
  277. $row = $wpdb->get_row(
  278. $wpdb->prepare( "SELECT id, email FROM {$wpdb->donors} WHERE verify_key = %s LIMIT 1", $token )
  279. );
  280. $now = date( 'Y-m-d H:i:s' );
  281. // Set token and remove verify key.
  282. if ( ! empty( $row ) ) {
  283. $wpdb->query(
  284. $wpdb->prepare( "UPDATE {$wpdb->donors} SET verify_key = '', token = %s, verify_throttle = %s WHERE id = %d LIMIT 1", $token, $now, $row->id )
  285. );
  286. $this->token_email = $row->email;
  287. $this->token = $token;
  288. return true;
  289. }
  290. return false;
  291. }
  292. /**
  293. * Users donations args
  294. *
  295. * Force Give to find donations by email, not user ID.
  296. *
  297. * @since 1.0
  298. * @access public
  299. *
  300. * @param $args array User Donations arguments.
  301. *
  302. * @return mixed
  303. */
  304. public function users_donations_args( $args ) {
  305. $args['user'] = $this->token_email;
  306. return $args;
  307. }
  308. /**
  309. * Create required columns
  310. *
  311. * Create the necessary columns for email access
  312. *
  313. * @since 1.0
  314. * @access public
  315. *
  316. * @return void
  317. */
  318. public function create_columns() {
  319. global $wpdb;
  320. // Create columns in donors table.
  321. $wpdb->query( "ALTER TABLE {$wpdb->donors} ADD `token` VARCHAR(255) CHARACTER SET utf8 NOT NULL, ADD `verify_key` VARCHAR(255) CHARACTER SET utf8 NOT NULL AFTER `token`, ADD `verify_throttle` DATETIME NOT NULL AFTER `verify_key`" );
  322. }
  323. }