jenkins-bot has submitted this change and it was merged. Change subject: Send authorization header to cxserver ......................................................................
Send authorization header to cxserver Also see https://gerrit.wikimedia.org/r/#/c/221857/ Bug: T97113 Change-Id: If349547fe072b3e7ef5a226afd34373a2199eb95 --- A api/ApiContentTranslationToken.php M composer.json M extension.json M i18n/en.json M i18n/qqq.json M modules/tools/ext.cx.tools.mt.js 6 files changed, 132 insertions(+), 7 deletions(-) Approvals: Santhosh: Looks good to me, approved jenkins-bot: Verified diff --git a/api/ApiContentTranslationToken.php b/api/ApiContentTranslationToken.php new file mode 100644 index 0000000..f7b47b3 --- /dev/null +++ b/api/ApiContentTranslationToken.php @@ -0,0 +1,57 @@ +<?php +/** + * Module that provides JWT tokens to authenticate with cxserver. + * + * @file + * @copyright See AUTHORS.txt + * @license GPL-2.0+ + */ +class ApiContentTranslationToken extends ApiBase { + public function execute() { + $user = $this->getUser(); + + if ( $user->isBlocked() ) { + $this->dieUsageMsg( 'blockedtext' ); + } + + if ( !$user->isLoggedIn() ) { + $this->dieUsage( 'Must be logged in', 'token-impossible' ); + } + + // Do not fatal out + if ( !class_exists( 'JWT' ) ) { + $this->dieUsage( 'JWT missing', 'token-impossible' ); + } + + $config = $this->getConfig()->get( 'ContentTranslationCXServerAuth' ); + $algorithm = $config['algorithm']; + $key = $config['key']; + + if ( $key === '' ) { + $this->dieUsage( 'Key not configured', 'token-impossible' ); + } + + $exp = time() + $config['age']; + + $token = array( + 'sub' => $user->getName(), + 'iat' => time(), + 'exp' => $exp, + ); + + $jwt = JWT::encode( $token, $key, $algorithm ); + + $this->getResult()->addValue( null, 'jwt', $jwt ); + $this->getResult()->addValue( null, 'exp', $exp ); + } + + public function needsToken() { + return 'csrf'; + } + + protected function getExamplesMessages() { + return array( + 'action=cxtoken&token=123ABC' => 'apihelp-cxtoken-example-1' + ); + } +} diff --git a/composer.json b/composer.json index 2f22485..aa2dacd 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ }, "require": { "php": ">=5.3.0", - "composer/installers": ">=1.0.1" + "composer/installers": ">=1.0.1", + "firebase/php-jwt": "~2.1.0" }, "require-dev": { "jakub-onderka/php-parallel-lint": "0.9", diff --git a/extension.json b/extension.json index 0d09ca0..fc6f936 100644 --- a/extension.json +++ b/extension.json @@ -37,7 +37,8 @@ "APIModules": { "cxpublish": "ApiContentTranslationPublish", "cxdelete": "ApiContentTranslationDelete", - "cxconfiguration": "ApiContentTranslationConfiguration" + "cxconfiguration": "ApiContentTranslationConfiguration", + "cxtoken": "ApiContentTranslationToken" }, "APIListModules": { "contenttranslation": "ApiQueryContentTranslation", @@ -54,11 +55,12 @@ }, "AutoloadClasses": { "ApiContentTranslationConfiguration": "api/ApiContentTranslationConfiguration.php", - "ApiContentTranslationPublish": "api/ApiContentTranslationPublish.php", "ApiContentTranslationDelete": "api/ApiContentTranslationDelete.php", + "ApiContentTranslationPublish": "api/ApiContentTranslationPublish.php", + "ApiContentTranslationToken": "api/ApiContentTranslationToken.php", "ApiQueryContentTranslation": "api/ApiQueryContentTranslation.php", - "ApiQueryContentTranslationStats": "api/ApiQueryContentTranslationStats.php", "ApiQueryContentTranslationLanguageTrend": "api/ApiQueryContentTranslationLanguageTrend.php", + "ApiQueryContentTranslationStats": "api/ApiQueryContentTranslationStats.php", "ApiQueryPublishedTranslations": "api/ApiQueryPublishedTranslations.php", "ContentTranslationHooks": "ContentTranslation.hooks.php", "ContentTranslation\\Database": "includes/Database.php", @@ -104,6 +106,11 @@ "ContentTranslationUseMagnusTool": true, "ContentTranslationBrowserBlacklist": { "msie": [ [ "<", 10 ] ] + }, + "ContentTranslationCXServerAuth": { + "algorithm": "HS256", + "key": "", + "age": "3600" } }, "ResourceModules": { diff --git a/i18n/en.json b/i18n/en.json index 9bf3d3b..e94229f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -139,6 +139,7 @@ "apihelp-query+contenttranslationlangtrend-param-interval": "The interval for calculating the trend. Can be 'week' or 'month'.", "apihelp-query+contenttranslationlangtrend-example-1": "Fetch the publishing trend for the language pair es-ca with weekly intervals", "apihelp-query+contenttranslationlangtrend-example-2": "Fetch the publishing trend for all languages", + "apihelp-cxtoken-example-1": "Fetch the authentication token for cxserver", "cx-save-draft-save-success": "Saved {{PLURAL:$1|a minute ago|$1 minutes ago|0=just now}}", "cx-save-draft-saving": "Saving...", "cx-save-draft-tooltip": "Translation drafts are saved automatically", diff --git a/i18n/qqq.json b/i18n/qqq.json index 7a03aa7..7983e0c 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -144,6 +144,7 @@ "apihelp-query+contenttranslationlangtrend-param-interval": "{{doc-apihelp-param|query+cxpublishedtranslations|interval}}", "apihelp-query+contenttranslationlangtrend-example-1": "{{doc-apihelp-example|query+contenttranslationlangtrend}}", "apihelp-query+contenttranslationlangtrend-example-2": "{{doc-apihelp-example|query+contenttranslationlangtrend}}", + "apihelp-cxtoken-example-1": "{{doc-apihelp-example|cxtoken}}", "cx-save-draft-save-success": "\"Saved\" refers to a draft of a translated page that was saved recently.", "cx-save-draft-saving": "Label of button to save the translation as draft while saving is in progress\n{{Identical|Saving}}", "cx-save-draft-tooltip": "Tooltip text shown for the save status indicator text in the header of [[Special:ContentTranslation]].\n\nParameters: \n* $1 - the number of minutes ago the translation was saved.", diff --git a/modules/tools/ext.cx.tools.mt.js b/modules/tools/ext.cx.tools.mt.js index 29e69c1..6773c10 100644 --- a/modules/tools/ext.cx.tools.mt.js +++ b/modules/tools/ext.cx.tools.mt.js @@ -11,11 +11,62 @@ ( function ( $, mw ) { 'use strict'; - var cache = {}, // MT requests cache + var + cxserverToken = { + expires: undefined, + jwt: undefined, + promise: undefined + }, + cache = {}, // MT requests cache providerIdPrefix = 'cx-provider-', disableMT = 'disable-mt', noMT = 'no-mt', sourceMT = 'source-mt'; + + /** + * Fetch token for authentication with cxserver. + * + * @return {jQuery.Promise} + */ + function getCXServerToken() { + var now = Math.floor( Date.now() / 1000 ); + + // If request in progress, wait for it + if ( cxserverToken.promise ) { + return cxserverToken.promise; + } + + // Return cached token if fresh and not expiring soon. + // And hope that client clock is at correct time. + if ( + cxserverToken.expires !== undefined && + cxserverToken.expires + 5 < now + ) { + return $.Deferred().resolve( cxserverToken.jwt ); + } + + // (Re-)fetch cxserver token + cxserverToken.promise = (new mw.Api()) + .postWithToken( 'edit', { action: 'cxtoken' } ) + .always( function () { + cxserverToken.promise = undefined; + } ) + .then( + function ( response ) { + cxserverToken.jwt = response.jwt; + cxserverToken.expires = response.exp; + + return response.jwt; + }, + // Not all MT services require token, so let the caller try + // with empty token to see if it fails. + function () { + return $.Deferred().resolve( '' ); + } + ); + + return cxserverToken.promise; + } /** * Get the registry of machine translation providers @@ -80,8 +131,15 @@ $provider: MTControlCard.provider } ); - return $.post( mtURL, sourceHtml ).then( null, function () { - return $.Deferred().reject( 'service-failure', arguments ).promise(); + return getCXServerToken().then( function ( token ) { + return $.ajax( { + type: 'post', + url: mtURL, + data: sourceHtml, + headers: { Authorization: token } + } ).then( null, function () { + return $.Deferred().reject( 'service-failure', arguments ).promise(); + } ); } ); } -- To view, visit https://gerrit.wikimedia.org/r/219194 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: If349547fe072b3e7ef5a226afd34373a2199eb95 Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/extensions/ContentTranslation Gerrit-Branch: master Gerrit-Owner: Nikerabbit <[email protected]> Gerrit-Reviewer: Amire80 <[email protected]> Gerrit-Reviewer: CSteipp <[email protected]> Gerrit-Reviewer: Legoktm <[email protected]> Gerrit-Reviewer: Nikerabbit <[email protected]> Gerrit-Reviewer: Santhosh <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
