Skip to content

Commit

Permalink
Ensure full validation of Calls post props (#8279)
Browse files Browse the repository at this point in the history
  • Loading branch information
streamer45 authored Oct 24, 2024
1 parent e4dc8db commit 751bb2d
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {Text, TouchableOpacity, View} from 'react-native';
import {leaveCallConfirmation} from '@calls/actions/calls';
import {leaveAndJoinWithAlert, showLimitRestrictedAlert} from '@calls/alerts';
import {setJoiningChannelId} from '@calls/state';
import {getCallPropsFromPost} from '@calls/utils';
import CompassIcon from '@components/compass_icon';
import FormattedRelativeTime from '@components/formatted_relative_time';
import FormattedText from '@components/formatted_text';
Expand Down Expand Up @@ -164,13 +165,15 @@ export const CallsCustomMessage = ({
leaveCallConfirmation(intl, otherParticipants, isAdmin, isHost, serverUrl, post.channelId);
}, [intl, otherParticipants, isAdmin, isHost, serverUrl, post.channelId]);

const title = post.props.title ? (
const callProps = getCallPropsFromPost(post);

const title = callProps.title ? (
<Text style={style.title}>
{post.props.title}
{callProps.title}
</Text>
) : null;

if (post.props.end_at) {
if (callProps.start_at > 0 && callProps.end_at > 0) {
return (
<>
{title}
Expand All @@ -195,7 +198,7 @@ export const CallsCustomMessage = ({
<Text>{' '}</Text>
<FormattedTime
style={style.timeText}
value={post.props.end_at}
value={callProps.end_at}
isMilitaryTime={isMilitaryTime}
timezone={timezone}
/>
Expand All @@ -204,7 +207,7 @@ export const CallsCustomMessage = ({
id={'mobile.calls_lasted'}
style={style.timeText}
defaultMessage={'Lasted {duration}'}
values={{duration: moment.duration(post.props.end_at - post.props.start_at).humanize(false)}}
values={{duration: moment.duration(callProps.end_at - callProps.start_at).humanize(false)}}
/>
</View>
</View>
Expand Down Expand Up @@ -273,7 +276,7 @@ export const CallsCustomMessage = ({
style={style.text}
/>
<FormattedRelativeTime
value={post.props.start_at}
value={callProps.start_at}
updateIntervalInSeconds={1}
style={style.timeText}
/>
Expand Down
108 changes: 107 additions & 1 deletion app/products/calls/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import assert from 'assert';
import {type CallsConfigState, DefaultCallsConfig} from '@calls/types/calls';
import {License} from '@constants';

import {getICEServersConfigs} from './utils';
import {getICEServersConfigs, getCallPropsFromPost} from './utils';

describe('getICEServersConfigs', () => {
it('backwards compatible case, no ICEServersConfigs present', () => {
Expand Down Expand Up @@ -97,3 +97,109 @@ describe('getICEServersConfigs', () => {
]);
});
});

describe('getCallPropsFromPost', () => {
test('undefined props', () => {
const post = {} as Post;

const props = getCallPropsFromPost(post);

expect(props.title).toBe('');
expect(props.start_at).toBe(0);
expect(props.end_at).toBe(0);
expect(props.recordings).toStrictEqual({});
expect(props.recording_files.length).toBe(0);
expect(props.transcriptions).toStrictEqual({});
expect(props.participants.length).toBe(0);
});

test('missing props', () => {
const post = {
props: {},
} as Post;

const props = getCallPropsFromPost(post);

expect(props.title).toBe('');
expect(props.start_at).toBe(0);
expect(props.end_at).toBe(0);
expect(props.recordings).toStrictEqual({});
expect(props.recording_files.length).toBe(0);
expect(props.transcriptions).toStrictEqual({});
expect(props.participants.length).toBe(0);
});

test('invalid props', () => {
const callProps = {
title: {},
start_at: 'invalid',
end_at: [],
recordings: null,
transcriptions: 45,
participants: 'invalid',
recording_files: 45,
};

const post = {
props: callProps as unknown,
} as Post;

const props = getCallPropsFromPost(post);

expect(props.title).toBe('');
expect(props.start_at).toBe(0);
expect(props.end_at).toBe(0);
expect(props.recordings).toStrictEqual({});
expect(props.recording_files.length).toBe(0);
expect(props.transcriptions).toStrictEqual({});
expect(props.participants.length).toBe(0);
});

test('full props', () => {
const callProps = {
title: 'call title',
start_at: 1000,
end_at: 1045,
recordings: {
recA: {
file_id: 'recAFileID',
post_id: 'recAPostID',
tr_id: 'trA',
},
recB: {
file_id: 'recBFileID',
post_id: 'recBPostID',
tr_id: 'trB',
},
},
recording_files: ['recAFileID', 'recBFileID'],
transcriptions: {
trA: {
file_id: 'trAFileID',
post_id: 'trAPostID',
rec_id: 'recA',
},
trB: {
file_id: 'trBFileID',
post_id: 'trBPostID',
rec_id: 'recB',
},
},
participants: ['userA', 'userB'],
};

const post = {
props: callProps as unknown,
} as Post;

const props = getCallPropsFromPost(post);

expect(props.title).toBe(post.props.title);
expect(props.start_at).toBe(post.props.start_at);
expect(props.end_at).toBe(post.props.end_at);
expect(props.recordings).toBe(post.props.recordings);
expect(props.recording_files).toBe(post.props.recording_files);
expect(props.transcriptions).toBe(post.props.transcriptions);
expect(props.participants).toBe(post.props.participants);
});
});
20 changes: 19 additions & 1 deletion app/products/calls/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
CallsTheme,
CallsVersion,
} from '@calls/types/calls';
import type {CallsConfig, Caption} from '@mattermost/calls/lib/types';
import type {CallsConfig, Caption, CallPostProps} from '@mattermost/calls/lib/types';
import type PostModel from '@typings/database/models/servers/post';
import type UserModel from '@typings/database/models/servers/user';
import type {IntlShape} from 'react-intl';
Expand Down Expand Up @@ -246,3 +246,21 @@ export const getTranscriptionUri = (serverUrl: string, postProps?: Record<string
selected: {type: SelectedTrackType.INDEX, value: 0},
};
};

function isValidObject(v: any) {
return typeof v === 'object' && !Array.isArray(v) && v !== null;
}

export function getCallPropsFromPost(post: PostModel | Post): CallPostProps {
return {
title: typeof post.props?.title === 'string' ? post.props.title : '',
start_at: typeof post.props?.start_at === 'number' ? post.props.start_at : 0,
end_at: typeof post.props?.end_at === 'number' ? post.props.end_at : 0,
recordings: isValidObject(post.props?.recordings) ? post.props.recordings : {},
transcriptions: isValidObject(post.props?.transcriptions) ? post.props.transcriptions : {},
participants: Array.isArray(post.props?.participants) ? post.props.participants : [],

// DEPRECATED
recording_files: Array.isArray(post.props?.recording_files) ? post.props.recording_files : [],
};
}

0 comments on commit 751bb2d

Please sign in to comment.