feat: added updateOurProfileDisplayName

which uses libsession to check the display name length, not yet used in onboarding
pull/3083/head
William Grant 9 months ago
parent 55f5cf5c9b
commit 0b811bc641

@ -4,15 +4,13 @@ import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { Dispatch } from '@reduxjs/toolkit';
import { SyncUtils, UserUtils } from '../../../session/utils';
import { UserUtils } from '../../../session/utils';
import { YourSessionIDPill, YourSessionIDSelectable } from '../../basic/YourSessionIDPill';
import { useHotkey } from '../../../hooks/useHotkey';
import { useOurAvatarPath, useOurConversationUsername } from '../../../hooks/useParamSelector';
import { ConversationTypeEnum } from '../../../models/conversationAttributes';
import { getConversationController } from '../../../session/conversations';
import { ProfileManager } from '../../../session/profile_manager/ProfileManager';
import { editProfileModal, updateEditProfilePictureModel } from '../../../state/ducks/modalDialog';
import { setLastProfileUpdateTimestamp } from '../../../util/storage';
import { SessionWrapperModal } from '../../SessionWrapperModal';
import { Flex } from '../../basic/Flex';
import { SessionButton } from '../../basic/SessionButton';
@ -166,20 +164,6 @@ const StyledSessionIdSection = styled(Flex)`
}
`;
const updateDisplayName = async (newName: string) => {
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
const conversation = await getConversationController().getOrCreateAndWait(
ourNumber,
ConversationTypeEnum.PRIVATE
);
conversation.setSessionDisplayNameNoCommit(newName);
// might be good to not trigger a sync if the name did not change
await conversation.commit();
await setLastProfileUpdateTimestamp(Date.now());
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
};
export type ProfileDialogModes = 'default' | 'edit' | 'qr' | 'lightbox';
export const EditProfileDialog = () => {
@ -227,11 +211,21 @@ export const EditProfileDialog = () => {
return;
}
setLoading(true);
await updateDisplayName(profileName);
setUpdateProfileName(profileName);
setMode('default');
setLoading(false);
try {
setLoading(true);
await ProfileManager.updateOurProfileDisplayName(profileName);
setUpdateProfileName(profileName);
setMode('default');
} catch (err) {
// Note error substring is taken from libsession-util
if (err.message && err.message.includes('exceeds maximum length')) {
setProfileNameError(window.i18n('displayNameTooLong'));
} else {
setProfileNameError(window.i18n('unknownError'));
}
} finally {
setLoading(false);
}
};
const handleProfileHeaderClick = () => {

@ -401,8 +401,8 @@ export class SwarmPolling {
hash: m.hash,
}));
await GenericWrapperActions.init('UserConfig', privateKeyEd25519, null);
await GenericWrapperActions.merge('UserConfig', incomingConfigMessages);
await UserConfigWrapperActions.init(privateKeyEd25519, null);
await UserConfigWrapperActions.merge(incomingConfigMessages);
const userInfo = await UserConfigWrapperActions.getUserInfo();
if (!userInfo) {
@ -412,7 +412,7 @@ export class SwarmPolling {
} catch (e) {
window.log.warn('LibSessionUtil.initializeLibSessionUtilWrappers failed with', e.message);
} finally {
await GenericWrapperActions.free('UserConfig');
await UserConfigWrapperActions.free();
}
return '';

@ -79,9 +79,6 @@ export const VALIDATION = {
export const DEFAULT_RECENT_REACTS = ['😂', '🥰', '😢', '😡', '😮', '😈'];
export const REACT_LIMIT = 6;
/** character limit for a display name based on libsession MAX_NAME_LENGTH */
export const MAX_NAME_LENGTH_BYTES = 100;
export const FEATURE_RELEASE_TIMESTAMPS = {
DISAPPEARING_MESSAGES_V2: 1710284400000, // 13/03/2024 10:00 Melbourne time
USER_CONFIG: 1690761600000, // Monday July 31st at 10am Melbourne time

@ -1,7 +1,10 @@
import { isEmpty } from 'lodash';
import { CONVERSATION_PRIORITIES, ConversationTypeEnum } from '../../models/conversationAttributes';
import { setLastProfileUpdateTimestamp } from '../../util/storage';
import { UserConfigWrapperActions } from '../../webworker/workers/browser/libsession_worker_interface';
import { getConversationController } from '../conversations';
import { UserUtils } from '../utils';
import { toHex } from '../utils/String';
import { SyncUtils, UserUtils } from '../utils';
import { fromHexToArray, sanitizeSessionUsername, toHex } from '../utils/String';
import { AvatarDownload } from '../utils/job_runners/jobs/AvatarDownloadJob';
export type Profile = {
@ -92,7 +95,49 @@ async function updateProfileOfContact(
}
}
export async function updateOurProfileDisplayName(newName: string, onboarding?: boolean) {
const cleanName = sanitizeSessionUsername(newName).trim();
if (onboarding) {
await UserConfigWrapperActions.setUserInfo(cleanName, CONVERSATION_PRIORITIES.default, null);
return cleanName;
}
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
const conversation = await getConversationController().getOrCreateAndWait(
ourNumber,
ConversationTypeEnum.PRIVATE
);
const dbProfileUrl = conversation.get('avatarPointer');
const dbProfileKey = conversation.get('profileKey')
? fromHexToArray(conversation.get('profileKey')!)
: null;
const dbPriority = conversation.get('priority') || CONVERSATION_PRIORITIES.default;
await UserConfigWrapperActions.setUserInfo(
cleanName,
dbPriority,
dbProfileUrl && dbProfileKey
? {
url: dbProfileUrl,
key: dbProfileKey,
}
: null
);
conversation.setSessionDisplayNameNoCommit(newName);
// might be good to not trigger a sync if the name did not change
await conversation.commit();
await setLastProfileUpdateTimestamp(Date.now());
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
return cleanName;
}
export const ProfileManager = {
updateOurProfileSync,
updateProfileOfContact,
updateOurProfileDisplayName,
};

@ -1,5 +1,4 @@
import ByteBuffer from 'bytebuffer';
import { MAX_NAME_LENGTH_BYTES } from '../constants';
export type Encoding = 'base64' | 'hex' | 'binary' | 'utf8';
export type BufferType = ByteBuffer | Buffer | ArrayBuffer | Uint8Array;
@ -56,19 +55,11 @@ const forbiddenDisplayCharRegex = /\uFFD2*/g;
* This function removes any forbidden char from a given display name.
* This does not trim it as otherwise, a user cannot type User A as when he hits the space, it gets trimmed right away.
* The trimming should hence happen after calling this and on saving the display name.
*
* This function makes sure that the MAX_NAME_LENGTH_BYTES is verified for utf8 byte length.
* @param inputName the input to sanitize
* @returns a sanitized string, untrimmed
*/
export const sanitizeSessionUsername = (inputName: string) => {
const validChars = inputName.replace(forbiddenDisplayCharRegex, '');
const lengthBytes = encode(validChars, 'utf8').byteLength;
if (lengthBytes > MAX_NAME_LENGTH_BYTES) {
throw new Error('Display name is too long');
}
return validChars;
};

@ -67,7 +67,7 @@ const generateKeypair = async (
* This registers a user account. It can also be used if an account restore fails and the user instead registers a new display name
* @param mnemonic The mnemonic generated on first app loading and to use for this brand new user
* @param mnemonicLanguage only 'english' is supported
* @param displayName the display name to register, character limit is MAX_NAME_LENGTH_BYTES
* @param displayName the display name to register
* @param registerCallback when restoring an account, registration completion is handled elsewhere so we need to pass the pubkey back up to the caller
*/
export async function registerSingleDevice(

Loading…
Cancel
Save