Page MenuHomePhabricator

D7685.id25930.diff
No OneTemporary

D7685.id25930.diff

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
@@ -4,28 +4,33 @@
import type { TInterface } from 'tcomb';
import { filteredThreadIDs } from 'lib/selectors/calendar-filter-selectors.js';
-import type {
- CalendarQuery,
- SaveEntryRequest,
- CreateEntryRequest,
- DeleteEntryRequest,
- DeleteEntryResponse,
- RestoreEntryRequest,
- RestoreEntryResponse,
- FetchEntryInfosResponse,
- DeltaEntryInfosResult,
- SaveEntryResponse,
+import {
+ type CalendarQuery,
+ type SaveEntryRequest,
+ type CreateEntryRequest,
+ type DeleteEntryRequest,
+ type DeleteEntryResponse,
+ type RestoreEntryRequest,
+ type RestoreEntryResponse,
+ type FetchEntryInfosResponse,
+ type DeltaEntryInfosResult,
+ type SaveEntryResponse,
+ rawEntryInfoValidator,
} from 'lib/types/entry-types.js';
import {
type CalendarFilter,
calendarThreadFilterTypes,
} from 'lib/types/filter-types.js';
-import type {
- FetchEntryRevisionInfosResult,
- FetchEntryRevisionInfosRequest,
+import {
+ type FetchEntryRevisionInfosResult,
+ type FetchEntryRevisionInfosRequest,
+ historyRevisionInfoValidator,
} from 'lib/types/history-types.js';
+import { rawMessageInfoValidator } from 'lib/types/message-types.js';
+import { serverCreateUpdatesResponseValidator } from 'lib/types/update-types.js';
+import { accountUserInfoValidator } from 'lib/types/user-types.js';
import { ServerError } from 'lib/utils/errors.js';
-import { tString, tShape, tDate } from 'lib/utils/validation-utils.js';
+import { tString, tShape, tDate, tID } from 'lib/utils/validation-utils.js';
import createEntry from '../creators/entry-creator.js';
import { deleteEntry, restoreEntry } from '../deleters/entry-deleters.js';
@@ -123,6 +128,12 @@
}
}
+export const fetchEntryInfosResponseValidator: TInterface<FetchEntryInfosResponse> =
+ tShape<FetchEntryInfosResponse>({
+ rawEntryInfos: t.list(rawEntryInfoValidator),
+ userInfos: t.dict(t.String, accountUserInfoValidator),
+ });
+
async function entryFetchResponder(
viewer: Viewer,
input: any,
@@ -140,6 +151,11 @@
id: t.String,
});
+export const fetchEntryRevisionInfosResultValidator: TInterface<FetchEntryRevisionInfosResult> =
+ tShape<FetchEntryRevisionInfosResult>({
+ result: t.list(historyRevisionInfoValidator),
+ });
+
async function entryRevisionFetchResponder(
viewer: Viewer,
input: any,
@@ -160,6 +176,13 @@
calendarQuery: t.maybe(newEntryQueryInputValidator),
});
+export const saveEntryResponseValidator: TInterface<SaveEntryResponse> =
+ tShape<SaveEntryResponse>({
+ entryID: tID,
+ newMessageInfos: t.list(rawMessageInfoValidator),
+ updatesResult: serverCreateUpdatesResponseValidator,
+ });
+
async function entryCreationResponder(
viewer: Viewer,
input: any,
@@ -195,6 +218,13 @@
calendarQuery: t.maybe(newEntryQueryInputValidator),
});
+export const deleteEntryResponseValidator: TInterface<DeleteEntryResponse> =
+ tShape<DeleteEntryResponse>({
+ newMessageInfos: t.list(rawMessageInfoValidator),
+ threadID: tID,
+ updatesResult: serverCreateUpdatesResponseValidator,
+ });
+
async function entryDeletionResponder(
viewer: Viewer,
input: any,
@@ -211,6 +241,12 @@
calendarQuery: t.maybe(newEntryQueryInputValidator),
});
+export const restoreEntryResponseValidator: TInterface<RestoreEntryResponse> =
+ tShape<RestoreEntryResponse>({
+ newMessageInfos: t.list(rawMessageInfoValidator),
+ updatesResult: serverCreateUpdatesResponseValidator,
+ });
+
async function entryRestorationResponder(
viewer: Viewer,
input: any,
@@ -220,6 +256,13 @@
return await restoreEntry(viewer, request);
}
+export const deltaEntryInfosResultValidator: TInterface<DeltaEntryInfosResult> =
+ tShape<DeltaEntryInfosResult>({
+ rawEntryInfos: t.list(rawEntryInfoValidator),
+ deletedEntryIDs: t.list(tID),
+ userInfos: t.dict(t.String, accountUserInfoValidator),
+ });
+
async function calendarQueryUpdateResponder(
viewer: Viewer,
input: any,
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
@@ -1,10 +1,13 @@
// @flow
-import t from 'tcomb';
+import t, { type TUnion } from 'tcomb';
import type { GetSessionPublicKeysArgs } from 'lib/types/request-types.js';
-import type { SessionPublicKeys } from 'lib/types/session-types.js';
-import { tShape } from 'lib/utils/validation-utils.js';
+import {
+ type SessionPublicKeys,
+ sessionPublicKeysValidator,
+} from 'lib/types/session-types.js';
+import { tShape, tNull } from 'lib/utils/validation-utils.js';
import { fetchSessionPublicKeys } from '../fetchers/key-fetchers.js';
import type { Viewer } from '../session/viewer.js';
@@ -14,10 +17,14 @@
session: t.String,
});
+type GetSessionPublicKeysResponse = SessionPublicKeys | null;
+export const getSessionPublicKeysResponseValidator: TUnion<GetSessionPublicKeysResponse> =
+ t.union([sessionPublicKeysValidator, tNull]);
+
async function getSessionPublicKeysResponder(
viewer: Viewer,
input: any,
-): Promise<SessionPublicKeys | null> {
+): Promise<GetSessionPublicKeysResponse> {
if (!viewer.loggedIn) {
return null;
}
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,11 +1,12 @@
// @flow
-import t from 'tcomb';
+import t, { 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 createMessageReport from '../creators/message-report-creator.js';
@@ -16,6 +17,9 @@
messageID: t.String,
});
+export const messageReportCreationResultValidator: TInterface<MessageReportCreationResult> =
+ tShape<MessageReportCreationResult>({ messageInfo: rawMessageInfoValidator });
+
async function messageReportCreationResponder(
viewer: Viewer,
input: any,
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
@@ -1,6 +1,6 @@
// @flow
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
import {
type RelationshipRequest,
@@ -18,6 +18,13 @@
userIDs: t.list(t.String),
});
+export const relationshipErrorsValidator: TInterface<RelationshipErrors> =
+ tShape<RelationshipErrors>({
+ invalid_user: t.maybe(t.list(t.String)),
+ already_friends: t.maybe(t.list(t.String)),
+ user_blocked: t.maybe(t.list(t.String)),
+ });
+
async function updateRelationshipsResponder(
viewer: Viewer,
input: any,
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
@@ -1,5 +1,23 @@
// @flow
+import {
+ setThreadUnreadStatusResult,
+ updateActivityResultValidator,
+} from 'lib/types/activity-types.js';
+
+import {
+ fetchEntryInfosResponseValidator,
+ fetchEntryRevisionInfosResultValidator,
+ saveEntryResponseValidator,
+ deleteEntryResponseValidator,
+ deltaEntryInfosResultValidator,
+ restoreEntryResponseValidator,
+} from './entry-responders.js';
+import { getSessionPublicKeysResponseValidator } from './keys-responders.js';
+import { messageReportCreationResultValidator } from './message-report-responder.js';
+import { relationshipErrorsValidator } from './relationship-responders.js';
+import { userSearchResultValidator } from './search-responders.js';
+import { siweNonceResponseValidator } from './siwe-nonce-responders.js';
import {
logInResponseValidator,
registerResponseValidator,
@@ -331,3 +349,271 @@
).toBe(false);
});
});
+
+describe('search responder', () => {
+ it('should validate search response', () => {
+ const response = {
+ userInfos: [
+ { id: '83817', username: 'temp_user0' },
+ { id: '83853', username: 'temp_user1' },
+ { id: '83890', username: 'temp_user2' },
+ { id: '83928', username: 'temp_user3' },
+ ],
+ };
+
+ expect(userSearchResultValidator.is(response)).toBe(true);
+ response.userInfos.push({ id: 123 });
+ expect(userSearchResultValidator.is(response)).toBe(false);
+ });
+});
+
+describe('message report responder', () => {
+ it('should validate message report response', () => {
+ const response = {
+ messageInfo: {
+ type: 0,
+ threadID: '101113',
+ creatorID: '5',
+ time: 1682429699746,
+ text: 'text',
+ id: '101121',
+ },
+ };
+
+ expect(messageReportCreationResultValidator.is(response)).toBe(true);
+ response.messageInfo.type = -2;
+ expect(messageReportCreationResultValidator.is(response)).toBe(false);
+ });
+});
+
+describe('relationship responder', () => {
+ it('should validate relationship response', () => {
+ const response = {
+ invalid_user: ['83817', '83890'],
+ already_friends: ['83890'],
+ };
+
+ expect(relationshipErrorsValidator.is(response)).toBe(true);
+ expect(
+ relationshipErrorsValidator.is({ ...response, user_blocked: {} }),
+ ).toBe(false);
+ });
+});
+
+describe('activity responder', () => {
+ it('should validate update activity response', () => {
+ const response = { unfocusedToUnread: ['93095'] };
+ expect(updateActivityResultValidator.is(response)).toBe(true);
+ response.unfocusedToUnread.push(123);
+ expect(updateActivityResultValidator.is(response)).toBe(false);
+ });
+
+ it('should validate set thread unread response', () => {
+ const response = { resetToUnread: false };
+ expect(setThreadUnreadStatusResult.is(response)).toBe(true);
+ expect(setThreadUnreadStatusResult.is({ ...response, unread: false })).toBe(
+ false,
+ );
+ });
+});
+
+describe('keys responder', () => {
+ it('should validate get session public keys response', () => {
+ const response = {
+ identityKey: 'key',
+ oneTimeKey: 'key',
+ };
+
+ expect(getSessionPublicKeysResponseValidator.is(response)).toBe(true);
+ expect(getSessionPublicKeysResponseValidator.is(null)).toBe(true);
+ expect(
+ getSessionPublicKeysResponseValidator.is({
+ ...response,
+ identityKey: undefined,
+ }),
+ ).toBe(false);
+ });
+});
+
+describe('siwe nonce responders', () => {
+ it('should validate siwe nonce response', () => {
+ const response = { nonce: 'nonce' };
+ expect(siweNonceResponseValidator.is(response)).toBe(true);
+ expect(siweNonceResponseValidator.is({ nonce: 123 })).toBe(false);
+ });
+});
+
+describe('entry reponders', () => {
+ it('should validate entry fetch response', () => {
+ const response = {
+ rawEntryInfos: [
+ {
+ id: '92860',
+ threadID: '85068',
+ text: 'text',
+ year: 2023,
+ month: 4,
+ day: 2,
+ creationTime: 1682082939882,
+ creatorID: '83853',
+ deleted: false,
+ },
+ ],
+ userInfos: {
+ '123': {
+ id: '123',
+ username: 'username',
+ },
+ },
+ };
+ expect(fetchEntryInfosResponseValidator.is(response)).toBe(true);
+ expect(
+ fetchEntryInfosResponseValidator.is({
+ ...response,
+ userInfos: undefined,
+ }),
+ ).toBe(false);
+ });
+
+ it('should validate entry revision fetch response', () => {
+ const response = {
+ result: [
+ {
+ id: '93297',
+ authorID: '83853',
+ text: 'text',
+ lastUpdate: 1682603494202,
+ deleted: false,
+ threadID: '83859',
+ entryID: '93270',
+ },
+ {
+ id: '93284',
+ authorID: '83853',
+ text: 'text',
+ lastUpdate: 1682603426996,
+ deleted: true,
+ threadID: '83859',
+ entryID: '93270',
+ },
+ ],
+ };
+ expect(fetchEntryRevisionInfosResultValidator.is(response)).toBe(true);
+ expect(
+ fetchEntryRevisionInfosResultValidator.is({
+ ...response,
+ result: {},
+ }),
+ ).toBe(false);
+ });
+
+ it('should validate entry save response', () => {
+ const response = {
+ entryID: '93270',
+ newMessageInfos: [
+ {
+ type: 9,
+ threadID: '83859',
+ creatorID: '83853',
+ time: 1682603362817,
+ entryID: '93270',
+ date: '2023-04-03',
+ text: 'text',
+ id: '93272',
+ },
+ ],
+ updatesResult: { viewerUpdates: [], userInfos: [] },
+ };
+
+ expect(saveEntryResponseValidator.is(response)).toBe(true);
+ expect(
+ saveEntryResponseValidator.is({
+ ...response,
+ entryID: undefined,
+ }),
+ ).toBe(false);
+ });
+
+ it('should validate entry delete response', () => {
+ const response = {
+ threadID: '83859',
+ newMessageInfos: [
+ {
+ type: 11,
+ threadID: '83859',
+ creatorID: '83853',
+ time: 1682603427038,
+ entryID: '93270',
+ date: '2023-04-03',
+ text: 'text',
+ id: '93285',
+ },
+ ],
+ updatesResult: { viewerUpdates: [], userInfos: [] },
+ };
+ expect(deleteEntryResponseValidator.is(response)).toBe(true);
+ expect(
+ deleteEntryResponseValidator.is({
+ ...response,
+ threadID: undefined,
+ }),
+ ).toBe(false);
+ });
+
+ it('should validate entry restore response', () => {
+ const response = {
+ newMessageInfos: [
+ {
+ type: 11,
+ threadID: '83859',
+ creatorID: '83853',
+ time: 1682603427038,
+ entryID: '93270',
+ date: '2023-04-03',
+ text: 'text',
+ id: '93285',
+ },
+ ],
+ updatesResult: { viewerUpdates: [], userInfos: [] },
+ };
+ expect(restoreEntryResponseValidator.is(response)).toBe(true);
+ expect(
+ restoreEntryResponseValidator.is({
+ ...response,
+ newMessageInfos: undefined,
+ }),
+ ).toBe(false);
+ });
+
+ it('should validate entry delta response', () => {
+ const response = {
+ rawEntryInfos: [
+ {
+ id: '92860',
+ threadID: '85068',
+ text: 'text',
+ year: 2023,
+ month: 4,
+ day: 2,
+ creationTime: 1682082939882,
+ creatorID: '83853',
+ deleted: false,
+ },
+ ],
+ deletedEntryIDs: ['92860'],
+ userInfos: {
+ '123': {
+ id: '123',
+ username: 'username',
+ },
+ },
+ };
+ expect(deltaEntryInfosResultValidator.is(response)).toBe(true);
+ expect(
+ deltaEntryInfosResultValidator.is({
+ ...response,
+ rawEntryInfos: undefined,
+ }),
+ ).toBe(false);
+ });
+});
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
@@ -1,11 +1,12 @@
// @flow
-import t from 'tcomb';
+import t, { type TInterface } from 'tcomb';
import type {
UserSearchRequest,
UserSearchResult,
} from 'lib/types/search-types.js';
+import { globalAccountUserInfoValidator } from 'lib/types/user-types.js';
import { tShape } from 'lib/utils/validation-utils.js';
import { searchForUsers } from '../search/users.js';
@@ -16,6 +17,11 @@
prefix: t.maybe(t.String),
});
+export const userSearchResultValidator: TInterface<UserSearchResult> =
+ tShape<UserSearchResult>({
+ userInfos: t.list(globalAccountUserInfoValidator),
+ });
+
async function userSearchResponder(
viewer: Viewer,
input: any,
diff --git a/keyserver/src/responders/siwe-nonce-responders.js b/keyserver/src/responders/siwe-nonce-responders.js
--- a/keyserver/src/responders/siwe-nonce-responders.js
+++ b/keyserver/src/responders/siwe-nonce-responders.js
@@ -1,11 +1,16 @@
// @flow
import { generateNonce } from 'siwe';
+import t, { type TInterface } from 'tcomb';
import type { SIWENonceResponse } from 'lib/types/siwe-types.js';
+import { tShape } from 'lib/utils/validation-utils.js';
import { createSIWENonceEntry } from '../creators/siwe-nonce-creator.js';
+export const siweNonceResponseValidator: TInterface<SIWENonceResponse> =
+ tShape<SIWENonceResponse>({ nonce: t.String });
+
async function siweNonceResponder(): Promise<SIWENonceResponse> {
const generatedNonce = generateNonce();
await createSIWENonceEntry(generatedNonce);
diff --git a/lib/types/activity-types.js b/lib/types/activity-types.js
--- a/lib/types/activity-types.js
+++ b/lib/types/activity-types.js
@@ -1,5 +1,9 @@
// @flow
+import t, { type TInterface } from 'tcomb';
+
+import { tID, tShape } from '../utils/validation-utils.js';
+
export type ActivityUpdate = {
+focus: boolean,
+threadID: string,
@@ -13,6 +17,10 @@
export type UpdateActivityResult = {
+unfocusedToUnread: $ReadOnlyArray<string>,
};
+export const updateActivityResultValidator: TInterface<UpdateActivityResult> =
+ tShape<UpdateActivityResult>({
+ unfocusedToUnread: t.list(tID),
+ });
export type ActivityUpdateSuccessPayload = {
+activityUpdates: $ReadOnlyArray<ActivityUpdate>,
@@ -32,6 +40,9 @@
export type SetThreadUnreadStatusResult = {
+resetToUnread: boolean,
};
+export const setThreadUnreadStatusResult: TInterface<SetThreadUnreadStatusResult> =
+ tShape<SetThreadUnreadStatusResult>({ resetToUnread: t.Boolean });
+
export type SetThreadUnreadStatusPayload = {
...SetThreadUnreadStatusResult,
+threadID: string,
diff --git a/lib/types/history-types.js b/lib/types/history-types.js
--- a/lib/types/history-types.js
+++ b/lib/types/history-types.js
@@ -1,5 +1,9 @@
// @flow
+import t, { type TInterface } from 'tcomb';
+
+import { tID, tShape } from '../utils/validation-utils.js';
+
export type HistoryMode = 'day' | 'entry';
export type HistoryRevisionInfo = {
@@ -11,6 +15,16 @@
+deleted: boolean,
+threadID: string,
};
+export const historyRevisionInfoValidator: TInterface<HistoryRevisionInfo> =
+ tShape<HistoryRevisionInfo>({
+ id: tID,
+ entryID: tID,
+ authorID: t.String,
+ text: t.String,
+ lastUpdate: t.Number,
+ deleted: t.Boolean,
+ threadID: tID,
+ });
export type FetchEntryRevisionInfosRequest = {
+id: string,
diff --git a/lib/types/session-types.js b/lib/types/session-types.js
--- a/lib/types/session-types.js
+++ b/lib/types/session-types.js
@@ -1,5 +1,7 @@
// @flow
+import t, { type TInterface } from 'tcomb';
+
import type { LogInActionSource } from './account-types.js';
import type { Shape } from './core.js';
import type { CalendarQuery } from './entry-types.js';
@@ -9,6 +11,7 @@
type CurrentUserInfo,
type LoggedOutUserInfo,
} from './user-types.js';
+import { tShape } from '../utils/validation-utils.js';
export const cookieLifetime = 30 * 24 * 60 * 60 * 1000; // in milliseconds
// Interval the server waits after a state check before starting a new one
@@ -107,3 +110,9 @@
+identityKey: string,
+oneTimeKey?: string,
};
+
+export const sessionPublicKeysValidator: TInterface<SessionPublicKeys> =
+ tShape<SessionPublicKeys>({
+ identityKey: t.String,
+ oneTimeKey: t.maybe(t.String),
+ });
diff --git a/lib/types/update-types.js b/lib/types/update-types.js
--- a/lib/types/update-types.js
+++ b/lib/types/update-types.js
@@ -13,6 +13,7 @@
import { type RawThreadInfo, rawThreadInfoValidator } from './thread-types.js';
import {
type UserInfo,
+ userInfoValidator,
type UserInfos,
type LoggedInUserInfo,
loggedInUserInfoValidator,
@@ -400,6 +401,12 @@
+userInfos: $ReadOnlyArray<UserInfo>,
};
+export const serverCreateUpdatesResponseValidator: TInterface<ServerCreateUpdatesResponse> =
+ tShape<ServerCreateUpdatesResponse>({
+ viewerUpdates: t.list(serverUpdateInfoValidator),
+ userInfos: t.list(userInfoValidator),
+ });
+
export type ClientCreateUpdatesResponse = {
+viewerUpdates: $ReadOnlyArray<ClientUpdateInfo>,
+userInfos: $ReadOnlyArray<UserInfo>,
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
@@ -25,6 +25,12 @@
+username: string,
+avatar?: ?ClientAvatar,
};
+export const globalAccountUserInfoValidator: TInterface<GlobalAccountUserInfo> =
+ tShape<GlobalAccountUserInfo>({
+ id: t.String,
+ username: t.String,
+ avatar: t.maybe(clientAvatarValidator),
+ });
export type UserInfo = {
+id: string,
@@ -46,6 +52,13 @@
+relationshipStatus?: UserRelationshipStatus,
+avatar?: ?ClientAvatar,
};
+export const accountUserInfoValidator: TInterface<AccountUserInfo> =
+ tShape<AccountUserInfo>({
+ id: t.String,
+ username: t.String,
+ relationshipStatus: t.maybe(userRelationshipStatusValidator),
+ avatar: t.maybe(clientAvatarValidator),
+ });
export type UserStore = {
+userInfos: UserInfos,
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
@@ -55,7 +55,7 @@
return false;
});
}
-
+const tNull: TIrreducible<null> = t.irreducible('null', x => x === null);
const tDate: TRegex = tRegex(/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/);
const tColor: TRegex = tRegex(validHexColorRegex); // we don't include # char
const tPlatform: TEnums = t.enums.of([
@@ -108,6 +108,7 @@
tShape,
tRegex,
tNumEnum,
+ tNull,
tDate,
tColor,
tPlatform,

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 2, 12:20 PM (19 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2607521
Default Alt Text
D7685.id25930.diff (21 KB)

Event Timeline