diff --git a/keyserver/src/creators/account-creator.js b/keyserver/src/creators/account-creator.js --- a/keyserver/src/creators/account-creator.js +++ b/keyserver/src/creators/account-creator.js @@ -9,9 +9,10 @@ import { policyTypes } from 'lib/facts/policies.js'; import { validUsernameRegex } from 'lib/shared/account-utils.js'; import type { + UserIdentifier, RegisterResponse, RegisterRequest, -} from 'lib/types/account-types.js'; +} from 'lib/types/account-types'; import type { ReservedUsernameMessage, SignedIdentityKeysBlob, @@ -296,6 +297,95 @@ return id; } +export type ProcessOLMAccountCreationRequest = { + +userID: string, + +identifier: UserIdentifier, + +calendarQuery: CalendarQuery, + +deviceTokenUpdateRequest?: ?DeviceTokenUpdateRequest, + +platformDetails: PlatformDetails, + +signedIdentityKeysBlob: SignedIdentityKeysBlob, +}; +// Note: `processOLMAccountCreation(...)` assumes that the validity of +// `ProcessOLMAccountCreationRequest` was checked at call site. +async function processOLMAccountCreation( + viewer: Viewer, + request: ProcessOLMAccountCreationRequest, +): Promise { + const { calendarQuery, signedIdentityKeysBlob } = request; + await verifyCalendarQueryThreadIDs(calendarQuery); + + const time = Date.now(); + const deviceToken = request.deviceTokenUpdateRequest + ? request.deviceTokenUpdateRequest.deviceToken + : viewer.deviceToken; + const newUserRow = [ + request.userID, + request.identifier.username, + request.identifier.walletAddress, + time, + ]; + const newUserQuery = SQL` + INSERT INTO users(id, username, ethereum_address, creation_time) + VALUES ${[newUserRow]} + `; + const [userViewerData] = await Promise.all([ + createNewUserCookie(request.userID, { + platformDetails: request.platformDetails, + deviceToken, + signedIdentityKeysBlob, + }), + deleteCookie(viewer.cookieID), + dbQuery(newUserQuery), + ]); + viewer.setNewCookie(userViewerData); + + await setNewSession(viewer, calendarQuery, 0); + + await Promise.all([ + updateThread( + createScriptViewer(ashoat.id), + { + threadID: genesis.id, + changes: { newMemberIDs: [request.userID] }, + }, + { forceAddMembers: true, silenceMessages: true, ignorePermissions: true }, + ), + viewerAcknowledgmentUpdater(viewer, policyTypes.tosAndPrivacyPolicy), + ]); + + const [privateThreadResult, ashoatThreadResult] = await Promise.all([ + createPrivateThread(viewer), + createThread( + viewer, + { + type: threadTypes.PERSONAL, + initialMemberIDs: [ashoat.id], + }, + { forceAddMembers: true }, + ), + ]); + const ashoatThreadID = ashoatThreadResult.newThreadID; + const privateThreadID = privateThreadResult.newThreadID; + + let messageTime = Date.now(); + const ashoatMessageDatas = ashoatMessages.map(message => ({ + type: messageTypes.TEXT, + threadID: ashoatThreadID, + creatorID: ashoat.id, + time: messageTime++, + text: message, + })); + const privateMessageDatas = privateMessages.map(message => ({ + type: messageTypes.TEXT, + threadID: privateThreadID, + creatorID: commbot.userID, + time: messageTime++, + text: message, + })); + const messageDatas = [...ashoatMessageDatas, ...privateMessageDatas]; + await Promise.all([createMessages(viewer, messageDatas)]); +} + async function createAndSendReservedUsernameMessage( payload: $ReadOnlyArray, ) { @@ -316,4 +406,4 @@ await rustAPI.addReservedUsernames(stringifiedMessage, signature); } -export { createAccount, processSIWEAccountCreation }; +export { createAccount, processSIWEAccountCreation, processOLMAccountCreation }; diff --git a/lib/types/account-types.js b/lib/types/account-types.js --- a/lib/types/account-types.js +++ b/lib/types/account-types.js @@ -172,6 +172,11 @@ +notAcknowledgedPolicies?: $ReadOnlyArray, }; +export type UserIdentifier = { + +username: string, + +walletAddress?: ?string, +}; + type KeyserverRequestData = { +initialContentEncryptedMessage: string, +initialNotificationsEncryptedMessage: string,