Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | "use strict"; |
michael@0 | 6 | |
michael@0 | 7 | module.metadata = { |
michael@0 | 8 | "stability": "unstable" |
michael@0 | 9 | }; |
michael@0 | 10 | |
michael@0 | 11 | const { EventEmitter } = require('../deprecated/events'); |
michael@0 | 12 | const { validateOptions } = require('../deprecated/api-utils'); |
michael@0 | 13 | const { isValidURI, URL } = require('../url'); |
michael@0 | 14 | const file = require('../io/file'); |
michael@0 | 15 | const { contract } = require('../util/contract'); |
michael@0 | 16 | const { isString, instanceOf } = require('../lang/type'); |
michael@0 | 17 | |
michael@0 | 18 | const LOCAL_URI_SCHEMES = ['resource', 'data']; |
michael@0 | 19 | |
michael@0 | 20 | // Returns `null` if `value` is `null` or `undefined`, otherwise `value`. |
michael@0 | 21 | function ensureNull(value) value == null ? null : value |
michael@0 | 22 | |
michael@0 | 23 | // map of property validations |
michael@0 | 24 | const valid = { |
michael@0 | 25 | contentURL: { |
michael@0 | 26 | map: function(url) !url ? ensureNull(url) : url.toString(), |
michael@0 | 27 | is: ['undefined', 'null', 'string'], |
michael@0 | 28 | ok: function (url) { |
michael@0 | 29 | if (url === null) |
michael@0 | 30 | return true; |
michael@0 | 31 | return isValidURI(url); |
michael@0 | 32 | }, |
michael@0 | 33 | msg: 'The `contentURL` option must be a valid URL.' |
michael@0 | 34 | }, |
michael@0 | 35 | contentScriptFile: { |
michael@0 | 36 | is: ['undefined', 'null', 'string', 'array', 'object'], |
michael@0 | 37 | map: ensureNull, |
michael@0 | 38 | ok: function(value) { |
michael@0 | 39 | if (value === null) |
michael@0 | 40 | return true; |
michael@0 | 41 | |
michael@0 | 42 | value = [].concat(value); |
michael@0 | 43 | |
michael@0 | 44 | // Make sure every item is a string or an |
michael@0 | 45 | // URL instance, and also a local file URL. |
michael@0 | 46 | return value.every(function (item) { |
michael@0 | 47 | |
michael@0 | 48 | if (!isString(item) && !(item instanceof URL)) |
michael@0 | 49 | return false; |
michael@0 | 50 | |
michael@0 | 51 | try { |
michael@0 | 52 | return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme); |
michael@0 | 53 | } |
michael@0 | 54 | catch(e) { |
michael@0 | 55 | return false; |
michael@0 | 56 | } |
michael@0 | 57 | }); |
michael@0 | 58 | |
michael@0 | 59 | }, |
michael@0 | 60 | msg: 'The `contentScriptFile` option must be a local URL or an array of URLs.' |
michael@0 | 61 | }, |
michael@0 | 62 | contentScript: { |
michael@0 | 63 | is: ['undefined', 'null', 'string', 'array'], |
michael@0 | 64 | map: ensureNull, |
michael@0 | 65 | ok: function(value) { |
michael@0 | 66 | return !Array.isArray(value) || value.every( |
michael@0 | 67 | function(item) { return typeof item === 'string' } |
michael@0 | 68 | ); |
michael@0 | 69 | }, |
michael@0 | 70 | msg: 'The `contentScript` option must be a string or an array of strings.' |
michael@0 | 71 | }, |
michael@0 | 72 | contentScriptWhen: { |
michael@0 | 73 | is: ['string'], |
michael@0 | 74 | ok: function(value) { return ~['start', 'ready', 'end'].indexOf(value) }, |
michael@0 | 75 | map: function(value) { |
michael@0 | 76 | return value || 'end'; |
michael@0 | 77 | }, |
michael@0 | 78 | msg: 'The `contentScriptWhen` option must be either "start", "ready" or "end".' |
michael@0 | 79 | }, |
michael@0 | 80 | contentScriptOptions: { |
michael@0 | 81 | ok: function(value) { |
michael@0 | 82 | if ( value === undefined ) { return true; } |
michael@0 | 83 | try { JSON.parse( JSON.stringify( value ) ); } catch(e) { return false; } |
michael@0 | 84 | return true; |
michael@0 | 85 | }, |
michael@0 | 86 | map: function(value) 'undefined' === getTypeOf(value) ? null : value, |
michael@0 | 87 | msg: 'The contentScriptOptions should be a jsonable value.' |
michael@0 | 88 | } |
michael@0 | 89 | }; |
michael@0 | 90 | exports.validationAttributes = valid; |
michael@0 | 91 | |
michael@0 | 92 | /** |
michael@0 | 93 | * Shortcut function to validate property with validation. |
michael@0 | 94 | * @param {Object|Number|String} suspect |
michael@0 | 95 | * value to validate |
michael@0 | 96 | * @param {Object} validation |
michael@0 | 97 | * validation rule passed to `api-utils` |
michael@0 | 98 | */ |
michael@0 | 99 | function validate(suspect, validation) validateOptions( |
michael@0 | 100 | { $: suspect }, |
michael@0 | 101 | { $: validation } |
michael@0 | 102 | ).$ |
michael@0 | 103 | |
michael@0 | 104 | function Allow(script) ({ |
michael@0 | 105 | get script() script, |
michael@0 | 106 | set script(value) script = !!value |
michael@0 | 107 | }) |
michael@0 | 108 | |
michael@0 | 109 | /** |
michael@0 | 110 | * Trait is intended to be used in some composition. It provides set of core |
michael@0 | 111 | * properties and bounded validations to them. Trait is useful for all the |
michael@0 | 112 | * compositions providing high level APIs for interaction with content. |
michael@0 | 113 | * Property changes emit `"propertyChange"` events on instances. |
michael@0 | 114 | */ |
michael@0 | 115 | const Loader = EventEmitter.compose({ |
michael@0 | 116 | /** |
michael@0 | 117 | * Permissions for the content, with the following keys: |
michael@0 | 118 | * @property {Object} [allow = { script: true }] |
michael@0 | 119 | * @property {Boolean} [allow.script = true] |
michael@0 | 120 | * Whether or not to execute script in the content. Defaults to true. |
michael@0 | 121 | */ |
michael@0 | 122 | get allow() this._allow || (this._allow = Allow(true)), |
michael@0 | 123 | set allow(value) this.allow.script = value && value.script, |
michael@0 | 124 | _allow: null, |
michael@0 | 125 | /** |
michael@0 | 126 | * The content to load. Either a string of HTML or a URL. |
michael@0 | 127 | * @type {String} |
michael@0 | 128 | */ |
michael@0 | 129 | get contentURL() this._contentURL, |
michael@0 | 130 | set contentURL(value) { |
michael@0 | 131 | value = validate(value, valid.contentURL); |
michael@0 | 132 | if (this._contentURL != value) { |
michael@0 | 133 | this._emit('propertyChange', { |
michael@0 | 134 | contentURL: this._contentURL = value |
michael@0 | 135 | }); |
michael@0 | 136 | } |
michael@0 | 137 | }, |
michael@0 | 138 | _contentURL: null, |
michael@0 | 139 | /** |
michael@0 | 140 | * When to load the content scripts. |
michael@0 | 141 | * Possible values are "end" (default), which loads them once all page |
michael@0 | 142 | * contents have been loaded, "ready", which loads them once DOM nodes are |
michael@0 | 143 | * ready (ie like DOMContentLoaded event), and "start", which loads them once |
michael@0 | 144 | * the `window` object for the page has been created, but before any scripts |
michael@0 | 145 | * specified by the page have been loaded. |
michael@0 | 146 | * Property change emits `propertyChange` event on instance with this key |
michael@0 | 147 | * and new value. |
michael@0 | 148 | * @type {'start'|'ready'|'end'} |
michael@0 | 149 | */ |
michael@0 | 150 | get contentScriptWhen() this._contentScriptWhen, |
michael@0 | 151 | set contentScriptWhen(value) { |
michael@0 | 152 | value = validate(value, valid.contentScriptWhen); |
michael@0 | 153 | if (value !== this._contentScriptWhen) { |
michael@0 | 154 | this._emit('propertyChange', { |
michael@0 | 155 | contentScriptWhen: this._contentScriptWhen = value |
michael@0 | 156 | }); |
michael@0 | 157 | } |
michael@0 | 158 | }, |
michael@0 | 159 | _contentScriptWhen: 'end', |
michael@0 | 160 | /** |
michael@0 | 161 | * Options avalaible from the content script as `self.options`. |
michael@0 | 162 | * The value of options can be of any type (object, array, string, etc.) |
michael@0 | 163 | * but only jsonable values will be available as frozen objects from the |
michael@0 | 164 | * content script. |
michael@0 | 165 | * Property change emits `propertyChange` event on instance with this key |
michael@0 | 166 | * and new value. |
michael@0 | 167 | * @type {Object} |
michael@0 | 168 | */ |
michael@0 | 169 | get contentScriptOptions() this._contentScriptOptions, |
michael@0 | 170 | set contentScriptOptions(value) this._contentScriptOptions = value, |
michael@0 | 171 | _contentScriptOptions: null, |
michael@0 | 172 | /** |
michael@0 | 173 | * The URLs of content scripts. |
michael@0 | 174 | * Property change emits `propertyChange` event on instance with this key |
michael@0 | 175 | * and new value. |
michael@0 | 176 | * @type {String[]} |
michael@0 | 177 | */ |
michael@0 | 178 | get contentScriptFile() this._contentScriptFile, |
michael@0 | 179 | set contentScriptFile(value) { |
michael@0 | 180 | value = validate(value, valid.contentScriptFile); |
michael@0 | 181 | if (value != this._contentScriptFile) { |
michael@0 | 182 | this._emit('propertyChange', { |
michael@0 | 183 | contentScriptFile: this._contentScriptFile = value |
michael@0 | 184 | }); |
michael@0 | 185 | } |
michael@0 | 186 | }, |
michael@0 | 187 | _contentScriptFile: null, |
michael@0 | 188 | /** |
michael@0 | 189 | * The texts of content script. |
michael@0 | 190 | * Property change emits `propertyChange` event on instance with this key |
michael@0 | 191 | * and new value. |
michael@0 | 192 | * @type {String|undefined} |
michael@0 | 193 | */ |
michael@0 | 194 | get contentScript() this._contentScript, |
michael@0 | 195 | set contentScript(value) { |
michael@0 | 196 | value = validate(value, valid.contentScript); |
michael@0 | 197 | if (value != this._contentScript) { |
michael@0 | 198 | this._emit('propertyChange', { |
michael@0 | 199 | contentScript: this._contentScript = value |
michael@0 | 200 | }); |
michael@0 | 201 | } |
michael@0 | 202 | }, |
michael@0 | 203 | _contentScript: null |
michael@0 | 204 | }); |
michael@0 | 205 | exports.Loader = Loader; |
michael@0 | 206 | |
michael@0 | 207 | exports.contract = contract(valid); |