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

Lobby / Connector: Move game control to lobby #689

Open
Indy2222 opened this issue Aug 17, 2023 · 2 comments
Open

Lobby / Connector: Move game control to lobby #689

Indy2222 opened this issue Aug 17, 2023 · 2 comments

Comments

@Indy2222
Copy link
Collaborator

Indy2222 commented Aug 17, 2023

Currently, it is up to the client to create / join / leave games at both DE Lobby and DE Connector. This complicates the clients and it is prone to dis-synchronization & timing issues.

Fix this by moving the Lobby game handling responsibility to DE Lobby:

  1. User requests game JWT from DE Lobby
  • It is restricted to a particular username and game name.
  • It encodes URL of the particular DE Lobby.
  1. During game creation / game joining, the user passes this JWT to DE Connector.
  2. DE Connector uses this JWT and contacts DE Lobby API during the handling of game creation, user joining and user leaving.
@redbugz
Copy link
Contributor

redbugz commented Jun 20, 2024

I wanted to fix #664 but since the fix there seems to require a bit of refactoring as well, I am exploring how this longer-term fix would work.

As I understand today, the connector is not authed, anyone who knows the ip address and port can connect and issue commands. For a 2 player game with host and peer and the client being the game binary, the current flow:

  1. host client -> lobby: auth and list available games, click Create
  2. host client -> connector: create game, get game port
  3. host client -> lobby: create/join game, set connector info and game details
  4. host client -> connector: listen and wait for others to join/readiness
  5. peer client -> lobby: auth and list available games, click Join
  6. peer client -> lobby: join game, get connector details
  7. peer client -> connector: connect and join game
  8. connector -> host client, send peer joined
  9. peer client -> connector: listen and wait for readiness
    Connector now handles all game state/flow
    Once client recognizes that the game has ended
  10. connector -> clients: game over
  11. peer client -> lobby: leave game (not currently implemented)
  12. host client -> lobby: leave game (not currently implemented)

The proposed new workflow would be:

  1. host client -> lobby: auth and list available games, click Create
  2. host client -> lobby: request game JWT with user, lobby URL, game name
  3. host clent -> connector: create game, provide JWT, get game port
  4. host client -> connector: listen and wait for updates
  5. connector -> lobby (auth with JWT): create/join game on behalf of host
  6. connector -> host: game registered with lobby (maybe?)
  7. peer client -> lobby: auth and list available games, click Join
  8. peer client -> lobby: request game JWT with user, lobby URL, game name
  9. peer client -> connector: join game, send JWT
  10. peer client -> connector: listen and wait for updates
  11. connector -> lobby (auth with JWT): join game on behalf of peer
  12. connector -> peer: lobby joined (maybe?)
    Connector now handles all game state/flow
    Game ends
  13. connector -> lobby: leave game on behalf of peer: lobby deletes player
  14. connector -> lobby: leave game on behalf of host: lobby deletes player, notices no more players and deletes game, or deletes game because the host leaves?
  15. connector -> host/peer: connection done
  16. host/peer disconnect from connector
  17. host/peer return to lobby
  18. host/peer -> lobby: list available games

I'm not sure if this would have to be a breaking change, it might be possible to have the lobby/connector handle both flows simultaneously during the transition.

This does essentially add some kind of indirect auth to the connector, as creating/joining now requires a JWT from the lobby, the connector could not validate the JWT, but it would know if it was valid once it tried to interact with the lobby and return auth errors to the clients if it's not valid.

Currently the connector only knows the max_players (I believe so it can reserve open ports for those players?). The connector would now have the lobby URL and game name from the JWT.
The JWT would be signed but not encrypted, so the connector could read it to extract the lobby URL and game name, but nobody could modify it. The connector would now need to know the Map details to send to the lobby, and any other details needed to create/join a game.

Tasks I can imagine:

  • [Lobby] Add game JWT endpoint (maybe POST to /a/games/{game_name}/token as it would require auth?). Accepts game name, returns JWT with user as sub, lobby URL as aud, not sure where to put game name. This means lobby needs to know it's own public URL, or extract it from the Host header, or any x-forward if it goes through any proxies, or it could be part of the POST request provided by the client
  • [Lobby] Add auth logic to accept/validate a game JWT for create/join/leave requests
  • [Lobby] update openapi spec and docs
  • [Connector] Update connector create/join requests (or create new sibling requests) that accept JWT plus full game config with map info
  • [Connector] Add connector logic to extract data from the JWT, and make http requests to the lobby for create/join/leave that pass the JWT in the auth header
  • [Connector] Add new messages to the client for success/error on lobby create/join/leave requests
  • [Client] [messages] Handle new messages from connector about success/error on lobby create/join/leave requests
  • [Client] [multiplayer] Update config/game state/lifecycle/etc to handle new flow
  • [Client] [menu] Adjust Create/Join logic to use new flow through the connector

@Indy2222
Copy link
Collaborator Author

I wanted to fix #664 but since the fix there seems to require a bit of refactoring as well, I am exploring how this longer-term fix would work.

As I understand today, the connector is not authed, anyone who knows the ip address and port can connect and issue commands.

Yes.

For a 2 player game with host and peer and the client being the game binary, the current flow:

1. host client -> lobby: auth and list available games, click Create

2. host client -> connector: create game, get game port

3. host client -> lobby: create/join game, set connector info and game details

4. host client -> connector: listen and wait for others to join/readiness

5. peer client -> lobby: auth and list available games, click Join

6. peer client -> lobby: join game, get connector details

7. peer client -> connector: connect and join game

8. connector -> host client, send peer joined

9. peer client -> connector: listen and wait for readiness
   Connector now handles all game state/flow
   Once client recognizes that the game has ended

10. connector -> clients: game over

11. peer client -> lobby: leave game (not currently implemented)

12. host client -> lobby: leave game (not currently implemented)

More or less, this is correct.

The proposed new workflow would be:

1. host client -> lobby: auth and list available games, click Create

2. host client -> lobby: request game JWT with user, lobby URL, game name

Exactly. The important thing here is that the game is not created in the lobby server, just the JWT.

3. host clent -> connector: create game, provide JWT, get game port

4. host client -> connector: listen and wait for updates

5. connector -> lobby (auth with JWT): create/join game on behalf of host

Yes. Basically, the authority to create, remove & keep the game updated is moved from players to the connector.

6. connector -> host: game registered with lobby (maybe?)

I think this is not necessary. We can add it later if the need arises.

7. peer client -> lobby: auth and list available games, click Join

8. peer client -> lobby: request game JWT with user, lobby URL, game name

9. peer client -> connector: join game, send JWT

10. peer client -> connector: listen and wait for updates

11. connector -> lobby (auth with JWT): join game on behalf of peer

12. connector -> peer: lobby joined (maybe?)
    Connector now handles all game state/flow
    Game ends

Ditto, I think that the connector does not have to inform the players that lobby was updated. It is AFAIK enough to inform the client that the join was successful (this is already part of the protocol).

13. connector -> lobby: leave game on behalf of peer: lobby deletes player

14. connector -> lobby: leave game on behalf of host: lobby deletes player, notices no more players and deletes game, or deletes game because the host leaves?

The connector should remove players from the lobby game as they leave. When all players leave (the detection mechanism is already implemented), it should delete the game with a request from lobby.

15. connector -> host/peer: connection done

16. host/peer disconnect from connector

17. host/peer return to lobby

18. host/peer -> lobby: list available games

I'm not sure if this would have to be a breaking change, it might be possible to have the lobby/connector handle both flows simultaneously during the transition.

At this stage of development, we do not have to care much about breaking changes (as long as the builds from main work with each other). So I would implement it in a way which is most straightforward.

This does essentially add some kind of indirect auth to the connector, as creating/joining now requires a JWT from the lobby, the connector could not validate the JWT, but it would know if it was valid once it tried to interact with the lobby and return auth errors to the clients if it's not valid.

Exactly. Once this is coupled with encryption (#459), it should be end-to-end secure (in a sence :-)).

Currently the connector only knows the max_players (I believe so it can reserve open ports for those players?).

It knows max players so that it does not allow more than that number of players to join the game (atomically).

The connector would now have the lobby URL and game name from the JWT. The JWT would be signed but not encrypted, so the connector could read it to extract the lobby URL and game name, but nobody could modify it.

Yes.

The connector would now need to know the Map details to send to the lobby, and any other details needed to create/join a game.

Yes. This might need a bit more design. But the ideas is this: you send JWT which encodes user name and game name + send other info like map (not part of the JWT?). This information would be then forwarded by the connector to the lobby (but not necessarily stored by the connector, only the lobby URL, game name and user associated JWT are needed for future requests).

Tasks I can imagine:

* [ ]  [Lobby] Add game JWT endpoint (maybe POST to `/a/games/{game_name}/token` as it would require auth?). Accepts game name, returns JWT with user as `sub`, lobby URL as `aud`, not sure where to put game name.

Makes sense. I would put game name to JWT payload (which is free form).

This means lobby needs to know it's own public URL, or extract it from the Host header, or any x-forward if it goes through any proxies, or it could be part of the POST request provided by the client

I think that the best way is to require public URL as part of the lobby configuration so it knows each own URL.

* [ ]  [Lobby] Add auth logic to accept/validate a game JWT for create/join/leave requests

Yes.It should validate signature + expiration of the JWT. It would use aud from the JWT to know what user is affected. When all users leave the game, it deletes the game (this must be carefully thought through so we do not introduce a race condition).

* [ ]  [Lobby] update openapi spec and docs

I would not consider this as a separate task, but each PR modifying or adding a new endpoint should update the OAS as well. This is so that the docs and implementation always stay in sync.

* [ ]  [Connector] Update connector create/join requests (or create new sibling requests) that accept JWT plus full game config with map info

* [ ]  [Connector] Add connector logic to extract data from the JWT, and make http requests to the lobby for create/join/leave that pass the JWT in the auth header

* [ ]  [Connector] Add new messages to the client for success/error on lobby create/join/leave requests

* [ ]  [Client] [messages] Handle new messages from connector about success/error on lobby create/join/leave requests

* [ ]  [Client] [multiplayer] Update config/game state/lifecycle/etc to handle new flow

* [ ]  [Client] [menu] Adjust Create/Join logic to use new flow through the connector

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants