@@ -640,8 +640,15 @@ const HTTPSRules = {
640640 return output ;
641641 } ,
642642
643+ /**
644+ * Return a list of rulesets that declare targets matching a given hostname.
645+ * The returned rulesets include those that are disabled for various reasons.
646+ * This function is only defined for fully-qualified hostnames. Wildcards and
647+ * cookie-style domain attributes with a leading dot are not permitted.
648+ * @param host {string}
649+ * @return {Array.<RuleSet> }
650+ */
643651 potentiallyApplicableRulesets : function ( host ) {
644- // Return a list of rulesets that declare targets matching this host
645652 var i , tmp , t ;
646653 var results = [ ] ;
647654
@@ -655,6 +662,10 @@ const HTTPSRules = {
655662 var segmented = host . split ( "." ) ;
656663 for ( i = 0 ; i < segmented . length ; ++ i ) {
657664 tmp = segmented [ i ] ;
665+ if ( tmp . length === 0 ) {
666+ this . log ( WARN , "Malformed host passed to potentiallyApplicableRulesets: " + host ) ;
667+ return null ;
668+ }
658669 segmented [ i ] = "*" ;
659670 t = segmented . join ( "." ) ;
660671 segmented [ i ] = tmp ;
@@ -702,23 +713,48 @@ const HTTPSRules = {
702713 this . log ( NOTE , count + " hits: average subsequent call to potentiallyApplicableRulesets took " + ( t2 - t1 ) / domains_l + " milliseconds" ) ;
703714 } ,
704715
705- shouldSecureCookie : function ( applicable_list , c , known_https ) {
706- // Check to see if the Cookie object c meets any of our cookierule citeria
707- // for being marked as secure.
708- // @applicable_list : an ApplicableList or record keeping
709- // @c : an nsICookie2
710- // @known_https : true if we know the page setting the cookie is https
716+ /**
717+ * If a cookie's domain attribute has a leading dot to indicate it should be
718+ * sent for all subdomains (".example.com"), return the actual host part (the
719+ * part after the dot).
720+ *
721+ * @param cookieDomain {string} A cookie domain to strip a leading dot from.
722+ * @return {string } a fully qualified hostname.
723+ */
724+ hostFromCookieDomain : function ( cookieDomain ) {
725+ if ( cookieDomain . length > 0 && cookieDomain [ 0 ] == "." ) {
726+ return cookieDomain . slice ( 1 ) ;
727+ } else {
728+ return cookieDomain ;
729+ }
730+ } ,
711731
732+ /**
733+ * Check to see if the Cookie object c meets any of our cookierule citeria
734+ * for being marked as secure.
735+ *
736+ * @param applicable_list {ApplicableList} an ApplicableList for record keeping
737+ * @param c {nsICookie2} The cookie we might secure.
738+ * @param known_https {boolean} True if the cookie appeared in an HTTPS request and
739+ * so we know it is okay to mark it secure (assuming a cookierule matches it.
740+ * TODO(jsha): Double-check that the code calling this actually does that.
741+ * @return {boolean } True if the cookie in question should have the 'secure'
742+ * flag set to true.
743+ */
744+ shouldSecureCookie : function ( applicable_list , c , known_https ) {
712745 this . log ( DBUG , " rawhost: " + c . rawHost + " name: " + c . name + " host" + c . host ) ;
713746 var i , j ;
714- var rs = this . potentiallyApplicableRulesets ( c . host ) ;
747+ // potentiallyApplicableRulesets is defined on hostnames not cookie-style
748+ // "domain" attributes, so we strip a leading dot before calling.
749+ var rs = this . potentiallyApplicableRulesets ( this . hostFromCookieDomain ( c . host ) ) ;
715750 for ( i = 0 ; i < rs . length ; ++ i ) {
716751 var ruleset = rs [ i ] ;
717752 if ( ruleset . active ) {
718753 ruleset . ensureCompiled ( ) ;
719754 // Never secure a cookie if this page might be HTTP
720- if ( ! known_https && ! this . safeToSecureCookie ( c . rawHost ) )
755+ if ( ! ( known_https || this . safeToSecureCookie ( c . rawHost ) ) ) {
721756 continue ;
757+ }
722758 for ( j = 0 ; j < ruleset . cookierules . length ; j ++ ) {
723759 var cr = ruleset . cookierules [ j ] ;
724760 if ( cr . host_c . test ( c . host ) && cr . name_c . test ( c . name ) ) {
@@ -727,37 +763,45 @@ const HTTPSRules = {
727763 return true ;
728764 }
729765 }
730- if ( ruleset . cookierules . length > 0 )
731- if ( applicable_list ) applicable_list . moot_rule ( ruleset ) ;
766+ if ( ruleset . cookierules . length > 0 && applicable_list ) {
767+ applicable_list . moot_rule ( ruleset ) ;
768+ }
732769 } else if ( ruleset . cookierules . length > 0 ) {
733- if ( applicable_list ) applicable_list . inactive_rule ( ruleset ) ;
770+ if ( applicable_list ) {
771+ applicable_list . inactive_rule ( ruleset ) ;
772+ }
734773 this . log ( INFO , "Inactive cookie rule " + ruleset . name ) ;
735774 }
736775 }
737776 return false ;
738777 } ,
739778
779+ /**
780+ * Check if the domain might be being served over HTTP. If so, it isn't
781+ * safe to secure a cookie! We can't always know this for sure because
782+ * observing cookie-changed doesn't give us enough context to know the
783+ * full origin URI. In particular, if cookies are set from Javascript (as
784+ * opposed to HTTP/HTTPS responses), we don't know what page context that
785+ * Javascript ran in.
786+
787+ * First, if there are any redirect loops on this domain, don't secure
788+ * cookies. XXX This is not a very satisfactory heuristic. Sometimes we
789+ * would want to secure the cookie anyway, because the URLs that loop are
790+ * not authenticated or not important. Also by the time the loop has been
791+ * observed and the domain blacklisted, a cookie might already have been
792+ * flagged as secure.
793+ *
794+ * @param domain {string} The cookie's 'domain' attribute.
795+ * @return {boolean } True if it's safe to secure a cookie on that domain.
796+ */
740797 safeToSecureCookie : function ( domain ) {
741- // Check if the domain might be being served over HTTP. If so, it isn't
742- // safe to secure a cookie! We can't always know this for sure because
743- // observing cookie-changed doesn't give us enough context to know the
744- // full origin URI.
745-
746- // First, if there are any redirect loops on this domain, don't secure
747- // cookies. XXX This is not a very satisfactory heuristic. Sometimes we
748- // would want to secure the cookie anyway, because the URLs that loop are
749- // not authenticated or not important. Also by the time the loop has been
750- // observed and the domain blacklisted, a cookie might already have been
751- // flagged as secure.
752-
753798 if ( domain in https_blacklist_domains ) {
754799 this . log ( INFO , "cookies for " + domain + "blacklisted" ) ;
755800 return false ;
756801 }
757802
758803 // If we passed that test, make up a random URL on the domain, and see if
759804 // we would HTTPSify that.
760-
761805 try {
762806 var nonce_path = "/" + Math . random ( ) . toString ( ) ;
763807 nonce_path = nonce_path + nonce_path ;
@@ -769,7 +813,9 @@ const HTTPSRules = {
769813 }
770814
771815 this . log ( DBUG , "Testing securecookie applicability with " + test_uri ) ;
772- var rs = this . potentiallyApplicableRulesets ( domain ) ;
816+ // potentiallyApplicableRulesets is defined on hostnames not cookie-style
817+ // "domain" attributes, so we strip a leading dot before calling.
818+ var rs = this . potentiallyApplicableRulesets ( this . hostFromCookieDomain ( domain ) ) ;
773819 for ( var i = 0 ; i < rs . length ; ++ i ) {
774820 if ( ! rs [ i ] . active ) continue ;
775821 var rewrite = rs [ i ] . apply ( test_uri ) ;
0 commit comments