working on backend:

- started FileStore implementation
- implemented placing cookies

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2024-07-18 01:22:43 +02:00
parent 67606a80f4
commit c5352ac73b
18 changed files with 399 additions and 26 deletions

View File

@@ -0,0 +1,21 @@
plugins {
id 'java'
}
group = 'de.srsoftware'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation project(':de.srsoftware.oidc.api')
implementation 'org.json:json:20240303'
}
test {
useJUnitPlatform()
}

View File

@@ -0,0 +1,87 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.file; /* © SRSoftware 2024 */
import static de.srsoftware.oidc.api.User.*;
import de.srsoftware.oidc.api.PasswordHasher;
import de.srsoftware.oidc.api.User;
import de.srsoftware.oidc.api.UserService;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import org.json.JSONObject;
public class FileStore implements UserService {
private static final String USERS = "users";
private final Path storageFile;
private final JSONObject json;
private final PasswordHasher<String> passwordHasher;
public FileStore(File storage, PasswordHasher<String> passwordHasher) throws IOException {
this.storageFile = storage.toPath();
this.passwordHasher = passwordHasher;
if (!storage.exists()) {
var parent = storage.getParentFile();
if (!parent.exists() && !parent.mkdirs()) throw new FileNotFoundException("Failed to create directory %s".formatted(parent));
Files.writeString(storageFile, "{}");
}
json = new JSONObject(Files.readString(storageFile));
}
@Override
public Optional<User> load(String username, String password) {
try {
var users = json.getJSONObject(USERS);
var uuids = users.keySet();
for (String uuid : uuids) {
var user = users.getJSONObject(uuid);
if (!user.getString(USERNAME).equals(username)) continue;
var hashedPass = user.getString(PASSWORD);
if (passwordHasher.matches(password, hashedPass)) {
return Optional.of(new User(username, hashedPass, user.getString(REALNAME), user.getString(EMAIL), uuid));
}
}
return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
}
@Override
public UserService delete(User user) {
return null;
}
@Override
public UserService init(User defaultUser) {
if (!json.has(USERS)) save(defaultUser);
return this;
}
@Override
public UserService save(User user) {
JSONObject users;
if (!json.has(USERS)) {
json.put(USERS, users = new JSONObject());
} else
users = json.getJSONObject(USERS);
users.put(user.uuid(), user.map(true));
try {
Files.writeString(storageFile, json.toString(2));
} catch (IOException e) {
throw new RuntimeException(e);
}
return this;
}
@Override
public List<User> list() {
return List.of();
}
}

View File

@@ -0,0 +1,39 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.file;
import static java.nio.charset.StandardCharsets.UTF_8;
import de.srsoftware.oidc.api.PasswordHasher;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class UuidHasher implements PasswordHasher<String> {
private static final String SHA256 = "SHA-256";
private final MessageDigest digest;
public UuidHasher() throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance(SHA256);
}
@Override
public String hash(String password, String uuid) {
var salt = uuid;
var saltedPass = "%s %s".formatted(salt, password);
var bytes = digest.digest(saltedPass.getBytes(UTF_8));
return "%s@%s".formatted(hex(bytes), salt);
}
@Override
public String salt(String hashedPassword) {
return hashedPassword.split("@")[1];
}
public static String hex(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString();
}
}