Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chatterbox registers two accounts when first opened, then crashes #105

Open
Rhys-T opened this issue Jan 19, 2024 · 5 comments · Fixed by willbruceSmartDCSIT/chatterbox#1 · May be fixed by #106
Open

Chatterbox registers two accounts when first opened, then crashes #105

Rhys-T opened this issue Jan 19, 2024 · 5 comments · Fixed by willbruceSmartDCSIT/chatterbox#1 · May be fixed by #106

Comments

@Rhys-T
Copy link

Rhys-T commented Jan 19, 2024

Describe the bug
I'm trying to set up a self-hosted instance of Chatterbox in invite_user mode. When I first click on the Chatterbox button, it starts to open, creates the room, and sends the invitation, but then gets an error saying that room is undefined (t is undefined in the built version) and removes itself from the page. If I then reload the page and open Chatterbox again, it creates a second room, sends an invitation to that room, and works correctly from that point on. If I simulate being a new user (by clearing site data, opening a private window, or using a different browser), it fails again, then starts working again after a reload.

The error seems to be happening in Hydrogen's RoomViewModel class here, but that seems to be a result of Chatterbox passing in undefined as the room. I've managed to trace the problem to this part of createRoomWithUserSpecifiedInConfig:

const roomBeingCreated = this._session.createRoom({
type: 1, //todo: use enum from hydrogen-sdk here
name: undefined,
topic: undefined,
isEncrypted: this._options.config["encrypt_room"] ?? false,
isFederationDisabled: false,
alias: undefined,
avatar: undefined,
invites: [userId],
powerLevelContentOverride: powerLevelContent,
});
const roomStatusObservable = await this._session.observeRoomStatus(roomBeingCreated.id);
await roomStatusObservable.waitFor(status => status === (RoomStatus.BeingCreated | RoomStatus.Replaced)).promise;
const roomId = roomBeingCreated.roomId;
await this.platform.settingsStorage.setString("created-room-id", roomId);
await this.platform.settingsStorage.setString("invite-user", userId);
room = this._session.rooms.get(roomId);
return room;
It starts creating the room/invite, and waits for it to finish, but when it does, somehow the this._sessions.rooms map is completely empty.

To Reproduce
Steps to reproduce the behavior:

  1. Download and extract chatterbox-v0.5.2.tar.gz.
  2. Edit config.json. Fill out the homeserver and token settings. Replace the auto_join_room setting with invite_user, and set it to a Matrix user ID that you control.
  3. Create a basic index.html file, and add the embed code to it.
    1. Optional: The browser's devtools get confused when Chatterbox removes its iframe, and won't let you look at the code that's failing anymore. To prevent this, add HTMLIFrameElement.prototype.remove = function() { console.log('refusing to remove iframe', this); }; after the CHATTERBOX_CONFIG_LOCATION line.
  4. Upload the contents of the chatterbox-v0.5.2 folder to a web server, or serve it on localhost using something like httplz.
  5. Visit the server.
  6. Click on the Chatterbox button. It will open briefly and send the invite, then self-destruct.

OR

  1. git clone https://github.com/element-hq/chatterbox; cd chatterbox
  2. Edit public/config.json. Fill out the homeserver and token settings. Replace the auto_join_room setting with invite_user, and set it to a Matrix user ID that you control.
  3. yarn install
  4. yarn start
  5. Visit http://localhost:5400/
  6. Click on the Chatterbox button. It will open briefly and send the invite, then self-destruct.

Expected behavior
Chatterbox should remain open after creating the room even if the user is opening it for the first time.

Screenshots
N/A. There's not really anything to take a screenshot of once Chatterbox removes itself.

Desktop (please complete the following information):

  • OS: macOS
  • Browser: Firefox, Chrome
  • Version: Firefox 121.0.1, Chrome 120.0.6099.234

Smartphone (please complete the following information):
Not tested yet.

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
I was originally testing with Chatterbox running on http://localhost:8000, but I've also tried running it from a real https:// site, and am getting the same results there. I'm running Chatterbox v0.5.2 (or 86bc290 when trying the dev build, but the only changes since v0.5.2 seem to be in the readme).

I have it set to use a self-hosted Synapse homeserver. When I first noticed the issue, invite_user was set to a user on a different self-hosted Synapse, but it seems to happen even if the invite_user is on the same server.

@orangestreet
Copy link

Same exact issue test on both same server and remote.

@Rhys-T
Copy link
Author

Rhys-T commented Jan 23, 2024

I noticed that in the auto_join_room case, Chatterbox actually checks whether it found a room object, and if room was undefined, it tries joining it and waiting for it to appear in the map:

let room = this._session.rooms.get(roomId);
if (!room) {
// user is not in specified room, so join it
await this._session.joinRoom(roomId);
// even though we've joined the room, we need to wait till the next sync to get the room
await this._waitForRoomFromSync(roomId);
room = this._session.rooms.get(roomId);
}
I tried adding a similar check to createRoomWithUserSpecifiedInConfig(), but the 'join' step just returns an M_FORBIDDEN 'You are not invited to this room.' error - even though (or perhaps because) it's already in (and an admin of) that room. If I skip that and just do the _waitForRoomFromSync part, it ends up waiting forever - the room never appears in the map.

If I look at the room from the account that's receiving the invitation, I can see that the Chatterbox user is still a member/admin of the room.

@Rhys-T
Copy link
Author

Rhys-T commented Jan 23, 2024

Upon further investigation, it seems Chatterbox is actually registering two accounts the first time it opens, creating or joining the room from the first one, then failing to find the room. This happens whether I'm using invite_user or auto_join_room mode. After a reload, it starts using the second account it created, and works fine - at least in invite_user mode.

At the point where CB tries to look up the room object in the map, the session object being used appears to correspond to the second account (according to its _user and _sessionInfo properties). I suspect that's why it's not finding the room - only the first account has actually joined it - but I still haven't figured out why it's registering twice at all.

(In auto_join_room mode, on the other hand, CB starts failing a different way. The first time, it creates two accounts, joins with the first one, and crashes. But after reloading, it doesn't open even briefly - it just joins the room with the second account, changes the CB button to the close button with nothing above it, and if I click that close button, it crashes here with TypeError: this._roomViewModel is undefined and removes itself. It continues to fail the same way no matter how many times I reload it.)

@Rhys-T Rhys-T changed the title room is undefined error the first time a user opens Chatterbox in invite_user mode Chatterbox registers two accounts when first opened, then crashes Jan 23, 2024
@willbruceSmartDCSIT
Copy link

Could a possible hack be to alter line 114?
const session = sessionIds.shift();
This would at least use the first account?

@Rhys-T
Copy link
Author

Rhys-T commented Feb 5, 2024

I just tried that patch, but it still fails the same way on the first page load, and only starts working after a reload. The only difference is that when it starts working, it's using the first of the two accounts - the one that already sent an invitation.

That line seems to be in the code that attempts to restore an existing session. The problem I'm seeing is happening when that function has decided there is no existing session, and a new account needs to be created. Somehow, the AccountSetupViewModel - the object responsible for registering an account - is getting created twice, and each instance is starting its own copy of the registration process.

I noticed that the _showTimeline function actually checks whether its viewmodel already exists before creating a new one (added in 8aa7ba4), but _showAccountSetup doesn't. If I add a similar check to _showAccountSetup, everything seems to work correctly: Chatterbox registers a single account, sends an invitation, and displays the room, all without requiring a reload. I'm not that familiar with the Chatterbox or Hydrogen codebases, so I might be missing something, but this seems like a reasonable fix.

(auto_join_room mode is still failing similarly to before, but I now believe this to be a separate problem. I can try to open a separate issue for that at some point, once I have time to make a proper report for it. invite_user mode is what I needed for my use case.)

Rhys-T added a commit to Rhys-T/chatterbox that referenced this issue Feb 5, 2024
Make sure AccountSetupViewModel is only created once

Fixes element-hq#105.
Rhys-T added a commit to Rhys-T/chatterbox that referenced this issue Feb 5, 2024
@Rhys-T Rhys-T linked a pull request Feb 5, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants