From bb18fc7d507ef1e79ab6443b33fe0e63cf4ae23a Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 20 Dec 2020 15:45:28 +0000 Subject: [PATCH] Add initial login protocol documentation There are still a small number of items I need to flesh out. I also need to document response codes for packets other than 16/18, as some response codes differ from the standard set. Signed-off-by: Graham --- share/doc/protocol/login.md | 370 ++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 share/doc/protocol/login.md diff --git a/share/doc/protocol/login.md b/share/doc/protocol/login.md new file mode 100644 index 0000000000..2974071860 --- /dev/null +++ b/share/doc/protocol/login.md @@ -0,0 +1,370 @@ +# Login protocol + +## Upstream + +| Opcode | Length | Jagex name | Description | +|-------:|---------------:|-----------------------------|------------------------------------| +| 14 | 1 | `INIT_GAME_CONNECTION` | Set username hash | +| 15 | 4 | `INIT_JS5REMOTE_CONNECTION` | Switch to JS5 mode | +| 16 | Variable short | `GAMELOGIN` | Login (new session) | +| 17 | 0 | Unknown | Switch to JAGGRAB mode | +| 18 | Variable short | Unknown | Reconnect (existing session) | +| 20 | 6 | Unknown | Check date of birth and country | +| 21 | 8 | `CREATE_CHECK_NAME` | Check username availability | +| 22 | Variable byte | `CREATE_ACCOUNT` | Create account | +| 23 | 4 | `REQUEST_WORLDLIST` | Request world list | +| 24 | Variable byte | `CHECK_WORLD_SUITABILITY` | Request most suitable world number | + +### 14 (`INIT_GAME_CONNECTION`) + +| Data type | Description | +|--------------|---------------| +| UnsignedByte | Username hash | + +The following algorithm computes the username hash: + + usernameHash = (encodedUsername >> 16) & 0x1F + +where `encodedUsername` is the player's Base37-encoded username. + +The consensus in the community is that Jagex's implementation uses the username +hash to load balance between login servers, but this has not been confirmed. + +### 15 (`INIT_JS5REMOTE_CONNECTION`) + +| Data type | Description | +|-----------|---------------------| +| Int | Client build number | + +### 16 (`GAMELOGIN`) + +| Data type | Description | +|---------------|----------------------------------------------| +| Int | Client build number | +| Byte | Unknown (hard-coded to `0` in client script) | +| Boolean | Advert suppressed | +| Boolean | Client signed | +| UnsignedByte | Display mode | +| UnsignedShort | Canvas width | +| UnsignedShort | Canvas height | +| UnsignedByte | Anti-aliasing mode | +| Byte\[24\] | UID | +| String | Settings cookie | +| Int | Affiliate ID | +| Int | Preferences | +| Short | TODO | +| Int\[29\] | JS5 archive checksums | +| UnsignedByte | RSA-encrypted payload length (n) | +| Byte\[n\] | RSA-encrypted payload | + +The unknown byte hard-coded to `0` in a client script might represent the +language. It is consistent with the ID for English. We can infer that there +were language-specific versions of the cache, as the surviving copy does not +contain translations. + +The structure of the plaintext payload is described below: + +| Data type | Description | +|--------------|--------------------------------| +| UnsignedByte | Must be `10` | +| Int | ISAAC cipher key (bits 0-31) | +| Int | ISAAC cipher key (bits 32-63) | +| Int | ISAAC cipher key (bits 64-95) | +| Int | ISAAC cipher key (bits 96-127) | +| Long | Base37-encoded username | +| String | Password | + +### 17 (Switch to JAGGRAB mode) + +### 18 (Reconnect) + +The packet is identical to `GAMELOGIN` in all but one way: the opcode of this +packet indicates the client is reconnecting due to connection loss, rather than +logging in from the login screen. + +### 20 (Check date of birth and country) + +| Data type | Description | +|---------------|------------------------------| +| UnsignedByte | Day | +| UnsignedByte | Month | +| UnsignedShort | Year | +| UnsignedShort | Country ID | + +### 21 (`CREATE_CHECK_NAME`) + +| Data type | Description | +|-----------|------------------------------| +| Long | Base37-encoded username | + +### 22 (`CREATE_ACCOUNT`) + +| Data type | Description | +|-----------------|-------------------------------------------------------| +| UnsignedShort | Client build number | +| UnsignedByte | RSA-encrypted payload length (n) | +| Byte\[n\] | RSA-encrypted payload | +| Byte\[len-n-3\] | XTEA-encrypted payload | + +The structure of the RSA-decrypted payload is described below: + +| Data type | Description | +|---------------|--------------------------------| +| UnsignedByte | Must be `10` | +| UnsignedShort | Flags (see below) | +| Long | Base37-encoded username | +| Int | XTEA key (bits 0-31) | +| String | Password | +| Int | XTEA key (bits 32-63) | +| UnsignedShort | Affiliate ID | +| UnsignedByte | Day | +| UnsignedByte | Month | +| Int | XTEA key (bits 64-95) | +| UnsignedShort | Year | +| UnsignedShort | Country ID | +| Int | XTEA key (bits 96-127) | + +| Flag | Description | +|------:|--------------------------------------| +| `0x1` | Receive RuneScape newsletters | +| `0x2` | Receive Other newsletters | +| `0x4` | Share details with business partners | + +The structure of the XTEA-decrypted payload is described below: + +| Data type | Description | +|-------------|---------------| +| String | Email address | +| Byte\[0-7\] | Padding | + +### 23 (`REQUEST_WORLDLIST`) + +| Data type | Description | +|-----------|------------------------------| +| Int | Previous world list checksum | + +The previous world list checksum is set to 0 if the client has not fetched the +world list before. It is used to save bandwidth if the world list has not +changed when the "Refresh" button is clicked: if checksum has not changed, the +server only sends the player counts and not the full world list. + +Given the use of CRC-32 elsewhere in the client, it is probably the CRC-32 +checksum of the encoded world list (excluding player counts), but this has not +been confirmed. + +### 24 (`CHECK_WORLD_SUITABILITY`) + +| Data type | Description | +|---------------|-------------------------------------------| +| UnsignedShort | Client build number | +| UnsignedByte | RSA-encrypted payload length (n) | +| Byte\[n\] | RSA-encrypted payload | + +The structure of the plaintext payload is described below: + +| Data type | Description | +|--------------|-------------------------| +| UnsignedByte | Must be `10` | +| Int | Random integer | +| Long | Base37-encoded username | +| Int | Random integer | +| String | Password | +| Int | Random integer | + +## Downstream + +| Opcode | Length | Jagex name | Description | +|-------:|-------:|----------------------------------|----------------------------------------| +| 0 | 8 | Unknown | Exchange session key | +| 1 | 0 | Unknown | Display video advertisement | +| 2 | 14 | `OK` | Login successful | +| 3 | 0 | `INVALID_USERNAME_OR_PASSWORD` | Invalid username or password | +| 4 | 0 | `BANNED` | Account banned | +| 5 | 0 | `DUPLICATE` | Already logged in | +| 6 | 0 | `CLIENT_OUT_OF_DATE` | Client out of date | +| 7 | 0 | `SERVER_FULL` | Server full | +| 8 | 0 | `LOGINSERVER_OFFLINE` | Login server offline | +| 9 | 0 | `IP_LIMIT` | Too many connections from IP address | +| 10 | 0 | Unknown | Bad session ID | +| 11 | 0 | `FORCE_PASSWORD_CHANGE` | Password is weak | +| 12 | 0 | `NEED_MEMBERS_ACCOUNT` | World is members-only | +| 13 | 0 | `INVALID_SAVE` | Could not complete login | +| 14 | 0 | `UPDATE_IN_PROGRESS` | Update in progress | +| 15 | 0 | `RECONNECT_OK` | Reconnect successful | +| 16 | 0 | `TOO_MANY_ATTEMPTS` | Too many login attemts from IP address | +| 17 | 0 | Unknown | Account in members-only area | +| 18 | 0 | `LOCKED` | Account locked | +| 19 | 0 | Unknown | Fullscreen is members-only | +| 20 | 0 | Unknown | Invalid login server requested | +| 21 | 1 | `HOP_BLOCKED` | Wait for profile transfer | +| 22 | 0 | `INVALID_LOGIN_PACKET` | Malformed login packet | +| 23 | 0 | Unknown | No reply from login server | +| 24 | 0 | `LOGINSERVER_LOAD_ERROR` | Error loading profile | +| 25 | 0 | `UNKNOWN_REPLY_FROM_LOGINSERVER` | Unknown reply from login server | +| 26 | 0 | `IP_BLOCKED` | IP address banned | +| 27 | 0 | Unknown | Service unavailable | +| 29 | 1 | `DISALLOWED_BY_SCRIPT` | Disallowed by script | +| 30 | 0 | Unknown | Client is members-only | +| 101 | 2 | Unknown | Switch world | + +### 0 (Exchange session key) + +| Data type | Description | +|-----------|--------------------------------| +| Long | ISAAC cipher key (bits 64-127) | + +### 1 (Display video advertisement) + +After the client has finished displaying the advertisement, it sends an empty +packet with opcode 17. The opcode is encrypted with ISAAC. + +### 2 (`OK`) + +| Data type | Description | +|---------------|--------------------------------| +| UnsignedByte | Staff moderator level | +| UnsignedByte | Player moderator level | +| Boolean | Player is underage | +| Boolean | Parental chat consent | +| Boolean | Parental advertisement consent | +| Boolean | Quick chat world | +| Boolean | Record mouse movement | +| UnsignedShort | Player index | +| Boolean | Player is a member | +| Boolean | Members-only world | + +### 3 (`INVALID_USERNAME_OR_PASSWORD`) + +**Message:** Invalid username or password. If you have forgotten your password, +click here. + +### 4 (`BANNED`) + +**Message:** Your account has been disabled. Please click here to check +your Message Centre for details. + +### 5 (`DUPLICATE`) + +**Message:** Your account has not logged out from its last session. Try again +in a few minutes. + +### 6 (`CLIENT_OUT_OF_DATE`) + +**Message:** RuneScape has been updated! Please reload this page. + +### 7 (`SERVER_FULL`) + +**Message:** This world is full. Please use a different world. + +### 8 (`LOGINSERVER_OFFLINE`) + +**Message:** Unable to connect: login server offline. + +### 9 (`IP_LIMIT`) + +**Message:** Login limit exceeded: too many connections from your address. + +### 10 (Bad session ID) + +**Message:** Unable to connect: bad session ID. + +### 11 (`FORCE_PASSWORD_CHANGE`) + +**Message:** Your password is an extremely common choice, and is very weak. You +must change it before you can login. Click here + +### 12 (`NEED_MEMBERS_ACCOUNT`) + +**Message:** You need a members' account to log in to this world. Please +subscribe or use a different world. + +### 13 (`INVALID_SAVE`) + +**Message:** Could not complete login. Please try using a different world. + +### 14 (`UPDATE_IN_PROGRESS`) + +**Message:** The server is being updated. Please wait a few minutes and try again. + +### 15 (`RECONNECT_OK`) + +### 16 (`TOO_MANY_ATTEMPTS`) + +**Message:** Too many incorrect logins from your address. Please wait 5 minutes before +trying again. + +### 17 (Account in members-only area) + +**Message:** You are standing in a members-only area. To play on this world, move to a free +area first. + +### 18 (`LOCKED`) + +**Message:** Your account has been locked as we suspect it has been stolen. Click here to +recover your account. + +### 19 (Fullscreen is members-only) + +**Message:** Fullscreen is currently a members-only feature. To log in, either return to the +main menu and exit fullscreen or use a members' account. + +### 20 (Invalid login server requested) + +**Message:** Invalid loginserver requested. Please try using a different world. + +### 21 (`HOP_BLOCKED`) + +| Data type | Description | +|--------------|-------------------------| +| UnsignedByte | Hop time | + +**Message:** You have only just left another world. Your profile will be transferred in +seconds. + +### 22 (`INVALID_LOGIN_PACKET`) + +**Message:** Malformed login packet. Please try again. + +### 23 (No reply from login server) + +**Message:** No reply from login server. Please wait a minute and try again. + +### 24 (`LOGINSERVER_LOAD_ERROR`) + +**Message:** Error loading your profile. Please contact Customer Support. + +### 25 (`UNKNOWN_REPLY_FROM_LOGINSERVER`) + +**Message:** Unexpected loginserver response. Please try using a different world. + +### 26 (`IP_BLOCKED`) + +**Message:** This comptuer's address has been blocked as it was used to break our rules. + +### 27 (Service unavailable) + +Service unavailable. + +### 29 (`DISALLOWED_BY_SCRIPT`) + +| Data type | Description | +|--------------|-------------------------| +| UnsignedByte | Reason | + +| Reason | Message | +|-------:|---------------------------------------------------------------------------------------| +| 0 | You must have a Combat Level of at least 20 (without Summoning) to enter a PvP world. | +| 1 | You are currently carrying lent items and cannot enter a PvP world. | +| 2 | You must be standing in the Wilderness or Edgeville to enter this Bounty world. | +| Other | Unexpected server response. Please try using a different world. | + +### 30 (Client is members-only) + +This is not a member's account; please choose the 'Free Users' option from the +website to play on this account. + +### 101 (Switch world) + +| Data type | Description | +|---------------|-------------------------| +| UnsignedShort | World number |