Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 113 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
CreateOAuthConsumer | |
0.00% |
0 / 107 |
|
0.00% |
0 / 2 |
240 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 68 |
|
0.00% |
0 / 1 |
210 |
1 | <?php |
2 | /** |
3 | * Example: |
4 | * |
5 | * createOAuthConsumer.php |
6 | * --callbackIsPrefix |
7 | * --callbackUrl="https://foourl" |
8 | * --description="Application description" |
9 | * --grants="editprotected" |
10 | * --grants="createaccount" |
11 | * --name="Application name" |
12 | * --user="Admin" |
13 | * --version="0.2" |
14 | * --wiki=default |
15 | * --approve |
16 | * |
17 | * You can optionally output successful results as json using --jsonOnSuccess |
18 | */ |
19 | |
20 | namespace MediaWiki\Extension\OAuth; |
21 | |
22 | use MediaWiki\Context\RequestContext; |
23 | use MediaWiki\Extension\OAuth\Backend\Consumer; |
24 | use MediaWiki\Extension\OAuth\Backend\Utils; |
25 | use MediaWiki\Extension\OAuth\Control\ConsumerSubmitControl; |
26 | use MediaWiki\Maintenance\Maintenance; |
27 | use MediaWiki\User\User; |
28 | use MWRestrictions; |
29 | |
30 | /** |
31 | * @ingroup Maintenance |
32 | */ |
33 | |
34 | if ( getenv( 'MW_INSTALL_PATH' ) ) { |
35 | $IP = getenv( 'MW_INSTALL_PATH' ); |
36 | } else { |
37 | $IP = __DIR__ . '/../../..'; |
38 | } |
39 | |
40 | require_once "$IP/maintenance/Maintenance.php"; |
41 | |
42 | class CreateOAuthConsumer extends Maintenance { |
43 | public function __construct() { |
44 | parent::__construct(); |
45 | $this->addDescription( "Create an OAuth consumer" ); |
46 | $this->addOption( |
47 | 'oauthVersion', |
48 | 'OAuth version (' . Consumer::OAUTH_VERSION_1 . ' or ' . Consumer::OAUTH_VERSION_2 . |
49 | ', default ' . Consumer::OAUTH_VERSION_1 . ')', |
50 | false, |
51 | true |
52 | ); |
53 | $this->addOption( 'user', 'User to run the script as', true, true ); |
54 | $this->addOption( 'name', 'Application name', true, true ); |
55 | $this->addOption( 'description', 'Application description', true, true ); |
56 | $this->addOption( 'version', 'Application version', true, true ); |
57 | $this->addOption( 'callbackUrl', 'Callback URL', true, true ); |
58 | $this->addOption( |
59 | 'callbackIsPrefix', |
60 | 'Allow a consumer to specify a callback in requests (OAuth 1 only)' |
61 | ); |
62 | $this->addOption( 'grants', 'Grants', true, true, false, true ); |
63 | $this->addOption( 'jsonOnSuccess', 'Output successful results as JSON' ); |
64 | $this->addOption( 'approve', 'Accept the consumer' ); |
65 | $this->addOption( |
66 | 'ownerOnly', |
67 | 'Make the consumer only usable by the given user; see ' . |
68 | 'https://www.mediawiki.org/wiki/OAuth/Owner-only_consumers.' |
69 | ); |
70 | $this->addOption( |
71 | 'oauth2IsNotConfidential', |
72 | 'Mark the client as *not* confidential (OAuth 2 only). By default, clients are confidential.' |
73 | ); |
74 | $this->addOption( |
75 | 'oauth2GrantTypes', |
76 | 'The OAuth 2 grant types: authorization_code, refresh_token, and/or client_credentials.', |
77 | false, |
78 | true, |
79 | false, |
80 | true |
81 | ); |
82 | $this->requireExtension( "OAuth" ); |
83 | } |
84 | |
85 | public function execute() { |
86 | $user = User::newFromName( $this->getOption( 'user' ) ); |
87 | if ( !$user->isNamed() ) { |
88 | $this->fatalError( 'User must be registered' ); |
89 | } |
90 | if ( $user->getEmail() === '' ) { |
91 | $this->fatalError( 'User must have an email' ); |
92 | } |
93 | $oauthVersion = (int)$this->getOption( 'oauthVersion', Consumer::OAUTH_VERSION_1 ); |
94 | if ( !in_array( $oauthVersion, [ Consumer::OAUTH_VERSION_1, Consumer::OAUTH_VERSION_2 ], true ) ) { |
95 | $this->fatalError( |
96 | 'Invalid oauthVersion, must be ' . Consumer::OAUTH_VERSION_1 . |
97 | ' or ' . Consumer::OAUTH_VERSION_2 . '!' |
98 | ); |
99 | } |
100 | if ( $oauthVersion === Consumer::OAUTH_VERSION_2 ) { |
101 | if ( $this->hasOption( 'callbackIsPrefix' ) ) { |
102 | $this->fatalError( 'callbackIsPrefix is only available in oauthVersion 1' ); |
103 | } |
104 | } else { |
105 | if ( $this->hasOption( 'oauth2IsNotConfidential' ) ) { |
106 | $this->fatalError( 'oauth2IsNotConfidential is only available in oauthVersion 2' ); |
107 | } |
108 | if ( $this->hasOption( 'oauth2GrantTypes' ) ) { |
109 | $this->fatalError( 'oauth2GrantTypes is only available in oauthVersion 2' ); |
110 | } |
111 | } |
112 | |
113 | $data = [ |
114 | 'action' => 'propose', |
115 | 'name' => $this->getOption( 'name' ), |
116 | 'version' => $this->getOption( 'version' ), |
117 | 'description' => $this->getOption( 'description' ), |
118 | 'callbackUrl' => $this->getOption( 'callbackUrl' ), |
119 | 'oauthVersion' => $oauthVersion, |
120 | 'callbackIsPrefix' => $this->hasOption( 'callbackIsPrefix' ), |
121 | 'grants' => '["' . implode( '","', $this->getOption( 'grants' ) ) . '"]', |
122 | 'granttype' => 'normal', |
123 | 'ownerOnly' => $this->hasOption( 'ownerOnly' ), |
124 | 'oauth2IsConfidential' => !$this->hasOption( 'oauth2IsNotConfidential' ), |
125 | 'oauth2GrantTypes' => $this->getOption( 'oauth2GrantTypes', [ 'authorization_code', 'refresh_token' ] ), |
126 | 'email' => $user->getEmail(), |
127 | // All wikis |
128 | 'wiki' => '*', |
129 | // Generate a key |
130 | 'rsaKey' => '', |
131 | 'agreement' => true, |
132 | 'restrictions' => MWRestrictions::newDefault(), |
133 | ]; |
134 | |
135 | $context = RequestContext::getMain(); |
136 | $context->setUser( $user ); |
137 | |
138 | $dbw = Utils::getCentralDB( DB_PRIMARY ); |
139 | $control = new ConsumerSubmitControl( $context, $data, $dbw ); |
140 | $status = $control->submit(); |
141 | |
142 | if ( !$status->isGood() ) { |
143 | $this->fatalError( $status->getMessage()->text() ); |
144 | } |
145 | |
146 | /** @var Consumer $cmr */ |
147 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
148 | $cmr = $status->value['result']['consumer']; |
149 | |
150 | if ( $this->hasOption( 'approve' ) ) { |
151 | $data = [ |
152 | 'action' => 'approve', |
153 | 'consumerKey' => $cmr->getConsumerKey(), |
154 | 'reason' => 'Approved by maintenance script', |
155 | 'changeToken' => $cmr->getChangeToken( $context ), |
156 | ]; |
157 | $control = new ConsumerSubmitControl( $context, $data, $dbw ); |
158 | $approveStatus = $control->submit(); |
159 | } |
160 | |
161 | $outputData = [ |
162 | 'created' => true, |
163 | 'id' => $cmr->getId(), |
164 | 'name' => $cmr->getName(), |
165 | 'key' => $cmr->getConsumerKey(), |
166 | 'secret' => Utils::hmacDBSecret( $cmr->getSecretKey() ), |
167 | ]; |
168 | |
169 | if ( isset( $approveStatus ) ) { |
170 | $outputData['approved'] = $approveStatus->isGood() ? |
171 | 1 : $approveStatus->getWikiText( false, false, 'en' ); |
172 | } |
173 | |
174 | if ( $this->hasOption( 'jsonOnSuccess' ) ) { |
175 | $this->output( json_encode( $outputData ) ); |
176 | } else { |
177 | foreach ( $outputData as $key => $value ) { |
178 | $this->output( $key . ': ' . $value . PHP_EOL ); |
179 | } |
180 | } |
181 | } |
182 | } |
183 | |
184 | $maintClass = CreateOAuthConsumer::class; |
185 | require_once RUN_MAINTENANCE_IF_MAIN; |