diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-07-18 08:24:24 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-07-18 08:24:24 +0200 |
commit | fc61780b35af913801d72086456f493f63197da6 (patch) | |
tree | f85891288a7bd988da9f0f15ae64e5c63f00d493 /application/basilisk/modules/AttributionCode.jsm | |
parent | 69f7f9e5f1475891ce11cc4f431692f965b0cd30 (diff) | |
parent | 50d3e596bbe89c95615f96eb71f6bc5be737a1db (diff) | |
download | UXP-9ccb235f04529c1ec345d87dad6521cb567d20bb.tar UXP-9ccb235f04529c1ec345d87dad6521cb567d20bb.tar.gz UXP-9ccb235f04529c1ec345d87dad6521cb567d20bb.tar.lz UXP-9ccb235f04529c1ec345d87dad6521cb567d20bb.tar.xz UXP-9ccb235f04529c1ec345d87dad6521cb567d20bb.zip |
Merge commit '50d3e596bbe89c95615f96eb71f6bc5be737a1db' into Basilisk-releasev2018.07.18
# Conflicts:
# browser/app/profile/firefox.js
# browser/components/preferences/jar.mn
Diffstat (limited to 'application/basilisk/modules/AttributionCode.jsm')
-rw-r--r-- | application/basilisk/modules/AttributionCode.jsm | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/application/basilisk/modules/AttributionCode.jsm b/application/basilisk/modules/AttributionCode.jsm new file mode 100644 index 000000000..dc42b2be4 --- /dev/null +++ b/application/basilisk/modules/AttributionCode.jsm @@ -0,0 +1,123 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +this.EXPORTED_SYMBOLS = ["AttributionCode"]; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, 'AppConstants', + 'resource://gre/modules/AppConstants.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'OS', + 'resource://gre/modules/osfile.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'Services', + 'resource://gre/modules/Services.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'Task', + 'resource://gre/modules/Task.jsm'); + +const ATTR_CODE_MAX_LENGTH = 200; +const ATTR_CODE_KEYS_REGEX = /^source|medium|campaign|content$/; +const ATTR_CODE_VALUE_REGEX = /[a-zA-Z0-9_%\\-\\.\\(\\)]*/; +const ATTR_CODE_FIELD_SEPARATOR = "%26"; // URL-encoded & +const ATTR_CODE_KEY_VALUE_SEPARATOR = "%3D"; // URL-encoded = + +let gCachedAttrData = null; + +/** + * Returns an nsIFile for the file containing the attribution data. + */ +function getAttributionFile() { + let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile); + // appinfo does not exist in xpcshell, so we need defaults. + file.append(Services.appinfo.vendor || "mozilla"); + file.append(AppConstants.MOZ_APP_NAME); + file.append("postSigningData"); + return file; +} + +/** + * Returns an object containing a key-value pair for each piece of attribution + * data included in the passed-in attribution code string. + * If the string isn't a valid attribution code, returns an empty object. + */ +function parseAttributionCode(code) { + if (code.length > ATTR_CODE_MAX_LENGTH) { + return {}; + } + + let isValid = true; + let parsed = {}; + for (let param of code.split(ATTR_CODE_FIELD_SEPARATOR)) { + let [key, value] = param.split(ATTR_CODE_KEY_VALUE_SEPARATOR, 2); + if (key && ATTR_CODE_KEYS_REGEX.test(key)) { + if (value && ATTR_CODE_VALUE_REGEX.test(value)) { + parsed[key] = value; + } + } else { + isValid = false; + break; + } + } + return isValid ? parsed : {}; +} + +var AttributionCode = { + /** + * Reads the attribution code, either from disk or a cached version. + * Returns a promise that fulfills with an object containing the parsed + * attribution data if the code could be read and is valid, + * or an empty object otherwise. + */ + getAttrDataAsync() { + return Task.spawn(function*() { + if (gCachedAttrData != null) { + return gCachedAttrData; + } + + let code = ""; + try { + let bytes = yield OS.File.read(getAttributionFile().path); + let decoder = new TextDecoder(); + code = decoder.decode(bytes); + } catch (ex) { + // The attribution file may already have been deleted, + // or it may have never been installed at all; + // failure to open or read it isn't an error. + } + + gCachedAttrData = parseAttributionCode(code); + return gCachedAttrData; + }); + }, + + /** + * Deletes the attribution data file. + * Returns a promise that resolves when the file is deleted, + * or if the file couldn't be deleted (the promise is never rejected). + */ + deleteFileAsync() { + return Task.spawn(function*() { + try { + yield OS.File.remove(getAttributionFile().path); + } catch (ex) { + // The attribution file may already have been deleted, + // or it may have never been installed at all; + // failure to delete it isn't an error. + } + }); + }, + + /** + * Clears the cached attribution code value, if any. + * Does nothing if called from outside of an xpcshell test. + */ + _clearCache() { + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + if (env.exists("XPCSHELL_TEST_PROFILE_DIR")) { + gCachedAttrData = null; + } + }, +}; |