Changeset View
Changeset View
Standalone View
Standalone View
keyserver/src/responders/user-responders.js
Show First 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | import { | ||||
newEntryQueryInputValidator, | newEntryQueryInputValidator, | ||||
normalizeCalendarQuery, | normalizeCalendarQuery, | ||||
verifyCalendarQueryThreadIDs, | verifyCalendarQueryThreadIDs, | ||||
} from './entry-responders.js'; | } from './entry-responders.js'; | ||||
import { | import { | ||||
createAccount, | createAccount, | ||||
processSIWEAccountCreation, | processSIWEAccountCreation, | ||||
} from '../creators/account-creator.js'; | } from '../creators/account-creator.js'; | ||||
import { createOlmSession } from '../creators/olm-session-creator.js'; | |||||
import { dbQuery, SQL } from '../database/database.js'; | import { dbQuery, SQL } from '../database/database.js'; | ||||
import { deleteAccount } from '../deleters/account-deleters.js'; | import { deleteAccount } from '../deleters/account-deleters.js'; | ||||
import { deleteCookie } from '../deleters/cookie-deleters.js'; | import { deleteCookie } from '../deleters/cookie-deleters.js'; | ||||
import { checkAndInvalidateSIWENonceEntry } from '../deleters/siwe-nonce-deleters.js'; | import { checkAndInvalidateSIWENonceEntry } from '../deleters/siwe-nonce-deleters.js'; | ||||
import { fetchEntryInfos } from '../fetchers/entry-fetchers.js'; | import { fetchEntryInfos } from '../fetchers/entry-fetchers.js'; | ||||
import { fetchMessageInfos } from '../fetchers/message-fetchers.js'; | import { fetchMessageInfos } from '../fetchers/message-fetchers.js'; | ||||
import { fetchNotAcknowledgedPolicies } from '../fetchers/policy-acknowledgment-fetchers.js'; | import { fetchNotAcknowledgedPolicies } from '../fetchers/policy-acknowledgment-fetchers.js'; | ||||
import { fetchThreadInfos } from '../fetchers/thread-fetchers.js'; | import { fetchThreadInfos } from '../fetchers/thread-fetchers.js'; | ||||
▲ Show 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | |||||
type ProcessSuccessfulLoginParams = { | type ProcessSuccessfulLoginParams = { | ||||
+viewer: Viewer, | +viewer: Viewer, | ||||
+input: any, | +input: any, | ||||
+userID: string, | +userID: string, | ||||
+calendarQuery: ?CalendarQuery, | +calendarQuery: ?CalendarQuery, | ||||
+socialProof?: ?SIWESocialProof, | +socialProof?: ?SIWESocialProof, | ||||
+signedIdentityKeysBlob?: ?SignedIdentityKeysBlob, | +signedIdentityKeysBlob?: ?SignedIdentityKeysBlob, | ||||
+initialNotificationsEncryptedMessage?: string, | |||||
}; | }; | ||||
async function processSuccessfulLogin( | async function processSuccessfulLogin( | ||||
params: ProcessSuccessfulLoginParams, | params: ProcessSuccessfulLoginParams, | ||||
): Promise<LogInResponse> { | ): Promise<LogInResponse> { | ||||
const { | const { | ||||
viewer, | viewer, | ||||
input, | input, | ||||
userID, | userID, | ||||
calendarQuery, | calendarQuery, | ||||
socialProof, | socialProof, | ||||
signedIdentityKeysBlob, | signedIdentityKeysBlob, | ||||
initialNotificationsEncryptedMessage, | |||||
} = params; | } = params; | ||||
const request: LogInRequest = input; | const request: LogInRequest = input; | ||||
const newServerTime = Date.now(); | const newServerTime = Date.now(); | ||||
const deviceToken = request.deviceTokenUpdateRequest | const deviceToken = request.deviceTokenUpdateRequest | ||||
? request.deviceTokenUpdateRequest.deviceToken | ? request.deviceTokenUpdateRequest.deviceToken | ||||
: viewer.deviceToken; | : viewer.deviceToken; | ||||
const [userViewerData, notAcknowledgedPolicies] = await Promise.all([ | const [userViewerData, notAcknowledgedPolicies] = await Promise.all([ | ||||
Show All 26 Lines | return { | ||||
userInfos: [], | userInfos: [], | ||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
if (calendarQuery) { | if (calendarQuery) { | ||||
await setNewSession(viewer, calendarQuery, newServerTime); | await setNewSession(viewer, calendarQuery, newServerTime); | ||||
} | } | ||||
const olmSessionPromise = (async () => { | |||||
if ( | |||||
userViewerData.cookieID && | |||||
initialNotificationsEncryptedMessage && | |||||
signedIdentityKeysBlob | |||||
) { | |||||
await createOlmSession( | |||||
initialNotificationsEncryptedMessage, | |||||
'notifications', | |||||
userViewerData.cookieID, | |||||
); | |||||
} | |||||
})(); | |||||
const threadCursors = {}; | const threadCursors = {}; | ||||
for (const watchedThreadID of request.watchedIDs) { | for (const watchedThreadID of request.watchedIDs) { | ||||
threadCursors[watchedThreadID] = null; | threadCursors[watchedThreadID] = null; | ||||
} | } | ||||
const messageSelectionCriteria = { threadCursors, joinedThreads: true }; | const messageSelectionCriteria = { threadCursors, joinedThreads: true }; | ||||
const [ | const [ | ||||
threadsResult, | threadsResult, | ||||
messagesResult, | messagesResult, | ||||
entriesResult, | entriesResult, | ||||
userInfos, | userInfos, | ||||
currentUserInfo, | currentUserInfo, | ||||
] = await Promise.all([ | ] = await Promise.all([ | ||||
fetchThreadInfos(viewer), | fetchThreadInfos(viewer), | ||||
fetchMessageInfos(viewer, messageSelectionCriteria, defaultNumberPerThread), | fetchMessageInfos(viewer, messageSelectionCriteria, defaultNumberPerThread), | ||||
calendarQuery ? fetchEntryInfos(viewer, [calendarQuery]) : undefined, | calendarQuery ? fetchEntryInfos(viewer, [calendarQuery]) : undefined, | ||||
fetchKnownUserInfos(viewer), | fetchKnownUserInfos(viewer), | ||||
fetchLoggedInUserInfo(viewer), | fetchLoggedInUserInfo(viewer), | ||||
olmSessionPromise, | |||||
]); | ]); | ||||
const rawEntryInfos = entriesResult ? entriesResult.rawEntryInfos : null; | const rawEntryInfos = entriesResult ? entriesResult.rawEntryInfos : null; | ||||
const response: LogInResponse = { | const response: LogInResponse = { | ||||
currentUserInfo, | currentUserInfo, | ||||
rawMessageInfos: messagesResult.rawMessageInfos, | rawMessageInfos: messagesResult.rawMessageInfos, | ||||
truncationStatuses: messagesResult.truncationStatuses, | truncationStatuses: messagesResult.truncationStatuses, | ||||
serverTime: newServerTime, | serverTime: newServerTime, | ||||
Show All 20 Lines | const logInRequestInputValidator = tShape<LogInRequest>({ | ||||
calendarQuery: t.maybe(entryQueryInputValidator), | calendarQuery: t.maybe(entryQueryInputValidator), | ||||
deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator), | deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator), | ||||
platformDetails: tPlatformDetails, | platformDetails: tPlatformDetails, | ||||
source: t.maybe(t.enums.of(values(logInActionSources))), | source: t.maybe(t.enums.of(values(logInActionSources))), | ||||
// We include `primaryIdentityPublicKey` to avoid breaking | // We include `primaryIdentityPublicKey` to avoid breaking | ||||
// old clients, but we no longer do anything with it. | // old clients, but we no longer do anything with it. | ||||
primaryIdentityPublicKey: t.maybe(tRegex(primaryIdentityPublicKeyRegex)), | primaryIdentityPublicKey: t.maybe(tRegex(primaryIdentityPublicKeyRegex)), | ||||
signedIdentityKeysBlob: t.maybe(signedIdentityKeysBlobValidator), | signedIdentityKeysBlob: t.maybe(signedIdentityKeysBlobValidator), | ||||
initialNotificationsEncryptedMessage: t.maybe(t.String), | |||||
}); | }); | ||||
export const logInResponseValidator: TInterface<LogInResponse> = | export const logInResponseValidator: TInterface<LogInResponse> = | ||||
tShape<LogInResponse>({ | tShape<LogInResponse>({ | ||||
currentUserInfo: t.union([ | currentUserInfo: t.union([ | ||||
loggedInUserInfoValidator, | loggedInUserInfoValidator, | ||||
oldLoggedInUserInfoValidator, | oldLoggedInUserInfoValidator, | ||||
]), | ]), | ||||
Show All 15 Lines | |||||
): Promise<LogInResponse> { | ): Promise<LogInResponse> { | ||||
const request = await validateInput( | const request = await validateInput( | ||||
viewer, | viewer, | ||||
logInRequestInputValidator, | logInRequestInputValidator, | ||||
input, | input, | ||||
); | ); | ||||
let identityKeys: ?IdentityKeysBlob; | let identityKeys: ?IdentityKeysBlob; | ||||
const { signedIdentityKeysBlob } = request; | const { signedIdentityKeysBlob, initialNotificationsEncryptedMessage } = | ||||
request; | |||||
if (signedIdentityKeysBlob) { | if (signedIdentityKeysBlob) { | ||||
identityKeys = JSON.parse(signedIdentityKeysBlob.payload); | identityKeys = JSON.parse(signedIdentityKeysBlob.payload); | ||||
const olmUtil: OlmUtility = getOlmUtility(); | const olmUtil: OlmUtility = getOlmUtility(); | ||||
try { | try { | ||||
olmUtil.ed25519_verify( | olmUtil.ed25519_verify( | ||||
identityKeys.primaryIdentityPublicKeys.ed25519, | identityKeys.primaryIdentityPublicKeys.ed25519, | ||||
signedIdentityKeysBlob.payload, | signedIdentityKeysBlob.payload, | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ): Promise<LogInResponse> { | ||||
const id = userRow.id.toString(); | const id = userRow.id.toString(); | ||||
const response = await processSuccessfulLogin({ | const response = await processSuccessfulLogin({ | ||||
viewer, | viewer, | ||||
input, | input, | ||||
userID: id, | userID: id, | ||||
calendarQuery, | calendarQuery, | ||||
signedIdentityKeysBlob, | signedIdentityKeysBlob, | ||||
initialNotificationsEncryptedMessage, | |||||
}); | }); | ||||
return validateOutput( | return validateOutput( | ||||
viewer.platformDetails, | viewer.platformDetails, | ||||
logInResponseValidator, | logInResponseValidator, | ||||
response, | response, | ||||
); | ); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 253 Lines • Show Last 20 Lines |