Upgraded to shield utils 5.2.0 + ported over improvements from the jestr study
This commit is contained in:
Родитель
dc5e025631
Коммит
ad1fad004b
|
@ -1,10 +1,11 @@
|
|||
# do not lint/format generated artifacts
|
||||
test/results/
|
||||
test/results/coverage/
|
||||
dist/
|
||||
package-lock.json
|
||||
src/privileged/privacyContext/api.js
|
||||
src/privileged/privacyContext/schema.json
|
||||
src/privileged/privacyContext/stubApi.js
|
||||
# do not lint/format bundled util libraries
|
||||
src/privileged/prefs/api.js
|
||||
src/privileged/prefs/schema.json
|
||||
src/privileged/study/api.js
|
||||
src/privileged/study/schema.json
|
||||
# makes sure that eslintrc.js gets linted/formatted
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
dist/*
|
||||
node_modules/
|
||||
.env
|
||||
test/results/coverage
|
||||
/firefox-*
|
||||
|
|
|
@ -77,6 +77,10 @@ Telemetry pings are loaded into S3 and re:dash. Sample query:
|
|||
|
||||
* [All pings](https://sql.telemetry.mozilla.org/queries/{#your-id}/source#table)
|
||||
|
||||
(OR, if Pioneer, use the below instead)
|
||||
|
||||
Telemetry pings are loaded into the encrypted Pioneer pipeline.
|
||||
|
||||
## Improving this add-on
|
||||
|
||||
See [DEV.md](./docs/DEV.md) for more details on how to work with this add-on as a developer.
|
||||
|
|
|
@ -50,7 +50,7 @@ npm run build
|
|||
|
||||
## Details
|
||||
|
||||
First, make sure you are on NPM 6+ installed:
|
||||
First, make sure you are on NPM 8+ installed:
|
||||
|
||||
```shell
|
||||
npm install -g npm
|
||||
|
|
|
@ -27,9 +27,11 @@
|
|||
|
||||
* (Create profile: <https://developer.mozilla.org/Firefox/Multiple_profiles>, or via some other method)
|
||||
* Navigate to _about:config_ and set the following preferences. (If a preference does not exist, create it be right-clicking in the white area and selecting New -> String)
|
||||
* Set `shieldStudy.logLevel` to `All`. This permits shield-add-on log output in browser console.
|
||||
* Set `shieldStudy.logLevel` to `info`. This permits shield-add-on log output in browser console.
|
||||
* (If Pioneer study) Make sure that the [Firefox Pioneer Add-on](https://addons.mozilla.org/en-US/firefox/addon/firefox-pioneer/) is installed
|
||||
* Set `extensions.button-icon-preference_shield_mozilla_org.test.variationName` to `kittens` (or any other study variation/branch to test specifically)
|
||||
* Go to [this study's tracking bug](tbd: replace with your study's launch bug link in bugzilla) and install the latest add-on zip file
|
||||
* (If you are installing an unsigned version of the add-on, you need to set `extensions.legacy.enabled` to `true` before installing the add-on)
|
||||
|
||||
## Expected User Experience / Functionality
|
||||
|
||||
|
@ -116,6 +118,8 @@ Any UI in a Shield study should be consistent with standard Firefox design speci
|
|||
### Note: checking "sent Telemetry is correct"
|
||||
|
||||
* Open the Browser Console using Firefox's top menu at `Tools > Web Developer > Browser Console`. This will display Shield (loading/telemetry) log output from the add-on.
|
||||
* To inspect the (unencrypted) contents individual telemetry packets, set `shieldStudy.logLevel` to `all`. This permits debug-level shield-add-on log output in the browser console. Note that this will negatively affect the performance of Firefox.
|
||||
* To see the actual (encrypted if Pioneer study) payloads, go to `about:telemetry` -> Click `current ping` -> Select `Archived ping data` -> Ping Type `pioneer-study` -> Choose a payload -> Raw Payload
|
||||
|
||||
See [TELEMETRY.md](./TELEMETRY.md) for more details on what pings are sent by this add-on.
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
29
package.json
29
package.json
|
@ -7,7 +7,7 @@
|
|||
"url": "https://github.com/mozilla/shield-studies-addon-template/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"shield-studies-addon-utils": "github:mozilla/shield-studies-addon-utils#release/5.0.4"
|
||||
"shield-studies-addon-utils": "5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
|
@ -46,6 +46,7 @@
|
|||
"sinon": "4.0.0",
|
||||
"sinon-chrome": "2.2.1",
|
||||
"web-ext": "^2.9.3",
|
||||
"webext-experiment-utils": "github:mozilla/webext-experiment-utils#develop",
|
||||
"yamljs": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -65,15 +66,17 @@
|
|||
},
|
||||
"scripts": {
|
||||
"build": "web-ext build",
|
||||
"bundle-utils": "copyStudyUtils src/privileged",
|
||||
"build:use-if-pioneer-study": "web-ext build && importPioneerOptIn",
|
||||
"bundle:studyUtils": "copyStudyUtils src/privileged",
|
||||
"docformat": "doctoc --title '**Contents**' docs/*.md && prettier '**/*.md' --write",
|
||||
"eslint": "eslint . --ext jsm,js,json",
|
||||
"eslint-fix": "npm run eslint -- --fix",
|
||||
"format": "prettier '**/*.{css,js,json,jsm,md}' --trailing-comma=all --ignore-path=.eslintignore --write",
|
||||
"generate": "npm-run-all -s -n generate:schema:* generate:docs:* generate:stubApi:* format",
|
||||
"generate:docs:testingOverrides": "node ./node_modules/shield-studies-addon-utils/weeUtils/documentSchema.js ./src/privileged/testingOverrides/schema.json > ./src/privileged/testingOverrides/api.md",
|
||||
"generate:schema:testingOverrides": "cd ./src/privileged/testingOverrides && yaml2json schema.yaml -p > schema.json && node ../../../node_modules/shield-studies-addon-utils/weeUtils/verifyWeeSchema.js schema.json",
|
||||
"generate:stubApi:testingOverrides": "cd ./src/privileged/testingOverrides && node ../../../node_modules/shield-studies-addon-utils/weeUtils/generateStubApi.js ./schema.json > stubApi.js",
|
||||
"generate": "npm-run-all -s -n generate:generateSchema:* generate:verifyWeeSchema:* generate:documentSchema:* generate:generateStubApi:*",
|
||||
"generate:documentSchema:privacyContext": "cd src/privileged/privacyContext && documentSchema schema.json > api.md",
|
||||
"generate:generateSchema:privacyContext": "cd src/privileged/privacyContext && yaml2json schema.yaml -p > schema.json",
|
||||
"generate:generateStubApi:privacyContext": "cd src/privileged/privacyContext && generateStubApi ./schema.json > stubApi.js",
|
||||
"generate:verifyWeeSchema:privacyContext": "cd src/privileged/privacyContext && verifyWeeSchema schema.json",
|
||||
"harness_test": "npm run test:func -- --retry 2 --reporter json",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:eslint": "npm run eslint",
|
||||
|
@ -81,17 +84,21 @@
|
|||
"lint:nsp": "nsp check",
|
||||
"lint:web-ext-lint": "web-ext lint",
|
||||
"postformat": "npm run eslint-fix && fixpack",
|
||||
"prebuild": "npm run bundle-utils",
|
||||
"prestart": "npm run bundle-utils",
|
||||
"prebuild": "npm-run-all bundle:*",
|
||||
"prestart": "npm run pretest",
|
||||
"pretest": "node test/ensure_minimum_node_version.js && npm run build",
|
||||
"prewatch": "npm run bundle-utils",
|
||||
"prewatch": "npm-run-all bundle:*",
|
||||
"sign": "echo 'TBD, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1407757'",
|
||||
"start": "web-ext run --no-reload",
|
||||
"test": "npm-run-all -n test:unit test:func",
|
||||
"start:use-if-pioneer-study": "npm run test:manual",
|
||||
"test": "npm-run-all -n test:unit # test:func",
|
||||
"test:func": "npm-run-all -pr test:func:*",
|
||||
"test:func:selenium-mocha": "FIREFOX_BINARY=${FIREFOX_BINARY:-nightly} ADDON_ZIP=./dist/button_icon_preference_-_shield_study_example-2.0.0.zip GECKODRIVER_URL=http://127.0.0.1:4444 mocha test/functional/ --bail --full-trace",
|
||||
"test:func:start-geckodriver-server": "geckodriver -vv 1> test/results/logs/geckodriver.log 2> test/results/logs/geckodriver.errors.log",
|
||||
"test:manual": "npm-run-all -pr test:func:start-geckodriver-server test:run-firefox",
|
||||
"test:run-firefox": "FIREFOX_BINARY=${FIREFOX_BINARY:-nightly} ADDON_ZIP=./dist/button_icon_preference_-_shield_study_example-2.0.0.zip GECKODRIVER_URL=http://127.0.0.1:4444 node run-firefox.js",
|
||||
"test:unit": "NODE_ENV=test karma start",
|
||||
"watch": "web-ext run"
|
||||
"watch": "web-ext run",
|
||||
"watch:use-if-pioneer-study": "echo \"Watch is disabled since Pioneer Opt-in add-on needs to be available in the empty profile and web-ext thus is not an option\""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/* eslint-env node */
|
||||
/* global browser */
|
||||
|
||||
// for unhandled promise rejection debugging
|
||||
process.on("unhandledRejection", r => console.error(r)); // eslint-disable-line no-console
|
||||
|
||||
const utils = require("./test/functional/utils");
|
||||
|
||||
const STUDY_TYPE = process.env.STUDY_TYPE || "shield";
|
||||
const LOG_LEVEL = process.env.LOG_LEVEL || "info";
|
||||
const EXPIRE_SECONDS = process.env.EXPIRE_SECONDS || false;
|
||||
const EXPIRED = process.env.EXPIRED || false;
|
||||
|
||||
const run = async studyType => {
|
||||
const driver = await utils.setupWebdriver.promiseSetupDriver(
|
||||
utils.FIREFOX_PREFERENCES,
|
||||
);
|
||||
const widgetId = utils.ui.makeWidgetId(
|
||||
"jestr-pioneer-shield-study@pioneer.mozilla.org",
|
||||
);
|
||||
/*
|
||||
await utils.preferences.set(
|
||||
driver,
|
||||
`extensions.${widgetId}.test.studyType`,
|
||||
STUDY_TYPE,
|
||||
);
|
||||
*/
|
||||
if (EXPIRE_SECONDS > 0) {
|
||||
// Set preference that simulates that the study will expire after EXPIRE_SECONDS seconds
|
||||
const beginTime = Date.now();
|
||||
const msInOneDay = 60 * 60 * 24 * 1000;
|
||||
const expiresInDays = 7 * 5; // 5 weeks // Needs to be the same as in src/studySetup.js
|
||||
const firstRunTimestamp =
|
||||
beginTime - msInOneDay * expiresInDays + EXPIRE_SECONDS * 1000;
|
||||
await utils.preferences.set(
|
||||
driver,
|
||||
`extensions.${widgetId}.test.firstRunTimestamp`,
|
||||
String(firstRunTimestamp),
|
||||
);
|
||||
}
|
||||
if (EXPIRED) {
|
||||
// Set preference that simulates that the study has already expired before the study starts
|
||||
await utils.preferences.set(
|
||||
driver,
|
||||
`extensions.${widgetId}.test.expired`,
|
||||
true,
|
||||
);
|
||||
}
|
||||
await utils.preferences.set(driver, `shieldStudy.logLevel`, LOG_LEVEL);
|
||||
await utils.preferences.set(
|
||||
driver,
|
||||
`browser.ctrlTab.recentlyUsedOrder`,
|
||||
false,
|
||||
);
|
||||
if (studyType === "pioneer") {
|
||||
await utils.setupWebdriver.installPioneerOptInAddon(driver);
|
||||
}
|
||||
await utils.setupWebdriver.installAddon(driver);
|
||||
await utils.ui.openBrowserConsole(driver);
|
||||
|
||||
await driver.sleep(1000 * 60 * 60 * 24);
|
||||
driver.quit();
|
||||
};
|
||||
|
||||
run(STUDY_TYPE);
|
|
@ -48,6 +48,7 @@ class StudyLifeCycleHandler {
|
|||
*/
|
||||
browser.study.onEndStudy.addListener(this.handleStudyEnding.bind(this));
|
||||
browser.study.onReady.addListener(this.enableFeature.bind(this));
|
||||
this.expirationAlarmName = `${browser.runtime.id}:studyExpiration`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,6 +62,7 @@ class StudyLifeCycleHandler {
|
|||
*/
|
||||
async cleanup() {
|
||||
await browser.storage.local.clear();
|
||||
await browser.alarms.clear(this.expirationAlarmName);
|
||||
await feature.cleanup();
|
||||
}
|
||||
|
||||
|
@ -74,11 +76,11 @@ class StudyLifeCycleHandler {
|
|||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
enableFeature(studyInfo) {
|
||||
console.log("Enabling experiment", studyInfo);
|
||||
async enableFeature(studyInfo) {
|
||||
await browser.study.logger.log(["Enabling experiment", studyInfo]);
|
||||
const { delayInMinutes } = studyInfo;
|
||||
if (delayInMinutes !== undefined) {
|
||||
const alarmName = `${browser.runtime.id}:studyExpiration`;
|
||||
const alarmName = this.expirationAlarmName;
|
||||
const alarmListener = async alarm => {
|
||||
if (alarm.name === alarmName) {
|
||||
browser.alarms.onAlarm.removeListener(alarmListener);
|
||||
|
@ -90,7 +92,7 @@ class StudyLifeCycleHandler {
|
|||
delayInMinutes,
|
||||
});
|
||||
}
|
||||
feature.configure(studyInfo);
|
||||
return feature.configure(studyInfo);
|
||||
}
|
||||
|
||||
/** handles `study:end` signals
|
||||
|
@ -103,19 +105,19 @@ class StudyLifeCycleHandler {
|
|||
* @returns {undefined}
|
||||
*/
|
||||
async handleStudyEnding(ending) {
|
||||
console.log(`Study wants to end:`, ending);
|
||||
await browser.study.logger.log([`Study wants to end:`, ending]);
|
||||
for (const url of ending.urls) {
|
||||
await browser.tabs.create({ url });
|
||||
}
|
||||
switch (ending.endingName) {
|
||||
// could have different actions depending on positive / ending names
|
||||
default:
|
||||
console.log(`The ending: ${ending.endingName}`);
|
||||
await browser.study.logger.log(`The ending: ${ending.endingName}`);
|
||||
await this.cleanup();
|
||||
break;
|
||||
}
|
||||
// actually remove the addon.
|
||||
console.log("About to actually uninstall");
|
||||
await browser.study.logger.log("About to actually uninstall");
|
||||
return browser.management.uninstallSelf();
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +131,7 @@ async function onEveryExtensionLoad() {
|
|||
new StudyLifeCycleHandler();
|
||||
|
||||
const studySetup = await getStudySetup();
|
||||
console.log(`Study setup: `, studySetup);
|
||||
await browser.study.logger.log([`Study setup: `, studySetup]);
|
||||
await browser.study.setup(studySetup);
|
||||
}
|
||||
onEveryExtensionLoad();
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 24 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.6 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 9.5 KiB |
|
@ -12,7 +12,6 @@
|
|||
xmlns:ns1="http://sozi.baierouge.fr"
|
||||
id="svg2"
|
||||
sodipodi:docname="Shield Icon.svg"
|
||||
inkscape:export-filename="C:\Documents and Settings\Marrick\Desktop\Inkscape\Shield Icon.png"
|
||||
viewBox="0 0 256 256"
|
||||
inkscape:export-xdpi="90"
|
||||
version="1.1"
|
||||
|
|
До Ширина: | Высота: | Размер: 9.7 KiB После Ширина: | Высота: | Размер: 9.6 KiB |
|
@ -19,6 +19,14 @@
|
|||
"paths": [["introductionNotificationBar"]]
|
||||
}
|
||||
},
|
||||
"privacyContext": {
|
||||
"schema": "./privileged/privacyContext/schema.json",
|
||||
"parent": {
|
||||
"scopes": ["addon_parent"],
|
||||
"script": "./privileged/privacyContext/api.js",
|
||||
"paths": [["privacyContext"]]
|
||||
}
|
||||
},
|
||||
"study": {
|
||||
"schema": "./privileged/study/schema.json",
|
||||
"parent": {
|
||||
|
@ -26,14 +34,6 @@
|
|||
"script": "./privileged/study/api.js",
|
||||
"paths": [["study"]]
|
||||
}
|
||||
},
|
||||
"testingOverrides": {
|
||||
"schema": "./privileged/testingOverrides/schema.json",
|
||||
"parent": {
|
||||
"scopes": ["addon_parent"],
|
||||
"script": "./privileged/testingOverrides/api.js",
|
||||
"paths": [["testingOverrides"]]
|
||||
}
|
||||
}
|
||||
},
|
||||
"permissions": ["management", "storage", "alarms"],
|
||||
|
@ -41,7 +41,8 @@
|
|||
"scripts": ["studySetup.js", "feature.js", "background.js"]
|
||||
},
|
||||
"icons": {
|
||||
"48": "icons/shield-icon.svg"
|
||||
"48": "icons/shield-icon.48.png",
|
||||
"96": "icons/shield-icon.98.png"
|
||||
},
|
||||
"browser_action": {
|
||||
"browser_style": true,
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# ignore APIs that are bundled from shield-studies-addon-utils
|
||||
# ignore APIs that are maintained elsewhere
|
||||
study/
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
|
||||
/* global ExtensionAPI */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Console.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/*
|
||||
const {ExtensionCommon} = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
const {ExtensionUtils} = ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
const { EventManager } = ExtensionCommon;
|
||||
const { EventEmitter } = ExtensionUtils;
|
||||
*/
|
||||
|
||||
const { PrivateBrowsingUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
);
|
||||
|
||||
this.privacyContext = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
return {
|
||||
privacyContext: {
|
||||
permanentPrivateBrowsing: async function permanentPrivateBrowsing() {
|
||||
return PrivateBrowsingUtils.permanentPrivateBrowsing;
|
||||
},
|
||||
/*
|
||||
privateBrowsingAutostartEnabled: async function privateBrowsingAutostartEnabled() {
|
||||
const privateBrowsingAutostart = Preferences.get(
|
||||
"browser.privatebrowsing.autostart",
|
||||
);
|
||||
return privateBrowsingAutostart !== false;
|
||||
},
|
||||
*/
|
||||
aPrivateBrowserWindowIsOpen: async function aPrivateBrowserWindowIsOpen() {
|
||||
if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
|
||||
return true;
|
||||
}
|
||||
const windowList = Services.wm.getEnumerator("navigator:browser");
|
||||
while (windowList.hasMoreElements()) {
|
||||
const nextWin = windowList.getNext();
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(nextWin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
# Namespace: `browser.privacyContext`
|
||||
|
||||
Accesses privacy-related context / settings which can affect study/experiment behavior
|
||||
|
||||
## Functions
|
||||
|
||||
### `browser.privacyContext.permanentPrivateBrowsing( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
### `browser.privacyContext.aPrivateBrowserWindowIsOpen( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
## Events
|
||||
|
||||
(None)
|
||||
|
||||
## Properties TBD
|
||||
|
||||
## Data Types
|
||||
|
||||
(None)
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"namespace": "privacyContext",
|
||||
"description": "Accesses privacy-related context / settings which can affect study/experiment behavior",
|
||||
"functions": [
|
||||
{
|
||||
"name": "permanentPrivateBrowsing",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "aPrivateBrowserWindowIsOpen",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -13,26 +13,16 @@
|
|||
#
|
||||
|
||||
---
|
||||
- namespace: testingOverrides
|
||||
description: Accesses preferences used to set studySetup testing flags
|
||||
- namespace: privacyContext
|
||||
description: Accesses privacy-related context / settings which can affect study/experiment behavior
|
||||
|
||||
functions:
|
||||
- name: getVariationNameOverride
|
||||
- name: permanentPrivateBrowsing
|
||||
type: 'function'
|
||||
async: true
|
||||
description: ''
|
||||
parameters: []
|
||||
- name: getFirstRunTimestampOverride
|
||||
type: 'function'
|
||||
async: true
|
||||
description: ''
|
||||
parameters: []
|
||||
- name: getExpiredOverride
|
||||
type: 'function'
|
||||
async: true
|
||||
description: ''
|
||||
parameters: []
|
||||
- name: listPreferences
|
||||
- name: aPrivateBrowserWindowIsOpen
|
||||
type: 'function'
|
||||
async: true
|
||||
description: ''
|
|
@ -0,0 +1,33 @@
|
|||
/* eslint-env commonjs */
|
||||
/* eslint no-logger: off */
|
||||
/* eslint no-unused-vars: off */
|
||||
/* global ExtensionAPI */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
/* eslint-disable no-undef */
|
||||
const { EventManager } = ExtensionCommon;
|
||||
const EventEmitter =
|
||||
ExtensionCommon.EventEmitter || ExtensionUtils.EventEmitter;
|
||||
|
||||
this.privacyContext = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
const apiEventEmitter = new EventEmitter();
|
||||
return {
|
||||
privacyContext: {
|
||||
/* @TODO no description given */
|
||||
permanentPrivateBrowsing: async function permanentPrivateBrowsing() {
|
||||
console.log("Called permanentPrivateBrowsing()");
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/* @TODO no description given */
|
||||
aPrivateBrowserWindowIsOpen: async function aPrivateBrowserWindowIsOpen() {
|
||||
console.log("Called aPrivateBrowserWindowIsOpen()");
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -1,54 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/* global ExtensionAPI, Preferences */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Console.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
this.testingOverrides = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
const { extension } = this;
|
||||
|
||||
// Copied here from tree
|
||||
function makeWidgetId(id) {
|
||||
id = id.toLowerCase();
|
||||
return id.replace(/[^a-z0-9_-]/g, "_");
|
||||
}
|
||||
|
||||
const widgetId = makeWidgetId(extension.manifest.applications.gecko.id);
|
||||
|
||||
function convertToNumberIfNotNull(value) {
|
||||
return value !== null ? Number(value) : null;
|
||||
}
|
||||
|
||||
return {
|
||||
testingOverrides: {
|
||||
getVariationNameOverride: async function getVariationNameOverride() {
|
||||
return Preferences.get(
|
||||
`extensions.${widgetId}.test.variationName`,
|
||||
null,
|
||||
);
|
||||
},
|
||||
getFirstRunTimestampOverride: async function getFirstRunTimestampOverride() {
|
||||
return convertToNumberIfNotNull(
|
||||
Preferences.get(
|
||||
`extensions.${widgetId}.test.firstRunTimestamp`,
|
||||
null,
|
||||
),
|
||||
);
|
||||
},
|
||||
getExpiredOverride: async function getExpiredOverride() {
|
||||
return Preferences.get(`extensions.${widgetId}.test.expired`, null);
|
||||
},
|
||||
listPreferences: async function listPreferences() {
|
||||
return [
|
||||
`extensions.${widgetId}.test.variationName`,
|
||||
`extensions.${widgetId}.test.firstRunTimestamp`,
|
||||
`extensions.${widgetId}.test.expired`,
|
||||
];
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
# Namespace: `browser.testingOverrides`
|
||||
|
||||
Accesses preferences used to set studySetup testing flags
|
||||
|
||||
## Functions
|
||||
|
||||
### `browser.testingOverrides.getVariationNameOverride( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
### `browser.testingOverrides.getFirstRunTimestampOverride( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
### `browser.testingOverrides.getExpiredOverride( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
### `browser.testingOverrides.listPreferences( )`
|
||||
|
||||
**Parameters**
|
||||
|
||||
## Events
|
||||
|
||||
(None)
|
||||
|
||||
## Properties TBD
|
||||
|
||||
## Data Types
|
||||
|
||||
(None)
|
|
@ -1,36 +0,0 @@
|
|||
[
|
||||
{
|
||||
"namespace": "testingOverrides",
|
||||
"description": "Accesses preferences used to set studySetup testing flags",
|
||||
"functions": [
|
||||
{
|
||||
"name": "getVariationNameOverride",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "getFirstRunTimestampOverride",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "getExpiredOverride",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "listPreferences",
|
||||
"type": "function",
|
||||
"async": true,
|
||||
"description": "",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,41 +0,0 @@
|
|||
/* eslint-disable */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const { EventManager } = ExtensionCommon;
|
||||
// eslint-disable-next-line no-undef
|
||||
const { EventEmitter } = ExtensionUtils;
|
||||
|
||||
this.testingOverrides = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
return {
|
||||
testingOverrides: {
|
||||
/* @TODO no description given */
|
||||
getVariationNameOverride: async function getVariationNameOverride() {
|
||||
console.log("called getVariationNameOverride ");
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/* @TODO no description given */
|
||||
getFirstRunTimestampOverride: async function getFirstRunTimestampOverride() {
|
||||
console.log("called getFirstRunTimestampOverride ");
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/* @TODO no description given */
|
||||
getExpiredOverride: async function getExpiredOverride() {
|
||||
console.log("called getExpiredOverride ");
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/* @TODO no description given */
|
||||
listPreferences: async function listPreferences() {
|
||||
console.log("called listPreferences ");
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -22,15 +22,17 @@ const baseStudySetup = {
|
|||
// used for activeExperiments tagging (telemetryEnvironment.setActiveExperiment)
|
||||
activeExperimentName: browser.runtime.id,
|
||||
|
||||
// uses shield sampling and telemetry semantics. Future: will support "pioneer"
|
||||
// use either "shield" or "pioneer" telemetry semantics and data pipelines
|
||||
studyType: "shield",
|
||||
|
||||
// telemetry
|
||||
telemetry: {
|
||||
// default false. Actually send pings.
|
||||
// Actually submit the pings to Telemetry. [default if omitted: false]
|
||||
send: true,
|
||||
// Marks pings with testing=true. Set flag to `true` before final release
|
||||
removeTestingFlag: false,
|
||||
// Marks pings with testing=true. Set flag to `true` for pings are meant to be seen by analysts [default if omitted: false]
|
||||
removeTestingFlag: true,
|
||||
// Keep an internal telemetry archive. Useful for verifying payloads of Pioneer studies without risking actually sending any unencrypted payloads [default if omitted: false]
|
||||
internalTelemetryArchive: false,
|
||||
},
|
||||
|
||||
// endings with urls
|
||||
|
@ -95,6 +97,24 @@ const baseStudySetup = {
|
|||
},
|
||||
};
|
||||
|
||||
async function isCurrentlyEligible(studySetup) {
|
||||
const dataPermissions = await browser.study.getDataPermissions();
|
||||
if (studySetup.studyType === "shield") {
|
||||
allowed = dataPermissions.shield;
|
||||
}
|
||||
if (studySetup.studyType === "pioneer") {
|
||||
allowed = dataPermissions.pioneer;
|
||||
}
|
||||
// Users with private browsing on autostart are not eligible
|
||||
if (await browser.privacyContext.permanentPrivateBrowsing()) {
|
||||
await browser.study.logger.log(
|
||||
"Permanent private browsing, exiting study",
|
||||
);
|
||||
allowed = false;
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine, based on common and study-specific criteria, if enroll (first run)
|
||||
* should proceed.
|
||||
|
@ -107,24 +127,23 @@ const baseStudySetup = {
|
|||
*
|
||||
* This implementation caches in local storage to speed up second run.
|
||||
*
|
||||
* @param {object} studySetup A complete study setup object
|
||||
* @returns {Promise<boolean>} answer An boolean answer about whether the user should be
|
||||
* allowed to enroll in the study
|
||||
*/
|
||||
async function cachingFirstRunShouldAllowEnroll() {
|
||||
async function wasEligibleAtFirstRun(studySetup) {
|
||||
// Cached answer. Used on 2nd run
|
||||
let allowed = await browser.storage.local.get("allowEnroll");
|
||||
if (allowed) return true;
|
||||
const localStorageResult = await browser.storage.local.get(
|
||||
"allowedEnrollOnFirstRun",
|
||||
);
|
||||
if (localStorageResult.allowedEnrollOnFirstRun === true) return true;
|
||||
|
||||
/*
|
||||
First run, we must calculate the answer.
|
||||
If false, the study will endStudy with 'ineligible' during `setup`
|
||||
*/
|
||||
|
||||
// could have other reasons to be eligible, such add-ons, prefs
|
||||
allowed = true;
|
||||
// First run, we must calculate the answer.
|
||||
// If false, the study will endStudy with 'ineligible' during `setup`
|
||||
const allowed = await isCurrentlyEligible(studySetup);
|
||||
|
||||
// cache the answer
|
||||
await browser.storage.local.set({ allowEnroll: allowed });
|
||||
await browser.storage.local.set({ allowedEnrollOnFirstRun: allowed });
|
||||
return allowed;
|
||||
}
|
||||
|
||||
|
@ -137,17 +156,20 @@ async function getStudySetup() {
|
|||
// shallow copy
|
||||
const studySetup = Object.assign({}, baseStudySetup);
|
||||
|
||||
studySetup.allowEnroll = await cachingFirstRunShouldAllowEnroll();
|
||||
studySetup.allowEnroll = await wasEligibleAtFirstRun(studySetup);
|
||||
|
||||
const testingPreferences = await browser.testingOverrides.listPreferences();
|
||||
console.log(
|
||||
"The preferences that can be used to override testing flags: ",
|
||||
testingPreferences,
|
||||
);
|
||||
// If the eligibility criterias are not dependent on the state of the first run only
|
||||
// but rather should be checked on every browser launch, skip the use
|
||||
// of wasEligibleAtFirstRun and instead use the below:
|
||||
// studySetup.allowEnroll = await wasEligibleAtFirstRun(studySetup);
|
||||
|
||||
const testingOverrides = await browser.study.getTestingOverrides();
|
||||
studySetup.testing = {
|
||||
variationName: await browser.testingOverrides.getVariationNameOverride(),
|
||||
firstRunTimestamp: await browser.testingOverrides.getFirstRunTimestampOverride(),
|
||||
expired: await browser.testingOverrides.getExpiredOverride(),
|
||||
variationName: testingOverrides.variationName,
|
||||
firstRunTimestamp: testingOverrides.firstRunTimestamp,
|
||||
expired: testingOverrides.expired,
|
||||
};
|
||||
// TODO: Possible add testing override for studySetup.telemetry.internalTelemetryArchive
|
||||
|
||||
return studySetup;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ const FIREFOX_PREFERENCES = {
|
|||
// Re-usable test methods from shield-studies-addon-utils
|
||||
const { executeJs } = require("shield-studies-addon-utils/testUtils/executeJs");
|
||||
const { nav } = require("shield-studies-addon-utils/testUtils/nav");
|
||||
const {
|
||||
preferences,
|
||||
} = require("shield-studies-addon-utils/testUtils/preferences");
|
||||
const {
|
||||
setupWebdriver,
|
||||
} = require("shield-studies-addon-utils/testUtils/setupWebdriver");
|
||||
|
@ -49,6 +52,7 @@ module.exports = {
|
|||
FIREFOX_PREFERENCES,
|
||||
executeJs,
|
||||
nav,
|
||||
preferences,
|
||||
setupWebdriver,
|
||||
telemetry,
|
||||
ui,
|
||||
|
|
|
@ -13,7 +13,10 @@ const defaultConfig = {
|
|||
firefox: process.env.FIREFOX_BINARY || "nightly",
|
||||
browserConsole: true,
|
||||
startUrl: ["about:debugging"],
|
||||
pref: ["shieldStudy.logLevel=All"],
|
||||
pref: [
|
||||
"shieldStudy.logLevel=All",
|
||||
"browser.ctrlTab.recentlyUsedOrder=false",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче