diff --git a/keyserver/src/responders/activity-responders.js b/keyserver/src/responders/activity-responders.js --- a/keyserver/src/responders/activity-responders.js +++ b/keyserver/src/responders/activity-responders.js @@ -29,16 +29,15 @@ }), ); -const inputValidator = tShape({ +const inputValidator = tShape({ updates: activityUpdatesInputValidator, }); async function updateActivityResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: UpdateActivityRequest = input; - await validateInput(viewer, inputValidator, request); + const request = await validateInput(viewer, inputValidator, input); const result = await activityUpdater(viewer, request); return validateOutput(viewer, updateActivityResultValidator, result); } @@ -50,10 +49,13 @@ }); async function threadSetUnreadStatusResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SetThreadUnreadStatusRequest = input; - await validateInput(viewer, setThreadUnreadStatusValidator, request); + const request = await validateInput( + viewer, + setThreadUnreadStatusValidator, + input, + ); const result = await setThreadUnreadStatus(viewer, request); return validateOutput(viewer, setThreadUnreadStatusResult, result); diff --git a/keyserver/src/responders/entry-responders.js b/keyserver/src/responders/entry-responders.js --- a/keyserver/src/responders/entry-responders.js +++ b/keyserver/src/responders/entry-responders.js @@ -136,10 +136,14 @@ async function entryFetchResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput(viewer, entryQueryInputValidator, input); - const request = normalizeCalendarQuery(input); + const inputQuery = await validateInput( + viewer, + entryQueryInputValidator, + input, + ); + const request = normalizeCalendarQuery(inputQuery); await verifyCalendarQueryThreadIDs(request); @@ -150,9 +154,10 @@ }); } -const entryRevisionHistoryFetchInputValidator = tShape({ - id: tID, -}); +const entryRevisionHistoryFetchInputValidator = + tShape({ + id: tID, + }); export const fetchEntryRevisionInfosResultValidator: TInterface = tShape({ @@ -161,10 +166,13 @@ async function entryRevisionFetchResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: FetchEntryRevisionInfosRequest = input; - await validateInput(viewer, entryRevisionHistoryFetchInputValidator, request); + const request = await validateInput( + viewer, + entryRevisionHistoryFetchInputValidator, + input, + ); const entryHistory = await fetchEntryRevisionInfo(viewer, request.id); const response = { result: entryHistory }; return validateOutput( @@ -174,7 +182,7 @@ ); } -const createEntryRequestInputValidator = tShape({ +const createEntryRequestInputValidator = tShape({ text: t.String, sessionID: t.maybe(t.String), timestamp: t.Number, @@ -193,15 +201,18 @@ async function entryCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: CreateEntryRequest = input; - await validateInput(viewer, createEntryRequestInputValidator, request); + const request = await validateInput( + viewer, + createEntryRequestInputValidator, + input, + ); const response = await createEntry(viewer, request); return validateOutput(viewer, saveEntryResponseValidator, response); } -const saveEntryRequestInputValidator = tShape({ +const saveEntryRequestInputValidator = tShape({ entryID: tID, text: t.String, prevText: t.String, @@ -212,15 +223,18 @@ async function entryUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SaveEntryRequest = input; - await validateInput(viewer, saveEntryRequestInputValidator, request); + const request = await validateInput( + viewer, + saveEntryRequestInputValidator, + input, + ); const response = await updateEntry(viewer, request); return validateOutput(viewer, saveEntryResponseValidator, response); } -const deleteEntryRequestInputValidator = tShape({ +const deleteEntryRequestInputValidator = tShape({ entryID: tID, prevText: t.String, sessionID: t.maybe(t.String), @@ -237,15 +251,18 @@ async function entryDeletionResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: DeleteEntryRequest = input; - await validateInput(viewer, deleteEntryRequestInputValidator, request); + const request = await validateInput( + viewer, + deleteEntryRequestInputValidator, + input, + ); const response = await deleteEntry(viewer, request); return validateOutput(viewer, deleteEntryResponseValidator, response); } -const restoreEntryRequestInputValidator = tShape({ +const restoreEntryRequestInputValidator = tShape({ entryID: tID, sessionID: t.maybe(t.String), timestamp: t.Number, @@ -260,10 +277,13 @@ async function entryRestorationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: RestoreEntryRequest = input; - await validateInput(viewer, restoreEntryRequestInputValidator, request); + const request = await validateInput( + viewer, + restoreEntryRequestInputValidator, + input, + ); const response = await restoreEntry(viewer, request); return validateOutput(viewer, restoreEntryResponseValidator, response); } @@ -277,10 +297,13 @@ async function calendarQueryUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: CalendarQuery = input; - await validateInput(viewer, newEntryQueryInputValidator, input); + const request = await validateInput( + viewer, + newEntryQueryInputValidator, + input, + ); await verifyCalendarQueryThreadIDs(request); if (!viewer.loggedIn) { diff --git a/keyserver/src/responders/keys-responders.js b/keyserver/src/responders/keys-responders.js --- a/keyserver/src/responders/keys-responders.js +++ b/keyserver/src/responders/keys-responders.js @@ -13,7 +13,7 @@ import type { Viewer } from '../session/viewer.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const getSessionPublicKeysInputValidator = tShape({ +const getSessionPublicKeysInputValidator = tShape({ session: t.String, }); @@ -23,13 +23,16 @@ async function getSessionPublicKeysResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { if (!viewer.loggedIn) { return null; } - const request: GetSessionPublicKeysArgs = input; - await validateInput(viewer, getSessionPublicKeysInputValidator, request); + const request = await validateInput( + viewer, + getSessionPublicKeysInputValidator, + input, + ); const response = await fetchSessionPublicKeys(request.session); return validateOutput( viewer, diff --git a/keyserver/src/responders/message-report-responder.js b/keyserver/src/responders/message-report-responder.js --- a/keyserver/src/responders/message-report-responder.js +++ b/keyserver/src/responders/message-report-responder.js @@ -13,23 +13,23 @@ import type { Viewer } from '../session/viewer.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const messageReportCreationRequestInputValidator = tShape({ - messageID: tID, -}); +const messageReportCreationRequestInputValidator = + tShape({ + messageID: tID, + }); export const messageReportCreationResultValidator: TInterface = tShape({ messageInfo: rawMessageInfoValidator }); async function messageReportCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput( + const request = await validateInput( viewer, messageReportCreationRequestInputValidator, input, ); - const request: MessageReportCreationRequest = input; const rawMessageInfos = await createMessageReport(viewer, request); const result = { messageInfo: rawMessageInfos[0] }; diff --git a/keyserver/src/responders/message-responders.js b/keyserver/src/responders/message-responders.js --- a/keyserver/src/responders/message-responders.js +++ b/keyserver/src/responders/message-responders.js @@ -63,7 +63,7 @@ } from '../updaters/upload-updaters.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const sendTextMessageRequestInputValidator = tShape({ +const sendTextMessageRequestInputValidator = tShape({ threadID: tID, localID: t.maybe(t.String), text: t.String, @@ -75,10 +75,13 @@ async function textMessageCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SendTextMessageRequest = input; - await validateInput(viewer, sendTextMessageRequestInputValidator, request); + const request = await validateInput( + viewer, + sendTextMessageRequestInputValidator, + input, + ); const { threadID, localID, text: rawText, sidebarCreation } = request; const text = trimMessage(rawText); @@ -123,10 +126,12 @@ return validateOutput(viewer, sendMessageResponseValidator, response); } -const fetchMessageInfosRequestInputValidator = tShape({ - cursors: t.dict(tID, t.maybe(tID)), - numberPerThread: t.maybe(t.Number), -}); +const fetchMessageInfosRequestInputValidator = tShape( + { + cursors: t.dict(tID, t.maybe(tID)), + numberPerThread: t.maybe(t.Number), + }, +); export const fetchMessageInfosResponseValidator: TInterface = tShape({ @@ -137,10 +142,13 @@ async function messageFetchResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: FetchMessageInfosRequest = input; - await validateInput(viewer, fetchMessageInfosRequestInputValidator, request); + const request = await validateInput( + viewer, + fetchMessageInfosRequestInputValidator, + input, + ); const response = await fetchMessageInfos( viewer, { threadCursors: request.cursors }, @@ -152,30 +160,30 @@ }); } -const sendMultimediaMessageRequestInputValidator = t.union([ - // This option is only used for messageTypes.IMAGES - tShape({ - threadID: tID, - localID: t.String, - sidebarCreation: t.maybe(t.Boolean), - mediaIDs: t.list(tID), - }), - tShape({ - threadID: tID, - localID: t.String, - sidebarCreation: t.maybe(t.Boolean), - mediaMessageContents: t.list(tMediaMessageMedia), - }), -]); +const sendMultimediaMessageRequestInputValidator = + t.union([ + // This option is only used for messageTypes.IMAGES + tShape({ + threadID: tID, + localID: t.String, + sidebarCreation: t.maybe(t.Boolean), + mediaIDs: t.list(tID), + }), + tShape({ + threadID: tID, + localID: t.String, + sidebarCreation: t.maybe(t.Boolean), + mediaMessageContents: t.list(tMediaMessageMedia), + }), + ]); async function multimediaMessageCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SendMultimediaMessageRequest = input; - await validateInput( + const request = await validateInput( viewer, sendMultimediaMessageRequestInputValidator, - request, + input, ); if ( @@ -248,19 +256,23 @@ return validateOutput(viewer, sendMessageResponseValidator, response); } -const sendReactionMessageRequestInputValidator = tShape({ - threadID: tID, - localID: t.maybe(t.String), - targetMessageID: tID, - reaction: tRegex(onlyOneEmojiRegex), - action: t.enums.of(['add_reaction', 'remove_reaction']), -}); +const sendReactionMessageRequestInputValidator = + tShape({ + threadID: tID, + localID: t.maybe(t.String), + targetMessageID: tID, + reaction: tRegex(onlyOneEmojiRegex), + action: t.enums.of(['add_reaction', 'remove_reaction']), + }); async function reactionMessageCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SendReactionMessageRequest = input; - await validateInput(viewer, sendReactionMessageRequestInputValidator, input); + const request = await validateInput( + viewer, + sendReactionMessageRequestInputValidator, + input, + ); const { threadID, localID, targetMessageID, reaction, action } = request; @@ -323,7 +335,7 @@ return validateOutput(viewer, sendMessageResponseValidator, response); } -const editMessageRequestInputValidator = tShape({ +const editMessageRequestInputValidator = tShape({ targetMessageID: tID, text: t.String, }); @@ -335,10 +347,13 @@ async function editMessageCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SendEditMessageRequest = input; - await validateInput(viewer, editMessageRequestInputValidator, input); + const request = await validateInput( + viewer, + editMessageRequestInputValidator, + input, + ); const { targetMessageID, text: rawText } = request; const text = trimMessage(rawText); @@ -414,9 +429,10 @@ return validateOutput(viewer, sendEditMessageResponseValidator, response); } -const fetchPinnedMessagesResponderInputValidator = tShape({ - threadID: tID, -}); +const fetchPinnedMessagesResponderInputValidator = + tShape({ + threadID: tID, + }); export const fetchPinnedMessagesResultValidator: TInterface = tShape({ @@ -425,10 +441,9 @@ async function fetchPinnedMessagesResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: FetchPinnedMessagesRequest = input; - await validateInput( + const request = await validateInput( viewer, fetchPinnedMessagesResponderInputValidator, input, diff --git a/keyserver/src/responders/relationship-responders.js b/keyserver/src/responders/relationship-responders.js --- a/keyserver/src/responders/relationship-responders.js +++ b/keyserver/src/responders/relationship-responders.js @@ -13,7 +13,7 @@ import { updateRelationships } from '../updaters/relationship-updaters.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const updateRelationshipInputValidator = tShape({ +const updateRelationshipInputValidator = tShape({ action: t.enums.of(relationshipActionsList, 'relationship action'), userIDs: t.list(t.String), }); @@ -27,10 +27,13 @@ async function updateRelationshipsResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: RelationshipRequest = input; - await validateInput(viewer, updateRelationshipInputValidator, request); + const request = await validateInput( + viewer, + updateRelationshipInputValidator, + input, + ); const response = await updateRelationships(viewer, request); return validateOutput(viewer, relationshipErrorsValidator, response); } diff --git a/keyserver/src/responders/report-responders.js b/keyserver/src/responders/report-responders.js --- a/keyserver/src/responders/report-responders.js +++ b/keyserver/src/responders/report-responders.js @@ -107,7 +107,7 @@ ), }); -const reportCreationRequestInputValidator = t.union([ +const reportCreationRequestInputValidator = t.union([ tShape({ type: t.maybe( t.irreducible('reportTypes.ERROR', x => x === reportTypes.ERROR), @@ -138,20 +138,23 @@ async function reportCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput(viewer, reportCreationRequestInputValidator, input); - if (input.type === null || input.type === undefined) { - input.type = reportTypes.ERROR; + let request = await validateInput( + viewer, + reportCreationRequestInputValidator, + input, + ); + if (request.type === null || request.type === undefined) { + request.type = reportTypes.ERROR; } - if (!input.platformDetails && input.deviceType) { - const { deviceType, codeVersion, stateVersion, ...rest } = input; - input = { + if (!request.platformDetails && request.deviceType) { + const { deviceType, codeVersion, stateVersion, ...rest } = request; + request = { ...rest, platformDetails: { platform: deviceType, codeVersion, stateVersion }, }; } - const request: ReportCreationRequest = input; const response = await createReport(viewer, request); if (!response) { throw new ServerError('ignored_report'); @@ -159,43 +162,46 @@ return validateOutput(viewer, reportCreationResponseValidator, response); } -const reportMultiCreationRequestInputValidator = tShape({ - reports: t.list( - t.union([ - tShape({ - type: t.irreducible('reportTypes.ERROR', x => x === reportTypes.ERROR), - platformDetails: tPlatformDetails, - errors: t.list( - tShape({ - errorMessage: t.String, - stack: t.maybe(t.String), - componentStack: t.maybe(t.String), - }), - ), - preloadedState: t.Object, - currentState: t.Object, - actions: t.list(t.union([t.Object, t.String])), - }), - threadInconsistencyReportCreationRequest, - entryInconsistencyReportCreationRquest, - mediaMissionReportCreationRequest, - userInconsistencyReportCreationRequest, - ]), - ), -}); +const reportMultiCreationRequestInputValidator = + tShape({ + reports: t.list( + t.union([ + tShape({ + type: t.irreducible( + 'reportTypes.ERROR', + x => x === reportTypes.ERROR, + ), + platformDetails: tPlatformDetails, + errors: t.list( + tShape({ + errorMessage: t.String, + stack: t.maybe(t.String), + componentStack: t.maybe(t.String), + }), + ), + preloadedState: t.Object, + currentState: t.Object, + actions: t.list(t.union([t.Object, t.String])), + }), + threadInconsistencyReportCreationRequest, + entryInconsistencyReportCreationRquest, + mediaMissionReportCreationRequest, + userInconsistencyReportCreationRequest, + ]), + ), + }); type ReportMultiCreationRequest = { reports: $ReadOnlyArray, }; async function reportMultiCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ReportMultiCreationRequest = input; - await validateInput( + const request = await validateInput( viewer, reportMultiCreationRequestInputValidator, - request, + input, ); await Promise.all( request.reports.map(reportCreationRequest => @@ -204,9 +210,10 @@ ); } -const fetchErrorReportInfosRequestInputValidator = tShape({ - cursor: t.maybe(t.String), -}); +const fetchErrorReportInfosRequestInputValidator = + tShape({ + cursor: t.maybe(t.String), + }); export const fetchErrorReportInfosResponseValidator: TInterface = tShape({ @@ -216,13 +223,12 @@ async function errorReportFetchInfosResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: FetchErrorReportInfosRequest = input; - await validateInput( + const request = await validateInput( viewer, fetchErrorReportInfosRequestInputValidator, - request, + input, ); const response = await fetchErrorReportInfos(viewer, request); return validateOutput( diff --git a/keyserver/src/responders/search-responders.js b/keyserver/src/responders/search-responders.js --- a/keyserver/src/responders/search-responders.js +++ b/keyserver/src/responders/search-responders.js @@ -13,7 +13,7 @@ import type { Viewer } from '../session/viewer.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const userSearchRequestInputValidator = tShape({ +const userSearchRequestInputValidator = tShape({ prefix: t.maybe(t.String), }); @@ -24,10 +24,13 @@ async function userSearchResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: UserSearchRequest = input; - await validateInput(viewer, userSearchRequestInputValidator, request); + const request = await validateInput( + viewer, + userSearchRequestInputValidator, + input, + ); const searchResults = await searchForUsers(request); const result = { userInfos: searchResults }; return validateOutput(viewer, userSearchResultValidator, result); diff --git a/keyserver/src/responders/thread-responders.js b/keyserver/src/responders/thread-responders.js --- a/keyserver/src/responders/thread-responders.js +++ b/keyserver/src/responders/thread-responders.js @@ -58,7 +58,7 @@ } from '../updaters/thread-updaters.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const threadDeletionRequestInputValidator = tShape({ +const threadDeletionRequestInputValidator = tShape({ threadID: tID, accountPassword: t.maybe(tPassword), }); @@ -73,10 +73,13 @@ async function threadDeletionResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ThreadDeletionRequest = input; - await validateInput(viewer, threadDeletionRequestInputValidator, request); + const request = await validateInput( + viewer, + threadDeletionRequestInputValidator, + input, + ); const result = await deleteThread(viewer, request); return validateOutput(viewer, leaveThreadResultValidator, result); } @@ -106,44 +109,53 @@ async function roleUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: RoleChangeRequest = input; - await validateInput(viewer, roleChangeRequestInputValidator, request); + const request = await validateInput( + viewer, + roleChangeRequestInputValidator, + input, + ); const result = await updateRole(viewer, request); return validateOutput(viewer, changeThreadSettingsResultValidator, result); } -const removeMembersRequestInputValidator = tShape({ +const removeMembersRequestInputValidator = tShape({ threadID: tID, memberIDs: t.list(t.String), }); async function memberRemovalResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: RemoveMembersRequest = input; - await validateInput(viewer, removeMembersRequestInputValidator, request); + const request = await validateInput( + viewer, + removeMembersRequestInputValidator, + input, + ); const result = await removeMembers(viewer, request); return validateOutput(viewer, changeThreadSettingsResultValidator, result); } -const leaveThreadRequestInputValidator = tShape({ +const leaveThreadRequestInputValidator = tShape({ threadID: tID, }); async function threadLeaveResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: LeaveThreadRequest = input; - await validateInput(viewer, leaveThreadRequestInputValidator, request); + const request = await validateInput( + viewer, + leaveThreadRequestInputValidator, + input, + ); const result = await leaveThread(viewer, request); return validateOutput(viewer, leaveThreadResultValidator, result); } -const updateThreadRequestInputValidator = tShape({ +const updateThreadRequestInputValidator = tShape({ threadID: tID, changes: tShape({ type: t.maybe(tNumEnum(values(threadTypes))), @@ -159,10 +171,13 @@ async function threadUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: UpdateThreadRequest = input; - await validateInput(viewer, updateThreadRequestInputValidator, request); + const request = await validateInput( + viewer, + updateThreadRequestInputValidator, + input, + ); const result = await updateThread(viewer, request); return validateOutput(viewer, changeThreadSettingsResultValidator, result); } @@ -205,10 +220,13 @@ async function threadCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ServerNewThreadRequest = input; - await validateInput(viewer, newThreadRequestInputValidator, request); + const request = await validateInput( + viewer, + newThreadRequestInputValidator, + input, + ); const result = await createThread(viewer, request, { silentlyFailMembers: request.type === threadTypes.SIDEBAR, @@ -216,7 +234,7 @@ return validateOutput(viewer, newThreadResponseValidator, result); } -const joinThreadRequestInputValidator = tShape({ +const joinThreadRequestInputValidator = tShape({ threadID: tID, calendarQuery: t.maybe(entryQueryInputValidator), inviteLinkSecret: t.maybe(t.String), @@ -236,10 +254,13 @@ async function threadJoinResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ServerThreadJoinRequest = input; - await validateInput(viewer, joinThreadRequestInputValidator, request); + const request = await validateInput( + viewer, + joinThreadRequestInputValidator, + input, + ); if (request.calendarQuery) { await verifyCalendarQueryThreadIDs(request.calendarQuery); @@ -249,7 +270,7 @@ return validateOutput(viewer, threadJoinResultValidator, result); } -const threadFetchMediaRequestInputValidator = tShape({ +const threadFetchMediaRequestInputValidator = tShape({ threadID: tID, limit: t.Number, offset: t.Number, @@ -260,15 +281,18 @@ async function threadFetchMediaResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ThreadFetchMediaRequest = input; - await validateInput(viewer, threadFetchMediaRequestInputValidator, request); + const request = await validateInput( + viewer, + threadFetchMediaRequestInputValidator, + input, + ); const result = await fetchMediaForThread(viewer, request); return validateOutput(viewer, threadFetchMediaResultValidator, result); } -const toggleMessagePinRequestInputValidator = tShape({ +const toggleMessagePinRequestInputValidator = tShape({ messageID: tID, action: t.enums.of(['pin', 'unpin']), }); @@ -281,10 +305,13 @@ async function toggleMessagePinResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ToggleMessagePinRequest = input; - await validateInput(viewer, toggleMessagePinRequestInputValidator, request); + const request = await validateInput( + viewer, + toggleMessagePinRequestInputValidator, + input, + ); const result = await toggleMessagePinForThread(viewer, request); return validateOutput(viewer, toggleMessagePinResultValidator, result); } diff --git a/keyserver/src/responders/user-responders.js b/keyserver/src/responders/user-responders.js --- a/keyserver/src/responders/user-responders.js +++ b/keyserver/src/responders/user-responders.js @@ -32,7 +32,6 @@ import { type ClientAvatar, clientAvatarValidator, - type UpdateUserAvatarRequest, type UpdateUserAvatarResponse, } from 'lib/types/avatar-types.js'; import type { @@ -119,6 +118,7 @@ createNewUserCookie, setNewSession, } from '../session/cookies.js'; +import { verifyClientSupported } from '../session/version.js'; import type { Viewer } from '../session/viewer.js'; import { accountUpdater, @@ -133,13 +133,14 @@ import { getOlmUtility } from '../utils/olm-utils.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; -const subscriptionUpdateRequestInputValidator = tShape({ - threadID: tID, - updatedFields: tShape({ - pushNotifs: t.maybe(t.Boolean), - home: t.maybe(t.Boolean), - }), -}); +const subscriptionUpdateRequestInputValidator = + tShape({ + threadID: tID, + updatedFields: tShape({ + pushNotifs: t.maybe(t.Boolean), + home: t.maybe(t.Boolean), + }), + }); export const subscriptionUpdateResponseValidator: TInterface = tShape({ @@ -148,17 +149,20 @@ async function userSubscriptionUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: SubscriptionUpdateRequest = input; - await validateInput(viewer, subscriptionUpdateRequestInputValidator, request); + const request = await validateInput( + viewer, + subscriptionUpdateRequestInputValidator, + input, + ); const threadSubscription = await userSubscriptionUpdater(viewer, request); return validateOutput(viewer, subscriptionUpdateResponseValidator, { threadSubscription, }); } -const accountUpdateInputValidator = tShape({ +const accountUpdateInputValidator = tShape({ updatedFields: tShape({ email: t.maybe(tEmail), password: t.maybe(tPassword), @@ -168,28 +172,36 @@ async function passwordUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: PasswordUpdate = input; - await validateInput(viewer, accountUpdateInputValidator, request); + const request = await validateInput( + viewer, + accountUpdateInputValidator, + input, + ); await accountUpdater(viewer, request); } async function sendVerificationEmailResponder(viewer: Viewer): Promise { - await validateInput(viewer, null, null); + if (!viewer.isSocket) { + await verifyClientSupported(viewer, viewer.platformDetails); + } await checkAndSendVerificationEmail(viewer); } -const resetPasswordRequestInputValidator = tShape({ +const resetPasswordRequestInputValidator = tShape({ usernameOrEmail: t.union([tEmail, tOldValidUsername]), }); async function sendPasswordResetEmailResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: ResetPasswordRequest = input; - await validateInput(viewer, resetPasswordRequestInputValidator, request); + const request = await validateInput( + viewer, + resetPasswordRequestInputValidator, + input, + ); await checkAndSendPasswordResetEmail(request); } @@ -199,7 +211,9 @@ }); async function logOutResponder(viewer: Viewer): Promise { - await validateInput(viewer, null, null); + if (!viewer.isSocket) { + await verifyClientSupported(viewer, viewer.platformDetails); + } if (viewer.loggedIn) { const [anonymousViewerData] = await Promise.all([ createNewAnonymousCookie({ @@ -219,16 +233,19 @@ return validateOutput(viewer, logOutResponseValidator, response); } -const deleteAccountRequestInputValidator = tShape({ +const deleteAccountRequestInputValidator = tShape({ password: t.maybe(tPassword), }); async function accountDeletionResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: DeleteAccountRequest = input; - await validateInput(viewer, deleteAccountRequestInputValidator, request); + const request = await validateInput( + viewer, + deleteAccountRequestInputValidator, + input, + ); const result = await deleteAccount(viewer, request); invariant(result, 'deleteAccount should return result if handed request'); return validateOutput(viewer, logOutResponseValidator, result); @@ -239,7 +256,7 @@ deviceToken: t.String, }); -const registerRequestInputValidator = tShape({ +const registerRequestInputValidator = tShape({ username: t.String, email: t.maybe(tEmail), password: tPassword, @@ -268,10 +285,13 @@ async function accountCreationResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: RegisterRequest = input; - await validateInput(viewer, registerRequestInputValidator, request); + const request = await validateInput( + viewer, + registerRequestInputValidator, + input, + ); const { signedIdentityKeysBlob } = request; if (signedIdentityKeysBlob) { const identityKeys: IdentityKeysBlob = JSON.parse( @@ -399,7 +419,7 @@ return response; } -const logInRequestInputValidator = tShape({ +const logInRequestInputValidator = tShape({ username: t.maybe(t.String), usernameOrEmail: t.maybe(t.union([tEmail, tOldValidUsername])), password: tPassword, @@ -434,10 +454,13 @@ async function logInResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput(viewer, logInRequestInputValidator, input); - const request: LogInRequest = input; + const request = await validateInput( + viewer, + logInRequestInputValidator, + input, + ); let identityKeys: ?IdentityKeysBlob; const { signedIdentityKeysBlob } = request; @@ -508,7 +531,7 @@ return validateOutput(viewer, logInResponseValidator, response); } -const siweAuthRequestInputValidator = tShape({ +const siweAuthRequestInputValidator = tShape({ signature: t.String, message: t.String, calendarQuery: entryQueryInputValidator, @@ -520,10 +543,14 @@ async function siweAuthResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput(viewer, siweAuthRequestInputValidator, input); - const request: SIWEAuthRequest = input; + const request = await validateInput( + viewer, + siweAuthRequestInputValidator, + input, + ); + const { message, signature, @@ -644,7 +671,7 @@ return validateOutput(viewer, logInResponseValidator, response); } -const updatePasswordRequestInputValidator = tShape({ +const updatePasswordRequestInputValidator = tShape({ code: t.String, password: tPassword, watchedIDs: t.list(tID), @@ -655,10 +682,14 @@ async function oldPasswordUpdateResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - await validateInput(viewer, updatePasswordRequestInputValidator, input); - const request: UpdatePasswordRequest = input; + const request = await validateInput( + viewer, + updatePasswordRequestInputValidator, + input, + ); + if (request.calendarQuery) { request.calendarQuery = normalizeCalendarQuery(request.calendarQuery); } @@ -666,7 +697,7 @@ return validateOutput(viewer, logInResponseValidator, response); } -const updateUserSettingsInputValidator = tShape({ +const updateUserSettingsInputValidator = tShape({ name: t.irreducible( userSettingsTypes.DEFAULT_NOTIFICATIONS, x => x === userSettingsTypes.DEFAULT_NOTIFICATIONS, @@ -676,26 +707,29 @@ async function updateUserSettingsResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: UpdateUserSettingsRequest = input; - await validateInput(viewer, updateUserSettingsInputValidator, request); + const request = await validateInput( + viewer, + updateUserSettingsInputValidator, + input, + ); await updateUserSettings(viewer, request); } -const policyAcknowledgmentRequestInputValidator = tShape({ - policy: t.maybe(t.enums.of(policies)), -}); +const policyAcknowledgmentRequestInputValidator = + tShape({ + policy: t.maybe(t.enums.of(policies)), + }); async function policyAcknowledgmentResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: PolicyAcknowledgmentRequest = input; - await validateInput( + const request = await validateInput( viewer, policyAcknowledgmentRequestInputValidator, - request, + input, ); await viewerAcknowledgmentUpdater(viewer, request.policy); } @@ -712,10 +746,13 @@ async function updateUserAvatarResponder( viewer: Viewer, - input: any, + input: mixed, ): Promise { - const request: UpdateUserAvatarRequest = input; - await validateInput(viewer, updateUserAvatarRequestValidator, request); + const request = await validateInput( + viewer, + updateUserAvatarRequestValidator, + input, + ); const result = await updateUserAvatar(viewer, request); return validateOutput(viewer, updateUserAvatarResponderValidator, result); } diff --git a/keyserver/src/utils/validation-utils.js b/keyserver/src/utils/validation-utils.js --- a/keyserver/src/utils/validation-utils.js +++ b/keyserver/src/utils/validation-utils.js @@ -21,19 +21,33 @@ import { verifyClientSupported } from '../session/version.js'; import type { Viewer } from '../session/viewer.js'; +const convertToNewIDSchema = false; +const keyserverPrefixID = '256'; + async function validateInput( viewer: Viewer, - inputValidator: ?TType, - input: T, -) { + inputValidator: TType, + input: mixed, +): Promise { if (!viewer.isSocket) { await checkClientSupported(viewer, inputValidator, input); } - checkInputValidator(inputValidator, input); -} + const convertedInput = checkInputValidator(inputValidator, input); -const convertToNewIDSchema = false; -const keyserverPrefixID = '256'; + if ( + hasMinCodeVersion(viewer.platformDetails, 1000) && + !isWebPlatform(viewer.platformDetails?.platform) && + convertToNewIDSchema + ) { + return convertClientIDsToServerIDs( + keyserverPrefixID, + inputValidator, + convertedInput, + ); + } + + return convertedInput; +} function validateOutput( viewer: Viewer, @@ -96,9 +110,9 @@ return convertObject(outputValidator, data, [tID], conversionFunction); } -function checkInputValidator(inputValidator: ?TType, input: T) { - if (!inputValidator || inputValidator.is(input)) { - return; +function checkInputValidator(inputValidator: TType, input: mixed): T { + if (inputValidator.is(input)) { + return assertWithValidator(input, inputValidator); } const error = new ServerError('invalid_parameters'); error.sanitizedInput = input ? sanitizeInput(inputValidator, input) : null; 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 @@ -51,10 +51,12 @@ export type RegisterRequest = { +username: string, + +email?: empty, +password: string, +calendarQuery?: ?CalendarQuery, +deviceTokenUpdateRequest?: ?DeviceTokenUpdateRequest, +platformDetails: PlatformDetails, + +primaryIdentityPublicKey?: empty, +signedIdentityKeysBlob?: SignedIdentityKeysBlob, }; @@ -125,6 +127,7 @@ +platformDetails: PlatformDetails, +watchedIDs: $ReadOnlyArray, +source?: LogInActionSource, + +primaryIdentityPublicKey?: empty, +signedIdentityKeysBlob?: SignedIdentityKeysBlob, }; diff --git a/lib/types/entry-types.js b/lib/types/entry-types.js --- a/lib/types/entry-types.js +++ b/lib/types/entry-types.js @@ -96,6 +96,7 @@ export type SaveEntryRequest = { +entryID: string, + +sessionID?: empty, +text: string, +prevText: string, +timestamp: number, @@ -130,6 +131,7 @@ export type CreateEntryRequest = { +text: string, + +sessionID?: empty, +timestamp: number, +date: string, +threadID: string, @@ -150,6 +152,7 @@ export type DeleteEntryRequest = { +entryID: string, + +sessionID?: empty, +prevText: string, +timestamp: number, +calendarQuery?: CalendarQuery, @@ -162,6 +165,7 @@ export type RestoreEntryRequest = { +entryID: string, + +sessionID?: empty, +timestamp: number, +calendarQuery?: CalendarQuery, }; diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -459,6 +459,7 @@ export type UpdateThreadRequest = { +threadID: string, +changes: ThreadChanges, + +accountPassword?: empty, }; export type BaseNewThreadRequest = {