Trim profile names when setting them
This commit is contained in:
parent
5f34ece87c
commit
0fa069f260
3 changed files with 70 additions and 5 deletions
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
@ -37,6 +37,7 @@ import {
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
import { UsernameSaveState } from '../state/ducks/conversationsEnums';
|
import { UsernameSaveState } from '../state/ducks/conversationsEnums';
|
||||||
import { MAX_USERNAME, MIN_USERNAME } from '../types/Username';
|
import { MAX_USERNAME, MIN_USERNAME } from '../types/Username';
|
||||||
|
import { isWhitespace, trim } from '../util/whitespaceStringUtil';
|
||||||
|
|
||||||
export enum EditState {
|
export enum EditState {
|
||||||
None = 'None',
|
None = 'None',
|
||||||
|
@ -286,7 +287,16 @@ export const ProfileEditor = ({
|
||||||
(avatar: Uint8Array | undefined) => {
|
(avatar: Uint8Array | undefined) => {
|
||||||
setAvatarBuffer(avatar);
|
setAvatarBuffer(avatar);
|
||||||
setEditState(EditState.None);
|
setEditState(EditState.None);
|
||||||
onProfileChanged(stagedProfile, avatar);
|
onProfileChanged(
|
||||||
|
{
|
||||||
|
...stagedProfile,
|
||||||
|
firstName: trim(stagedProfile.firstName),
|
||||||
|
familyName: stagedProfile.familyName
|
||||||
|
? trim(stagedProfile.familyName)
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
avatar
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[onProfileChanged, stagedProfile]
|
[onProfileChanged, stagedProfile]
|
||||||
);
|
);
|
||||||
|
@ -422,7 +432,8 @@ export const ProfileEditor = ({
|
||||||
const shouldDisableSave =
|
const shouldDisableSave =
|
||||||
!stagedProfile.firstName ||
|
!stagedProfile.firstName ||
|
||||||
(stagedProfile.firstName === fullName.firstName &&
|
(stagedProfile.firstName === fullName.firstName &&
|
||||||
stagedProfile.familyName === fullName.familyName);
|
stagedProfile.familyName === fullName.familyName) ||
|
||||||
|
isWhitespace(stagedProfile.firstName);
|
||||||
|
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
import dataInterface from '../sql/Client';
|
import dataInterface from '../sql/Client';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
|
import * as Errors from '../types/errors';
|
||||||
|
import * as log from '../logging/log';
|
||||||
import { computeHash } from '../Crypto';
|
import { computeHash } from '../Crypto';
|
||||||
import { encryptProfileData } from '../util/encryptProfileData';
|
import { encryptProfileData } from '../util/encryptProfileData';
|
||||||
import { getProfile } from '../util/getProfile';
|
import { getProfile } from '../util/getProfile';
|
||||||
import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue';
|
import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue';
|
||||||
import * as Errors from '../types/errors';
|
import { strictAssert } from '../util/assert';
|
||||||
import * as log from '../logging/log';
|
import { isWhitespace } from '../util/whitespaceStringUtil';
|
||||||
|
|
||||||
export async function writeProfile(
|
export async function writeProfile(
|
||||||
conversation: ConversationType,
|
conversation: ConversationType,
|
||||||
|
@ -32,6 +34,11 @@ export async function writeProfile(
|
||||||
firstName,
|
firstName,
|
||||||
} = conversation;
|
} = conversation;
|
||||||
|
|
||||||
|
strictAssert(
|
||||||
|
!isWhitespace(String(conversation.firstName)),
|
||||||
|
'writeProfile: Cannot set an empty profile name'
|
||||||
|
);
|
||||||
|
|
||||||
const [profileData, encryptedAvatarData] = await encryptProfileData(
|
const [profileData, encryptedAvatarData] = await encryptProfileData(
|
||||||
conversation,
|
conversation,
|
||||||
avatarBuffer
|
avatarBuffer
|
||||||
|
|
47
ts/util/whitespaceStringUtil.ts
Normal file
47
ts/util/whitespaceStringUtil.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
const WHITESPACE = new Set([
|
||||||
|
' ',
|
||||||
|
'\u200E', // left-to-right mark
|
||||||
|
'\u200F', // right-to-left mark
|
||||||
|
'\u2007', // figure space
|
||||||
|
'\u200B', // zero-width space
|
||||||
|
'\u2800', // braille blank
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function trim(str: string): string {
|
||||||
|
let start = 0;
|
||||||
|
let end = str.length - 1;
|
||||||
|
|
||||||
|
for (start; start < str.length; start += 1) {
|
||||||
|
const char = str[start];
|
||||||
|
if (!WHITESPACE.has(char)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (end; end > 0; end -= 1) {
|
||||||
|
const char = str[end];
|
||||||
|
if (!WHITESPACE.has(char)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start > 0 || end < str.length - 1) {
|
||||||
|
return str.substring(start, end + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWhitespace(str: string): boolean {
|
||||||
|
for (let i = 0; i < str.length; i += 1) {
|
||||||
|
const char = str[i];
|
||||||
|
if (!WHITESPACE.has(char)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Reference in a new issue