-
Notifications
You must be signed in to change notification settings - Fork 59
Feature/jdbc cli #18
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
base: main
Are you sure you want to change the base?
Feature/jdbc cli #18
Changes from all commits
a0d384e
92d176f
b69a47c
a9c7436
3101eaf
1abc57c
1a40bfb
7e455f4
f2f5940
62f2bb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| package com.example; | ||
|
|
||
| import javax.sql.DataSource; | ||
| import java.sql.*; | ||
|
|
||
| public class AccountRepository { | ||
| private final DataSource ds; | ||
|
|
||
| public AccountRepository(DataSource ds) { | ||
| this.ds = ds; | ||
| } | ||
|
|
||
| /** Kontrollera login mot name + password */ | ||
| public boolean login(String username, String password) throws SQLException { | ||
| String sql = "SELECT 1 FROM account WHERE name=? AND password=?"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql)) { | ||
| ps.setString(1, username); | ||
| ps.setString(2, password); | ||
| try (ResultSet rs = ps.executeQuery()) { | ||
| return rs.next(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** Skapa nytt konto och generera unikt username (name). Vid kollision läggs siffersuffix till (t.ex. AngFra1). */ | ||
| public String createAccount(String first, String last, String ssn, String password) throws SQLException { | ||
| String base = (first == null ? "" : first.trim()); | ||
| String sur = (last == null ? "" : last.trim()); | ||
| String ssnTrim = (ssn == null ? "" : ssn.trim()); | ||
|
|
||
| String baseName = base.substring(0, Math.min(3, base.length())) | ||
| + sur.substring(0, Math.min(3, sur.length())); | ||
|
|
||
| String sql = "INSERT INTO account(name, password, first_name, last_name, ssn) VALUES (?,?,?,?,?)"; | ||
|
|
||
| try (Connection conn = ds.getConnection()) { | ||
| conn.setAutoCommit(true); | ||
|
|
||
| String candidate = baseName; | ||
| int suffix = 0; | ||
| while (true) { | ||
| try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { | ||
| ps.setString(1, candidate); | ||
| ps.setString(2, password); // medvetet: lösenord trimmas inte | ||
| ps.setString(3, base); | ||
| ps.setString(4, sur); | ||
| ps.setString(5, ssnTrim); | ||
| ps.executeUpdate(); | ||
|
|
||
| try (ResultSet keys = ps.getGeneratedKeys()) { | ||
| if (keys.next()) { | ||
| System.out.println("Account created with user_id=" + keys.getLong(1) | ||
| + " and username=" + candidate); | ||
| } else { | ||
| System.out.println("Account created with username=" + candidate); | ||
| } | ||
| } | ||
| return candidate; | ||
| } catch (SQLException e) { | ||
| // SQLState 23000 = integrity constraint violation (includes unique constraint) | ||
| String sqlState = e.getSQLState(); | ||
| if ("23000".equals(sqlState) || e.getMessage().toLowerCase().contains("duplicate") || e.getMessage().toLowerCase().contains("unique")) { | ||
| suffix++; | ||
| candidate = baseName + suffix; | ||
| // prova igen med nytt kandidatnamn | ||
| continue; | ||
| } | ||
| throw e; | ||
| } | ||
| } | ||
|
Comment on lines
+42
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add safety limit to prevent infinite retry loop. The retry logic could loop indefinitely if a non-duplicate constraint violation occurs repeatedly (e.g., invalid SSN format, NULL constraint on another field). Add a maximum retry limit: String candidate = baseName;
int suffix = 0;
+ int maxRetries = 100;
+ int attempts = 0;
- while (true) {
+ while (attempts < maxRetries) {
+ attempts++;
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
ps.setString(1, candidate);
ps.setString(2, password);
ps.setString(3, base);
ps.setString(4, sur);
ps.setString(5, ssnTrim);
ps.executeUpdate();
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
System.out.println("Account created with user_id=" + keys.getLong(1)
+ " and username=" + candidate);
} else {
System.out.println("Account created with username=" + candidate);
}
}
return candidate;
} catch (SQLException e) {
String sqlState = e.getSQLState();
if ("23000".equals(sqlState) || e.getMessage().toLowerCase().contains("duplicate") || e.getMessage().toLowerCase().contains("unique")) {
suffix++;
candidate = baseName + suffix;
continue;
}
throw e;
}
}
+ throw new SQLException("Failed to create account after " + maxRetries + " attempts");
|
||
| } | ||
| } | ||
|
|
||
| /** Uppdatera lösenord, returnerar true om lyckades */ | ||
| public boolean updatePassword(long userId, String newPassword) throws SQLException { | ||
| String sql = "UPDATE account SET password=? WHERE user_id=?"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql)) { | ||
| ps.setString(1, newPassword); | ||
| ps.setLong(2, userId); | ||
| int rows = ps.executeUpdate(); | ||
| return rows > 0; | ||
| } | ||
| } | ||
|
|
||
| /** Ta bort konto, returnerar true om lyckades */ | ||
| public boolean deleteAccount(long userId) throws SQLException { | ||
| String sql = "DELETE FROM account WHERE user_id=?"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql)) { | ||
| ps.setLong(1, userId); | ||
| int rows = ps.executeUpdate(); | ||
| return rows > 0; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,4 +21,4 @@ public static void start() { | |
| System.setProperty("APP_DB_PASS", mysql.getPassword()); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.example; | ||
|
|
||
| import javax.sql.DataSource; | ||
| import java.sql.*; | ||
|
|
||
| public class MoonMissionRepository { | ||
| private final DataSource ds; | ||
|
|
||
| public MoonMissionRepository(DataSource ds) { | ||
| this.ds = ds; | ||
| } | ||
|
|
||
| public void listMissions() throws SQLException { | ||
| String sql = "SELECT spacecraft FROM moon_mission ORDER BY mission_id"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql); | ||
| ResultSet rs = ps.executeQuery()) { | ||
| while (rs.next()) { | ||
| System.out.println(rs.getString("spacecraft")); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void getMissionById(long id) throws SQLException { | ||
| String sql = "SELECT mission_id, spacecraft, launch_date FROM moon_mission WHERE mission_id=?"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql)) { | ||
| ps.setLong(1, id); | ||
| try (ResultSet rs = ps.executeQuery()) { | ||
| if (rs.next()) { | ||
| System.out.println("Mission ID: " + rs.getLong("mission_id")); | ||
| System.out.println("Spacecraft: " + rs.getString("spacecraft")); | ||
| System.out.println("Launch Date: " + rs.getDate("launch_date")); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void countByYear(int year) throws SQLException { | ||
| String sql = "SELECT COUNT(*) as count FROM moon_mission WHERE YEAR(launch_date)=?"; | ||
| try (Connection conn = ds.getConnection(); | ||
| PreparedStatement ps = conn.prepareStatement(sql)) { | ||
| ps.setInt(1, year); | ||
| try (ResultSet rs = ps.executeQuery()) { | ||
| if (rs.next()) { | ||
| System.out.println("Number of missions in " + year + ": " + rs.getInt("count")); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Plaintext password storage and comparison.
The login method compares passwords in plaintext, which is a severe security vulnerability. Passwords must be hashed using a secure algorithm like BCrypt or Argon2.
This affects the entire account system:
createAccount(line 45) andupdatePassword(line 80) also handle plaintext passwordsRecommended fix:
createAccount)updatePasswordto hash new passwordsExample using BCrypt:
Add BCrypt dependency to pom.xml:
🤖 Prompt for AI Agents