Csrf::generateToken()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 3
c 1
b 0
f 1
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * @package   WPEmerge
4
 * @author    Atanas Angelov <[email protected]>
5
 * @copyright 2017-2019 Atanas Angelov
6
 * @license   https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
7
 * @link      https://wpemerge.com/
8
 */
9
10
namespace WPEmerge\Csrf;
11
12
use WPEmerge\Requests\RequestInterface;
13
14
/**
15
 * Provide CSRF protection utilities through WordPress nonces.
16
 */
17
class Csrf {
18
	/**
19
	 * Convenience header to check for the token.
20
	 *
21
	 * @var string
22
	 */
23
	protected $header = 'X-CSRF-TOKEN';
24
25
	/**
26
	 * GET/POST parameter key to check for the token.
27
	 *
28
	 * @var string
29
	 */
30
	protected $key = '';
31
32
	/**
33
	 * Maximum token lifetime.
34
	 *
35
	 * @link https://codex.wordpress.org/Function_Reference/wp_verify_nonce
36
	 * @var integer
37
	 */
38
	protected $maximum_lifetime = 2;
39
40
	/**
41
	 * Last generated tokens.
42
	 *
43
	 * @var array<string, string>
44
	 */
45
	protected $tokens = [];
46
47
	/**
48
	 * Constructor.
49
	 *
50
	 * @codeCoverageIgnore
51
	 * @param string  $key
52
	 * @param integer $maximum_lifetime
53
	 */
54
	public function __construct( $key = '__wpemergeCsrfToken', $maximum_lifetime = 2 ) {
55
		$this->key = $key;
56
		$this->maximum_lifetime = $maximum_lifetime;
57
	}
58
59
	/**
60
	 * Get the last generated token.
61
	 *
62
	 * @param  int|string $action
63
	 * @return string
64
	 */
65
	public function getToken( $action = -1 ) {
66
		if ( ! isset( $this->tokens[ $action ] ) ) {
67
			return $this->generateToken( $action );
68
		}
69
70
		return $this->tokens[ $action ];
71
	}
72
73
	/**
74
	 * Get the csrf token from a request.
75
	 *
76
	 * @param  RequestInterface $request
77
	 * @return string
78
	 */
79
	public function getTokenFromRequest( RequestInterface $request ) {
80
		$query = $request->query( $this->key );
81
		if ( $query ) {
82
			return $query;
83
		}
84
85
		$body = $request->body( $this->key );
86
		if ( $body ) {
87
			return $body;
88
		}
89
90
		$header = $request->getHeaderLine( $this->header );
91
		if ( $header ) {
92
			return $header;
93
		}
94
95
		return '';
96
	}
97
98
	/**
99
	 * Generate a new token.
100
	 *
101
	 * @param  int|string $action
102
	 * @return string
103
	 */
104
	public function generateToken( $action = -1 ) {
105
		$action = $action === -1 ? session_id() : $action;
106
107
		$this->tokens[ $action ] = wp_create_nonce( $action );
108
109
		return $this->getToken( $action );
110
	}
111
112
	/**
113
	 * Check if a token is valid.
114
	 *
115
	 * @param  string     $token
116
	 * @param  int|string $action
117
	 * @return boolean
118
	 */
119
	public function isValidToken( $token, $action = -1 ) {
120
		$action = $action === -1 ? session_id() : $action;
121
		$lifetime = (int) wp_verify_nonce( $token, $action );
122
123
		return ( $lifetime > 0 && $lifetime <= $this->maximum_lifetime );
124
	}
125
126
	/**
127
	 * Add the token to a URL.
128
	 *
129
	 * @param  string     $url
130
	 * @param  int|string $action
131
	 * @return string
132
	 */
133
	public function url( $url, $action = -1 ) {
134
		return add_query_arg( $this->key, $this->getToken( $action ), $url );
135
	}
136
137
	/**
138
	 * Return the markup for a hidden input which holds the current token.
139
	 *
140
	 * @param  int|string $action
141
	 * @return void
142
	 */
143
	public function field( $action = -1 ) {
144
		echo sprintf(
145
			'<input type="hidden" name="%1$s" value="%2$s" />',
146
			esc_attr( $this->key ),
147
			esc_attr( $this->getToken( $action ) )
148
		);
149
	}
150
}
151