Yurik has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/184995

Change subject: TLS support
......................................................................

TLS support

Original patches with comments:

Combined Ie9a845b5f2861f1c96f21c3def55043af9fe9c51 and
I5f8414baaab805715a990ad788111e50171a7fe1

Show noscript HTTPS to HTTP tap if HTTPS charged

This supports a tap-through option for users on <noscript>
devices on HTTPS when HTTPS isn't zero-rated. The HTTPS downgrade
verbiage is visible if the configuration for the operator is updated
with a "showHttpsDowngrade" option for the particular connection
type (e.g., "DIRECT") used by the user.

The tap-through action is a link to http://zero.wikipedia.org/ ,
which has relatively graceful redirection.

Additionally, for the zerodot-not-supported scenario where a red
banner image is shown, a tap-through is exposed for
http://zero.wikipedia.org/, which will have similar benefits.

Finally, for the zerodot-IS-supported scenario where the operator's
banner is shown as a GIF for these RLI users on HTTPS (rare), the
tap-through link is in place, mainly to avoid complicating the code
base for this relatively small portion of users (approximately 6.5%
of users on Wikipedia Zero). It can be thought of as a feature to get
the user back to the landing page / main page pertinent for them.

Per the business development team, HTTPS downgrades should have a
gray background. Thus the foreground text is made black in this case.

Change-Id: I91aa173f915310cba5de75866b89059d9b8e3d91
---
M ZeroBanner.php
M i18n/en.json
M i18n/qqq.json
M includes/PageRendering.php
M includes/ZeroConfig.php
M includes/ZeroSpecialPage.php
M modules/ZeroOverlay.js
M modules/banner.css
M modules/interstitial.js
A templates/interstitialask.hogan
10 files changed, 163 insertions(+), 19 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ZeroBanner 
refs/changes/95/184995/1

diff --git a/ZeroBanner.php b/ZeroBanner.php
index a7d664f..dff6c5c 100644
--- a/ZeroBanner.php
+++ b/ZeroBanner.php
@@ -80,6 +80,7 @@
        'remoteExtPath' => $remoteExtPath,
        'templates' => array(
                'interstitial.hogan' => 'templates/interstitial.hogan',
+               'interstitialask.hogan' => 'templates/interstitialask.hogan',
                'zeroinfo.hogan' => 'templates/zeroinfo.hogan'
        ),
        'targets' => array( 'mobile' ),
@@ -95,6 +96,8 @@
                'zero-accept',
                'zero-go-back',
                'zero-dont-ask',
+               'zero-http',
+               'zero-https-http-extended',
                'zero-interstitial-title',
                'zero-info-title',
                'zero-info-intro',
diff --git a/i18n/en.json b/i18n/en.json
index 1c799f0..69bb801 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -34,6 +34,9 @@
        "zero-dont-ask": "Do not warn me about potential charges in the future",
        "zero-go-back": "Go back",
        "zero-accept": "Accept",
+       "zero-http": "Go to http",
+       "zero-https-http": "Data not free on encrypted https. Free on http",
+       "zero-https-http-extended": "Your mobile operator supports Wikipedia 
without data charges on unencrypted http only. You can try browsing on http for 
free data, but you may get redirected to https if your device does not support 
it.",
        "zero-click-to-view-image": "Click to view image of \"$1\"...",
        "zero-dismiss-notification": "dismiss this notification",
        "zero-config-name": "Parameter \"$1\" must be an object that maps valid 
language codes to strings. e.g. { \"en\":\"English\", ... }",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 119fa84..1ac9cf2 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -50,6 +50,9 @@
        "zero-dont-ask": "Shown next to a checkbox that allows user to always 
skip the following warning:\n* {{msg-mw|Zero-charge-auth}}",
        "zero-go-back": "Text for going back (in browser 
history).\n{{Identical|Go back}}",
        "zero-accept": "Text for accepting (e.g. 
charges).\n{{Identical|Accept}}",
+       "zero-http": "Go to http button label, with http intentionally 
lowercase due to that being the format in the address bar",
+       "zero-https-http": "Text concisely explaining encrypted HTTPS is not 
zero-rated, but HTTP is zero-rated",
+       "zero-https-http-extended": "Extended explanation about HTTPS not being 
zero-rated, but HTTP being zero-rated, with an explanation to the user that the 
user can try to continue to HTTP",
        "zero-click-to-view-image": "Text for viewing an image link. 
Parameters:\n* $1 - the alt text of the image that can be viewed\n----\n“Zero 
rated mobile access only displays text. For images, the value of the \"alt\" 
[text] attribute is displayed. In case a user may want to the see images, they 
can click a link, but data charges may then apply. That's the complete 
context.” [[Thread:Support/About 
MediaWiki:Zero-rated-mobile-access-click-to-view-image/en/reply|Siebrand‎ – 
14:04, 27 February 2012]]",
        "zero-dismiss-notification": "Text for dismissing banner on top of 
screen",
        "zero-config-name": "Aמn error message shown when the \"name\" 
parameter is invalid. Parameters:\n* $1 - field name\n{{Related|Zeroconfig}}",
diff --git a/includes/PageRendering.php b/includes/PageRendering.php
index d20b6ad..1cc8ce1 100644
--- a/includes/PageRendering.php
+++ b/includes/PageRendering.php
@@ -367,7 +367,7 @@
                        $urlJsBanner = self::getSpecial()->getLocalURL( $query 
);
 
                        $script = Html::linkedScript( $urlJsBanner );
-                       $noScript = self::renderBannerImgTag( $isFilePage );
+                       $noScript = self::renderBannerImgTag( $isFilePage, 
null, $this->isHttps(), $this->isZeroSubdomain() );
 //                     $noScript =
 //                             Html::rawElement( 'a', array( 'href' => 
self::getSpecial()->getLinkURL( 'info=1' ) ),
 //                                     $noScript );
@@ -395,9 +395,11 @@
         * Render <img> tag for the Zero image banner
         * @param bool $isFilePage
         * @param string|null $langCode
+        * @param bool $isHttps
+        * @param bool $isZeroSubdomain
         * @return string
         */
-       public static function renderBannerImgTag( $isFilePage, $langCode = 
null ) {
+       public static function renderBannerImgTag( $isFilePage, $langCode, 
$isHttps = false, $isZeroSubdomain = false ) {
                $query = array( 'zcmd' => 'img-banner' );
                if ( $isFilePage ) {
                        $query['zfile'] = '1';
@@ -406,7 +408,39 @@
                        $query['zlang'] = $langCode;
                }
                $url = self::getSpecial()->getLocalURL( $query );
-               return Html::rawElement( 'img', array( 'src' => $url ) );
+               $html = Html::rawElement( 'img', array( 'src' => $url ) );
+               // We know that HTTPS and zerodot are more likely to be risky 
on <noscript> devices,
+               // so we give the user a bouncing point. zerodot webroot 
handles things well enough.
+               //     zerodot not in site list, mdot in sites list: redirects 
to an mdot page
+               //     zerodot in the site list: redirects the user to a 
zero-rated zerodot page;
+               //         note that if the user is on zerodot on HTTPS with a 
<noscript> device, it's
+               //         surprising because there really aren't many entry 
points into zerodot
+               //         on HTTPS. So kicking the user to HTTP on zerodot 
should be rare.
+               //     user not on a zero-rated operator: user gets page 
linking to mdot main page.
+               //
+               // If we examine the cases for the if() below, we can reason as 
follows.
+               // 1. isHttps, isZeroSubdomain w/ <noscript>: rare.
+               // 2. isHttps, !isZeroSubdomain w/<noscript> : rare (slightly 
more common).
+               // 3. !isHttps, isZeroSubdomain w/<noscript>: rare, but if the 
user taps the banner user gets landing page
+               //    with a search box or ends up at the main page. No harm 
done, almost a nice feature.
+               // 4. !isHttps, !isZeroSubdomain w/<noscript>: this is going to 
be a 1x1 pixel, so no point linking.
+               //
+               // This is simpler than growing the cache per-operator (no!) or 
putting some sort of complicated
+               // parameter trying to help us intuit the user's intention
+
+               if ( $isHttps || $isZeroSubdomain ) {
+                       // We probably don't need the project from the 
(instance) getWikiInfo() method because
+                       // (a) we're not expanding zerodot to sister projects, 
and
+                       // (b) if the user is on a <noscript> device on an 
HTTPS connection to a sister
+                       // project, sending the user to zero.wikipedia.org/ 
could be considered a feature
+                       // of the clickable banner (e.g., if I click here, it 
gets me to a landing/homepage).
+                       global $wgZeroBannerClusterDomain;
+                       $html = Html::rawElement( 'a',
+                               array( 'href' => 
"http://zero.wikipedia.$wgZeroBannerClusterDomain/";),
+                               $html );
+
+               }
+               return $html;
        }
 
        /**
@@ -1105,7 +1139,9 @@
         * @return bool
         */
        public function isHttps() {
-               return $this->getRequest()->getProtocol() === 'https';
+               // it's handy to have the $isHttps variable here for local 
debug simulation of HTTPS
+               $isHttps = $this->getRequest()->getProtocol() === 'https';
+               return $isHttps;
        }
 
        /**
diff --git a/includes/ZeroConfig.php b/includes/ZeroConfig.php
index 52fa8f1..f1aab04 100644
--- a/includes/ZeroConfig.php
+++ b/includes/ZeroConfig.php
@@ -194,6 +194,10 @@
                return $this->config->enableHttps;
        }
 
+       public function showHttpsDowngrade() {
+               return $this->config->showHttpsDowngrade;
+       }
+
        public function ipsetNames() {
                return $this->config->ipsets;
        }
@@ -319,6 +323,8 @@
                                $this->test( array( 'configs', $k, 
'whitelistedLangs' ), self::getWhitelistedLangsValidator() );
                                $this->test( array( 'configs', $k, 'proxies' ), 
self::getProxiesValidator() );
                                $this->testOptional( array( 'configs', $k, 
'enableHttps' ), false, $isBool );
+                               // If we'll show HTTPS-to-HTTP downgrades, when 
user is on HTTPS and HTTPS isn't zero-rated
+                               $this->testOptional( array( 'configs', $k, 
'showHttpsDowngrade' ), false, $isBool );
                                $this->testOptional( array( 'configs', $k, 
'disableApps' ), false, $isBool );
                                $this->testOptional( array( 'configs', $k, 
'bannerWarning' ), false, $isBool );
                        }
diff --git a/includes/ZeroSpecialPage.php b/includes/ZeroSpecialPage.php
index ad8ca1a..c821621 100644
--- a/includes/ZeroSpecialPage.php
+++ b/includes/ZeroSpecialPage.php
@@ -392,6 +392,9 @@
                        //
                        $response->header( 'Content-type: 
application/javascript; charset=UTF-8' );
                        $banner = '';
+                       // Even with Apache/Varnish redirects to HTTPS, this is 
fine, because
+                       // the Special:ZRMA URL from getStartPageUrl does not 
itself call back
+                       // into this js-banner endpoint, thereby avoiding 
recursive redirects.
                        if ( $state->isZeroSubdomain() && 
!$state->getZeroConfig() ) {
                                // If zerodot isn't supported here and the user 
isn't already on
                                // Special:ZeroRatedMobileAccess, send the user 
to Special:ZeroRatedMobileAccess
@@ -401,15 +404,22 @@
                                $url = $state->getStartPageUrl( $info[0], 
$flags );
                                $banner = 
"window.location='$url?from='+encodeURIComponent(window.location)";
                        } else {
-                               $config = $state->getZeroConfig();
-                               if ( $config && $config->enabled() ) {
-                                       $bannerHtml = 
PageRendering::renderBanner( $state, $config, null, null, $isFilePage );
-                                       $cfg = PageRendering::getJsConfigBlock( 
$this, $id, $config, (bool)$bannerHtml );
+                               $config = $state->getZeroConfig( 
ZeroConfig::ignoreHttps );
+                               // note we set the ZeroConfig::ignoreHttps flag 
above, so we need to take that into account for banners
+                               $httpsCausesCharge = $config && 
$state->isHttps() && !$config->enableHttps();
+                               $configForBanner = $httpsCausesCharge ? null : 
$config;
+                               if ( $configForBanner ) {
+                                       $bannerHtml = 
PageRendering::renderBanner( $state, $configForBanner, null, null, $isFilePage 
);
+                                       $cfg = PageRendering::getJsConfigBlock( 
$this, $id, $configForBanner, (bool)$bannerHtml );
                                        if ( $bannerHtml ) {
                                                $banner = 'document.write(' . 
Xml::encodeJsVar( $bannerHtml ) . ');';
                                        }
                                } else {
-                                       $cfg = PageRendering::getJsConfigBlock( 
$this, $id, $config, false );
+                                       if ( $config && 
$config->showHttpsDowngrade() ) {
+                                               $banner = 'document.write(' . 
Xml::encodeJsVar( self::renderHttpsDowngrade() ) . ');';
+                               }
+                                       // Note we use the banner config 
variable instead of the HTTPS-ignoreing one
+                                       $cfg = PageRendering::getJsConfigBlock( 
$this, $id, $configForBanner, false );
                                }
                                $banner = $cfg . $banner;
                        }
@@ -421,14 +431,29 @@
                        $lang = $this->getRequest()->getVal( 'zlang' );
                        // If lang was given (showing in the portal), ignore 
everything except language
                        $config =
-                               $state->getZeroConfig( $lang ? ( 
ZeroConfig::ignoreNetwork | ZeroConfig::ignoreDisabled |
-                                                                
ZeroConfig::ignoreHttps | ZeroConfig::ignoreSite ) : 0 );
-                       $text = PageRendering::getBannerText( $config, 
$isFilePage, $lang );
+                               $state->getZeroConfig( $lang
+                                       ? ( ZeroConfig::ignoreNetwork | 
ZeroConfig::ignoreDisabled |
+                                               ZeroConfig::ignoreHttps | 
ZeroConfig::ignoreSite )
+                                       : ZeroConfig::ignoreHttps );
+
+                       // note we set the ZeroConfig::ignoreHttps flag above, 
so we need to take that into account for banners
+                       $httpsCausesCharge = $config && $state->isHttps() && 
!$config->enableHttps();
+                       $text = false;
+                       if ( $httpsCausesCharge && !$lang ) {
+                               $text = PageRendering::getBannerText( $config, 
$isFilePage, $lang );
+                       }
                        $banner = false;
                        if ( $text ) {
+                               // implicitly, the configuration was valid
                                $banner = self::createImageBanner( 
$config->background(), $config->foreground(), $text );
                                $errors = !$banner;
+                       } elseif ( $httpsCausesCharge && 
$config->showHttpsDowngrade() ) {
+                               // the configuration would have been valid if 
it were on http:// cleartext
+                               // TODO: look at the user's cookies to see if 
the user doesn't care about charges?
+                               // TODO: replicate for JavaScript devices
+                               $banner = self::createImageBanner( 'gainsboro', 
'black', $this->msg( 'zero-https-http' )->text(), true );
                        } elseif ( $state->isZeroSubdomain() ) {
+                               // the configuration only would have been valid 
if it wasn't on zerodot
                                $host = implode( '.', $state->getWikiInfo() );
                                $bannerText = $this->msg( 'zero-sorry', $host 
)->text() . "\n\n";
 
@@ -455,6 +480,39 @@
                return true;
        }
 
+       private static function renderHttpsDowngrade() {
+               global $wgLang;
+
+               $dismiss = Html::rawElement(
+                       'button',
+                       array( 'class' => 'notify-close mw-mf-banner-gray',
+                                  'title' => wfMessage( 
'zero-dismiss-notification' )->escaped() ),
+                       Html::rawElement(
+                               'span',
+                               array( 'class' => 'notify-close-x 
notify-close-x-downgrade mw-mf-banner-gray'),
+                               '&#120;'
+                       )
+               );
+
+               $banner = Html::rawElement(
+                       'span',
+                       array( 'id' => 'zero-rated-banner-downgrade', 'class' 
=> 'mw-mf-message mw-mf-banner-gray' ),
+                       Html::rawElement( 'span',
+                               array(
+                                       'id' => 'zero-rli-click',
+                                       'onClick' => 
"window.ZERODOWNGRADETIMER=setTimeout(function(){window.location='http://'+window.location.hostname+window.location.pathname;},1999)"
+                               ),
+                               wfMessage( 'zero-https-http' )->inLanguage( 
$wgLang )
+                       )
+               );
+
+               return  Html::rawElement(
+                       'div',
+                       array( 'class' => 'mw-mf-banner mw-mf-banner-gray' ),
+                       $dismiss . $banner
+               );
+       }
+
        /**
         * @param WebRequest $request
         * @param int $min
diff --git a/modules/ZeroOverlay.js b/modules/ZeroOverlay.js
index c86b9bf..575325d 100644
--- a/modules/ZeroOverlay.js
+++ b/modules/ZeroOverlay.js
@@ -16,19 +16,22 @@
                ProcessDialog.static.title = mw.msg( 'zero-interstitial-title' 
);
                ProcessDialog.static.actions = [
                        { label: 'X', flags: 'safe' },
-                       { label: mw.msg( 'zero-accept' ), flags: 'primary', 
action: 'open' }
+                       { label: mw.msg( options.accept ), flags: 'primary', 
action: 'open' }
                ];
                ProcessDialog.prototype.initialize = function () {
                        ProcessDialog.super.prototype.initialize.apply( this, 
arguments );
 
                                var tplData = {
                                        dontask: mw.msg( 'zero-dont-ask' ),
-                                       warning: mw.msg( options.image ? 
'zero-file-auth' : 'zero-charge-auth' )
+                                       warning: mw.msg( options.warn )
                                };
 
                        $.extend(tplData, options);
 
-                       var content = mw.template.get( 'zerobanner', 
'interstitial.hogan' ).render( tplData );
+                       var content = mw.template.get(
+                               'zerobanner',
+                               options.alwaysAsk ? 'interstitialask.hogan' : 
'interstitial.hogan'
+                       ).render( tplData );
 
                        this.$body.append( content );
                        $('#zerodontask').on( 'click', function () {
@@ -47,7 +50,8 @@
                        return 
ProcessDialog.super.prototype.getTeardownProcess.call( this, data )
                                .first( function () {
                                        if ( 
window.location.hash.indexOf('#/zerosite') > -1 ||
-                                               
window.location.hash.indexOf('#/zerofile') > -1 ) {
+                                               
window.location.hash.indexOf('#/zerofile') > -1 ||
+                                               
window.location.hash.indexOf('#/zerodowngrade') > -1 ) {
                                                history.replaceState('', 
document.title, window.location.pathname + location.search);
                                        }
                                }, this );
@@ -65,10 +69,18 @@
        };
 
        M.router.route( /^\/zerosite\/(.*)/, function( url ) {
-               return new ZeroOverlay( { url: url, image: false } );
+               return new ZeroOverlay( { url: url, warn: 'zero-charge-auth', 
accept: 'zero-accept' } );
        } );
        M.router.route( /^\/zerofile\/(.*)/, function( url ) {
-               return new ZeroOverlay( { url: url, image: true } );
+               return new ZeroOverlay( { url: url, warn: 'zero-file-auth', 
accept: 'zero-accept' } );
+       } );
+       M.router.route( /^\/zerodowngrade\//, function() {
+               return new ZeroOverlay( {
+                       url: 'http://' + window.location.hostname + 
window.location.pathname,
+                       warn: 'zero-https-http-extended',
+                       alwaysAsk: true,
+                       accept: 'zero-http'
+               } );
        } );
 
        M.define( 'ZeroOverlay', ZeroOverlay );
diff --git a/modules/banner.css b/modules/banner.css
index 704be35..10103be 100644
--- a/modules/banner.css
+++ b/modules/banner.css
@@ -19,8 +19,14 @@
        white-space: normal !important;
        font-family: Tahoma, sans-serif;
 }
+.mw-mf-banner-gray {
+       color: #000000 !important;
+       background: #DCDCDC !important;
+       font-weight: normal;
+}
 .mw-mf-banner .mw-mf-message,
-.mw-mf-banner button {
+.mw-mf-banner button,
+.mw-mf-banner-gray button {
        padding-top: 10px;
        padding-bottom: 10px;
 }
@@ -54,6 +60,11 @@
        width: 1.3em;
        line-height: 0.6;
 }
+
+.mw-mf-banner span.notify-close-x-downgrade {
+       border: 2px solid #000000 !important;
+}
+
 .mw-mf-banner p {
        line-height: normal;
 }
diff --git a/modules/interstitial.js b/modules/interstitial.js
index 7272a36..0c57e80 100644
--- a/modules/interstitial.js
+++ b/modules/interstitial.js
@@ -62,6 +62,15 @@
                        } );
                }
 
+               if ( config ) {
+                       $( '#zero-rated-banner-downgrade, #zero-rli-click' 
).on( 'click', function ( ev ) {
+                               ev.preventDefault();
+                               clearTimeout( window.ZERODOWNGRADETIMER );
+                               M.require( 'ZeroOverlay' );
+                               window.location.hash = '#/zerodowngrade/';
+                       } );
+               }
+
                // Disable other click event handlers for images/thumbnails, 
for example, the
                // mobile media viewer.
                // FIXME: Figure out a less fragile way to handle this
diff --git a/templates/interstitialask.hogan b/templates/interstitialask.hogan
new file mode 100644
index 0000000..452e812
--- /dev/null
+++ b/templates/interstitialask.hogan
@@ -0,0 +1,3 @@
+<div class="content">
+       <p>{{warning}}</p>
+</div>
\ No newline at end of file

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I91aa173f915310cba5de75866b89059d9b8e3d91
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ZeroBanner
Gerrit-Branch: master
Gerrit-Owner: Yurik <yu...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to