mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 10:40:12 +00:00
Bug 860581 - Add support for Mixed Content Blocking. r=wesj
This commit is contained in:
parent
76437ec0bc
commit
5604435af7
@ -476,6 +476,11 @@ pref("security.alternate_certificate_error_page", "certerror");
|
||||
|
||||
pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712.
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Block insecure active content on https pages
|
||||
pref("security.mixed_content.block_active_content", true);
|
||||
#endif
|
||||
|
||||
// Override some named colors to avoid inverse OS themes
|
||||
pref("ui.-moz-dialog", "#efebe7");
|
||||
pref("ui.-moz-dialogtext", "#101010");
|
||||
|
@ -960,16 +960,9 @@ public class BrowserToolbar implements Tabs.OnTabsChangedListener,
|
||||
}
|
||||
|
||||
private void setSecurityMode(String mode) {
|
||||
mShowSiteSecurity = true;
|
||||
|
||||
if (mode.equals(SiteIdentityPopup.IDENTIFIED)) {
|
||||
mSiteSecurity.setImageLevel(1);
|
||||
} else if (mode.equals(SiteIdentityPopup.VERIFIED)) {
|
||||
mSiteSecurity.setImageLevel(2);
|
||||
} else {
|
||||
mSiteSecurity.setImageLevel(0);
|
||||
mShowSiteSecurity = false;
|
||||
}
|
||||
int imageLevel = SiteIdentityPopup.getSecurityImageLevel(mode);
|
||||
mSiteSecurity.setImageLevel(imageLevel);
|
||||
mShowSiteSecurity = (imageLevel != SiteIdentityPopup.LEVEL_UKNOWN);
|
||||
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
@ -688,6 +688,8 @@ RES_DRAWABLE_MDPI = \
|
||||
res/drawable-mdpi/menu_item_check.png \
|
||||
res/drawable-mdpi/menu_item_more.png \
|
||||
res/drawable-mdpi/menu_item_uncheck.png \
|
||||
res/drawable-mdpi/site_security_blocked_mixed_content.png \
|
||||
res/drawable-mdpi/site_security_loaded_mixed_content.png \
|
||||
res/drawable-mdpi/site_security_identified.png \
|
||||
res/drawable-mdpi/site_security_verified.png \
|
||||
res/drawable-mdpi/tabs_normal.png \
|
||||
@ -792,6 +794,8 @@ RES_DRAWABLE_HDPI = \
|
||||
res/drawable-hdpi/menu_item_check.png \
|
||||
res/drawable-hdpi/menu_item_more.png \
|
||||
res/drawable-hdpi/menu_item_uncheck.png \
|
||||
res/drawable-hdpi/site_security_blocked_mixed_content.png \
|
||||
res/drawable-hdpi/site_security_loaded_mixed_content.png \
|
||||
res/drawable-hdpi/site_security_identified.png \
|
||||
res/drawable-hdpi/site_security_verified.png \
|
||||
res/drawable-hdpi/tabs_normal.png \
|
||||
@ -888,6 +892,8 @@ RES_DRAWABLE_XHDPI = \
|
||||
res/drawable-xhdpi/tab_indicator_divider.9.png \
|
||||
res/drawable-xhdpi/tab_indicator_selected.9.png \
|
||||
res/drawable-xhdpi/tab_indicator_selected_focused.9.png \
|
||||
res/drawable-xhdpi/site_security_blocked_mixed_content.png \
|
||||
res/drawable-xhdpi/site_security_loaded_mixed_content.png \
|
||||
res/drawable-xhdpi/site_security_identified.png \
|
||||
res/drawable-xhdpi/site_security_verified.png \
|
||||
res/drawable-xhdpi/tabs_normal.png \
|
||||
|
@ -21,12 +21,26 @@ import android.widget.TextView;
|
||||
* SiteIdentityPopup is a singleton class that displays site identity data in
|
||||
* an arrow panel popup hanging from the lock icon in the browser toolbar.
|
||||
*/
|
||||
public class SiteIdentityPopup extends ArrowPopup {
|
||||
public class SiteIdentityPopup extends ArrowPopup
|
||||
implements DoorHanger.OnButtonClickListener {
|
||||
private static final String LOGTAG = "GeckoSiteIdentityPopup";
|
||||
|
||||
public static final String UNKNOWN = "unknown";
|
||||
public static final String VERIFIED = "verified";
|
||||
public static final String IDENTIFIED = "identified";
|
||||
public static final String MIXED_CONTENT_BLOCKED = "mixed_content_blocked";
|
||||
public static final String MIXED_CONTENT_LOADED = "mixed_content_loaded";
|
||||
|
||||
// Security states corresponding to image levels in site_security_level.xml
|
||||
public static final int LEVEL_UKNOWN = 0;
|
||||
public static final int LEVEL_IDENTIFIED = 1;
|
||||
public static final int LEVEL_VERIFIED = 2;
|
||||
public static final int LEVEL_MIXED_CONTENT_BLOCKED = 3;
|
||||
public static final int LEVEL_MIXED_CONTENT_LOADED = 4;
|
||||
|
||||
// FIXME: Update this URL for mobile. See bug 885923.
|
||||
private static final String MIXED_CONTENT_SUPPORT_URL =
|
||||
"https://support.mozilla.org/kb/how-does-content-isnt-secure-affect-my-safety";
|
||||
|
||||
private Resources mResources;
|
||||
|
||||
@ -37,12 +51,30 @@ public class SiteIdentityPopup extends ArrowPopup {
|
||||
private TextView mEncrypted;
|
||||
private ImageView mLarry;
|
||||
|
||||
private DoorHanger mMixedContentNotification;
|
||||
|
||||
SiteIdentityPopup(BrowserApp aActivity) {
|
||||
super(aActivity, null);
|
||||
|
||||
mResources = aActivity.getResources();
|
||||
}
|
||||
|
||||
public static int getSecurityImageLevel(String mode) {
|
||||
if (IDENTIFIED.equals(mode)) {
|
||||
return LEVEL_IDENTIFIED;
|
||||
}
|
||||
if (VERIFIED.equals(mode)) {
|
||||
return LEVEL_VERIFIED;
|
||||
}
|
||||
if (MIXED_CONTENT_BLOCKED.equals(mode)) {
|
||||
return LEVEL_MIXED_CONTENT_BLOCKED;
|
||||
}
|
||||
if (MIXED_CONTENT_LOADED.equals(mode)) {
|
||||
return LEVEL_MIXED_CONTENT_LOADED;
|
||||
}
|
||||
return LEVEL_UKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
@ -61,26 +93,7 @@ public class SiteIdentityPopup extends ArrowPopup {
|
||||
mLarry = (ImageView) layout.findViewById(R.id.larry);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param identityData A JSONObject that holds the current tab's identity data.
|
||||
*/
|
||||
public void updateIdentity(JSONObject identityData) {
|
||||
String mode;
|
||||
try {
|
||||
mode = identityData.getString("mode");
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Exception trying to get identity mode", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mode.equals(VERIFIED) && !mode.equals(IDENTIFIED)) {
|
||||
Log.e(LOGTAG, "Can't show site identity popup in non-identified state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mInflated)
|
||||
init();
|
||||
|
||||
private void setIdentity(JSONObject identityData) {
|
||||
try {
|
||||
String host = identityData.getString("host");
|
||||
mHost.setText(host);
|
||||
@ -99,19 +112,110 @@ public class SiteIdentityPopup extends ArrowPopup {
|
||||
mVerifier.setText(verifier + "\n" + encrypted);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Exception trying to get identity data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onButtonClick(DoorHanger dh, String tag) {
|
||||
if (tag.equals("disable")) {
|
||||
// To disable mixed content blocking, reload the page with a flag to load mixed content.
|
||||
try {
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("allowMixedContent", true);
|
||||
GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", data.toString());
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Exception creating message to allow mixed content", e);
|
||||
}
|
||||
} else if (tag.equals("enable")) {
|
||||
// To enable mixed content blocking, reload the page without any flags.
|
||||
GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", "");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
}
|
||||
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void addMixedContentNotification(boolean blocked) {
|
||||
// Remove any exixting mixed content notification.
|
||||
removeMixedContentNotification();
|
||||
mMixedContentNotification = new DoorHanger(mActivity);
|
||||
|
||||
String message;
|
||||
if (blocked) {
|
||||
message = mActivity.getString(R.string.blocked_mixed_content_message_top) + "\n\n" +
|
||||
mActivity.getString(R.string.blocked_mixed_content_message_bottom);
|
||||
} else {
|
||||
message = mActivity.getString(R.string.loaded_mixed_content_message);
|
||||
}
|
||||
mMixedContentNotification.setMessage(message);
|
||||
mMixedContentNotification.addLink(mActivity.getString(R.string.learn_more), MIXED_CONTENT_SUPPORT_URL, "\n\n");
|
||||
|
||||
if (blocked) {
|
||||
mMixedContentNotification.addButton(mActivity.getString(R.string.disable_protection), "disable", this);
|
||||
mMixedContentNotification.addButton(mActivity.getString(R.string.keep_blocking), "keepBlocking", this);
|
||||
} else {
|
||||
mMixedContentNotification.addButton(mActivity.getString(R.string.enable_protection), "enable", this);
|
||||
}
|
||||
mMixedContentNotification.hideDivider();
|
||||
mMixedContentNotification.setBackgroundColor(0xFFDDE4EA);
|
||||
|
||||
mContent.addView(mMixedContentNotification);
|
||||
}
|
||||
|
||||
private void removeMixedContentNotification() {
|
||||
if (mMixedContentNotification != null) {
|
||||
mContent.removeView(mMixedContentNotification);
|
||||
mMixedContentNotification = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param identityData A JSONObject that holds the current tab's identity data.
|
||||
*/
|
||||
public void updateIdentity(JSONObject identityData) {
|
||||
String mode;
|
||||
try {
|
||||
mode = identityData.getString("mode");
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Exception trying to get identity mode", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode.equals(VERIFIED)) {
|
||||
if (UNKNOWN.equals(mode)) {
|
||||
Log.e(LOGTAG, "Can't show site identity popup in non-identified state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mInflated)
|
||||
init();
|
||||
|
||||
setIdentity(identityData);
|
||||
|
||||
if (VERIFIED.equals(mode)) {
|
||||
// Use a blue theme for SSL
|
||||
mLarry.setImageResource(R.drawable.larry_blue);
|
||||
mHost.setTextColor(mResources.getColor(R.color.identity_verified));
|
||||
mOwner.setTextColor(mResources.getColor(R.color.identity_verified));
|
||||
} else {
|
||||
} else if (IDENTIFIED.equals(mode)) {
|
||||
// Use a green theme for EV
|
||||
mLarry.setImageResource(R.drawable.larry_green);
|
||||
mHost.setTextColor(mResources.getColor(R.color.identity_identified));
|
||||
mOwner.setTextColor(mResources.getColor(R.color.identity_identified));
|
||||
} else {
|
||||
// Use a gray theme for sites with mixed content
|
||||
// FIXME: Get a gray larry
|
||||
mLarry.setImageResource(R.drawable.larry_blue);
|
||||
mHost.setTextColor(mResources.getColor(R.color.identity_mixed_content));
|
||||
mOwner.setTextColor(mResources.getColor(R.color.identity_mixed_content));
|
||||
|
||||
addMixedContentNotification(MIXED_CONTENT_BLOCKED.equals(mode));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
super.dismiss();
|
||||
removeMixedContentNotification();
|
||||
}
|
||||
}
|
||||
|
@ -288,6 +288,15 @@ with that structure, consider a translation which ignores the preceding domain a
|
||||
just addresses the organization to follow, e.g. "This site is run by " -->
|
||||
<!ENTITY identity_run_by "which is run by">
|
||||
|
||||
<!-- Mixed content notifications in site identity popup -->
|
||||
<!ENTITY loaded_mixed_content_message "This page is displaying content that isn\'t secure.">
|
||||
<!ENTITY blocked_mixed_content_message_top "&brandShortName; has blocked content that isn\'t secure.">
|
||||
<!ENTITY blocked_mixed_content_message_bottom "Most websites will still work properly even when this content is blocked.">
|
||||
<!ENTITY learn_more "Learn More">
|
||||
<!ENTITY enable_protection "Enable protection">
|
||||
<!ENTITY disable_protection "Disable protection">
|
||||
<!ENTITY keep_blocking "Keep blocking">
|
||||
|
||||
<!ENTITY private_data_success "Private data cleared">
|
||||
<!ENTITY private_data_fail "Some private data could not be cleared">
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 691 B |
Binary file not shown.
After Width: | Height: | Size: 679 B |
Binary file not shown.
After Width: | Height: | Size: 346 B |
Binary file not shown.
After Width: | Height: | Size: 679 B |
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 679 B |
@ -8,5 +8,7 @@
|
||||
<item android:maxLevel="0" android:drawable="@android:color/transparent"/>
|
||||
<item android:maxLevel="1" android:drawable="@drawable/site_security_identified"/>
|
||||
<item android:maxLevel="2" android:drawable="@drawable/site_security_verified"/>
|
||||
<item android:maxLevel="3" android:drawable="@drawable/site_security_blocked_mixed_content"/>
|
||||
<item android:maxLevel="4" android:drawable="@drawable/site_security_loaded_mixed_content"/>
|
||||
|
||||
</level-list>
|
||||
|
@ -68,6 +68,7 @@
|
||||
<color name="validation_message_text">#ffffff</color>
|
||||
<color name="identity_verified">#FF3298FF</color>
|
||||
<color name="identity_identified">#FF89C450</color>
|
||||
<color name="identity_mixed_content">#FF000000</color>
|
||||
<color name="url_bar_text_highlight">#FFFF9500</color>
|
||||
<color name="url_bar_text_highlight_pb">#FFD06BFF</color>
|
||||
<color name="suggestion_primary">#dddddd</color>
|
||||
|
@ -262,6 +262,13 @@
|
||||
<!-- Site identity popup -->
|
||||
<string name="identity_connected_to">&identity_connected_to;</string>
|
||||
<string name="identity_run_by">&identity_run_by;</string>
|
||||
<string name="loaded_mixed_content_message">&loaded_mixed_content_message;</string>
|
||||
<string name="blocked_mixed_content_message_top">&blocked_mixed_content_message_top;</string>
|
||||
<string name="blocked_mixed_content_message_bottom">&blocked_mixed_content_message_bottom;</string>
|
||||
<string name="learn_more">&learn_more;</string>
|
||||
<string name="enable_protection">&enable_protection;</string>
|
||||
<string name="disable_protection">&disable_protection;</string>
|
||||
<string name="keep_blocking">&keep_blocking;</string>
|
||||
|
||||
<!-- Clear private data -->
|
||||
<string name="private_data_success">&private_data_success;</string>
|
||||
|
@ -1316,11 +1316,18 @@ var BrowserApp = {
|
||||
browser.goForward();
|
||||
break;
|
||||
|
||||
case "Session:Reload":
|
||||
case "Session:Reload": {
|
||||
let allowMixedContent = false;
|
||||
if (aData) {
|
||||
let data = JSON.parse(aData);
|
||||
allowMixedContent = data.allowMixedContent;
|
||||
}
|
||||
|
||||
// Try to use the session history to reload so that framesets are
|
||||
// handled properly. If the window has no session history, fall back
|
||||
// to using the web navigation's reload method.
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
|
||||
let flags = allowMixedContent ? Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT :
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
|
||||
let webNav = browser.webNavigation;
|
||||
try {
|
||||
let sh = webNav.sessionHistory;
|
||||
@ -1329,15 +1336,17 @@ var BrowserApp = {
|
||||
} catch (e) {}
|
||||
webNav.reload(flags);
|
||||
break;
|
||||
}
|
||||
|
||||
case "Session:Stop":
|
||||
browser.stop();
|
||||
break;
|
||||
|
||||
case "Session:ShowHistory":
|
||||
case "Session:ShowHistory": {
|
||||
let data = JSON.parse(aData);
|
||||
this.showHistory(data.fromIndex, data.toIndex, data.selIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
case "Tab:Load": {
|
||||
let data = JSON.parse(aData);
|
||||
@ -6034,10 +6043,24 @@ var CharacterEncoding = {
|
||||
};
|
||||
|
||||
var IdentityHandler = {
|
||||
// Mode strings used to control CSS display
|
||||
IDENTITY_MODE_IDENTIFIED : "identified", // High-quality identity information
|
||||
IDENTITY_MODE_DOMAIN_VERIFIED : "verified", // Minimal SSL CA-signed domain verification
|
||||
IDENTITY_MODE_UNKNOWN : "unknown", // No trusted identity information
|
||||
// No trusted identity information. No site identity icon is shown.
|
||||
IDENTITY_MODE_UNKNOWN: "unknown",
|
||||
|
||||
// Minimal SSL CA-signed domain verification. Blue lock icon is shown.
|
||||
IDENTITY_MODE_DOMAIN_VERIFIED: "verified",
|
||||
|
||||
// High-quality identity information. Green lock icon is shown.
|
||||
IDENTITY_MODE_IDENTIFIED: "identified",
|
||||
|
||||
// The following mixed content modes are only used if "security.mixed_content.block_active_content"
|
||||
// is enabled. Even though the mixed content state and identitity state are orthogonal,
|
||||
// our Java frontend coalesces them into one indicator.
|
||||
|
||||
// Blocked active mixed content. Shield icon is shown, with a popup option to load content.
|
||||
IDENTITY_MODE_MIXED_CONTENT_BLOCKED: "mixed_content_blocked",
|
||||
|
||||
// Loaded active mixed content. Yellow triangle icon is shown.
|
||||
IDENTITY_MODE_MIXED_CONTENT_LOADED: "mixed_content_loaded",
|
||||
|
||||
// Cache the most recent SSLStatus and Location seen in getIdentityStrings
|
||||
_lastStatus : null,
|
||||
@ -6077,6 +6100,14 @@ var IdentityHandler = {
|
||||
},
|
||||
|
||||
getIdentityMode: function getIdentityMode(aState) {
|
||||
if (aState & Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT)
|
||||
return this.IDENTITY_MODE_MIXED_CONTENT_BLOCKED;
|
||||
|
||||
// Only show an indicator for loaded mixed content if the pref to block it is enabled
|
||||
if ((aState & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) &&
|
||||
Services.prefs.getBoolPref("security.mixed_content.block_active_content"))
|
||||
return this.IDENTITY_MODE_MIXED_CONTENT_LOADED;
|
||||
|
||||
if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL)
|
||||
return this.IDENTITY_MODE_IDENTIFIED;
|
||||
|
||||
@ -6126,7 +6157,7 @@ var IdentityHandler = {
|
||||
result.verifier = Strings.browser.formatStringFromName("identity.identified.verifier", [iData.caOrg], 1);
|
||||
|
||||
// If the cert is identified, then we can populate the results with credentials
|
||||
if (mode == this.IDENTITY_MODE_IDENTIFIED) {
|
||||
if (aState & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
|
||||
result.owner = iData.subjectOrg;
|
||||
|
||||
// Build an appropriate supplemental block out of whatever location data we have
|
||||
@ -6145,7 +6176,7 @@ var IdentityHandler = {
|
||||
}
|
||||
|
||||
// Otherwise, we don't know the cert owner
|
||||
result.owner = Strings.browser.GetStringFromName("identity.ownerUnknown2");
|
||||
result.owner = Strings.browser.GetStringFromName("identity.ownerUnknown3");
|
||||
|
||||
// Cache the override service the first time we need to check it
|
||||
if (!this._overrideService)
|
||||
|
@ -72,7 +72,7 @@ identity.identified.verified_by_you=You have added a security exception for this
|
||||
identity.identified.state_and_country=%S, %S
|
||||
identity.identified.title_with_country=%S (%S)
|
||||
identity.encrypted2=Encrypted
|
||||
identity.ownerUnknown2=(unknown)
|
||||
identity.ownerUnknown3=unknown
|
||||
|
||||
# Geolocation UI
|
||||
geolocation.allow=Share
|
||||
|
Loading…
x
Reference in New Issue
Block a user