Page MenuHomePhorge

D7572.1765060625.diff
No OneTemporary

Size
24 KB
Referenced Files
None
Subscribers
None

D7572.1765060625.diff

diff --git a/keyserver/src/responders/responder-validators.test.js b/keyserver/src/responders/responder-validators.test.js
new file mode 100644
--- /dev/null
+++ b/keyserver/src/responders/responder-validators.test.js
@@ -0,0 +1,333 @@
+// @flow
+
+import {
+ logInResponseValidator,
+ registerResponseValidator,
+ logOutResponseValidator,
+} from './user-responders.js';
+
+describe('user responder validators', () => {
+ it('should validate logout response', () => {
+ const response = { currentUserInfo: { id: '93078', anonymous: true } };
+ expect(logOutResponseValidator.is(response)).toBe(true);
+ response.currentUserInfo.anonymous = false;
+ expect(logOutResponseValidator.is(response)).toBe(false);
+ });
+
+ it('should validate register response', () => {
+ const response = {
+ id: '93079',
+ rawMessageInfos: [
+ {
+ type: 1,
+ threadID: '93095',
+ creatorID: '93079',
+ time: 1682086407469,
+ initialThreadState: {
+ type: 6,
+ name: null,
+ parentThreadID: '1',
+ color: '648caa',
+ memberIDs: ['256', '93079'],
+ },
+ id: '93110',
+ },
+ {
+ type: 0,
+ threadID: '93095',
+ creatorID: '256',
+ time: 1682086407575,
+ text: 'welcome to Comm!',
+ id: '93113',
+ },
+ ],
+ currentUserInfo: { id: '93079', username: 'user' },
+ cookieChange: {
+ threadInfos: {
+ '1': {
+ id: '1',
+ type: 12,
+ name: 'GENESIS',
+ description: 'desc',
+ color: 'c85000',
+ creationTime: 1672934346213,
+ parentThreadID: null,
+ members: [
+ {
+ id: '256',
+ role: '83796',
+ permissions: {
+ know_of: { value: true, source: '1' },
+ membership: { value: false, source: null },
+ visible: { value: true, source: '1' },
+ voiced: { value: true, source: '1' },
+ edit_entries: { value: true, source: '1' },
+ edit_thread: { value: true, source: '1' },
+ edit_thread_description: { value: true, source: '1' },
+ edit_thread_color: { value: true, source: '1' },
+ delete_thread: { value: true, source: '1' },
+ create_subthreads: { value: true, source: '1' },
+ create_sidebars: { value: true, source: '1' },
+ join_thread: { value: false, source: null },
+ edit_permissions: { value: false, source: null },
+ add_members: { value: true, source: '1' },
+ remove_members: { value: true, source: '1' },
+ change_role: { value: true, source: '1' },
+ leave_thread: { value: false, source: null },
+ react_to_message: { value: true, source: '1' },
+ edit_message: { value: true, source: '1' },
+ },
+ isSender: false,
+ },
+ ],
+ roles: {
+ '83795': {
+ id: '83795',
+ name: 'Members',
+ permissions: {
+ know_of: true,
+ visible: true,
+ descendant_open_know_of: true,
+ descendant_open_visible: true,
+ descendant_opentoplevel_join_thread: true,
+ },
+ isDefault: true,
+ },
+ },
+ currentUser: {
+ role: '83795',
+ permissions: {
+ know_of: { value: true, source: '1' },
+ membership: { value: false, source: null },
+ visible: { value: true, source: '1' },
+ voiced: { value: false, source: null },
+ edit_entries: { value: false, source: null },
+ edit_thread: { value: false, source: null },
+ edit_thread_description: { value: false, source: null },
+ edit_thread_color: { value: false, source: null },
+ delete_thread: { value: false, source: null },
+ create_subthreads: { value: false, source: null },
+ create_sidebars: { value: false, source: null },
+ join_thread: { value: false, source: null },
+ edit_permissions: { value: false, source: null },
+ add_members: { value: false, source: null },
+ remove_members: { value: false, source: null },
+ change_role: { value: false, source: null },
+ leave_thread: { value: false, source: null },
+ react_to_message: { value: false, source: null },
+ edit_message: { value: false, source: null },
+ },
+ subscription: { home: true, pushNotifs: true },
+ unread: true,
+ },
+ repliesCount: 0,
+ containingThreadID: null,
+ community: null,
+ },
+ },
+ userInfos: [
+ { id: '5', username: 'commbot' },
+ { id: '256', username: 'ashoat' },
+ { id: '93079', username: 'temp_user7' },
+ ],
+ },
+ };
+
+ expect(registerResponseValidator.is(response)).toBe(true);
+ response.cookieChange.userInfos = undefined;
+ expect(registerResponseValidator.is(response)).toBe(false);
+ });
+
+ it('should validate login response', () => {
+ const response = {
+ currentUserInfo: { id: '93079', username: 'temp_user7' },
+ rawMessageInfos: [
+ {
+ type: 0,
+ id: '93115',
+ threadID: '93094',
+ time: 1682086407577,
+ creatorID: '5',
+ text: 'This is your private chat, where you can set',
+ },
+ {
+ type: 1,
+ id: '93111',
+ threadID: '93094',
+ time: 1682086407467,
+ creatorID: '93079',
+ initialThreadState: {
+ type: 7,
+ name: 'temp_user7',
+ parentThreadID: '1',
+ color: '575757',
+ memberIDs: ['93079'],
+ },
+ },
+ ],
+ truncationStatuses: { '93094': 'exhaustive', '93095': 'exhaustive' },
+ serverTime: 1682086579416,
+ userInfos: [
+ { id: '5', username: 'commbot' },
+ { id: '256', username: 'ashoat' },
+ { id: '93079', username: 'temp_user7' },
+ ],
+ cookieChange: {
+ threadInfos: {
+ '1': {
+ id: '1',
+ type: 12,
+ name: 'GENESIS',
+ description:
+ 'This is the first community on Comm. In the future it will',
+ color: 'c85000',
+ creationTime: 1672934346213,
+ parentThreadID: null,
+ members: [
+ {
+ id: '256',
+ role: '83796',
+ permissions: {
+ know_of: { value: true, source: '1' },
+ membership: { value: false, source: null },
+ visible: { value: true, source: '1' },
+ voiced: { value: true, source: '1' },
+ edit_entries: { value: true, source: '1' },
+ edit_thread: { value: true, source: '1' },
+ edit_thread_description: { value: true, source: '1' },
+ edit_thread_color: { value: true, source: '1' },
+ delete_thread: { value: true, source: '1' },
+ create_subthreads: { value: true, source: '1' },
+ create_sidebars: { value: true, source: '1' },
+ join_thread: { value: false, source: null },
+ edit_permissions: { value: false, source: null },
+ add_members: { value: true, source: '1' },
+ remove_members: { value: true, source: '1' },
+ change_role: { value: true, source: '1' },
+ leave_thread: { value: false, source: null },
+ react_to_message: { value: true, source: '1' },
+ edit_message: { value: true, source: '1' },
+ },
+ isSender: false,
+ },
+ {
+ id: '93079',
+ role: '83795',
+ permissions: {
+ know_of: { value: true, source: '1' },
+ membership: { value: false, source: null },
+ visible: { value: true, source: '1' },
+ voiced: { value: false, source: null },
+ edit_entries: { value: false, source: null },
+ edit_thread: { value: false, source: null },
+ edit_thread_description: { value: false, source: null },
+ edit_thread_color: { value: false, source: null },
+ delete_thread: { value: false, source: null },
+ create_subthreads: { value: false, source: null },
+ create_sidebars: { value: false, source: null },
+ join_thread: { value: false, source: null },
+ edit_permissions: { value: false, source: null },
+ add_members: { value: false, source: null },
+ remove_members: { value: false, source: null },
+ change_role: { value: false, source: null },
+ leave_thread: { value: false, source: null },
+ react_to_message: { value: false, source: null },
+ edit_message: { value: false, source: null },
+ },
+ isSender: false,
+ },
+ ],
+ roles: {
+ '83795': {
+ id: '83795',
+ name: 'Members',
+ permissions: {
+ know_of: true,
+ visible: true,
+ descendant_open_know_of: true,
+ descendant_open_visible: true,
+ descendant_opentoplevel_join_thread: true,
+ },
+ isDefault: true,
+ },
+ '83796': {
+ id: '83796',
+ name: 'Admins',
+ permissions: {
+ know_of: true,
+ visible: true,
+ voiced: true,
+ react_to_message: true,
+ edit_message: true,
+ edit_entries: true,
+ edit_thread: true,
+ edit_thread_color: true,
+ edit_thread_description: true,
+ create_subthreads: true,
+ create_sidebars: true,
+ add_members: true,
+ delete_thread: true,
+ remove_members: true,
+ change_role: true,
+ descendant_know_of: true,
+ descendant_visible: true,
+ descendant_toplevel_join_thread: true,
+ child_join_thread: true,
+ descendant_voiced: true,
+ descendant_edit_entries: true,
+ descendant_edit_thread: true,
+ descendant_edit_thread_color: true,
+ descendant_edit_thread_description: true,
+ descendant_toplevel_create_subthreads: true,
+ descendant_toplevel_create_sidebars: true,
+ descendant_add_members: true,
+ descendant_delete_thread: true,
+ descendant_edit_permissions: true,
+ descendant_remove_members: true,
+ descendant_change_role: true,
+ },
+ isDefault: false,
+ },
+ },
+ currentUser: {
+ role: '83795',
+ permissions: {
+ know_of: { value: true, source: '1' },
+ membership: { value: false, source: null },
+ visible: { value: true, source: '1' },
+ voiced: { value: false, source: null },
+ edit_entries: { value: false, source: null },
+ edit_thread: { value: false, source: null },
+ edit_thread_description: { value: false, source: null },
+ edit_thread_color: { value: false, source: null },
+ delete_thread: { value: false, source: null },
+ create_subthreads: { value: false, source: null },
+ create_sidebars: { value: false, source: null },
+ join_thread: { value: false, source: null },
+ edit_permissions: { value: false, source: null },
+ add_members: { value: false, source: null },
+ remove_members: { value: false, source: null },
+ change_role: { value: false, source: null },
+ leave_thread: { value: false, source: null },
+ react_to_message: { value: false, source: null },
+ edit_message: { value: false, source: null },
+ },
+ subscription: { home: true, pushNotifs: true },
+ unread: true,
+ },
+ repliesCount: 0,
+ containingThreadID: null,
+ community: null,
+ },
+ },
+ userInfos: [],
+ },
+ rawEntryInfos: [],
+ };
+
+ expect(logInResponseValidator.is(response)).toBe(true);
+ expect(
+ logInResponseValidator.is({ ...response, currentUserInfo: undefined }),
+ ).toBe(false);
+ });
+});
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
@@ -3,10 +3,14 @@
import type { Utility as OlmUtility } from '@commapp/olm';
import invariant from 'invariant';
import { ErrorTypes, SiweMessage } from 'siwe';
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
import bcrypt from 'twin-bcrypt';
-import { baseLegalPolicies, policies } from 'lib/facts/policies.js';
+import {
+ baseLegalPolicies,
+ policies,
+ policyTypeValidator,
+} from 'lib/facts/policies.js';
import { hasMinCodeVersion } from 'lib/shared/version-utils.js';
import type {
ResetPasswordRequest,
@@ -33,18 +37,33 @@
IdentityKeysBlob,
SignedIdentityKeysBlob,
} from 'lib/types/crypto-types.js';
-import type { CalendarQuery } from 'lib/types/entry-types.js';
-import { defaultNumberPerThread } from 'lib/types/message-types.js';
+import {
+ type CalendarQuery,
+ rawEntryInfoValidator,
+} from 'lib/types/entry-types.js';
+import {
+ defaultNumberPerThread,
+ rawMessageInfoValidator,
+ messageTruncationStatusesValidator,
+} from 'lib/types/message-types.js';
import type {
SIWEAuthRequest,
SIWEMessage,
SIWESocialProof,
} from 'lib/types/siwe-types.js';
-import type {
- SubscriptionUpdateRequest,
- SubscriptionUpdateResponse,
+import {
+ type SubscriptionUpdateRequest,
+ type SubscriptionUpdateResponse,
+ threadSubscriptionValidator,
} from 'lib/types/subscription-types.js';
-import type { PasswordUpdate } from 'lib/types/user-types.js';
+import { rawThreadInfoValidator } from 'lib/types/thread-types.js';
+import {
+ type PasswordUpdate,
+ loggedOutUserInfoValidator,
+ loggedInUserInfoValidator,
+ oldLoggedInUserInfoValidator,
+ userInfoValidator,
+} from 'lib/types/user-types.js';
import { updateUserAvatarRequestValidator } from 'lib/utils/avatar-utils.js';
import {
identityKeysBlobValidator,
@@ -66,6 +85,7 @@
tEmail,
tOldValidUsername,
tRegex,
+ tID,
} from 'lib/utils/validation-utils.js';
import {
@@ -118,6 +138,11 @@
}),
});
+export const subscriptionUpdateResponseValidator: TInterface<SubscriptionUpdateResponse> =
+ tShape<SubscriptionUpdateResponse>({
+ threadSubscription: threadSubscriptionValidator,
+ });
+
async function userSubscriptionUpdateResponder(
viewer: Viewer,
input: any,
@@ -163,6 +188,11 @@
await checkAndSendPasswordResetEmail(request);
}
+export const logOutResponseValidator: TInterface<LogOutResponse> =
+ tShape<LogOutResponse>({
+ currentUserInfo: loggedOutUserInfoValidator,
+ });
+
async function logOutResponder(viewer: Viewer): Promise<LogOutResponse> {
await validateInput(viewer, null, null);
if (viewer.loggedIn) {
@@ -216,6 +246,20 @@
signedIdentityKeysBlob: t.maybe(signedIdentityKeysBlobValidator),
});
+export const registerResponseValidator: TInterface<RegisterResponse> =
+ tShape<RegisterResponse>({
+ id: t.String,
+ rawMessageInfos: t.list(rawMessageInfoValidator),
+ currentUserInfo: t.union([
+ oldLoggedInUserInfoValidator,
+ loggedInUserInfoValidator,
+ ]),
+ cookieChange: tShape({
+ threadInfos: t.dict(t.String, rawThreadInfoValidator),
+ userInfos: t.list(userInfoValidator),
+ }),
+ });
+
async function accountCreationResponder(
viewer: Viewer,
input: any,
@@ -363,6 +407,24 @@
signedIdentityKeysBlob: t.maybe(signedIdentityKeysBlobValidator),
});
+export const logInResponseValidator: TInterface<LogInResponse> =
+ tShape<LogInResponse>({
+ currentUserInfo: t.union([
+ loggedInUserInfoValidator,
+ oldLoggedInUserInfoValidator,
+ ]),
+ rawMessageInfos: t.list(rawMessageInfoValidator),
+ truncationStatuses: messageTruncationStatusesValidator,
+ userInfos: t.list(userInfoValidator),
+ rawEntryInfos: t.maybe(t.list(rawEntryInfoValidator)),
+ serverTime: t.Number,
+ cookieChange: tShape({
+ threadInfos: t.dict(tID, rawThreadInfoValidator),
+ userInfos: t.list(userInfoValidator),
+ }),
+ notAcknowledgedPolicies: t.maybe(t.list(policyTypeValidator)),
+ });
+
async function logInResponder(
viewer: Viewer,
input: any,
diff --git a/lib/facts/policies.js b/lib/facts/policies.js
--- a/lib/facts/policies.js
+++ b/lib/facts/policies.js
@@ -1,5 +1,7 @@
// @flow
+import t, { type TEnums } from 'tcomb';
+
import { values } from '../utils/objects.js';
export const policyTypes = Object.freeze({
@@ -9,5 +11,6 @@
export const policies: $ReadOnlyArray<string> = values(policyTypes);
export type PolicyType = $Values<typeof policyTypes>;
+export const policyTypeValidator: TEnums = t.enums.of(policies);
export const baseLegalPolicies = [policyTypes.tosAndPrivacyPolicy];
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
@@ -1,5 +1,7 @@
// @flow
+import t, { type TInterface } from 'tcomb';
+
import type { SignedIdentityKeysBlob } from './crypto-types.js';
import type { PlatformDetails } from './device-types.js';
import type {
@@ -7,21 +9,22 @@
CalendarResult,
RawEntryInfo,
} from './entry-types.js';
-import type {
- RawMessageInfo,
- MessageTruncationStatuses,
- GenericMessagesResult,
+import {
+ type RawMessageInfo,
+ type MessageTruncationStatuses,
+ type GenericMessagesResult,
} from './message-types.js';
import type { PreRequestUserState } from './session-types.js';
-import type { RawThreadInfo } from './thread-types.js';
-import type {
- UserInfo,
- LoggedOutUserInfo,
- LoggedInUserInfo,
- OldLoggedInUserInfo,
+import { type RawThreadInfo } from './thread-types.js';
+import {
+ type UserInfo,
+ type LoggedOutUserInfo,
+ type LoggedInUserInfo,
+ type OldLoggedInUserInfo,
} from './user-types.js';
import type { PolicyType } from '../facts/policies.js';
import { values } from '../utils/objects.js';
+import { tShape } from '../utils/validation-utils.js';
export type ResetPasswordRequest = {
+usernameOrEmail: string,
@@ -175,10 +178,6 @@
DEFAULT_NOTIFICATIONS: 'default_user_notifications',
});
-export type DefaultNotificationPayload = {
- +default_user_notifications: ?NotificationTypes,
-};
-
export const notificationTypes = Object.freeze({
FOCUSED: 'focused',
BADGE_ONLY: 'badge_only',
@@ -189,3 +188,12 @@
export const notificationTypeValues: $ReadOnlyArray<NotificationTypes> =
values(notificationTypes);
+
+export type DefaultNotificationPayload = {
+ +default_user_notifications: ?NotificationTypes,
+};
+
+export const defaultNotificationPayloadValidator: TInterface<DefaultNotificationPayload> =
+ tShape<DefaultNotificationPayload>({
+ default_user_notifications: t.maybe(t.enums.of(notificationTypeValues)),
+ });
diff --git a/lib/types/message-types.js b/lib/types/message-types.js
--- a/lib/types/message-types.js
+++ b/lib/types/message-types.js
@@ -1,7 +1,12 @@
// @flow
import invariant from 'invariant';
-import t, { type TUnion, type TInterface } from 'tcomb';
+import t, {
+ type TUnion,
+ type TDict,
+ type TEnums,
+ type TInterface,
+} from 'tcomb';
import { type ClientDBMediaInfo } from './media-types.js';
import { messageTypes, type MessageType } from './message-types-enum.js';
@@ -133,6 +138,7 @@
} from './messages/update-relationship.js';
import { type RelativeUserInfo, type UserInfos } from './user-types.js';
import type { CallServerEndpointResultInfoInterface } from '../utils/call-server-endpoint.js';
+import { values } from '../utils/objects.js';
import { tNumber, tShape, tID } from '../utils/validation-utils.js';
const composableMessageTypes = new Set([
@@ -532,9 +538,14 @@
);
return ourMessageTruncationStatus;
}
+export const messageTruncationStatusValidator: TEnums = t.enums.of(
+ values(messageTruncationStatus),
+);
export type MessageTruncationStatuses = {
[threadID: string]: MessageTruncationStatus,
};
+export const messageTruncationStatusesValidator: TDict<MessageTruncationStatuses> =
+ t.dict(tID, messageTruncationStatusValidator);
export type ThreadCursors = { +[threadID: string]: ?string };
diff --git a/lib/types/relationship-types.js b/lib/types/relationship-types.js
--- a/lib/types/relationship-types.js
+++ b/lib/types/relationship-types.js
@@ -1,7 +1,10 @@
// @flow
+import type { TRefinement } from 'tcomb';
+
import type { AccountUserInfo } from './user-types.js';
import { values } from '../utils/objects.js';
+import { tNumEnum } from '../utils/validation-utils.js';
export const undirectedStatus = Object.freeze({
KNOW_OF: 0,
@@ -24,6 +27,9 @@
BOTH_BLOCKED: 6,
});
export type UserRelationshipStatus = $Values<typeof userRelationshipStatus>;
+export const userRelationshipStatusValidator: TRefinement<number> = tNumEnum(
+ values(userRelationshipStatus),
+);
export const relationshipActions = Object.freeze({
FRIEND: 'friend',
diff --git a/lib/types/user-types.js b/lib/types/user-types.js
--- a/lib/types/user-types.js
+++ b/lib/types/user-types.js
@@ -1,9 +1,18 @@
// @flow
-import type { DefaultNotificationPayload } from './account-types.js';
-import type { ClientAvatar } from './avatar-types.js';
-import type { UserRelationshipStatus } from './relationship-types.js';
+import t, { type TInterface } from 'tcomb';
+
+import {
+ type DefaultNotificationPayload,
+ defaultNotificationPayloadValidator,
+} from './account-types.js';
+import { type ClientAvatar, clientAvatarValidator } from './avatar-types.js';
+import {
+ type UserRelationshipStatus,
+ userRelationshipStatusValidator,
+} from './relationship-types.js';
import type { UserInconsistencyReportCreationRequest } from './report-types.js';
+import { tBool, tShape } from '../utils/validation-utils.js';
export type GlobalUserInfo = {
+id: string,
@@ -23,6 +32,12 @@
+relationshipStatus?: UserRelationshipStatus,
+avatar?: ?ClientAvatar,
};
+export const userInfoValidator: TInterface<UserInfo> = tShape<UserInfo>({
+ id: t.String,
+ username: t.maybe(t.String),
+ relationshipStatus: t.maybe(userRelationshipStatusValidator),
+ avatar: t.maybe(clientAvatarValidator),
+});
export type UserInfos = { +[id: string]: UserInfo };
export type AccountUserInfo = {
@@ -50,6 +65,13 @@
+email: string,
+emailVerified: boolean,
};
+export const oldLoggedInUserInfoValidator: TInterface<OldLoggedInUserInfo> =
+ tShape<OldLoggedInUserInfo>({
+ id: t.String,
+ username: t.String,
+ email: t.String,
+ emailVerified: t.Boolean,
+ });
export type LoggedInUserInfo = {
+id: string,
@@ -57,11 +79,20 @@
+settings?: DefaultNotificationPayload,
+avatar?: ?ClientAvatar,
};
+export const loggedInUserInfoValidator: TInterface<LoggedInUserInfo> =
+ tShape<LoggedInUserInfo>({
+ id: t.String,
+ username: t.String,
+ settings: t.maybe(defaultNotificationPayloadValidator),
+ avatar: t.maybe(clientAvatarValidator),
+ });
export type LoggedOutUserInfo = {
+id: string,
+anonymous: true,
};
+export const loggedOutUserInfoValidator: TInterface<LoggedOutUserInfo> =
+ tShape<LoggedOutUserInfo>({ id: t.String, anonymous: tBool(true) });
export type OldCurrentUserInfo = OldLoggedInUserInfo | LoggedOutUserInfo;
export type CurrentUserInfo = LoggedInUserInfo | LoggedOutUserInfo;

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 6, 10:37 PM (23 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5841135
Default Alt Text
D7572.1765060625.diff (24 KB)

Event Timeline