fix(backups): remove useless backups concept

This commit is contained in:
Lewis
2026-03-18 12:17:33 +00:00
committed by Tangled
parent 938df6495d
commit ebf5af4922
197 changed files with 959 additions and 5803 deletions
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id, backup_enabled FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "backup_enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "017b04caf42b30f2c8f9468acf61a83244b7c2fa5cacfaee41a946a6af5ef68e"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT t.token FROM plc_operation_tokens t JOIN users u ON t.user_id = u.id WHERE u.did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "05fd99170e31e68fa5028c862417cdf535cd70e09fde0a8a28249df0070eb2fc"
}
@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE users SET deactivated_at = $1 WHERE did = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Timestamptz",
"Text"
]
},
"nullable": []
},
"hash": "0710b57fb9aa933525f617b15e6e2e5feaa9c59c38ec9175568abdacda167107"
}
@@ -1,53 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT u.id, u.did, u.backup_enabled, u.deactivated_at, r.repo_root_cid, r.repo_rev\n FROM users u\n JOIN repos r ON r.user_id = u.id\n WHERE u.backup_enabled = true\n AND u.deactivated_at IS NULL\n AND (\n NOT EXISTS (\n SELECT 1 FROM account_backups ab WHERE ab.user_id = u.id\n )\n OR (\n SELECT MAX(ab.created_at) FROM account_backups ab WHERE ab.user_id = u.id\n ) < NOW() - make_interval(secs => $1)\n )\n LIMIT $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "backup_enabled",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "deactivated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "repo_root_cid",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "repo_rev",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Float8",
"Int8"
]
},
"nullable": [
false,
false,
false,
true,
false,
true
]
},
"hash": "07c54d6bcfdc08d821e788c31dc46cc240dc8507c7dd5bdd2ceeb36d2084e8ce"
}
@@ -1,87 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n id,\n delegated_did,\n actor_did,\n controller_did,\n action_type as \"action_type: PgDelegationActionType\",\n action_details,\n ip_address,\n user_agent,\n created_at\n FROM delegation_audit_log\n WHERE controller_did = $1\n ORDER BY created_at DESC\n LIMIT $2 OFFSET $3\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "delegated_did",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "actor_did",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "controller_did",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "action_type: PgDelegationActionType",
"type_info": {
"Custom": {
"name": "delegation_action_type",
"kind": {
"Enum": [
"grant_created",
"grant_revoked",
"scopes_modified",
"token_issued",
"repo_write",
"blob_upload",
"account_action"
]
}
}
}
},
{
"ordinal": 5,
"name": "action_details",
"type_info": "Jsonb"
},
{
"ordinal": 6,
"name": "ip_address",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "user_agent",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Int8",
"Int8"
]
},
"nullable": [
false,
false,
false,
true,
false,
true,
true,
true,
false
]
},
"hash": "0ce61cd393867522de318c1f86c787851ec7bbc31b147b9c2fb2bac9b2676ba6"
}
@@ -1,29 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT ab.storage_key, ab.repo_rev\n FROM account_backups ab\n JOIN users u ON u.id = ab.user_id\n WHERE ab.id = $1 AND u.did = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "storage_key",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "repo_rev",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "0d70da6b077d6fbab5056c38490acbe772626a3447182b76b0cbcee15c5a46dc"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT body FROM comms_queue WHERE user_id = (SELECT id FROM users WHERE did = $1) AND comms_type = 'email_update' ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "body",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "0ec60bb854a4991d0d7249a68f7445b65c8cc8c723baca221d85f5e4f2478b99"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT token FROM sso_pending_registration WHERE token = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "0fae1be7a75bdc58c69a9af97cad4aec23c32a9378764b8d6d7eb2cc89c562b1"
}
@@ -1,29 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, storage_key\n FROM account_backups\n WHERE user_id = $1\n ORDER BY created_at DESC\n OFFSET $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "storage_key",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Uuid",
"Int8"
]
},
"nullable": [
false,
false
]
},
"hash": "120c30d563b3cc40a2bb670f0c38c4ad63360b4a4f8e20c21afbe60c6fb7087a"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM sso_pending_registration\n WHERE token = $1 AND expires_at > NOW()\n RETURNING token\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "1c84643fd6bc57c76517849a64d2d877df337e823d4c2c2b077f695bbfc9e9ac"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM sso_pending_registration\n WHERE token = $1 AND expires_at > NOW()\n RETURNING token, request_uri\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "request_uri",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "24b823043ab60f36c29029137fef30dfe33922bb06067f2fdbfc1fbb4b0a2a81"
}
@@ -1,38 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO external_identities (did, provider, provider_user_id)\n VALUES ($1, $2, $3)\n RETURNING id\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text"
]
},
"nullable": [
false
]
},
"hash": "2841093a67480e75e1e9e4046bf3eb74afae2d04f5ea0ec17a4d433983e6d71c"
}
@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE users SET password_reset_code_expires_at = NOW() - INTERVAL '1 hour' WHERE email = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "29ef76852bb89af1ab9e679ceaa4abcf8bc8268a348d3be0da9840d1708d20b5"
}
@@ -1,52 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT u.id, u.did, u.backup_enabled, u.deactivated_at, r.repo_root_cid, r.repo_rev\n FROM users u\n JOIN repos r ON r.user_id = u.id\n WHERE u.did = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "backup_enabled",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "deactivated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "repo_root_cid",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "repo_rev",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
true,
false,
true
]
},
"hash": "3043db19db2d0f51d1db6965a3ba0af4a1a4a76cc4ab1cad8395ba6babecc37d"
}
@@ -1,32 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_pending_registration (token, request_uri, provider, provider_user_id, provider_email_verified)\n VALUES ($1, $2, $3, $4, $5)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "376b72306b50f747bc9161985ff4f50c35c53025a55ccf5e9933dc3795d29313"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM external_identities WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "3933ea5b147ab6294936de147b98e116cfae848ecd76ea5d367585eb5117f2ad"
}
@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO users (did, handle, email, password_hash) VALUES ($1, $2, $3, 'hash')",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "3bed8d4843545f4a9676207513806603c50eb2af92957994abaf1c89c0294c12"
}
@@ -1,55 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT subject, body, comms_type as \"comms_type: String\" FROM comms_queue WHERE user_id = $1 AND comms_type = 'admin_email' ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "subject",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "body",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "comms_type: String",
"type_info": {
"Custom": {
"name": "comms_type",
"kind": {
"Enum": [
"welcome",
"email_verification",
"password_reset",
"email_update",
"account_deletion",
"admin_email",
"plc_operation",
"two_factor_code",
"channel_verification",
"passkey_recovery",
"legacy_login_alert",
"migration_verification",
"channel_verified"
]
}
}
}
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true,
false,
false
]
},
"hash": "4445cc86cdf04894b340e67661b79a3c411917144a011f50849b737130b24dbe"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM users WHERE email = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "4560c237741ce9d4166aecd669770b3360a3ac71e649b293efb88d92c3254068"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT token, expires_at FROM account_deletion_requests WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "expires_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "47fe4a54857344d8f789f37092a294cd58f64b4fb431b54b5deda13d64525e88"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT email_verified FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email_verified",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "49cbc923cc4a0dcf7dea4ead5ab9580ff03b717586c4ca2d5343709e2dac86b6"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT token FROM sso_pending_registration\n WHERE token = $1 AND expires_at > NOW()\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "4fef326fa2d03d04869af3fec702c901d1ecf392545a3a032438b2c1859d46cc"
}
@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO oauth_authorization_request (id, client_id, parameters, expires_at)\n VALUES ($1, 'https://test.example.com', $2, NOW() + INTERVAL '1 hour')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Jsonb"
]
},
"nullable": []
},
"hash": "575c1e5529874f8f523e6fe22ccf4ee3296806581b1765dfb91a84ffab347f15"
}
@@ -1,33 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_pending_registration (token, request_uri, provider, provider_user_id, provider_username, provider_email)\n VALUES ($1, $2, $3, $4, $5, $6)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "596c3400a60c77c7645fd46fcea61fa7898b6832e58c0f647f382b23b81d350e"
}
@@ -1,81 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, did, provider as \"provider: SsoProviderType\", provider_user_id, provider_username, provider_email\n FROM external_identities\n WHERE provider = $1 AND provider_user_id = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "provider: SsoProviderType",
"type_info": {
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
}
},
{
"ordinal": 3,
"name": "provider_user_id",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "provider_username",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "provider_email",
"type_info": "Text"
}
],
"parameters": {
"Left": [
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text"
]
},
"nullable": [
false,
false,
false,
false,
true,
true
]
},
"hash": "59e63c5cf92985714e9586d1ce012efef733d4afaa4ea09974daf8303805e5d2"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT k.key_bytes, k.encryption_version\n FROM user_keys k\n JOIN users u ON k.user_id = u.id\n WHERE u.did = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "key_bytes",
"type_info": "Bytea"
},
{
"ordinal": 1,
"name": "encryption_version",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
true
]
},
"hash": "5a016f289caf75177731711e56e92881ba343c73a9a6e513e205c801c5943ec0"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM sso_auth_state\n WHERE state = $1 AND expires_at > NOW()\n RETURNING state\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "state",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "5af4a386c1632903ad7102551a5bd148bcf541baab6a84c8649666a695f9c4d1"
}
@@ -1,43 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT provider_user_id, provider_email_verified\n FROM external_identities\n WHERE did = $1 AND provider = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "provider_user_id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "provider_email_verified",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
}
]
},
"nullable": [
false,
false
]
},
"hash": "5e4c0dd92ac3c4b5e2eae5d129f2649cf3a8f068105f44a8dca9625427affc06"
}
@@ -1,33 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_auth_state (state, request_uri, provider, action, nonce, code_verifier)\n VALUES ($1, $2, $3, $4, $5, $6)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "5e9c6ec72c2c0ea1c8dff551d01baddd1dd953c828a5656db2ee39dea996f890"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT did, email_verified FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "email_verified",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "63f6f2a89650794fe90e10ce7fc785a6b9f7d37c12b31a6ff13f7c5214eef19e"
}
@@ -1,66 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT state, request_uri, provider as \"provider: SsoProviderType\", action, nonce, code_verifier\n FROM sso_auth_state\n WHERE state = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "state",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "request_uri",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "provider: SsoProviderType",
"type_info": {
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
}
},
{
"ordinal": 3,
"name": "action",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "nonce",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "code_verifier",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
true,
true
]
},
"hash": "6c7ace2a64848adc757af6c93b9162e1d95788b372370a7ad0d7540338bb73ee"
}
@@ -1,27 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO account_backups (user_id, storage_key, repo_root_cid, repo_rev, block_count, size_bytes)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (storage_key) DO UPDATE SET created_at = NOW()\n RETURNING id\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Text",
"Text",
"Text",
"Int4",
"Int8"
]
},
"nullable": [
false
]
},
"hash": "6c7d5b62546ed7581edbfdb6946492a6cc41b94b04009b5602f1ef72e0138edc"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT state FROM sso_auth_state WHERE state = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "state",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "6fbcff0206599484bfb6cef165b6f729d27e7a342f7718ee4ac07f0ca94412ba"
}
@@ -1,33 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_pending_registration (token, request_uri, provider, provider_user_id, provider_username, provider_email_verified)\n VALUES ($1, $2, $3, $4, $5, $6)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "712459c27fc037f45389e2766cf1057e86e93ef756a784ed12beb453b03c5da1"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT subject FROM comms_queue WHERE user_id = $1 AND comms_type = 'admin_email' AND body = 'Email without subject' LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "subject",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "785a864944c5939331704c71b0cd3ed26ffdd64f3fd0f26ecc28b6a0557bbe8f"
}
@@ -1,35 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT ab.id, ab.storage_key, u.deactivated_at\n FROM account_backups ab\n JOIN users u ON u.id = ab.user_id\n WHERE ab.id = $1 AND u.did = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "storage_key",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "deactivated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
false,
true
]
},
"hash": "78be3d837cfb54d5e915ff0c5b1aaedc104776a22ad28b637de574e58d052036"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT t.token\n FROM plc_operation_tokens t\n JOIN users u ON t.user_id = u.id\n WHERE u.did = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "7caa8f9083b15ec1209dda35c4c6f6fba9fe338e4a6a10636b5389d426df1631"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT provider_username, last_login_at FROM external_identities WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "provider_username",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "last_login_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true,
true
]
},
"hash": "7d24e744a4e63570b1410e50b45b745ce8915ab3715b3eff7efc2d84f27735d0"
}
@@ -1,46 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n u.did,\n u.handle,\n d.granted_scopes,\n d.granted_at,\n (u.deactivated_at IS NULL AND u.takedown_ref IS NULL) as \"is_active!\"\n FROM account_delegations d\n JOIN users u ON u.did = d.controller_did\n WHERE d.delegated_did = $1 AND d.revoked_at IS NULL\n ORDER BY d.granted_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "handle",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "granted_scopes",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "granted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "is_active!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
null
]
},
"hash": "7d43e7e917104d7bce29459149a345145361c6940e9b8e2ccc561a0a032f63c0"
}
@@ -1,52 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, repo_rev, repo_root_cid, block_count, size_bytes, created_at\n FROM account_backups\n WHERE user_id = $1\n ORDER BY created_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "repo_rev",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "repo_root_cid",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "block_count",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "size_bytes",
"type_info": "Int8"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false
]
},
"hash": "7ec9500e28b450ab569ec50f968f5f66b7e8e80b160db9734cb78f91fc9f2cc6"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT t.token, t.expires_at FROM plc_operation_tokens t JOIN users u ON t.user_id = u.id WHERE u.did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "expires_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "82717b6f61cd79347e1ca7e92c4413743ba168d1e0d8b85566711e54d4048f81"
}
@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_pending_registration (token, request_uri, provider, provider_user_id, provider_username, provider_email, provider_email_verified)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "85ffc37a77af832d7795f5f37efe304fced4bf56b4f2287fe9aeb3fc97e1b191"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT body FROM comms_queue WHERE user_id = (SELECT id FROM users WHERE did = $1) AND comms_type = 'email_verification' ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "body",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "9ad422bf3c43e3cfd86fc88c73594246ead214ca794760d3fe77bb5cf4f27be5"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT did, public_key_did_key FROM reserved_signing_keys WHERE public_key_did_key = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "public_key_did_key",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true,
false
]
},
"hash": "9b035b051769e6b9d45910a8bb42ac0f84c73de8c244ba4560f004ee3f4b7002"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id FROM external_identities WHERE did = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "9dba64081d4f95b5490c9a9bf30a7175db3429f39df4f25e212f38f33882fc65"
}
@@ -1,66 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT token, request_uri, provider as \"provider: SsoProviderType\", provider_user_id,\n provider_username, provider_email\n FROM sso_pending_registration\n WHERE token = $1 AND expires_at > NOW()\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "request_uri",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "provider: SsoProviderType",
"type_info": {
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
}
},
{
"ordinal": 3,
"name": "provider_user_id",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "provider_username",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "provider_email",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
true,
true
]
},
"hash": "9fd56986c1c843d386d1e5884acef8573eb55a3e9f5cb0122fcf8b93d6d667a5"
}
@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT private_key_bytes, expires_at, used_at FROM reserved_signing_keys WHERE public_key_did_key = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "private_key_bytes",
"type_info": "Bytea"
},
{
"ordinal": 1,
"name": "expires_at",
"type_info": "Timestamptz"
},
{
"ordinal": 2,
"name": "used_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
true
]
},
"hash": "a23a390659616779d7dbceaa3b5d5171e70fa25e3b8393e142cebcbff752f0f5"
}
@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE external_identities\n SET provider_username = $2, last_login_at = NOW()\n WHERE id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": []
},
"hash": "a3d549a32e76c24e265c73a98dd739067623f275de0740bd576ee288f4444496"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT token FROM account_deletion_requests WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
},
"hash": "a802d7d860f263eace39ce82bb27b633cec7287c1cc177f0e1d47ec6571564d5"
}
@@ -1,40 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT preferred_comms_channel as \"preferred_comms_channel: String\", discord_username FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "preferred_comms_channel: String",
"type_info": {
"Custom": {
"name": "comms_channel",
"kind": {
"Enum": [
"email",
"discord",
"telegram",
"signal"
]
}
}
}
},
{
"ordinal": 1,
"name": "discord_username",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
true
]
},
"hash": "a844774d8dd3c50c5faf3de5d43f534b80234759c8437434e467ca33ea10fd1f"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM sso_auth_state\n WHERE state = $1 AND expires_at > NOW()\n RETURNING state, request_uri\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "state",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "request_uri",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false
]
},
"hash": "aee3e8e1d8924d41bec7d866e274f8bb2ddef833eb03326103c2d0a17ee56154"
}
@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT DISTINCT b.cid, b.storage_key, b.mime_type\n FROM blobs b\n JOIN record_blobs rb ON rb.blob_cid = b.cid\n WHERE rb.repo_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "cid",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "storage_key",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "mime_type",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false
]
},
"hash": "b22003e74a58303beb993547a8e2bf2415152a5546d6a10c9aebc223420b0088"
}
@@ -1,31 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_pending_registration (token, request_uri, provider, provider_user_id, expires_at)\n VALUES ($1, $2, $3, $4, NOW() - INTERVAL '1 hour')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text"
]
},
"nullable": []
},
"hash": "ba9684872fad5201b8504c2606c29364a2df9631fe98817e7bfacd3f3f51f6cb"
}
@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM sso_auth_state WHERE expires_at < NOW()",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "bb4460f75d30f48b79d71b97f2c7d54190260deba2d2ade177dbdaa507ab275b"
}
@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM account_backups WHERE user_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "bb83d46014c20edc99ef7e81808087097e719771c6c8163e4e8e11a98bb97dde"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT deactivated_at FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "deactivated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "bf2b237ee5cfe66d038dce3f564c05a683d391aebda7871d65d302e04b5d733f"
}
@@ -1,46 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n u.did,\n u.handle,\n d.granted_scopes,\n d.granted_at,\n true as \"is_active!\"\n FROM account_delegations d\n JOIN users u ON u.did = d.controller_did\n WHERE d.delegated_did = $1\n AND d.revoked_at IS NULL\n AND u.deactivated_at IS NULL\n AND u.takedown_ref IS NULL\n ORDER BY d.granted_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "did",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "handle",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "granted_scopes",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "granted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "is_active!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
null
]
},
"hash": "c69577bc8e88e2f2cc516d6bec3d201419b589b6088ceb933cb182265b14e363"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT password_reset_code FROM users WHERE email = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "password_reset_code",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "cd3b8098ad4c1056c1d23acd8a6b29f7abfe18ee6f559bd94ab16274b1cfdfee"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) as \"count!\" FROM plc_operation_tokens t JOIN users u ON t.user_id = u.id WHERE u.did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "cda68f9b6c60295a196fc853b70ec5fd51a8ffaa2bac5942c115c99d1cbcafa3"
}
@@ -1,31 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sso_auth_state (state, request_uri, provider, action, expires_at)\n VALUES ($1, $2, $3, $4, NOW() - INTERVAL '1 hour')\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text"
]
},
"nullable": []
},
"hash": "d0d4fb4b44cda3442b20037b4d5efaa032e1d004c775e2b6077c5050d7d62041"
}
@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE account_deletion_requests SET expires_at = NOW() - INTERVAL '1 hour' WHERE token = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "d529d6dc9858c1da360f0417e94a3b40041b043bae57e95002d4bf5df46a4ab4"
}
@@ -1,52 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n d.controller_did,\n u.handle as \"handle?\",\n d.granted_scopes,\n d.granted_at,\n true as \"is_active!\",\n u.did IS NOT NULL as \"is_local!\"\n FROM account_delegations d\n LEFT JOIN users u ON u.did = d.controller_did\n WHERE d.delegated_did = $1\n AND d.revoked_at IS NULL\n AND (u.did IS NULL OR (u.deactivated_at IS NULL AND u.takedown_ref IS NULL))\n ORDER BY d.granted_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "controller_did",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "handle?",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "granted_scopes",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "granted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "is_active!",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "is_local!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
null,
null
]
},
"hash": "d8e646324c93b375cceccea533ddd880225931f29ce4d8c5184197fecce25fa7"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT COUNT(*) as \"count!\"\n FROM account_delegations d\n JOIN users u ON u.did = d.controller_did\n WHERE d.delegated_did = $1\n AND d.revoked_at IS NULL\n AND u.deactivated_at IS NULL\n AND u.takedown_ref IS NULL\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "d92bfa1e67c60c4fb333b6390e49224381c1dd23c3ef09aff3a6d59eadd13c64"
}
@@ -1,40 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO external_identities (did, provider, provider_user_id, provider_username, provider_email)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text",
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "dd7d80d4d118a5fc95b574e2ca9ffaccf974e52fb6ac368f716409c55f9d3ab0"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM comms_queue WHERE user_id = $1 AND comms_type = 'password_reset'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "e20cbe2a939d790aaea718b084a80d8ede655ba1cc0fd4346d7e91d6de7d6cf3"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT used_at FROM reserved_signing_keys WHERE public_key_did_key = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "used_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "e64cd36284d10ab7f3d9f6959975a1a627809f444b0faff7e611d985f31b90e9"
}
@@ -1,30 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO external_identities (did, provider, provider_user_id)\n VALUES ($1, $2, $3)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
{
"Custom": {
"name": "sso_provider_type",
"kind": {
"Enum": [
"github",
"discord",
"google",
"gitlab",
"oidc",
"apple"
]
}
}
},
"Text"
]
},
"nullable": []
},
"hash": "eb54d2ce02cab7c2e7f9926bd469b19e5f0513f47173b2738fc01a57082d7abb"
}
@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM external_identities WHERE id = $1 AND did = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": []
},
"hash": "ec22a8cc89e480c403a239eac44288e144d83364129491de6156760616666d3d"
}
@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT email FROM users WHERE did = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "f26c13023b47b908ec96da2e6b8bf8b34ca6a2246c20fc96f76f0e95530762a7"
}
@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE users SET is_admin = TRUE WHERE did = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "f29da3bdfbbc547b339b4cdb059fac26435b0feec65cf1c56f851d1c4d6b1814"
}
@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE users SET backup_enabled = $1 WHERE did = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Bool",
"Text"
]
},
"nullable": []
},
"hash": "f71428b1ce982504cd531937131d49196ec092b4d13e9ae7dcdaedfe98de5a70"
}
@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT password_reset_code, password_reset_code_expires_at FROM users WHERE email = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "password_reset_code",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "password_reset_code_expires_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true,
true
]
},
"hash": "f7af28963099aec12cf1d4f8a9a03699bb3a90f39bc9c4c0f738a37827e8f382"
}
@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM account_backups WHERE id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "f85f8d49bbd2d5e048bd8c29081aef5b8097e2384793e85df72eeeb858b7c532"
}
+1 -1
View File
@@ -24,7 +24,7 @@ members = [
]
[workspace.package]
version = "0.4.3"
version = "0.4.4"
edition = "2024"
license = "AGPL-3.0-or-later"
+3 -3
View File
@@ -1,6 +1,3 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Auth, NotTakendown, Permissive};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -10,6 +7,9 @@ use axum::{
use chrono::{Datelike, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Auth, NotTakendown, Permissive};
use tranquil_pds::state::AppState;
const APP_BSKY_NAMESPACE: &str = "app.bsky";
const MAX_PREFERENCES_COUNT: usize = 100;
@@ -1,8 +1,3 @@
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
use axum::{
Json,
extract::State,
@@ -10,6 +5,11 @@ use axum::{
};
use serde::Deserialize;
use tracing::warn;
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
#[derive(Deserialize)]
pub struct DeleteAccountInput {
@@ -1,7 +1,3 @@
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
use axum::{
Json,
extract::State,
@@ -10,6 +6,10 @@ use axum::{
};
use serde::{Deserialize, Serialize};
use tracing::warn;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -1,7 +1,3 @@
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
use axum::{
Json,
extract::{Query, RawQuery, State},
@@ -10,6 +6,10 @@ use axum::{
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
#[derive(Deserialize)]
pub struct GetAccountInfoParams {
@@ -196,10 +196,11 @@ pub async fn get_account_infos(
_auth: Auth<Admin>,
RawQuery(raw_query): RawQuery,
) -> Result<Response, ApiError> {
let dids: Vec<String> = tranquil_pds::util::parse_repeated_query_param(raw_query.as_deref(), "dids")
.into_iter()
.filter(|d| !d.is_empty())
.collect();
let dids: Vec<String> =
tranquil_pds::util::parse_repeated_query_param(raw_query.as_deref(), "dids")
.into_iter()
.filter(|d| !d.is_empty())
.collect();
if dids.is_empty() {
return Err(ApiError::InvalidRequest("dids is required".into()));
@@ -1,7 +1,3 @@
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
use axum::{
Json,
extract::{Query, State},
@@ -9,6 +5,10 @@ use axum::{
response::{IntoResponse, Response},
};
use serde::{Deserialize, Serialize};
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
#[derive(Deserialize)]
pub struct SearchAccountsParams {
@@ -1,8 +1,3 @@
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle, PlainPassword};
use axum::{
Json,
extract::State,
@@ -10,6 +5,11 @@ use axum::{
};
use serde::Deserialize;
use tracing::{error, warn};
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle, PlainPassword};
#[derive(Deserialize)]
pub struct UpdateAccountEmailInput {
+3 -3
View File
@@ -1,9 +1,9 @@
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use axum::{Json, extract::State};
use serde::{Deserialize, Serialize};
use tracing::{error, warn};
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_types::CidLink;
#[derive(Serialize)]
+4 -4
View File
@@ -1,7 +1,3 @@
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::{Query, State},
@@ -11,6 +7,10 @@ use axum::{
use serde::{Deserialize, Serialize};
use tracing::error;
use tranquil_db_traits::InviteCodeSortOrder;
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -1,12 +1,12 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
response::{IntoResponse, Response},
};
use serde::Serialize;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
+4 -4
View File
@@ -1,7 +1,3 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{CidLink, Did};
use axum::{
Json,
extract::{Query, State},
@@ -11,6 +7,10 @@ use axum::{
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{error, warn};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Admin, Auth};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{CidLink, Did};
#[derive(Deserialize)]
pub struct GetSubjectStatusParams {
+4 -2
View File
@@ -1,5 +1,3 @@
use tranquil_pds::auth::{AccountRequirement, extract_auth_token_from_header, validate_token_with_dpop};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -7,6 +5,10 @@ use axum::{
response::{IntoResponse, Response},
};
use serde_json::json;
use tranquil_pds::auth::{
AccountRequirement, extract_auth_token_from_header, validate_token_with_dpop,
};
use tranquil_pds::state::AppState;
pub async fn get_state(State(state): State<AppState>, headers: HeaderMap) -> Response {
let created_at = get_account_created_at(&state, &headers).await;
-766
View File
@@ -1,766 +0,0 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::api::{EmptyResponse, EnabledResponse};
use tranquil_pds::auth::{Active, Auth};
use tranquil_pds::scheduled::generate_full_backup;
use tranquil_pds::state::AppState;
use tranquil_pds::storage::{BackupStorage, backup_retention_count};
use anyhow::Context;
use axum::{
Json,
extract::{Query, State},
http::StatusCode,
response::{IntoResponse, Response},
};
use cid::Cid;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::str::FromStr;
use tracing::{error, info, warn};
use tranquil_db::{BackupRepository, OldBackupInfo};
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BackupInfo {
pub id: String,
pub repo_rev: String,
pub repo_root_cid: String,
pub block_count: i32,
pub size_bytes: i64,
pub created_at: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ListBackupsOutput {
pub backups: Vec<BackupInfo>,
pub backup_enabled: bool,
}
pub async fn list_backups(
State(state): State<AppState>,
auth: Auth<Active>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let (user_id, backup_enabled) = match state.backup_repo.get_user_backup_status(&auth.did).await
{
Ok(Some(status)) => status,
Ok(None) => {
return Ok(ApiError::AccountNotFound.into_response());
}
Err(e) => {
error!("DB error fetching user: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
let backups = match state.backup_repo.list_backups_for_user(user_id).await {
Ok(rows) => rows,
Err(e) => {
error!("DB error fetching backups: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
let backup_list: Vec<BackupInfo> = backups
.into_iter()
.map(|b| BackupInfo {
id: b.id.to_string(),
repo_rev: b.repo_rev,
repo_root_cid: b.repo_root_cid,
block_count: b.block_count,
size_bytes: b.size_bytes,
created_at: b.created_at.to_rfc3339(),
})
.collect();
Ok((
StatusCode::OK,
Json(ListBackupsOutput {
backups: backup_list,
backup_enabled,
}),
)
.into_response())
}
#[derive(Deserialize)]
pub struct GetBackupQuery {
pub id: String,
}
pub async fn get_backup(
State(state): State<AppState>,
auth: Auth<Active>,
Query(query): Query<GetBackupQuery>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let backup_id = match uuid::Uuid::parse_str(&query.id) {
Ok(id) => id,
Err(_) => {
return Ok(ApiError::InvalidRequest("Invalid backup ID".into()).into_response());
}
};
let backup_info = match state
.backup_repo
.get_backup_storage_info(backup_id, &auth.did)
.await
{
Ok(Some(b)) => b,
Ok(None) => {
return Ok(ApiError::BackupNotFound.into_response());
}
Err(e) => {
error!("DB error fetching backup: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
let backup_storage = match state.backup_storage.as_ref() {
Some(storage) => storage,
None => {
return Ok(ApiError::BackupsDisabled.into_response());
}
};
let car_bytes = match backup_storage.get_backup(&backup_info.storage_key).await {
Ok(bytes) => bytes,
Err(e) => {
error!("Failed to fetch backup from storage: {:?}", e);
return Ok(
ApiError::InternalError(Some("Failed to retrieve backup".into())).into_response(),
);
}
};
Ok((
StatusCode::OK,
[
(axum::http::header::CONTENT_TYPE, "application/vnd.ipld.car"),
(
axum::http::header::CONTENT_DISPOSITION,
&format!("attachment; filename=\"{}.car\"", backup_info.repo_rev),
),
],
car_bytes,
)
.into_response())
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBackupOutput {
pub id: String,
pub repo_rev: String,
pub size_bytes: i64,
pub block_count: i32,
}
pub async fn create_backup(
State(state): State<AppState>,
auth: Auth<Active>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let backup_storage = match state.backup_storage.as_ref() {
Some(storage) => storage,
None => {
return Ok(ApiError::BackupsDisabled.into_response());
}
};
let user = match state.backup_repo.get_user_for_backup(&auth.did).await {
Ok(Some(u)) => u,
Ok(None) => {
return Ok(ApiError::AccountNotFound.into_response());
}
Err(e) => {
error!("DB error fetching user: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
if user.deactivated_at.is_some() {
return Ok(ApiError::AccountDeactivated.into_response());
}
let repo_rev = match &user.repo_rev {
Some(rev) => rev.clone(),
None => {
return Ok(ApiError::RepoNotReady.into_response());
}
};
let head_cid = match Cid::from_str(&user.repo_root_cid) {
Ok(c) => c,
Err(_) => {
return Ok(
ApiError::InternalError(Some("Invalid repo root CID".into())).into_response(),
);
}
};
let car_bytes = match generate_full_backup(
state.repo_repo.as_ref(),
&state.block_store,
user.id,
&head_cid,
)
.await
{
Ok(bytes) => bytes,
Err(e) => {
error!("Failed to generate CAR: {:?}", e);
return Ok(
ApiError::InternalError(Some("Failed to generate backup".into())).into_response(),
);
}
};
let block_count = tranquil_pds::scheduled::count_car_blocks(&car_bytes);
let size_bytes = i64::try_from(car_bytes.len()).unwrap_or(i64::MAX);
let storage_key = match backup_storage
.put_backup(&user.did, &repo_rev, &car_bytes)
.await
{
Ok(key) => key,
Err(e) => {
error!("Failed to upload backup: {:?}", e);
return Ok(
ApiError::InternalError(Some("Failed to store backup".into())).into_response(),
);
}
};
let backup_id = match state
.backup_repo
.insert_backup(
user.id,
&storage_key,
&user.repo_root_cid,
&repo_rev,
block_count,
size_bytes,
)
.await
{
Ok(id) => id,
Err(e) => {
error!("DB error inserting backup: {:?}", e);
if let Err(rollback_err) = backup_storage.delete_backup(&storage_key).await {
error!(
storage_key = %storage_key,
error = %rollback_err,
"Failed to rollback orphaned backup from S3"
);
}
return Ok(
ApiError::InternalError(Some("Failed to record backup".into())).into_response(),
);
}
};
info!(
did = %user.did,
rev = %repo_rev,
size_bytes,
"Created manual backup"
);
let retention = backup_retention_count();
if let Err(e) = cleanup_old_backups(
state.backup_repo.as_ref(),
backup_storage.as_ref(),
user.id,
retention,
)
.await
{
warn!(did = %user.did, error = %e, "Failed to cleanup old backups after manual backup");
}
Ok((
StatusCode::OK,
Json(CreateBackupOutput {
id: backup_id.to_string(),
repo_rev,
size_bytes,
block_count,
}),
)
.into_response())
}
async fn cleanup_old_backups(
backup_repo: &dyn BackupRepository,
backup_storage: &dyn BackupStorage,
user_id: uuid::Uuid,
retention_count: u32,
) -> anyhow::Result<()> {
let old_backups: Vec<OldBackupInfo> = backup_repo
.get_old_backups(user_id, i64::from(retention_count))
.await
.context("DB error fetching old backups")?;
for backup in old_backups {
if let Err(e) = backup_storage.delete_backup(&backup.storage_key).await {
warn!(
storage_key = %backup.storage_key,
error = %e,
"Failed to delete old backup from storage, skipping DB cleanup to avoid orphan"
);
continue;
}
backup_repo
.delete_backup(backup.id)
.await
.context("Failed to delete old backup record")?;
}
Ok(())
}
#[derive(Deserialize)]
pub struct DeleteBackupQuery {
pub id: String,
}
pub async fn delete_backup(
State(state): State<AppState>,
auth: Auth<Active>,
Query(query): Query<DeleteBackupQuery>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let backup_id = match uuid::Uuid::parse_str(&query.id) {
Ok(id) => id,
Err(_) => {
return Ok(ApiError::InvalidRequest("Invalid backup ID".into()).into_response());
}
};
let backup = match state
.backup_repo
.get_backup_for_deletion(backup_id, &auth.did)
.await
{
Ok(Some(b)) => b,
Ok(None) => {
return Ok(ApiError::BackupNotFound.into_response());
}
Err(e) => {
error!("DB error fetching backup: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
if backup.deactivated_at.is_some() {
return Ok(ApiError::AccountDeactivated.into_response());
}
if let Some(backup_storage) = state.backup_storage.as_ref()
&& let Err(e) = backup_storage.delete_backup(&backup.storage_key).await
{
warn!(
storage_key = %backup.storage_key,
error = %e,
"Failed to delete backup from storage (continuing anyway)"
);
}
if let Err(e) = state.backup_repo.delete_backup(backup.id).await {
error!("DB error deleting backup: {:?}", e);
return Ok(ApiError::InternalError(Some("Failed to delete backup".into())).into_response());
}
info!(did = %auth.did, backup_id = %backup_id, "Deleted backup");
Ok(EmptyResponse::ok().into_response())
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SetBackupEnabledInput {
pub enabled: bool,
}
pub async fn set_backup_enabled(
State(state): State<AppState>,
auth: Auth<Active>,
Json(input): Json<SetBackupEnabledInput>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let deactivated_at = match state
.backup_repo
.get_user_deactivated_status(&auth.did)
.await
{
Ok(Some(status)) => status,
Ok(None) => {
return Ok(ApiError::AccountNotFound.into_response());
}
Err(e) => {
error!("DB error fetching user: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
if deactivated_at.is_some() {
return Ok(ApiError::AccountDeactivated.into_response());
}
if let Err(e) = state
.backup_repo
.update_backup_enabled(&auth.did, input.enabled)
.await
{
error!("DB error updating backup_enabled: {:?}", e);
return Ok(
ApiError::InternalError(Some("Failed to update setting".into())).into_response(),
);
}
info!(did = %auth.did, enabled = input.enabled, "Updated backup_enabled setting");
Ok(EnabledResponse::response(input.enabled).into_response())
}
pub async fn export_blobs(
State(state): State<AppState>,
auth: Auth<Active>,
) -> Result<Response, tranquil_pds::api::error::ApiError> {
let user_id = match state.backup_repo.get_user_id_by_did(&auth.did).await {
Ok(Some(id)) => id,
Ok(None) => {
return Ok(ApiError::AccountNotFound.into_response());
}
Err(e) => {
error!("DB error fetching user: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
let blobs = match state.backup_repo.get_blobs_for_export(user_id).await {
Ok(rows) => rows,
Err(e) => {
error!("DB error fetching blobs: {:?}", e);
return Ok(ApiError::InternalError(None).into_response());
}
};
if blobs.is_empty() {
return Ok((
StatusCode::OK,
[
(axum::http::header::CONTENT_TYPE, "application/zip"),
(
axum::http::header::CONTENT_DISPOSITION,
"attachment; filename=\"blobs.zip\"",
),
],
Vec::<u8>::new(),
)
.into_response());
}
let mut zip_buffer = std::io::Cursor::new(Vec::new());
{
let mut zip = zip::ZipWriter::new(&mut zip_buffer);
let options = zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Deflated);
let mut exported: Vec<serde_json::Value> = Vec::new();
let mut skipped: Vec<serde_json::Value> = Vec::new();
for blob in &blobs {
let blob_data = match state.blob_store.get(&blob.storage_key).await {
Ok(data) => data,
Err(e) => {
warn!(cid = %blob.cid, error = %e, "Failed to fetch blob, skipping");
skipped.push(json!({
"cid": blob.cid,
"mimeType": blob.mime_type,
"reason": "fetch_failed"
}));
continue;
}
};
let extension = mime_to_extension(&blob.mime_type);
let filename = format!("{}{}", blob.cid, extension);
if let Err(e) = zip.start_file(&filename, options) {
warn!(filename = %filename, error = %e, "Failed to start zip file entry");
skipped.push(json!({
"cid": blob.cid,
"mimeType": blob.mime_type,
"reason": "zip_entry_failed"
}));
continue;
}
if let Err(e) = std::io::Write::write_all(&mut zip, &blob_data) {
warn!(filename = %filename, error = %e, "Failed to write blob to zip");
skipped.push(json!({
"cid": blob.cid,
"mimeType": blob.mime_type,
"reason": "write_failed"
}));
continue;
}
exported.push(json!({
"cid": blob.cid,
"filename": filename,
"mimeType": blob.mime_type,
"sizeBytes": blob_data.len()
}));
}
let manifest = json!({
"exportedAt": chrono::Utc::now().to_rfc3339(),
"totalBlobs": blobs.len(),
"exportedCount": exported.len(),
"skippedCount": skipped.len(),
"exported": exported,
"skipped": skipped
});
if zip.start_file("manifest.json", options).is_ok() {
let _ = std::io::Write::write_all(
&mut zip,
serde_json::to_string_pretty(&manifest)
.unwrap_or_else(|_| "{}".to_string())
.as_bytes(),
);
}
if let Err(e) = zip.finish() {
error!("Failed to finish zip: {:?}", e);
return Ok(
ApiError::InternalError(Some("Failed to create zip file".into())).into_response(),
);
}
}
let zip_bytes = zip_buffer.into_inner();
info!(did = %auth.did, blob_count = blobs.len(), size_bytes = zip_bytes.len(), "Exported blobs");
Ok((
StatusCode::OK,
[
(axum::http::header::CONTENT_TYPE, "application/zip"),
(
axum::http::header::CONTENT_DISPOSITION,
"attachment; filename=\"blobs.zip\"",
),
],
zip_bytes,
)
.into_response())
}
fn mime_to_extension(mime_type: &str) -> &'static str {
match mime_type {
"application/font-sfnt" => ".otf",
"application/font-tdpfr" => ".pfr",
"application/font-woff" => ".woff",
"application/gzip" => ".gz",
"application/json" => ".json",
"application/json5" => ".json5",
"application/jsonml+json" => ".jsonml",
"application/octet-stream" => ".bin",
"application/pdf" => ".pdf",
"application/zip" => ".zip",
"audio/aac" => ".aac",
"audio/ac3" => ".ac3",
"audio/aiff" => ".aiff",
"audio/annodex" => ".axa",
"audio/audible" => ".aa",
"audio/basic" => ".au",
"audio/flac" => ".flac",
"audio/m4a" => ".m4a",
"audio/m4b" => ".m4b",
"audio/m4p" => ".m4p",
"audio/mid" => ".mid",
"audio/midi" => ".midi",
"audio/mp4" => ".mp4a",
"audio/mpeg" => ".mp3",
"audio/ogg" => ".ogg",
"audio/s3m" => ".s3m",
"audio/scpls" => ".pls",
"audio/silk" => ".sil",
"audio/vnd.audible.aax" => ".aax",
"audio/vnd.dece.audio" => ".uva",
"audio/vnd.digital-winds" => ".eol",
"audio/vnd.dlna.adts" => ".adt",
"audio/vnd.dra" => ".dra",
"audio/vnd.dts" => ".dts",
"audio/vnd.dts.hd" => ".dtshd",
"audio/vnd.lucent.voice" => ".lvp",
"audio/vnd.ms-playready.media.pya" => ".pya",
"audio/vnd.nuera.ecelp4800" => ".ecelp4800",
"audio/vnd.nuera.ecelp7470" => ".ecelp7470",
"audio/vnd.nuera.ecelp9600" => ".ecelp9600",
"audio/vnd.rip" => ".rip",
"audio/wav" => ".wav",
"audio/webm" => ".weba",
"audio/x-caf" => ".caf",
"audio/x-gsm" => ".gsm",
"audio/x-m4r" => ".m4r",
"audio/x-matroska" => ".mka",
"audio/x-mpegurl" => ".m3u",
"audio/x-ms-wax" => ".wax",
"audio/x-ms-wma" => ".wma",
"audio/x-pn-realaudio" => ".ra",
"audio/x-pn-realaudio-plugin" => ".rpm",
"audio/x-sd2" => ".sd2",
"audio/x-smd" => ".smd",
"audio/xm" => ".xm",
"font/collection" => ".ttc",
"font/ttf" => ".ttf",
"font/woff" => ".woff",
"font/woff2" => ".woff2",
"image/apng" => ".apng",
"image/avif" => ".avif",
"image/avif-sequence" => ".avifs",
"image/bmp" => ".bmp",
"image/cgm" => ".cgm",
"image/cis-cod" => ".cod",
"image/g3fax" => ".g3",
"image/gif" => ".gif",
"image/heic" => ".heic",
"image/heic-sequence" => ".heics",
"image/heif" => ".heif",
"image/heif-sequence" => ".heifs",
"image/ief" => ".ief",
"image/jp2" => ".jp2",
"image/jpeg" => ".jpg",
"image/jpm" => ".jpm",
"image/jpx" => ".jpf",
"image/jxl" => ".jxl",
"image/ktx" => ".ktx",
"image/pict" => ".pct",
"image/png" => ".png",
"image/prs.btif" => ".btif",
"image/qoi" => ".qoi",
"image/sgi" => ".sgi",
"image/svg+xml" => ".svg",
"image/tiff" => ".tiff",
"image/vnd.dece.graphic" => ".uvg",
"image/vnd.djvu" => ".djv",
"image/vnd.fastbidsheet" => ".fbs",
"image/vnd.fpx" => ".fpx",
"image/vnd.fst" => ".fst",
"image/vnd.fujixerox.edmics-mmr" => ".mmr",
"image/vnd.fujixerox.edmics-rlc" => ".rlc",
"image/vnd.ms-modi" => ".mdi",
"image/vnd.ms-photo" => ".wdp",
"image/vnd.net-fpx" => ".npx",
"image/vnd.radiance" => ".hdr",
"image/vnd.rn-realflash" => ".rf",
"image/vnd.wap.wbmp" => ".wbmp",
"image/vnd.xiff" => ".xif",
"image/webp" => ".webp",
"image/x-3ds" => ".3ds",
"image/x-adobe-dng" => ".dng",
"image/x-canon-cr2" => ".cr2",
"image/x-canon-cr3" => ".cr3",
"image/x-canon-crw" => ".crw",
"image/x-cmu-raster" => ".ras",
"image/x-cmx" => ".cmx",
"image/x-epson-erf" => ".erf",
"image/x-freehand" => ".fh",
"image/x-fuji-raf" => ".raf",
"image/x-icon" => ".ico",
"image/x-jg" => ".art",
"image/x-jng" => ".jng",
"image/x-kodak-dcr" => ".dcr",
"image/x-kodak-k25" => ".k25",
"image/x-kodak-kdc" => ".kdc",
"image/x-macpaint" => ".mac",
"image/x-minolta-mrw" => ".mrw",
"image/x-mrsid-image" => ".sid",
"image/x-nikon-nef" => ".nef",
"image/x-nikon-nrw" => ".nrw",
"image/x-olympus-orf" => ".orf",
"image/x-panasonic-rw" => ".raw",
"image/x-panasonic-rw2" => ".rw2",
"image/x-pentax-pef" => ".pef",
"image/x-portable-anymap" => ".pnm",
"image/x-portable-bitmap" => ".pbm",
"image/x-portable-graymap" => ".pgm",
"image/x-portable-pixmap" => ".ppm",
"image/x-qoi" => ".qoi",
"image/x-quicktime" => ".qti",
"image/x-rgb" => ".rgb",
"image/x-sigma-x3f" => ".x3f",
"image/x-sony-arw" => ".arw",
"image/x-sony-sr2" => ".sr2",
"image/x-sony-srf" => ".srf",
"image/x-tga" => ".tga",
"image/x-xbitmap" => ".xbm",
"image/x-xcf" => ".xcf",
"image/x-xpixmap" => ".xpm",
"image/x-xwindowdump" => ".xwd",
"model/gltf+json" => ".gltf",
"model/gltf-binary" => ".glb",
"model/iges" => ".igs",
"model/mesh" => ".msh",
"model/vnd.collada+xml" => ".dae",
"model/vnd.gdl" => ".gdl",
"model/vnd.gtw" => ".gtw",
"model/vnd.vtu" => ".vtu",
"model/vrml" => ".vrml",
"model/x3d+binary" => ".x3db",
"model/x3d+vrml" => ".x3dv",
"model/x3d+xml" => ".x3d",
"text/css" => ".css",
"text/html" => ".html",
"text/plain" => ".txt",
"video/3gpp" => ".3gp",
"video/3gpp2" => ".3g2",
"video/annodex" => ".axv",
"video/divx" => ".divx",
"video/h261" => ".h261",
"video/h263" => ".h263",
"video/h264" => ".h264",
"video/jpeg" => ".jpgv",
"video/jpm" => ".jpgm",
"video/mj2" => ".mj2",
"video/mp4" => ".mp4",
"video/mpeg" => ".mpg",
"video/ogg" => ".ogv",
"video/quicktime" => ".mov",
"video/vnd.dece.hd" => ".uvh",
"video/vnd.dece.mobile" => ".uvm",
"video/vnd.dece.pd" => ".uvp",
"video/vnd.dece.sd" => ".uvs",
"video/vnd.dece.video" => ".uvv",
"video/vnd.dlna.mpeg-tts" => ".ts",
"video/vnd.dvb.file" => ".dvb",
"video/vnd.fvt" => ".fvt",
"video/vnd.mpegurl" => ".m4u",
"video/vnd.ms-playready.media.pyv" => ".pyv",
"video/vnd.uvvu.mp4" => ".uvu",
"video/vnd.vivo" => ".viv",
"video/webm" => ".webm",
"video/x-dv" => ".dv",
"video/x-f4v" => ".f4v",
"video/x-fli" => ".fli",
"video/x-flv" => ".flv",
"video/x-ivf" => ".ivf",
"video/x-la-asf" => ".lsf",
"video/x-m4v" => ".m4v",
"video/x-matroska" => ".mkv",
"video/x-mng" => ".mng",
"video/x-ms-asf" => ".asf",
"video/x-ms-vob" => ".vob",
"video/x-ms-wm" => ".wm",
"video/x-ms-wmp" => ".wmp",
"video/x-ms-wmv" => ".wmv",
"video/x-ms-wmx" => ".wmx",
"video/x-ms-wvx" => ".wvx",
"video/x-msvideo" => ".avi",
"video/x-sgi-movie" => ".movie",
"video/x-smv" => ".smv",
_ => ".bin",
}
}
+48 -43
View File
@@ -1,13 +1,4 @@
use crate::identity::provision::{create_plc_did, init_genesis_repo};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Active, Auth};
use tranquil_pds::delegation::{
DelegationActionType, SCOPE_PRESETS, ValidatedDelegationScope, verify_can_add_controllers,
verify_can_control_accounts,
};
use tranquil_pds::rate_limit::{AccountCreationLimit, RateLimited};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
use axum::{
Json,
extract::{Query, State},
@@ -17,6 +8,15 @@ use axum::{
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{error, info, warn};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Active, Auth};
use tranquil_pds::delegation::{
DelegationActionType, SCOPE_PRESETS, ValidatedDelegationScope, verify_can_add_controllers,
verify_can_control_accounts,
};
use tranquil_pds::rate_limit::{AccountCreationLimit, RateLimited};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle};
pub async fn list_controllers(
State(state): State<AppState>,
@@ -70,33 +70,32 @@ pub async fn add_controller(
.await
.ok_or(ApiError::ControllerNotFound)?;
if !resolved.is_local {
if let Some(ref pds_url) = resolved.pds_url {
if !pds_url.starts_with("https://") {
return Ok(
ApiError::InvalidDelegation("Controller PDS must use HTTPS".into())
.into_response(),
);
if !resolved.is_local
&& let Some(ref pds_url) = resolved.pds_url
{
if !pds_url.starts_with("https://") {
return Ok(
ApiError::InvalidDelegation("Controller PDS must use HTTPS".into()).into_response(),
);
}
match state
.cross_pds_oauth
.check_remote_is_delegated(pds_url, input.controller_did.as_str())
.await
{
Some(true) => {
return Ok(ApiError::InvalidDelegation(
"Cannot add a delegated account from another PDS as a controller".into(),
)
.into_response());
}
match state
.cross_pds_oauth
.check_remote_is_delegated(pds_url, input.controller_did.as_str())
.await
{
Some(true) => {
return Ok(ApiError::InvalidDelegation(
"Cannot add a delegated account from another PDS as a controller".into(),
)
.into_response());
}
Some(false) => {}
None => {
warn!(
controller = %input.controller_did,
pds = %pds_url,
"Could not verify remote controller delegation status"
);
}
Some(false) => {}
None => {
warn!(
controller = %input.controller_did,
pds = %pds_url,
"Could not verify remote controller delegation status"
);
}
}
}
@@ -106,12 +105,17 @@ pub async fn add_controller(
Err(response) => return Ok(response),
};
if resolved.is_local {
if state.delegation_repo.is_delegated_account(&input.controller_did).await.unwrap_or(false) {
return Ok(ApiError::InvalidDelegation(
"Cannot add a controlled account as a controller".into(),
).into_response());
}
if resolved.is_local
&& state
.delegation_repo
.is_delegated_account(&input.controller_did)
.await
.unwrap_or(false)
{
return Ok(ApiError::InvalidDelegation(
"Cannot add a controlled account as a controller".into(),
)
.into_response());
}
match state
@@ -511,7 +515,9 @@ pub async fn resolve_controller(
let identifier = params.identifier.trim().trim_start_matches('@');
let did: Did = if identifier.starts_with("did:") {
identifier.parse().map_err(|_| ApiError::ControllerNotFound)?
identifier
.parse()
.map_err(|_| ApiError::ControllerNotFound)?
} else {
let local_handle: Option<Handle> = identifier.parse().ok();
let local_user = match local_handle {
@@ -534,4 +540,3 @@ pub async fn resolve_controller(
Ok(Json(resolved).into_response())
}
+33 -27
View File
@@ -1,10 +1,4 @@
use super::did::verify_did_web;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{ServiceTokenVerifier, extract_auth_token_from_header, is_service_token};
use tranquil_pds::rate_limit::{AccountCreationLimit, RateLimited};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle, PlainPassword};
use tranquil_pds::validation::validate_password;
use axum::{
Json,
extract::State,
@@ -17,6 +11,12 @@ use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{debug, error, info, warn};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{ServiceTokenVerifier, extract_auth_token_from_header, is_service_token};
use tranquil_pds::rate_limit::{AccountCreationLimit, RateLimited};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle, PlainPassword};
use tranquil_pds::validation::validate_password;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -335,14 +335,16 @@ pub async fn create_account(
.into_response();
}
};
let access_meta =
match tranquil_pds::auth::create_access_token_with_metadata(&did, &secret_key_bytes) {
Ok(m) => m,
Err(e) => {
error!("Error creating access token: {:?}", e);
return ApiError::InternalError(None).into_response();
}
};
let access_meta = match tranquil_pds::auth::create_access_token_with_metadata(
&did,
&secret_key_bytes,
) {
Ok(m) => m,
Err(e) => {
error!("Error creating access token: {:?}", e);
return ApiError::InternalError(None).into_response();
}
};
let refresh_meta = match tranquil_pds::auth::create_refresh_token_with_metadata(
&did,
&secret_key_bytes,
@@ -646,8 +648,9 @@ pub async fn create_account(
verification_channel,
recipient,
);
let formatted_token =
tranquil_pds::auth::verification_token::format_token_for_display(&verification_token);
let formatted_token = tranquil_pds::auth::verification_token::format_token_for_display(
&verification_token,
);
if let Err(e) = tranquil_pds::comms::comms_repo::enqueue_signup_verification(
state.user_repo.as_ref(),
state.infra_repo.as_ref(),
@@ -666,9 +669,12 @@ pub async fn create_account(
}
}
} else if let Some(ref user_email) = email {
let token =
tranquil_pds::auth::verification_token::generate_migration_token(&did_for_commit, user_email);
let formatted_token = tranquil_pds::auth::verification_token::format_token_for_display(&token);
let token = tranquil_pds::auth::verification_token::generate_migration_token(
&did_for_commit,
user_email,
);
let formatted_token =
tranquil_pds::auth::verification_token::format_token_for_display(&token);
if let Err(e) = tranquil_pds::comms::comms_repo::enqueue_migration_verification(
state.user_repo.as_ref(),
state.infra_repo.as_ref(),
@@ -683,14 +689,14 @@ pub async fn create_account(
}
}
let access_meta = match tranquil_pds::auth::create_access_token_with_metadata(&did, &secret_key_bytes)
{
Ok(m) => m,
Err(e) => {
error!("createAccount: Error creating access token: {:?}", e);
return ApiError::InternalError(None).into_response();
}
};
let access_meta =
match tranquil_pds::auth::create_access_token_with_metadata(&did, &secret_key_bytes) {
Ok(m) => m,
Err(e) => {
error!("createAccount: Error creating access token: {:?}", e);
return ApiError::InternalError(None).into_response();
}
};
let refresh_meta =
match tranquil_pds::auth::create_refresh_token_with_metadata(&did, &secret_key_bytes) {
Ok(m) => m,
+13 -11
View File
@@ -1,12 +1,3 @@
use tranquil_pds::api::{ApiError, DidResponse, EmptyResponse};
use tranquil_pds::auth::{Auth, NotTakendown};
use tranquil_pds::plc::signing_key_to_did_key;
use tranquil_pds::rate_limit::{
HandleUpdateDailyLimit, HandleUpdateLimit, check_user_rate_limit_with_message,
};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Handle;
use tranquil_pds::util::get_header_str;
use axum::{
Json,
extract::{Path, Query, State},
@@ -19,6 +10,15 @@ use k256::elliptic_curve::sec1::ToEncodedPoint;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{error, warn};
use tranquil_pds::api::{ApiError, DidResponse, EmptyResponse};
use tranquil_pds::auth::{Auth, NotTakendown};
use tranquil_pds::plc::signing_key_to_did_key;
use tranquil_pds::rate_limit::{
HandleUpdateDailyLimit, HandleUpdateLimit, check_user_rate_limit_with_message,
};
use tranquil_pds::state::AppState;
use tranquil_pds::types::Handle;
use tranquil_pds::util::get_header_str;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -503,7 +503,8 @@ pub async fn verify_did_web(
))?;
let pds_endpoint = format!("https://{}", hostname);
let has_valid_service = services.iter().any(|s| {
s["type"] == tranquil_pds::plc::ServiceType::Pds.as_str() && s["serviceEndpoint"] == pds_endpoint
s["type"] == tranquil_pds::plc::ServiceType::Pds.as_str()
&& s["serviceEndpoint"] == pds_endpoint
});
if !has_valid_service {
return Err(DidWebVerifyError::PdsNotListed(pds_endpoint));
@@ -811,7 +812,8 @@ pub async fn update_plc_handle(
Some(r) => r,
None => return Ok(()),
};
let key_bytes = tranquil_pds::config::decrypt_key(&user_row.key_bytes, user_row.encryption_version)?;
let key_bytes =
tranquil_pds::config::decrypt_key(&user_row.key_bytes, user_row.encryption_version)?;
let signing_key = k256::ecdsa::SigningKey::from_slice(&key_bytes)?;
let plc_client = state.plc_client();
let last_op = plc_client.get_last_op(did).await?;
+2 -2
View File
@@ -1,10 +1,10 @@
use tranquil_pds::rate_limit::{HandleVerificationLimit, RateLimited};
use tranquil_pds::types::{Did, Handle};
use axum::{
Json,
response::{IntoResponse, Response},
};
use serde::{Deserialize, Serialize};
use tranquil_pds::rate_limit::{HandleVerificationLimit, RateLimited};
use tranquil_pds::types::{Did, Handle};
#[derive(Deserialize)]
pub struct VerifyHandleOwnershipInput {
@@ -1,13 +1,13 @@
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::state::AppState;
use axum::{
extract::State,
response::{IntoResponse, Response},
};
use chrono::{Duration, Utc};
use tracing::{info, warn};
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::state::AppState;
fn generate_plc_token() -> String {
tranquil_pds::util::generate_token_code()
+13 -11
View File
@@ -1,9 +1,3 @@
use tranquil_pds::api::ApiError;
use tranquil_pds::api::error::DbResultExt;
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::circuit_breaker::with_circuit_breaker;
use tranquil_pds::plc::{PlcError, PlcService, ServiceType, create_update_op, sign_operation};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -16,6 +10,12 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use tracing::{error, info};
use tranquil_pds::api::ApiError;
use tranquil_pds::api::error::DbResultExt;
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::circuit_breaker::with_circuit_breaker;
use tranquil_pds::plc::{PlcError, PlcService, ServiceType, create_update_op, sign_operation};
use tranquil_pds::state::AppState;
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -86,11 +86,13 @@ pub async fn sign_plc_operation(
.log_db_err("fetching user key")?
.ok_or_else(|| ApiError::InternalError(Some("User signing key not found".into())))?;
let key_bytes = tranquil_pds::config::decrypt_key(&key_row.key_bytes, key_row.encryption_version)
.map_err(|e| {
error!("Failed to decrypt user key: {}", e);
ApiError::InternalError(None)
})?;
let key_bytes =
tranquil_pds::config::decrypt_key(&key_row.key_bytes, key_row.encryption_version).map_err(
|e| {
error!("Failed to decrypt user key: {}", e);
ApiError::InternalError(None)
},
)?;
let signing_key = SigningKey::from_slice(&key_bytes).map_err(|e| {
error!("Failed to create signing key: {:?}", e);
+13 -11
View File
@@ -1,9 +1,3 @@
use tranquil_pds::api::error::DbResultExt;
use tranquil_pds::api::{ApiError, EmptyResponse};
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::circuit_breaker::with_circuit_breaker;
use tranquil_pds::plc::{signing_key_to_did_key, validate_plc_operation};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -13,6 +7,12 @@ use k256::ecdsa::SigningKey;
use serde::Deserialize;
use serde_json::Value;
use tracing::{error, info, warn};
use tranquil_pds::api::error::DbResultExt;
use tranquil_pds::api::{ApiError, EmptyResponse};
use tranquil_pds::auth::{Auth, Permissive};
use tranquil_pds::circuit_breaker::with_circuit_breaker;
use tranquil_pds::plc::{signing_key_to_did_key, validate_plc_operation};
use tranquil_pds::state::AppState;
#[derive(Debug, Deserialize)]
pub struct SubmitPlcOperationInput {
@@ -57,11 +57,13 @@ pub async fn submit_plc_operation(
.log_db_err("fetching user key")?
.ok_or_else(|| ApiError::InternalError(Some("User signing key not found".into())))?;
let key_bytes = tranquil_pds::config::decrypt_key(&key_row.key_bytes, key_row.encryption_version)
.map_err(|e| {
error!("Failed to decrypt user key: {}", e);
ApiError::InternalError(None)
})?;
let key_bytes =
tranquil_pds::config::decrypt_key(&key_row.key_bytes, key_row.encryption_version).map_err(
|e| {
error!("Failed to decrypt user key: {}", e);
ApiError::InternalError(None)
},
)?;
let signing_key = SigningKey::from_slice(&key_bytes).map_err(|e| {
error!("Failed to create signing key: {:?}", e);
+19 -14
View File
@@ -1,11 +1,11 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::repo_ops::create_signed_commit;
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
use jacquard_common::types::{integer::LimitedU32, string::Tid};
use jacquard_repo::{mst::Mst, storage::BlockStore};
use k256::ecdsa::SigningKey;
use std::sync::Arc;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::repo_ops::create_signed_commit;
use tranquil_pds::state::AppState;
use tranquil_pds::types::Did;
pub struct PlcDidResult {
pub did: Did,
@@ -50,12 +50,16 @@ pub async fn submit_plc_genesis(
.clone()
.unwrap_or_else(|| tranquil_pds::plc::signing_key_to_did_key(signing_key));
let genesis_result =
tranquil_pds::plc::create_genesis_operation(signing_key, &rotation_key, handle, &pds_endpoint)
.map_err(|e| {
tracing::error!("Error creating PLC genesis operation: {:?}", e);
ApiError::InternalError(Some("Failed to create PLC operation".into()))
})?;
let genesis_result = tranquil_pds::plc::create_genesis_operation(
signing_key,
&rotation_key,
handle,
&pds_endpoint,
)
.map_err(|e| {
tracing::error!("Error creating PLC genesis operation: {:?}", e);
ApiError::InternalError(Some("Failed to create PLC operation".into()))
})?;
state
.plc_client()
@@ -84,10 +88,11 @@ pub async fn init_genesis_repo(
signing_key: &SigningKey,
signing_key_bytes: &[u8],
) -> Result<GenesisRepo, ApiError> {
let encrypted_key_bytes = tranquil_pds::config::encrypt_key(signing_key_bytes).map_err(|e| {
tracing::error!("Error encrypting signing key: {:?}", e);
ApiError::InternalError(None)
})?;
let encrypted_key_bytes =
tranquil_pds::config::encrypt_key(signing_key_bytes).map_err(|e| {
tracing::error!("Error encrypting signing key: {:?}", e);
ApiError::InternalError(None)
})?;
let mst = Mst::new(Arc::new(state.block_store.clone()));
let mst_root = mst.persist().await.map_err(|e| {
+304 -109
View File
@@ -1,7 +1,6 @@
pub mod actor;
pub mod admin;
pub mod age_assurance;
pub mod backup;
pub mod delegation;
pub mod discord_webhook;
pub mod identity;
@@ -32,10 +31,7 @@ pub fn api_routes() -> axum::Router<AppState> {
"/com.atproto.server.createSession",
post(server::create_session),
)
.route(
"/com.atproto.server.getSession",
get(server::get_session),
)
.route("/com.atproto.server.getSession", get(server::get_session))
.route("/_account.listSessions", get(server::list_sessions))
.route("/_account.revokeSession", post(server::revoke_session))
.route(
@@ -66,29 +62,14 @@ pub fn api_routes() -> axum::Router<AppState> {
"/com.atproto.identity.resolveHandle",
get(identity::resolve_handle),
)
.route(
"/com.atproto.repo.createRecord",
post(repo::create_record),
)
.route("/com.atproto.repo.createRecord", post(repo::create_record))
.route("/com.atproto.repo.putRecord", post(repo::put_record))
.route("/com.atproto.repo.getRecord", get(repo::get_record))
.route(
"/com.atproto.repo.deleteRecord",
post(repo::delete_record),
)
.route(
"/com.atproto.repo.listRecords",
get(repo::list_records),
)
.route(
"/com.atproto.repo.describeRepo",
get(repo::describe_repo),
)
.route("/com.atproto.repo.deleteRecord", post(repo::delete_record))
.route("/com.atproto.repo.listRecords", get(repo::list_records))
.route("/com.atproto.repo.describeRepo", get(repo::describe_repo))
.route("/com.atproto.repo.uploadBlob", post(repo::upload_blob))
.route(
"/com.atproto.repo.applyWrites",
post(repo::apply_writes),
)
.route("/com.atproto.repo.applyWrites", post(repo::apply_writes))
.route(
"/com.atproto.server.checkAccountStatus",
get(server::check_account_status),
@@ -144,99 +125,315 @@ pub fn api_routes() -> axum::Router<AppState> {
.route("/_account.changePassword", post(server::change_password))
.route("/_account.removePassword", post(server::remove_password))
.route("/_account.setPassword", post(server::set_password))
.route("/_account.getPasswordStatus", get(server::get_password_status))
.route(
"/_account.getPasswordStatus",
get(server::get_password_status),
)
.route("/_account.getReauthStatus", get(server::get_reauth_status))
.route("/_account.reauthPassword", post(server::reauth_password))
.route("/_account.reauthTotp", post(server::reauth_totp))
.route("/_account.reauthPasskeyStart", post(server::reauth_passkey_start))
.route("/_account.reauthPasskeyFinish", post(server::reauth_passkey_finish))
.route("/_account.getLegacyLoginPreference", get(server::get_legacy_login_preference))
.route("/_account.updateLegacyLoginPreference", post(server::update_legacy_login_preference))
.route(
"/_account.reauthPasskeyStart",
post(server::reauth_passkey_start),
)
.route(
"/_account.reauthPasskeyFinish",
post(server::reauth_passkey_finish),
)
.route(
"/_account.getLegacyLoginPreference",
get(server::get_legacy_login_preference),
)
.route(
"/_account.updateLegacyLoginPreference",
post(server::update_legacy_login_preference),
)
.route("/_account.updateLocale", post(server::update_locale))
.route("/_account.listTrustedDevices", get(server::list_trusted_devices))
.route("/_account.revokeTrustedDevice", post(server::revoke_trusted_device))
.route("/_account.updateTrustedDevice", post(server::update_trusted_device))
.route("/_account.createPasskeyAccount", post(server::create_passkey_account))
.route("/_account.startPasskeyRegistrationForSetup", post(server::start_passkey_registration_for_setup))
.route("/_account.completePasskeySetup", post(server::complete_passkey_setup))
.route("/_account.requestPasskeyRecovery", post(server::request_passkey_recovery))
.route("/_account.recoverPasskeyAccount", post(server::recover_passkey_account))
.route("/_account.updateDidDocument", post(server::update_did_document))
.route(
"/_account.listTrustedDevices",
get(server::list_trusted_devices),
)
.route(
"/_account.revokeTrustedDevice",
post(server::revoke_trusted_device),
)
.route(
"/_account.updateTrustedDevice",
post(server::update_trusted_device),
)
.route(
"/_account.createPasskeyAccount",
post(server::create_passkey_account),
)
.route(
"/_account.startPasskeyRegistrationForSetup",
post(server::start_passkey_registration_for_setup),
)
.route(
"/_account.completePasskeySetup",
post(server::complete_passkey_setup),
)
.route(
"/_account.requestPasskeyRecovery",
post(server::request_passkey_recovery),
)
.route(
"/_account.recoverPasskeyAccount",
post(server::recover_passkey_account),
)
.route(
"/_account.updateDidDocument",
post(server::update_did_document),
)
.route("/_account.getDidDocument", get(server::get_did_document))
.route("/com.atproto.server.requestEmailUpdate", post(server::request_email_update))
.route(
"/com.atproto.server.requestEmailUpdate",
post(server::request_email_update),
)
.route("/_checkEmailVerified", post(server::check_email_verified))
.route("/_checkChannelVerified", post(server::check_channel_verified))
.route("/com.atproto.server.confirmEmail", post(server::confirm_email))
.route("/com.atproto.server.updateEmail", post(server::update_email))
.route("/_account.authorizeEmailUpdate", get(server::authorize_email_update))
.route("/_account.checkEmailUpdateStatus", get(server::check_email_update_status))
.route("/_account.checkEmailInUse", post(server::check_email_in_use))
.route("/_account.checkCommsChannelInUse", post(server::check_comms_channel_in_use))
.route("/com.atproto.server.reserveSigningKey", post(server::reserve_signing_key))
.route("/com.atproto.server.verifyMigrationEmail", post(server::verify_migration_email))
.route("/com.atproto.server.resendMigrationVerification", post(server::resend_migration_verification))
.route("/com.atproto.identity.updateHandle", post(identity::update_handle))
.route("/com.atproto.identity.requestPlcOperationSignature", post(identity::request_plc_operation_signature))
.route("/com.atproto.identity.signPlcOperation", post(identity::sign_plc_operation))
.route("/com.atproto.identity.submitPlcOperation", post(identity::submit_plc_operation))
.route("/_identity.verifyHandleOwnership", post(identity::verify_handle_ownership))
.route(
"/_checkChannelVerified",
post(server::check_channel_verified),
)
.route(
"/com.atproto.server.confirmEmail",
post(server::confirm_email),
)
.route(
"/com.atproto.server.updateEmail",
post(server::update_email),
)
.route(
"/_account.authorizeEmailUpdate",
get(server::authorize_email_update),
)
.route(
"/_account.checkEmailUpdateStatus",
get(server::check_email_update_status),
)
.route(
"/_account.checkEmailInUse",
post(server::check_email_in_use),
)
.route(
"/_account.checkCommsChannelInUse",
post(server::check_comms_channel_in_use),
)
.route(
"/com.atproto.server.reserveSigningKey",
post(server::reserve_signing_key),
)
.route(
"/com.atproto.server.verifyMigrationEmail",
post(server::verify_migration_email),
)
.route(
"/com.atproto.server.resendMigrationVerification",
post(server::resend_migration_verification),
)
.route(
"/com.atproto.identity.updateHandle",
post(identity::update_handle),
)
.route(
"/com.atproto.identity.requestPlcOperationSignature",
post(identity::request_plc_operation_signature),
)
.route(
"/com.atproto.identity.signPlcOperation",
post(identity::sign_plc_operation),
)
.route(
"/com.atproto.identity.submitPlcOperation",
post(identity::submit_plc_operation),
)
.route(
"/_identity.verifyHandleOwnership",
post(identity::verify_handle_ownership),
)
.route("/com.atproto.repo.importRepo", post(repo::import_repo))
.route("/com.atproto.admin.deleteAccount", post(admin::delete_account))
.route("/com.atproto.admin.updateAccountEmail", post(admin::update_account_email))
.route("/com.atproto.admin.updateAccountHandle", post(admin::update_account_handle))
.route("/com.atproto.admin.updateAccountPassword", post(admin::update_account_password))
.route("/com.atproto.server.listAppPasswords", get(server::list_app_passwords))
.route("/com.atproto.server.createAppPassword", post(server::create_app_password))
.route("/com.atproto.server.revokeAppPassword", post(server::revoke_app_password))
.route("/com.atproto.server.createInviteCode", post(server::create_invite_code))
.route("/com.atproto.server.createInviteCodes", post(server::create_invite_codes))
.route("/com.atproto.server.getAccountInviteCodes", get(server::get_account_invite_codes))
.route("/com.atproto.server.createTotpSecret", post(server::create_totp_secret))
.route(
"/com.atproto.admin.deleteAccount",
post(admin::delete_account),
)
.route(
"/com.atproto.admin.updateAccountEmail",
post(admin::update_account_email),
)
.route(
"/com.atproto.admin.updateAccountHandle",
post(admin::update_account_handle),
)
.route(
"/com.atproto.admin.updateAccountPassword",
post(admin::update_account_password),
)
.route(
"/com.atproto.server.listAppPasswords",
get(server::list_app_passwords),
)
.route(
"/com.atproto.server.createAppPassword",
post(server::create_app_password),
)
.route(
"/com.atproto.server.revokeAppPassword",
post(server::revoke_app_password),
)
.route(
"/com.atproto.server.createInviteCode",
post(server::create_invite_code),
)
.route(
"/com.atproto.server.createInviteCodes",
post(server::create_invite_codes),
)
.route(
"/com.atproto.server.getAccountInviteCodes",
get(server::get_account_invite_codes),
)
.route(
"/com.atproto.server.createTotpSecret",
post(server::create_totp_secret),
)
.route("/com.atproto.server.enableTotp", post(server::enable_totp))
.route("/com.atproto.server.disableTotp", post(server::disable_totp))
.route("/com.atproto.server.getTotpStatus", get(server::get_totp_status))
.route("/com.atproto.server.regenerateBackupCodes", post(server::regenerate_backup_codes))
.route("/com.atproto.server.startPasskeyRegistration", post(server::start_passkey_registration))
.route("/com.atproto.server.finishPasskeyRegistration", post(server::finish_passkey_registration))
.route("/com.atproto.server.listPasskeys", get(server::list_passkeys))
.route("/com.atproto.server.deletePasskey", post(server::delete_passkey))
.route("/com.atproto.server.updatePasskey", post(server::update_passkey))
.route("/com.atproto.admin.getInviteCodes", get(admin::get_invite_codes))
.route(
"/com.atproto.server.disableTotp",
post(server::disable_totp),
)
.route(
"/com.atproto.server.getTotpStatus",
get(server::get_totp_status),
)
.route(
"/com.atproto.server.regenerateBackupCodes",
post(server::regenerate_backup_codes),
)
.route(
"/com.atproto.server.startPasskeyRegistration",
post(server::start_passkey_registration),
)
.route(
"/com.atproto.server.finishPasskeyRegistration",
post(server::finish_passkey_registration),
)
.route(
"/com.atproto.server.listPasskeys",
get(server::list_passkeys),
)
.route(
"/com.atproto.server.deletePasskey",
post(server::delete_passkey),
)
.route(
"/com.atproto.server.updatePasskey",
post(server::update_passkey),
)
.route(
"/com.atproto.admin.getInviteCodes",
get(admin::get_invite_codes),
)
.route("/_admin.getServerStats", get(admin::get_server_stats))
.route("/_server.getConfig", get(admin::get_server_config))
.route("/_admin.updateServerConfig", post(admin::update_server_config))
.route("/com.atproto.admin.disableAccountInvites", post(admin::disable_account_invites))
.route("/com.atproto.admin.enableAccountInvites", post(admin::enable_account_invites))
.route("/com.atproto.admin.disableInviteCodes", post(admin::disable_invite_codes))
.route("/com.atproto.admin.getSubjectStatus", get(admin::get_subject_status))
.route("/com.atproto.admin.updateSubjectStatus", post(admin::update_subject_status))
.route(
"/_admin.updateServerConfig",
post(admin::update_server_config),
)
.route(
"/com.atproto.admin.disableAccountInvites",
post(admin::disable_account_invites),
)
.route(
"/com.atproto.admin.enableAccountInvites",
post(admin::enable_account_invites),
)
.route(
"/com.atproto.admin.disableInviteCodes",
post(admin::disable_invite_codes),
)
.route(
"/com.atproto.admin.getSubjectStatus",
get(admin::get_subject_status),
)
.route(
"/com.atproto.admin.updateSubjectStatus",
post(admin::update_subject_status),
)
.route("/com.atproto.admin.sendEmail", post(admin::send_email))
.route("/app.bsky.actor.getPreferences", get(actor::get_preferences))
.route("/app.bsky.actor.putPreferences", post(actor::put_preferences))
.route("/com.atproto.temp.checkSignupQueue", get(temp::check_signup_queue))
.route("/com.atproto.temp.dereferenceScope", post(temp::dereference_scope))
.route("/_account.getNotificationPrefs", get(notification_prefs::get_notification_prefs))
.route("/_account.updateNotificationPrefs", post(notification_prefs::update_notification_prefs))
.route("/_account.getNotificationHistory", get(notification_prefs::get_notification_history))
.route("/_account.confirmChannelVerification", post(verification::confirm_channel_verification))
.route(
"/app.bsky.actor.getPreferences",
get(actor::get_preferences),
)
.route(
"/app.bsky.actor.putPreferences",
post(actor::put_preferences),
)
.route(
"/com.atproto.temp.checkSignupQueue",
get(temp::check_signup_queue),
)
.route(
"/com.atproto.temp.dereferenceScope",
post(temp::dereference_scope),
)
.route(
"/_account.getNotificationPrefs",
get(notification_prefs::get_notification_prefs),
)
.route(
"/_account.updateNotificationPrefs",
post(notification_prefs::update_notification_prefs),
)
.route(
"/_account.getNotificationHistory",
get(notification_prefs::get_notification_history),
)
.route(
"/_account.confirmChannelVerification",
post(verification::confirm_channel_verification),
)
.route("/_account.verifyToken", post(server::verify_token))
.route("/_delegation.listControllers", get(delegation::list_controllers))
.route("/_delegation.addController", post(delegation::add_controller))
.route("/_delegation.removeController", post(delegation::remove_controller))
.route("/_delegation.updateControllerScopes", post(delegation::update_controller_scopes))
.route("/_delegation.listControlledAccounts", get(delegation::list_controlled_accounts))
.route(
"/_delegation.listControllers",
get(delegation::list_controllers),
)
.route(
"/_delegation.addController",
post(delegation::add_controller),
)
.route(
"/_delegation.removeController",
post(delegation::remove_controller),
)
.route(
"/_delegation.updateControllerScopes",
post(delegation::update_controller_scopes),
)
.route(
"/_delegation.listControlledAccounts",
get(delegation::list_controlled_accounts),
)
.route("/_delegation.getAuditLog", get(delegation::get_audit_log))
.route("/_delegation.getScopePresets", get(delegation::get_scope_presets))
.route("/_delegation.createDelegatedAccount", post(delegation::create_delegated_account))
.route("/_delegation.resolveController", get(delegation::resolve_controller))
.route("/_backup.listBackups", get(backup::list_backups))
.route("/_backup.getBackup", get(backup::get_backup))
.route("/_backup.createBackup", post(backup::create_backup))
.route("/_backup.deleteBackup", post(backup::delete_backup))
.route("/_backup.setEnabled", post(backup::set_backup_enabled))
.route("/_backup.exportBlobs", get(backup::export_blobs))
.route("/app.bsky.ageassurance.getState", get(age_assurance::get_state))
.route("/app.bsky.unspecced.getAgeAssuranceState", get(age_assurance::get_age_assurance_state))
.route(
"/_delegation.getScopePresets",
get(delegation::get_scope_presets),
)
.route(
"/_delegation.createDelegatedAccount",
post(delegation::create_delegated_account),
)
.route(
"/_delegation.resolveController",
get(delegation::resolve_controller),
)
.route(
"/app.bsky.ageassurance.getState",
get(age_assurance::get_state),
)
.route(
"/app.bsky.unspecced.getAgeAssuranceState",
get(age_assurance::get_age_assurance_state),
)
}
pub fn well_known_api_routes() -> axum::Router<AppState> {
@@ -253,13 +450,11 @@ pub fn webhook_routes() -> axum::Router<AppState> {
axum::Router::new()
.route(
"/webhook/telegram",
post(telegram_webhook::handle_telegram_webhook)
.layer(DefaultBodyLimit::max(64 * 1024)),
post(telegram_webhook::handle_telegram_webhook).layer(DefaultBodyLimit::max(64 * 1024)),
)
.route(
"/webhook/discord",
post(discord_webhook::handle_discord_webhook)
.layer(DefaultBodyLimit::max(64 * 1024)),
post(discord_webhook::handle_discord_webhook).layer(DefaultBodyLimit::max(64 * 1024)),
)
}
+4 -4
View File
@@ -1,7 +1,3 @@
use tranquil_pds::api::ApiError;
use tranquil_pds::api::proxy_client::{is_ssrf_safe, proxy_client};
use tranquil_pds::auth::{AnyUser, Auth};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -11,6 +7,10 @@ use axum::{
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use tracing::{error, info};
use tranquil_pds::api::ApiError;
use tranquil_pds::api::proxy_client::{is_ssrf_safe, proxy_client};
use tranquil_pds::auth::{AnyUser, Auth};
use tranquil_pds::state::AppState;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ReportReasonType {
@@ -1,6 +1,3 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Active, Auth};
use tranquil_pds::state::AppState;
use axum::{
Json,
extract::State,
@@ -10,6 +7,9 @@ use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::info;
use tranquil_db_traits::{CommsChannel, CommsStatus, CommsType};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::auth::{Active, Auth};
use tranquil_pds::state::AppState;
use tranquil_types::Did;
#[derive(Serialize)]
@@ -141,8 +141,9 @@ pub async fn request_channel_verification(
identifier: &str,
handle: Option<&str>,
) -> Result<String, ApiError> {
let token =
tranquil_pds::auth::verification_token::generate_channel_update_token(did, channel, identifier);
let token = tranquil_pds::auth::verification_token::generate_channel_update_token(
did, channel, identifier,
);
let formatted_token = tranquil_pds::auth::verification_token::format_token_for_display(&token);
match channel {
+6 -6
View File
@@ -1,9 +1,3 @@
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Auth, AuthAny, NotTakendown, Permissive, VerifyScope};
use tranquil_pds::delegation::DelegationActionType;
use tranquil_pds::state::AppState;
use tranquil_pds::types::{CidLink, Did};
use tranquil_pds::util::get_header_str;
use axum::body::Body;
use axum::{
Json,
@@ -19,6 +13,12 @@ use serde::{Deserialize, Serialize};
use serde_json::json;
use std::pin::Pin;
use tracing::{debug, error, info, warn};
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Auth, AuthAny, NotTakendown, Permissive, VerifyScope};
use tranquil_pds::delegation::DelegationActionType;
use tranquil_pds::state::AppState;
use tranquil_pds::types::{CidLink, Did};
use tranquil_pds::util::get_header_str;
fn detect_mime_type(data: &[u8], client_hint: &str) -> String {
if let Some(kind) = infer::get(data) {
+11 -11
View File
@@ -1,11 +1,3 @@
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::repo_ops::create_signed_commit;
use tranquil_pds::auth::{Auth, NotTakendown};
use tranquil_pds::state::AppState;
use tranquil_pds::sync::import::{ImportError, apply_import, parse_car};
use tranquil_pds::sync::verify::CarVerifier;
use tranquil_pds::types::Did;
use axum::{
body::Bytes,
extract::State,
@@ -16,6 +8,14 @@ use jacquard_repo::storage::BlockStore;
use k256::ecdsa::SigningKey;
use serde_json::json;
use tracing::{debug, error, info, warn};
use tranquil_pds::api::EmptyResponse;
use tranquil_pds::api::error::{ApiError, DbResultExt};
use tranquil_pds::auth::{Auth, NotTakendown};
use tranquil_pds::repo_ops::create_signed_commit;
use tranquil_pds::state::AppState;
use tranquil_pds::sync::import::{ImportError, apply_import, parse_car};
use tranquil_pds::sync::verify::CarVerifier;
use tranquil_pds::types::Did;
use tranquil_types::{AtUri, CidLink};
pub async fn import_repo(
@@ -266,9 +266,9 @@ pub async fn import_repo(
let key_bytes =
tranquil_pds::config::decrypt_key(&key_row.key_bytes, key_row.encryption_version)
.map_err(|e| {
error!("Failed to decrypt signing key: {}", e);
ApiError::InternalError(None)
})?;
error!("Failed to decrypt signing key: {}", e);
ApiError::InternalError(None)
})?;
let signing_key = SigningKey::from_slice(&key_bytes).map_err(|e| {
error!("Invalid signing key: {:?}", e);
ApiError::InternalError(None)
+3 -3
View File
@@ -1,6 +1,3 @@
use tranquil_pds::api::error::ApiError;
use tranquil_pds::state::AppState;
use tranquil_pds::types::AtIdentifier;
use axum::{
Json,
extract::{Query, State},
@@ -8,6 +5,9 @@ use axum::{
};
use serde::Deserialize;
use serde_json::json;
use tranquil_pds::api::error::ApiError;
use tranquil_pds::state::AppState;
use tranquil_pds::types::AtIdentifier;
#[derive(Deserialize)]
pub struct DescribeRepoInput {

Some files were not shown because too many files have changed in this diff Show More