Page MenuHomePhabricator

D8879.id30125.diff
No OneTemporary

D8879.id30125.diff

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
@@ -8,6 +8,11 @@
hasMinStateVersion,
} from 'lib/shared/version-utils.js';
import { type PlatformDetails } from 'lib/types/device-types.js';
+import {
+ convertClientIDsToServerIDs,
+ convertObject,
+ convertServerIDsToClientIDs,
+} from 'lib/utils/conversion-utils.js';
import { ServerError } from 'lib/utils/errors.js';
import {
tCookie,
@@ -16,9 +21,6 @@
tPlatformDetails,
assertWithValidator,
ashoatKeyserverID,
- convertClientIDsToServerIDs,
- convertObject,
- convertServerIDsToClientIDs,
} from 'lib/utils/validation-utils.js';
import { fetchNotAcknowledgedPolicies } from '../fetchers/policy-acknowledgment-fetchers.js';
diff --git a/lib/selectors/socket-selectors.js b/lib/selectors/socket-selectors.js
--- a/lib/selectors/socket-selectors.js
+++ b/lib/selectors/socket-selectors.js
@@ -36,13 +36,10 @@
userInfosValidator,
} from '../types/user-types.js';
import { getConfig } from '../utils/config.js';
+import { convertClientIDsToServerIDs } from '../utils/conversion-utils.js';
import { minimumOneTimeKeysRequired } from '../utils/crypto-utils.js';
import { values, hash } from '../utils/objects.js';
-import {
- tID,
- convertClientIDsToServerIDs,
- ashoatKeyserverID,
-} from '../utils/validation-utils.js';
+import { tID, ashoatKeyserverID } from '../utils/validation-utils.js';
const queuedReports: (
state: AppState,
diff --git a/lib/utils/validation-utils.js b/lib/utils/conversion-utils.js
copy from lib/utils/validation-utils.js
copy to lib/utils/conversion-utils.js
--- a/lib/utils/validation-utils.js
+++ b/lib/utils/conversion-utils.js
@@ -1,109 +1,14 @@
// @flow
-import invariant from 'invariant';
import _mapKeys from 'lodash/fp/mapKeys.js';
import _mapValues from 'lodash/fp/mapValues.js';
-import t from 'tcomb';
-import type {
- TStructProps,
- TIrreducible,
- TRefinement,
- TEnums,
- TInterface,
- TUnion,
- TType,
-} from 'tcomb';
+import type { TInterface, TType } from 'tcomb';
+import { assertWithValidator, tID } from './validation-utils.js';
import {
- validEmailRegex,
- oldValidUsernameRegex,
- validHexColorRegex,
-} from '../shared/account-utils.js';
-import type { PlatformDetails } from '../types/device-types';
-import type {
- MediaMessageServerDBContent,
- PhotoMessageServerDBContent,
- VideoMessageServerDBContent,
-} from '../types/messages/media';
-
-function tBool(value: boolean): TIrreducible<boolean> {
- return t.irreducible(value.toString(), x => x === value);
-}
-
-function tString(value: string): TIrreducible<string> {
- return t.irreducible(`'${value}'`, x => x === value);
-}
-
-function tNumber(value: number): TIrreducible<number> {
- return t.irreducible(value.toString(), x => x === value);
-}
-
-function tShape<T>(spec: TStructProps<T>): TInterface<T> {
- return t.interface(spec, { strict: true });
-}
-
-type TRegex = TRefinement<string>;
-function tRegex(regex: RegExp): TRegex {
- return t.refinement(t.String, val => regex.test(val));
-}
-
-function tNumEnum(nums: $ReadOnlyArray<number>): TRefinement<number> {
- return t.refinement(t.Number, (input: number) => {
- for (const num of nums) {
- if (input === num) {
- return true;
- }
- }
- 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([
- 'ios',
- 'android',
- 'web',
- 'windows',
- 'macos',
-]);
-const tDeviceType: TEnums = t.enums.of(['ios', 'android']);
-const tPlatformDetails: TInterface<PlatformDetails> = tShape({
- platform: tPlatform,
- codeVersion: t.maybe(t.Number),
- stateVersion: t.maybe(t.Number),
-});
-const tPassword: TRefinement<string> = t.refinement(
- t.String,
- (password: string) => !!password,
-);
-const tCookie: TRegex = tRegex(/^(user|anonymous)=[0-9]+:[0-9a-f]+$/);
-const tEmail: TRegex = tRegex(validEmailRegex);
-const tOldValidUsername: TRegex = tRegex(oldValidUsernameRegex);
-const tID: TRefinement<string> = t.refinement(t.String, (id: string) => !!id);
-
-const tMediaMessagePhoto: TInterface<PhotoMessageServerDBContent> = tShape({
- type: tString('photo'),
- uploadID: tID,
-});
-
-const tMediaMessageVideo: TInterface<VideoMessageServerDBContent> = tShape({
- type: tString('video'),
- uploadID: tID,
- thumbnailUploadID: tID,
-});
-
-const tMediaMessageMedia: TUnion<MediaMessageServerDBContent> = t.union([
- tMediaMessagePhoto,
- tMediaMessageVideo,
-]);
-
-function assertWithValidator<T>(data: mixed, validator: TType<T>): T {
- invariant(validator.is(data), "data isn't of type T");
- return (data: any);
-}
-
-const ashoatKeyserverID = '256';
+ getPendingThreadID,
+ parsePendingThreadID,
+} from '../shared/thread-utils.js';
function convertServerIDsToClientIDs<T>(
serverPrefixID: string,
@@ -115,6 +20,26 @@
console.warn(`Server id '${id}' already has a prefix`);
return id;
}
+
+ const pendingIDContents = parsePendingThreadID(id);
+ if (!pendingIDContents) {
+ return `${serverPrefixID}|${id}`;
+ }
+
+ const { threadType, sourceMessageID, memberIDs } = pendingIDContents;
+
+ if (!sourceMessageID) {
+ return id;
+ }
+
+ if (sourceMessageID.startsWith(serverPrefixID)) {
+ return getPendingThreadID(
+ threadType,
+ memberIDs,
+ `${serverPrefixID}|${sourceMessageID}`,
+ );
+ }
+
return `${serverPrefixID}|${id}`;
};
@@ -132,6 +57,25 @@
return id.substr(prefix.length);
}
+ const pendingIDContents = parsePendingThreadID(id);
+ if (!pendingIDContents) {
+ throw new Error('invalid_client_id_prefix');
+ }
+
+ const { threadType, sourceMessageID, memberIDs } = pendingIDContents;
+
+ if (!sourceMessageID) {
+ return id;
+ }
+
+ if (sourceMessageID.startsWith(prefix)) {
+ return getPendingThreadID(
+ threadType,
+ memberIDs,
+ sourceMessageID.substr(prefix.length),
+ );
+ }
+
throw new Error('invalid_client_id_prefix');
};
@@ -219,33 +163,8 @@
return input;
}
-const idSchemaRegex = '(?:[0-9]+\\|)?[0-9]+';
-
export {
- tBool,
- tString,
- tNumber,
- tShape,
- tRegex,
- tNumEnum,
- tNull,
- tDate,
- tColor,
- tPlatform,
- tDeviceType,
- tPlatformDetails,
- tPassword,
- tCookie,
- tEmail,
- tOldValidUsername,
- tID,
- tMediaMessagePhoto,
- tMediaMessageVideo,
- tMediaMessageMedia,
- assertWithValidator,
- ashoatKeyserverID,
convertClientIDsToServerIDs,
convertServerIDsToClientIDs,
convertObject,
- idSchemaRegex,
};
diff --git a/lib/utils/conversion-utils.test.js b/lib/utils/conversion-utils.test.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/conversion-utils.test.js
@@ -0,0 +1,69 @@
+// @flow
+
+import invariant from 'invariant';
+import t from 'tcomb';
+
+import {
+ convertServerIDsToClientIDs,
+ convertClientIDsToServerIDs,
+} from './conversion-utils.js';
+import { tShape, tID, idSchemaRegex } from './validation-utils.js';
+
+describe('id conversion', () => {
+ it('should convert string id', () => {
+ const validator = tShape({ id: tID });
+ const serverData = { id: '1' };
+ const clientData = { id: '0|1' };
+
+ expect(
+ convertServerIDsToClientIDs('0', validator, serverData),
+ ).toStrictEqual(clientData);
+ expect(
+ convertClientIDsToServerIDs('0', validator, clientData),
+ ).toStrictEqual(serverData);
+ });
+
+ it('should convert a complex type', () => {
+ const validator = tShape({ ids: t.dict(tID, t.list(tID)) });
+ const serverData = { ids: { '1': ['11', '12'], '2': [], '3': ['13'] } };
+ const clientData = {
+ ids: { '0|1': ['0|11', '0|12'], '0|2': [], '0|3': ['0|13'] },
+ };
+
+ expect(
+ convertServerIDsToClientIDs('0', validator, serverData),
+ ).toStrictEqual(clientData);
+ expect(
+ 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);
+ });
+});
+
+describe('idSchemaRegex tests', () => {
+ it('should capture ids', () => {
+ const regex = new RegExp(`^(${idSchemaRegex})$`);
+ const ids = ['123|123', '0|0', '123', '0'];
+
+ for (const id of ids) {
+ const result = regex.exec(id);
+ expect(result).not.toBeNull();
+ invariant(result, 'result is not null');
+ const matches = [...result];
+ expect(matches).toHaveLength(2);
+ expect(matches[1]).toBe(id);
+ }
+ });
+});
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
@@ -1,8 +1,6 @@
// @flow
import invariant from 'invariant';
-import _mapKeys from 'lodash/fp/mapKeys.js';
-import _mapValues from 'lodash/fp/mapValues.js';
import t from 'tcomb';
import type {
TStructProps,
@@ -105,120 +103,6 @@
const ashoatKeyserverID = '256';
-function convertServerIDsToClientIDs<T>(
- serverPrefixID: string,
- outputValidator: TType<T>,
- data: T,
-): T {
- const conversionFunction = id => {
- if (id.indexOf('|') !== -1) {
- console.warn(`Server id '${id}' already has a prefix`);
- return id;
- }
- return `${serverPrefixID}|${id}`;
- };
-
- return convertObject(outputValidator, data, [tID], conversionFunction);
-}
-
-function convertClientIDsToServerIDs<T>(
- serverPrefixID: string,
- outputValidator: TType<T>,
- data: T,
-): T {
- const prefix = serverPrefixID + '|';
- const conversionFunction = id => {
- if (id.startsWith(prefix)) {
- return id.substr(prefix.length);
- }
-
- throw new Error('invalid_client_id_prefix');
- };
-
- return convertObject(outputValidator, data, [tID], conversionFunction);
-}
-
-function convertObject<T, I>(
- validator: TType<I>,
- input: I,
- typesToConvert: $ReadOnlyArray<TType<T>>,
- conversionFunction: T => T,
-): I {
- if (input === null || input === undefined) {
- return input;
- }
-
- // While they should be the same runtime object,
- // `TValidator` is `TType<T>` and `validator` is `TType<I>`.
- // Having them have different types allows us to use `assertWithValidator`
- // to change `input` flow type
- const TValidator = typesToConvert[typesToConvert.indexOf(validator)];
- if (TValidator && TValidator.is(input)) {
- const TInput = assertWithValidator(input, TValidator);
- const converted = conversionFunction(TInput);
- return assertWithValidator(converted, validator);
- }
-
- if (validator.meta.kind === 'maybe' || validator.meta.kind === 'subtype') {
- return convertObject(
- validator.meta.type,
- input,
- typesToConvert,
- conversionFunction,
- );
- }
- if (validator.meta.kind === 'interface' && typeof input === 'object') {
- const recastValidator: TInterface<typeof input> = (validator: any);
- const result = {};
- for (const key in input) {
- const innerValidator = recastValidator.meta.props[key];
- result[key] = convertObject(
- innerValidator,
- input[key],
- typesToConvert,
- conversionFunction,
- );
- }
- return assertWithValidator(result, recastValidator);
- }
- if (validator.meta.kind === 'union') {
- for (const innerValidator of validator.meta.types) {
- if (innerValidator.is(input)) {
- return convertObject(
- innerValidator,
- input,
- typesToConvert,
- conversionFunction,
- );
- }
- }
- return input;
- }
- if (validator.meta.kind === 'list' && Array.isArray(input)) {
- const innerValidator = validator.meta.type;
- return (input.map(value =>
- convertObject(innerValidator, value, typesToConvert, conversionFunction),
- ): any);
- }
- if (validator.meta.kind === 'dict' && typeof input === 'object') {
- const domainValidator = validator.meta.domain;
- const codomainValidator = validator.meta.codomain;
- if (typesToConvert.includes(domainValidator)) {
- input = _mapKeys(key => conversionFunction(key))(input);
- }
- return _mapValues(value =>
- convertObject(
- codomainValidator,
- value,
- typesToConvert,
- conversionFunction,
- ),
- )(input);
- }
-
- return input;
-}
-
const idSchemaRegex = '(?:[0-9]+\\|)?[0-9]+';
export {
@@ -244,8 +128,5 @@
tMediaMessageMedia,
assertWithValidator,
ashoatKeyserverID,
- convertClientIDsToServerIDs,
- convertServerIDsToClientIDs,
- convertObject,
idSchemaRegex,
};
diff --git a/lib/utils/validation-utils.test.js b/lib/utils/validation-utils.test.js
--- a/lib/utils/validation-utils.test.js
+++ b/lib/utils/validation-utils.test.js
@@ -1,17 +1,9 @@
// @flow
-import invariant from 'invariant';
-import t from 'tcomb';
-
import {
tMediaMessagePhoto,
tMediaMessageVideo,
tNumEnum,
- tShape,
- tID,
- convertServerIDsToClientIDs,
- convertClientIDsToServerIDs,
- idSchemaRegex,
} from './validation-utils.js';
import { threadTypes } from '../types/thread-types-enum.js';
import { values } from '../utils/objects.js';
@@ -148,62 +140,3 @@
});
});
});
-
-describe('id conversion', () => {
- it('should convert string id', () => {
- const validator = tShape({ id: tID });
- const serverData = { id: '1' };
- const clientData = { id: '0|1' };
-
- expect(
- convertServerIDsToClientIDs('0', validator, serverData),
- ).toStrictEqual(clientData);
- expect(
- convertClientIDsToServerIDs('0', validator, clientData),
- ).toStrictEqual(serverData);
- });
-
- it('should convert a complex type', () => {
- const validator = tShape({ ids: t.dict(tID, t.list(tID)) });
- const serverData = { ids: { '1': ['11', '12'], '2': [], '3': ['13'] } };
- const clientData = {
- ids: { '0|1': ['0|11', '0|12'], '0|2': [], '0|3': ['0|13'] },
- };
-
- expect(
- convertServerIDsToClientIDs('0', validator, serverData),
- ).toStrictEqual(clientData);
- expect(
- 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);
- });
-});
-
-describe('idSchemaRegex tests', () => {
- it('should capture ids', () => {
- const regex = new RegExp(`^(${idSchemaRegex})$`);
- const ids = ['123|123', '0|0', '123', '0'];
-
- for (const id of ids) {
- const result = regex.exec(id);
- expect(result).not.toBeNull();
- invariant(result, 'result is not null');
- const matches = [...result];
- expect(matches).toHaveLength(2);
- expect(matches[1]).toBe(id);
- }
- });
-});

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 2, 4:04 PM (18 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2608131
Default Alt Text
D8879.id30125.diff (15 KB)

Event Timeline