Failed Conditions
Push — master ( 40bf1c...d6ae0e )
by Atanas
01:33
created

src/Csrf/Csrf.php (3 issues)

1
<?php
2
/**
3
 * @package   WPEmerge
4
 * @author    Atanas Angelov <[email protected]>
5
 * @copyright 2018 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 token.
42
	 *
43
	 * @var string
44
	 */
45
	protected $token = '';
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
	 * @return string
63
	 */
64
	public function getToken() {
65
		if ( ! $this->token ) {
66
			$this->generateToken();
67
		}
68
		return $this->token;
69
	}
70
71
	/**
72
	 * Get the csrf token from a request.
73
	 *
74
	 * @param  RequestInterface $request
75
	 * @return string
76
	 */
77
	public function getTokenFromRequest( RequestInterface $request ) {
78
		if ( $request->get( $this->key ) ) {
0 ignored issues
show
The call to WPEmerge\Requests\RequestInterface::get() has too many arguments starting with $this->key. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
		if ( $request->/** @scrutinizer ignore-call */ get( $this->key ) ) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
79
			return $request->get( $this->key );
80
		}
81
82
		if ( $request->post( $this->key ) ) {
0 ignored issues
show
The call to WPEmerge\Requests\RequestInterface::post() has too many arguments starting with $this->key. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
		if ( $request->/** @scrutinizer ignore-call */ post( $this->key ) ) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
83
			return $request->post( $this->key );
84
		}
85
86
		if ( $request->headers( $this->header ) ) {
0 ignored issues
show
The call to WPEmerge\Requests\RequestInterface::headers() has too many arguments starting with $this->header. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
		if ( $request->/** @scrutinizer ignore-call */ headers( $this->header ) ) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
87
			return $request->headers( $this->header );
88
		}
89
90
		return '';
91
	}
92
93
	/**
94
	 * Generate a new token.
95
	 *
96
	 * @param  int|string $action
97
	 * @return string
98
	 */
99
	public function generateToken( $action = -1 ) {
100
		$action = $action === -1 ? session_id() : $action;
101
		$this->token = wp_create_nonce( $action );
102
		return $this->getToken();
103
	}
104
105
	/**
106
	 * Check if a token is valid.
107
	 *
108
	 * @param  string     $token
109
	 * @param  int|string $action
110
	 * @return boolean
111
	 */
112
	public function isValidToken( $token, $action = -1 ) {
113
		$action = $action === -1 ? session_id() : $action;
114
		$lifetime = (int) wp_verify_nonce( $token, $action );
115
		return ( $lifetime > 0 && $lifetime <= $this->maximum_lifetime );
116
	}
117
118
	/**
119
	 * Add the token to a URL.
120
	 *
121
	 * @param  string $url
122
	 * @return string
123
	 */
124
	public function url( $url ) {
125
		return add_query_arg( $this->key, $this->getToken(), $url );
126
	}
127
128
	/**
129
	 * Return the markup for a hidden input which holds the current token.
130
	 *
131
	 * @return void
132
	 */
133
	public function field() {
134
		echo sprintf(
135
			'<input type="hidden" name="%1$s" value="%2$s" />',
136
			esc_attr( $this->key ),
137
			esc_attr( $this->getToken() )
138
		);
139
	}
140
}
141