Completed
Push — main ( d84a15...26c7b4 )
by
unknown
04:34
created

MediawikiSession::setLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Addwiki\Mediawiki\Api\Client;
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
	public function __construct( MediawikiApi $api ) {
41
		$this->api = $api;
42
		$this->logger = new NullLogger();
43
	}
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
	public function getToken( $type = 'csrf' ) {
68
		// If we don't already have the token that we want
69
		if ( !array_key_exists( $type, $this->tokens ) ) {
70
			$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
			if ( $this->usePre125TokensModule ) {
74
				return $this->reallyGetPre125Token( $type );
75
			} else {
76
				return $this->reallyGetToken( $type );
77
			}
78
79
		}
80
81
		return $this->tokens[$type];
82
	}
83
84
	private function reallyGetPre125Token( $type ) {
85
		// Suppress deprecation warning
86
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
87
			new SimpleRequest( 'tokens', [ 'type' => $this->getOldTokenType( $type ) ] )
88
		);
89
		$this->tokens[$type] = array_pop( $result['tokens'] );
90
91
		return $this->tokens[$type];
92
	}
93
94
	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
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
97
			new SimpleRequest( 'query', [
98
				'meta' => 'tokens',
99
				'type' => $this->getNewTokenType( $type ),
100
				'continue' => '',
101
			] )
102
		);
103
		// If mw<1.25 (no new module)
104
		$metaWarning = "Unrecognized value for parameter 'meta': tokens";
105
		if ( isset( $result['warnings']['query']['*'] )
106
			&& strpos( $result['warnings']['query']['*'], $metaWarning ) !== false ) {
107
			$this->usePre125TokensModule = true;
108
			$this->logger->log( LogLevel::DEBUG, 'Falling back to pre 1.25 token system' );
109
			$this->tokens[$type] = $this->reallyGetPre125Token( $type );
110
		} else {
111
			$this->tokens[$type] = array_pop( $result['query']['tokens'] );
112
		}
113
114
		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
	private function getNewTokenType( $type ) {
125
		switch ( $type ) {
126
			case 'edit':
127
			case 'delete':
128
			case 'protect':
129
			case 'move':
130
			case 'block':
131
			case 'unblock':
132
			case 'email':
133
			case 'import':
134
			case 'options':
135
				return 'csrf';
136
		}
137
		// Return the same type, don't know what to do with this..
138
		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
	private function getOldTokenType( $type ) {
149
		if ( $type === 'csrf' ) {
150
			return 'edit';
151
		}
152
		return $type;
153
	}
154
155
	/**
156
	 * Clears all tokens stored by the api
157
	 *
158
	 * @since 0.2
159
	 */
160
	public function clearTokens() {
161
		$this->logger->log( LogLevel::DEBUG, 'Clearing session tokens', [ 'tokens' => $this->tokens ] );
162
		$this->tokens = [];
163
	}
164
165
}
166