RuneHive-Game
Loading...
Searching...
No Matches
com.runehive.net.session.LoginSession Class Reference

Represents a Session for authenticating users logging in. More...

Inheritance diagram for com.runehive.net.session.LoginSession:
Collaboration diagram for com.runehive.net.session.LoginSession:

Classes

class  FailedLoginAttempt
 A data class that represents a failed login attempt. More...

Public Member Functions

void handleClientPacket (Object o)
 The method that is called when the client sends packets to the server.
void handleUserLoginDetails (final LoginDetailsPacket packet)
 LoginSession (Channel channel)
Public Member Functions inherited from com.runehive.net.session.Session
final void close ()
 The method to close this session.
Channel getChannel ()
 Gets the underlying Channel for this Session.
String getHost ()
 Gets the users host address.
 Session (Channel channel)
 Creates a new Session.

Private Member Functions

LoginResponse authenticatedForumUser (Player player, boolean isEmail)
LoginResponse evaluate (Player player)
boolean isBanned (long unixTime)

Static Private Member Functions

static void sendFailedResponse (final Channel channel, final LoginResponse response)

Static Private Attributes

static final ConcurrentMap< String, FailedLoginAttemptfailedLogins = new ConcurrentHashMap<>()
static final Logger logger = LoggerFactory.getLogger(LoginSession.class)

Additional Inherited Members

Protected Member Functions inherited from com.runehive.net.session.Session
void onClose (ChannelFuture future)
 The method called after a session has been closed.
Protected Attributes inherited from com.runehive.net.session.Session
final Channel channel
 The channel attached to this session.
final String host
 The users host address.

Detailed Description

Represents a Session for authenticating users logging in.

Author
nshusa

Definition at line 42 of file LoginSession.java.

Constructor & Destructor Documentation

◆ LoginSession()

com.runehive.net.session.LoginSession.LoginSession ( Channel channel)

Definition at line 48 of file LoginSession.java.

48 {
49 super(channel);
50 }

References com.runehive.net.session.Session.channel.

Referenced by handleUserLoginDetails().

Here is the caller graph for this function:

Member Function Documentation

◆ authenticatedForumUser()

LoginResponse com.runehive.net.session.LoginSession.authenticatedForumUser ( Player player,
boolean isEmail )
private

Definition at line 218 of file LoginSession.java.

218 {
219 final String username = player.getUsername();
220 try {
221 final LoginResponse response = new JdbcSession(ForumService.getConnectionPool())
222 .sql(isEmail ? "SELECT member_id, members_pass_hash, name, temp_ban FROM core_members WHERE UPPER(email) = ?" : "SELECT member_id, members_pass_hash, temp_ban FROM core_members WHERE UPPER(name) = ?")
223 .set(username.toUpperCase())
224 .select((rset, stmt) -> {
225 if (rset.next()) {
226 final int memberId = rset.getInt(1);
227 final String passwordHash = rset.getString(2);
228 final String forumUsername = isEmail ? rset.getString(3) : username;
229 final long unixTime = rset.getLong(isEmail ? 4 : 3);
230
231 if (isBanned(unixTime)) {
232 return LoginResponse.ACCOUNT_DISABLED;
233 }
234
235 if (passwordHash.isEmpty()) {
236 return LoginResponse.INVALID_CREDENTIALS;
237 } else if (BCrypt.checkpw(player.getPassword(), passwordHash)) {
238 player.setMemberId(memberId);
239 player.setUsername(forumUsername);
240 player.setPassword(passwordHash);
241 return LoginResponse.NORMAL;
242 } else {
243 return LoginResponse.INVALID_CREDENTIALS;
244 }
245 }
246 return LoginResponse.FORUM_REGISTRATION;
247 });
248 return response;
249 } catch (Exception ex) {
250 ex.printStackTrace();
251 }
252 return LoginResponse.LOGIN_SERVER_OFFLINE;
253 }

References com.runehive.net.codec.login.LoginResponse.ACCOUNT_DISABLED, com.runehive.net.codec.login.LoginResponse.FORUM_REGISTRATION, com.runehive.game.service.ForumService.getConnectionPool(), com.runehive.game.world.entity.mob.player.Player.getPassword(), com.runehive.game.world.entity.mob.player.Player.getUsername(), com.runehive.net.codec.login.LoginResponse.INVALID_CREDENTIALS, isBanned(), com.runehive.net.codec.login.LoginResponse.LOGIN_SERVER_OFFLINE, com.runehive.net.codec.login.LoginResponse.NORMAL, com.runehive.game.world.entity.mob.player.Player.setMemberId(), com.runehive.game.world.entity.mob.player.Player.setPassword(), and com.runehive.game.world.entity.mob.player.Player.setUsername().

Referenced by evaluate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ evaluate()

LoginResponse com.runehive.net.session.LoginSession.evaluate ( Player player)
private

Definition at line 141 of file LoginSession.java.

141 {
142 final String username = player.getUsername();
143 final String password = player.getPassword();
144 final boolean isEmail = username.indexOf('@') != -1;
145
146 // prevents users from logging in before the server is ready to accept connections
147 if (!RuneHive.serverStarted.get()) {
148 return LoginResponse.SERVER_BEING_UPDATED;
149 }
150
151 // prevents users from using accounts with bot names
152 for (String botName : BotUtility.BOT_NAMES) {
153 if (username.equalsIgnoreCase(botName)) {
154 return LoginResponse.INSUFFICIENT_PERMSSION;
155 }
156 }
157
158 // the world is currently full
159 if (World.getPlayerCount() == Config.MAX_PLAYERS) {
160 return LoginResponse.WORLD_FULL;
161 }
162
163 // prevents users from logging in if the world is being updated
164 if (World.update.get()) {
165 return LoginResponse.SERVER_BEING_UPDATED;
166 }
167
168 if (BannedPlayers.bans.contains(username.toLowerCase())) {
169 return LoginResponse.ACCOUNT_DISABLED;
170 }
171
172 if (isEmail) {
173 if (!Config.FORUM_INTEGRATION) {
174 return LoginResponse.BAD_USERNAME;
175 }
176
177 if (username.length() > Config.EMAIL_MAX_CHARACTERS || username.length() < Config.EMAIL_MIN_CHARACTERS) {
178 return LoginResponse.INVALID_EMAIL;
179 }
180
181 // does email have illegal characters
182 if (!(username.matches("^[a-zA-Z0-9.@]{1," + Config.EMAIL_MAX_CHARACTERS + "}$"))) {
183 return LoginResponse.INVALID_CREDENTIALS;
184 }
185 } else if (username.length() < Config.USERNAME_MIN_CHARACTERS) {
186 return LoginResponse.SHORT_USERNAME;
187 } else if (username.length() > Config.USERNAME_MAX_CHARACTERS) {
188 return LoginResponse.BAD_USERNAME;
189 } else if (World.getPlayerByHash(Utility.nameToLong(username)).isPresent()) { // this user is already online
190 return LoginResponse.ACCOUNT_ONLINE;
191 } else if (!(username.matches("^[a-zA-Z0-9 ]{1," + Config.USERNAME_MAX_CHARACTERS + "}$"))) { // does username have illegal characters
192 return LoginResponse.INVALID_CREDENTIALS;
193 } else if (password.isEmpty()/* || password.length() > Config.PASSWORD_MAX_CHARACTERS*/) {
194 return LoginResponse.INVALID_CREDENTIALS;
195 }
196
197 if (World.search(username).isPresent()) {
198 return LoginResponse.ACCOUNT_ONLINE;
199 }
200
201 if (Config.FORUM_INTEGRATION) {
202 // check username and password from client with username and password from forum
203 final LoginResponse response = authenticatedForumUser(player, isEmail);
204 if (response != LoginResponse.NORMAL) {
205 return response;
206 }
207 }
208
209 LoginResponse response = PlayerSerializer.load(player, password);
210
211 if (World.searchAll(username).isPresent()) {
212 return LoginResponse.ACCOUNT_ONLINE;
213 }
214
215 return response;
216 }

References com.runehive.net.codec.login.LoginResponse.ACCOUNT_DISABLED, com.runehive.net.codec.login.LoginResponse.ACCOUNT_ONLINE, authenticatedForumUser(), com.runehive.net.codec.login.LoginResponse.BAD_USERNAME, com.runehive.game.world.entity.mob.player.BannedPlayers.bans, com.runehive.content.bot.BotUtility.BOT_NAMES, com.runehive.Config.EMAIL_MAX_CHARACTERS, com.runehive.Config.EMAIL_MIN_CHARACTERS, com.runehive.Config.FORUM_INTEGRATION, com.runehive.game.world.entity.mob.player.Player.getPassword(), com.runehive.game.world.World.getPlayerByHash(), com.runehive.game.world.World.getPlayerCount(), com.runehive.game.world.entity.mob.player.Player.getUsername(), com.runehive.net.codec.login.LoginResponse.INSUFFICIENT_PERMSSION, com.runehive.net.codec.login.LoginResponse.INVALID_CREDENTIALS, com.runehive.net.codec.login.LoginResponse.INVALID_EMAIL, com.runehive.game.world.entity.mob.player.persist.PlayerSerializer.load(), com.runehive.Config.MAX_PLAYERS, com.runehive.util.Utility.nameToLong(), com.runehive.net.codec.login.LoginResponse.NORMAL, com.runehive.game.world.World.search(), com.runehive.game.world.World.searchAll(), com.runehive.net.codec.login.LoginResponse.SERVER_BEING_UPDATED, com.runehive.RuneHive.serverStarted, com.runehive.net.codec.login.LoginResponse.SHORT_USERNAME, com.runehive.game.world.World.update, com.runehive.Config.USERNAME_MAX_CHARACTERS, com.runehive.Config.USERNAME_MIN_CHARACTERS, and com.runehive.net.codec.login.LoginResponse.WORLD_FULL.

Referenced by handleUserLoginDetails().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleClientPacket()

void com.runehive.net.session.LoginSession.handleClientPacket ( Object o)

The method that is called when the client sends packets to the server.

Parameters
oThe vague object packet.

Reimplemented from com.runehive.net.session.Session.

Definition at line 53 of file LoginSession.java.

53 {
54 if (o instanceof LoginDetailsPacket) {
55 LoginDetailsPacket packet = (LoginDetailsPacket) o;
56 RuneHive.getInstance().getLoginExecutorService().execute(this, packet);
57 //handleUserLoginDetails(packet);
58 }
59 }

References com.runehive.net.LoginExecutorService.execute(), com.runehive.RuneHive.getInstance(), and com.runehive.RuneHive.getLoginExecutorService().

Here is the call graph for this function:

◆ handleUserLoginDetails()

void com.runehive.net.session.LoginSession.handleUserLoginDetails ( final LoginDetailsPacket packet)

Definition at line 61 of file LoginSession.java.

61 {
62 final ConcurrentMap<String, FailedLoginAttempt> failedLogins = LoginSession.failedLogins;
63
64 final String username = packet.getUsername();
65
66 final FailedLoginAttempt attempt = failedLogins.get(username);
67 if (attempt != null) {
68 final Stopwatch stopwatch = attempt.getStopwatch();
69 final AtomicInteger atomicTime = attempt.getAttempt();
70 final int time = atomicTime.get();
71 if (time >= Config.FAILED_LOGIN_ATTEMPTS
72 && !stopwatch.elapsed(Config.FAILED_LOGIN_TIMEOUT, TimeUnit.MINUTES)) {
73 sendFailedResponse(channel, LoginResponse.LOGIN_ATTEMPTS_EXCEEDED);
74 return;
75 } else if (time >= Config.FAILED_LOGIN_ATTEMPTS
76 && stopwatch.elapsed(Config.FAILED_LOGIN_TIMEOUT, TimeUnit.MINUTES)) {
77 failedLogins.remove(username);
78 } else {
79 atomicTime.incrementAndGet();
80 }
81 }
82
83 final Player player = new Player(username);
84 final String password = packet.getPassword();
85 player.setPassword(password);
86
87 final LoginResponse response = evaluate(player);
88 if (response == LoginResponse.INVALID_CREDENTIALS) {
89 if (!failedLogins.containsKey(username)) {
90 failedLogins.put(username, new FailedLoginAttempt());
91 }
92 } else if (response == LoginResponse.NORMAL) {
93 failedLogins.remove(username);
94 }
95
96 final Channel channel = this.channel;
97
98 if (response != LoginResponse.NORMAL) {
99 sendFailedResponse(channel, response);
100 return;
101 }
102
103 final Argon2Types argon2Type = Argon2.argon2Type(player.getPassword());
104 if (argon2Type != Argon2.DEFAULT_TYPE) {
105 // needs rehashing (this should be moved onto another thread, as hashing is slow)
106 final String passwordHash = Argon2.getDefault().hash(
107 Argon2.DEFAULT_ITERATIONS,
108 Argon2.DEFAULT_MEMORY,
109 Argon2.DEFAULT_PARALLELISM,
110 password);
111 player.setPassword(passwordHash); // update password to hashed version
112 }
113
114 ProfileRepository.put(new Profile(username, player.lastHost, player.hostList, player.right));
115
116 channel.writeAndFlush(new LoginResponsePacket(response, player.right, false))
117 .addListener((ChannelFutureListener) sourceFuture -> {
118 try {
119 final ChannelPipeline pipeline = channel.pipeline();
120 pipeline.replace("login-decoder",
121 "game-decoder", new GamePacketDecoder(packet.getDecryptor()));
122 pipeline.replace("login-encoder",
123 "game-encoder", new GamePacketEncoder(packet.getEncryptor()));
124
125 final GameSession session = new GameSession(channel, player);
126 channel.attr(Config.SESSION_KEY).set(session);
127 player.setSession(session);
128
129 World.queueLogin(player);
130 } catch (final Exception e) {
131 logger.error("Failed to queue login for \"" + username + "\"", e);
132 }
133 });
134 }

References com.runehive.net.session.Session.channel, com.runehive.util.Stopwatch.elapsed(), evaluate(), com.runehive.Config.FAILED_LOGIN_ATTEMPTS, com.runehive.Config.FAILED_LOGIN_TIMEOUT, failedLogins, com.runehive.net.session.LoginSession.FailedLoginAttempt.getAttempt(), com.runehive.game.world.entity.mob.player.Player.getPassword(), com.runehive.net.session.LoginSession.FailedLoginAttempt.getStopwatch(), com.runehive.game.world.entity.mob.player.Player.hostList, com.runehive.net.codec.login.LoginResponse.INVALID_CREDENTIALS, com.runehive.game.world.entity.mob.player.Player.lastHost, logger, com.runehive.net.codec.login.LoginResponse.LOGIN_ATTEMPTS_EXCEEDED, LoginSession(), com.runehive.net.codec.login.LoginResponse.NORMAL, com.runehive.game.world.entity.mob.player.profile.ProfileRepository.put(), com.runehive.game.world.World.queueLogin(), com.runehive.game.world.entity.mob.player.Player.right, sendFailedResponse(), com.runehive.Config.SESSION_KEY, com.runehive.game.world.entity.mob.player.Player.setPassword(), and com.runehive.game.world.entity.mob.player.Player.setSession().

Referenced by com.runehive.net.LoginExecutorService.execute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isBanned()

boolean com.runehive.net.session.LoginSession.isBanned ( long unixTime)
private

Definition at line 255 of file LoginSession.java.

255 {
256 // not banned
257 if (unixTime == 0) {
258 return false;
259 } else if (unixTime == -1) { // perm ban
260 return true;
261 }
262
263 final Date date = Date.from(Instant.ofEpochSecond(unixTime));
264
265 final Date currentDate = Date.from(Instant.now());
266
267 return date.after(currentDate);
268 }

Referenced by authenticatedForumUser().

Here is the caller graph for this function:

◆ sendFailedResponse()

void com.runehive.net.session.LoginSession.sendFailedResponse ( final Channel channel,
final LoginResponse response )
staticprivate

Definition at line 136 of file LoginSession.java.

136 {
137 channel.writeAndFlush(new LoginResponsePacket(response))
138 .addListener(ChannelFutureListener.CLOSE);
139 }

References com.runehive.net.session.Session.channel.

Referenced by handleUserLoginDetails().

Here is the caller graph for this function:

Member Data Documentation

◆ failedLogins

final ConcurrentMap<String, FailedLoginAttempt> com.runehive.net.session.LoginSession.failedLogins = new ConcurrentHashMap<>()
staticprivate

Definition at line 46 of file LoginSession.java.

Referenced by handleUserLoginDetails().

◆ logger

final Logger com.runehive.net.session.LoginSession.logger = LoggerFactory.getLogger(LoginSession.class)
staticprivate

Definition at line 44 of file LoginSession.java.

Referenced by handleUserLoginDetails().


The documentation for this class was generated from the following file: