SignupInfo.java
/*
* Copyright (c) 2007-2026 MetaSolutions AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.entrystore.rest.springboot.model.auth;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import java.util.Date;
import java.util.Map;
/**
* @author Hannes Ebner
*/
@Getter
@Setter
public class SignupInfo {
private String firstName;
private String lastName;
private String email;
private String saltedHashedPassword;
private Date expirationDate;
private String urlSuccess;
private String urlFailure;
private Map<String, String> customProperties;
/**
* Number of failed credential-confirmation attempts made against this pending token. Once it
* reaches the configured limit the token is invalidated (see {@code SignupTokenCache#confirmAttempt}).
* This counter is the sole enforcement of the confirmation lockout, so it has no public setter and is
* mutated only via {@link #recordFailedConfirmation()}, keeping its monotonic increment owned here.
*/
@Setter(AccessLevel.NONE)
private int confirmationAttempts;
/**
* Records a failed credential-confirmation attempt by incrementing the counter and returning the new total.
*/
public int recordFailedConfirmation() {
return ++confirmationAttempts;
}
/**
* Estimated bytes held in this record's strings, for the token cache's byte bound: one byte per char for a
* Latin-1 string, two once it holds a char above U+00FF (compact strings). A new string field must be added
* here, or it escapes the bound.
*/
public int estimatedSize() {
int size = bytes(firstName) + bytes(lastName) + bytes(email) + bytes(saltedHashedPassword)
+ bytes(urlSuccess) + bytes(urlFailure);
if (customProperties != null) {
for (var property : customProperties.entrySet()) {
size += bytes(property.getKey()) + bytes(property.getValue());
}
}
return size;
}
private static int bytes(String value) {
if (value == null) {
return 0;
}
return value.chars().allMatch(c -> c <= 0xFF) ? value.length() : 2 * value.length();
}
public void setEmail(@NonNull String email) {
// we have to store it in lower case only to avoid problems with different cases in
// different steps of the process (if the user provides inconsistent information)
this.email = email.toLowerCase();
}
}