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 @@ -12,7 +12,7 @@ setThreadUnreadStatusResult, updateActivityResultValidator, } from 'lib/types/activity-types.js'; -import { tShape } from 'lib/utils/validation-utils.js'; +import { tShape, tID } from 'lib/utils/validation-utils.js'; import type { Viewer } from '../session/viewer.js'; import { @@ -24,8 +24,8 @@ const activityUpdatesInputValidator: TList> = t.list( tShape({ focus: t.Bool, - threadID: t.String, - latestMessage: t.maybe(t.String), + threadID: tID, + latestMessage: t.maybe(tID), }), ); @@ -43,10 +43,10 @@ return validateOutput(viewer, updateActivityResultValidator, result); } -const setThreadUnreadStatusValidator = tShape({ - threadID: t.String, +const setThreadUnreadStatusValidator = tShape({ + threadID: tID, unread: t.Bool, - latestMessage: t.maybe(t.String), + latestMessage: t.maybe(tID), }); async function threadSetUnreadStatusResponder( viewer: Viewer, 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 @@ -68,7 +68,7 @@ }), tShape({ type: tString(calendarThreadFilterTypes.THREAD_LIST), - threadIDs: t.list(t.String), + threadIDs: t.list(tID), }), ]), ), @@ -85,7 +85,7 @@ }), tShape({ type: tString(calendarThreadFilterTypes.THREAD_LIST), - threadIDs: t.list(t.String), + threadIDs: t.list(tID), }), ]), ), @@ -151,7 +151,7 @@ } const entryRevisionHistoryFetchInputValidator = tShape({ - id: t.String, + id: tID, }); export const fetchEntryRevisionInfosResultValidator: TInterface = @@ -179,7 +179,7 @@ sessionID: t.maybe(t.String), timestamp: t.Number, date: tDate, - threadID: t.String, + threadID: tID, localID: t.maybe(t.String), calendarQuery: t.maybe(newEntryQueryInputValidator), }); @@ -202,7 +202,7 @@ } const saveEntryRequestInputValidator = tShape({ - entryID: t.String, + entryID: tID, text: t.String, prevText: t.String, sessionID: t.maybe(t.String), @@ -221,7 +221,7 @@ } const deleteEntryRequestInputValidator = tShape({ - entryID: t.String, + entryID: tID, prevText: t.String, sessionID: t.maybe(t.String), timestamp: t.Number, @@ -246,7 +246,7 @@ } const restoreEntryRequestInputValidator = tShape({ - entryID: t.String, + entryID: tID, sessionID: t.maybe(t.String), timestamp: t.Number, calendarQuery: t.maybe(newEntryQueryInputValidator), 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 @@ -1,20 +1,20 @@ // @flow -import t, { type TInterface } from 'tcomb'; +import type { TInterface } from 'tcomb'; import { type MessageReportCreationRequest, type MessageReportCreationResult, } from 'lib/types/message-report-types.js'; import { rawMessageInfoValidator } from 'lib/types/message-types.js'; -import { tShape } from 'lib/utils/validation-utils.js'; +import { tShape, tID } from 'lib/utils/validation-utils.js'; import createMessageReport from '../creators/message-report-creator.js'; import type { Viewer } from '../session/viewer.js'; import { validateInput, validateOutput } from '../utils/validation-utils.js'; const messageReportCreationRequestInputValidator = tShape({ - messageID: t.String, + messageID: tID, }); export const messageReportCreationResultValidator: TInterface = 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 @@ -37,6 +37,7 @@ tRegex, tShape, tMediaMessageMedia, + tID, } from 'lib/utils/validation-utils.js'; import createMessages from '../creators/message-creator.js'; @@ -63,7 +64,7 @@ import { validateInput, validateOutput } from '../utils/validation-utils.js'; const sendTextMessageRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, localID: t.maybe(t.String), text: t.String, sidebarCreation: t.maybe(t.Boolean), @@ -123,7 +124,7 @@ } const fetchMessageInfosRequestInputValidator = tShape({ - cursors: t.dict(t.String, t.maybe(t.String)), + cursors: t.dict(tID, t.maybe(tID)), numberPerThread: t.maybe(t.Number), }); @@ -154,13 +155,13 @@ const sendMultimediaMessageRequestInputValidator = t.union([ // This option is only used for messageTypes.IMAGES tShape({ - threadID: t.String, + threadID: tID, localID: t.String, sidebarCreation: t.maybe(t.Boolean), - mediaIDs: t.list(t.String), + mediaIDs: t.list(tID), }), tShape({ - threadID: t.String, + threadID: tID, localID: t.String, sidebarCreation: t.maybe(t.Boolean), mediaMessageContents: t.list(tMediaMessageMedia), @@ -248,9 +249,9 @@ } const sendReactionMessageRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, localID: t.maybe(t.String), - targetMessageID: t.String, + targetMessageID: tID, reaction: tRegex(onlyOneEmojiRegex), action: t.enums.of(['add_reaction', 'remove_reaction']), }); @@ -323,7 +324,7 @@ } const editMessageRequestInputValidator = tShape({ - targetMessageID: t.String, + targetMessageID: tID, text: t.String, }); @@ -414,7 +415,7 @@ } const fetchPinnedMessagesResponderInputValidator = tShape({ - threadID: t.String, + threadID: tID, }); export const fetchPinnedMessagesResultValidator: TInterface = diff --git a/keyserver/src/responders/responder-validators.test.js b/keyserver/src/responders/responder-validators.test.js --- a/keyserver/src/responders/responder-validators.test.js +++ b/keyserver/src/responders/responder-validators.test.js @@ -32,6 +32,7 @@ threadFetchMediaResultValidator, threadJoinResultValidator, toggleMessagePinResultValidator, + roleChangeRequestInputValidator, } from './thread-responders.js'; import { logInResponseValidator, @@ -815,6 +816,25 @@ toggleMessagePinResultValidator.is({ ...response, threadID: undefined }), ).toBe(false); }); + + it('should validate role change request input', () => { + const input = { + threadID: '123', + memberIDs: [], + role: '1', + }; + + expect(roleChangeRequestInputValidator.is(input)).toBe(true); + expect(roleChangeRequestInputValidator.is({ ...input, role: '2|1' })).toBe( + true, + ); + expect(roleChangeRequestInputValidator.is({ ...input, role: '-1' })).toBe( + false, + ); + expect(roleChangeRequestInputValidator.is({ ...input, role: '2|-1' })).toBe( + false, + ); + }); }); describe('message responders', () => { 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 @@ -59,7 +59,7 @@ import { validateInput, validateOutput } from '../utils/validation-utils.js'; const threadDeletionRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, accountPassword: t.maybe(tPassword), }); @@ -81,14 +81,18 @@ return validateOutput(viewer, leaveThreadResultValidator, result); } -const roleChangeRequestInputValidator = tShape({ - threadID: t.String, - memberIDs: t.list(t.String), - role: t.refinement(t.String, str => { - const int = parseInt(str, 10); - return String(int) === str && int > 0; - }), -}); +export const roleChangeRequestInputValidator: TInterface = + tShape({ + threadID: tID, + memberIDs: t.list(t.String), + role: t.refinement(tID, str => { + if (str.indexOf('|') !== -1) { + str = str.split('|')[1]; + } + const int = parseInt(str, 10); + return String(int) === str && int > 0; + }), + }); export const changeThreadSettingsResultValidator: TInterface = tShape({ @@ -111,7 +115,7 @@ } const removeMembersRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, memberIDs: t.list(t.String), }); @@ -126,7 +130,7 @@ } const leaveThreadRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, }); async function threadLeaveResponder( @@ -140,13 +144,13 @@ } const updateThreadRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, changes: tShape({ type: t.maybe(tNumEnum(values(threadTypes))), name: t.maybe(t.String), description: t.maybe(t.String), color: t.maybe(tColor), - parentThreadID: t.maybe(t.String), + parentThreadID: t.maybe(tID), newMemberIDs: t.maybe(t.list(t.String)), avatar: t.maybe(updateUserAvatarRequestValidator), }), @@ -167,14 +171,14 @@ name: t.maybe(t.String), description: t.maybe(t.String), color: t.maybe(tColor), - parentThreadID: t.maybe(t.String), + parentThreadID: t.maybe(tID), initialMemberIDs: t.maybe(t.list(t.String)), calendarQuery: t.maybe(entryQueryInputValidator), }; const newThreadRequestInputValidator: TUnion = t.union([ tShape({ type: tNumEnum([threadTypes.SIDEBAR]), - sourceMessageID: t.String, + sourceMessageID: tID, ...threadRequestValidationShape, }), tShape({ @@ -213,7 +217,7 @@ } const joinThreadRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, calendarQuery: t.maybe(entryQueryInputValidator), inviteLinkSecret: t.maybe(t.String), }); @@ -246,7 +250,7 @@ } const threadFetchMediaRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, limit: t.Number, offset: t.Number, }); @@ -265,7 +269,7 @@ } const toggleMessagePinRequestInputValidator = tShape({ - messageID: t.String, + messageID: tID, action: t.enums.of(['pin', 'unpin']), }); 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 @@ -134,7 +134,7 @@ import { validateInput, validateOutput } from '../utils/validation-utils.js'; const subscriptionUpdateRequestInputValidator = tShape({ - threadID: t.String, + threadID: tID, updatedFields: tShape({ pushNotifs: t.maybe(t.Boolean), home: t.maybe(t.Boolean), @@ -403,7 +403,7 @@ username: t.maybe(t.String), usernameOrEmail: t.maybe(t.union([tEmail, tOldValidUsername])), password: tPassword, - watchedIDs: t.list(t.String), + watchedIDs: t.list(tID), calendarQuery: t.maybe(entryQueryInputValidator), deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator), platformDetails: tPlatformDetails, @@ -514,7 +514,7 @@ calendarQuery: entryQueryInputValidator, deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator), platformDetails: tPlatformDetails, - watchedIDs: t.list(t.String), + watchedIDs: t.list(tID), signedIdentityKeysBlob: t.maybe(signedIdentityKeysBlobValidator), }); @@ -647,7 +647,7 @@ const updatePasswordRequestInputValidator = tShape({ code: t.String, password: tPassword, - watchedIDs: t.list(t.String), + watchedIDs: t.list(tID), calendarQuery: t.maybe(entryQueryInputValidator), deviceTokenUpdateRequest: t.maybe(deviceTokenUpdateRequestInputValidator), platformDetails: tPlatformDetails, 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 @@ -231,7 +231,7 @@ return assertWithValidator(converted, validator); } - if (validator.meta.kind === 'maybe') { + if (validator.meta.kind === 'maybe' || validator.meta.kind === 'subtype') { return convertObject( validator.meta.type, input, diff --git a/keyserver/src/utils/validation-utils.test.js b/keyserver/src/utils/validation-utils.test.js --- a/keyserver/src/utils/validation-utils.test.js +++ b/keyserver/src/utils/validation-utils.test.js @@ -106,4 +106,17 @@ convertClientIDsToServerIDs('0', validator, clientData), ).toStrictEqual(serverData); }); + + it('should convert a refinement', () => { + const validator = t.refinement(tID, () => true); + const serverData = '1'; + const clientData = '0|1'; + + expect( + convertServerIDsToClientIDs('0', validator, serverData), + ).toStrictEqual(clientData); + expect( + convertClientIDsToServerIDs('0', validator, clientData), + ).toStrictEqual(serverData); + }); }); diff --git a/lib/utils/avatar-utils.js b/lib/utils/avatar-utils.js --- a/lib/utils/avatar-utils.js +++ b/lib/utils/avatar-utils.js @@ -3,7 +3,7 @@ import t from 'tcomb'; import type { TUnion, TInterface } from 'tcomb'; -import { tRegex, tShape, tString } from './validation-utils.js'; +import { tRegex, tShape, tString, tID } from './validation-utils.js'; import { validHexColorRegex } from '../shared/account-utils.js'; import { onlyOneEmojiRegex } from '../shared/emojis.js'; import type { @@ -22,7 +22,7 @@ const imageAvatarDBContentValidator: TInterface = tShape({ type: tString('image'), - uploadID: t.String, + uploadID: tID, }); const ensAvatarDBContentValidator: TInterface = tShape({ diff --git a/lib/utils/validation-utils.js b/lib/utils/validation-utils.js --- a/lib/utils/validation-utils.js +++ b/lib/utils/validation-utils.js @@ -82,13 +82,13 @@ const tMediaMessagePhoto: TInterface = tShape({ type: tString('photo'), - uploadID: t.String, + uploadID: tID, }); const tMediaMessageVideo: TInterface = tShape({ type: tString('video'), - uploadID: t.String, - thumbnailUploadID: t.String, + uploadID: tID, + thumbnailUploadID: tID, }); const tMediaMessageMedia: TUnion = t.union([