Giter Club home page Giter Club logo

extension-workshop's Introduction

CI

Firefox Extension Workshop

Welcome to Firefox Extension Workshop, a launchpad for building Firefox extensions! πŸš€

Updating Content

If you would like to update content or other resources on Firefox Extension Workshop, please refer to contributing.md

Development Guide: Getting Started

These instructions get a copy of the project up and running on your local machine for development and testing purposes.

For notes on how to deploy the project on a live system, see Deployment.

Prerequisites

  • Node JS. Runnning the LTS release is recommended.
  • Yarn for package management.
yarn install

To start local development, run:

yarn start

ℹ️ NOTE: Running locally will show unpublished content that uses the published: false convention in frontmatter. Content with published: false will not be available on staging or production.

Available yarn commands

Command Description
yarn start Starts eleventy and includes unpublished content.
yarn build:production Builds the site for production.
yarn build:unpublished Builds the site for production with unpublished content.
yarn clean Clears the output directory. (You probably won't need to use this manually.)

How the site is built

The site is built with Eleventy, a NodeJS-based static site generator.

The site works in slightly different ways depending on whether you're running the site for local development or building the site for production.

Development builds

When you run yarn start the CSS and JS is built in parallel with the eleventy build. Once up and running both eleventy and the JS and CSS build scripts watch for changes. When something changes the site is re-built.

In development Eleventy knows nothing about the CSS and JavaScript builds. For automatic reloading of the JS and CSS, each script uses a fetch to the public API to tell browserSync there is new code and it reloads it for you.

Production builds

Building for production is slightly different. The Eleventy process and the JS and CSS builds happen in series. Then a 3rd asset-pipeline process initiates and takes the the built content from ./build directory and runs it through various optimizations.

During these optimizations, the following takes place:

  • Binary files are versioned with hashes in the file names.
  • References to these file in CSS and JS are updated.
  • CSS and JS are minified.
  • The HTML is processed to update the references to the assets new hash-based filenames.

All of this means that we can serve the site with far-future Expires headers. If the resource is in the browser's cache, the browser won't even make a request for it. To break the cache, the resource's URL needs to change. When something is updated and the script is re-run, the hash in the filename will change, so the new filename won't be cached and the browser will know to fetch it. This helps the site be fast.

Whilst the asset-pipline script is custom, it leverages a lot of existing libs where possible, these include Terser, postHTML, postCSS, and various plugins.

It's likely that some day, 11ty will have its own mechanism for wrangling assets. At that point, this will no longer be required.

Asset paths

For the asset-pipeline script to do its thing, all you need to do is refer to all assets with a path beginning with /assets/. If you do that, everything else is handled for you ✨

Development Guide: Content Updates

This site has three templates:

  1. A full-width page
  2. A sidebar "page" for documentation
  3. A Content Guidelines page

Repo layout

extensionworkshop.com
β”œβ”€β”€ bin
β”‚   β”œβ”€β”€ asset-pipeline           # The asset build script
β”‚   β”œβ”€β”€ build-script             # The JS build script
β”‚   └── build-styles             # The CSS build script
β”‚
β”œβ”€β”€ build                        # Where eleventy builds the site to
β”‚
β”œβ”€β”€ dist                         # Where production builds are built
β”‚
β”œβ”€β”€ libs
β”‚   β”œβ”€β”€ markdown.js              # The markdown renderer instance and plugins
β”‚   β”œβ”€β”€ slugify.js               # The central slug function
β”‚   └── templates.js             # The liquidjs template instance
β”‚
β”œβ”€β”€ screenshots                  # Screenshots used in README.md
β”‚
β”œβ”€β”€ src
β”‚   β”œβ”€β”€ assets                   # Assets (CSS, JavaScript, fonts and images)
β”‚   β”œβ”€β”€ content                  # Content (Markdown and JS (generated))
β”‚   β”œβ”€β”€ data                     # Data files (JSON)
β”‚   β”œβ”€β”€ includes                 # Components (Liquid)
β”‚   └── layouts                  # Layout templates
β”‚
β”œβ”€β”€ tests                        # Test files run by jest `yarn test`.
β”‚
β”œβ”€β”€ eleventy.config.js           # Eleventy configuration
β”œβ”€β”€ .eleventyignore              # Files ignored by Eleventy
β”œβ”€β”€ .gitignore                   # Files not tracked by Git
β”œβ”€β”€ .stylelintrc                 # Stylelint configuration
β”œβ”€β”€ .prettierrc                  # Prettier config
β”œβ”€β”€ .prettierignore              # Files ignored by prettier
β”œβ”€β”€ .eslintrc                    # eslint config
β”œβ”€β”€ .eslintignore                # Files ignored by eslint
β”œβ”€β”€ package.json                 # Node.js package manifest
β”œβ”€β”€ yarn.lock                    # Package manager lock file
└── README.md                    # This file

Uploading media

  1. Add the image files to src/assets/img/
  2. In your page, link to images using this page structure:

You can reference images with the full path from the assets/ directory (e.g, /assets/img/image.png).

Here's an example in markdown:

![Remembear subtitle screenshot](/assets/img/remembear-subtitle.png "Remembear subtitle text")

Adding notes and alerts

For a note, use the markdown syntax extensions as follows. (These markdown extensions are supplied by a plugin to the markdown renderer.)

::: note
This is a note
:::

Looks like this Note Screenshot

For an alert, use the following:

::: note alert
This is an alert
:::

Looks like this Alert Screenshot

How to add a "sidebar" layout page

  1. Open data/pages.json.
  2. Add a node with appropriate attributes, in the appropriate location, for the new page. See below: Understanding the pages.json structure.
  3. Create a new page, nested inside a folder struture that matches the URL path. For example, for permalink /documentation/develop/best-practices-for-collecting-user-data-consents/, you would create a file called best-practices-for-collecting-user-data-consents.md and place it in documentation β–ΆοΈŽ develop.
  4. For reference on how to create a page, review the sidebar-master-template.md file, which lists all available modules. Some notes:
    • published: false will withhold this content from staging and production. To publish content, remove this line.
    • skip_index: true is used for pages that shouldn't be indexed for search results.
    • When creating page sections that should be listed in the table of contents, add an id attribute to the section container that matches the subpageitems entry added to pages.json. If your layout requires several sections for one table of contents entry, nest your sections inside a containing element which has the id attribute.
    • Rule for creating section ids: use the h2 title of the section, converted to lowercase, spaces replaced with dashes, all non-alphanumeric characters removed. For example, the section h2 title "Know your privacy settings" would be converted to know-your-privacy-settings for the section id.
    • The first section following the "Page Hero" module should be the "Table of Contents" module: modules/column-w-toc.html.

Understanding the pages.json structure

  • Each page has a title and url attribute.
    ℹ️ NOTE: The url attribute must exactly match the permalink attribute of the page's front matter (including leading and trailing slashes).
  • Pages may also have a subpageitems node for sections within the page to be referenced in the table of contents for that page:
    • Each subpageitem node has a title and id attribute. The value of id matches the id attribute of the section container.
      (ℹ️ NOTE: ids must be added to the containing element, rather than the heading element, of the section. This ensures that highlighting for the section remains active, even when the section title is out of view.)
  • Overview pages have category nodes for each of their contained (sub) categories.
  • Categories have a category attibute (which denotes the category title), and a pages attribute (which lists sub-pages of the overview page).
  • The Documentation Topics section pages are nested inside a subfolderitems node, which creates the dropdown panel.
General overview of the pages.json layout:
[
  {
    "title": "Documentation Topics",
    "subfolderitems": [
      {
        "title": "Develop",
        "url": "/documentation/develop/",
        "subpageitems": [
          {
            "title": "Firefox Tools",
            "id": "firefox-tools"
          }
        ],
        "categories": [
          {
            "category": "Getting Started",
            "pages": [
              {
                "title": "Firefox Workflow Overview",
                "url": "/documentation/develop/firefox-workflow-overview/"
              }
            ]
          }
        ]
      },
      {
        "title": "Publish",
        "url": "/documentation/publish/",
        "subpageitems": [
          {
            "title": "Get your extension signed",
           "id": "get-your-extension-signed"
          }
        ]
      },
      {
        "title": "Manage",
        "url": "/documentation/manage/",
        "subpageitems": [
          {
            "title": "Stay informed when Firefox changes",
            "id": "stay-informed-when-firefox-changes"
          }
        ]
      },
      {
        "title": "Enterprise",
        "url": "/documentation/enterprise/",
        "subpageitems": [
          {
            "title": "Section Title",
            "id": "introduction"
          }
        ]
      },
      {
        "title": "Themes",
        "url": "/documentation/themes/",
        "subpageitems": [
          {
            "title": "What themes are",
            "id": "what-themes-are"
          }
        ]
      }
    ]
  },
  {
    "title": "Extension Basics",
    "url": "/extension-basics/",
    "subpageitems": [
      {
        "title": "Getting started",
        "id": "getting-started"
      }
    ]
  },
  {
    "title": "Community",
    "url": "/community/",
    "subpageitems": [
      {
        "title": "Who is part of the community?",
        "id": "who-is-part-of-the-community"
      }
    ],
    "categories": [
      {
        "category": "About the Community",
        "pages": [
          {
            "title": "",
            "url": ""
          }
        ]
      }
    ]
  }
]

How to add a "Content Guidelines" page

Create a new page

  1. Create new file
  2. Add frontmatter (see example below)
  3. Copy 'modules' needed from content-guidelines/master-template.md and paste in new file
  4. Save as markdown: content-guidelines/page-name.md
---
layout: guides
title: Page Name
permalink: /content-guidelines/page-name/
published: false
---

ℹ️ NOTE: published: false will withhold this content from staging and production. To publish content, remove this line.

Add the page to the menu

Go to data/content-guidelines-pages.json and add a new entry for your page:

{
  "title": "Page Name",
  "url": "/content-guidelines/page-name/",
  "draft-label": true
}

Controlling draft labelling

If you don't want the page to be labelled as a draft (such as and when it's ready), remove "draft-label": true from the relevant entry in data/content-guidelines-pages.json.

Tagging

Tags should aim to follow the AMO calendar format: YYYY.MM.DD with an optional -x suffix for cherry-picking.

Deployment

Stage Deploys

The site is auto-deployed on commits to master to https://extensionworkshop.allizom.org/. You can check the version with the stage version link.

Production Deploys

Tags matching ^20\d{2}\.\d{2}\.\d{2}(?:-\d+)?$ regular expression will be deployed to https://extensionworkshop.com/. You can check the version on production with the production version link.

A good example tag for a production deploy would be 2022.03.03.

extension-workshop's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

extension-workshop's Issues

Security Checklist

Risk Management

  • The service must have performed a Rapid Risk Assessment and have a Risk Record bug
  • The service must be registered via a New Service issue

Infrastructure

  • Access and application logs must be archived for a minimum of 90 days
  • Use Modern or Intermediate TLS
  • Set HSTS to 31536000 (1 year)
    • strict-transport-security: max-age=31536000
    • If the service is not hosted under services.mozilla.com, it must be manually added to Firefox's preloaded pins. This only applies to production services, not short-lived experiments.
  • If service has an admin panels, it must:
    • only be available behind Mozilla VPN (which provides MFA)
    • require Auth0 authentication

Development

  • Ensure your code repository is configured and located appropriately:
    • Application built internally should be hosted in trusted GitHub organizations (mozilla, mozilla-services, mozilla-bteam, mozilla-conduit, mozilla-mobile, taskcluster). Sometimes we build and deploy applications we don't fully control. In those cases, the Dockerfile that builds the application container should be hosted in its own repository in a trusted organization.
    • Secure your repository by implementing Mozilla's GitHub security standard.
  • Sign all release tags, and ideally commits as well
    • Developers should configure git to sign all tags and upload their PGP fingerprint to https://login.mozilla.com
    • The signature verification will eventually become a requirement to shipping a release to staging & prod: the tag being deployed in the pipeline must have a matching tag in git signed by a project owner. This control is designed to reduce the risk of a 3rd party GitHub integration from compromising our source code.
  • enable security scanning of 3rd-party libraries and dependencies
    • For node.js, use npm audit with audit-filter to review and handle exceptions (see example in speech-proxy)
    • For Python, enable pyup security updates:
      • Add a pyup config to your repo (example config: https://github.com/mozilla-services/antenna/blob/master/.pyup.yml)
      • Enable branch protection for master and other development branches. Make sure the approved-mozilla-pyup-configuration team CANNOT push to those branches.
      • From the "add a team" dropdown for your repo /settings page
        • Add the "Approved Mozilla PyUp Configuration" team for your github org (e.g. for mozilla and mozilla-services)
        • Grant it write permission so it can make pull requests
      • notify [email protected] to enable the integration in pyup
  • Keep 3rd-party libraries up to date (in addition to the security updates)
  • Integrate static code analysis in CI, and avoid merging code with issues
    • Javascript applications should use ESLint with the Mozilla ruleset
    • Python applications should use Bandit
    • Go applications should use the Go Meta Linter
    • Use whitelisting mechanisms in these tools to deal with false positives

Dual Sign Off

  • Services that push data to Firefox clients must require a dual sign off on every change, implemented in their admin panels
    • This mechanism must be reviewed and approved by the Firefox Operations Security team before being enabled in production

Logging

  • Publish detailed logs in mozlog format (APP-MOZLOG)
    • Business logic must be logged with app specific codes (see FxA)
    • Access control failures must be logged at WARN level

Web Applications

  • Must have a CSP with
    • a report-uri pointing to the service's own /__cspreport__ endpoint
    • web API responses should return default-src 'none'; frame-ancestors 'none'; base-uri 'none'; report-uri /__cspreport__ to disallowing all content rendering, framing, and report violations
    • if default-src is not none, frame-src, and object-src should be none or only allow specific origins
    • no use of unsafe-inline or unsafe-eval in script-src, style-src, and img-src
  • Third-party javascript must be pinned to specific versions using Subresource Integrity (SRI)
  • Web APIs must set a non-HTML content-type on all responses, including 300s, 400s and 500s
  • Set the Secure and HTTPOnly flags on Cookies, and use sensible Expiration
  • Make sure your application gets an A+ on the Mozilla Observatory
  • Verify your application doesn't have any failures on the Security Baseline.
    • Contact secops@ or ping 'psiinon' on github to document exceptions to the baseline, mark csrf exempt forms, etc.
  • Web APIs should export an OpenAPI (Swagger) to facilitate automated vulnerability tests

Security Features

  • Authentication of end-users should be via FxA. Authentication of Mozillians should be via Auth0/SSO. Any exceptions must be approved by the security team.
  • Session Management should be via existing and well regarded frameworks. In all cases you should contact the security team for a design and implementation review
    • Store session keys server side (typically in a db) so that they can be revoked immediately.
    • Session keys must be changed on login to prevent session fixation attacks.
    • Session cookies must have HttpOnly and Secure flags set and the SameSite attribute set to 'strict' or 'lax' (which allows external regular links to login).
    • For more information about potential pitfalls see the OWASP Session Management Cheat Sheet
  • Form that change state should use anti CSRF tokens. Anti CSRF tokens can be dropped for internal sites using SameSite session cookies where we are sure all users will be on Firefox 60+. Forms that do not change state (e.g. search forms) should use the 'data-no-csrf' form attribute.
  • Access Control should be via existing and well regarded frameworks. If you really do need to roll your own then contact the security team for a design and implementation review.
  • If you are building a core Firefox service, consider adding it to the list of restricted domains in the preference extensions.webextensions.restrictedDomains. This will prevent a malicious extension from being able to steal sensitive information from it, see bug 1415644.

Databases

  • All SQL queries must be parameterized, not concatenated
  • Applications must use accounts with limited GRANTS when connecting to databases
    • In particular, applications must not use admin or owner accounts, to decrease the impact of a sql injection vulnerability.

Common issues

  • User data must be escaped for the right context prior to reflecting it
    • When inserting user generated html into an html context:
      • Python applications should use Bleach
      • Javascript applications should use DOMPurify
  • Apply sensible limits to user inputs, see input validation
    • POST body size should be small (<500kB) unless explicitly needed
  • When allowing users to upload or generate content, make sure to host that content on a separate domain (eg. firefoxusercontent.com, etc.). This will prevent malicious content from having access to storage and cookies from the origin.
    • Also use this technique to host rich content you can't protect with a CSP, such as metrics reports, wiki pages, etc.
  • When managing permissions, make sure access controls are enforced server-side
  • If an authenticated user accesses protected resource, make sure the pages with those resource arent cached and served up to unauthenticated users (like via a CDN).
  • If handling cryptographic keys, must have a mechanism to handle quarterly key rotations
    • Keys used to sign sessions don't need a rotation mechanism if destroying all sessions is acceptable in case of emergency.
  • Do not proxy requests from users without strong limitations and filtering (see Pocket UserData vulnerability). Don't proxy requests to link local, loopback, or private networks or DNS that resolves to addresses in those ranges (i.e. 169.254.0.0/16, 127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 172.16.0.0/12, 192.168.0.0/16, 198.18.0.0/15).
  • Do not use target="_blank" in external links unless you also use rel="noopener noreferrer" (to prevent Reverse Tabnabbing)

Minify JS

Currently the asset pipeline isn't compressing JS. The CSS is being minified.

Use a package manager for client side libraries

This is to allow us to be warned when client side libraries become out of date or have vulnerabilities reported against them.
This is part of the security checklist #31 so see that for more details of the recommended approaches.

Configure Google Analytics

Once we have a site id to use, it needs to be setup. At the same time we should use a hash for the inline-js in the CSP so that we don't need unsafe-inline for script-src.

Script isn't built from source as a build step

Ideally a script should be handling bundling of script but right now it seems like codekit is being used - which looks to be a desktop app. https://codekitapp.com/

Script should be bundled at build time by a script and not committed built.

If it's committed built then no package updates will have any effect and it will look like we have updated versions of dependencies when we don't which is obviously not a situation we want to be in.

CSP is currently blocking some script

Currently seeing the following in the console loading the page:

Content Security Policy: The page’s settings blocked the loading of a resource at https://code.jquery.com/jquery-1.12.4.min.js (β€œscript-src”).
Content Security Policy: The page’s settings blocked the loading of a resource at https://splashthat.com/sites/view/addonscommunityevent.splashthat.com?partial=823525519,495830716&screenshotHash=494156500dffa3d9 (β€œframe-src”).
Content Security Policy: The page’s settings blocked the loading of a resource at https://splashthat.com/v2/js/splash/bundles/splash-js-1.0.min.js (β€œscript-src”).
Content Security Policy: The page’s settings blocked the loading of a resource at https://rss.bloople.net/?url=https%3A%2F%2Fblog.mozilla.org%2Faddons%2Ffeed%2F&detail=140&limit=3&showtitle=false&type=js (β€œscript-src”).
ReferenceError: jQuery is not defined[Learn More] slick.min.js:1:129
ReferenceError: jQuery is not defined[Learn More]

CSP needs review

default-src 'self'; 
font-src 'self' fonts.gstatic.com use.typekit.net; 
form-action 'none'; 
frame-ancestors 'self';
img-src 'self' data: https://ssl.google-analytics.com https://www.google-analytics.com https://p.typekit.net/p.gif; 
object-src 'none';
script-src 'self' 'unsafe-inline' use.typekit.net https://ssl.google-analytics.com https://www.google-analytics.com/analytics.js;
style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'none';

Few things that stand-out at a glance:

  • form-action: 'none' will probably prevent the newsletter form from working.
  • base-uri should be defined.
  • Doe the site need to frame itself? Maybe frame-ancestors could be 'none'
  • Can default-src be 'none' that's a tighter default.
  • Does script-src need to allow 'unsafe-inline'? That weakens the CSP considerably.

Reduce image asset sizes

Image asset sizes are quite large in some cases, let's see if ImageOptim via jekyll-assets can help reduce the sizes as a first pass.

extension_workshop___firefox_extension_workshop__make_the_web_do_what_you_want__if_you_can_dream_it__our_open_souce_api_and_your_html__css__and_javascript_skills_can_make_it_happen_

Temporarily hide the Splash iFrame

The Splash events portal hasn't been rolled out to the Reps yet, so we should probably hide the iFrame for a little bit until the rollout happens and content is populated.

Add security headers to 404s

The staging site is only failing the security baseline on 2 things - good work team!
Both of them are missing security headers on 404s:

  • Content Security Policy (CSP) Header Not Set
  • Strict-Transport-Security Header Not Set
curl -I https://extensionworkshop.allizom.org/rubbish
HTTP/1.1 404 Not Found
Connection: keep-alive
x-amz-error-code: NoSuchKey
x-amz-error-message: The specified key does not exist.
x-amz-error-detail-Key: rubbish
Date: Fri, 08 Feb 2019 10:55:21 GMT
Server: AmazonS3
X-Cache: Error from cloudfront
Via: 1.1 16291083b92e5aa4f2f272f1da69c5e4.cloudfront.net (CloudFront)
X-Amz-Cf-Id: lhULSY3paIGZtnLmKVqfoSHkNPP-geVAnz5JTsDsAVcdsakOhQIRrA==

Can these be added?
Its not a blocker to going to production but would be good to fix these soon.

Setup a staging site

Since we need to iron out some CSP config issues would it be possible to deploy in the same way that we'd deploy to production on a staging site.

Maybe extensionsworkshop.allizom.org could be used or something else? This should be built from master. This way we can iron out the CSP config issues and any other deployment wrinkles ahead of the site being live on https://extensionsworkshop.com.

Firefox download links should have attribution

The links on AMO have attribution params such as

https://www.mozilla.org/firefox/channel/desktop/?utm_source=addons.mozilla.org&utm_campaign=footer&utm_medium=referral

This part needs to be added to the end of the download links ?utm_source=extensionworkshop.com&utm_campaign=footer&utm_medium=referral

Language switcher is a no-op

I'm not sure what the plan is for localization but currently the language switcher isn't actually doing anything.

Improve the build speed for local development

The build is quite slow for local development because all the image optimizations are happening there too. This was useful for setting that up, but it could be configured differently now that things are working so that optimizations only happen in production builds.

The way to do this would be to use a development config file and make modifications for dev.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.