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

Implement part of the old client 127 protocol for Account Creation and Password Recovery #41

Closed
Hubcapp opened this issue Oct 9, 2020 · 13 comments
Assignees
Labels
enhancement New feature or request

Comments

@Hubcapp
Copy link
Member

Hubcapp commented Oct 9, 2020

Background information:

mudclient 127 from March 18th 2002 has more advanced Account Manangement than later versions of the client, such as the one that RSC+ is based on.

These Account Management features include:

  • Account Creation
  • Setting Account Recovery Questions
  • Recovering an Account

I'm not sure precisely when these features were removed, but by mudclient 192 (April 8th 2004), the features are gone, and the client instructs the user to use the website instead.

Objective:

It would be useful for private server use if these features were intact in the client, but RSC+ WILL NOT implement private server exclusive features. If this feature enters RSC+, it must behave identically to how it did in Client 127. This way, it is not a private server feature, it is just reintroducing past functionality, similar to the FPS counter already in RSC+.

This feature must look exactly like it did in Client 127, and the network protocol must be exactly the same as Client 127 (regarding opcode, packet structure, and encryption).

Here is some 127 deob code for the relevant packets to be implemented:

Account creation (client opcode 2)

this.conn.enter(2);
this.conn.short_put(version);
this.conn.long_put(DataUtil.encode_name(s));
this.conn.enc_cred_put(pass, id, this.exp, this.mod);
this.conn.int_put(seed());
this.conn.send();
this.conn.read();
int j = this.conn.read();
this.conn.close();
System.out.println("Newplayer response: " + j);

Setting account recovery questions (client opcode 208)

this.conn.enter(208);
for (int j1 = 0; j1 < 5; j1++) {
  String s2 = this.aStringArray975[j1];
  if ((s2 == null) || (s2.length() == 0))
    s2 = String.valueOf(j1 + 1);
  if (s2.length() > 50)
    s2 = s2.substring(0, 50);
  this.conn.byte_put(s2.length());
  this.conn.str_put(s2);
  this.conn.enc_cred_put(DataUtil.base47_encode(this.aClass6_966
      .text(this.anIntArray971[j1])), this.sess_id,
      this.RSA_EXP, this.RSA_MOD);
}

this.conn.exit();

Using account recovery questions (client opcode 8)

this.conn.enter(8);
this.conn.long_put(DataUtil
    .encode_name(this.aString947));
this.conn.int_put(seed());
this.conn.enc_cred_put(new StringBuilder().append(s4)
    .append(s6).toString(), i1, this.RSA_EXP,
    this.RSA_MOD);
for (int k1 = 0; k1 < 5; k1++) {
  this.conn.enc_cred_put(DataUtil
      .base47_encode(this.lost_ui
          .text(this.anIntArray989[k1])), i1,
      this.RSA_EXP, this.RSA_MOD);
}
this.conn.send();
this.conn.read();
int l1 = this.conn.read();
System.out.println(new StringBuilder()
    .append("Recover response: ").append(l1)
    .toString());
if (l1 == 0) {
  this.ui_state = 2;
  status_text(
      "Sorry, recovery failed. You may try again in 1 hour",
      "");
  this.aBoolean976 = true;
  return;
}
if (l1 == 1) {
  this.ui_state = 2;
  status_text(
      "Your pass has been reset. You may now use the new pass to login",
      "");
  return;
}
this.ui_state = 2;
status_text("Recovery failed! Attempts exceeded?", "");
return;

Challenges:

  1. Although there is no client opcode 2 or client opcode 208 in the modern client, client opcode 8 is already CLIENT_OPCODE_SEND_DUEL_SETTINGS. Obviously there is no conflict on our side if the client just sending opcode 8 with all this "extra" data, but if a server were implementing the hybrid RSC127/RSC235 protocol we are looking to adapt here, they would have to write a small distinction to figure out which opcode 8 the client is talking about. It could be done either by seeing that there is no Player associated with the connection, or by checking if packet length is 4 bytes long or not (RSC235 client opcode 8 is always 4 bytes, and RSC127 client opcode 8 can never be 4 bytes). If it were not possible to distinguish the two opcodes, there would be a problem, but it works out.

  2. RSC+ currently automatically skips the first screen of the client with this line of code here:

login_screen = 2;

This should probably have been an option in the first place. We skip this screen right now because:
a. After the removal of these Account Management options, the initial screen really serves no purpose.
b. Actually, it is a hindrance. Every time this screen is loaded, the saved Username and Password are cleared. And also it is an extra click before you get into the client.

2020-10-09-162953_800x580_scrot

This screen has been disabled in RSC+ since 2016 and all features of the client have been programmed assuming that it is skipped. The screen must be made functional again, it must be tested with replay compatibility (drag-n-drop & queue especially). It must actually be extended to work (currently, even if this one line of code is removed, the "Click here to login" button seems to be broken) and it must be extended further to implement the RSC127 interface.

  1. Like all other things, this feature must be on a toggle. If the user desires to restore the original RSC+ functionality of always launching directly to login screen on start, that must be possible.

  2. Furthermore, I would probably like it if this login screen is only shown at the beginning of client run. Once the user has "click here to login", the client should not show the screen again unless the user clicks "Cancel" or relaunches the client.

@Hubcapp Hubcapp added the enhancement New feature or request label Oct 9, 2020
@Hubcapp
Copy link
Member Author

Hubcapp commented Oct 9, 2020

I tested dragging a replay onto the client while at that "Click here to login" screen, and luckily, it seems to work properly, just going directly to replay. :p

@Hubcapp
Copy link
Member Author

Hubcapp commented Oct 22, 2020

More information:

The FORGOT_PASSWORD opcode existed in mudclient 127. It is client opcode 4 there, which conflicts with CLIENT_CAST_ON_INVENTORY_ITEM in the 235 protocol.
https://github.com/hikilaka/mudclient_127/blob/master/src/mudclient.java#L1848


ALSO
I found out that there is indeed already a toggle on the "Click here to login" screen. It is under the Streaming & Privacy tab. "Save login information between logins (Requires restart)".

@lmsv-mx123
Copy link
Member

lmsv-mx123 commented Nov 2, 2020

Will be divided by 3 segments (feature updates) very likely

  • Account Creation - Released
  • Setting Account Security & Recovery Questions - Released
  • Account Recovery - Released

Hubcapp added a commit that referenced this issue Nov 16, 2020
@Hubcapp
Copy link
Member Author

Hubcapp commented Nov 16, 2020

Account Creation has been implemented in #51

@lmsv-mx123
Copy link
Member

lmsv-mx123 commented Nov 16, 2020

Although was not present in the 127, would like to also get added the in-game option of "Change contact details", this game option was featured sometime between mudclient 127 and 204. This can be seen in the mudclient 175

The relevant code block concerning protocol part would be like:

String string = this.hL.e(this.hN);  //Full name
String string2 = this.hL.e(this.hO); //Postcode/Zipcode
String string3 = this.hL.e(this.hP); //Country
String string4 = this.hL.e(this.hQ); //Email address
if (string != null && string.length() != 0 && string2 != null && string2.length() != 0 && string3 != null && string3.length() != 0 && string4 != null && string4.length() != 0) {
this.Y.a(253, 155); // conn.enter(253);
this.Y.a(string.length()); //conn.byte_put(string.length())
this.Y.a(string); //conn.str_put(string)
this.Y.a(string2.length()); //conn.byte_put(string2.length())
this.Y.a(string2); //conn.str_put(string2)
this.Y.a(string3.length()); //conn.byte_put(string3.length())
this.Y.a(string3); //conn.str_put(string3)
this.Y.a(string4.length()); //conn.byte_put(string4.length())
this.Y.a(string4); //conn.str_put(string4)
this.Y.g(); //conn.exit();
this.bO.c(); //this.screen.clear();
this.hK = false;
return;
}

For reference, the code block above had been from deob of mudclient175. It is important to also include it since having an email for the user may make it easier for servers to provide password recovery mechanism via email token. On the aesthetics part, having the 3 security settings (see bottom part of https://classic.runescape.wiki/w/Manual:Screenshots_(2003)) fills better the space

@lmsv-mx123
Copy link
Member

lmsv-mx123 commented Nov 16, 2020

To place in next, probably will also be good to have included a validation that was on new accounts, basically:

image

Mudclient 175 seems to have opcodes from 127 intact which is good

@lmsv-mx123
Copy link
Member

OPCODE 197 - Change recovery questions request (mudclient 127 & mudclient 175)
OPCODE 247 - Change contact details request (mudclient 175)

@Hubcapp
Copy link
Member Author

Hubcapp commented Nov 17, 2020

client opcode 197 is "Decline Duel" in RSC235
client opcode 247 is "Take Ground Item" in RSC235

@lmsv-mx123
Copy link
Member

lmsv-mx123 commented Nov 17, 2020

Change password request is Opcode 25 (after doing preliminary client side validations)

public void send_cred(String oldPwd, String newPwd) {
oldPass = DataUtil.filter_str(oldPwd, 20); 
newPass = DataUtil.filter_str(newPwd, 20);
conn.enter(25);
conn.enc_cred_put(oldPass + newPass, sess_id, exp, mod);
conn.exit();
}

Client receives packet with opcode 224 after doing Change recovery questions request

if (id == 224) {
this.lkb = true;
for (var20 = 0; var20 < 5; ++var20) {
this.ukb[var20] = var20;
this.vkb[var20] = "~:" + this.ukb[var20];
this.mkb.set_text(this.rkb[var20], "");
this.mkb.set_text(this.qkb[var20], var20 + 1 + ": " + this.ymb[this.ukb[var20]]);
}
return;
}

Client receives packet with opcode 232 after doing Change contact details request

if (var1_1 == 232) {
this.hK = true;
this.hL.a(this.hN, "");
this.hL.a(this.hO, "");
this.hL.a(this.hP, "");
this.hL.a(this.hQ, "");
return;
}

Fortunately the received opcodes 224 and 232 seem to be unused in RSC235. Hence can be placed accordingly in handleIncomingPacket() without charging much the client to demux them.

@Hubcapp
Copy link
Member Author

Hubcapp commented Dec 2, 2020

All that's left is RSC175 opcode 196, to cancel Account Recovery questions "If you do not remember making this request"

@Hubcapp
Copy link
Member Author

Hubcapp commented Dec 2, 2020

luckily there is no RSC235 client opcode 196

@lmsv-mx123
Copy link
Member

lmsv-mx123 commented Dec 2, 2020

So here's my thoughts for the cancel Account recovery questions change, probably @Hubcapp can indicate better if wrong

  • Server instructs with code welcomeRecoverySetDays = 201 if user has recovery questions set and they cannot be canceled (either as first time or time expired, i.e. 14 days or more). In RSC175 and earlier would have sent the time remaining to have activated the new questions, in days with the case of RSC175 (for documentation purposes for RSC127 was minutes)

  • Code of welcomeRecoverySetDays = 200 is player has not set their recovery questions and gives the You have not yet set any password recovery questions. [...] Do this from the \'account management\' area on our front webpage. This wasn't a thing in RSC175 and previous (probably here we can just have trimmed the do this from the account management part)

  • Just by reading from the client it would seem that a number between 0 and 199 (inclusive) would have given (though very likely kept server side concept of more than 14 days then marked as permanent recovery questions

              this.surface.drawstringCenter(var4 + " you changed your recovery questions", 1, var3, 256, 0xff8000);
              var3 += 15;
              this.surface.drawstringCenter("If you do not remember making this change then cancel it immediately", 1, var3, 256, 0xff8000);
              var3 += 15;
              this.surface.drawstringCenter("Do this from the \'account management\' area on our front webpage", 1, var3, 256, 0xff8000);
              var3 += 15;
    
  • The previous would be needed to be placed equivalent to:

      	this.screen.center_text_draw(var4 + " you requested new recovery questions", 256, var2, 1, 16744448);
      	var2 += 15;
      	this.screen.center_text_draw("If you do not remember making this request then", 256, var2, 1, 16744448);
      	var2 += 15;
      	this.screen.center_text_draw("cancel it and change your password immediately!", 256, var2, 1, 16744448);
      	var2 += 15;
      	var2 += 15;
      	var5 = 16777215;
      	if (super.mouse_y > var2 - 12 && super.mouse_y <= var2 && super.mouse_x > 106
      			&& super.mouse_x < 406) {
      		var5 = 16711680;
      	}
    
      	this.screen.center_text_draw("No that wasn't me - Cancel the request!", 256, var2, 1, var5);
      	if (var5 == 16711680 && this.field_184 == 1) {
      		conn.enter(196);
      		conn.exit();
      		this.iib = false;
      	}
    
      	var2 += 15;
      	var5 = 16777215;
      	if (super.mouse_y > var2 - 12 && super.mouse_y <= var2 && super.mouse_x > 106
      			&& super.mouse_x < 406) {
      		var5 = 16711680;
      	}
    
      	this.screen.center_text_draw("That's ok, activate the new questions in " + var3 + " days time", 256, var2, 1,
      			var5);
      	if (var5 == 16711680 && this.field_184 == 1) {
      		this.iib = false;
      	}
    
  • var3 being 14 - welcomeRecoverySetDays

@lmsv-mx123
Copy link
Member

All good to go for this issue, follow-up for any possible enhancements will be in #62

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants