Bug 1661756 - Add VPN Card and Banner r=prathiksha,flod,nhnt11

Differential Revision: https://phabricator.services.mozilla.com/D88633
This commit is contained in:
Erica Wright 2020-09-23 17:55:50 +00:00
parent 98201431da
commit 39db0a2518
21 changed files with 995 additions and 27 deletions

View File

@ -49,6 +49,16 @@ const SCOPE_MONITOR = [
"https://identity.mozilla.com/apps/monitor",
];
const SCOPE_VPN = "profile https://identity.mozilla.com/account/subscriptions";
const VPN_ENDPOINT = `${Services.prefs.getStringPref(
"identity.fxaccounts.auth.uri"
)}oauth/subscriptions/active`;
// The ID of the vpn subscription, if we see this ID attached to a user's account then they have subscribed to vpn.
const VPN_SUB_ID = Services.prefs.getStringPref(
"browser.contentblocking.report.vpn_sub_id"
);
// Error messages
const INVALID_OAUTH_TOKEN = "Invalid OAuth token";
const USER_UNSUBSCRIBED_TO_MONITOR = "User is not subscribed to Monitor";
@ -301,6 +311,57 @@ class AboutProtectionsParent extends JSWindowActorParent {
);
}
async VPNSubStatus() {
// For testing, set vpn sub status manually
if (gTestOverride && "vpnOverrides" in gTestOverride) {
return gTestOverride.vpnOverrides().hasSubscription;
}
const vpnToken = await fxAccounts.getOAuthToken({ scope: SCOPE_VPN });
let headers = new Headers();
headers.append("Authorization", `Bearer ${vpnToken}`);
const request = new Request(VPN_ENDPOINT, { headers });
const res = await fetch(request);
if (res.ok) {
const result = await res.json();
for (let sub of result) {
if (sub.subscriptionId == VPN_SUB_ID) {
return true;
}
}
return false;
}
// there was an error, assume user is not subscribed to VPN
return false;
}
// VPN shows if we are in a supported region and supported languages
// VPN does not show in China - VPNs are illegal there, this is a requirement to hardcode, and not use in a pref.
VPNShouldShow() {
let currentRegion = "";
if (gTestOverride && "vpnOverrides" in gTestOverride) {
currentRegion = gTestOverride.vpnOverrides().location;
} else {
// The region we have detected the user to be in
// We cannot run this in tests due to it using a request
currentRegion = Region.current ? Region.current.toLowerCase() : "";
}
// The region that the user has set as their home region
const homeRegion = Region.home.toLowerCase() || "";
const regionsWithVPN = Services.prefs.getStringPref(
"browser.contentblocking.report.vpn_regions"
);
const language = Services.locale.appLocaleAsBCP47;
return (
currentRegion != "cn" &&
homeRegion != "cn" &&
regionsWithVPN.includes(currentRegion) &&
language.includes("en-")
);
}
async receiveMessage(aMessage) {
let win = this.browsingContext.top.embedderElement.ownerGlobal;
switch (aMessage.name) {
@ -386,6 +447,12 @@ class AboutProtectionsParent extends JSWindowActorParent {
case "FetchEntryPoint":
return entrypoint;
case "FetchVPNSubStatus":
return this.VPNSubStatus();
case "FetchShowVPNCard":
return this.VPNShouldShow();
}
return undefined;

View File

@ -1699,6 +1699,15 @@ pref("browser.contentblocking.report.proxy.enabled", false);
// Disable the mobile promotion by default.
pref("browser.contentblocking.report.show_mobile_app", true);
// Enable the vpn card by default.
pref("browser.contentblocking.report.vpn.enabled", true);
// Only show vpn card to certain regions. Comma separated string of two letter ISO 3166-1 country codes.
pref("browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb");
// Comma separated string of mozilla vpn supported platforms.
pref("browser.contentblocking.report.vpn_platforms", "win");
pref("browser.contentblocking.report.hide_vpn_banner", false);
pref("browser.contentblocking.report.vpn_sub_id", "sub_HrfCZF7VPHzZkA");
pref("browser.contentblocking.report.monitor.url", "https://monitor.firefox.com/?entrypoint=protection_report_monitor&utm_source=about-protections");
pref("browser.contentblocking.report.monitor.how_it_works.url", "https://monitor.firefox.com/about");
pref("browser.contentblocking.report.monitor.sign_in_url", "https://monitor.firefox.com/oauth/init?entrypoint=protection_report_monitor&utm_source=about-protections&email=");
@ -1711,6 +1720,10 @@ pref("browser.contentblocking.report.lockwise.mobile-ios.url", "https://apps.app
pref("browser.contentblocking.report.lockwise.mobile-android.url", "https://play.google.com/store/apps/details?id=mozilla.lockbox&referrer=utm_source%3Dprotection_report%26utm_content%3Dmobile_promotion");
pref("browser.contentblocking.report.mobile-ios.url", "https://apps.apple.com/app/firefox-private-safe-browser/id989804926");
pref("browser.contentblocking.report.mobile-android.url", "https://play.google.com/store/apps/details?id=org.mozilla.firefox&referrer=utm_source%3Dprotection_report%26utm_content%3Dmobile_promotion");
pref("browser.contentblocking.report.vpn.url", "https://vpn.mozilla.org/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=about-protections-card");
pref("browser.contentblocking.report.vpn-promo.url", "https://vpn.mozilla.org/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=about-protections-top-promo");
pref("browser.contentblocking.report.vpn-android.url", "https://play.google.com/store/apps/details?id=org.mozilla.firefox.vpn&referrer=utm_source%3Dfirefox-browser%26utm_medium%3Dfirefox-browser%26utm_campaign%3Dabout-protections-mobile-vpn%26anid%3D--");
pref("browser.contentblocking.report.vpn-ios.url", "https://apps.apple.com/us/app/firefox-private-network-vpn/id1489407738");
// Protection Report's SUMO urls
pref("browser.contentblocking.report.lockwise.how_it_works.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/password-manager-report");

View File

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="192" height="192" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M96 21.6c-7.953 0-14.4 6.447-14.4 14.4S88.047 50.4 96 50.4s14.4-6.447 14.4-14.4-6.447-14.4-14.4-14.4zM62.4 36C62.4 17.443 77.443 2.4 96 2.4c18.557 0 33.6 15.043 33.6 33.6 0 18.557-15.043 33.6-33.6 33.6a33.45 33.45 0 01-15.985-4.039L65.561 80.015A33.397 33.397 0 0168.21 86.4h55.582c4.131-13.88 16.988-24 32.209-24 18.557 0 33.6 15.043 33.6 33.6 0 18.557-15.043 33.6-33.6 33.6a33.452 33.452 0 01-15.985-4.039l-14.454 14.454A33.452 33.452 0 01129.6 156c0 18.557-15.043 33.6-33.6 33.6-18.557 0-33.6-15.043-33.6-33.6 0-18.557 15.043-33.6 33.6-33.6a33.452 33.452 0 0115.985 4.039l14.454-14.454a33.37 33.37 0 01-2.648-6.385H68.209c-4.131 13.879-16.988 24-32.209 24-18.557 0-33.6-15.043-33.6-33.6 0-18.557 15.043-33.6 33.6-33.6a33.45 33.45 0 0115.985 4.039l14.454-14.454A33.45 33.45 0 0162.4 36zm19.2 120c0-7.953 6.447-14.4 14.4-14.4s14.4 6.447 14.4 14.4-6.447 14.4-14.4 14.4-14.4-6.447-14.4-14.4zM36 81.6c-7.953 0-14.4 6.447-14.4 14.4s6.447 14.4 14.4 14.4 14.4-6.447 14.4-14.4S43.953 81.6 36 81.6zM141.6 96c0-7.953 6.447-14.4 14.4-14.4s14.4 6.447 14.4 14.4-6.447 14.4-14.4 14.4-14.4-6.447-14.4-14.4z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="188" height="188" xmlns="http://www.w3.org/2000/svg">
<path d="M94 19.6c-7.953 0-14.4 6.447-14.4 14.4S86.047 48.4 94 48.4s14.4-6.447 14.4-14.4-6.447-14.4-14.4-14.4zM60.4 34C60.4 15.443 75.443.4 94 .4c18.557 0 33.6 15.043 33.6 33.6 0 18.557-15.043 33.6-33.6 33.6a33.45 33.45 0 01-15.985-4.039L63.561 78.015A33.397 33.397 0 0166.21 84.4h55.582c4.131-13.88 16.988-24 32.209-24 18.557 0 33.6 15.043 33.6 33.6 0 18.557-15.043 33.6-33.6 33.6a33.452 33.452 0 01-15.985-4.039l-14.454 14.454A33.452 33.452 0 01127.6 154c0 18.557-15.043 33.6-33.6 33.6-18.557 0-33.6-15.043-33.6-33.6 0-18.557 15.043-33.6 33.6-33.6a33.452 33.452 0 0115.985 4.039l14.454-14.454a33.37 33.37 0 01-2.648-6.385H66.209c-4.131 13.879-16.988 24-32.209 24C15.443 127.6.4 112.557.4 94 .4 75.443 15.443 60.4 34 60.4a33.45 33.45 0 0115.985 4.039l14.454-14.454A33.45 33.45 0 0160.4 34zm19.2 120c0-7.953 6.447-14.4 14.4-14.4s14.4 6.447 14.4 14.4-6.447 14.4-14.4 14.4-14.4-6.447-14.4-14.4zM34 79.6c-7.953 0-14.4 6.447-14.4 14.4s6.447 14.4 14.4 14.4 14.4-6.447 14.4-14.4S41.953 79.6 34 79.6zM139.6 94c0-7.953 6.447-14.4 14.4-14.4s14.4 6.447 14.4 14.4-6.447 14.4-14.4 14.4-14.4-6.447-14.4-14.4z" fill="#000" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -22,6 +22,7 @@ const kESModuleList = new Set([
/browser\/lockwise-card.js$/,
/browser\/monitor-card.js$/,
/browser\/proxy-card.js$/,
/browser\/vpn-card.js$/,
/toolkit\/content\/global\/certviewer\/components\/.*\.js$/,
/toolkit\/content\/global\/certviewer\/.*\.js$/,
]);

View File

@ -22,6 +22,8 @@ browser.jar:
content/browser/logos/send.svg (content/logos/send.svg)
content/browser/logos/tracking-protection.svg (content/logos/tracking-protection.svg)
content/browser/logos/tracking-protection-dark-theme.svg (content/logos/tracking-protection-dark-theme.svg)
content/browser/logos/vpn-dark.svg (content/logos/vpn-dark.svg)
content/browser/logos/vpn-light.svg (content/logos/vpn-light.svg)
content/browser/aboutNetErrorCodes.js (content/aboutNetErrorCodes.js)
content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml)
content/browser/aboutNetError.js (content/aboutNetError.js)

View File

@ -33,10 +33,10 @@
--gear-icon-fill: var(--grey-90-a60);
--hover-grey-link: var(--grey-70);
--feature-banner-color: rgba(0, 0, 0, 0.05);
}
body {
margin-block: 40px 80px;
box-sizing: border-box;
}
@ -85,9 +85,11 @@ h2 {
#report-content {
width: 763px;
margin: 0 auto;
margin-block: 40px 80px;
}
.card-header .wrapper {
.card-header .wrapper,
.new-banner .wrapper {
display: grid;
grid-template-columns: repeat(7, 1fr);
align-items: center;
@ -97,6 +99,8 @@ h2 {
.card-header > button,
#save-passwords-button,
#get-proxy-extension-link,
#get-vpn-link,
#vpn-banner-link,
#manage-passwords-button,
#sign-up-for-monitor-link {
grid-area: 1 / 5 / 1 / -1;
@ -108,6 +112,15 @@ h2 {
line-height: initial;
}
#vpn-banner-link {
grid-area: 1 / 6 / 1 / -1;
}
.new-banner .wrapper div:nth-child(1) {
grid-area: 1 / 1 / 1 / 6;
padding-inline-end: 15px;
}
.lockwise-card.has-logins .wrapper div:nth-child(1) {
grid-area: 1 / 1 / 1 / 6;
}
@ -126,6 +139,11 @@ h2 {
grid-area: 1 / 1 / 1 / -1;
}
.vpn-card.subscribed .wrapper div:nth-child(1) {
padding-inline-end: 29px;
grid-area: 1 / 1 / 1 / 7;
}
/* We want to hide certain components depending on its state. */
.no-logins .monitor-scanned-wrapper,
.etp-card.custom-not-blocking .card-body,
@ -133,6 +151,8 @@ h2 {
#manage-protections,
.etp-card .icon.dark,
.proxy-card .icon.dark,
.vpn-card .icon.dark,
.vpn-banner .icon.dark,
a.hidden,
.loading .card-body,
.lockwise-card.hidden,
@ -156,6 +176,7 @@ a.hidden,
.loading button,
.loading .wrapper,
.proxy-card.hidden,
.vpn-card.hidden,
.card-body.hidden,
.hidden {
display: none;
@ -169,6 +190,15 @@ a.hidden,
z-index: 1;
}
.vpn-card .icon {
width: 56px;
height: 56px;
}
.new-banner .icon {
width: 50px;
height: 50px;
}
@media (prefers-color-scheme: dark) {
:root {
@ -179,16 +209,21 @@ a.hidden,
--cryptominer-highlight-color: #BEBECA;
--gear-icon-fill: rgba(249, 249, 250, 0.60);
--hover-grey-link: var(--grey-30)
--hover-grey-link: var(--grey-30);
--feature-banner-color: rgba(255, 255, 255, 0.1);
}
.etp-card .icon.dark,
.proxy-card .icon.dark {
.proxy-card .icon.dark,
.vpn-card .icon.dark,
.vpn-banner .icon.dark {
display: block;
}
.etp-card .icon.light,
.proxy-card .icon.light {
.proxy-card .icon.light,
.vpn-card .icon.light,
.vpn-banner .icon.light {
display: none;
}
}
@ -658,7 +693,7 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
.lockwise-scanned-wrapper {
display: grid;
grid-template-columns: 7% auto;
grid-template-columns: 24px auto;
margin-block-start: 24px;
grid-area: 2 / 1 / 2 / 5;
padding-bottom: 1.7em;
@ -677,6 +712,18 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
margin-inline-end: 15px;
}
.vpn-card.subscribed #get-vpn-link {
display: none;
}
.vpn-card:not(.subscribed) .content.subscribed {
display: none;
}
.vpn-card.subscribed .content:not(.subscribed) {
display: none;
}
/* Monitor card */
.monitor-info-wrapper {
display: grid;
@ -947,6 +994,8 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
#manage-protections,
#sign-up-for-monitor-link,
#get-proxy-extension-link,
#get-vpn-link,
#vpn-banner-link,
.monitor-partial-breaches-link-wrapper,
.monitor-breaches-link-wrapper {
background-color: var(--in-content-primary-button-background);
@ -959,6 +1008,8 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
#manage-protections:active,
#sign-up-for-monitor-link:active,
#get-proxy-extension-link:active,
#get-vpn-link:active,
#vpn-banner-link:active,
#monitor-partial-breaches-link:active,
#monitor-breaches-link:active {
background-color: var(--in-content-primary-button-background-active);
@ -967,6 +1018,8 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
#manage-protections:hover,
#sign-up-for-monitor-link:hover,
#get-proxy-extension-link:hover,
#get-vpn-link:hover,
#vpn-banner-link:hover,
#monitor-partial-breaches-link:hover,
#monitor-breaches-link:hover {
background-color: var(--in-content-primary-button-background-hover);
@ -975,6 +1028,8 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
#manage-protections:focus,
#sign-up-for-monitor-link:focus,
#get-proxy-extension-link:focus,
#get-vpn-link:focus,
#vpn-banner-link:focus,
#monitor-partial-breaches-link:focus,
.monitor-block > a:focus,
#monitor-breaches-link:focus {
@ -1025,3 +1080,54 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
opacity: 0.02;
}
}
.new-banner {
width: 100%;
background: var(--feature-banner-color);
}
.banner-wrapper {
width: 763px;
display: grid;
grid-template-columns: 1fr 7fr;
grid-gap: var(--card-padding);
line-height: 1.3em;
margin: 0 auto;
padding: 12px var(--card-padding);
}
.new-banner .banner-title {
margin: 0;
line-height: 1.25;
cursor: default;
font-size: inherit;
}
.new-banner .content {
margin-block: 5px 0;
font-size: 0.88em;
cursor: default;
color: var(--in-content-deemphasized-text);
}
.new-banner .exit-icon {
top: auto;
inset-inline-end: 30px;
}
.vpn-card .title-wrapper {
display: grid;
grid-template-columns: 24px auto;
}
.vpn-card:not(.subscribed) .card-title {
grid-area: 1 / 1 / 1 / -1;
}
.vpn-card.subscribed .card-title {
margin-inline-start: 3px;
}
.vpn-card:not(.subscribed) #check-icon {
display: none;
}

View File

@ -11,3 +11,16 @@
proxy-title = Stay safe on public Wi-Fi
proxy-header-content = { -secure-proxy-brand-name } makes wireless hotspots more secure to protect you from hackers.
get-proxy-extension-link = Get the Extension
vpn-title = Take privacy protections beyond the browser
vpn-header-content = Protect your entire device with { -mozilla-vpn-brand-name }. One tap encrypts all traffic and hides your location.
get-vpn-link = Get { -mozilla-vpn-brand-name }
vpn-title-subscribed = VPN: Subscribed
# Note This text is not being translated, and the <br> will need to be removed if or when it does get translated
vpn-header-content-subscribed = Using the { -mozilla-vpn-brand-name } encrypts all your traffic and hides your location — on up to 5 devices. Get the most from your subscription — add it from <br> the <a data-l10n-name="vpn-google-playstore-link">Google Play Store</a> or <a data-l10n-name="vpn-app-store-link">Apple App Store</a>.
vpn-banner-header = Protection that extends beyond the browser
# Note This text is not being translated, and the <br> will need to be removed if or when it does get translated
vpn-banner-content = Try { -mozilla-vpn-brand-name } risk-free and see why TechRadar says <br> “its speed, simplicity and low monthly price make it worth a look.”
vpn-banner-link = Get { -mozilla-vpn-brand-name }

View File

@ -20,10 +20,25 @@
<script type="module" src="chrome://browser/content/lockwise-card.js"></script>
<script type="module" src="chrome://browser/content/monitor-card.js"></script>
<script type="module" src="chrome://browser/content/proxy-card.js"></script>
<script type="module" src="chrome://browser/content/vpn-card.js"></script>
<title data-l10n-id="protection-report-webpage-title"></title>
</head>
<body>
<div class="new-banner vpn-banner hidden">
<div class=banner-wrapper>
<img class="icon light" src="chrome://browser/content/logos/vpn-light.svg"/>
<img class="icon dark" src="chrome://browser/content/logos/vpn-dark.svg"/>
<div class="wrapper">
<div>
<h3 class="banner-title" data-l10n-id="vpn-banner-header"></h3>
<span class="content" data-l10n-id="vpn-banner-content"></span>
</div>
<a target="_blank" id="vpn-banner-link" data-l10n-id="get-vpn-link"></a>
<button class="exit-icon" data-l10n-id="protections-close-button2"></button>
</div>
</div>
</div>
<div id="report-content">
<h1 id="report-title" data-l10n-id="protection-report-page-content-title"></h1>
<p id="report-summary" data-l10n-id="protection-report-page-summary-default"></p>
@ -287,6 +302,27 @@
</div>
</div>
</section>
<section class="card card-no-hover vpn-card hidden">
<div class="card-header">
<img class="icon light" src="chrome://browser/content/logos/vpn-light.svg"/>
<img class="icon dark" src="chrome://browser/content/logos/vpn-dark.svg"/>
<div class="wrapper">
<div>
<div class="title-wrapper">
<img id="check-icon" src="chrome://browser/skin/protections/resolved-breach.svg">
<h3 class="card-title" data-l10n-id="vpn-title"></h3>
</div>
<p class="content" data-l10n-id="vpn-header-content"></p>
<p class="content subscribed" data-l10n-id="vpn-header-content-subscribed">
<a target="_blank" id="vpn-google-playstore-link" data-l10n-name="vpn-google-playstore-link"></a>
<a target="_blank" id="vpn-app-store-link" data-l10n-name="vpn-app-store-link"></a>
</p>
</div>
<a target="_blank" id="get-vpn-link" data-l10n-id="get-vpn-link"></a>
</div>
</div>
</section>
</div>
</body>
</html>

View File

@ -7,6 +7,7 @@
import LockwiseCard from "./lockwise-card.js";
import MonitorCard from "./monitor-card.js";
import ProxyCard from "./proxy-card.js";
import VPNCard from "./vpn-card.js";
let cbCategory = RPMGetStringPref("browser.contentblocking.category");
document.sendTelemetryEvent = (action, object, value = "") => {
@ -480,4 +481,16 @@ document.addEventListener("DOMContentLoaded", e => {
// For tests
const proxyUI = document.querySelector(".proxy-card");
proxyUI.dataset.enabled = proxyEnabled;
const VPNEnabled = RPMGetBoolPref(
"browser.contentblocking.report.vpn.enabled",
true
);
if (VPNEnabled) {
const vpnCard = new VPNCard(document);
vpnCard.init();
}
// For tests
const vpnUI = document.querySelector(".vpn-card");
vpnUI.dataset.enabled = VPNEnabled;
});

View File

@ -0,0 +1,116 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env mozilla/frame-script */
export default class VPNCard {
constructor(document) {
this.doc = document;
}
init() {
const vpnLink = this.doc.getElementById("get-vpn-link");
const vpnBannerLink = this.doc.getElementById("vpn-banner-link");
vpnLink.href = RPMGetStringPref(
"browser.contentblocking.report.vpn.url",
""
);
vpnBannerLink.href = RPMGetStringPref(
"browser.contentblocking.report.vpn-promo.url",
""
);
vpnLink.addEventListener("click", () => {
this.doc.sendTelemetryEvent("click", "vpn_card_link");
});
let androidVPNAppLink = document.getElementById(
"vpn-google-playstore-link"
);
androidVPNAppLink.href = RPMGetStringPref(
"browser.contentblocking.report.vpn-android.url"
);
androidVPNAppLink.addEventListener("click", () => {
document.sendTelemetryEvent("click", "vpn_app_link_android");
});
let iosVPNAppLink = document.getElementById("vpn-app-store-link");
iosVPNAppLink.href = RPMGetStringPref(
"browser.contentblocking.report.vpn-ios.url"
);
iosVPNAppLink.addEventListener("click", () => {
document.sendTelemetryEvent("click", "vpn_app_link_ios");
});
const vpnBanner = this.doc.querySelector(".vpn-banner");
const exitIcon = vpnBanner.querySelector(".exit-icon");
vpnBannerLink.addEventListener("click", () => {
this.doc.sendTelemetryEvent("click", "vpn_banner_link");
});
// User has closed the vpn banner, hide it.
exitIcon.addEventListener("click", () => {
vpnBanner.classList.add("hidden");
this.doc.sendTelemetryEvent("click", "vpn_banner_close");
});
this.showVPNCard();
}
// Show the VPN card if user is located in areas, and on platforms, it serves
async showVPNCard() {
const showVPNBanner = this.showVPNBanner.bind(this);
RPMSendQuery("FetchShowVPNCard", {}).then(shouldShow => {
if (!shouldShow) {
return;
}
const vpnCard = this.doc.querySelector(".vpn-card");
let availablePlatforms = RPMGetStringPref(
"browser.contentblocking.report.vpn_platforms"
);
let hasSupportedPlatform = false;
for (let platform of availablePlatforms.split(",")) {
if (navigator.platform.toLowerCase().includes(platform)) {
hasSupportedPlatform = true;
break;
}
}
if (!hasSupportedPlatform) {
return;
}
// add 'subscribed' class if user is subscribed to vpn
RPMSendQuery("FetchVPNSubStatus", {}).then(async hasVPN => {
if (hasVPN) {
vpnCard.classList.add("subscribed");
vpnCard
.querySelector(".card-title")
.setAttribute("data-l10n-id", "vpn-title-subscribed");
// hide the promo banner if the user is already subscribed to vpn
await RPMSetBoolPref(
"browser.contentblocking.report.hide_vpn_banner",
true
);
}
vpnCard.classList.remove("hidden");
showVPNBanner();
});
});
}
showVPNBanner() {
if (
RPMGetBoolPref("browser.contentblocking.report.hide_vpn_banner", false) ||
!RPMGetBoolPref("browser.contentblocking.report.vpn.enabled", false)
) {
return;
}
const vpnBanner = this.doc.querySelector(".vpn-banner");
vpnBanner.classList.remove("hidden");
this.doc.sendTelemetryEvent("show", "vpn_banner");
// VPN banner only shows on the first visit, flip a pref so it does not show again.
RPMSetBoolPref("browser.contentblocking.report.hide_vpn_banner", true);
}
}

View File

@ -9,3 +9,4 @@ browser.jar:
content/browser/protections.html (content/protections.html)
content/browser/protections.js (content/protections.js)
content/browser/proxy-card.js (content/proxy-card.js)
content/browser/vpn-card.js (content/vpn-card.js)

View File

@ -10,3 +10,4 @@ support-files =
[browser_protections_proxy.js]
[browser_protections_report_ui.js]
[browser_protections_telemetry.js]
[browser_protections_vpn.js]

View File

@ -13,6 +13,7 @@ add_task(async function setup() {
set: [
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.vpn.enabled", false],
],
});
});

View File

@ -31,7 +31,10 @@ const SQL = {
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.database.enabled", true]],
set: [
["browser.contentblocking.database.enabled", true],
["browser.contentblocking.report.vpn.enabled", false],
],
});
});

View File

@ -10,6 +10,10 @@ XPCOMUtils.defineLazyServiceGetter(
"nsITrackingDBService"
);
XPCOMUtils.defineLazyModuleGetters(this, {
Region: "resource://gre/modules/Region.jsm",
});
const { AboutProtectionsParent } = ChromeUtils.import(
"resource:///actors/AboutProtectionsParent.jsm"
);
@ -46,10 +50,9 @@ requestLongerTimeout(2);
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", true],
["browser.contentblocking.report.monitor.enabled", true],
["browser.contentblocking.report.lockwise.enabled", true],
["browser.contentblocking.report.proxy.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb"],
["browser.contentblocking.report.vpn_platforms", "win"],
// Change the endpoints to prevent non-local network connections when landing on the page.
["browser.contentblocking.report.monitor.url", ""],
["browser.contentblocking.report.monitor.sign_in_url", ""],
@ -64,6 +67,10 @@ add_task(async function setup() {
["browser.contentblocking.report.mobile-android.url", ""],
["browser.contentblocking.report.monitor.home_page_url", ""],
["browser.contentblocking.report.monitor.preferences_url", ""],
["browser.contentblocking.report.vpn.url", ""],
["browser.contentblocking.report.vpn-promo.url", ""],
["browser.contentblocking.report.vpn-android.url", ""],
["browser.contentblocking.report.vpn-ios.url", ""],
],
});
@ -71,16 +78,21 @@ add_task(async function setup() {
Services.telemetry.canRecordExtended = true;
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
// AboutProtectionsParent.setTestOverride(null);
});
});
add_task(async function checkTelemetryLoadEvents() {
// There's an arbitrary interval of 2 seconds in which the content
// processes sync their event data with the parent process, we wait
// this out to ensure that we clear everything that is left over from
// previous tests and don't receive random events in the middle of our tests.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(c => setTimeout(c, 2000));
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", false],
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.proxy.enabled", false],
["browser.contentblocking.report.vpn.enabled", false],
],
});
await addArbitraryTimeout();
// Clear everything.
Services.telemetry.clearEvents();
@ -158,13 +170,26 @@ function waitForTelemetryEventCount(count) {
}, "waiting for telemetry event count of: " + count);
}
add_task(async function checkTelemetryClickEvents() {
let addArbitraryTimeout = async () => {
// There's an arbitrary interval of 2 seconds in which the content
// processes sync their event data with the parent process, we wait
// this out to ensure that we clear everything that is left over from
// previous tests and don't receive random events in the middle of our tests.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(c => setTimeout(c, 2000));
};
add_task(async function checkTelemetryClickEvents() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", true],
["browser.contentblocking.report.monitor.enabled", true],
["browser.contentblocking.report.lockwise.enabled", true],
["browser.contentblocking.report.proxy.enabled", true],
["browser.contentblocking.report.vpn.enabled", false],
],
});
await addArbitraryTimeout();
// Clear everything.
Services.telemetry.clearEvents();
@ -820,12 +845,16 @@ add_task(async function test_save_telemetry() {
// Test that telemetry is sent if entrypoint param is included,
// and test that it is recorded as default if entrypoint param is not properly included
add_task(async function checkTelemetryLoadEventForEntrypoint() {
// There's an arbitrary interval of 2 seconds in which the content
// processes sync their event data with the parent process, we wait
// this out to ensure that we clear everything that is left over from
// previous tests and don't receive random events in the middle of our tests.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(c => setTimeout(c, 2000));
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", false],
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.proxy.enabled", false],
["browser.contentblocking.report.vpn.enabled", false],
],
});
await addArbitraryTimeout();
// Clear everything.
Services.telemetry.clearEvents();
@ -903,3 +932,248 @@ add_task(async function checkTelemetryLoadEventForEntrypoint() {
// Clean up.
await BrowserTestUtils.removeTab(tab);
});
// This test is skipping due to failures on try, it passes locally.
// Test that telemetry is sent from the vpn card
add_task(async function checkTelemetryClickEventsVPN() {
if (Services.sysinfo.getProperty("name") != "Windows_NT") {
ok(true, "User is on an unsupported platform, the vpn card will not show");
return;
}
await addArbitraryTimeout();
// Clear everything.
Services.telemetry.clearEvents();
await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
true
).content;
return !events || !events.length;
});
Services.telemetry.setEventRecordingEnabled("security.ui.protections", true);
// user is not subscribed to VPN, and is in the us
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", false],
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.proxy.enabled", false],
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb,cn"],
["browser.contentblocking.report.vpn_platforms", "win"],
["browser.contentblocking.report.hide_vpn_banner", true],
["browser.contentblocking.report.vpn-android.url", ""],
["browser.contentblocking.report.vpn-ios.url", ""],
["browser.contentblocking.report.vpn.url", ""],
],
});
Services.locale.availableLocales = ["en-US"];
Services.locale.requestedLocales = ["en-US"];
Region._setHomeRegion("US", false);
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections",
gBrowser,
});
info("checking for vpn link");
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
const getVPNLink = await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("get-vpn-link");
}, "get vpn link exists");
await ContentTaskUtils.waitForCondition(
() => ContentTaskUtils.is_visible(getVPNLink),
"get vpn link is visible"
);
await EventUtils.sendMouseEvent(
{ type: "click", button: 1 },
getVPNLink,
content
);
});
let events = await waitForTelemetryEventCount(2);
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "click" &&
e[3] == "vpn_card_link"
);
is(
events.length,
1,
`recorded telemetry for vpn_card_link when user is not subscribed`
);
// User is subscribed to VPN
AboutProtectionsParent.setTestOverride(getVPNOverrides(true, "us"));
await reloadTab(tab);
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
const androidVPNLink = await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("vpn-google-playstore-link");
}, "android vpn link exists");
await ContentTaskUtils.waitForCondition(
() => ContentTaskUtils.is_visible(androidVPNLink),
"android vpn link is visible"
);
await ContentTaskUtils.waitForCondition(() => {
return content.document
.querySelector(".vpn-card")
.classList.contains("subscribed");
}, "subscribed class is added to the vpn card");
await EventUtils.sendMouseEvent(
{ type: "click", button: 1 },
androidVPNLink,
content
);
});
events = await waitForTelemetryEventCount(5);
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "click" &&
e[3] == "vpn_app_link_android"
);
is(events.length, 1, `recorded telemetry for vpn_app_link_android link`);
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
const iosVPNLink = await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("vpn-app-store-link");
}, "ios vpn link exists");
await ContentTaskUtils.waitForCondition(
() => ContentTaskUtils.is_visible(iosVPNLink),
"ios vpn link is visible"
);
await ContentTaskUtils.waitForCondition(() => {
return content.document
.querySelector(".vpn-card")
.classList.contains("subscribed");
}, "subscribed class is added to the vpn card");
await EventUtils.sendMouseEvent(
{ type: "click", button: 1 },
iosVPNLink,
content
);
});
events = await waitForTelemetryEventCount(6);
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "click" &&
e[3] == "vpn_app_link_ios"
);
is(events.length, 1, `recorded telemetry for vpn_app_link_ios link`);
// Clean up.
await BrowserTestUtils.removeTab(tab);
}).skip();
// This test is skipping due to failures on try, it passes locally.
// Test that telemetry is sent from the vpn banner
add_task(async function checkTelemetryEventsVPNBanner() {
if (Services.sysinfo.getProperty("name") != "Windows_NT") {
ok(true, "User is on an unsupported platform, the vpn card will not show");
return;
}
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.database.enabled", false],
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.proxy.enabled", false],
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb"],
["browser.contentblocking.report.vpn_platforms", "win"],
["browser.contentblocking.report.hide_vpn_banner", false],
["browser.contentblocking.report.vpn-promo.url", ""],
],
});
await addArbitraryTimeout();
// The VPN banner only shows if the user is in en*
Services.locale.availableLocales = ["en-US"];
Services.locale.requestedLocales = ["en-US"];
// Clear everything.
Services.telemetry.clearEvents();
await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
true
).content;
return !events || !events.length;
});
Services.telemetry.setEventRecordingEnabled("security.ui.protections", true);
// User is not subscribed to VPN
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections",
gBrowser,
});
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
const bannerVPNLink = await ContentTaskUtils.waitForCondition(() => {
return content.document.getElementById("vpn-banner-link");
}, "vpn banner link exists");
await ContentTaskUtils.waitForCondition(
() => ContentTaskUtils.is_visible(bannerVPNLink),
"vpn banner link is visible"
);
await EventUtils.sendMouseEvent(
{ type: "click", button: 1 },
bannerVPNLink,
content
);
});
let events = await waitForTelemetryEventCount(3);
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "click" &&
e[3] == "vpn_banner_link"
);
is(events.length, 1, `recorded telemetry for vpn_banner_link`);
// VPN Banner flips this pref each time it shows, flip back between each instruction.
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.hide_vpn_banner", false]],
});
await reloadTab(tab);
await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
const bannerExitLink = await ContentTaskUtils.waitForCondition(() => {
return content.document.querySelector(".vpn-banner .exit-icon");
}, "vpn banner exit link exists");
await ContentTaskUtils.waitForCondition(
() => ContentTaskUtils.is_visible(bannerExitLink),
"vpn banner exit link is visible"
);
await EventUtils.sendMouseEvent(
{ type: "click", button: 1 },
bannerExitLink,
content
);
});
events = await waitForTelemetryEventCount(7);
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "click" &&
e[3] == "vpn_banner_close"
);
is(events.length, 1, `recorded telemetry for vpn_banner_close`);
// Clean up.
await BrowserTestUtils.removeTab(tab);
}).skip();

View File

@ -0,0 +1,277 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
XPCOMUtils.defineLazyModuleGetters(this, {
Region: "resource://gre/modules/Region.jsm",
});
const { AboutProtectionsParent } = ChromeUtils.import(
"resource:///actors/AboutProtectionsParent.jsm"
);
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.monitor.enabled", false],
["browser.contentblocking.report.lockwise.enabled", false],
["browser.contentblocking.report.vpn.enabled", true],
],
});
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
const avLocales = Services.locale.availableLocales;
registerCleanupFunction(() => {
Services.locale.availableLocales = avLocales;
});
});
add_task(async function testVPNCardVisibility() {
if (Services.sysinfo.getProperty("name") != "Windows_NT") {
ok(true, "User is on an unsupported platform, the vpn card will not show");
return;
}
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "my"));
Region._setHomeRegion("my", false);
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections",
gBrowser,
});
info("Enable showing the VPN card");
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb"],
["browser.contentblocking.report.vpn_platforms", "win"],
],
});
info("Check that vpn card is hidden if user's language is not en*");
Services.locale.availableLocales = ["ko-KR", "ar"];
Services.locale.requestedLocales = ["ko-KR"];
await reloadTab(tab);
await checkVPNCardVisibility(tab, true);
info("Check that vpn card is shown if user's language is en*");
// Set language back to en-US
Services.locale.availableLocales = ["en-US"];
Services.locale.requestedLocales = ["en-US"];
await reloadTab(tab);
await checkVPNCardVisibility(tab, false);
info(
"Check that vpn card is hidden if user's location is not on the regions list."
);
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "ls"));
await reloadTab(tab);
await checkVPNCardVisibility(tab, true);
info(
"Check that vpn card shows a different version if user has subscribed to Mozilla vpn."
);
AboutProtectionsParent.setTestOverride(getVPNOverrides(true, "us"));
await reloadTab(tab);
await checkVPNCardVisibility(tab, false, true);
info(
"VPN card should be hidden when vpn not enabled, though all other conditions are true"
);
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.vpn.enabled", false]],
});
await reloadTab(tab);
await checkVPNCardVisibility(tab, true);
await BrowserTestUtils.removeTab(tab);
});
async function checkVPNCardVisibility(tab, shouldBeHidden, subscribed = false) {
await SpecialPowers.spawn(
tab.linkedBrowser,
[{ _shouldBeHidden: shouldBeHidden, _subscribed: subscribed }],
async function({ _shouldBeHidden, _subscribed }) {
await ContentTaskUtils.waitForCondition(() => {
const vpnCard = content.document.querySelector(".vpn-card");
const subscribedStateCorrect =
vpnCard.classList.contains("subscribed") == _subscribed;
return (
ContentTaskUtils.is_hidden(vpnCard) === _shouldBeHidden &&
subscribedStateCorrect
);
});
const visibilityState = _shouldBeHidden ? "hidden" : "shown";
ok(true, `VPN card is ${visibilityState}.`);
}
);
}
add_task(async function testVPNPromoBanner() {
if (Services.sysinfo.getProperty("name") != "Windows_NT") {
ok(true, "User is on an unsupported platform, the vpn card will not show");
return;
}
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections",
gBrowser,
});
info("Enable showing the VPN card and banner");
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb"],
["browser.contentblocking.report.vpn_platforms", "win"],
["browser.contentblocking.report.hide_vpn_banner", false],
],
});
info("Check that vpn banner is hidden if user's language is not en*");
Services.locale.availableLocales = ["de"];
Services.locale.requestedLocales = ["de"];
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, true);
// VPN Banner flips this pref each time it shows, flip back between each instruction.
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.hide_vpn_banner", false]],
});
info("Check that vpn banner is shown if user's language is en*");
// Set language back to en-US
Services.locale.availableLocales = ["en-US"];
Services.locale.requestedLocales = ["en-US"];
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, false);
is(
Services.prefs.getBoolPref(
"browser.contentblocking.report.hide_vpn_banner",
false
),
true,
"After showing the banner once, the pref to hide the VPN banner is flipped"
);
info("The banner does not show when the pref to hide it is flipped");
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, true);
// VPN Banner flips this pref each time it shows, flip back between each instruction.
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.hide_vpn_banner", false]],
});
info(
"Check that VPN banner is hidden if user's location is not on the regions list."
);
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "ls"));
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, true);
info(
"VPN banner should be hidden when vpn not enabled, though all other conditions are true"
);
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.vpn.enabled", false],
["browser.contentblocking.report.hide_vpn_banner", false],
],
});
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, true);
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.hide_vpn_banner", false],
],
});
info("If user is subscribed to VPN already the promo banner should not show");
AboutProtectionsParent.setTestOverride(getVPNOverrides(true, "us"));
await reloadTab(tab);
await checkVPNPromoBannerVisibility(tab, true);
await BrowserTestUtils.removeTab(tab);
});
async function checkVPNPromoBannerVisibility(tab, shouldBeHidden) {
await SpecialPowers.spawn(
tab.linkedBrowser,
[{ _shouldBeHidden: shouldBeHidden }],
async function({ _shouldBeHidden }) {
await ContentTaskUtils.waitForCondition(() => {
const vpnBanner = content.document.querySelector(".vpn-banner");
return ContentTaskUtils.is_hidden(vpnBanner) === _shouldBeHidden;
});
const visibilityState = _shouldBeHidden ? "hidden" : "shown";
ok(true, `VPN banner is ${visibilityState}.`);
}
);
}
// Expect the vpn card and banner to not show as we are expressly excluding China. Even when cn is in the supported region pref.
add_task(async function testVPNDoesNotShowChina() {
if (Services.sysinfo.getProperty("name") != "Windows_NT") {
ok(true, "User is on an unsupported platform, the vpn card will not show");
return;
}
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us"));
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections",
gBrowser,
});
info("Enable showing the VPN card");
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.report.vpn.enabled", true],
["browser.contentblocking.report.vpn_regions", "us,ca,nz,sg,my,gb,cn"],
["browser.contentblocking.report.vpn_platforms", "win,mac"],
["browser.contentblocking.report.hide_vpn_banner", false],
],
});
info("Check that vpn banner and card are able to show when conditions allow");
Region._setHomeRegion("US", false);
Services.locale.availableLocales = ["en-US"];
Services.locale.requestedLocales = ["en-US"];
await reloadTab(tab);
await checkVPNCardVisibility(tab, false);
await checkVPNPromoBannerVisibility(tab, false);
// VPN Banner flips this pref each time it shows, flip back between each instruction.
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.hide_vpn_banner", false]],
});
info(
"set home location to China, even though user is currently in the US, expect vpn card to be hidden"
);
Region._setHomeRegion("CN", false);
await reloadTab(tab);
await checkVPNCardVisibility(tab, true);
await checkVPNPromoBannerVisibility(tab, true);
// VPN Banner flips this pref each time it shows, flip back between each instruction.
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.report.hide_vpn_banner", false]],
});
info("home region is US, but current location is China");
Region._setHomeRegion("US", false);
AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "cn"));
await reloadTab(tab);
await checkVPNCardVisibility(tab, true);
await checkVPNPromoBannerVisibility(tab, true);
await BrowserTestUtils.removeTab(tab);
});

View File

@ -77,3 +77,15 @@ const mockGetMonitorData = data => {
registerCleanupFunction(function head_cleanup() {
Services.logins.removeAllLogins();
});
// Used to replace AboutProtectionsParent.VPNSubStatus and Region.current
const getVPNOverrides = (hasSubscription = false, location = "us") => {
return {
vpnOverrides: () => {
return {
hasSubscription,
location,
};
},
};
};

View File

@ -1835,14 +1835,16 @@ security.ui.protections:
show:
objects: [
"protection_report",
"vpn_banner",
]
bug_numbers:
- 1557050
- 1610897
- 1643428
- 1650468
- 1661756
description: >
User arrived on the protection report. This also includes a 'value' attribute which defaults to 'direct' or will be the value that a referring website addds to the url.
User arrived on the protection report. This also includes a 'value' attribute which defaults to 'direct' or will be the value that a referring website addds to the url. This also indicates if the vpn banner has been seen.
expiry_version: "86"
record_in_processes: ["content"]
release_channel_collection: opt-out
@ -1885,6 +1887,7 @@ security.ui.protections:
- 1612091
- 1637615
- 1643428
- 1661756
description: >
User interaction by click events on the protection report.
objects: [
@ -1897,6 +1900,11 @@ security.ui.protections:
"trackers_about_link",
"mobile_app_link",
"settings_link",
"vpn_banner_link",
"vpn_banner_close",
"vpn_card_link",
"vpn_app_link_android",
"vpn_app_link_ios",
]
expiry_version: "86"
record_in_processes: ["content"]

View File

@ -18,6 +18,10 @@ const kAllowedPrefs = new Set([
"testing.allowed-prefs.some-char-pref",
"testing.allowed-prefs.some-int-pref",
"browser.contentblocking.report.hide_lockwise_app",
"browser.contentblocking.report.hide_vpn_banner",
"browser.contentblocking.report.show_mobile_app",
"narrate.rate",
"narrate.voice",
@ -58,8 +62,6 @@ const kAllowedPrefs = new Set([
"security.ssl.errorReporting.automatic",
"security.tls.version.enable-deprecated",
"security.xfocsp.errorReporting.automatic",
"browser.contentblocking.report.hide_lockwise_app",
"browser.contentblocking.report.show_mobile_app",
]);
const kPrefTypeMap = new Map([

View File

@ -143,12 +143,15 @@ let RemotePageAccessManager = {
"FetchMobileDeviceConnected",
"GetShowProxyCard",
"FetchEntryPoint",
"FetchVPNSubStatus",
"FetchShowVPNCard",
],
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
RPMSetBoolPref: [
"browser.contentblocking.report.hide_lockwise_app",
"browser.contentblocking.report.show_mobile_app",
"browser.contentblocking.report.hide_vpn_banner",
],
RPMGetBoolPref: [
"browser.contentblocking.report.lockwise.enabled",
@ -161,6 +164,8 @@ let RemotePageAccessManager = {
"privacy.trackingprotection.socialtracking.enabled",
"browser.contentblocking.report.hide_lockwise_app",
"browser.contentblocking.report.show_mobile_app",
"browser.contentblocking.report.hide_vpn_banner",
"browser.contentblocking.report.vpn.enabled",
],
RPMGetStringPref: [
"browser.contentblocking.category",
@ -172,6 +177,11 @@ let RemotePageAccessManager = {
"browser.contentblocking.report.lockwise.mobile-ios.url",
"browser.contentblocking.report.mobile-ios.url",
"browser.contentblocking.report.mobile-android.url",
"browser.contentblocking.report.vpn.url",
"browser.contentblocking.report.vpn-promo.url",
"browser.contentblocking.report.vpn-android.url",
"browser.contentblocking.report.vpn-ios.url",
"browser.contentblocking.report.vpn_platforms",
],
RPMGetIntPref: ["network.cookie.cookieBehavior"],
RPMGetFormatURLPref: [