Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.90% |
90 / 91 |
|
83.33% |
5 / 6 |
CRAP | |
0.00% |
0 / 1 |
ListClients | |
98.90% |
90 / 91 |
|
83.33% |
5 / 6 |
13 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
needsWriteAccess | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
run | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
getParamSettings | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
1 | |||
getDbResults | |
100.00% |
27 / 27 |
|
100.00% |
1 / 1 |
2 | |||
processDbResults | |
96.97% |
32 / 33 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\OAuth\Rest\Handler; |
4 | |
5 | use MediaWiki\Extension\OAuth\Backend\Consumer; |
6 | use MediaWiki\Extension\OAuth\Backend\Utils; |
7 | use MediaWiki\Extension\OAuth\Control\ConsumerAccessControl; |
8 | use MediaWiki\Rest\LocalizedHttpException; |
9 | use MediaWiki\Rest\ResponseInterface; |
10 | use MediaWiki\Rest\SimpleHandler; |
11 | use RequestContext; |
12 | use Wikimedia\Message\MessageValue; |
13 | use Wikimedia\ParamValidator\ParamValidator; |
14 | use Wikimedia\Rdbms\ILoadBalancer; |
15 | use Wikimedia\Rdbms\IResultWrapper; |
16 | use Wikimedia\Rdbms\SelectQueryBuilder; |
17 | |
18 | /** |
19 | * Handles the oauth2/consumers endpoint, which returns |
20 | * a list of registered consumers for the user |
21 | */ |
22 | class ListClients extends SimpleHandler { |
23 | |
24 | /** @var string[] */ |
25 | protected $propertyMapping = [ |
26 | 'id' => 'oarc_id', |
27 | 'client_key' => 'oarc_consumer_key', |
28 | 'name' => 'oarc_name', |
29 | 'version' => 'oarc_version', |
30 | 'email' => 'oarc_email', |
31 | 'callback_url' => 'oarc_callback_url', |
32 | 'scopes' => 'oarc_grants', |
33 | 'registration' => 'oarc_registration', |
34 | 'stage' => 'oarc_stage', |
35 | 'oauth_version' => 'oarc_oauth_version', |
36 | 'description' => 'oarc_description', |
37 | 'allowed_grants' => 'oarc_oauth2_allowed_grants', |
38 | 'restrictions' => 'oarc_restrictions', |
39 | 'user_id' => 'oarc_user_id', |
40 | 'callback_is_prefix' => 'oarc_callback_is_prefix', |
41 | 'email_authenticated' => 'oarc_email_authenticated', |
42 | 'developer_agreement' => 'oarc_developer_agreement', |
43 | 'owner_only' => 'oarc_owner_only', |
44 | 'wiki' => 'oarc_wiki', |
45 | 'secret_key' => 'oarc_secret_key', |
46 | 'rsa_key' => 'oarc_rsa_key', |
47 | 'stage_timestamp' => 'oarc_stage_timestamp', |
48 | 'deleted' => 'oarc_deleted', |
49 | 'oauth2_is_confidential' => 'oarc_oauth2_is_confidential', |
50 | ]; |
51 | |
52 | /** |
53 | * |
54 | * @var ILoadBalancer |
55 | */ |
56 | private $loadBalancer; |
57 | |
58 | /** |
59 | * @param ILoadBalancer $loadBalancer |
60 | */ |
61 | public function __construct( ILoadBalancer $loadBalancer ) { |
62 | $this->loadBalancer = $loadBalancer; |
63 | } |
64 | |
65 | /** |
66 | * @return bool |
67 | */ |
68 | public function needsWriteAccess() { |
69 | return false; |
70 | } |
71 | |
72 | /** |
73 | * @return ResponseInterface |
74 | * @throws LocalizedHttpException |
75 | */ |
76 | public function run(): ResponseInterface { |
77 | // @todo Inject this, when there is a good way to do that, see T239753 |
78 | $user = RequestContext::getMain()->getUser(); |
79 | |
80 | $centralId = Utils::getCentralIdFromUserName( $user->getName() ); |
81 | $responseFactory = $this->getResponseFactory(); |
82 | |
83 | if ( !$centralId ) { |
84 | throw new LocalizedHttpException( |
85 | new MessageValue( 'rest-nonexistent-user', [ $user->getName() ] ), 404 |
86 | ); |
87 | } |
88 | $response = $this->getDbResults( $centralId ); |
89 | |
90 | return $responseFactory->createJson( $response ); |
91 | } |
92 | |
93 | /** @inheritDoc */ |
94 | public function getParamSettings() { |
95 | return [ |
96 | 'limit' => [ |
97 | self::PARAM_SOURCE => 'query', |
98 | ParamValidator::PARAM_TYPE => 'integer', |
99 | ParamValidator::PARAM_REQUIRED => false, |
100 | ParamValidator::PARAM_DEFAULT => 25 |
101 | ], |
102 | 'offset' => [ |
103 | self::PARAM_SOURCE => 'query', |
104 | ParamValidator::PARAM_TYPE => 'integer', |
105 | ParamValidator::PARAM_REQUIRED => false, |
106 | ParamValidator::PARAM_DEFAULT => 0 |
107 | ], |
108 | 'oauth_version' => [ |
109 | self::PARAM_SOURCE => 'query', |
110 | ParamValidator::PARAM_TYPE => [ '1', '2' ], |
111 | ParamValidator::PARAM_REQUIRED => false, |
112 | ParamValidator::PARAM_DEFAULT => '2' |
113 | ] |
114 | ]; |
115 | } |
116 | |
117 | /** |
118 | * @param int $centralId the user id of calling user |
119 | * @return array the results |
120 | */ |
121 | private function getDbResults( int $centralId ) { |
122 | $dbr = $this->loadBalancer->getConnection( DB_REPLICA ); |
123 | |
124 | $params = $this->getValidatedParams(); |
125 | $limit = $params['limit']; |
126 | $offset = $params['offset']; |
127 | |
128 | $oauthVersion = $params['oauth_version']; |
129 | $conds = [ 'oarc_user_id' => $centralId ]; |
130 | if ( $oauthVersion !== null ) { |
131 | $conds['oarc_oauth_version'] = (int)$oauthVersion; |
132 | } |
133 | |
134 | $res = $dbr->newSelectQueryBuilder() |
135 | ->select( array_values( $this->propertyMapping ) ) |
136 | ->from( 'oauth_registered_consumer' ) |
137 | ->where( $conds ) |
138 | ->orderBy( 'oarc_id', SelectQueryBuilder::SORT_DESC ) |
139 | ->limit( $limit ) |
140 | ->offset( $offset ) |
141 | ->caller( __METHOD__ ) |
142 | ->fetchResultSet(); |
143 | |
144 | $total = $dbr->newSelectQueryBuilder() |
145 | ->select( 'oarc_consumer_key' ) |
146 | ->from( 'oauth_registered_consumer' ) |
147 | ->where( $conds ) |
148 | ->caller( __METHOD__ ) |
149 | ->fetchRowCount(); |
150 | |
151 | return [ |
152 | 'clients' => $this->processDbResults( $res ), |
153 | 'total' => $total |
154 | ]; |
155 | } |
156 | |
157 | /** |
158 | * @param IResultWrapper $res database results, or an empty array if none |
159 | * @return array consumer data |
160 | */ |
161 | private function processDbResults( $res ) { |
162 | $consumers = []; |
163 | $requestContext = RequestContext::getMain(); |
164 | $user = $requestContext->getUser(); |
165 | |
166 | foreach ( $res as $row ) { |
167 | |
168 | $consumer = []; |
169 | |
170 | $cmrAc = ConsumerAccessControl::wrap( |
171 | Consumer::newFromRow( Utils::getCentralDB( DB_REPLICA ), $row ), |
172 | $requestContext |
173 | ); |
174 | |
175 | if ( !$cmrAc ) { |
176 | continue; |
177 | } |
178 | |
179 | $consumer['email'] = $cmrAc->getEmail(); |
180 | $consumer['name'] = $cmrAc->getName(); |
181 | $consumer['version'] = $cmrAc->getVersion(); |
182 | $consumer['callback_url'] = $cmrAc->getCallbackUrl(); |
183 | $consumer['description'] = $cmrAc->getDescription(); |
184 | $consumer['client_key'] = $cmrAc->getConsumerKey(); |
185 | $consumer['owner_only'] = $cmrAc->getOwnerOnly(); |
186 | |
187 | $consumer['stage'] = (int)$cmrAc->getStage(); |
188 | $consumer['oauth_version'] = $cmrAc->getOAuthVersion(); |
189 | $consumer['registration_formatted'] = $requestContext->getLanguage()->userTimeAndDate( |
190 | $cmrAc->getRegistration(), |
191 | $user |
192 | ); |
193 | |
194 | if ( $consumer['oauth_version'] === Consumer::OAUTH_VERSION_2 ) { |
195 | $consumer['allowed_grants'] = $cmrAc->get( 'oauth2GrantTypes' ); |
196 | } |
197 | |
198 | $consumer['scopes'] = $cmrAc->getGrants(); |
199 | $consumer['restrictions'] = $cmrAc->getRestrictions(); |
200 | |
201 | foreach ( $consumer as $key => $value ) { |
202 | if ( is_object( $consumer[$key] ) ) { |
203 | unset( $consumer[$key] ); |
204 | } |
205 | } |
206 | |
207 | $consumers[] = $consumer; |
208 | } |
209 | |
210 | return $consumers; |
211 | } |
212 | } |