diff --git a/keyserver/src/deleters/account-deleters.js b/keyserver/src/deleters/account-deleters.js index d6c8a8c72..6a869dd3f 100644 --- a/keyserver/src/deleters/account-deleters.js +++ b/keyserver/src/deleters/account-deleters.js @@ -1,152 +1,152 @@ // @flow import { getRustAPI } from 'rust-node-addon'; import type { LogOutResponse } from 'lib/types/account-types.js'; import type { ReservedUsernameMessage } from 'lib/types/crypto-types.js'; import { updateTypes } from 'lib/types/update-types-enum.js'; import type { UserInfo } from 'lib/types/user-types.js'; import { ServerError } from 'lib/utils/errors.js'; import { values } from 'lib/utils/objects.js'; import { promiseAll, ignorePromiseRejections } from 'lib/utils/promises.js'; import { createUpdates } from '../creators/update-creator.js'; import { dbQuery, SQL } from '../database/database.js'; import { fetchKnownUserInfos, fetchUsername, } from '../fetchers/user-fetchers.js'; import { rescindPushNotifs } from '../push/rescind.js'; import { createNewAnonymousCookie } from '../session/cookies.js'; import type { Viewer, AnonymousViewerData } from '../session/viewer.js'; import { fetchOlmAccount } from '../updaters/olm-account-updater.js'; async function deleteAccount(viewer: Viewer): Promise { if (!viewer.loggedIn) { throw new ServerError('not_logged_in'); } const deletedUserID = viewer.userID; await rescindPushNotifs(SQL`n.user = ${deletedUserID}`, SQL`NULL`); const knownUserInfos = await fetchKnownUserInfos(viewer); const usersToUpdate: $ReadOnlyArray = values(knownUserInfos).filter( (user: UserInfo): boolean => user.id !== deletedUserID, ); // TODO: if this results in any orphaned orgs, convert them to chats const deletionQuery = SQL` START TRANSACTION; DELETE FROM users WHERE id = ${deletedUserID}; DELETE FROM ids WHERE id = ${deletedUserID}; DELETE c, i FROM cookies c LEFT JOIN ids i ON i.id = c.id WHERE c.user = ${deletedUserID}; DELETE FROM memberships WHERE user = ${deletedUserID}; DELETE FROM focused WHERE user = ${deletedUserID}; DELETE n, i FROM notifications n LEFT JOIN ids i ON i.id = n.id WHERE n.user = ${deletedUserID}; DELETE u, i FROM updates u LEFT JOIN ids i ON i.id = u.id WHERE u.user = ${deletedUserID}; DELETE s, i FROM sessions s LEFT JOIN ids i ON i.id = s.id WHERE s.user = ${deletedUserID}; DELETE r, i FROM reports r LEFT JOIN ids i ON i.id = r.id WHERE r.user = ${deletedUserID}; DELETE u, i FROM uploads u LEFT JOIN ids i on i.id = u.id - WHERE u.container = ${deletedUserID}; + WHERE u.user_container = ${deletedUserID}; DELETE FROM relationships_undirected WHERE user1 = ${deletedUserID}; DELETE FROM relationships_undirected WHERE user2 = ${deletedUserID}; DELETE FROM relationships_directed WHERE user1 = ${deletedUserID}; DELETE FROM relationships_directed WHERE user2 = ${deletedUserID}; COMMIT; `; const deletionPromise = dbQuery(deletionQuery, { multipleStatements: true }); const anonymousViewerDataPromise: Promise = (async () => { if (viewer.isScriptViewer) { return undefined; } return await createNewAnonymousCookie({ platformDetails: viewer.platformDetails, deviceToken: viewer.deviceToken, }); })(); const usernamePromise = fetchUsername(deletedUserID); const { anonymousViewerData, username } = await promiseAll({ anonymousViewerData: anonymousViewerDataPromise, username: usernamePromise, deletion: deletionPromise, }); if (username) { const issuedAt = new Date().toISOString(); const reservedUsernameMessage: ReservedUsernameMessage = { statement: 'Remove the following username from reserved list', payload: username, issuedAt, }; const message = JSON.stringify(reservedUsernameMessage); ignorePromiseRejections( (async () => { const rustAPI = await getRustAPI(); const accountInfo = await fetchOlmAccount('content'); const signature = accountInfo.account.sign(message); await rustAPI.removeReservedUsername(message, signature); })(), ); } if (anonymousViewerData) { viewer.setNewCookie(anonymousViewerData); } const deletionUpdatesPromise = createAccountDeletionUpdates( usersToUpdate, deletedUserID, ); if (viewer.isScriptViewer) { await deletionUpdatesPromise; } else { ignorePromiseRejections(deletionUpdatesPromise); } if (viewer.isScriptViewer) { return null; } return { currentUserInfo: { anonymous: true, }, }; } async function createAccountDeletionUpdates( knownUserInfos: $ReadOnlyArray, deletedUserID: string, ): Promise { const time = Date.now(); const updateDatas = []; for (const userInfo of knownUserInfos) { const { id: userID } = userInfo; updateDatas.push({ type: updateTypes.DELETE_ACCOUNT, userID, time, deletedUserID, }); } await createUpdates(updateDatas); } export { deleteAccount }; diff --git a/keyserver/src/deleters/upload-deleters.js b/keyserver/src/deleters/upload-deleters.js index 0625cb1a4..4f44ed1d2 100644 --- a/keyserver/src/deleters/upload-deleters.js +++ b/keyserver/src/deleters/upload-deleters.js @@ -1,51 +1,56 @@ // @flow import { ServerError } from 'lib/utils/errors.js'; import { dbQuery, SQL } from '../database/database.js'; import type { Viewer } from '../session/viewer.js'; async function deleteUpload(viewer: Viewer, id: string): Promise { if (!viewer.loggedIn) { throw new ServerError('not_logged_in'); } const fetchQuery = SQL` - SELECT uploader, container + SELECT uploader, container, user_container AS userContainer FROM uploads WHERE id = ${id} `; const [result] = await dbQuery(fetchQuery); if (result.length === 0) { throw new ServerError('invalid_parameters'); } const [row] = result; - const { uploader, container } = row; + const { uploader, container, userContainer } = row; - if (uploader.toString() !== viewer.userID || container !== null) { + if ( + uploader.toString() !== viewer.userID || + container !== null || + userContainer !== null + ) { throw new ServerError('invalid_parameters'); } const deleteQuery = SQL` DELETE u, i FROM uploads u LEFT JOIN ids i ON i.id = u.id WHERE u.id = ${id} `; await dbQuery(deleteQuery); } const maxUnassignedUploadAge = 24 * 60 * 60 * 1000; async function deleteUnassignedUploads(): Promise { const oldestUnassignedUploadToKeep = Date.now() - maxUnassignedUploadAge; await dbQuery(SQL` DELETE u, i FROM uploads u LEFT JOIN ids i ON i.id = u.id WHERE u.container IS NULL + AND u.user_container IS NULL AND creation_time < ${oldestUnassignedUploadToKeep} `); } export { deleteUpload, deleteUnassignedUploads };