forked from Ivasoft/mattermost-mobile
Sanitize sqlite like queries and allow non-latin characters (#7141)
This commit is contained in:
43
app/helpers/database/index.test.ts
Normal file
43
app/helpers/database/index.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {sanitizeLikeString} from '.';
|
||||
|
||||
describe('Test SQLite Sanitize like string with latin and non-latin characters', () => {
|
||||
const disallowed = ',./;[]!@#$%^&*()_-=+~';
|
||||
|
||||
test('test (latin)', () => {
|
||||
expect(sanitizeLikeString('test123')).toBe('test123');
|
||||
expect(sanitizeLikeString(`test123${disallowed}`)).toBe(`test123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (arabic)', () => {
|
||||
expect(sanitizeLikeString('اختبار123')).toBe('اختبار123');
|
||||
expect(sanitizeLikeString(`اختبار123${disallowed}`)).toBe(`اختبار123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (greek)', () => {
|
||||
expect(sanitizeLikeString('δοκιμή123')).toBe('δοκιμή123');
|
||||
expect(sanitizeLikeString(`δοκιμή123${disallowed}`)).toBe(`δοκιμή123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (hebrew)', () => {
|
||||
expect(sanitizeLikeString('חשבון123')).toBe('חשבון123');
|
||||
expect(sanitizeLikeString(`חשבון123${disallowed}`)).toBe(`חשבון123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (russian)', () => {
|
||||
expect(sanitizeLikeString('тест123')).toBe('тест123');
|
||||
expect(sanitizeLikeString(`тест123${disallowed}`)).toBe(`тест123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (chinese trad)', () => {
|
||||
expect(sanitizeLikeString('測試123')).toBe('測試123');
|
||||
expect(sanitizeLikeString(`測試123${disallowed}`)).toBe(`測試123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
|
||||
test('test (japanese)', () => {
|
||||
expect(sanitizeLikeString('テスト123')).toBe('テスト123');
|
||||
expect(sanitizeLikeString(`テスト123${disallowed}`)).toBe(`テスト123${'_'.repeat(disallowed.length)}`);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import xRegExp from 'xregexp';
|
||||
|
||||
import {General} from '@constants';
|
||||
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
@@ -91,3 +93,7 @@ export const filterAndSortMyChannels = ([myChannels, channels, notifyProps]: Fil
|
||||
|
||||
return [...mentions, ...unreads, ...mutedMentions];
|
||||
};
|
||||
|
||||
// Matches letters from any alphabet and numbers
|
||||
const sqliteLikeStringRegex = xRegExp('[^\\p{L}\\p{Nd}]', 'g');
|
||||
export const sanitizeLikeString = (value: string) => value.replace(sqliteLikeStringRegex, '_');
|
||||
|
||||
@@ -9,6 +9,7 @@ import {map as map$, switchMap, distinctUntilChanged} from 'rxjs/operators';
|
||||
|
||||
import {General, Permissions} from '@constants';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {sanitizeLikeString} from '@helpers/database';
|
||||
import {hasPermission} from '@utils/role';
|
||||
|
||||
import {prepareDeletePost} from './post';
|
||||
@@ -523,7 +524,7 @@ export function queryMyRecentChannels(database: Database, take: number) {
|
||||
|
||||
export const observeDirectChannelsByTerm = (database: Database, term: string, take = 20, matchStart = false) => {
|
||||
const onlyDMs = term.startsWith('@') ? "AND c.type='D'" : '';
|
||||
const value = Q.sanitizeLikeString(term.startsWith('@') ? term.substring(1) : term);
|
||||
const value = sanitizeLikeString(term.startsWith('@') ? term.substring(1) : term);
|
||||
let username = `u.username LIKE '${value}%'`;
|
||||
let displayname = `c.display_name LIKE '${value}%'`;
|
||||
if (!matchStart) {
|
||||
@@ -549,7 +550,7 @@ export const observeDirectChannelsByTerm = (database: Database, term: string, ta
|
||||
export const observeNotDirectChannelsByTerm = (database: Database, term: string, take = 20, matchStart = false) => {
|
||||
const teammateNameSetting = observeTeammateNameDisplay(database);
|
||||
|
||||
const value = Q.sanitizeLikeString(term.startsWith('@') ? term.substring(1) : term);
|
||||
const value = sanitizeLikeString(term.startsWith('@') ? term.substring(1) : term);
|
||||
let username = `u.username LIKE '${value}%'`;
|
||||
let nickname = `u.nickname LIKE '${value}%'`;
|
||||
let displayname = `(u.first_name || ' ' || u.last_name) LIKE '${value}%'`;
|
||||
@@ -590,7 +591,7 @@ export const observeJoinedChannelsByTerm = (database: Database, term: string, ta
|
||||
return of$([]);
|
||||
}
|
||||
|
||||
const value = Q.sanitizeLikeString(term);
|
||||
const value = sanitizeLikeString(term);
|
||||
let displayname = `c.display_name LIKE '${value}%'`;
|
||||
if (!matchStart) {
|
||||
displayname = `c.display_name LIKE '%${value}%' AND c.display_name NOT LIKE '${value}%'`;
|
||||
@@ -608,7 +609,7 @@ export const observeArchiveChannelsByTerm = (database: Database, term: string, t
|
||||
return of$([]);
|
||||
}
|
||||
|
||||
const value = Q.sanitizeLikeString(term);
|
||||
const value = sanitizeLikeString(term);
|
||||
const displayname = `%${value}%`;
|
||||
return database.get<MyChannelModel>(MY_CHANNEL).query(
|
||||
Q.on(CHANNEL, Q.and(
|
||||
@@ -639,7 +640,7 @@ export const observeChannelsByLastPostAt = (database: Database, myChannels: MyCh
|
||||
};
|
||||
|
||||
export const queryChannelsForAutocomplete = (database: Database, matchTerm: string, isSearch: boolean, teamId: string) => {
|
||||
const likeTerm = `%${Q.sanitizeLikeString(matchTerm)}%`;
|
||||
const likeTerm = `%${sanitizeLikeString(matchTerm)}%`;
|
||||
const clauses: Q.Clause[] = [];
|
||||
if (isSearch) {
|
||||
clauses.push(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {sanitizeLikeString} from '@helpers/database';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupChannelModel from '@typings/database/models/servers/group_channel';
|
||||
@@ -14,7 +15,7 @@ const {SERVER: {GROUP, GROUP_CHANNEL, GROUP_MEMBERSHIP, GROUP_TEAM}} = MM_TABLES
|
||||
|
||||
export const queryGroupsByName = (database: Database, name: string) => {
|
||||
return database.collections.get<GroupModel>(GROUP).query(
|
||||
Q.where('name', Q.like(`%${Q.sanitizeLikeString(name)}%`)),
|
||||
Q.where('name', Q.like(`%${sanitizeLikeString(name)}%`)),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,14 +28,14 @@ export const queryGroupsByNames = (database: Database, names: string[]) => {
|
||||
export const queryGroupsByNameInTeam = (database: Database, name: string, teamId: string) => {
|
||||
return database.collections.get<GroupModel>(GROUP).query(
|
||||
Q.on(GROUP_TEAM, 'team_id', teamId),
|
||||
Q.where('name', Q.like(`%${Q.sanitizeLikeString(name)}%`)),
|
||||
Q.where('name', Q.like(`%${sanitizeLikeString(name)}%`)),
|
||||
);
|
||||
};
|
||||
|
||||
export const queryGroupsByNameInChannel = (database: Database, name: string, channelId: string) => {
|
||||
return database.collections.get<GroupModel>(GROUP).query(
|
||||
Q.on(GROUP_CHANNEL, 'channel_id', channelId),
|
||||
Q.where('name', Q.like(`%${Q.sanitizeLikeString(name)}%`)),
|
||||
Q.where('name', Q.like(`%${sanitizeLikeString(name)}%`)),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {distinctUntilChanged, switchMap} from 'rxjs/operators';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
import {sanitizeLikeString} from '@helpers/database';
|
||||
|
||||
import {queryDisplayNamePreferences} from './preference';
|
||||
import {observeCurrentUserId, observeLicense, getCurrentUserId, getConfig, getLicense, observeConfigValue} from './system';
|
||||
@@ -86,7 +87,7 @@ export async function getTeammateNameDisplay(database: Database) {
|
||||
export const queryUsersLike = (database: Database, likeUsername: string) => {
|
||||
return database.get<UserModel>(USER).query(
|
||||
Q.where('username', Q.like(
|
||||
`%${Q.sanitizeLikeString(likeUsername)}%`,
|
||||
`%${sanitizeLikeString(likeUsername)}%`,
|
||||
)),
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user