├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── .taskcluster.yml
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── README.md
├── eslint.config.mjs
├── extension
├── background.js
├── content
│ ├── broom.svg
│ ├── download.svg
│ ├── index.html
│ ├── list-2.3.1.min.js
│ ├── script.js
│ └── style.css
├── experiments
│ └── remotesettings
│ │ ├── api.js
│ │ └── schema.json
├── icon.svg
└── manifest.json
├── package-lock.json
├── package.json
├── renovate.json
├── screenshot.png
├── tests
└── selenium.spec.js
└── update.json
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | - main
6 | pull_request:
7 |
8 | name: CI
9 | jobs:
10 | lint:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 |
15 | - uses: actions/setup-node@v4
16 | with:
17 | node-version-file: 'package.json'
18 | cache: 'npm'
19 |
20 | - name: Print environment
21 | run: |
22 | node --version
23 | npm --version
24 |
25 | - name: Install Node dependencies
26 | run: npm ci
27 |
28 | - name: Code Style
29 | run: npm run cs-check
30 |
31 | - name: Code Lint
32 | run: npm run lint
33 |
34 | - name: Ext Lint
35 | run: npx web-ext lint --ignore-files="**/*.min.js" --warnings-as-errors --privileged --self-hosted --source-dir=extension/
36 |
37 | test:
38 | runs-on: ubuntu-latest
39 | env:
40 | TEST_TAG: user/app:test
41 | steps:
42 | - uses: actions/checkout@v4
43 |
44 | - name: Build container
45 | uses: docker/build-push-action@v6
46 | with:
47 | tags: ${{ env.TEST_TAG }}
48 | file: Dockerfile
49 | load: true
50 | context: .
51 |
52 | - name: Run container
53 | run: |
54 | docker run --rm ${{ env.TEST_TAG }} && sleep 5
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | web-ext-artifacts/
3 | node_modules/
4 | .vscode/
5 | rs-devtools/
6 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | extension/content/list-2.3.1.min.js
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | module.exports = {
3 | trailingComma: "all",
4 | proseWrap: "always",
5 | };
6 |
--------------------------------------------------------------------------------
/.taskcluster.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 1
3 | reporting: checks-v1
4 | policy:
5 | pullRequests: public
6 | tasks:
7 | - $let:
8 | # XXX Set to `true` for private repos
9 | privateRepo: false
10 | # XXX Use
11 | # `system` for system add-on,
12 | # `privileged` for AMO or self-hosted privileged add-on,
13 | # `mozillaonline-privileged` for Mozilla China add-on,
14 | # `normandy-privileged` for normandy add-on
15 | # to enable siging on push/PR.
16 | xpiSigningType: "privileged"
17 |
18 | template:
19 | repo: https://github.com/mozilla-extensions/xpi-template
20 | branch: main
21 | trustDomain: xpi
22 | in:
23 | $if: 'tasks_for in ["github-pull-request", "github-push", "action", "cron"]'
24 | then:
25 | $let:
26 | # Github events have this stuff in different places...
27 | ownerEmail:
28 | $if: 'tasks_for == "github-push"'
29 | then: '${event.pusher.email}'
30 | # Assume Pull Request
31 | else:
32 | $if: 'tasks_for == "github-pull-request"'
33 | then: '${event.pull_request.user.login}@users.noreply.github.com'
34 | else:
35 | $if: 'tasks_for in ["cron", "action"]'
36 | then: '${tasks_for}@noreply.mozilla.org'
37 | project:
38 | $if: 'tasks_for == "github-push"'
39 | then: '${event.repository.name}'
40 | else:
41 | $if: 'tasks_for == "github-pull-request"'
42 | then: '${event.pull_request.head.repo.name}'
43 | else:
44 | $if: 'tasks_for in ["cron", "action"]'
45 | then: '${repository.project}'
46 | head_branch:
47 | $if: 'tasks_for == "github-pull-request"'
48 | then: ${event.pull_request.head.ref}
49 | else:
50 | $if: 'tasks_for == "github-push"'
51 | then: ${event.ref}
52 | else:
53 | $if: 'tasks_for in ["cron", "action"]'
54 | then: '${push.branch}'
55 | head_sha:
56 | $if: 'tasks_for == "github-push"'
57 | then: '${event.after}'
58 | else:
59 | $if: 'tasks_for == "github-pull-request"'
60 | then: '${event.pull_request.head.sha}'
61 | else:
62 | $if: 'tasks_for in ["cron", "action"]'
63 | then: '${push.revision}'
64 | ownTaskId:
65 | $if: '"github" in tasks_for'
66 | then: {$eval: as_slugid("decision_task")}
67 | else:
68 | $if: 'tasks_for in ["cron", "action"]'
69 | then: '${ownTaskId}'
70 | repoFullName:
71 | $if: 'tasks_for in "github-push"'
72 | then: '${event.repository.full_name}'
73 | else:
74 | $if: 'tasks_for == "github-pull-request"'
75 | then: '${event.pull_request.base.repo.full_name}'
76 | else:
77 | $if: 'tasks_for in ["cron", "action"]'
78 | # Trim https://github.com/
79 | then: '${repository.url[19:]}'
80 | baseRepoUrl:
81 | $if: '!privateRepo' # public repo
82 | then:
83 | $if: 'tasks_for == "github-push"'
84 | then: '${event.repository.html_url}'
85 | else:
86 | $if: 'tasks_for == "github-pull-request"'
87 | then: '${event.pull_request.base.repo.html_url}'
88 | else:
89 | $if: 'tasks_for in ["cron", "action"]'
90 | then: '${repository.url}'
91 | else:
92 | $if: 'tasks_for == "github-push"'
93 | then: '${event.repository.ssh_url}'
94 | else:
95 | $if: 'tasks_for == "github-pull-request"'
96 | then: '${event.pull_request.base.repo.ssh_url}'
97 | else:
98 | $if: 'tasks_for in ["cron", "action"]'
99 | then: '${repository.url}'
100 | repoUrl:
101 | $if: '!privateRepo' # public repo
102 | then:
103 | $if: 'tasks_for == "github-push"'
104 | then: '${event.repository.html_url}'
105 | else:
106 | $if: 'tasks_for == "github-pull-request"'
107 | then: '${event.pull_request.head.repo.html_url}'
108 | else:
109 | $if: 'tasks_for in ["cron", "action"]'
110 | then: '${repository.url}'
111 | else:
112 | $if: 'tasks_for == "github-push"'
113 | then: '${event.repository.ssh_url}'
114 | else:
115 | $if: 'tasks_for == "github-pull-request"'
116 | then: '${event.pull_request.base.repo.ssh_url}'
117 | else:
118 | $if: 'tasks_for in ["cron", "action"]'
119 | then: '${repository.url}'
120 | in:
121 | $let:
122 | level: 1
123 | in:
124 | taskId:
125 | $if: 'tasks_for != "action"'
126 | then: '${ownTaskId}'
127 | taskGroupId:
128 | $if: 'tasks_for == "action"'
129 | then:
130 | '${action.taskGroupId}'
131 | else:
132 | '${ownTaskId}' # same as taskId; this is how automation identifies a decision task
133 | schedulerId: '${trustDomain}-level-${level}'
134 | created: {$fromNow: ''}
135 | deadline: {$fromNow: '1 day'}
136 | expires: {$fromNow: '1 year 1 second'} # 1 second so artifacts expire first, despite rounding errors
137 | metadata:
138 | $merge:
139 | - owner: "${ownerEmail}"
140 | - $if: '!privateRepo' # public repo
141 | then:
142 | source: '${repoUrl}/raw/${head_sha}/.taskcluster.yml'
143 | else:
144 | source: 'ssh://github.com/${repoUrl[15:-4]}/raw/${head_sha}/.taskcluster.yml'
145 | - $if: 'tasks_for in ["github-push", "github-pull-request"]'
146 | then:
147 | name: "Decision Task"
148 | description: 'The task that creates all of the other tasks in the task graph'
149 | else:
150 | $if: 'tasks_for == "action"'
151 | then:
152 | name: "Action: ${action.title}"
153 | description: '${action.description}'
154 | else:
155 | name: "Decision Task for cron job ${cron.job_name}"
156 | description: 'Created by a [cron task](https://tools.taskcluster.net/tasks/${cron.task_id})'
157 | provisionerId: "xpi-${level}"
158 | workerType: "decision-gcp"
159 | tags:
160 | $if: 'tasks_for in ["github-push", "github-pull-request"]'
161 | then:
162 | kind: decision-task
163 | else:
164 | $if: 'tasks_for == "action"'
165 | then:
166 | kind: 'action-callback'
167 | else:
168 | $if: 'tasks_for == "cron"'
169 | then:
170 | kind: cron-task
171 | routes:
172 | $flatten:
173 | - checks
174 | - $if: 'tasks_for == "github-push"'
175 | then:
176 | - "index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.decision"
177 | else: []
178 | scopes:
179 | $if: 'tasks_for == "github-push"'
180 | then:
181 | $let:
182 | short_head_branch:
183 | $if: 'head_branch[:10] == "refs/tags/"'
184 | then: {$eval: 'head_branch[10:]'}
185 | else:
186 | $if: 'head_branch[:11] == "refs/heads/"'
187 | then: {$eval: 'head_branch[11:]'}
188 | else: ${head_branch}
189 | in:
190 | - 'assume:repo:github.com/${repoFullName}:branch:${short_head_branch}'
191 |
192 |
193 | else:
194 | $if: 'tasks_for == "github-pull-request"'
195 | then:
196 | - 'assume:repo:github.com/${repoFullName}:pull-request'
197 |
198 | else:
199 | $if: 'tasks_for == "action"'
200 | then:
201 | # when all actions are hooks, we can calculate this directly rather than using a variable
202 | - '${action.repo_scope}'
203 | else:
204 | - 'assume:repo:github.com/${repoFullName}:cron:${cron.job_name}'
205 |
206 |
207 | requires: all-completed
208 | priority: lowest
209 | retries: 5
210 |
211 | payload:
212 | env:
213 | # run-task uses these to check out the source; the inputs
214 | # to `mach taskgraph decision` are all on the command line.
215 | $merge:
216 | - XPI_BASE_REPOSITORY: '${baseRepoUrl}'
217 | XPI_HEAD_REPOSITORY: '${repoUrl}'
218 | XPI_HEAD_REF: '${head_branch}'
219 | XPI_HEAD_REV: '${head_sha}'
220 | XPI_REPOSITORY_TYPE: git
221 | XPI_SIGNING_TYPE: '${xpiSigningType}'
222 | TEMPLATE_BASE_REPOSITORY: '${template.repo}'
223 | TEMPLATE_HEAD_REPOSITORY: '${template.repo}'
224 | TEMPLATE_HEAD_REV: '${template.branch}'
225 | TEMPLATE_HEAD_REF: '${template.branch}'
226 | TEMPLATE_REPOSITORY_TYPE: git
227 | TEMPLATE_PIP_REQUIREMENTS: taskcluster/requirements.txt
228 | REPOSITORIES: {$json: {xpi: "XPI Manifest", template: "XPI Template"}}
229 | HG_STORE_PATH: /builds/worker/checkouts/hg-store
230 | - $if: 'privateRepo'
231 | then:
232 | XPI_SSH_SECRET_NAME: project/xpi/xpi-github-clone-ssh
233 | - $if: 'tasks_for in ["github-pull-request"]'
234 | then:
235 | XPI_PULL_REQUEST_NUMBER: '${event.pull_request.number}'
236 | - $if: 'tasks_for == "action"'
237 | then:
238 | ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task
239 | ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded)
240 | ACTION_INPUT: {$json: {$eval: 'input'}}
241 | ACTION_CALLBACK: '${action.cb_name}'
242 | features:
243 | taskclusterProxy: true
244 | chainOfTrust: true
245 | # Note: This task is built server side without the context or tooling that
246 | # exist in tree so we must hard code the hash
247 | image: mozillareleases/taskgraph:decision-5483484ad45a3d27a0f5bd05f1c87d90e08df67a3713605d812b851a8a5bd854@sha256:ef132cc5741539f846a85bbe0cebc3c9ead30b8f24c1da46c55363f2170c3993
248 |
249 | maxRunTime: 1800
250 |
251 | command:
252 | - /usr/local/bin/run-task
253 | - '--xpi-checkout=/builds/worker/checkouts/src'
254 | - '--template-checkout=/builds/worker/checkouts/template'
255 | - '--task-cwd=/builds/worker/checkouts/src'
256 | - '--'
257 | - bash
258 | - -cx
259 | - $let:
260 | extraArgs: {$if: 'tasks_for == "cron"', then: '${cron.quoted_args}', else: ''}
261 | in:
262 | $if: 'tasks_for == "action"'
263 | then: >
264 | cd /builds/worker/checkouts/src &&
265 | rm -rf taskcluster &&
266 | ln -s /builds/worker/checkouts/template/taskcluster taskcluster &&
267 | ln -s /builds/worker/artifacts artifacts &&
268 | ~/.local/bin/taskgraph action-callback
269 | else: >
270 | rm -rf taskcluster &&
271 | ln -s /builds/worker/checkouts/template/taskcluster taskcluster &&
272 | ln -s /builds/worker/artifacts artifacts &&
273 | ~/.local/bin/taskgraph decision
274 | --pushlog-id='0'
275 | --pushdate='0'
276 | --project='${project}'
277 | --message=""
278 | --owner='${ownerEmail}'
279 | --level='${level}'
280 | --base-repository="$XPI_BASE_REPOSITORY"
281 | --head-repository="$XPI_HEAD_REPOSITORY"
282 | --head-ref="$XPI_HEAD_REF"
283 | --head-rev="$XPI_HEAD_REV"
284 | --repository-type="$XPI_REPOSITORY_TYPE"
285 | --tasks-for='${tasks_for}'
286 | ${extraArgs}
287 |
288 | artifacts:
289 | 'public':
290 | type: 'directory'
291 | path: '/builds/worker/artifacts'
292 | expires: {$fromNow: '1 year'}
293 |
294 | extra:
295 | $merge:
296 | - $if: 'tasks_for == "action"'
297 | then:
298 | parent: '${action.taskGroupId}'
299 | action:
300 | name: '${action.name}'
301 | context:
302 | taskGroupId: '${action.taskGroupId}'
303 | taskId: {$eval: 'taskId'}
304 | input: {$eval: 'input'}
305 | - $if: 'tasks_for == "cron"'
306 | then:
307 | cron: {$json: {$eval: 'cron'}}
308 | - tasks_for: '${tasks_for}'
309 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Community Participation Guidelines
2 |
3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines.
4 | For more details, please read the
5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
6 |
7 | ## How to Report
8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.
9 |
10 |
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Only used for testing
2 | FROM node:22-bookworm
3 |
4 | WORKDIR /opt
5 |
6 | # pull latest nightly
7 | RUN wget -O nightly.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US"
8 | RUN tar -xf nightly.tar.bz2
9 |
10 | # install firefox dependencies
11 | RUN apt update && apt install -y libasound2 libgtk-3-0 libx11-xcb1
12 |
13 | # copy files over
14 | COPY . ./
15 |
16 | # install node dependencies
17 | RUN npm ci
18 |
19 | ENV NIGHTLY_PATH="/opt/firefox/firefox"
20 |
21 | CMD npm run tcs:test
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Remote Settings Devtools
2 |
3 | This addon provides some tools to assist developers with remote settings.
4 |
5 | # Features
6 |
7 | - Trigger synchronization manually
8 | - Inspect local data
9 | - Clear local data
10 | - Switch from/to DEV, STAGE, or PROD
11 |
12 | 
13 |
14 |
15 | # Install
16 |
17 | ## Firefox for desktop
18 |
19 | - Pick the .xpi file from the [releases page](https://github.com/mozilla-extensions/remote-settings-devtools/releases).
20 | - When asked for confirmation, select "Continue to installation".
21 |
22 | > Note: it is highly recommended to use a temporary or development user profile
23 |
24 | ## Firefox for Android
25 |
26 | - Download the .xpi file from the [releases page](https://github.com/mozilla-extensions/remote-settings-devtools/releases).
27 | - Enable the Debug Menu: https://firefox-source-docs.mozilla.org/mobile/android/fenix/Secret-settings-debug-menu-instructions.html
28 | - Install the extension from file
29 |
30 | # Development
31 |
32 |
33 | This addon relies on the [Experiments API](https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html#webextensions-experiments) in order to expose Remote Settings internals to the Web Extension.
34 |
35 | Unsigned addons with experiments can only be loaded in Firefox Nightly and Developer Edition, with specific preferences set.
36 |
37 | 1. Download [Nightly](https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly)
38 | 2. Install dependencies with `npm install`
39 | 3. Run `npm run start:macos` or `npm run start:linux`, and it will spawn a browser window with the addon installed
40 | 4. Enjoy!
41 |
42 | It relies on [web-ext](https://github.com/mozilla/web-ext). Additional CLI params can be passed using `--`:
43 |
44 | ```
45 | npx run start:linux -- --firefox-profile rs-devtools --profile-create-if-missing --keep-profile-changes
46 | ```
47 |
48 | More information about the temporary loaded addon can be found in `about:debugging#/runtime/this-firefox`
49 |
50 | ## Running tests locally
51 |
52 | Automated tests can be run locally or in docker to verify changes.
53 | - `npm run tcs:docker` - will build and run the automated tests within a container using the latest firefox nightly package.
54 | - `npm run tcs:test` to run automated tests locally using your firefox nightly package.
55 | - Setting the `NIGHTLY_PATH` environment parameter will allow you to run tests against an arbitrary firefox nightly binary. Ex: `NIGHTLY_PATH=/opt/custom/nightly npm run tcs:test`
56 |
57 | # Release
58 |
59 | ### Prerequisites (get access to Ship-It)
60 |
61 | 1. Create a ticket to be added to the VPN group (can clone and edit [this Bugzilla ticket](https://bugzilla.mozilla.org/show_bug.cgi?id=1740098))
62 | 2. Ask in the [#addons-pipeline](https://mozilla.slack.com/archives/CMKP7NPKN) channel to be added to the `XPI_PRIVILEGED_BUILD_GROUP` to get access to create an XPI release for `remote-settings-devtools` on [Ship-It](https://shipit.mozilla-releng.net/)
63 |
64 | ### Create a new tag/release
65 |
66 | 1. Bump version in `package.json` and `extension/manifest.json`
67 | 2. Tag commit `git tag -a X.Y.Z` and push it `git push origin X.Y.Z`
68 | 3. Create release with changelog on [GitHub's releases page](https://github.com/mozilla-extensions/remote-settings-devtools/releases/new)
69 | 4. Check that `FirefoxCI` action has run for tagged commit
70 |
71 | ### Create release on Ship-It
72 |
73 | 1. Ensure you're connected to the VPN
74 | 2. Go to [Ship-It](https://shipit.mozilla-releng.net/)
75 | 3. Login with SSO at the top right
76 | 4. Click `Releases` > `Extensions` > `New` at the top and select the following options:
77 | - `Available XPIs` → `remote-settings-devtools`
78 | - `Available revisions` → revision with the commit hash associated with the tag that's being released
79 | 5. Ensure the version that was tagged is the one shown
80 | 6. Select `CREATE RELEASE` → `SUBMIT`
81 | 7. Scroll to the bottom of the [pending releases page](https://shipit.mozilla-releng.net/xpi)
82 | 8. Click `Build` > `Schedule` on the new release labeled `remote-settings-devtools-X.Y.Z-build1`
83 | 9. Submit a [sign off request](https://mana.mozilla.org/wiki/pages/viewpage.action?spaceKey=FDPDT&title=Mozilla+Add-on+Review+Requests+Intake)
84 |
85 | The binary will be published in the [releases page](https://github.com/mozilla-extensions/remote-settings-devtools/releases) automatically.
86 |
87 | 10. Update the `update.json` file to reflect the `version` value assigned by Taskcluster (eg. `1.9.0buildid20240422.103808`) and the download URL for the XPI file.
88 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import globals from "globals";
2 | import json from "eslint-plugin-json";
3 | import mozilla from "eslint-plugin-mozilla";
4 | import pluginJest from "eslint-plugin-jest";
5 |
6 | export default [
7 | {
8 | ignores: [
9 | "node_modules/",
10 | "web-ext-artifacts/",
11 | "extension/content/*.min.js",
12 | ],
13 | },
14 | {
15 | languageOptions: {
16 | globals: {
17 | ...globals.es2024,
18 | },
19 | },
20 | },
21 | ...mozilla.configs["flat/recommended"],
22 | {
23 | files: ["**/*.json"],
24 | plugins: { json },
25 | processor: json.processors[".json"],
26 | rules: json.configs.recommended.rules,
27 | },
28 | {
29 | files: ["extension/**"],
30 | languageOptions: {
31 | globals: {
32 | ...globals.webextensions,
33 | },
34 | },
35 | },
36 | {
37 | files: ["extension/content/*.js"],
38 | languageOptions: {
39 | globals: {
40 | ...globals.browser,
41 | },
42 | },
43 | },
44 | {
45 | files: ["extension/experiments/**/*.js"],
46 | languageOptions: {
47 | sourceType: "script",
48 | globals: {
49 | ...mozilla.environments.privileged.globals,
50 | },
51 | },
52 | },
53 | {
54 | files: [
55 | "tests/*.spec.js",
56 | ],
57 | languageOptions: {
58 | sourceType: "module",
59 | globals: {
60 | ...globals.node,
61 | ...pluginJest.environments.globals.globals,
62 | },
63 | },
64 | },
65 | {
66 | files: [
67 | ".prettierrc.js",
68 | ],
69 | languageOptions: {
70 | sourceType: "script",
71 | globals: {
72 | ...globals.node,
73 | },
74 | },
75 | },
76 | ];
--------------------------------------------------------------------------------
/extension/background.js:
--------------------------------------------------------------------------------
1 | browser.browserAction.onClicked.addListener(async () => {
2 | await browser.tabs.create({
3 | url: "content/index.html",
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/extension/content/broom.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/extension/content/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/extension/content/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
⚠️ Environment cannot be changed. Try running Firefox with environment variable