2024-08-01 17:01:50 +00:00
|
|
|
module auth.data_impl_fs;
|
2024-07-31 17:20:17 +00:00
|
|
|
|
|
|
|
import handy_httpd.components.optional;
|
|
|
|
|
2024-08-01 17:01:50 +00:00
|
|
|
import auth.data;
|
|
|
|
import auth.model;
|
2024-07-31 17:20:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* User implementation that stores each user's data in a separate directory.
|
|
|
|
*/
|
|
|
|
class FileSystemUserRepository : UserRepository {
|
|
|
|
import std.path;
|
|
|
|
import std.file;
|
|
|
|
import std.json;
|
|
|
|
|
|
|
|
private string usersDir;
|
|
|
|
|
|
|
|
this(string usersDir = "users") {
|
|
|
|
this.usersDir = usersDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional!User findByUsername(string username) {
|
|
|
|
if (
|
|
|
|
!validateUsername(username) ||
|
|
|
|
!exists(getUserDir(username)) ||
|
|
|
|
!exists(getUserDataFile(username))
|
|
|
|
) {
|
|
|
|
return Optional!User.empty;
|
|
|
|
}
|
2024-09-19 19:12:23 +00:00
|
|
|
return Optional!User.of(readUser(username));
|
|
|
|
}
|
|
|
|
|
|
|
|
User[] findAll() {
|
|
|
|
User[] users;
|
|
|
|
foreach (DirEntry entry; dirEntries(this.usersDir, SpanMode.shallow, false)) {
|
|
|
|
string username = baseName(entry.name);
|
|
|
|
users ~= readUser(username);
|
|
|
|
}
|
|
|
|
return users;
|
2024-07-31 17:20:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
User createUser(string username, string passwordHash) {
|
|
|
|
if (!validateUsername(username)) throw new Exception("Invalid username");
|
|
|
|
if (exists(getUserDir(username))) throw new Exception("User already exists.");
|
|
|
|
JSONValue userObj = JSONValue.emptyObject;
|
|
|
|
userObj.object["passwordHash"] = JSONValue(passwordHash);
|
|
|
|
string jsonStr = userObj.toPrettyString();
|
|
|
|
if (!exists(this.usersDir)) mkdir(this.usersDir);
|
|
|
|
mkdir(getUserDir(username));
|
|
|
|
std.file.write(getUserDataFile(username), cast(ubyte[]) jsonStr);
|
|
|
|
return User(username, passwordHash);
|
|
|
|
}
|
|
|
|
|
|
|
|
void deleteByUsername(string username) {
|
|
|
|
if (validateUsername(username) && exists(getUserDir(username))) {
|
|
|
|
rmdirRecurse(getUserDir(username));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private string getUserDir(string username) {
|
|
|
|
return buildPath(this.usersDir, username);
|
|
|
|
}
|
|
|
|
|
|
|
|
private string getUserDataFile(string username) {
|
|
|
|
return buildPath(this.usersDir, username, "user-data.json");
|
|
|
|
}
|
2024-09-19 19:12:23 +00:00
|
|
|
|
|
|
|
private User readUser(string username) {
|
|
|
|
if (!exists(getUserDataFile(username))) {
|
|
|
|
throw new Exception("User data file for " ~ username ~ " doesn't exist.");
|
|
|
|
}
|
|
|
|
JSONValue userObj = parseJSON(readText(getUserDataFile(username)));
|
|
|
|
return User(
|
|
|
|
username,
|
|
|
|
userObj.object["passwordHash"].str
|
|
|
|
);
|
|
|
|
}
|
2024-08-01 17:01:50 +00:00
|
|
|
}
|