Closed Bug 283521 Opened 19 years ago Closed 19 years ago

Add security icon/button to the Chatzilla status bar.

Categories

(Other Applications :: ChatZilla, enhancement)

enhancement
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: justinarthur, Assigned: Gijs)

References

Details

(Keywords: privacy, Whiteboard: [cz-0.9.69])

Attachments

(1 file, 3 obsolete files)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b2) Gecko/20050219
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b2) Gecko/20050219

With bug 174087 (IRC over SSL support) fixed, it would be nice to have the
security lock icon from the browser available in the status bar of chatzilla to
denote the security status of the current Chatzilla view. It should look exactly
like the browser's security icon if the user is running Chatzilla on the Suite
or Firefox. It would also be nice to give it tooltip text showing the signer and
have it clickable to invoke a certificate info dialog box.

Reproducible: Always

Steps to Reproduce:
Keywords: privacy
Taking this bug. Thanks a bundle (in advance) to Justin Arthur, Christian
Biesinger and Darin Fisher for helping me out when looking for the proper
interface on the transport variable. I'll be attaching a patch as soon as I have
enough time to properly fix all of this.
Assignee: rginda → gijskruitbosch
Status: UNCONFIRMED → NEW
Ever confirmed: true
Small explanation as to why this is taking a bit longer than I expected:
Seamonkey and Firefox both have a different CSS used for styling this icon
(navigator.css vs. browser.css) and viewing the certificate requires just a left
click in Seamonkey while it needs a double-click in Firefox. 

Since we want to mimic this behaviour to the best possible extent, I'm currently
trying to figure out if and how I can set what css to use during runtime (on a
XUL window!). Which is a pain, but I'll keep trying ;-).
Attached patch Patch v1 (obsolete) — Splinter Review
Prototype patch. I think we need XULRunner fixed (at the moment, it's bound not
to work), does anyone know what css I could use for that? Should we add our
own?

Asking review to see if the general approach I'm taking is okay :-).
Attachment #178577 - Flags: review?(samuel)
Depends on: 288153
Attachment #178577 - Attachment is obsolete: true
Attachment #178577 - Flags: review?(samuel)
Comment on attachment 178577 [details] [diff] [review]
Patch v1

I know this has been marked obsolete, but I want to comment on some things
anyway.

>Index: mozilla/extensions/irc/js/lib/irc.js

>     this.parent.users = this.users;
>     e.destObject = this.parent;
>     e.set = "network";
>+

The new code should go before the destObject/set lines - they are traditionally
at the end.

>+    const wpl = Components.interfaces.nsIWebProgressListener;
>+    if (!this.isSecure)
>+    {
>+        this.securityStatus = wpl.STATE_IS_INSECURE;
>+        this.securityTooltip = MSG_SECURITY_INFO;
>+        this.connection.cert = null;

We should not be using WPL constants in the library; heck, Components may not
even exist.

Also, the IRC library should never have UI-related code (tooltip).

>+        updateSecurityIcon();
>+        return;
>+    }
>+    /* We're on a secure server, store Certificate for later use. We can only
>+     * do this when fully connected, so we do it here. Every IRC server is
>+     * supposed to send a 001, so we should always be able to set it :-)
>+     */

If we don't get a 001, NOTHING will work. ;)

>+    try
>+    {
>+        var sslSp = Components.interfaces.nsISSLStatusProvider;
>+        var sslStatus = Components.interfaces.nsISSLStatus;
>+
>+        // Get the actual SSL Status
>+        sslSp = this.connection._transport.securityInfo.QueryInterface(sslSp);
>+        sslStatus = sslSp.SSLStatus.QueryInterface(sslStatus);

Ick. You should never need to use an _ property unless you are part of the
implementation (in this case, you must be in connection*.js to use _transport).

My suggestion is to add a method to CBSConnection to get the different things
you want below, and probably make connection-rhino.js have impls. that return
null/0/whatever instead. So, we'd probably want something like...

  getSecurityState(), which can return:
    0	unknown
    1	insecure
    2	broken
    3	secure

  getSecurityStrenth()
    0  unknown or no security
    1  low security
    2  med security
    3  high security

  getSecurityCertificate()
    returns the actual cert.

>+
>+        // Store certificate and appropriate tooltip
>+        this.connection.cert = sslStatus.serverCert;
>+        this.securityTooltip = getMsg(MSG_SECURE_CONNECTION,
>+                                      this.connection.cert.issuerOrganization);
>+
>+        // Store appropriate status
>+        if (!("keyLength" in sslStatus) || !sslStatus.keyLength)
>+            this.securityStatus = wpl.STATE_IS_BROKEN;
>+        else if (sslStatus.keyLength >= 90)
>+            this.securityStatus = wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH;
>+        else
>+            this.securityStatus = wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW;
>+    }
>+    catch (ex)
>+    {
>+        // Break means broken, set correct values:
>+        dd("Exception getting certificate stuff: " + ex.message);
>+        this.securityStatus = wpl.STATE_IS_BROKEN;
>+        this.securityTooltip = MSG_SECURITY_INFO;
>+        this.connection.cert = null;
>+    }
>+    updateSecurityIcon();


>Index: mozilla/extensions/irc/js/lib/utils.js

>+function viewCert(cert, parent)
>+{
>+    const nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
>+    const nsCertificateDialogs = "@mozilla.org/nsCertificateDialogs;1"
>+    var cd = getService(nsCertificateDialogs, nsICertificateDialogs);

At least use the shorter form!

    var cd = getService("@mozilla.org/nsCertificateDialogs;1",
"nsICertificateDialogs");

>+
>+    if (!parent)
>+        parent = window;
>+    cd.viewCert(parent, cert);
>+}
>+


>Index: mozilla/extensions/irc/xul/content/handlers.js

>+    // Correct security Values
>+    const wpl = Components.interfaces.nsIWebProgressListener;
>+    e.server.securityStatus = wpl.STATE_IS_INSECURE;
>+    e.server.securityTooltip = MSG_SECURITY_INFO;
>+

It would probably be better to do all the security state changes in the IRC
library - remeber that can be used without the CZ UI. Then, you can send a new
event (e.g. onSecurityChange) to the network so that the FE code can update the
statusbar/tooltip.

>     dispatch("sync-header");
>     updateTitle();
>     updateProgress();
>+    updateSecurityIcon();
>+


>Index: mozilla/extensions/irc/xul/content/static.js

>+    // Get the appropriate css in to style the security icon
>+    var attribs, processingInstruction, windowElem
>+    attribs = " type=\"text/css\"";
>+    if (client.host == "Mozilla")
>+        attribs = "href=\"chrome://navigator/skin/navigator.css\"" + attribs;
>+    else if (client.host == "Firefox")
>+        attribs = "href=\"chrome://browser/skin/browser.css\"" + attribs;
>+    else if (client.host == "XULRunner")
>+        return; // Unless anyone knows what we can use for XULRunner?

Returning early for XULRunner is a bad idea; nest the code below in a if
(secCSSUrl), and use that above for simplicity. THEN construct the PI inside
the if.

>+    processingInstruction = document.createProcessingInstruction(
>+                            "xml-stylesheet", attribs);
>+    windowElem = document.getElementById("chatzilla-window");
>+    document.insertBefore(processingInstruction, windowElem);
>+
>+    // Copy behaviour of security-button from browser
>+    var eventhandler = "if (event.button == 0) displayCertificateInfo();";
>+    var securityButton = document.getElementById("security-button");
>+    if (client.host == "Firefox")
>+    {
>+        securityButton.setAttribute("ondblclick", eventhandler);
>+        securityButton.setAttribute("class", "statusbarpanel-iconic-text");
>+    }
>+    else if (client.host == "Mozilla")
>+    {
>+        securityButton.setAttribute("class", "statusbarpanel-iconic");
>+        securityButton.setAttribute("oncommand", "displayCertificateInfo();");
>+    }

I wonder if we can crash an old Mozilla with this stuff... :)

>+function updateSecurityIcon()
>+{
>+    var o = getObjectDetails (client.currentObject);
>+    const wpl = Components.interfaces.nsIWebProgressListener;
>+    var securityButton = window.document.getElementById("security-button");
>+
>+    if (!o.server || !o.server.securityStatus)
>+    {
>+        // No server or security Status
>+        securityButton.removeAttribute("level");
>+        securityButton.setAttribute("tooltiptext", MSG_SECURITY_INFO);
>+        if (client.host == "Firefox")
>+            securityButton.removeAttribute("label");
>+        return;
>+    }
>+

This next switch would be better if you used a security interface on the
server; you could actually use the interface I wrote out for the connection,
and make the server not do anything but pass through the calls...

>+    switch (o.server.securityStatus) 
>+    {
>+        case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
>+            securityButton.setAttribute("level", "high");
>+            break;
>+        case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
>+            securityButton.setAttribute("level", "low");
>+            break;
>+        case wpl.STATE_IS_BROKEN:
>+            securityButton.setAttribute("level", "broken");
>+            break;
>+        case wpl.STATE_IS_INSECURE:
>+        default:
>+            securityButton.removeAttribute("level");
>+            break;
>+    }
>+    securityButton.setAttribute("tooltiptext", o.server.securityTooltip);

Clearly this is v.bad. :)  Need to pick the tooltip *here*.

>+
>+    // Set click / dblclick events, and label if appropriate
>+    var serverSecure = o.server.securityStatus & wpl.STATE_IS_SECURE
>+    if (client.host == "Firefox" && serverSecure)
>+        securityButton.setAttribute("label", o.server.hostname);

Comment seems to be out-of-date... and I think it would be better to use some
of FF's behaviour globally - like showing the hostname.

>+function displayCertificateInfo()
>+{
>+    var o = getObjectDetails (client.currentObject);
>+    if (!o.server)
>+        return;
>+
>+    if (!o.server.isSecure)
>+    {
>+        display(getMsg(MSG_INSECURE_SERVER, o.server.hostname), MT_INFO);
>+        return;
>+    }
>+
>+    viewCert(o.server.connection.cert);
>+}

It somehow seems wrong to use display for failing when success opens a
dialog... oh well.
Attached patch Patch v2 (obsolete) — Splinter Review
I think this fixes everything mentioned by Silver, but I'm feeling drowsy and
I've already been spending way too much time on this thing, from stupid XUL
bugs (tooltips suck, let me tell you that much) to incompatibility (XBL is well
hidden and I still don't get why people use it, but anyway) to Fx trunk not
taking in extensions. Yay.

Anyhow, this should have separated UI vs. underlying mechanisms. No XPCom
constants used anymore. Works on Moz 1.0, Moz trunk, XULRunner trunk, Fx 1.0.3,
and it ought to work on Fx trunk, but that failed to install it so I stopped
bothering.
Attachment #183187 - Flags: review?(silver)
For reference: there are icons added to mozilla/extensions/irc/xul/skin/images
called 'secure.png' and 'security-broken.png' (both full-lowercase, like the
rest of that directory), they are copied from:

http://lxr.mozilla.org/seamonkey/source/browser/themes/winstripe/browser/Secure.png
http://lxr.mozilla.org/seamonkey/source/browser/themes/winstripe/browser/Security-broken.png
Comment on attachment 183187 [details] [diff] [review]
Patch v2

>? mozilla/extensions/irc/xpi/log.tmp
>? mozilla/extensions/irc/xul/skin/images/secure.png
>? mozilla/extensions/irc/xul/skin/images/security-broken.png
>Index: mozilla/extensions/irc/jar.mn

>+	skin/modern/chatzilla/images/secure.png         (xul/skin/images/secure.png)
>+	skin/modern/chatzilla/images/security-broken.png         (xul/skin/images/security-broken.png)

The naming is inconsistent here. Could you maybe fix it?



>Index: mozilla/extensions/irc/js/lib/connection-xpcom.js

>+// Security Constants. 
>+const STATE_IS_INSECURE = 4
>+const STATE_IS_BROKEN = 1
>+const STATE_IS_SECURE = 2
>+
>+const STATE_SECURE_HIGH = 262144
>+const STATE_SECURE_LOW = 131072

Hmm. Could you use hex notation (0x...) so that these make some kind of sense?
Preferably do it for all the constants. Actually, alternatively, make both be
single digits (1, 2, 3 only) - see later for why.

>+CBSConnection.prototype.getSecurityState =
>+function bc_getsecuritystate()
>+{
>+    if (!this.isConnected || !this._transport.securityInfo)
>+        return STATE_IS_INSECURE;
>+
>+    try
>+    {
>+        var sslSp = Components.interfaces.nsISSLStatusProvider;
>+        var sslStatus = Components.interfaces.nsISSLStatus;
>+
>+        // Get the actual SSL Status
>+        sslSp = this._transport.securityInfo.QueryInterface(sslSp);
>+        sslStatus = sslSp.SSLStatus.QueryInterface(sslStatus);
>+        // Store appropriate status
>+        if (!("keyLength" in sslStatus) || !sslStatus.keyLength)
>+            return STATE_IS_BROKEN;
>+        else if (sslStatus.keyLength >= 90)
>+            return (STATE_IS_SECURE | STATE_SECURE_HIGH);
>+        else
>+            return (STATE_IS_SECURE | STATE_SECURE_LOW);

Would it make sense to return an array?
  [STATE_IS_BROKEN]
  [STATE_IS_SECURE, STATE_SECURE_LOW]

Also, shouldn't we have a medium too?

>+    }
>+    catch (ex)
>+    {
>+        // Something goes wrong -> broken security icon
>+        dd("Exception getting certificate for connection: " + ex.message);
>+        return STATE_IS_BROKEN;
>+    }
>+}



>Index: mozilla/extensions/irc/xul/content/menus.xul

>+      <statusbarpanel id="security-button" ondblclick="if (event.button == 0) displayCertificateInfo();">
>+        <label id="security-button-label"/>
>+        <image id="security-button-image"/>
>+      </statusbarpanel>

I feel the even hook should be in handlers.js, but it's not like all the code
is that good. :)



>Index: mozilla/extensions/irc/xul/content/static.js

>+function updateSecurityIcon()
>+{
>+    var o = getObjectDetails (client.currentObject);

Nit: no space before parmeter list.

>+    var securityButton = window.document.getElementById("security-button");
>+    securityButton.removeAttribute("level");
>+    securityButton.removeAttribute("tooltiptext");
>+    if (!o.server || !o.server.isConnected) // No server or connection?
>+    {
>+        securityButton.setAttribute("tooltiptext", MSG_SECURITY_INFO);
>+        return;
>+    }
>+
>+    var securityState = o.server.connection.getSecurityState()

Now, here we go... I really dislike this switch. The main problem is this: if
we are secure, but at a new level, what happens? We get the insecure one. If
you want to keep this bitmask thing (rather than switching to an array/object),
please do it like this:

  if (securityState & STATE_IS_SECURE)
  {
      ...

So that we always have an else for secure, but unknown level, and what-not.

If you go with an array/object, this will also be nessessary.

>+    switch (securityState) 
>+    {
>+        case STATE_IS_SECURE | STATE_SECURE_HIGH:
>+            securityButton.setAttribute("level", "high");
>+            securityButton.firstChild.value = o.server.hostname;
>+            break;
>+        case STATE_IS_SECURE | STATE_SECURE_LOW:
>+            securityButton.setAttribute("level", "low");
>+            securityButton.firstChild.value = o.server.hostname;
>+            break;
>+        case STATE_IS_BROKEN:
>+            securityButton.setAttribute("level", "broken");
>+            // No break to make sure we get the correct tooltip
>+        case STATE_IS_INSECURE:
>+        default:
>+            securityButton.setAttribute("tooltiptext", MSG_SECURITY_INFO);
>+    }
>+
>+    if ((securityState & STATE_IS_SECURE) == STATE_IS_SECURE)

The first use of the constant should be a mask constant, if you compare to a
single bit flag.

>+    {
>+        var issuer = o.server.connection.getCertificate().issuerOrganization;
>+        var tooltiptext = getMsg(MSG_SECURE_CONNECTION, issuer);
>+        securityButton.setAttribute("tooltiptext", tooltiptext);
>+        securityButton.firstChild.setAttribute("tooltiptext", tooltiptext);
>+        securityButton.lastChild.setAttribute("tooltiptext", tooltiptext);
>+    }
>+}

Also, let me get this right... this code will /always/ display the security
box? That seems wrong...


>+function displayCertificateInfo()
>+{
>+    var o = getObjectDetails (client.currentObject);

Nit: again. :)

>+    if (!o.server)
>+        return;
>+
>+    if (!o.server.isSecure)
>+    {
>+        alert(getMsg(MSG_INSECURE_SERVER, o.server.hostname));
>+        return;
>+    }
>+
>+    viewCert(o.server.connection.getCertificate());
>+}



>Index: mozilla/extensions/irc/xul/skin/chatzilla.css

>+/* Hack; Stop the status-bar from distorting without a security icon */
>+#status-text {
>+    min-height: 17px;
>+}
>+
>+#security-button {
>+    min-width: 20px;
>+    display: none;
>+}
>+
>+#security-button[level="high"], #security-button[level="low"], 
>+#security-button[level="broken"] {
>+    display: -moz-box;
>+}

*cough*

Can we do this the "nice" way, rather than thinking we know what display is
'right'?

#security-button:not([level="high"]):not([level="low"]):not([level="broken"]) {
    display: none;
}


>+
>+#security-button[level="high"] > image {
>+    list-style-image: url("chrome://chatzilla/skin/images/secure.png");
>+}
>+
>+#security-button[level="low"] > image {
>+    list-style-image: url("chrome://chatzilla/skin/images/secure.png");
>+}
>+
>+#security-button[level="broken"] > image {
>+    list-style-image: url("chrome://chatzilla/skin/images/security-broken.png");
>+}
>+
>+/* prevent margins of a value-less label from shifting the image */
>+#security-button > label:not([value]) {
>+    display: none;
>+}

See! You used :not() here! ;)
Fixes the nits, uses hex values for the constants, still no medium constant
because Mozilla doesn't use it either (check lxr for it, or in Silver's case,
your logs, as we discussed it previously), ondblclick handler now in
handlers.js, passing arrays to updateSecurityIcon instead of added-up
constants, which simplifies, clarifies and robustifies (if that's a word) the
security checking's logic. I've also fixed (as far as I can see) the criticism
on the css used.

Setting r? again.
Attachment #183187 - Attachment is obsolete: true
Attachment #185301 - Flags: review?(silver)
Attachment #183187 - Flags: review?(silver)
Comment on attachment 185301 [details] [diff] [review]
Patch with James' criticism fixed (should be)

r=silver with the stuff below addressed (don't need to bother with another
patch, they're all trivial changes).


>Index: mozilla/extensions/irc/js/lib/connection-xpcom.js

>+// Security Constants. 
>+const STATE_IS_BROKEN = 0x00000001;
>+const STATE_IS_SECURE = 0x00000002;
>+const STATE_IS_INSECURE = 0x00000004;
>+
>+const STATE_SECURE_LOW = 0x00020000;
>+const STATE_SECURE_HIGH = 0x00040000;

Since these are separate now (returned as separate items in the array) they
don't need to be in different bit positions. Do they even need to be bit flags?
Not from what I can see.... just give the items the values 1, 2, 3, 1, 2
respectively.

>+CBSConnection.prototype.getSecurityState =
>+function bc_getsecuritystate()

We could do with a comment above this explaining what it returns (array with at
least one item, and if the first item is STATE_IS_SECURE you get the security
level in a 2nd item).


>Index: mozilla/extensions/irc/xul/locale/en-US/chatzilla.properties

>+msg.insecure.server   = Your connection to the server ``%S'' is not secure.
>+msg.secure.connection = Signed by %S

This needs a " on the end (sorry I missed this before).

>+msg.security.info     = Displays security information about the current connection
Attachment #185301 - Flags: review?(silver) → review+
Comment on attachment 185301 [details] [diff] [review]
Patch with James' criticism fixed (should be)

Requesting approval for yet another ChatZilla patch.
Attachment #185301 - Flags: approval1.8b3?
Attachment #185301 - Flags: approval1.8b3? → approval1.8b3+
Checked in --> FIXED.
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Attachment #204044 - Attachment description: Unescapes URI escapes in JAR entry names when read from nsIJARURI → Nevermind, my apologies. I was sending a patch to #289851, I don't know where I got to the patch submission page for #283521 (wasn't even viewing this bug).
Attachment #204044 - Attachment is obsolete: true
Attachment #204044 - Attachment is patch: false
Whiteboard: [cz-0.9.69]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: