How the install works

Why the installer asks for an invite code, what it checks before it unpacks anything, why the scope goes in your home directory, and the Chrome profile it opens.

An install fetches code from this site and runs it, so the first question is who the installer lets through, the second is what stops a tampered copy, and the third is why the steps ask for what they do — a home-directory file, developer mode, a directory in your home folder and a Chrome profile of its own. Install the Chrome extension and Install a server are the steps.

The invite code

Commentware is invite-only for now, and the installer asks for the same invite code the homepage takes. The check runs on your own machine, so it is a gate and not a lock: it keeps out anybody who does not read the installer’s source, and nobody who does.

The installer asks on its first run, before it fetches anything from the registry. It opens your terminal itself, so it asks under curl … | sh as well. A code is twelve letters and digits, and its first four characters name its batch. The site publishes a list for each batch at /codes/<batch>.json. The list holds the SHA-256 digest of every code in the batch, not the codes. The installer downloads the list for your code’s batch and looks for your code’s digest in it. Capitals, spaces and dashes do not matter, so ABCD EFGH JKMN is abcd-efgh-jkmn. A wrong answer is refused with That is not a valid invite code., and the installer asks again, three tries in all; after the third it stops and installs nothing.

A valid code is kept in ~/Commentware/invite (%USERPROFILE%\Commentware\invite on Windows), and every later run checks it against the list again. A 404 for the batch, or a list that does not hold the digest, removes the file and the installer asks for a new code. An error other than not found, such as a server that is down or a timeout, keeps the code and the run goes on. Delete the file to be asked again.

Two cases stop a run with nothing installed. On a first run, or with --invite, a hub that cannot be reached stops the run, because nothing has admitted the machine yet. A code given with --invite that is not valid stops the run too.

Only a run with no controlling terminal needs --invite: CI, cron, or ssh without -t. A script started from a terminal, and curl … | sh, are still asked. A run with no terminal, no --invite and no kept code stops before it downloads anything. The flag goes after the install command: curl -fsSL … | sh -s -- --invite <code>. A code given that way is checked, replaces a different kept code when it is valid, and is the kept code when it is the same. --path, --version and --licenses print and exit without asking.

What a run installs and updates

Each install command names what it installs in its address: /install/extension, /install/server or /install/extension-and-server. The script there runs commentware-installer-cli with --install and those parts. A run also updates every part already on the machine, so running any of the commands again is how you update. With nothing named and nothing installed, a run installs the extension. A machine that runs only a server never gets an extension.

A flag that asks something of a part the run neither installs nor finds installed, such as --profile on a run with no extension, stops the run before anything is installed.

What the installer checks before it unpacks anything

commentware-installer-cli reads the registry’s listing for each part it installs once, resolves one version, and checks the signature over that version. Then it downloads that version’s tarball and refuses unless the bytes hash to exactly the number the signature covered. One version, one download, no gap between what was checked and what lands on disk.

Which key it checks against depends on the build, and it says which:

  • A key pinned into the binary. This is the check worth having. An attacker who took over the host serving this registry could rewrite the tarball, the listing, the hash and the key document that sits beside them, and they would all agree with each other — but they cannot produce a signature that the key in your copy of the binary accepts. That copy did not come from the listing, so rewriting the listing does not reach it.
  • The key this registry publishes, in a build with no pinned key. That key is served by the same host, so a match proves the registry is internally consistent — a mirror, a truncated deploy or mismatched releases would fail — rather than that it has not been tampered with.
  • No check, when a build with no pinned key meets a registry that publishes no key. It says “signature not checked”, and why.

It prints which check ran, every time, because a check that says nothing when it passes cannot be told from one that never ran.

What it cannot check is its own arrival: the install command fetches a binary from this site and runs it, and that has already happened by the time any of the above does. An update runs the install command again, so the same is true of every update: each one fetches the newest installer from this site and runs it. If you would rather read the script before running it, fetch it with -o and open it.

The home directory, not a project

Installing the server is a global install, and none of the four package managers reads a project’s own configuration for one. A file beside a package.json works for that project and then the next command fails with a 404 from the public registry, which reads as “this package does not exist” rather than as “you configured the wrong file”.

config set goes to the home directory on its own, in both npm and pnpm — the project file is somewhere you have to ask for, with --location=project. That is why the npm and pnpm tabs in Install with a package manager are a command and not a line to paste: the mistake this step has is not reachable from the command.

Yarn and bun each have a reason not to be. bun reads ~/.npmrc and has no command that writes it. Yarn 2 and later has one, yarn config set … --home, and yarn 1 accepts that command too, prints success, and writes a file yarn 2 never reads — so the yarn tab is the file, in the syntax of the yarn that reads it. Check with yarn --version if you want the command: outside a project, a bare yarn is often still yarn 1.

The line sends only the names that start with @commentware-private to this registry, the part of a package’s name npm calls its scope. A registry= line in ~/.npmrc would send every package any project installs here instead, and this registry holds only Commentware’s, so every other install would fail with a 404. The packages are public: the scope’s name does not mean that an npm login is needed.

The setup page behind the invite code prints the same command, ready to copy. It is built from the address this site is served at, so a self-hosted Commentware prints its own — and so do both installer commands in Install the Chrome extension, and the binaries they fetch: a self-hosted deployment serves its own, pointed at its own registry.

Developer mode and its standing warning

The extension is loaded unpacked, which means Chrome needs developer mode switched on. A browser whose policy forbids developer mode cannot run it, and there is no way around that.

Chrome will show a standing warning about extensions running in developer mode. That warning is about the mode, not about this extension, and it cannot be dismissed permanently.

Where the extension is unpacked

The directory is in your home folder rather than in the place an application would normally keep its files, and that is deliberate: it is a directory you have to find in a file dialog, and every platform hides its application-data folder from exactly that dialog.

A Chrome profile only for this

The installer finds Google Chrome and opens the setup page in a profile whose directory is Commentware. A first install makes it; every run after reuses it. Chrome names a new profile itself, so it shows as Person 1 or Your Chrome until you rename it from the profile menu at the top right of Chrome.

An extension is loaded into one profile, not into Chrome. Load unpacked in one window puts Commentware in that profile and in no other, and /ext/ answers for the profile its tab is open in. That is why the installer picks the window rather than leaving it to whichever one the system opens: the one it opened is the one to load the extension into.

The extension consults the servers you connect to about the URLs you visit, so a profile dedicated to the sites you comment on limits what any of them could ever be asked about. See What Commentware stores.

The cost is that a new profile is signed into nothing, and the sites you want to comment on are usually ones you log into. Sign into those in the new profile, once. Opening a profile also makes it the one Chrome starts in next time, so the next time you open Chrome it may be this one; the profile menu switches back.

Three things change that:

  • --profile <directory> opens the page in a profile you already have, by its directory in Chrome’s data folder: Default, Profile 2. It refuses a directory that is not there and lists the ones that are, so a typo does not make a new profile. --profile Commentware is the dedicated one.
  • --default-browser leaves the choice to your system, as an installer without this step would: whichever browser and profile it picks. It is also the way to use a browser that is not Google Chrome.
  • An update does not make a profile. If you installed Commentware before the installer chose profiles, it is loaded in some profile of yours, and an update opens the page through your system unless a Commentware profile exists. Run it with --profile <directory> for the profile that holds the extension, or --profile Commentware to move to the dedicated one.

When Google Chrome is not in the usual place, or will not start, the installer says so and opens the page through your system. The flags go after the install command: curl -fsSL … | sh -s -- --profile "Profile 2".

Next steps

Documentation

Type to search…

↑↓ navigate↵ selectEsc close