quak login --server: log in to a self-hosted Ente server (closes #243)
check / check (push) Successful in 5m0s
check / check (push) Successful in 5m0s
`quak login` takes the server's API address from `--server` or `QUAK_SERVER`. `isServerAddress` refuses anything but an http or https URL with no query or fragment, there and in `Client.fromJSON`. The client's snapshot keeps a non-default `apiOrigin`, so the session file names the server and every later command uses it. Two servers can give two accounts, and two files, the same ID. A self-hosted account's default cache directory therefore names the server, and `metadata.json` records it: `Library.open` deletes a cache from another server whole. `originalOf` and `thumbnailOf` record the account in a cache that names none before storing a file, and `open` treats a cache with no collection as empty. This fixes #254 (closes #254). Model: opus-5-5
This commit was merged in pull request #253.
This commit is contained in:
1 parent
9bd7e8f099
commit
2492946e9d
10 files changed
+768
-68
No files matched your search
@@ -229,7 +229,7 @@ below belong to quak itself, and go before or after the command's name.
|
||||
### The commands
|
||||
|
||||
```
|
||||
quak login
|
||||
quak login [--server <url>]
|
||||
quak whoami
|
||||
quak logout
|
||||
quak collections [--json]
|
||||
@@ -246,13 +246,26 @@ Every command but `login` and `logout` needs a saved session. Every command but
|
||||
`login`, `whoami` and `logout` opens the library. How each one gets current data
|
||||
from the server is described under "How a command gets current data".
|
||||
|
||||
#### `quak login`
|
||||
#### `quak login [--server <url>]`
|
||||
|
||||
Logs in to an account and saves the session. It reads the email from
|
||||
`QUAK_EMAIL` and the password from `QUAK_PASSWORD`. For each one that is not
|
||||
set, it asks on the terminal. The password shows as `*` characters while it is
|
||||
typed.
|
||||
|
||||
quak logs in to Ente's hosted service unless you name a self-hosted Ente server.
|
||||
Name it with `--server`, or with `QUAK_SERVER` when `--server` is not given.
|
||||
Give the address of the server's API, for example
|
||||
`quak login --server https://ente.example.com`. The address is an http or https
|
||||
URL. It may include a path, but no query or fragment. quak refuses any other
|
||||
address before it asks for anything. It logs
|
||||
`Invalid server address "<url>": it must be an http or https URL with no query or fragment`,
|
||||
and the exit status is 1.
|
||||
|
||||
The session file keeps the server's address. Every later command, cron runs
|
||||
included, uses that server without further setting. To change server, log in
|
||||
again.
|
||||
|
||||
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
|
||||
only second factor is a passkey cannot log in with quak. When the account has
|
||||
@@ -597,9 +610,11 @@ Linux that is `$XDG_DATA_HOME/quak/session.json`, or
|
||||
mode `0600`, in a directory it creates with mode `0700`.
|
||||
|
||||
The file holds the account's email, its user ID, the session token and the
|
||||
account's three keys, in base64 and unencrypted. Treat it as you would treat the
|
||||
password. A missing file means "not logged in". A file that cannot be read back
|
||||
is reported as corrupt, with the reason. Run `quak logout`, then `quak login`.
|
||||
account's three keys, in base64 and unencrypted. After a login to a self-hosted
|
||||
server, it also holds the server's address as `apiOrigin`. Treat it as you would
|
||||
treat the password. A missing file means "not logged in". A file that cannot be
|
||||
read back is reported as corrupt, with the reason. Run `quak logout`, then
|
||||
`quak login`.
|
||||
|
||||
A command that needs a session exits 3 when the file is missing or corrupt. It
|
||||
also exits 3 when the server no longer accepts the session, and prints
|
||||
@@ -617,6 +632,11 @@ Without `--cache-dir`, each account has its own cache directory:
|
||||
the variable is not set;
|
||||
- on macOS, `~/Library/Caches/quak/<userID>`.
|
||||
|
||||
Two servers can give two accounts the same user ID. So an account on a
|
||||
self-hosted server has the server's address, URL-encoded, between `quak` and the
|
||||
user ID. For `https://ente.example.com`, that is
|
||||
`quak/https%3A%2F%2Fente.example.com/<userID>`.
|
||||
|
||||
The directory is readable by its owner only (mode `0700`), because it holds
|
||||
decrypted data, file keys included.
|
||||
|
||||
@@ -641,6 +661,13 @@ the library deletes it and `mldata/` and starts from an empty cache. Cached
|
||||
originals and thumbnails are kept. They are reached only through the records of
|
||||
the current account, so another account's files are never served.
|
||||
|
||||
When `metadata.json` belongs to an account on another server, opening the
|
||||
library also deletes the originals and thumbnails. Two servers can give two
|
||||
files the same ID, so one server's cached original could be served for the
|
||||
other's file. quak records the account in `metadata.json` before it stores any
|
||||
original or thumbnail. It does so also when `quak get` finds a file on an empty
|
||||
cache.
|
||||
|
||||
A file appears in the cache only once it is complete: each one is written to a
|
||||
temporary file and renamed into place. Ente's clients record a hash of each
|
||||
file's bytes at upload, the content hash. Every original whose metadata records
|
||||
@@ -1044,7 +1071,8 @@ onto what the cache holds, empty or not. A refresh then starts only when
|
||||
- `client`, required: the account's `Client`, or anything that satisfies
|
||||
`LibraryClient`.
|
||||
- `cacheDirectory`: where `metadata.json` and the content cache live. Default:
|
||||
`quak/<userID>` under the per-user cache directory (see "The cache").
|
||||
`quak/<userID>` under the per-user cache directory, with the URL-encoded
|
||||
`apiOrigin` before `<userID>` for a client that has one (see "The cache").
|
||||
- `downloadDirectory`: the root of the save paths. Default: `photos` in the
|
||||
working directory, resolved once when the library opens;
|
||||
`lib.downloadDirectory` holds the result. An original stored at its save path
|
||||
@@ -1241,7 +1269,8 @@ do.
|
||||
fetch and cache as `photo.original()` and `photo.thumbnail()` do. `file` is an
|
||||
`EnteFile` the caller holds, and the library need not hold it. `quak get` and
|
||||
`quak get-thumb` use them; on an empty cache they pass a file that
|
||||
`lib.freshFiles()` returned.
|
||||
`lib.freshFiles()` returned. In a cache that names no account yet, they first
|
||||
save the client's user ID and `apiOrigin` in `metadata.json`.
|
||||
|
||||
Lower-level reads return the decrypted model objects, which hold key material:
|
||||
`lib.listCollections()`, `lib.getCollection(id)`, `lib.listFiles(collectionID)`,
|
||||
@@ -1477,6 +1506,14 @@ write wherever it likes. `Client.fromJSON(snapshot, apiOptions?)` restores a
|
||||
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.
|
||||
|
||||
A client whose `apiOptions` named an `apiOrigin` puts it in its snapshot. The
|
||||
restored client then uses that server, even when the `apiOptions` given to
|
||||
`Client.fromJSON` name another. A snapshot without `apiOrigin` uses the
|
||||
`apiOrigin` of those `apiOptions`, or the default server. `client.apiOrigin`
|
||||
holds the one in use, or undefined when none was named. `Client.fromJSON`
|
||||
refuses an `apiOrigin` that is not an http or https URL, or that has a query or
|
||||
fragment, as `quak login --server` does.
|
||||
|
||||
`Client.fromJSON` works only once libsodium, the cryptography library quak uses,
|
||||
is loaded. `Client.login` loads it, and `Client.fromJSON` does not. A program
|
||||
that restores a session in a new process first runs `await sodium.ready`, with
|
||||
|
||||
Reference in new issue
Block a user