package com.gianlu.pyxreloaded.singletons; import com.gianlu.pyxreloaded.Consts; import com.gianlu.pyxreloaded.data.accounts.*; import com.gianlu.pyxreloaded.server.BaseCahHandler; import com.gianlu.pyxreloaded.socials.facebook.FacebookProfileInfo; import com.gianlu.pyxreloaded.socials.facebook.FacebookToken; import com.gianlu.pyxreloaded.socials.github.GithubProfileInfo; import com.gianlu.pyxreloaded.socials.twitter.TwitterProfileInfo; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.mindrot.jbcrypt.BCrypt; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.ParseException; import java.util.Map; public final class UsersWithAccount { private final ServerDatabase db; public UsersWithAccount(ServerDatabase db) { this.db = db; } @NotNull private static String VALUES(String... values) { StringBuilder builder = new StringBuilder(); builder.append("("); boolean first = true; for (@Nullable String val : values) { if (!first) builder.append(","); if (val == null) builder.append("NULL"); else builder.append("'").append(val).append("'"); first = false; } return builder.append(")").toString(); } @NotNull private static <A extends UserAccount> A preferences(@NotNull Statement statement, @NotNull A account) throws SQLException { ResultSet prefs = statement.executeQuery("SELECT key, value FROM preferences WHERE username='" + account.username + "'"); account.loadPreferences(prefs); return account; // Just to have a better code structure } @NotNull private static ResultSet user(@NotNull Statement statement, @NotNull Consts.AuthType type, @NotNull String key, @NotNull String value) throws SQLException { return statement.executeQuery("SELECT * FROM users WHERE " + key + "='" + value + "' AND auth='" + type.toString() + "'"); } // ---- Query methods ---- // @Nullable public PasswordAccount getPasswordAccountForNickname(@NotNull String nickname) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.PASSWORD, "username", nickname)) { return user.next() ? preferences(statement, new PasswordAccount(user)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } @Nullable public PasswordAccount getPasswordAccountForEmail(@NotNull String email) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.PASSWORD, "email", email)) { return user.next() ? preferences(statement, new PasswordAccount(user)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } @Nullable public GoogleAccount getGoogleAccount(@NotNull GoogleIdToken.Payload token) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.GOOGLE, "google_sub", token.getSubject())) { return user.next() ? preferences(statement, new GoogleAccount(user, token)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } @Nullable public FacebookAccount getFacebookAccount(@NotNull FacebookToken token) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.FACEBOOK, "facebook_user_id", token.userId)) { return user.next() ? preferences(statement, new FacebookAccount(user)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } @Nullable public GithubAccount getGithubAccount(@NotNull GithubProfileInfo info) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.GITHUB, "github_user_id", info.id)) { return user.next() ? preferences(statement, new GithubAccount(user, info)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } @Nullable public TwitterAccount getTwitterAccount(@NotNull TwitterProfileInfo info) throws BaseCahHandler.CahException { try (Statement statement = db.statement(); ResultSet user = user(statement, Consts.AuthType.TWITTER, "twitter_user_id", info.id)) { return user.next() ? preferences(statement, new TwitterAccount(user)) : null; } catch (SQLException ex) { throw new RuntimeException(ex); } catch (ParseException ex) { throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex); } } public boolean hasEmail(@NotNull String email) { try (ResultSet set = db.statement().executeQuery("SELECT count(*) FROM users WHERE email='" + email + "'")) { set.next(); return set.getInt(1) > 0; } catch (SQLException ex) { throw new RuntimeException(ex); } } public boolean hasNickname(@NotNull String nickname) { try (ResultSet set = db.statement().executeQuery("SELECT count(*) FROM users WHERE username='" + nickname + "'")) { set.next(); return set.getInt(1) > 0; } catch (SQLException ex) { throw new RuntimeException(ex); } } // ---- Add methods ---- // private void addAccount(@NotNull PasswordAccount account) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("INSERT INTO users (username, auth, email, email_verified, avatar_url, password) VALUES " + VALUES(account.username, Consts.AuthType.PASSWORD.toString(), account.email, "0", account.avatarUrl, account.hashedPassword)); if (result != 1) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } private void addAccount(@NotNull GoogleAccount account) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("INSERT INTO users (username, auth, email, avatar_url, google_sub) VALUES " + VALUES(account.username, Consts.AuthType.GOOGLE.toString(), account.email, account.avatarUrl, account.subject)); if (result != 1) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } private void addAccount(@NotNull FacebookAccount account) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("INSERT INTO users (username, auth, email, avatar_url, facebook_user_id) VALUES " + VALUES(account.username, Consts.AuthType.FACEBOOK.toString(), account.email, account.avatarUrl, account.userId)); if (result != 1) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } private void addAccount(@NotNull GithubAccount account) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("INSERT INTO users (username, auth, email, avatar_url, github_user_id) VALUES " + VALUES(account.username, Consts.AuthType.GITHUB.toString(), account.email, account.avatarUrl, account.id)); if (result != 1) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } private void addAccount(@NotNull TwitterAccount account) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("INSERT INTO users (username, auth, email, avatar_url, twitter_user_id) VALUES " + VALUES(account.username, Consts.AuthType.TWITTER.toString(), account.email, account.avatarUrl, account.id)); if (result != 1) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } // ---- Update methods ---- // public void updatePreferences(UserAccount account, Map<String, String> map) { try (Statement statement = db.statement()) { for (Map.Entry<String, String> entry : map.entrySet()) { statement.executeUpdate("INSERT OR REPLACE INTO preferences (username, key, value) VALUES " + VALUES(account.username, entry.getKey(), entry.getValue())); } } catch (SQLException ex) { throw new RuntimeException(ex); } } public void updateVerifiedStatus(PasswordAccount account, boolean verified) { try (Statement statement = db.statement()) { int result = statement.executeUpdate("UPDATE users SET email_verified=" + (verified ? 1 : 0) + " WHERE email='" + account.email + "'"); if (result == 0) throw new IllegalStateException(); } catch (SQLException ex) { throw new RuntimeException(ex); } } // ---- Utility methods ---- // @NotNull public PasswordAccount registerWithPassword(@NotNull String nickname, @NotNull String email, @NotNull String password) { PasswordAccount account = new PasswordAccount(nickname, email, false, BCrypt.hashpw(password, BCrypt.gensalt())); addAccount(account); return account; } @NotNull public GoogleAccount registerWithGoogle(@NotNull String nickname, @NotNull GoogleIdToken.Payload token) { GoogleAccount account = new GoogleAccount(nickname, token); addAccount(account); return account; } public FacebookAccount registerWithFacebook(@NotNull String nickname, @NotNull FacebookToken token, @NotNull FacebookProfileInfo info) { FacebookAccount account = new FacebookAccount(nickname, token, info); addAccount(account); return account; } public GithubAccount registerWithGithub(@NotNull String nickname, @NotNull GithubProfileInfo info) { GithubAccount account = new GithubAccount(nickname, info); addAccount(account); return account; } public TwitterAccount registerWithTwitter(@NotNull String nickname, @NotNull TwitterProfileInfo info) { TwitterAccount account = new TwitterAccount(nickname, info); addAccount(account); return account; } }