Completed
Push — main ( 26c7b4...5ab5c5 )
by
unknown
04:18
created

MediawikiSession   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 151
c 0
b 0
f 0
wmc 22
lcom 1
cbo 4
rs 10
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
	private array $tokens = [];
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_ARRAY, expecting T_FUNCTION or T_CONST
Loading history...
18
19
	private MediawikiApi $api;
20
21
	/**
22
	 * @var bool if this session is running against mediawiki version pre 1.25
23
	 */
24
	private bool $usePre125TokensModule = false;
25
26
	private LoggerInterface $logger;
27
28
	/**
29
	 * @param MediawikiApi $api The API object to use for this session.
30
	 */
31
	public function __construct( MediawikiApi $api ) {
32
		$this->api = $api;
33
		$this->logger = new NullLogger();
34
	}
35
36
	/**
37
	 * Sets a logger instance on the object
38
	 *
39
	 * @since 1.1
40
	 *
41
	 * @param LoggerInterface $logger The new Logger object.
42
	 *
43
	 * @return null
44
	 */
45
	public function setLogger( LoggerInterface $logger ) {
46
		$this->logger = $logger;
47
	}
48
49
	/**
50
	 * Tries to get the specified token from the API
51
	 *
52
	 * @since 0.1
53
	 *
54
	 * @param string $type The type of token to get.
55
	 */
56
	public function getToken( string $type = 'csrf' ): string {
57
		// If we don't already have the token that we want
58
		if ( !array_key_exists( $type, $this->tokens ) ) {
59
			$this->logger->log( LogLevel::DEBUG, 'Getting fresh token', [ 'type' => $type ] );
60
61
			// If we know that we don't have the new module mw<1.25
62
			if ( $this->usePre125TokensModule ) {
63
				return $this->reallyGetPre125Token( $type );
64
			} else {
65
				return $this->reallyGetToken( $type );
66
			}
67
68
		}
69
70
		return $this->tokens[$type];
71
	}
72
73
	private function reallyGetPre125Token( $type ) {
74
		// Suppress deprecation warning
75
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
76
			new SimpleRequest( 'tokens', [ 'type' => $this->getOldTokenType( $type ) ] )
77
		);
78
		$this->tokens[$type] = array_pop( $result['tokens'] );
79
80
		return $this->tokens[$type];
81
	}
82
83
	private function reallyGetToken( $type ) {
84
		// We suppress errors on this call so the user doesn't get get a warning that isn't their fault.
85
		$result = @$this->api->postRequest( // @codingStandardsIgnoreLine
86
			new SimpleRequest( 'query', [
87
				'meta' => 'tokens',
88
				'type' => $this->getNewTokenType( $type ),
89
				'continue' => '',
90
			] )
91
		);
92
		// If mw<1.25 (no new module)
93
		$metaWarning = "Unrecognized value for parameter 'meta': tokens";
94
		if ( isset( $result['warnings']['query']['*'] )
95
			&& strpos( $result['warnings']['query']['*'], $metaWarning ) !== false ) {
96
			$this->usePre125TokensModule = true;
97
			$this->logger->log( LogLevel::DEBUG, 'Falling back to pre 1.25 token system' );
98
			$this->tokens[$type] = $this->reallyGetPre125Token( $type );
99
		} else {
100
			$this->tokens[$type] = array_pop( $result['query']['tokens'] );
101
		}
102
103
		return $this->tokens[$type];
104
	}
105
106
	/**
107
	 * Tries to guess a new token type from an old token type
108
	 *
109
	 *
110
	 * @return void|string
111
	 */
112
	private function getNewTokenType( string $type ) {
113
		switch ( $type ) {
114
			case 'edit':
115
			case 'delete':
116
			case 'protect':
117
			case 'move':
118
			case 'block':
119
			case 'unblock':
120
			case 'email':
121
			case 'import':
122
			case 'options':
123
				return 'csrf';
124
		}
125
		// Return the same type, don't know what to do with this..
126
		return $type;
127
	}
128
129
	/**
130
	 * Tries to guess an old token type from a new token type
131
	 *
132
	 *
133
	 */
134
	private function getOldTokenType( string $type ): string {
135
		if ( $type === 'csrf' ) {
136
			return 'edit';
137
		}
138
		return $type;
139
	}
140
141
	/**
142
	 * Clears all tokens stored by the api
143
	 *
144
	 * @since 0.2
145
	 */
146
	public function clearTokens(): void {
147
		$this->logger->log( LogLevel::DEBUG, 'Clearing session tokens', [ 'tokens' => $this->tokens ] );
148
		$this->tokens = [];
149
	}
150
151
}
152