Bug 860581 - Add support for Mixed Content Blocking. r=wesj

This commit is contained in:
Margaret Leibovic 2013-06-21 20:36:38 -07:00
Родитель 76437ec0bc
Коммит 5604435af7
16 изменённых файлов: 201 добавлений и 43 удалений

Просмотреть файл

@ -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">

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 691 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 679 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 346 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 679 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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