diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 71cafd0b0..fa8e45124 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -814,6 +814,7 @@ const handleClientReady = async (socket, message) => { const sessionInfo = sessioninfos[socket.id]; // Check if the user has already disconnected. if (sessionInfo == null) return; + assert(sessionInfo.author); const padIds = await readOnlyManager.getIds(sessionInfo.auth.padID); sessionInfo.padId = padIds.padId; @@ -823,10 +824,16 @@ const handleClientReady = async (socket, message) => { await hooks.aCallAll('clientReady', message); // Deprecated due to awkward context. - // get all authordata of this new user - assert(sessionInfo.author); - const {colorId: authorColorId, name: authorName} = - await authorManager.getAuthor(sessionInfo.author); + let {colorId: authorColorId, name: authorName} = message.userInfo || {}; + if (authorColorId && !/^#(?:[0-9A-F]{3}){1,2}$/i.test(authorColorId)) { + messageLogger.warn(`Ignoring invalid colorId in CLIENT_READY message: ${authorColorId}`); + authorColorId = null; + } + await Promise.all([ + authorName && authorManager.setAuthorName(sessionInfo.author, authorName), + authorColorId && authorManager.setAuthorColorId(sessionInfo.author, authorColorId), + ]); + ({colorId: authorColorId, name: authorName} = await authorManager.getAuthor(sessionInfo.author)); // load the pad-object from the database const pad = await padManager.getPad(sessionInfo.padId); diff --git a/src/static/js/collab_client.js b/src/static/js/collab_client.js index 837fc3ba0..849fff5fc 100644 --- a/src/static/js/collab_client.js +++ b/src/static/js/collab_client.js @@ -245,14 +245,6 @@ const getCollabClient = (ace2editor, serverVars, initialUserInfo, options, _pad) } else if (msg.type === 'USER_NEWINFO') { const userInfo = msg.userInfo; const id = userInfo.userId; - - // Avoid a race condition when setting colors. If our color was set by a - // query param, ignore our own "new user" message's color value. - if (id === initialUserInfo.userId && initialUserInfo.globalUserColor) { - msg.userInfo.colorId = initialUserInfo.globalUserColor; - } - - if (userSet[id]) { userSet[id] = userInfo; callbacks.onUpdateUserInfo(userInfo); diff --git a/src/static/js/pad.js b/src/static/js/pad.js index d2d75f7c7..306c2b191 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -184,12 +184,23 @@ const sendClientReady = (isReconnect) => { Cookies.set('token', token, {expires: 60}); } + // If known, propagate the display name and color to the server in the CLIENT_READY message. This + // allows the server to include the values in its reply CLIENT_VARS message (which avoids + // initialization race conditions) and in the USER_NEWINFO messages sent to the other users on the + // pad (which enables them to display a user join notification with the correct name). + const params = getUrlVars(); + const userInfo = { + colorId: params.get('userColor'), + name: params.get('userName'), + }; + const msg = { component: 'pad', type: 'CLIENT_READY', padId, sessionID: Cookies.get('sessionID'), token, + userInfo, }; // this is a reconnect, lets tell the server our revisionnumber