Completed
Push — master ( fea716...246f0f )
by adam
04:02
created

MediawikiSession::getToken()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 17
c 2
b 0
f 0
ccs 6
cts 7
cp 0.8571
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3.0261
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
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
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
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
71 6
			$this->logger->log( LogLevel::DEBUG, 'Getting fresh token', [ 'type' => $type ] );
72
73
			// If we know that we don't have the new module mw<1.25
74 6
			if ( $this->usePre125TokensModule ) {
75
				return $this->reallyGetPre125Token( $type );
76
			} else {
77 6
				return $this->reallyGetToken( $type );
78
			}
79
80
		}
81
82 4
		return $this->tokens[$type];
83
	}
84
85 2
	private function reallyGetPre125Token( $type ) {
86
		// Suppress deprecation warning
87 2
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
88 2
			new SimpleRequest( 'tokens', [ 'type' => $this->getOldTokenType( $type ) ] )
89 2
		);
90 2
		$this->tokens[$type] = array_pop( $result['tokens'] );
91
92 2
		return $this->tokens[$type];
93
	}
94
95 4
	private function reallyGetToken( $type ) {
96
		// We suppress errors on this call so the user doesn't get get a warning that isn't their fault.
97 4
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
98 4
			new SimpleRequest( 'query', [
99 4
				'meta' => 'tokens',
100 4
				'type' => $this->getNewTokenType( $type ),
101 4
				'continue' => '',
102 4
			] )
103 4
		);
104
		// If mw<1.25 (no new module)
105 4
		$metaWarning = "Unrecognized value for parameter 'meta': tokens";
106 4
		if ( isset( $result['warnings']['query']['*'] )
107 4
			&& false !== strpos( $result['warnings']['query']['*'], $metaWarning ) ) {
108 2
			$this->usePre125TokensModule = true;
109 2
			$this->logger->log( LogLevel::DEBUG, 'Falling back to pre 1.25 token system' );
110 2
			$this->tokens[$type] = $this->reallyGetPre125Token( $type );
111 2
		} else {
112 2
			$this->tokens[$type] = array_pop( $result['query']['tokens'] );
113
		}
114
115 4
		return $this->tokens[$type];
116
	}
117
118
	/**
119
	 * Tries to guess a new token type from an old token type
120
	 *
121
	 * @param string $type
122
	 *
123
	 * @return string
124
	 */
125 4
	private function getNewTokenType( $type ) {
126
		switch ( $type ) {
127 4
			case 'edit':
128 4
			case 'delete':
129 4
			case 'protect':
130 4
			case 'move':
131 4
			case 'block':
132 4
			case 'unblock':
133 4
			case 'email':
134 4
			case 'import':
135 4
			case 'options':
136
				return 'csrf';
137
		}
138
		// Return the same type, don't know what to do with this..
139 4
		return $type;
140
	}
141
142
	/**
143
	 * Tries to guess an old token type from a new token type
144
	 *
145
	 * @param $type
146
	 *
147
	 * @return string
148
	 */
149 2
	private function getOldTokenType( $type ) {
150
		switch ( $type ) {
151
			// Guess that we want an edit token, this may not always work as we might be trying to
152
			// use it for something else...
153 2
			case 'csrf':
154 2
				return 'edit';
155
		}
156
		return $type;
157
	}
158
159
	/**
160
	 * Clears all tokens stored by the api
161
	 *
162
	 * @since 0.2
163
	 */
164 2
	public function clearTokens() {
165 2
		$this->logger->log( LogLevel::DEBUG, 'Clearing session tokens', [ 'tokens' => $this->tokens ] );
166 2
		$this->tokens = [];
167 2
	}
168
169
}
170