Skip to content
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

663: Protect pw reset mail #1526

Merged
merged 5 commits into from
Jul 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
import java.time.Instant

@Suppress("unused")
class ResetPasswordMutationService {
@GraphQLDescription("Sends a mail that allows the administrator to reset their password.")
fun sendResetMail(dfe: DataFetchingEnvironment, project: String, email: String): Boolean {
val logger = LoggerFactory.getLogger(ResetPasswordMutationService::class.java)
val backendConfig = dfe.getContext<GraphQLContext>().backendConfiguration
val projectConfig = backendConfig.projects.find { it.id == project }
?: throw ProjectNotFoundException(project)
Expand All @@ -35,6 +37,10 @@ class ResetPasswordMutationService {
val key = AdministratorsRepository.setNewPasswordResetKey(user)
Mailer.sendResetPasswordMail(backendConfig, projectConfig, key, email)
}
if (user == null) {
val context = dfe.getContext<GraphQLContext>()
logger.info("${context.remoteIp} $email failed to request password reset mail")
}
f1sh1918 marked this conversation as resolved.
Show resolved Hide resolved
}
return true
}
Expand All @@ -47,7 +53,9 @@ class ResetPasswordMutationService {
passwordResetKey: String,
newPassword: String
): Boolean {
val logger = LoggerFactory.getLogger(ResetPasswordMutationService::class.java)
val backendConfig = dfe.getContext<GraphQLContext>().backendConfiguration
val context = dfe.getContext<GraphQLContext>()
if (!backendConfig.projects.any { it.id == project }) throw ProjectNotFoundException(project)
transaction {
val user = Administrators.innerJoin(Projects).slice(Administrators.columns)
Expand All @@ -57,11 +65,14 @@ class ResetPasswordMutationService {
val passwordResetKeyHash = user?.passwordResetKeyHash
// We don't send error messages for empty collection to the user to avoid scraping of mail addresses
if (user === null || passwordResetKeyHash === null) {
logger.info("${context.remoteIp} $email failed to reset password (unknown user or no reset mail sent)")
return@transaction
}
if (user.passwordResetKeyExpiry!!.isBefore(Instant.now())) {
logger.info("${context.remoteIp} $email failed to reset password (expired reset key)")
throw PasswordResetKeyExpiredException()
} else if (!PasswordCrypto.verifyPasswordResetKey(passwordResetKey, passwordResetKeyHash)) {
logger.info("${context.remoteIp} $email failed to reset password (invalid reset key)")
throw InvalidLinkException()
}

Expand Down