Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3397118
D8879.id30125.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D8879.id30125.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D8879: [lib] Move conversion function out of validation utils
Attached
Detach File
Event Timeline
Log In to Comment