mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
feat(backup): restore an erased account's copy into a chosen account
After an account is erased the operator still has its disaster-recovery file, and the upload refused it because its owner was gone. The refusal now carries backup.owner.missing, and the file can be sent again with a target in the query: an existing account that holds no records yet, confirmed by typing its username, or a new account created for the copy. The file's owner is rewritten to that account as it is read, so the stored copy, its preview, its download and its restore are that account's, and the restore that follows is the ordinary one. The new account has no password and no email; an admin sets its first password with the existing reset. A file whose own account is still here is refused with a target, and an account made for a refused file is removed again. The refusal of an unknown owner no longer writes the owner's id into the audit trail, since the erasure took every row that named it.
This commit is contained in:
1 parent
9baeb95bab
commit
8014fd4aae
5 files changed
+786
-25
No files matched your search
+65
-6
@@ -25090,10 +25090,52 @@ paths:
|
||||
same pass; a file that fails any check leaves nothing behind. It is refused when it is not valid JSON, fails the
|
||||
backup schema, was written by a newer schema version than this server reads, needs an encryption key this server
|
||||
does not hold (`meta.errorCode` = `backup.key.missing`, `meta.keyIds` naming them), or belongs to an account
|
||||
that does not exist here. Three uploads a minute per administrator. Admin session cookie required; Bearer tokens
|
||||
cannot reach admin endpoints. A browser session needs a fresh proof as well as a live one: a sign-in or `POST
|
||||
/api/auth/reproof` within the last five minutes (with a second factor, on an account that has one). Without it
|
||||
the answer is 401 `auth.reproof.required`, with `meta.methods` naming the proofs the account can give."
|
||||
that does not exist here (`meta.errorCode` = `backup.owner.missing`). A file of an account that no longer exists
|
||||
here (erased, say) can be sent again with a target in the query: `into=existing&userId=<id>&confirm=<username>`
|
||||
for an account that holds no records yet, or `into=new&username=<name>` for a new account created for the copy,
|
||||
with no password and no email (an admin sets its first password with the existing password reset). The file's
|
||||
owner is rewritten to that account as it is read, so the stored copy is that account's copy and restores like
|
||||
any other; the erased account's id is not stored. A target is refused before the file is read when the account
|
||||
does not exist, is a managed profile, is pending deletion, or holds records (a restore replaces records, it does
|
||||
not merge them); a file whose own account is still here is refused with a target (`backup.owner.exists`). Three
|
||||
uploads a minute per administrator. Admin session cookie required; Bearer tokens cannot reach admin endpoints. A
|
||||
browser session needs a fresh proof as well as a live one: a sign-in or `POST /api/auth/reproof` within the last
|
||||
five minutes (with a second factor, on an account that has one). Without it the answer is 401
|
||||
`auth.reproof.required`, with `meta.methods` naming the proofs the account can give."
|
||||
parameters:
|
||||
- in: query
|
||||
name: into
|
||||
schema:
|
||||
description: "Where the copy goes when the account the file names does not exist here. Absent: the file's own account,
|
||||
which has to exist."
|
||||
type: string
|
||||
enum:
|
||||
- existing
|
||||
- new
|
||||
description: "Where the copy goes when the account the file names does not exist here. Absent: the file's own account,
|
||||
which has to exist."
|
||||
- in: query
|
||||
name: userId
|
||||
schema:
|
||||
description: "With `into=existing`: the account's id."
|
||||
type: string
|
||||
maxLength: 64
|
||||
description: "With `into=existing`: the account's id."
|
||||
- in: query
|
||||
name: confirm
|
||||
schema:
|
||||
description: "With `into=existing`: the account's username, typed by the operator."
|
||||
type: string
|
||||
maxLength: 64
|
||||
description: "With `into=existing`: the account's username, typed by the operator."
|
||||
- in: query
|
||||
name: username
|
||||
schema:
|
||||
description: "With `into=new`: the new account's username (letters, digits, `_` and `-`)."
|
||||
type: string
|
||||
minLength: 3
|
||||
maxLength: 30
|
||||
description: "With `into=new`: the new account's username (letters, digits, `_` and `-`)."
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -25139,6 +25181,22 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"403": *a25
|
||||
"404":
|
||||
description: The account chosen with `into=existing` does not exist (`backup.target.not_found`). Nothing was stored.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"409":
|
||||
description: "The chosen target cannot take the copy, and nothing was stored: a managed profile
|
||||
(`backup.target.managed_profile`), an account pending deletion (`backup.target.pending_deletion`), an
|
||||
account that already holds records (`backup.target.holds_records`, `meta.models` naming them), a username
|
||||
already taken (`backup.target.username_taken`), or a file whose own account is still here
|
||||
(`backup.owner.exists`)."
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"413":
|
||||
description: "Too large: over 512 MB as sent (10 MB in a form), a gzip file that expands past what any backup this
|
||||
server wrote does, or larger than the stored-copy limit once encrypted (`meta.errorCode` =
|
||||
@@ -25150,8 +25208,9 @@ paths:
|
||||
"422":
|
||||
description: "The file was refused and nothing was stored: no file in the request, not valid JSON or not readable as
|
||||
gzip, failed the backup schema (`meta.issues`), an unsupported schema version, a key this server does not
|
||||
hold (`meta.errorCode` = `backup.key.missing`, `meta.keyIds`), or an owner account that does not exist
|
||||
here."
|
||||
hold (`meta.errorCode` = `backup.key.missing`, `meta.keyIds`), an owner account that does not exist here
|
||||
(`backup.owner.missing`), a target query that does not parse (`details.issues`), or an `into=existing` whose
|
||||
`confirm` is not the account's username (`backup.target.unconfirmed`)."
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
||||
Reference in new issue
Block a user