Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3332847
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/keyserver/src/updaters/account-updaters.js b/keyserver/src/updaters/account-updaters.js
index 195f17200..5d2578585 100644
--- a/keyserver/src/updaters/account-updaters.js
+++ b/keyserver/src/updaters/account-updaters.js
@@ -1,253 +1,255 @@
// @flow
import invariant from 'invariant';
import bcrypt from 'twin-bcrypt';
import { hasMinCodeVersion } from 'lib/shared/version-utils.js';
import type {
ResetPasswordRequest,
UpdatePasswordRequest,
UpdateUserSettingsRequest,
ServerLogInResponse,
} from 'lib/types/account-types.js';
import type {
ClientAvatar,
UpdateUserAvatarRequest,
UpdateUserAvatarResponse,
} from 'lib/types/avatar-types.js';
import { updateTypes } from 'lib/types/update-types-enum.js';
import type {
CreateUpdatesResult,
UpdateData,
} from 'lib/types/update-types.js';
import type {
PasswordUpdate,
UserInfo,
UserInfos,
} from 'lib/types/user-types.js';
import { ServerError } from 'lib/utils/errors.js';
import { values } from 'lib/utils/objects.js';
import { createUpdates } from '../creators/update-creator.js';
import { dbQuery, SQL } from '../database/database.js';
import { getUploadURL, makeUploadURI } from '../fetchers/upload-fetchers.js';
import { fetchKnownUserInfos } from '../fetchers/user-fetchers.js';
import type { Viewer } from '../session/viewer.js';
async function passwordUpdater(
viewer: Viewer,
update: PasswordUpdate,
): Promise<void> {
if (!viewer.loggedIn) {
throw new ServerError('not_logged_in');
}
const newPassword = update.updatedFields.password;
if (!newPassword) {
// If it's an old client it may have given us an email,
// but we don't store those anymore
return;
}
const verifyQuery = SQL`
SELECT username, hash FROM users WHERE id = ${viewer.userID}
`;
const [verifyResult] = await dbQuery(verifyQuery);
if (verifyResult.length === 0) {
throw new ServerError('internal_error');
}
const verifyRow = verifyResult[0];
if (!bcrypt.compareSync(update.currentPassword, verifyRow.hash)) {
throw new ServerError('invalid_credentials');
}
const changedFields = { hash: bcrypt.hashSync(newPassword) };
const saveQuery = SQL`
UPDATE users SET ${changedFields} WHERE id = ${viewer.userID}
`;
await dbQuery(saveQuery);
}
// eslint-disable-next-line no-unused-vars
async function checkAndSendVerificationEmail(viewer: Viewer): Promise<void> {
// We don't want to crash old clients that call this,
// but we have nothing we can do because we no longer store email addresses
}
async function checkAndSendPasswordResetEmail(
// eslint-disable-next-line no-unused-vars
request: ResetPasswordRequest,
): Promise<void> {
// We don't want to crash old clients that call this,
// but we have nothing we can do because we no longer store email addresses
}
/* eslint-disable no-unused-vars */
async function updatePassword(
viewer: Viewer,
request: UpdatePasswordRequest,
): Promise<ServerLogInResponse> {
/* eslint-enable no-unused-vars */
// We have no way to handle this request anymore
throw new ServerError('deprecated');
}
async function updateUserSettings(
viewer: Viewer,
request: UpdateUserSettingsRequest,
) {
if (!viewer.loggedIn) {
throw new ServerError('not_logged_in');
}
const createOrUpdateSettingsQuery = SQL`
INSERT INTO settings (user, name, data)
VALUES ${[[viewer.id, request.name, request.data]]}
ON DUPLICATE KEY UPDATE data = VALUE(data)
`;
await dbQuery(createOrUpdateSettingsQuery);
}
async function updateUserAvatar(
viewer: Viewer,
request: UpdateUserAvatarRequest,
): Promise<?ClientAvatar | UpdateUserAvatarResponse> {
if (!viewer.loggedIn) {
throw new ServerError('not_logged_in');
}
const newAvatarValue =
request.type === 'remove' ? null : JSON.stringify(request);
const mediaID =
request.type === 'image' || request.type === 'encrypted_image'
? request.uploadID
: null;
const query = SQL`
START TRANSACTION;
UPDATE uploads
- SET container = NULL
+ SET user_container = NULL
WHERE uploader = ${viewer.userID}
- AND container = ${viewer.userID}
+ AND user_container = ${viewer.userID}
AND (
${mediaID} IS NULL
OR EXISTS (
SELECT 1
FROM uploads
WHERE id = ${mediaID}
AND uploader = ${viewer.userID}
AND container IS NULL
+ AND user_container IS NULL
AND thread IS NULL
)
);
UPDATE uploads
- SET container = ${viewer.userID}
+ SET user_container = ${viewer.userID}
WHERE id = ${mediaID}
AND uploader = ${viewer.userID}
AND container IS NULL
+ AND user_container IS NULL
AND thread IS NULL;
UPDATE users
SET avatar = ${newAvatarValue}
WHERE id = ${viewer.userID}
AND (
${mediaID} IS NULL
OR EXISTS (
SELECT 1
FROM uploads
WHERE id = ${mediaID}
AND uploader = ${viewer.userID}
- AND container = ${viewer.userID}
+ AND user_container = ${viewer.userID}
AND thread IS NULL
)
);
COMMIT;
SELECT id AS upload_id, secret AS upload_secret, extra AS upload_extra
FROM uploads
WHERE id = ${mediaID}
AND uploader = ${viewer.userID}
- AND container = ${viewer.userID};
+ AND user_container = ${viewer.userID};
`;
const [resultSet] = await dbQuery(query, { multipleStatements: true });
const selectResult = resultSet.pop();
const knownUserInfos: UserInfos = await fetchKnownUserInfos(viewer);
const updates: CreateUpdatesResult = await createUserAvatarUpdates(
viewer,
knownUserInfos,
);
if (hasMinCodeVersion(viewer.platformDetails, { native: 215 })) {
const updateUserAvatarResponse: UpdateUserAvatarResponse = {
updates,
};
return updateUserAvatarResponse;
}
if (request.type === 'remove') {
return null;
} else if (request.type !== 'image' && request.type !== 'encrypted_image') {
return request;
} else {
const [{ upload_id, upload_secret, upload_extra }] = selectResult;
const uploadID = upload_id.toString();
invariant(
uploadID === request.uploadID,
'uploadID of upload should match uploadID of UpdateUserAvatarRequest',
);
if (request.type === 'encrypted_image') {
const uploadExtra = JSON.parse(upload_extra);
return {
type: 'encrypted_image',
blobURI: makeUploadURI(uploadExtra.blobHash, uploadID, upload_secret),
encryptionKey: uploadExtra.encryptionKey,
thumbHash: uploadExtra.thumbHash,
};
}
return {
type: 'image',
uri: getUploadURL(uploadID, upload_secret),
};
}
}
async function createUserAvatarUpdates(
viewer: Viewer,
knownUserInfos: UserInfos,
): Promise<CreateUpdatesResult> {
const time = Date.now();
const userUpdates: $ReadOnlyArray<UpdateData> = values(knownUserInfos).map(
(user: UserInfo): UpdateData => ({
type: updateTypes.UPDATE_USER,
userID: user.id,
time,
updatedUserID: viewer.userID,
}),
);
const currentUserUpdate: UpdateData = {
type: updateTypes.UPDATE_CURRENT_USER,
userID: viewer.userID,
time,
};
return await createUpdates([...userUpdates, currentUserUpdate], {
viewer,
updatesForCurrentSession: 'return',
});
}
export {
passwordUpdater,
checkAndSendVerificationEmail,
checkAndSendPasswordResetEmail,
updateUserSettings,
updatePassword,
updateUserAvatar,
};
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 2:20 AM (23 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2559368
Default Alt Text
(7 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment