diff --git a/README.md b/README.md index 22af425245e20cbf3946e233400a9493a4ec3e71..fcc62fd744356358f9cae0efd92a083747999bfb 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,23 @@ correct protection flags on the session cookie.* #### Notes – task 0 -Here you write your notes about how this task was performed. +Task A: +Used SCrypt on the password string before creating a new +Password instance as a way to have a more secure +password authentication. + +Task B: +I used the older NIST guide-lines where it was common +to demand at least a lowercase- and uppercase character +and a number, at least 8 character and at most 64 character. +The password is tested for this in InChat.Register. + +Task C: +Handler:145 -> set cookie to: + cookie.setHttpOnly(true); + cookie.setSecure(true); + + ### Task 1 – SQL injection (4 points) @@ -156,7 +172,7 @@ it wide open to injection attacks. #### Notes – task 1 -Here you write your notes about how this task was performed. +I Used prepared statements to protect the sql code from sql-injections. ### Task 2 – Cross-site scripting (4 points) @@ -171,7 +187,8 @@ take a look at the [OWASP XSS prevention cheat sheet](https://cheatsheetseries.o #### Notes – task 2 -Here you write your notes about how this task was performed. +I encoded every variable before putting it into the html script in Handler +as safety measures. This prevents XSS attacks by untrusted input-variables. ### Task 3 – Cross-site request forgery (1 point) @@ -243,6 +260,13 @@ can ignore issues related HTTPS. #### Notes – task ω -Here you write your notes about how this task was performed. +Issue 1: +No implementation for asserting that password and password_repeat +are the same when registering a new user. + +Issue 2: +It's possible to create a new user though it already exists. + +Both issues are resolved in InChat.register. diff --git a/src/main/java/inf226/inchat/Account.java b/src/main/java/inf226/inchat/Account.java index c3279aed8bd52397ae8a3a87bbd8789ac98d2bea..a2de7f9210f74708bfc041db3f1904f358ae118a 100644 --- a/src/main/java/inf226/inchat/Account.java +++ b/src/main/java/inf226/inchat/Account.java @@ -61,8 +61,12 @@ public final class Account { * @return true if password matches. */ public boolean checkPassword(String password) { - // TODO: This does not seem right. - return true; + if (SCryptUtil.check(password,hashedPassword.toString())) { + return true; + } + + System.out.println("Wrong password"); + return false; } diff --git a/src/main/java/inf226/inchat/AccountStorage.java b/src/main/java/inf226/inchat/AccountStorage.java index 6b20d475a7b6175ba60d44b1ac28aa84b1a3f406..50721dbf265cb92ea6386f461bb5f2f9658872d9 100644 --- a/src/main/java/inf226/inchat/AccountStorage.java +++ b/src/main/java/inf226/inchat/AccountStorage.java @@ -1,9 +1,6 @@ package inf226.inchat; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.time.Instant; import java.util.UUID; @@ -39,7 +36,7 @@ public final class AccountStorage this.channelStore = channelStore; connection.createStatement() - .executeUpdate("CREATE TABLE IF NOT EXISTS Account (id TEXT PRIMARY KEY, version TEXT, user TEXT, FOREIGN KEY(user) REFERENCES User(id) ON DELETE CASCADE)"); + .executeUpdate("CREATE TABLE IF NOT EXISTS Account (id TEXT PRIMARY KEY, version TEXT, user TEXT, password TEXT ,FOREIGN KEY(user) REFERENCES User(id) ON DELETE CASCADE)"); connection.createStatement() .executeUpdate("CREATE TABLE IF NOT EXISTS AccountChannel (account TEXT, channel TEXT, alias TEXT, ordinal INTEGER, PRIMARY KEY(account,channel), FOREIGN KEY(account) REFERENCES Account(id) ON DELETE CASCADE, FOREIGN KEY(channel) REFERENCES Channel(id) ON DELETE CASCADE)"); } @@ -49,10 +46,13 @@ public final class AccountStorage throws SQLException { final Stored<Account> stored = new Stored<Account>(account); - String sql = "INSERT INTO Account VALUES('" + stored.identity + "','" - + stored.version + "','" - + account.user.identity + "')"; - connection.createStatement().executeUpdate(sql); + final String sql = "INSERT INTO Account VALUES(?, ?, ?, ?)"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, stored.identity); + prepStmt.setObject(2, stored.version); + prepStmt.setObject(3, account.user.identity); + prepStmt.setString(4, account.hashedPassword.toString()); + prepStmt.executeUpdate(); // Write the list of channels final Maybe.Builder<SQLException> exception = Maybe.builder(); @@ -61,11 +61,16 @@ public final class AccountStorage String alias = element.first; Stored<Channel> channel = element.second; final String msql - = "INSERT INTO AccountChannel VALUES('" + stored.identity + "','" - + channel.identity + "','" - + alias + "','" - + ordinal.get().toString() + "')"; - try { connection.createStatement().executeUpdate(msql); } + = "INSERT INTO AccountChannel VALUES(?, ?, ?, ?)"; + + try { + PreparedStatement prepStmt2 = connection.prepareStatement(msql); + prepStmt2.setObject(1, stored.identity); + prepStmt2.setObject(2, channel.identity); + prepStmt2.setObject(3, alias); + prepStmt2.setString(4, ordinal.get().toString()); + prepStmt2.executeUpdate(); + } catch (SQLException e) { exception.accept(e) ; } ordinal.accept(ordinal.get() + 1); }); @@ -84,27 +89,35 @@ public final class AccountStorage final Stored<Account> updated = current.newVersion(new_account); if(current.version.equals(account.version)) { String sql = "UPDATE Account SET" + - " (version,user) =('" - + updated.version + "','" - + new_account.user.identity - + "') WHERE id='"+ updated.identity + "'"; + " (version,user) =(?, ?) WHERE id= ?"; connection.createStatement().executeUpdate(sql); - + + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, updated.version); + prepStmt.setObject(2, new_account.user.identity); + prepStmt.setObject(3, updated.identity); + prepStmt.executeUpdate(); + // Rewrite the list of channels - connection.createStatement().executeUpdate("DELETE FROM AccountChannel WHERE account='" + account.identity + "'"); - + String sql2 = "DELETE FROM AccountChannel WHERE account=?"; + PreparedStatement prepStmt2 = connection.prepareStatement(sql2); + prepStmt2.setObject(1, account.identity); + prepStmt2.executeUpdate(); + final Maybe.Builder<SQLException> exception = Maybe.builder(); final Mutable<Integer> ordinal = new Mutable<Integer>(0); new_account.channels.forEach(element -> { String alias = element.first; Stored<Channel> channel = element.second; - final String msql - = "INSERT INTO AccountChannel VALUES('" + account.identity + "','" - + channel.identity + "','" - + alias + "','" - + ordinal.get().toString() + "')"; - try { connection.createStatement().executeUpdate(msql); } + final String msql = "INSERT INTO AccountChannel VALUES(?, ?, ?, ?)"; + try (PreparedStatement ps3 = connection.prepareStatement(msql)) { + ps3.setObject(1, account.identity); + ps3.setObject(2, channel.identity); + ps3.setString(3, alias); + ps3.setString(4, ordinal.get().toString()); + ps3.executeUpdate(); + } catch (SQLException e) { exception.accept(e) ; } ordinal.accept(ordinal.get() + 1); }); @@ -123,8 +136,10 @@ public final class AccountStorage SQLException { final Stored<Account> current = get(account.identity); if(current.version.equals(account.version)) { - String sql = "DELETE FROM Account WHERE id ='" + account.identity + "'"; - connection.createStatement().executeUpdate(sql); + String sql = "DELETE FROM Account WHERE id=?"; + PreparedStatement ps = connection.prepareStatement(sql); + ps.setObject(1, account.identity); + ps.executeUpdate(); } else { throw new UpdatedException(current); } @@ -134,7 +149,7 @@ public final class AccountStorage throws DeletedException, SQLException { - final String accountsql = "SELECT version,user FROM Account WHERE id = '" + id.toString() + "'"; + final String accountsql = "SELECT version,user,password FROM Account WHERE id = '" + id.toString() + "'"; final String channelsql = "SELECT channel,alias,ordinal FROM AccountChannel WHERE account = '" + id.toString() + "' ORDER BY ordinal DESC"; final Statement accountStatement = connection.createStatement(); @@ -171,12 +186,13 @@ public final class AccountStorage public Stored<Account> lookup(String username) throws DeletedException, SQLException { - final String sql = "SELECT Account.id from Account INNER JOIN User ON user=User.id where User.name='" + username + "'"; - - System.err.println(sql); - final Statement statement = connection.createStatement(); - - final ResultSet rs = statement.executeQuery(sql); + + final String sql = "SELECT Account.id from Account INNER JOIN User ON user=User.id where User.name=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, username); + + //System.err.println(sql); + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) { final UUID identity = UUID.fromString(rs.getString("id")); @@ -184,6 +200,18 @@ public final class AccountStorage } throw new DeletedException(); } + + /** + * Gets the password based on the username + */ + public String getPassword(String username) throws SQLException { + final String sql = "SELECT Account.password FROM Account INNER JOIN User on user=User.id WHERE User.name=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setString(1, username); + + final ResultSet result = prepStmt.executeQuery(); + return result.getString("password"); + } } diff --git a/src/main/java/inf226/inchat/ChannelStorage.java b/src/main/java/inf226/inchat/ChannelStorage.java index 4b6c1970496442cd3355e06dd813141e163cd7d8..fc0d4d1b9339a75772d1173d1992fe4cf0655e2e 100644 --- a/src/main/java/inf226/inchat/ChannelStorage.java +++ b/src/main/java/inf226/inchat/ChannelStorage.java @@ -1,9 +1,6 @@ package inf226.inchat; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.time.Instant; import java.util.UUID; import java.util.TreeMap; @@ -46,19 +43,25 @@ public final class ChannelStorage throws SQLException { final Stored<Channel> stored = new Stored<Channel>(channel); - String sql = "INSERT INTO Channel VALUES('" + stored.identity + "','" - + stored.version + "','" - + channel.name + "')"; - connection.createStatement().executeUpdate(sql); + String sql = "INSERT INTO Channel VALUES(?, ?, ?)"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, stored.identity); + prepStmt.setObject(2, stored.version); + prepStmt.setObject(3, channel.name); + prepStmt.execute(); // Write the list of events final Maybe.Builder<SQLException> exception = Maybe.builder(); final Mutable<Integer> ordinal = new Mutable<Integer>(0); channel.events.forEach(event -> { - final String msql = "INSERT INTO ChannelEvent VALUES('" + stored.identity + "','" - + event.identity + "','" - + ordinal.get().toString() + "')"; - try { connection.createStatement().executeUpdate(msql); } + final String msql = "INSERT INTO ChannelEvent VALUES(?, ?, ?)"; + try { + PreparedStatement prepStmt2 = connection.prepareStatement(msql); + prepStmt2.setObject(1, stored.identity); + prepStmt2.setObject(2, event.identity); + prepStmt2.setObject(3, ordinal.get().toString()); + prepStmt2.execute(); + } catch (SQLException e) { exception.accept(e) ; } ordinal.accept(ordinal.get() + 1); }); @@ -77,23 +80,29 @@ public final class ChannelStorage final Stored<Channel> updated = current.newVersion(new_channel); if(current.version.equals(channel.version)) { String sql = "UPDATE Channel SET" + - " (version,name) =('" - + updated.version + "','" - + new_channel.name - + "') WHERE id='"+ updated.identity + "'"; - connection.createStatement().executeUpdate(sql); - + " (version,name) = (?, ?) WHERE id=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, updated.version); + prepStmt.setObject(2, new_channel.name); + prepStmt.setObject(3, updated.identity); + prepStmt.execute(); // Rewrite the list of events - connection.createStatement().executeUpdate("DELETE FROM ChannelEvent WHERE channel='" + channel.identity + "'"); - + String sql2 = "DELETE FROM ChannelEvent WHERE channel=?"; + PreparedStatement prepStmt2 = connection.prepareStatement(sql2); + prepStmt2.setObject(1,channel.identity); + prepStmt2.execute(); final Maybe.Builder<SQLException> exception = Maybe.builder(); final Mutable<Integer> ordinal = new Mutable<Integer>(0); new_channel.events.forEach(event -> { - final String msql = "INSERT INTO ChannelEvent VALUES('" + channel.identity + "','" - + event.identity + "','" - + ordinal.get().toString() + "')"; - try { connection.createStatement().executeUpdate(msql); } + final String msql = "INSERT INTO ChannelEvent VALUES(?, ?, ?)"; + try { + PreparedStatement prepStmt3 = connection.prepareStatement(msql); + prepStmt3.setObject(1,channel.identity); + prepStmt3.setObject(2,event.identity); + prepStmt3.setObject(3,ordinal.get().toString()); + prepStmt3.execute(); + } catch (SQLException e) { exception.accept(e) ; } ordinal.accept(ordinal.get() + 1); }); @@ -113,8 +122,11 @@ public final class ChannelStorage SQLException { final Stored<Channel> current = get(channel.identity); if(current.version.equals(channel.version)) { - String sql = "DELETE FROM Channel WHERE id ='" + channel.identity + "'"; - connection.createStatement().executeUpdate(sql); + String sql = "DELETE FROM Channel WHERE id =?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1,channel.identity); + prepStmt.execute(); + } else { throw new UpdatedException(current); } @@ -158,8 +170,11 @@ public final class ChannelStorage public Stored<Channel> noChangeUpdate(UUID channelId) throws SQLException, DeletedException { String sql = "UPDATE Channel SET" + - " (version) =('" + UUID.randomUUID() + "') WHERE id='"+ channelId + "'"; - connection.createStatement().executeUpdate(sql); + " (version) = (?) WHERE id=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, UUID.randomUUID()); + prepStmt.setObject(2, channelId); + prepStmt.execute(); Stored<Channel> channel = get(channelId); giveNextVersion(channel); return channel; @@ -173,10 +188,10 @@ public final class ChannelStorage throws DeletedException, SQLException { - final String channelsql = "SELECT version FROM Channel WHERE id = '" + id.toString() + "'"; - final Statement channelStatement = connection.createStatement(); - - final ResultSet channelResult = channelStatement.executeQuery(channelsql); + final String channelsql = "SELECT version FROM Channel WHERE id = ?"; + PreparedStatement prepStmt = connection.prepareStatement(channelsql); + prepStmt.setObject(1, id.toString()); + final ResultSet channelResult = prepStmt.executeQuery(); if(channelResult.next()) { return UUID.fromString( channelResult.getString("version")); @@ -247,8 +262,10 @@ public final class ChannelStorage */ public Stored<Channel> lookupChannelForEvent(Stored<Channel.Event> e) throws SQLException, DeletedException { - String sql = "SELECT channel FROM ChannelEvent WHERE event='" + e.identity + "'"; - final ResultSet rs = connection.createStatement().executeQuery(sql); + String sql = "SELECT channel FROM ChannelEvent WHERE event=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1,e.identity); + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) { final UUID channelId = UUID.fromString(rs.getString("channel")); return get(channelId); diff --git a/src/main/java/inf226/inchat/EventStorage.java b/src/main/java/inf226/inchat/EventStorage.java index 310b62dce1c394aaf96a053926fdd93fedaf84be..a097267854a000cf3c6ece2c9a87d3dcd99c54eb 100644 --- a/src/main/java/inf226/inchat/EventStorage.java +++ b/src/main/java/inf226/inchat/EventStorage.java @@ -1,9 +1,6 @@ package inf226.inchat; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.time.Instant; import java.util.UUID; import java.util.function.Consumer; @@ -36,23 +33,31 @@ public final class EventStorage final Stored<Channel.Event> stored = new Stored<Channel.Event>(event); - String sql = "INSERT INTO Event VALUES('" + stored.identity + "','" - + stored.version + "','" - + event.type.code + "','" - + event.time + "')"; - connection.createStatement().executeUpdate(sql); + String sql = "INSERT INTO Event VALUES(?, ?, ?, ?)"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, stored.identity); + prepStmt.setObject(2, stored.version); + prepStmt.setObject(3, event.type.code); + prepStmt.setObject(4, event.time); + prepStmt.execute(); + switch (event.type) { case message: - sql = "INSERT INTO Message VALUES('" + stored.identity + "','" - + event.sender + "','" - + event.message +"')"; + sql = "INSERT INTO Message VALUES(?, ?, ?)"; + PreparedStatement prepStmt2 = connection.prepareStatement(sql); + prepStmt2.setObject(1, stored.identity); + prepStmt2.setObject(2, event.sender); + prepStmt2.setObject(3, event.message); + prepStmt2.execute(); break; case join: - sql = "INSERT INTO Joined VALUES('" + stored.identity + "','" - + event.sender +"')"; + sql = "INSERT INTO Joined VALUES(?, ?)"; + PreparedStatement prepStmt3 = connection.prepareStatement(sql); + prepStmt3.setObject(1, stored.identity); + prepStmt3.setObject(2, event.sender); + prepStmt3.execute(); break; } - connection.createStatement().executeUpdate(sql); return stored; } @@ -66,22 +71,30 @@ public final class EventStorage final Stored<Channel.Event> updated = current.newVersion(new_event); if(current.version.equals(event.version)) { String sql = "UPDATE Event SET" + - " (version,time,type) =('" - + updated.version + "','" - + new_event.time + "','" - + new_event.type.code - + "') WHERE id='"+ updated.identity + "'"; - connection.createStatement().executeUpdate(sql); + " (version,time,type) = (?, ?, ?) WHERE id=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, updated.version); + prepStmt.setObject(2, new_event.time); + prepStmt.setObject(3, new_event.type.code); + prepStmt.setObject(4, updated.identity); + prepStmt.execute(); switch (new_event.type) { case message: - sql = "UPDATE Message SET (sender,content)=('" + new_event.sender + "','" - + new_event.message +"') WHERE id='"+ updated.identity + "'"; + sql = "UPDATE Message SET (sender,content)= (?, ?) WHERE id=?"; + PreparedStatement prepStmt2 = connection.prepareStatement(sql); + prepStmt2.setObject(1, new_event.sender); + prepStmt2.setObject(2, new_event.message); + prepStmt2.setObject(3, updated.identity); + prepStmt2.execute(); break; case join: - sql = "UPDATE Joined SET (sender)=('" + new_event.sender +"') WHERE id='"+ updated.identity + "'"; + sql = "UPDATE Joined SET (sender)= (?) WHERE id=?"; + PreparedStatement prepStmt3 = connection.prepareStatement(sql); + prepStmt3.setObject(1, new_event.sender); + prepStmt3.setObject(2, updated.identity); + prepStmt3.execute(); break; } - connection.createStatement().executeUpdate(sql); } else { throw new UpdatedException(current); } @@ -95,8 +108,10 @@ public final class EventStorage SQLException { final Stored<Channel.Event> current = get(event.identity); if(current.version.equals(event.version)) { - String sql = "DELETE FROM Event WHERE id ='" + event.identity + "'"; - connection.createStatement().executeUpdate(sql); + String sql = "DELETE FROM Event WHERE id =?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, event.identity); + prepStmt.execute(); } else { throw new UpdatedException(current); } @@ -105,9 +120,10 @@ public final class EventStorage public Stored<Channel.Event> get(UUID id) throws DeletedException, SQLException { - final String sql = "SELECT version,time,type FROM Event WHERE id = '" + id.toString() + "'"; - final Statement statement = connection.createStatement(); - final ResultSet rs = statement.executeQuery(sql); + final String sql = "SELECT version,time,type FROM Event WHERE id = ?"; + final PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1,id.toString()); + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) { final UUID version = UUID.fromString(rs.getString("version")); @@ -116,22 +132,26 @@ public final class EventStorage final Instant time = Instant.parse(rs.getString("time")); - final Statement mstatement = connection.createStatement(); + //final Statement mstatement = connection.createStatement(); switch(type) { case message: - final String msql = "SELECT sender,content FROM Message WHERE id = '" + id.toString() + "'"; - final ResultSet mrs = mstatement.executeQuery(msql); - mrs.next(); + final String sql2 = "SELECT sender,content FROM Message WHERE id = ?"; + PreparedStatement prepStmt2 = connection.prepareStatement(sql2); + prepStmt2.setObject(1, id.toString()); + final ResultSet rs2 = prepStmt2.executeQuery(); + rs2.next(); return new Stored<Channel.Event>( - Channel.Event.createMessageEvent(time,mrs.getString("sender"),mrs.getString("content")), + Channel.Event.createMessageEvent(time,rs2.getString("sender"),rs2.getString("content")), id, version); case join: - final String asql = "SELECT sender FROM Joined WHERE id = '" + id.toString() + "'"; - final ResultSet ars = mstatement.executeQuery(asql); - ars.next(); + final String sql3 = "SELECT sender FROM Joined WHERE id = ?"; + PreparedStatement prepStmt3 = connection.prepareStatement(sql3); + prepStmt3.setObject(1, id.toString()); + final ResultSet rs3 = prepStmt3.executeQuery(); + rs3.next(); return new Stored<Channel.Event>( - Channel.Event.createJoinEvent(time,ars.getString("sender")), + Channel.Event.createJoinEvent(time,rs3.getString("sender")), id, version); } diff --git a/src/main/java/inf226/inchat/Handler.java b/src/main/java/inf226/inchat/Handler.java index e5c456e14d65801cc0946a23abfa4021a147c150..cfaf9b832c5634cad958f2232a2aa63f2f659710 100644 --- a/src/main/java/inf226/inchat/Handler.java +++ b/src/main/java/inf226/inchat/Handler.java @@ -101,11 +101,10 @@ public class Handler extends AbstractHandler (request.getParameter("username"))).get(); String password = (new Maybe<String> (request.getParameter("password"))).get(); - System.err.println("Registering user: \"" + username - + "\" with password \"" + password + "\""); - + String passwordRepeat = (new Maybe<String> + (request.getParameter("password_repeat"))).get(); - inchat.register(username,password).forEach(sessionBuilder); + inchat.register(username,password,passwordRepeat).forEach(sessionBuilder); } catch (Maybe.NothingException e) { // Not enough data suppied for login System.err.println("Broken usage of register"); @@ -142,7 +141,10 @@ public class Handler extends AbstractHandler final Stored<Account> account = session.value.account; // User is now logged in with a valid sesion. // We set the session cookie to keep the user logged in: - response.addCookie(new Cookie("session",session.identity.toString())); + final Cookie cookie = new Cookie("session",session.identity.toString()); + cookie.setHttpOnly(true); + cookie.setSecure(true); + response.addCookie(cookie); final PrintWriter out = response.getWriter(); // Handle a logged in request. @@ -570,7 +572,7 @@ public class Handler extends AbstractHandler = new SessionStorage(connection,accountStore); inchat = new InChat(userStore,channelStore,accountStore,sessionStore); try { - final Stored<Session> admin = inchat.register("admin","pa$$w0rd").get(); + final Stored<Session> admin = inchat.register("admin","pa$$w0rd","pa$$w0rd").get(); final Stored<Channel> debug = inchat.createChannel(admin.value.account, "debug").get(); (new Thread(){ public void run() { Mutable<Stored<Channel>> chan = new Mutable<Stored<Channel>>(debug); diff --git a/src/main/java/inf226/inchat/InChat.java b/src/main/java/inf226/inchat/InChat.java index 49b77c8b301d76d3d91b56935c992a0963800cef..04b4057b0a28a693ecc6d83bb2184d1d5249eff5 100644 --- a/src/main/java/inf226/inchat/InChat.java +++ b/src/main/java/inf226/inchat/InChat.java @@ -50,9 +50,11 @@ public class InChat { // TODO: Here you can implement login. try { final Stored<Account> account = accountStore.lookup(username); - final Stored<Session> session = - sessionStore.save(new Session(account, Instant.now().plusSeconds(60*60*24))); - return Maybe.just(session); + if (account.value.checkPassword(password)) { + final Stored<Session> session = + sessionStore.save(new Session(account, Instant.now().plusSeconds(60 * 60 * 24))); + return Maybe.just(session); + } } catch (SQLException e) { } catch (DeletedException e) { } @@ -62,15 +64,31 @@ public class InChat { /** * Register a new user. */ - public Maybe<Stored<Session>> register(String username, String password) { + public Maybe<Stored<Session>> register(String username, String password, String passwordRepeat) { try { + try { + accountStore.lookup(username); + System.err.println("ERROR: User already exists"); + return Maybe.nothing(); + } catch (DeletedException e) {} + if (!Password.validPassword(password)) { + System.err.println("ERROR: Unsafe password"); + return Maybe.nothing(); + } + if (!password.equals(passwordRepeat)) { + System.err.println("ERROR: Failed to repeat password"); + return Maybe.nothing(); + } final Stored<User> user = - userStore.save(User.create(username)); + userStore.save(User.create(username)); final Stored<Account> account = - accountStore.save(Account.create(user, password)); + accountStore.save(Account.create(user, password)); final Stored<Session> session = - sessionStore.save(new Session(account, Instant.now().plusSeconds(60*60*24))); - return Maybe.just(session); + sessionStore.save(new Session(account, Instant.now().plusSeconds(60 * 60 * 24))); + System.err.println("Registering user: \"" + username + + "\" with password \"" + password +"\""); + return Maybe.just(session); + } catch (SQLException e) { return Maybe.nothing(); } diff --git a/src/main/java/inf226/inchat/Password.java b/src/main/java/inf226/inchat/Password.java index 3a6f0738a23a914c781214f0f010c111401def97..92f0563fcc53731f437febc395fef1351be32cd2 100644 --- a/src/main/java/inf226/inchat/Password.java +++ b/src/main/java/inf226/inchat/Password.java @@ -8,9 +8,10 @@ public final class Password { this.password = password; } - public boolean validPassword (String password) { + + public static boolean validPassword(String password) { int hPLength = password.length(); - if (hPLength >= 6 && hPLength <= 30) { + if (hPLength >= 8 && hPLength <= 64) { int digits, upperCases, lowerCases; digits = upperCases = lowerCases = 0; for (char c : password.toCharArray()) { @@ -27,6 +28,7 @@ public final class Password { if (digits != 0 && upperCases != 0 && lowerCases != 0) { return true; } + System.out.println("Password is invalid"); } return false; } diff --git a/src/main/java/inf226/inchat/SessionStorage.java b/src/main/java/inf226/inchat/SessionStorage.java index 259191065b8700c075189204af36bd41a35923c8..986aba009349731410649fb426d1bb0ceb143f7c 100644 --- a/src/main/java/inf226/inchat/SessionStorage.java +++ b/src/main/java/inf226/inchat/SessionStorage.java @@ -1,9 +1,6 @@ package inf226.inchat; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.time.Instant; import java.util.UUID; @@ -32,11 +29,13 @@ public final class SessionStorage throws SQLException { final Stored<Session> stored = new Stored<Session>(session); - String sql = "INSERT INTO Session VALUES('" + stored.identity + "','" - + stored.version + "','" - + session.account.identity + "','" - + session.expiry.toString() + "')"; - connection.createStatement().executeUpdate(sql); + String sql = "INSERT INTO Session VALUES(?, ?, ?, ?)"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, stored.identity); + prepStmt.setObject(2, stored.version); + prepStmt.setObject(3, session.account.identity); + prepStmt.setObject(4, session.expiry.toString()); + prepStmt.execute(); return stored; } @@ -50,12 +49,13 @@ public final class SessionStorage final Stored<Session> updated = current.newVersion(new_session); if(current.version.equals(session.version)) { String sql = "UPDATE Session SET" + - " (version,account,expiry) =('" - + updated.version + "','" - + new_session.account.identity + "','" - + new_session.expiry.toString() - + "') WHERE id='"+ updated.identity + "'"; - connection.createStatement().executeUpdate(sql); + " (version,account,expiry) = (?, ?, ?) WHERE id=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, updated.version); + prepStmt.setObject(2, new_session.account.identity); + prepStmt.setObject(3, new_session.expiry.toString()); + prepStmt.setObject(4, updated.identity); + prepStmt.execute(); } else { throw new UpdatedException(current); } @@ -69,8 +69,10 @@ public final class SessionStorage SQLException { final Stored<Session> current = get(session.identity); if(current.version.equals(session.version)) { - String sql = "DELETE FROM Session WHERE id ='" + session.identity + "'"; - connection.createStatement().executeUpdate(sql); + String sql = "DELETE FROM Session WHERE id = ?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1,session.identity); + prepStmt.execute(); } else { throw new UpdatedException(current); } @@ -79,9 +81,10 @@ public final class SessionStorage public Stored<Session> get(UUID id) throws DeletedException, SQLException { - final String sql = "SELECT version,account,expiry FROM Session WHERE id = '" + id.toString() + "'"; - final Statement statement = connection.createStatement(); - final ResultSet rs = statement.executeQuery(sql); + final String sql = "SELECT version,account,expiry FROM Session WHERE id = ?"; + final PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, id.toString()); + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) { final UUID version = UUID.fromString(rs.getString("version")); diff --git a/src/main/java/inf226/inchat/UserStorage.java b/src/main/java/inf226/inchat/UserStorage.java index e24b9d8bc9a0fb8bb4c38f096e61cd868217a2f1..1001599f0ae3334bc854e2aa37af7e2a6e155a8a 100644 --- a/src/main/java/inf226/inchat/UserStorage.java +++ b/src/main/java/inf226/inchat/UserStorage.java @@ -1,9 +1,6 @@ package inf226.inchat; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.time.Instant; import java.util.UUID; @@ -31,11 +28,13 @@ public final class UserStorage public Stored<User> save(User user) throws SQLException { final Stored<User> stored = new Stored<User>(user); - String sql = "INSERT INTO User VALUES('" + stored.identity + "','" - + stored.version + "','" - + user.name + "','" - + user.joined.toString() + "')"; - connection.createStatement().executeUpdate(sql); + String sql = "INSERT INTO User VALUES(?, ?, ?, ?)"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, stored.identity); + prepStmt.setObject(2, stored.version); + prepStmt.setObject(3, user.name); + prepStmt.setObject(4, user.joined.toString()); + prepStmt.execute(); return stored; } @@ -49,12 +48,13 @@ public final class UserStorage final Stored<User> updated = current.newVersion(new_user); if(current.version.equals(user.version)) { String sql = "UPDATE User SET" + - " (version,name,joined) =('" - + updated.version + "','" - + new_user.name + "','" - + new_user.joined.toString() - + "') WHERE id='"+ updated.identity + "'"; - connection.createStatement().executeUpdate(sql); + " (version,name,joined) = (?, ?, ?, ?) WHERE id=?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, updated.version); + prepStmt.setObject(2, new_user.name); + prepStmt.setObject(3, new_user.joined.toString()); + prepStmt.setObject(4, updated.identity); + prepStmt.execute(); } else { throw new UpdatedException(current); } @@ -66,21 +66,25 @@ public final class UserStorage throws UpdatedException, DeletedException, SQLException { - final Stored<User> current = get(user.identity); - if(current.version.equals(user.version)) { - String sql = "DELETE FROM User WHERE id ='" + user.identity + "'"; - connection.createStatement().executeUpdate(sql); - } else { - throw new UpdatedException(current); - } + final Stored<User> current = get(user.identity); + if(current.version.equals(user.version)) { + String sql = "DELETE FROM User WHERE id = ?"; + PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, user.identity); + prepStmt.execute(); + } else { + throw new UpdatedException(current); + } } @Override public Stored<User> get(UUID id) throws DeletedException, SQLException { - final String sql = "SELECT version,name,joined FROM User WHERE id = '" + id.toString() + "'"; - final Statement statement = connection.createStatement(); - final ResultSet rs = statement.executeQuery(sql); + final String sql = "SELECT version,name,joined FROM User WHERE id = ?"; + final PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, id.toString()); + + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) { final UUID version = @@ -97,11 +101,12 @@ public final class UserStorage /** * Look up a user by their username; **/ - public Maybe<Stored<User>> lookup(String name) { - final String sql = "SELECT id FROM User WHERE name = '" + name + "'"; + public Maybe<Stored<User>> lookup(String name) throws SQLException { + final String sql = "SELECT id FROM User WHERE name = ?"; + final PreparedStatement prepStmt = connection.prepareStatement(sql); + prepStmt.setObject(1, name); try{ - final Statement statement = connection.createStatement(); - final ResultSet rs = statement.executeQuery(sql); + final ResultSet rs = prepStmt.executeQuery(); if(rs.next()) return Maybe.just( get(UUID.fromString(rs.getString("id")))); diff --git a/src/test/java/inf226/inchat/InchatTest.java b/src/test/java/inf226/inchat/InchatTest.java index 732144bf5e908275befc0f570f99ca58d5c8e6e2..cc9e8033c6030c2c79f3c7fcae90185855accbae 100644 --- a/src/test/java/inf226/inchat/InchatTest.java +++ b/src/test/java/inf226/inchat/InchatTest.java @@ -32,8 +32,8 @@ public class InchatTest{ SessionStorage sessionStore = new SessionStorage(connection,accountStore); InChat inchat = new InChat(userStore,channelStore,accountStore,sessionStore); - Stored<Session> aliceSession = inchat.register("Alice","badpassword").get(); - inchat.register("Bob","worse").get(); + Stored<Session> aliceSession = inchat.register("Alice","badpassword","badpassword").get(); + inchat.register("Bob","worse","worse").get(); Stored<Session> bobSession = inchat.login("Bob","worse").get(); Stored<Channel> channel = inchat.createChannel(aliceSession.value.account,"Awesome").get(); inchat.postMessage(aliceSession.value.account,channel, "Test message.").get();