MediawikiSession::reallyGetToken()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 14
cts 14
cp 1
rs 9.568
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
namespace Mediawiki\Api;
4
5
use Psr\Log\LoggerAwareInterface;
6
use Psr\Log\LoggerInterface;
7
use Psr\Log\LogLevel;
8
use Psr\Log\NullLogger;
9
10
/**
11
 * @since 0.1
12
 *
13
 * @author Addshore
14
 */
15
class MediawikiSession implements LoggerAwareInterface {
16
17
	/**
18
	 * @var array
19
	 */
20
	private $tokens = [];
21
22
	/**
23
	 * @var MediawikiApi
24
	 */
25
	private $api;
26
27
	/**
28
	 * @var bool if this session is running against mediawiki version pre 1.25
29
	 */
30
	private $usePre125TokensModule = false;
31
32
	/**
33
	 * @var LoggerInterface
34
	 */
35
	private $logger;
36
37
	/**
38
	 * @param MediawikiApi $api The API object to use for this session.
39
	 */
40 5
	public function __construct( MediawikiApi $api ) {
41 5
		$this->api = $api;
42 5
		$this->logger = new NullLogger();
43 5
	}
44
45
	/**
46
	 * Sets a logger instance on the object
47
	 *
48
	 * @since 1.1
49
	 *
50
	 * @param LoggerInterface $logger The new Logger object.
51
	 *
52
	 * @return null
53
	 */
54
	public function setLogger( LoggerInterface $logger ) {
55
		$this->logger = $logger;
56
	}
57
58
	/**
59
	 * Tries to get the specified token from the API
60
	 *
61
	 * @since 0.1
62
	 *
63
	 * @param string $type The type of token to get.
64
	 *
65
	 * @return string
66
	 */
67 6
	public function getToken( $type = 'csrf' ) {
68
		// If we don't already have the token that we want
69 6
		if ( !array_key_exists( $type, $this->tokens ) ) {
70 6
			$this->logger->log( LogLevel::DEBUG, 'Getting fresh token', [ 'type' => $type ] );
71
72
			// If we know that we don't have the new module mw<1.25
73 6
			if ( $this->usePre125TokensModule ) {
74
				return $this->reallyGetPre125Token( $type );
75
			} else {
76 6
				return $this->reallyGetToken( $type );
77
			}
78
79
		}
80
81 4
		return $this->tokens[$type];
82
	}
83
84 2
	private function reallyGetPre125Token( $type ) {
85
		// Suppress deprecation warning
86 2
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
87 2
			new SimpleRequest( 'tokens', [ 'type' => $this->getOldTokenType( $type ) ] )
88
		);
89 2
		$this->tokens[$type] = array_pop( $result['tokens'] );
90
91 2
		return $this->tokens[$type];
92
	}
93
94 4
	private function reallyGetToken( $type ) {
95
		// We suppress errors on this call so the user doesn't get get a warning that isn't their fault.
96 4
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
97 4
			new SimpleRequest( 'query', [
98 4
				'meta' => 'tokens',
99 4
				'type' => $this->getNewTokenType( $type ),
100 4
				'continue' => '',
101
			] )
102
		);
103
		// If mw<1.25 (no new module)
104 4
		$metaWarning = "Unrecognized value for parameter 'meta': tokens";
105 4
		if ( isset( $result['warnings']['query']['*'] )
106 4
			&& strpos( $result['warnings']['query']['*'], $metaWarning ) !== false ) {
107 2
			$this->usePre125TokensModule = true;
108 2
			$this->logger->log( LogLevel::DEBUG, 'Falling back to pre 1.25 token system' );
109 2
			$this->tokens[$type] = $this->reallyGetPre125Token( $type );
110
		} else {
111 2
			$this->tokens[$type] = array_pop( $result['query']['tokens'] );
112
		}
113
114 4
		return $this->tokens[$type];
115
	}
116
117
	/**
118
	 * Tries to guess a new token type from an old token type
119
	 *
120
	 * @param string $type
121
	 *
122
	 * @return string
123
	 */
124 4
	private function getNewTokenType( $type ) {
125
		switch ( $type ) {
126 4
			case 'edit':
127 4
			case 'delete':
128 4
			case 'protect':
129 4
			case 'move':
130 4
			case 'block':
131 4
			case 'unblock':
132 4
			case 'email':
133 4
			case 'import':
134 4
			case 'options':
135
				return 'csrf';
136
		}
137
		// Return the same type, don't know what to do with this..
138 4
		return $type;
139
	}
140
141
	/**
142
	 * Tries to guess an old token type from a new token type
143
	 *
144
	 * @param string $type
145
	 *
146
	 * @return string
147
	 */
148 2
	private function getOldTokenType( $type ) {
149
		switch ( $type ) {
150
			// Guess that we want an edit token, this may not always work as we might be trying to
151
			// use it for something else...
152 2
			case 'csrf':
153 2
				return 'edit';
154
		}
155
		return $type;
156
	}
157
158
	/**
159
	 * Clears all tokens stored by the api
160
	 *
161
	 * @since 0.2
162
	 */
163 2
	public function clearTokens() {
164 2
		$this->logger->log( LogLevel::DEBUG, 'Clearing session tokens', [ 'tokens' => $this->tokens ] );
165 2
		$this->tokens = [];
166 2
	}
167
168
}
169