Skip to content

Commit

Permalink
Merge pull request #26 from GregDThomas/fix-docs
Browse files Browse the repository at this point in the history
Fix documentation
  • Loading branch information
GregDThomas authored Jan 1, 2025
2 parents 82609f3 + 2f5f707 commit fd5d4c6
Show file tree
Hide file tree
Showing 25 changed files with 2,982 additions and 2,874 deletions.
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ test {
}

checkstyle {
toolVersion = '8.31'
toolVersion = '10.21.1'
maxWarnings = 0
}

Expand Down Expand Up @@ -95,7 +95,6 @@ dependencies {

testCompileOnly lombok

testImplementation 'com.github.spotbugs:spotbugs-annotations:4.0.1'
testImplementation platform('org.junit:junit-bom:5.11.4')
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation 'org.mockito:mockito-junit-jupiter:5.14.2'
Expand Down
765 changes: 433 additions & 332 deletions config/checkstyle/checkstyle.xml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/lombok.config
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
lombok.extern.findbugs.addSuppressFBWarnings = true
Original file line number Diff line number Diff line change
@@ -1,165 +1,165 @@
package org.jivesoftware.openfire.plugin.passwordreset;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.StringUtils;

@Slf4j
@SuppressFBWarnings({"EI_EXPOSE_REP2"})
public class PasswordResetTokenManager {

private static final int TOKEN_LENGTH = 32;
private static final String INSERT_SQL =
"INSERT INTO ofPasswordResetToken (token, userId, sourceAddress, expires)"
+ " VALUES (?,?,?,?)";
private static final String PURGE_EXPIRED_SQL =
"DELETE FROM ofPasswordResetToken WHERE expires < NOW()";
private static final String FIND_USER_SQL =
"SELECT userId FROM ofPasswordResetToken WHERE token = ?";
private static final String DELETE_TOKENS_FOR_USER =
"DELETE FROM ofPasswordResetToken WHERE userId = ?";
private static final String RESET_REQUESTS_SQL =
"SELECT userId, sourceAddress, expires FROM ofPasswordResetToken ORDER by userId, expires";
private final SqlExceptionSupplier<Connection> connectionSupplier;
private final UserManager userManager;

/**
* Can't use a {@link java.util.function.Supplier} because of the exception.
*/
public interface SqlExceptionSupplier<T> {

T get() throws SQLException;
}

public PasswordResetTokenManager(
final SqlExceptionSupplier<Connection> connectionSupplier,
final UserManager userManager) {
this.connectionSupplier = connectionSupplier;
this.userManager = userManager;
}

/**
* Generates a random token for the user, and persists in the database.
*
* @param user The user to create the token for
* @param sourceAddress The address from which the request was made
* @return the random token
* @throws SQLException if anything untoward happens
*/
public String generateToken(final User user, final String sourceAddress) throws SQLException {
purgeOldTokens();
final String token = StringUtils.randomString(TOKEN_LENGTH);
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(INSERT_SQL)) {
statement.setString(1, token);
statement.setString(2, user.getUsername());
statement.setString(3, sourceAddress);
statement.setTimestamp(4,
new Timestamp(Instant.now().plus(PasswordResetPlugin.EXPIRY.getValue())
.toEpochMilli()));
statement.execute();
}
return token;
}

private void purgeOldTokens() throws SQLException {
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(PURGE_EXPIRED_SQL)) {
final int updateCount = statement.executeUpdate();
log.debug("Purged {} records", updateCount);
}
}

/**
* Finds the user for the specified token.
*
* @param token the token to perform the search on
* @return the user, if any
* @throws SQLException if something untoward happens
*/
public Optional<User> getUser(final String token) throws SQLException {
purgeOldTokens();
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(FIND_USER_SQL)) {
statement.setString(1, token);
try (final ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
final String userId = resultSet.getString("userId");
try {
return Optional.of(userManager.getUser(userId));
} catch (final UserNotFoundException ignored) {
return Optional.empty();
}
} else {
return Optional.empty();
}
}
}
}

/**
* Deletes all existing tokens for a user.
*
* @param user the user whose tokens should be deleted.
* @throws SQLException if something untoward happens
*/
public void deleteTokens(final User user) throws SQLException {
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement
= connection.prepareStatement(DELETE_TOKENS_FOR_USER)) {
statement.setString(1, user.getUsername());
statement.execute();
}
}

/**
* Returns the current list of reset requests - excluding the all important token.
*
* @return the list of reset requests.
*/
public List<ResetRequest> getResetRequests() {
try {
purgeOldTokens();
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(RESET_REQUESTS_SQL);
final ResultSet resultSet = statement.executeQuery()) {

final List<ResetRequest> resetRequests = new ArrayList<>();
while (resultSet.next()) {

final ResetRequest resetRequest = new ResetRequest(
resultSet.getString("userId"),
resultSet.getString("sourceAddress"),
resultSet.getTimestamp("expires"));
resetRequests.add(resetRequest);
}
return resetRequests;
}
} catch (final SQLException e) {
log.error("Unexpected exception retrieving outstanding requests", e);
return Collections.emptyList();
}
}

@Data
public static class ResetRequest {
public final String userId;
public final String sourceAddress;
public final Date expires;
}
}
package org.jivesoftware.openfire.plugin.passwordreset;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.StringUtils;

@Slf4j
@SuppressFBWarnings({"EI_EXPOSE_REP2"})
public class PasswordResetTokenManager {

private static final int TOKEN_LENGTH = 32;
private static final String INSERT_SQL =
"INSERT INTO ofPasswordResetToken (token, userId, sourceAddress, expires)"
+ " VALUES (?,?,?,?)";
private static final String PURGE_EXPIRED_SQL =
"DELETE FROM ofPasswordResetToken WHERE expires < NOW()";
private static final String FIND_USER_SQL =
"SELECT userId FROM ofPasswordResetToken WHERE token = ?";
private static final String DELETE_TOKENS_FOR_USER =
"DELETE FROM ofPasswordResetToken WHERE userId = ?";
private static final String RESET_REQUESTS_SQL =
"SELECT userId, sourceAddress, expires FROM ofPasswordResetToken ORDER by userId, expires";
private final SqlExceptionSupplier<Connection> connectionSupplier;
private final UserManager userManager;

/**
* Can't use a {@link java.util.function.Supplier} because of the exception.
*/
public interface SqlExceptionSupplier<T> {

T get() throws SQLException;
}

public PasswordResetTokenManager(
final SqlExceptionSupplier<Connection> connectionSupplier,
final UserManager userManager) {
this.connectionSupplier = connectionSupplier;
this.userManager = userManager;
}

/**
* Generates a random token for the user, and persists in the database.
*
* @param user The user to create the token for
* @param sourceAddress The address from which the request was made
* @return the random token
* @throws SQLException if anything untoward happens
*/
public String generateToken(final User user, final String sourceAddress) throws SQLException {
purgeOldTokens();
final String token = StringUtils.randomString(TOKEN_LENGTH);
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(INSERT_SQL)) {
statement.setString(1, token);
statement.setString(2, user.getUsername());
statement.setString(3, sourceAddress);
statement.setTimestamp(4,
new Timestamp(Instant.now().plus(PasswordResetPlugin.EXPIRY.getValue())
.toEpochMilli()));
statement.execute();
}
return token;
}

private void purgeOldTokens() throws SQLException {
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(PURGE_EXPIRED_SQL)) {
final int updateCount = statement.executeUpdate();
log.debug("Purged {} records", updateCount);
}
}

/**
* Finds the user for the specified token.
*
* @param token the token to perform the search on
* @return the user, if any
* @throws SQLException if something untoward happens
*/
public Optional<User> getUser(final String token) throws SQLException {
purgeOldTokens();
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(FIND_USER_SQL)) {
statement.setString(1, token);
try (final ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
final String userId = resultSet.getString("userId");
try {
return Optional.of(userManager.getUser(userId));
} catch (final UserNotFoundException ignored) {
return Optional.empty();
}
} else {
return Optional.empty();
}
}
}
}

/**
* Deletes all existing tokens for a user.
*
* @param user the user whose tokens should be deleted.
* @throws SQLException if something untoward happens
*/
public void deleteTokens(final User user) throws SQLException {
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement
= connection.prepareStatement(DELETE_TOKENS_FOR_USER)) {
statement.setString(1, user.getUsername());
statement.execute();
}
}

/**
* Returns the current list of reset requests - excluding the all important token.
*
* @return the list of reset requests.
*/
public List<ResetRequest> getResetRequests() {
try {
purgeOldTokens();
try (final Connection connection = connectionSupplier.get();
final PreparedStatement statement = connection.prepareStatement(RESET_REQUESTS_SQL);
final ResultSet resultSet = statement.executeQuery()) {

final List<ResetRequest> resetRequests = new ArrayList<>();
while (resultSet.next()) {

final ResetRequest resetRequest = new ResetRequest(
resultSet.getString("userId"),
resultSet.getString("sourceAddress"),
resultSet.getTimestamp("expires"));
resetRequests.add(resetRequest);
}
return resetRequests;
}
} catch (final SQLException e) {
log.error("Unexpected exception retrieving outstanding requests", e);
return Collections.emptyList();
}
}

@Data
public static class ResetRequest {
public final String userId;
public final String sourceAddress;
public final Date expires;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,6 @@ private Dto() {
resetRequests = resetTokenManager.getResetRequests();
}

private boolean allValid() {
return serverError.isEmpty() && senderNameError.isEmpty()
&& senderAddressError.isEmpty() && subjectError.isEmpty() && bodyError.isEmpty()
&& expiryError.isEmpty() && minLengthError.isEmpty() && maxLengthError.isEmpty();
}

private Dto(final HttpServletRequest request) {
this.notSupported = userProvider.isReadOnly();
this.enabled = ParamUtils.getBooleanParameter(request, "enabled");
Expand All @@ -245,6 +239,12 @@ private Dto(final HttpServletRequest request) {
resetRequests = resetTokenManager.getResetRequests();
}

private boolean allValid() {
return serverError.isEmpty() && senderNameError.isEmpty()
&& senderAddressError.isEmpty() && subjectError.isEmpty() && bodyError.isEmpty()
&& expiryError.isEmpty() && minLengthError.isEmpty() && maxLengthError.isEmpty();
}

private String validateMaxLength() {
final int max = StringUtils.parseInteger(this.maxLength).orElse(-1);
if (max < 0) {
Expand Down
Loading

0 comments on commit fd5d4c6

Please sign in to comment.