Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d9852af13 |
@@ -73,7 +73,8 @@ and `dist/` is not committed. Clone and build it as above, then add the clone to
|
|||||||
your own program's `package.json` by its path, for example
|
your own program's `package.json` by its path, for example
|
||||||
`yarn add file:../quak`. The package's `main`, `types` and `exports` fields
|
`yarn add file:../quak`. The package's `main`, `types` and `exports` fields
|
||||||
point into `dist/`, so the clone must be built first. The package is an ES
|
point into `dist/`, so the clone must be built first. The package is an ES
|
||||||
module only, so a CommonJS program cannot `require` it.
|
module only: `package.json` sets `"type": "module"`, and its `exports` field
|
||||||
|
offers only `import`, so a CommonJS program cannot `require` it.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { Client, Library } from "quak";
|
import { Client, Library } from "quak";
|
||||||
@@ -89,9 +90,8 @@ const client = await Client.login({
|
|||||||
const lib = await Library.open({
|
const lib = await Library.open({
|
||||||
client,
|
client,
|
||||||
// Without these two, open() also starts downloading every thumbnail in
|
// Without these two, open() also starts downloading every thumbnail in
|
||||||
// the account, and the originals of the favorites album and the latest
|
// the account and the latest week's originals into the cache. It fetches
|
||||||
// week, into the cache. It fetches machine-learning data after each
|
// machine-learning data after each refresh either way.
|
||||||
// refresh either way.
|
|
||||||
precacheThumbnails: false,
|
precacheThumbnails: false,
|
||||||
precacheOriginals: false,
|
precacheOriginals: false,
|
||||||
});
|
});
|
||||||
@@ -122,12 +122,10 @@ await lib.close();
|
|||||||
for. It refreshes every 3 seconds until `close()`. It also downloads, in the
|
for. It refreshes every 3 seconds until `close()`. It also downloads, in the
|
||||||
background, every thumbnail in the account and the originals of the favorites
|
background, every thumbnail in the account and the originals of the favorites
|
||||||
album and of the latest week (see "Opening a library"). The example turns those
|
album and of the latest week (see "Opening a library"). The example turns those
|
||||||
two downloads off. After each refresh that succeeds, the library also fetches
|
two downloads off. After each refresh the library also fetches each file's
|
||||||
each file's machine-learning data into the cache. That is the faces and the
|
machine-learning data into the cache. That is the faces and the other data
|
||||||
other data Ente's apps compute for a photo (see "The JSON beside each
|
Ente's apps compute for a photo (see "The JSON beside each original"). No option
|
||||||
original"). No option in `LibraryOptions` turns this off. A `client` without a
|
turns this off.
|
||||||
`fetchMLData` method fetches none, which is how quak's own read commands open
|
|
||||||
their library.
|
|
||||||
|
|
||||||
The `Client` under the library handles login, saved sessions and the raw
|
The `Client` under the library handles login, saved sessions and the raw
|
||||||
requests. The "Library reference" below covers both.
|
requests. The "Library reference" below covers both.
|
||||||
@@ -136,9 +134,9 @@ requests. The "Library reference" below covers both.
|
|||||||
|
|
||||||
`quak backup` never prompts, so cron can run it. `make install` builds quak as
|
`quak backup` never prompts, so cron can run it. `make install` builds quak as
|
||||||
one binary and copies it to `~/bin/quak`. Besides what Getting Started needs,
|
one binary and copies it to `~/bin/quak`. Besides what Getting Started needs,
|
||||||
`make install` needs `make` and [nix](https://nixos.org/download). It uses bun,
|
`make install` needs [nix](https://nixos.org/download). It uses bun, a
|
||||||
a JavaScript runtime, to bundle the built `dist/` into one executable. It runs
|
JavaScript runtime, to bundle the built `dist/` into one executable. It runs bun
|
||||||
bun through `nix-shell -p bun`.
|
through `nix-shell -p bun`.
|
||||||
|
|
||||||
Log in once with `~/bin/quak`, as the user the cron job will run as:
|
Log in once with `~/bin/quak`, as the user the cron job will run as:
|
||||||
|
|
||||||
@@ -158,11 +156,10 @@ output to `~/quak-backup.log`. Sunday's run adds `--verify`:
|
|||||||
|
|
||||||
A run with `--verify` does all a plain run does. It also hashes each original
|
A run with `--verify` does all a plain run does. It also hashes each original
|
||||||
already in the backup and compares the result with the content hash. The content
|
already in the backup and compares the result with the content hash. The content
|
||||||
hash is the hash of the file's bytes that Ente recorded at upload. It fetches a
|
hash is the hash of the file's bytes that Ente recorded at upload. It replaces
|
||||||
new copy of each original that does not match, and replaces the original once
|
any original that does not match. Sunday's run is the `--verify` run, rather
|
||||||
the copy matches. Sunday's run is the `--verify` run, rather than a second job
|
than a second job that night, because two backups of one directory cannot run at
|
||||||
that night, because two backups of one directory cannot run at once. The second
|
once. The second one exits 2 without doing anything.
|
||||||
one exits 2 without doing anything.
|
|
||||||
|
|
||||||
Cron runs the job with a short `PATH`, usually `/usr/bin:/bin`, so the crontab
|
Cron runs the job with a short `PATH`, usually `/usr/bin:/bin`, so the crontab
|
||||||
names quak by its full path. quak finds the saved session through `HOME`, which
|
names quak by its full path. quak finds the saved session through `HOME`, which
|
||||||
@@ -230,12 +227,9 @@ set, it asks on the terminal. The password shows as `*` characters while it is
|
|||||||
typed.
|
typed.
|
||||||
|
|
||||||
When the account has a second factor, quak asks for the code. It asks
|
When the account has a second factor, quak asks for the code. It asks
|
||||||
`TOTP code: ` for a time-based code from an authenticator app. An account whose
|
`TOTP code: ` for a time-based code from an authenticator app, and
|
||||||
only second factor is a passkey cannot log in with quak. When the account has
|
`Email verification code: ` for a code sent by email. An account whose only
|
||||||
email verification on, quak asks `Email verification code: ` for the code sent
|
second factor is a passkey cannot log in with quak.
|
||||||
by email. The password is then used only to unlock the keys. After the email
|
|
||||||
code quak expects the login to complete. When the server asks for a second
|
|
||||||
factor at that point, login fails.
|
|
||||||
|
|
||||||
On success it logs `Logged in as <email> (user <id>)` and
|
On success it logs `Logged in as <email> (user <id>)` and
|
||||||
`Session saved to <path>`. On failure it logs `Login failed: <reason>`, and the
|
`Session saved to <path>`. On failure it logs `Login failed: <reason>`, and the
|
||||||
@@ -245,9 +239,7 @@ to stdout.
|
|||||||
#### `quak whoami`
|
#### `quak whoami`
|
||||||
|
|
||||||
Prints the saved session's account on stdout as one line of JSON:
|
Prints the saved session's account on stdout as one line of JSON:
|
||||||
`{"email":"you@example.com","userID":12345}`. It reads the session file only and
|
`{"email":"you@example.com","userID":12345}`.
|
||||||
sends no request, so it succeeds even when the server no longer accepts the
|
|
||||||
session.
|
|
||||||
|
|
||||||
#### `quak logout`
|
#### `quak logout`
|
||||||
|
|
||||||
@@ -382,8 +374,7 @@ thumbnail in the account, one collection at a time, newest collection first, so
|
|||||||
on a large account it takes a while. A thumbnail counts as missing when the
|
on a large account it takes a while. A thumbnail counts as missing when the
|
||||||
server answers with an empty body or with HTTP 404. Any other failure is logged
|
server answers with an empty body or with HTTP 404. Any other failure is logged
|
||||||
as `[<collection>] Could not check <title>: <reason> (not reported as missing)`,
|
as `[<collection>] Could not check <title>: <reason> (not reported as missing)`,
|
||||||
and the file is left out of the list. The command exits 0 even when some files
|
and the file is left out of the list.
|
||||||
could not be checked.
|
|
||||||
|
|
||||||
The server lets only a file's owner replace its thumbnail. A file another
|
The server lets only a file's owner replace its thumbnail. A file another
|
||||||
account owns, in a collection shared with you, is skipped and not checked.
|
account owns, in a collection shared with you, is skipped and not checked.
|
||||||
@@ -426,13 +417,12 @@ Each file ends in one of three states:
|
|||||||
`--file` is held by no collection.
|
`--file` is held by no collection.
|
||||||
|
|
||||||
Without `--json`, the command ends with counts of fixed, skipped and failed
|
Without `--json`, the command ends with counts of fixed, skipped and failed
|
||||||
files. A `Skipped:` list and a `Failed files:` list follow when they have
|
files, a `Skipped:` list and a `Failed files:` list. With `--json`, one JSON
|
||||||
entries. With `--json`, one JSON array on stdout replaces them; each object
|
array on stdout replaces them; each object holds `fileID`, `title`,
|
||||||
holds `fileID`, `title`, `collection`, `status` and, for a skipped or failed
|
`collection`, `status` and, for a skipped or failed file, `reason`. When any
|
||||||
file, `reason`. When any file failed, the exit status is 1. A skipped file does
|
file failed, the exit status is 1. A skipped file does not change it. When
|
||||||
not change it. When nothing needs fixing, the command logs
|
nothing needs fixing, the command logs `No missing thumbnails found.` and
|
||||||
`No missing thumbnails found.` and exits 0. With `--json` it then writes nothing
|
exits 0. With `--json` it then writes nothing on stdout.
|
||||||
on stdout.
|
|
||||||
|
|
||||||
quak refuses the whole command, before any request, when one `--file` ID is
|
quak refuses the whole command, before any request, when one `--file` ID is
|
||||||
invalid (see "IDs").
|
invalid (see "IDs").
|
||||||
@@ -463,9 +453,9 @@ collection fetched, such as `Fetched the files of 3 of 120 collections`.
|
|||||||
|
|
||||||
When a refresh or a search fails, the command logs the error on one line and
|
When a refresh or a search fails, the command logs the error on one line and
|
||||||
exits 1, or 3 when the server no longer accepts the saved session. A collection
|
exits 1, or 3 when the server no longer accepts the saved session. A collection
|
||||||
or file that quak cannot decrypt does not stop a refresh or a search: the
|
or file that quak cannot decrypt does not stop a refresh: the command answers
|
||||||
command leaves it out and answers from what did decrypt (see "Default reads and
|
from what did decrypt (see "Default reads and fresh reads"). `backup` counts it
|
||||||
fresh reads"). `backup` counts it as failed (see "What quak cannot decrypt").
|
as failed (see "What quak cannot decrypt").
|
||||||
|
|
||||||
### IDs
|
### IDs
|
||||||
|
|
||||||
@@ -517,12 +507,11 @@ one that exits non-zero prints only its fatal lines. The prompts of `login` are
|
|||||||
not log lines, and `-q` leaves them alone.
|
not log lines, and `-q` leaves them alone.
|
||||||
|
|
||||||
With `--json`, a command's JSON on stdout takes the place of its summary on
|
With `--json`, a command's JSON on stdout takes the place of its summary on
|
||||||
stderr. For `backup`, that is the `--- Backup complete ---` line, the counts and
|
stderr. For `backup`, that is the lines from `--- Backup complete ---` to the
|
||||||
the `Failed files:` list. For `list-missing-thumbnails`, it is
|
end of the `Failed files:` list. For `list-missing-thumbnails`, it is
|
||||||
`No missing thumbnails found.` or `<n> file(s) with missing thumbnails:`. For
|
`No missing thumbnails found.` or `<n> file(s) with missing thumbnails:`. For
|
||||||
`fix-missing-thumbnails`, it is the `--- Done ---` line, the counts, the
|
`fix-missing-thumbnails`, it is the lines from `--- Done ---` to the end of the
|
||||||
`Skipped:` list and the `Failed files:` list. Every other line is logged as
|
`Failed files:` list. Every other line is logged as without `--json`.
|
||||||
without `--json`.
|
|
||||||
|
|
||||||
### Exit codes
|
### Exit codes
|
||||||
|
|
||||||
@@ -780,13 +769,11 @@ too. It is then cut short before the ID, just far enough to fit. IDs never
|
|||||||
change, so a name stays the same from run to run until such a clash appears or
|
change, so a name stays the same from run to run until such a clash appears or
|
||||||
goes away.
|
goes away.
|
||||||
|
|
||||||
Each run removes every symlink in a collection's directory that points into the
|
Each run removes the symlinks that no longer belong in a collection's directory.
|
||||||
date folders and is not one of its current links, yours included. A file or
|
It removes the directory and JSON of a collection that was deleted or renamed,
|
||||||
symlink of yours at the name of one of its links is replaced by the link. A
|
once the directory holds nothing else. Nothing else under `collections/` is
|
||||||
directory at that name stays, and the file goes into `failures.json`. Anything
|
touched: a file or symlink you put there stays, and a directory that still holds
|
||||||
else you put under `collections/` stays. A run removes the directory and JSON of
|
one stays too, with its JSON.
|
||||||
a collection that was deleted or renamed, once the directory holds nothing else.
|
|
||||||
One that still holds something of yours stays, with its JSON.
|
|
||||||
|
|
||||||
A collection whose directory or JSON cannot be written does not stop the run.
|
A collection whose directory or JSON cannot be written does not stop the run.
|
||||||
For example, a file you put there may already have the directory's name. The run
|
For example, a file you put there may already have the directory's name. The run
|
||||||
@@ -850,8 +837,8 @@ file outside them. `failures.json` is deleted when the list is empty.
|
|||||||
`backup.lock` keeps two backups of the same directory from running at once, such
|
`backup.lock` keeps two backups of the same directory from running at once, such
|
||||||
as a cron run that starts while the previous one is still going. A backup
|
as a cron run that starts while the previous one is still going. A backup
|
||||||
creates `<dir>` if it is missing and takes the lock before its refresh, so a
|
creates `<dir>` if it is missing and takes the lock before its refresh, so a
|
||||||
refused run sends no request. A run that still holds the lock removes it when it
|
refused run sends no request. It removes the lock when it ends, whether it
|
||||||
ends, whether it succeeded or failed.
|
succeeded or failed.
|
||||||
|
|
||||||
The lock is a directory that
|
The lock is a directory that
|
||||||
[proper-lockfile](https://github.com/moxystudio/node-proper-lockfile) creates.
|
[proper-lockfile](https://github.com/moxystudio/node-proper-lockfile) creates.
|
||||||
@@ -899,13 +886,13 @@ The summary and the `--json` output add the counts `verified`, `mismatched` and
|
|||||||
`unchecked`. Each counts only originals that were already stored. A mismatch
|
`unchecked`. Each counts only originals that were already stored. A mismatch
|
||||||
that was replaced with matching bytes does not make the exit code non-zero.
|
that was replaced with matching bytes does not make the exit code non-zero.
|
||||||
|
|
||||||
A run without `--verify` drops two kinds of failure from `failures.json`:
|
Two kinds of failure stay in `failures.json` only until the next run:
|
||||||
|
|
||||||
- a mismatched original whose new copy failed;
|
- a mismatched original whose new copy failed;
|
||||||
- a stored original that cannot be read.
|
- a stored original that cannot be read.
|
||||||
|
|
||||||
That run finds the original in place, counts it as skipped and drops the entry,
|
A run without `--verify` finds the original in place, counts it as skipped, and
|
||||||
so it can exit 0. Only a `--verify` run hashes the original again.
|
drops the entry, so that run can exit 0. Only a `--verify` run hashes it again.
|
||||||
|
|
||||||
Without `--verify`, no stored original is hashed, the summary is unchanged, and
|
Without `--verify`, no stored original is hashed, the summary is unchanged, and
|
||||||
the three counts are 0 in the JSON.
|
the three counts are 0 in the JSON.
|
||||||
@@ -931,11 +918,7 @@ scheme. Opening a library deletes such leftovers in the cache's `originals/` and
|
|||||||
The rename replaces whatever was at the destination rather than writing through
|
The rename replaces whatever was at the destination rather than writing through
|
||||||
it. A symlink there is replaced, not followed, and the new file has the
|
it. A symlink there is replaced, not followed, and the new file has the
|
||||||
temporary file's permissions, not those of the file it replaced. Each original
|
temporary file's permissions, not those of the file it replaced. Each original
|
||||||
is written with mode `0600`, readable by its owner only. Everything else the
|
is written with mode `0600`, readable by its owner only.
|
||||||
backup writes, its folders and JSON files included, gets the mode your umask
|
|
||||||
allows, which usually lets every user on the machine read it. The JSON beside an
|
|
||||||
original holds the file's location and faces. The `backup-metadata` tree is
|
|
||||||
written the same way.
|
|
||||||
|
|
||||||
### The metadata dump directory
|
### The metadata dump directory
|
||||||
|
|
||||||
@@ -1043,11 +1026,10 @@ onto what the cache holds, empty or not. A refresh then starts only when
|
|||||||
- `contentSource`: a replacement for the client's own byte source. Mainly for
|
- `contentSource`: a replacement for the client's own byte source. Mainly for
|
||||||
tests.
|
tests.
|
||||||
|
|
||||||
In the content and thumbnail pools, your own requests take the next free slot
|
In each pool, your own requests take the next free slot ahead of the two
|
||||||
ahead of the two background downloads. A file already in the cache is not
|
background downloads. A file already in the cache is not fetched again. When the
|
||||||
fetched again. When the originals cache grows past its limit, the least recently
|
originals cache grows past its limit, the least recently used originals are
|
||||||
used originals are evicted, but never a pinned one, and never one whose fetch is
|
evicted, but never a pinned one, and never one whose fetch is still in flight.
|
||||||
still in flight.
|
|
||||||
|
|
||||||
`onProgress` receives a `RefreshEvent`. Its `operation` names the work:
|
`onProgress` receives a `RefreshEvent`. Its `operation` names the work:
|
||||||
`"refresh"`, `"fetchMLData"` for a machine-learning fetch, and
|
`"refresh"`, `"fetchMLData"` for a machine-learning fetch, and
|
||||||
@@ -1275,9 +1257,7 @@ symlinks. Once the lock is lost, it rejects with
|
|||||||
`BackupOptions`:
|
`BackupOptions`:
|
||||||
|
|
||||||
- `downloadDirectory`: where the tree lives. Default: the library's.
|
- `downloadDirectory`: where the tree lives. Default: the library's.
|
||||||
- `includeOriginals`: fetch and store originals. Default `true`. With `false`,
|
- `includeOriginals`: fetch and store originals. Default `true`.
|
||||||
the backup also fetches no machine-learning data, and writes no JSON beside
|
|
||||||
the originals and no symlinks.
|
|
||||||
- `includeThumbnails`: also store thumbnails as `thumbnails/<fileID>.jpg` beside
|
- `includeThumbnails`: also store thumbnails as `thumbnails/<fileID>.jpg` beside
|
||||||
`collections/`. Default `false`. `quak backup` does not set it.
|
`collections/`. Default `false`. `quak backup` does not set it.
|
||||||
- `onlyAlbumNames`: back up only the albums with these names.
|
- `onlyAlbumNames`: back up only the albums with these names.
|
||||||
@@ -1298,13 +1278,11 @@ releases it once the backup ends.
|
|||||||
many requests run at once, because Ente meters these three kinds of traffic
|
many requests run at once, because Ente meters these three kinds of traffic
|
||||||
differently:
|
differently:
|
||||||
|
|
||||||
- metadata, with 10 slots: only the machine-learning data requests;
|
- metadata, with 10 slots;
|
||||||
- content, with 5: originals;
|
- content, with 5;
|
||||||
- thumbnails, with 25: thumbnails.
|
- thumbnails, with 25.
|
||||||
|
|
||||||
Only the requests named above go through the pools. A refresh,
|
Construct one with
|
||||||
`freshCollections()` and `freshFiles()` send theirs outside them. Construct one
|
|
||||||
with
|
|
||||||
`new RequestPools({ metadataConcurrency, contentConcurrency, thumbnailConcurrency })`
|
`new RequestPools({ metadataConcurrency, contentConcurrency, thumbnailConcurrency })`
|
||||||
and pass it as `pools`. Each pool serves on-demand work ahead of background
|
and pass it as `pools`. Each pool serves on-demand work ahead of background
|
||||||
work. A task submitted under a key that is still pending is not run a second
|
work. A task submitted under a key that is still pending is not run a second
|
||||||
@@ -1433,9 +1411,8 @@ return, quak never keeps a truncated file.
|
|||||||
`Client.login({ email, password, totp?, emailOTP?, apiOptions? })` logs in and
|
`Client.login({ email, password, totp?, emailOTP?, apiOptions? })` logs in and
|
||||||
resolves to a `Client`. `totp` and `emailOTP` are callbacks that return the code
|
resolves to a `Client`. `totp` and `emailOTP` are callbacks that return the code
|
||||||
when the account asks for one. Without the callback the account needs, login
|
when the account asks for one. Without the callback the account needs, login
|
||||||
throws. A passkey challenge always throws. After an email code, login expects
|
throws. A passkey challenge always throws. `apiOptions` configures the HTTP
|
||||||
the key attributes and the token. When the server asks for a second factor
|
client (see below).
|
||||||
instead, login throws. `apiOptions` configures the HTTP client (see below).
|
|
||||||
|
|
||||||
The `Client` holds the session token, the master key, the secret key and the
|
The `Client` holds the session token, the master key, the secret key and the
|
||||||
public key in memory. There is no on-disk session store in the library; the
|
public key in memory. There is no on-disk session store in the library; the
|
||||||
@@ -1445,13 +1422,6 @@ write wherever it likes. `Client.fromJSON(snapshot, apiOptions?)` restores a
|
|||||||
working client from that snapshot without logging in again. It checks every
|
working client from that snapshot without logging in again. It checks every
|
||||||
field and each key's length first, and throws an error naming the bad field.
|
field and each key's length first, and throws an error naming the bad field.
|
||||||
|
|
||||||
`Client.fromJSON` works only once libsodium, the cryptography library quak uses,
|
|
||||||
is loaded. Only `Client.login` loads it. A program that restores a session in a
|
|
||||||
new process first runs `await sodium.ready`, with `sodium` imported from
|
|
||||||
`libsodium-wrappers-sumo`, which quak depends on. The exported `beginLogin`,
|
|
||||||
`unwrapAuth`, `decryptCollection`, `decryptFile`, `downloadFile` and
|
|
||||||
`downloadThumbnail` need the same.
|
|
||||||
|
|
||||||
`client.logout()` clears the token and zeroes the key buffers in place. After
|
`client.logout()` clears the token and zeroes the key buffers in place. After
|
||||||
it, every other method on that client throws. It does not contact the server, so
|
it, every other method on that client throws. It does not contact the server, so
|
||||||
the token stays valid there and in any saved snapshot. Call
|
the token stays valid there and in any saved snapshot. Call
|
||||||
@@ -1474,10 +1444,8 @@ return only the decrypted records that are not deleted, from `sinceTime` `0`.
|
|||||||
`client.fetchMLData({ fileIDs, fileKeys })` fetches and decrypts the
|
`client.fetchMLData({ fileIDs, fileKeys })` fetches and decrypts the
|
||||||
machine-learning data of up to 200 files. `client.downloadFile(file, outPath?)`
|
machine-learning data of up to 200 files. `client.downloadFile(file, outPath?)`
|
||||||
and `client.downloadThumbnail(file, outPath?)` download and decrypt one file to
|
and `client.downloadThumbnail(file, outPath?)` download and decrypt one file to
|
||||||
`outPath`. For a live photo, `downloadFile` writes the image and the video, each
|
`outPath`. Without `outPath`, they write to the working directory under the
|
||||||
named `outPath` with its own extension. `quak get --out` instead puts the image
|
names `quak get` and `quak get-thumb` would use.
|
||||||
at the path itself. Without `outPath`, they write to the working directory under
|
|
||||||
the names `quak get` and `quak get-thumb` would use.
|
|
||||||
|
|
||||||
`ApiClientOptions`:
|
`ApiClientOptions`:
|
||||||
|
|
||||||
@@ -1672,8 +1640,8 @@ Login derives the keys in this order:
|
|||||||
the code (`POST /users/two-factor/verify`); the server then returns the key
|
the code (`POST /users/two-factor/verify`); the server then returns the key
|
||||||
attributes and the token. quak cannot answer a passkey request. When the
|
attributes and the token. quak cannot answer a passkey request. When the
|
||||||
account has email verification on (`isEmailMFAEnabled`), an email code
|
account has email verification on (`isEmailMFAEnabled`), an email code
|
||||||
replaces SRP. quak then expects the key attributes and the token in the
|
replaces SRP, and the server returns the key attributes and the token after
|
||||||
answer, and fails the login when the server asks for a second factor instead.
|
it.
|
||||||
5. `crypto_secretbox_open_easy` over the encrypted master key with the KEK
|
5. `crypto_secretbox_open_easy` over the encrypted master key with the KEK
|
||||||
yields the 32-byte master key.
|
yields the 32-byte master key.
|
||||||
6. `crypto_secretbox_open_easy` over the encrypted secret key with the master
|
6. `crypto_secretbox_open_easy` over the encrypted secret key with the master
|
||||||
@@ -1752,35 +1720,36 @@ This repository adheres to the
|
|||||||
standard. Normalized scripts in `script/` are the entrypoints for the
|
standard. Normalized scripts in `script/` are the entrypoints for the
|
||||||
development workflow, and most Makefile targets are thin shims that call them.
|
development workflow, and most Makefile targets are thin shims that call them.
|
||||||
The scripts are POSIX `sh`, not bash, so they run in minimal containers such as
|
The scripts are POSIX `sh`, not bash, so they run in minimal containers such as
|
||||||
Alpine. Of these, only `bootstrap`, `setup`, `test` and `cibuild` come from the
|
Alpine. The scripts marked "ours" are this repository's own additions to the
|
||||||
standard. The others are additions to it.
|
standard.
|
||||||
|
|
||||||
- `script/bootstrap`: install all dependencies. It installs `make`, `git`, Node
|
- `script/bootstrap`: install all dependencies. It installs `make`, `git`, Node
|
||||||
and `yarn` when they are missing, then runs `yarn install --frozen-lockfile`.
|
and `yarn` when they are missing, then runs `yarn install --frozen-lockfile`.
|
||||||
- `script/setup`: set up the repo for development after a fresh clone. It runs
|
- `script/setup`: set up the repo for development after a fresh clone. It runs
|
||||||
`script/bootstrap`, then `script/install-precommit`.
|
`script/bootstrap`, then `script/install-precommit`.
|
||||||
- `script/projectname`: print the project name. `script/docker` uses it for the
|
- `script/projectname` (ours): print the project name. `script/docker` uses it
|
||||||
image tag.
|
for the image tag.
|
||||||
- `script/build`: compile the TypeScript sources into `dist/` and stamp the
|
- `script/build` (ours): compile the TypeScript sources into `dist/` and stamp
|
||||||
version into `dist/package.json`. Then check that the entrypoints
|
the version into `dist/package.json`. Then check that the entrypoints
|
||||||
`package.json` declares (`main`, `types`, `bin`) were written, and make the
|
`package.json` declares (`main`, `types`, `bin`) were written, and make the
|
||||||
command line executable.
|
command line executable.
|
||||||
- `script/version`: print the version `script/build` stamps (see "Version").
|
- `script/version` (ours): print the version `script/build` stamps (see
|
||||||
|
"Version").
|
||||||
- `script/test`: run the test suite, by building the `test` phase of the
|
- `script/test`: run the test suite, by building the `test` phase of the
|
||||||
`Dockerfile`. Requires Docker.
|
`Dockerfile`. Requires Docker.
|
||||||
- `script/lint`: run eslint and a prettier check, by building the `lint` phase
|
- `script/lint`: run eslint and a prettier check, by building the `lint` phase
|
||||||
of the `Dockerfile`. Requires Docker.
|
of the `Dockerfile`. Requires Docker.
|
||||||
- `script/fmt`: format all files with prettier. It rewrites files in place.
|
- `script/fmt`: format all files with prettier. It rewrites files in place.
|
||||||
- `script/fmt-check`: check formatting on the host. It is read-only.
|
- `script/fmt-check`: check formatting on the host. It is read-only.
|
||||||
- `script/check`: run all checks: `test`, `lint`, `fmt-check`.
|
- `script/check` (ours): run all checks: `test`, `lint`, `fmt-check`.
|
||||||
- `script/docker`: build the image, tagged with `script/projectname`.
|
- `script/docker`: build the image, tagged with `script/projectname`.
|
||||||
- `script/cibuild`: what CI runs: `script/bootstrap`, then `script/check`, then
|
- `script/cibuild`: what CI runs: `script/bootstrap`, then `script/check`, then
|
||||||
the image build.
|
the image build.
|
||||||
- `script/precommit`: run by the git pre-commit hook. It runs `script/lint` and
|
- `script/precommit` (ours): run by the git pre-commit hook. It runs
|
||||||
`script/fmt-check`, and not the tests, so that a commit of failing tests can
|
`script/lint` and `script/fmt-check`, and not the tests, so that a commit of
|
||||||
land (see "Development workflow").
|
failing tests can land (see "Development workflow").
|
||||||
- `script/install-precommit`: install the git pre-commit hook. `make hooks`
|
- `script/install-precommit` (ours): install the git pre-commit hook.
|
||||||
calls it.
|
`make hooks` calls it.
|
||||||
|
|
||||||
The Makefile targets are:
|
The Makefile targets are:
|
||||||
|
|
||||||
@@ -1847,8 +1816,8 @@ empty, `dev` or `unknown`, because such a build could not be traced to its
|
|||||||
commit.
|
commit.
|
||||||
|
|
||||||
`.dockerignore` therefore does not leave out `.git`, so any `docker build .` of
|
`.dockerignore` therefore does not leave out `.git`, so any `docker build .` of
|
||||||
a clone stamps the commit it was built from. A clone of depth 1 stamps a tag
|
a clone stamps the commit it was built from. A shallow clone stamps a tag only
|
||||||
only when its commit carries one, and otherwise the short commit.
|
when the cloned commit itself carries one, and otherwise the short commit.
|
||||||
`.dockerignore` does leave out `.git/config`, which holds the clone's remote URL
|
`.dockerignore` does leave out `.git/config`, which holds the clone's remote URL
|
||||||
and any credential in it; `git describe` does not need that file.
|
and any credential in it; `git describe` does not need that file.
|
||||||
`script/docker` and `script/cibuild` work out the version on the host, with
|
`script/docker` and `script/cibuild` work out the version on the host, with
|
||||||
@@ -1904,10 +1873,7 @@ These apply to people and to coding agents alike.
|
|||||||
- the nvm archive `script/bootstrap` downloads, and the Python packages
|
- the nvm archive `script/bootstrap` downloads, and the Python packages
|
||||||
`bin/clip-keyword-vectors` installs, by SHA-256 hash;
|
`bin/clip-keyword-vectors` installs, by SHA-256 hash;
|
||||||
- Node and yarn, when `script/bootstrap` installs them, by version.
|
- Node and yarn, when `script/bootstrap` installs them, by version.
|
||||||
- Not pinned:
|
- bun is not pinned: `make build-bin` uses whatever `nix-shell -p bun` provides.
|
||||||
- bun, which `make build-bin` takes from `nix-shell -p bun`;
|
|
||||||
- `make` and `git`, which `script/bootstrap` installs from the system
|
|
||||||
package manager when they are missing, as every `Dockerfile` stage does.
|
|
||||||
- Follow the workflow above: branches off `next`, tests first and committed
|
- Follow the workflow above: branches off `next`, tests first and committed
|
||||||
failing, and `next` merged into `main` by sneak alone.
|
failing, and `next` merged into `main` by sneak alone.
|
||||||
- Before every commit, `make lint` and `make fmt-check` must pass. `make lint`
|
- Before every commit, `make lint` and `make fmt-check` must pass. `make lint`
|
||||||
|
|||||||
Reference in New Issue
Block a user