jenkins-bot has submitted this change and it was merged.

Change subject: Add owner-only consumers
......................................................................


Add owner-only consumers

An owner-only consumer is automatically approved, automatically
accepted by the owner, cannot be used by anyone other than the owner,
cannot use the usual authorization flow, and does not tag changes.

Bug: T87395
Bug: T121113
Change-Id: I3c791b949e19eb476968e5f9dd1511d485e52810
---
M api/MWOAuthAPI.setup.php
M backend/MWOAuthConsumer.php
M backend/MWOAuthServer.php
M backend/schema/MWOAuthUpdater.hooks.php
M backend/schema/mysql/OAuth.sql
A backend/schema/mysql/owner_only.sql
M backend/schema/sqlite/OAuth.sql
A backend/schema/sqlite/owner_only.sql
M control/MWOAuthConsumerAcceptanceSubmitControl.php
M control/MWOAuthConsumerSubmitControl.php
M frontend/specialpages/SpecialMWOAuth.php
M frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
M frontend/specialpages/SpecialMWOAuthManageConsumers.php
M i18n/en.json
M i18n/qqq.json
15 files changed, 205 insertions(+), 50 deletions(-)

Approvals:
  CSteipp: Looks good to me, but someone else must approve
  Gergő Tisza: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/api/MWOAuthAPI.setup.php b/api/MWOAuthAPI.setup.php
index b2d80e8..02c2b72 100755
--- a/api/MWOAuthAPI.setup.php
+++ b/api/MWOAuthAPI.setup.php
@@ -115,9 +115,7 @@
 
                                // The consumer is approved or owned by 
$localUser, and is for this wiki.
                                $consumer = MWOAuthConsumer::newFromId( $dbr, 
$access->get( 'consumerId' ) );
-                               if ( $consumer->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
-                                       && !$consumer->isPendingAndOwnedBy( 
$localUser ) // let publisher test this
-                               ) {
+                               if ( !$consumer->isUsableBy( $localUser ) ) {
                                        throw self::makeException( 
'mwoauth-invalid-authorization-not-approved' );
                                } elseif ( $consumer->get( 'wiki' ) !== '*'
                                        && $consumer->get( 'wiki' ) !== $wiki
@@ -301,12 +299,15 @@
                        $dbr = MWOAuthUtils::getCentralDB( DB_SLAVE );
                        $access = MWOAuthConsumerAcceptance::newFromToken( 
$dbr, $accesstoken->key );
                        $consumerId = $access->get( 'consumerId' );
-                       \ChangeTags::addTags(
-                               "OAuth CID: $consumerId",
-                               $rc->mAttribs['rc_id'],
-                               $rc->mAttribs['rc_this_oldid'],
-                               $rc->mAttribs['rc_logid']
-                       );
+                       $consumer = MWOAuthConsumer::newFromId( $dbr, 
$consumerId );
+                       if ( !$consumer->get( 'ownerOnly' ) ) {
+                               \ChangeTags::addTags(
+                                       "OAuth CID: $consumerId",
+                                       $rc->mAttribs['rc_id'],
+                                       $rc->mAttribs['rc_this_oldid'],
+                                       $rc->mAttribs['rc_logid']
+                               );
+                       }
                }
                return true;
        }
diff --git a/backend/MWOAuthConsumer.php b/backend/MWOAuthConsumer.php
index 76631fb..3d14873 100644
--- a/backend/MWOAuthConsumer.php
+++ b/backend/MWOAuthConsumer.php
@@ -47,6 +47,8 @@
        protected $emailAuthenticated;
        /** @var int User accepted the developer agreement */
        protected $developerAgreement;
+       /** @var int Consumer is for use by the owner only */
+       protected $ownerOnly;
        /** @var string Wiki ID the application can be used on (or "*" for all) 
*/
        protected $wiki;
        /** @var string TS_MW timestamp of proposal */
@@ -88,6 +90,7 @@
                                'email'              => 'oarc_email',
                                'emailAuthenticated' => 
'oarc_email_authenticated',
                                'developerAgreement' => 
'oarc_developer_agreement',
+                               'ownerOnly'          => 'oarc_owner_only',
                                'wiki'               => 'oarc_wiki',
                                'grants'             => 'oarc_grants',
                                'registration'       => 'oarc_registration',
@@ -215,13 +218,20 @@
        }
 
        /**
-        * Check if the consumer is still pending approval and is owned by $user
+        * Check if the consumer is usable by $user
+        *
+        * "Usable by $user" includes:
+        * - Approved for multi-user use
+        * - Approved for owner-only use and is owned by $user
+        * - Still pending approval and is owned by $user
         *
         * @param \User $user
         * @return boolean
         */
-       public function isPendingAndOwnedBy( \User $user ) {
-               if ( $this->stage === self::STAGE_PROPOSED ) {
+       public function isUsableBy( \User $user ) {
+               if ( $this->stage === self::STAGE_APPROVED && !$this->get( 
'ownerOnly' ) ) {
+                       return true;
+               } elseif ( $this->stage === self::STAGE_PROPOSED || 
$this->stage === self::STAGE_APPROVED ) {
                        $centralId = MWOAuthUtils::getCentralIdFromLocalUser( 
$user );
                        return ( $centralId && $this->userId === $centralId );
                }
diff --git a/backend/MWOAuthServer.php b/backend/MWOAuthServer.php
index c0ba27a..0300cc0 100644
--- a/backend/MWOAuthServer.php
+++ b/backend/MWOAuthServer.php
@@ -26,6 +26,16 @@
 
                $consumer = $this->get_consumer( $request );
 
+               // Consumer must not be owner-only
+               if ( $consumer->get( 'ownerOnly' ) ) {
+                       throw new MWOAuthException( 
'mwoauthserver-consumer-owner-only', array(
+                               $consumer->get( 'name' ),
+                               \SpecialPage::getTitleFor(
+                                       'OAuthConsumerRegistration', 'update/' 
. $consumer->get( 'consumerKey' )
+                               )
+                       ) );
+               }
+
                // Consumer must have a key for us to verify
                if ( !$consumer->get( 'secretKey' ) && !$consumer->get( 
'rsaKey' ) ) {
                        throw new MWOAuthException( 
'mwoauthserver-consumer-no-secret' );
@@ -105,6 +115,16 @@
                $this->get_version( $request );
 
                $consumer = $this->get_consumer( $request );
+
+               // Consumer must not be owner-only
+               if ( $consumer->get( 'ownerOnly' ) ) {
+                       throw new MWOAuthException( 
'mwoauthserver-consumer-owner-only', array(
+                               $consumer->get( 'name' ),
+                               \SpecialPage::getTitleFor(
+                                       'OAuthConsumerRegistration', 'update/' 
. $consumer->get( 'consumerKey' )
+                               )
+                       ) );
+               }
 
                // Consumer must have a key for us to verify
                if ( !$consumer->get( 'secretKey' ) && !$consumer->get( 
'rsaKey' ) ) {
@@ -186,9 +206,7 @@
                $consumer = $this->data_store->lookup_consumer( $consumerKey );
                if ( !$consumer || $consumer->get( 'deleted' ) ) {
                        throw new MWOAuthException( 
'mwoauthserver-bad-consumer-key' );
-               } elseif ( $consumer->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
-                       && !$consumer->isPendingAndOwnedBy( $mwUser ) // let 
publisher test this
-               ) {
+               } elseif ( !$consumer->isUsableBy( $mwUser ) ) {
                        $owner = MWOAuthUtils::getCentralUserNameFromId(
                                $consumer->get( 'userId' ),
                                $mwUser
@@ -197,6 +215,13 @@
                                'mwoauthserver-bad-consumer',
                                array( $consumer->get( 'name' ), 
MWOAuthUtils::getCentralUserTalk( $owner ) )
                        );
+               } elseif ( $consumer->get( 'ownerOnly' ) ) {
+                       throw new MWOAuthException( 
'mwoauthserver-consumer-owner-only', array(
+                               $consumer->get( 'name' ),
+                               \SpecialPage::getTitleFor(
+                                       'OAuthConsumerRegistration', 'update/' 
. $consumer->get( 'consumerKey' )
+                               )
+                       ) );
                }
 
                // Generate and Update the tokens:
diff --git a/backend/schema/MWOAuthUpdater.hooks.php 
b/backend/schema/MWOAuthUpdater.hooks.php
index 611b508..90bf2ae 100644
--- a/backend/schema/MWOAuthUpdater.hooks.php
+++ b/backend/schema/MWOAuthUpdater.hooks.php
@@ -39,6 +39,14 @@
                                true
                        ) );
 
+                       $updater->addExtensionUpdate( array(
+                               'addField',
+                               'oauth_registered_consumer',
+                               'oarc_owner_only',
+                               "$base/owner_only.sql",
+                               true
+                       ) );
+
                } elseif ( $dbType == 'postgres' ) {
                        //$base = "$base/postgres";
 
diff --git a/backend/schema/mysql/OAuth.sql b/backend/schema/mysql/OAuth.sql
index 6b96d3b..4edb72b 100644
--- a/backend/schema/mysql/OAuth.sql
+++ b/backend/schema/mysql/OAuth.sql
@@ -29,6 +29,8 @@
     oarc_email_authenticated varbinary(14) NULL,
     -- Did the owner accept the developer agreement?
     oarc_developer_agreement tinyint NOT NULL DEFAULT 0,
+    -- Is this consumer owner-only
+    oarc_owner_only tinyint NOT NULL DEFAULT 0,
     -- What wiki this is allowed on (a single wiki or '*' for all)
     oarc_wiki varbinary(32) NOT NULL,
     -- Grants needed for client consumers
diff --git a/backend/schema/mysql/owner_only.sql 
b/backend/schema/mysql/owner_only.sql
new file mode 100644
index 0000000..f231f41
--- /dev/null
+++ b/backend/schema/mysql/owner_only.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/oauth_registered_consumer ADD COLUMN `oarc_owner_only` 
tinyint NOT NULL DEFAULT 0 AFTER `oarc_developer_agreement`;
diff --git a/backend/schema/sqlite/OAuth.sql b/backend/schema/sqlite/OAuth.sql
index 6b96d3b..4edb72b 100644
--- a/backend/schema/sqlite/OAuth.sql
+++ b/backend/schema/sqlite/OAuth.sql
@@ -29,6 +29,8 @@
     oarc_email_authenticated varbinary(14) NULL,
     -- Did the owner accept the developer agreement?
     oarc_developer_agreement tinyint NOT NULL DEFAULT 0,
+    -- Is this consumer owner-only
+    oarc_owner_only tinyint NOT NULL DEFAULT 0,
     -- What wiki this is allowed on (a single wiki or '*' for all)
     oarc_wiki varbinary(32) NOT NULL,
     -- Grants needed for client consumers
diff --git a/backend/schema/sqlite/owner_only.sql 
b/backend/schema/sqlite/owner_only.sql
new file mode 100644
index 0000000..c0ddbfa
--- /dev/null
+++ b/backend/schema/sqlite/owner_only.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/oauth_registered_consumer ADD COLUMN `oarc_owner_only` 
tinyint NOT NULL DEFAULT 0;
diff --git a/control/MWOAuthConsumerAcceptanceSubmitControl.php 
b/control/MWOAuthConsumerAcceptanceSubmitControl.php
index 90913df..38f9fb4 100644
--- a/control/MWOAuthConsumerAcceptanceSubmitControl.php
+++ b/control/MWOAuthConsumerAcceptanceSubmitControl.php
@@ -89,9 +89,7 @@
                        $cmr = MWOAuthConsumer::newFromKey( $dbw, 
$this->vals['consumerKey'] );
                        if ( !$cmr ) {
                                return $this->failure( 'invalid_consumer_key', 
'mwoauth-invalid-consumer-key' );
-                       } elseif ( $cmr->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
-                               && !$cmr->isPendingAndOwnedBy( $user ) // let 
publisher test this
-                       ) {
+                       } elseif ( !$cmr->isUsableBy( $user ) ) {
                                return $this->failure( 'permission_denied', 
'badaccess-group0' );
                        }
 
diff --git a/control/MWOAuthConsumerSubmitControl.php 
b/control/MWOAuthConsumerSubmitControl.php
index 4bb2c5a..dc287b8 100644
--- a/control/MWOAuthConsumerSubmitControl.php
+++ b/control/MWOAuthConsumerSubmitControl.php
@@ -64,8 +64,9 @@
                        'propose'     => array(
                                'name'         => '/^.{1,128}$/',
                                'version'      => 
'/^\d{1,3}(\.\d{1,2}){0,2}(-(dev|alpha|beta))?$/',
-                               'callbackUrl'  => function( $s ) {
-                                       return wfParseUrl( $s ) !== null; },
+                               'callbackUrl'  => function( $s, $vals ) {
+                                       return $vals['ownerOnly'] || 
wfParseUrl( $s ) !== null;
+                               },
                                'description'  => '/^.*$/s',
                                'email'        => function( $s ) {
                                        return \Sanitizer::validateEmail( $s ); 
},
@@ -185,6 +186,16 @@
                                        
'mwoauth-consumer-alreadyexistsversion', $curVer );
                        }
 
+                       // Handle owner-only mode
+                       if ( $this->vals['ownerOnly'] ) {
+                               $this->vals['callbackUrl'] = 
\SpecialPage::getTitleFor( 'OAuth', 'verified' )
+                                       ->getLocalUrl();
+                               $this->vals['callbackIsPrefix'] = '';
+                               $stage = MWOAuthConsumer::STAGE_APPROVED;
+                       } else {
+                               $stage = MWOAuthConsumer::STAGE_PROPOSED;
+                       }
+
                        // Handle grant types
                        $grants = array();
                        switch( $this->vals['granttype'] ) {
@@ -213,7 +224,7 @@
                                        'developerAgreement' => 1,
                                        'secretKey'          => 
\MWCryptRand::generateHex( 32 ),
                                        'registration'       => $now,
-                                       'stage'              => 
MWOAuthConsumer::STAGE_PROPOSED,
+                                       'stage'              => $stage,
                                        'stageTimestamp'     => $now,
                                        'grants'             => $grants,
                                        'restrictions'       => 
\FormatJSON::decode( $this->vals['restrictions'], true ),
@@ -222,7 +233,10 @@
                        );
                        $cmr->save( $dbw );
 
-                       $logEntry = new \ManualLogEntry( 'mwoauthconsumer', 
'propose' );
+                       $logEntry = new \ManualLogEntry(
+                               'mwoauthconsumer',
+                               $cmr->get( 'ownerOnly' ) ? 'create-owner-only' 
: 'propose'
+                       );
                        $logEntry->setPerformer( $user );
                        $logEntry->setTarget( $this->getLogTitle( $dbw, 
$cmr->get( 'userId' ) ) );
                        $logEntry->setComment( $this->vals['description'] );
@@ -232,7 +246,24 @@
                        ) );
                        $logEntry->insert( $dbw );
 
-                       return $this->success( $cmr );
+                       // If it's owner-only, automatically accept it for the 
user too.
+                       $cmra = null;
+                       if ( $cmr->get( 'ownerOnly' ) ) {
+                               $accessToken = MWOAuthDataStore::newToken();
+                               $cmra = 
MWOAuthConsumerAcceptance::newFromArray( array(
+                                       'id'           => null,
+                                       'wiki'         => $cmr->get( 'wiki' ),
+                                       'userId'       => $centralUserId,
+                                       'consumerId'   => $cmr->get( 'id' ),
+                                       'accessToken'  => $accessToken->key,
+                                       'accessSecret' => $accessToken->secret,
+                                       'grants'       => $cmr->get( 'grants' ),
+                                       'accepted'     => $now,
+                               ) );
+                               $cmra->save( $dbw );
+                       }
+
+                       return $this->success( array( 'consumer' => $cmr, 
'acceptance' => $cmra ) );
                case 'update':
                        if ( !$user->isAllowed( 'mwoauthupdateownconsumer' ) ) {
                                return $this->failure( 'permission_denied', 
'badaccess-group0' );
@@ -274,7 +305,32 @@
                                $logEntry->insert( $dbw );
                        }
 
-                       return $this->success( $cmr );
+                       $cmra = null;
+                       if ( $cmr->get( 'ownerOnly' ) && 
$this->vals['resetSecret'] ) {
+                               $accessToken = MWOAuthDataStore::newToken();
+                               $fields = array(
+                                       'wiki'         => $cmr->get( 'wiki' ),
+                                       'userId'       => $centralUserId,
+                                       'consumerId'   => $cmr->get( 'id' ),
+                                       'accessSecret' => $accessToken->secret,
+                                       'grants'       => $cmr->get( 'grants' ),
+                               );
+
+                               $oauthServer = MWOAuthUtils::newMWOAuthServer();
+                               $cmra = $oauthServer->getCurrentAuthorization( 
$user, $cmr, wfWikiId() );
+                               if ( $cmra ) {
+                                       $cmra->setFields( $fields );
+                               } else {
+                                       $cmra = 
MWOAuthConsumerAcceptance::newFromArray( $fields + array(
+                                               'id'           => null,
+                                               'accessToken'  => 
$accessToken->key,
+                                               'accepted'     => 
wfTimestampNow(),
+                                       ) );
+                               }
+                               $cmra->save( $dbw );
+                       }
+
+                       return $this->success( array( 'consumer' => $cmr, 
'acceptance' => $cmra ) );
                case 'approve':
                        if ( !$user->isAllowed( 'mwoauthmanageconsumer' ) ) {
                                return $this->failure( 'permission_denied', 
'badaccess-group0' );
diff --git a/frontend/specialpages/SpecialMWOAuth.php 
b/frontend/specialpages/SpecialMWOAuth.php
index c26d9cb..31e07b6 100644
--- a/frontend/specialpages/SpecialMWOAuth.php
+++ b/frontend/specialpages/SpecialMWOAuth.php
@@ -291,9 +291,7 @@
                );
                if ( !$cmr ) {
                        throw new MWOAuthException( 
'mwoauthserver-bad-consumer-key' );
-               } elseif ( $cmr->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
-                       && !$cmr->getDAO()->isPendingAndOwnedBy( $user )
-               ) {
+               } elseif ( !$cmr->getDAO()->isUsableBy( $user ) ) {
                        throw new MWOAuthException(
                                'mwoauthserver-bad-consumer',
                                array(
diff --git a/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php 
b/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
index 1df807a..82abb33 100644
--- a/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
+++ b/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
@@ -116,15 +116,22 @@
                                                'required' => true,
                                                'rows' => 5
                                        ),
+                                       'ownerOnly' => array(
+                                               'type' => 'check',
+                                               'label-message' => array( 
'mwoauth-consumer-owner-only', $user->getName() ),
+                                               'help-message' => array( 
'mwoauth-consumer-owner-only-help', $user->getName() ),
+                                       ),
                                        'callbackUrl' => array(
                                                'type' => 'text',
                                                'label-message' => 
'mwoauth-consumer-callbackurl',
-                                               'required' => true
+                                               'required' => true,
+                                               'hide-if' => array( '!==', 
'ownerOnly', '' ),
                                        ),
                                        'callbackIsPrefix' => array(
                                                'type' => 'check',
                                                'label-message' => 
'mwoauth-consumer-callbackisprefix',
-                                               'required' => true
+                                               'required' => true,
+                                               'hide-if' => array( '!==', 
'ownerOnly', '' ),
                                        ),
                                        'email' => array(
                                                'type' => 'text',
@@ -157,7 +164,7 @@
                                                'type' => 'checkmatrix',
                                                'label-message' => 
'mwoauth-consumer-grantsneeded',
                                                'help-message' => 
'mwoauth-consumer-grantshelp',
-                                               'hide-if' => array( '!==', 
'wpgranttype', 'normal' ),
+                                               'hide-if' => array( '!==', 
'granttype', 'normal' ),
                                                'columns' => array(
                                                        $this->msg( 
'mwoauth-consumer-required-grant' )->escaped() => 'grant'
                                                ),
@@ -223,9 +230,20 @@
 
                        $status = $form->show();
                        if ( $status instanceof \Status && $status->isOk() ) {
-                               $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-proposed',
-                                       $status->value['result']->get( 
'consumerKey' ),
-                                       MWOAuthUtils::hmacDBSecret( 
$status->value['result']->get( 'secretKey' ) ) );
+                               $cmr = $status->value['result']['consumer'];
+                               if ( $cmr->get( 'ownerOnly' ) ) {
+                                       $cmra = 
$status->value['result']['acceptance'];
+                                       $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-created-owner-only',
+                                               $cmr->get( 'consumerKey' ),
+                                               MWOAuthUtils::hmacDBSecret( 
$cmr->get( 'secretKey' ) ),
+                                               $cmra->get( 'accessToken' ),
+                                               MWOAuthUtils::hmacDBSecret( 
$cmra->get( 'accessSecret' ) )
+                                       );
+                               } else {
+                                       $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-proposed',
+                                               $cmr->get( 'consumerKey' ),
+                                               MWOAuthUtils::hmacDBSecret( 
$cmr->get( 'secretKey' ) ) );
+                               }
                                $this->getOutput()->returnToMain();
                        }
                        break;
@@ -322,11 +340,22 @@
 
                        $status = $form->show();
                        if ( $status instanceof \Status && $status->isOk() ) {
+                               $cmr = $status->value['result']['consumer'];
                                $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-updated' );
-                               $curSecretKey = $status->value['result']->get( 
'secretKey' );
+                               $curSecretKey = $cmr->get( 'secretKey' );
                                if ( $oldSecretKey !== $curSecretKey ) { // 
token reset?
-                                       $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-secretreset',
-                                               MWOAuthUtils::hmacDBSecret( 
$curSecretKey ) );
+                                       if ( $cmr->get( 'ownerOnly' ) ) {
+                                               $cmra = 
$status->value['result']['acceptance'];
+                                               $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-secretreset-owner-only',
+                                                       $cmr->get( 
'consumerKey' ),
+                                                       
MWOAuthUtils::hmacDBSecret( $curSecretKey ),
+                                                       $cmra->get( 
'accessToken' ),
+                                                       
MWOAuthUtils::hmacDBSecret( $cmra->get( 'accessSecret' ) )
+                                               );
+                                       } else {
+                                               $this->getOutput()->addWikiMsg( 
'mwoauthconsumerregistration-secretreset',
+                                                       
MWOAuthUtils::hmacDBSecret( $curSecretKey ) );
+                                       }
                                }
                                $this->getOutput()->returnToMain();
                        } else {
diff --git a/frontend/specialpages/SpecialMWOAuthManageConsumers.php 
b/frontend/specialpages/SpecialMWOAuthManageConsumers.php
index 8959e61..81d6cae 100755
--- a/frontend/specialpages/SpecialMWOAuthManageConsumers.php
+++ b/frontend/specialpages/SpecialMWOAuthManageConsumers.php
@@ -242,6 +242,21 @@
                        }
                }
 
+               $owner = $cmr->get( 'userId', function( $s ) {
+                       $name = MWOAuthUtils::getCentralUserNameFromId( $s );
+                       return $name;
+               } );
+
+               $link = \Linker::linkKnown(
+                       $title = \SpecialPage::getTitleFor( 
'OAuthListConsumers' ),
+                       wfMessage( 'mwoauthmanageconsumers-search-publisher' 
)->escaped(),
+                       array(),
+                       array( 'publisher' => $owner )
+               );
+               $ownerLink = htmlspecialchars( $owner ) . ' ' .
+                       wfMessage( 'parentheses' )->rawParams( $link 
)->escaped();
+               $ownerOnly = $cmr->get( 'ownerOnly' );
+
                $dbw = MWOAuthUtils::getCentralDB( DB_MASTER ); // @TODO: lazy 
handle
                $control = new MWOAuthConsumerSubmitControl( 
$this->getContext(), array(), $dbw );
                $form = new \HTMLForm(
@@ -274,17 +289,7 @@
                                'user' => array(
                                        'type' => 'info',
                                        'label-message' => 
'mwoauth-consumer-user',
-                                       'default' => $cmr->get( 'userId', 
function( $s ) {
-                                               $name = 
MWOAuthUtils::getCentralUserNameFromId( $s );
-                                               $link = \Linker::linkKnown(
-                                                       $title = 
\SpecialPage::getTitleFor( 'OAuthListConsumers' ),
-                                                       wfMessage( 
'mwoauthmanageconsumers-search-publisher' )->escaped(),
-                                                       array(),
-                                                       array( 'publisher' => 
$name )
-                                               );
-                                               return htmlspecialchars( $name 
) . ' ' .
-                                                       wfMessage( 
'parentheses' )->rawParams( $link )->escaped();
-                                       } ),
+                                       'default' => $ownerLink,
                                        'raw' => true
                                ),
                                'description' => array(
@@ -293,13 +298,18 @@
                                        'default' => $cmr->get( 'description' ),
                                        'rows' => 5
                                ),
+                               'ownerOnly' => array(
+                                       'type' => $ownerOnly ? 'info' : 
'hidden',
+                                       'label-message' => 
'mwoauth-consumer-owner-only-label',
+                                       'default' => wfMessage( 
'mwoauth-consumer-owner-only', $owner )->escaped(),
+                               ),
                                'callbackUrl' => array(
-                                       'type' => 'info',
+                                       'type' => $ownerOnly ? 'hidden' : 
'info',
                                        'label-message' => 
'mwoauth-consumer-callbackurl',
-                                       'default' => $cmr->get( 'callbackUrl' )
+                                       'default' => $cmr->get( 'callbackUrl' ),
                                ),
                                'callbackIsPrefix' => array(
-                                       'type' => 'info',
+                                       'type' => $ownerOnly ? 'hidden' : 
'info',
                                        'label-message' => 
'mwoauth-consumer-callbackisprefix',
                                        'default' => $cmr->get( 
'callbackIsPrefix' )
                                ),
diff --git a/i18n/en.json b/i18n/en.json
index 8616f1d..1dcc801 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -21,6 +21,9 @@
        "mwoauth-consumer-user": "Publisher:",
        "mwoauth-consumer-stage": "Current status:",
        "mwoauth-consumer-email": "Contact email address:",
+       "mwoauth-consumer-owner-only-label": "Owner-only:",
+       "mwoauth-consumer-owner-only": "This consumer is for use only by $1.",
+       "mwoauth-consumer-owner-only-help": "Selecting this option will cause 
the consumer to be automatically approved and accepted for use by $1. It will 
not be usable by any other user, and the usual authorization flow will not 
function. Actions taken using this consumer will not be tagged.",
        "mwoauth-consumer-description": "Application description:",
        "mwoauth-consumer-callbackurl": "OAuth \"callback\" URL:",
        "mwoauth-consumer-callbackisprefix": "Allow consumer to specify a 
callback in requests and use \"callback\" URL above as a required prefix.",
@@ -81,8 +84,10 @@
        "mwoauthconsumerregistration-manage": "manage",
        "mwoauthconsumerregistration-resetsecretkey": "Reset the secret key to 
a new value",
        "mwoauthconsumerregistration-proposed": "Your OAuth consumer request 
has been received.\n\nYou have been assigned a consumer token of '''$1''' and a 
secret token of '''$2'''. ''Please record these for future reference.''",
+       "mwoauthconsumerregistration-created-owner-only": "Your OAuth consumer 
has been created.\n\nYour tokens are:\n; Consumer token: $1\n; Consumer secret: 
$2\n; Access token: $3\n; Access secret: $4\n<em>Please record these for future 
reference.</em>",
        "mwoauthconsumerregistration-updated": "Your OAuth consumer registry 
was successfully updated.",
        "mwoauthconsumerregistration-secretreset": "You have been assigned a 
consumer secret token of '''$1'''. ''Please record this for future 
reference.''",
+       "mwoauthconsumerregistration-secretreset-owner-only": "Your OAuth 
consumer tokens have been reset. The new tokens are:\n; Consumer token: $1\n; 
Consumer secret: $2\n; Access token: $3\n; Access secret: $4\n<em>Please record 
these for future reference.</em>",
        "oauthmanageconsumers": "Manage OAuth consumers",
        "mwoauthmanageconsumers-notloggedin": "You have to be logged in to 
access this page.",
        "mwoauthmanageconsumers-type": "Queues:",
@@ -179,6 +184,7 @@
        "logentry-mwoauthconsumer-reject": "$1 {{GENDER:$2|rejected}} an OAuth 
consumer by $3 (consumer key $4)",
        "logentry-mwoauthconsumer-disable": "$1 {{GENDER:$2|disabled}} an OAuth 
consumer by $3 (consumer key $4)",
        "logentry-mwoauthconsumer-reenable": "$1 {{GENDER:$2|re-enabled}} an 
OAuth consumer by $3 (consumer key $4)",
+       "logentry-mwoauthconsumer-create-owner-only": "$1 {{GENDER:$2|created}} 
an owner-only OAuth consumer (consumer key $4)",
        "mwoauthconsumer-consumer-logpage": "OAuth consumer log",
        "mwoauthconsumer-consumer-logpagetext": "Log of approvals, rejections, 
and disabling of registered OAuth consumers.",
        "mwoauth-bad-request-missing-params": "Sorry, something went wrong 
configuring this connected application. <span 
class=\"plainlinks\">[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:OAuth
 Contact support]</span> to get help fixing it.\n\n<span class=\"plainlinks 
mw-mwoautherror-details\">OAuth missing parameters, 
[https://www.mediawiki.org/wiki/Help:OAuth/Errors#E001 E001]</span>",
@@ -199,6 +205,7 @@
        "mwoauthserver-invalid-request-token": "Invalid token in your request.",
        "mwoauthserver-invalid-user": "To use Connected Apps on this site, you 
must have an account across all projects. When you have an account on all 
projects, you can try to connect \"$1\" again.\n\n<span class=\"plainlinks 
mw-mwoautherror-details\">Unified login needed, 
[https://www.mediawiki.org/wiki/Help:OAuth/Errors#E008 E008]</span>",
        "mwoauthserver-consumer-no-secret": "Sorry, something went wrong 
connecting this application.\n\n<span class=\"plainlinks 
mw-mwoautherror-details\">Consumer has no secret key, 
[https://www.mediawiki.org/wiki/Help:OAuth/Errors#E009 E009]</span>",
+       "mwoauthserver-consumer-owner-only": "\"$1\" is an owner-only Connected 
App. To fetch the access token, see [[$2]].\n\n<span class=\"plainlinks 
mw-mwoautherror-details\">Consumer is owner-only, 
[https://www.mediawiki.org/wiki/Help:OAuth/Errors#E010 E010]</span>",
        "mwoauth-invalid-authorization-title": "OAuth authorization error",
        "mwoauth-invalid-authorization": "The authorization headers in your 
request are not valid: $1",
        "mwoauth-invalid-authorization-wrong-wiki": "The authorization headers 
in your request are not valid for $1",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 41da588..8eaa080 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -29,6 +29,9 @@
        "mwoauth-consumer-user": "Used as label for the \"Central username\" 
box.\n{{Identical|Publisher}}",
        "mwoauth-consumer-stage": "Used as label for the \"Stage\" 
value\n\nFollowed by any one of the following messages:\n* 
{{msg-mw|Mwoauth-consumer-stage-proposed}}\n* 
{{msg-mw|Mwoauth-consumer-stage-rejected}}\n* 
{{msg-mw|Mwoauth-consumer-stage-expired}}\n* 
{{msg-mw|Mwoauth-consumer-stage-approved}}\n* 
{{msg-mw|Mwoauth-consumer-stage-disabled}}\n* 
{{msg-mw|Mwoauth-consumer-stage-suppressed}}\n{{Identical|Current status}}",
        "mwoauth-consumer-email": "Used as label for the \"Email address\" 
input box.",
+       "mwoauth-consumer-owner-only-label": "Used as label for the \"Owner 
only\" field.",
+       "mwoauth-consumer-owner-only": "Used as label for the \"Owner only\" 
checkbox.",
+       "mwoauth-consumer-owner-only-help": "Used as help text for the \"Owner 
only\" checkbox.",
        "mwoauth-consumer-description": "Used as label for the \"description\" 
textarea.\n{{Identical|Application description}}",
        "mwoauth-consumer-callbackurl": "Used as label for the \"Callback URL\" 
input box.\n\nSee [[w:Callback (computer programming)]].",
        "mwoauth-consumer-callbackisprefix": "Used as a label for the check box 
where user can decide if their consumer should use \"Callback URL\" as a string 
prefix (checked), or if the consumer cannot customize the callback URL in its 
requests as is required to specify \"oob\" (unchecked, default).",
@@ -89,8 +92,10 @@
        "mwoauthconsumerregistration-manage": "Used as link 
text.\n{{Identical|Manage}}",
        "mwoauthconsumerregistration-resetsecretkey": "Used a label for a 
checkbox",
        "mwoauthconsumerregistration-proposed": "Used as success 
message.\n\nParameters:\n* $1 - consumer key\n* $2 - secret key",
+       "mwoauthconsumerregistration-created-owner-only": "Used as success 
message.\n\nParameters:\n* $1 - consumer key\n* $2 - consumer secret\n* $3 - 
access key\n* $4 - access secret",
        "mwoauthconsumerregistration-updated": "Shown as success message",
        "mwoauthconsumerregistration-secretreset": "Shown on success message. 
Parameters:\n* $1 - new secret token",
+       "mwoauthconsumerregistration-secretreset-owner-only": "Shown on success 
message.\n\nParameters:\n* $1 - consumer key\n* $2 - consumer secret\n* $3 - 
access key\n* $4 - access secret",
        "oauthmanageconsumers": 
"{{doc-special|MWOAuthManageConsumers}}\n{{Identical|Manage OAuth consumer}}",
        "mwoauthmanageconsumers-notloggedin": "Used if the user is not logged 
in.",
        "mwoauthmanageconsumers-type": "Used as subtitle.\n\nFollowed by any 
one (or zero) of the following messages:\n* 
{{msg-mw|Mwoauthmanageconsumers-showproposed}}\n* 
{{msg-mw|Mwoauthmanageconsumers-showrejected}}\n* 
{{msg-mw|Mwoauthmanageconsumers-showexpired}}\n{{Identical|Queue}}",
@@ -187,6 +192,7 @@
        "logentry-mwoauthconsumer-reject": "{{logentry}}\n* $4 - consumer key",
        "logentry-mwoauthconsumer-disable": "{{logentry}}\n* $4 - consumer key",
        "logentry-mwoauthconsumer-reenable": "{{logentry}}\n* $4 - consumer 
key",
+       "logentry-mwoauthconsumer-create-owner-only": "{{logentry}}\n* $4 - 
consumer key",
        "mwoauthconsumer-consumer-logpage": "{{doc-logpage}}",
        "mwoauthconsumer-consumer-logpagetext": "Description of the OAuth 
consumer log.",
        "mwoauth-bad-request-missing-params": "Error message when MediaWiki 
makes an error during the authorization process, and fails to send all the 
required url parameters",
@@ -207,6 +213,7 @@
        "mwoauthserver-invalid-request-token": "Error message when an invalid 
request token was submitted",
        "mwoauthserver-invalid-user": "Error when the user attempts to use 
OAuth, but they do not have a unified (SUL) account, which is 
required.\n\nParameters:\n* $1 - application name",
        "mwoauthserver-consumer-no-secret": "Error when a consumer with no 
secret or RSA was submitted",
+       "mwoauthserver-consumer-owner-only": "Error when an owner-only consumer 
attempted to use the authorization process",
        "mwoauth-invalid-authorization-title": "Title of the error page when 
the Authorization header is invalid",
        "mwoauth-invalid-authorization": "Text of the error page when the 
Authorization header is invalid. Parameters are:\n* $1 - Specific error message 
from the OAuth layer, probably not localized",
        "mwoauth-invalid-authorization-wrong-wiki": "Text of the error page 
when the Authorization header is for the wrong wiki. Parameters are:\n* $1 - 
wiki id",

-- 
To view, visit https://gerrit.wikimedia.org/r/255488
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I3c791b949e19eb476968e5f9dd1511d485e52810
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/OAuth
Gerrit-Branch: master
Gerrit-Owner: Anomie <[email protected]>
Gerrit-Reviewer: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: BryanDavis <[email protected]>
Gerrit-Reviewer: CSteipp <[email protected]>
Gerrit-Reviewer: GergÅ‘ Tisza <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: Springle <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to