Add UserHandler with promote/demote capabilities.
Fix bug in ConfigLoad preventing salt and hash fields from being populated when loading users. Convert User to a class. Fix UserService.getUser bug where it would compare the input user string instead of the resulting user against null.
This commit is contained in:
parent
f6c6930e50
commit
9f4c55e80d
8 changed files with 95 additions and 4 deletions
|
|
@ -20,7 +20,9 @@ The server includes a (working but very WIP) HTTP API for third-party clients an
|
||||||
- [x] Search
|
- [x] Search
|
||||||
- [x] Downloads
|
- [x] Downloads
|
||||||
- [ ] Resumable downloads
|
- [ ] Resumable downloads
|
||||||
- [ ] User Management
|
- [x] User Management
|
||||||
|
- [x] Promote/demote users
|
||||||
|
- [ ] Create/delete users
|
||||||
|
|
||||||
### Web interface
|
### Web interface
|
||||||
- [x] Authentication
|
- [x] Authentication
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,40 @@
|
||||||
package org.adrianvictor.livingroom.auth;
|
package org.adrianvictor.livingroom.auth;
|
||||||
|
|
||||||
|
import org.adrianvictor.livingroom.config.AppConfig;
|
||||||
import org.adrianvictor.livingroom.utils.PasswordUtils;
|
import org.adrianvictor.livingroom.utils.PasswordUtils;
|
||||||
|
|
||||||
public record User(String username, String hashedPassword, String salt, Role role) {
|
public class User {
|
||||||
|
private final String username;
|
||||||
|
private final String hashedPassword;
|
||||||
|
private final String salt;
|
||||||
|
private Role role;
|
||||||
|
|
||||||
|
public User(String username, String hashedPassword, String salt, Role role) {
|
||||||
|
this.username = username;
|
||||||
|
this.hashedPassword = hashedPassword;
|
||||||
|
this.salt = salt;
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean auth(String password) {
|
public boolean auth(String password) {
|
||||||
return PasswordUtils.verifyPassword(password, salt, hashedPassword);
|
return PasswordUtils.verifyPassword(password, salt, hashedPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AppConfig.UserConfig toConfig() {
|
||||||
|
AppConfig.UserConfig config = new AppConfig.UserConfig();
|
||||||
|
config.setRole(role.toString().toLowerCase());
|
||||||
|
config.setHash(this.hashedPassword);
|
||||||
|
config.setSalt(this.salt);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(Role role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role role() { return role; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.adrianvictor.livingroom.config;
|
package org.adrianvictor.livingroom.config;
|
||||||
|
|
||||||
import org.adrianvictor.livingroom.Logger;
|
import org.adrianvictor.livingroom.Logger;
|
||||||
|
import org.adrianvictor.livingroom.auth.User;
|
||||||
import org.adrianvictor.livingroom.utils.PasswordUtils;
|
import org.adrianvictor.livingroom.utils.PasswordUtils;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ public class ConfigLoader {
|
||||||
AppConfig.UserConfig user = new AppConfig.UserConfig();
|
AppConfig.UserConfig user = new AppConfig.UserConfig();
|
||||||
user.setRole((String) userJson.get("role"));
|
user.setRole((String) userJson.get("role"));
|
||||||
user.setPassword((String) userJson.get("password"));
|
user.setPassword((String) userJson.get("password"));
|
||||||
|
user.setSalt((String) userJson.get("salt"));
|
||||||
|
user.setHash((String) userJson.get("hash"));
|
||||||
|
|
||||||
users.put(username, user);
|
users.put(username, user);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.adrianvictor.livingroom.http;
|
package org.adrianvictor.livingroom.http;
|
||||||
|
|
||||||
import org.adrianvictor.livingroom.http.handlers.*;
|
import org.adrianvictor.livingroom.http.handlers.*;
|
||||||
|
import org.adrianvictor.livingroom.http.handlers.UserHandler;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
@ -16,6 +17,7 @@ public class Handlers {
|
||||||
map.put(new WebRedirectHandler(), "/");
|
map.put(new WebRedirectHandler(), "/");
|
||||||
map.put(new LoginHandler(), "/login");
|
map.put(new LoginHandler(), "/login");
|
||||||
map.put(new SearchHandler(), "/search");
|
map.put(new SearchHandler(), "/search");
|
||||||
|
map.put(new UserHandler(), "/user");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HashMap<Handler, String> getAll() {
|
public static HashMap<Handler, String> getAll() {
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ public class Server {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
try {
|
try {
|
||||||
AuthenticationHelper.sendUnauthorized(exchange, null);
|
AuthenticationHelper.sendUnauthorized(exchange, null);
|
||||||
|
return;
|
||||||
} catch (IOException ignored) {}
|
} catch (IOException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +99,7 @@ public class Server {
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.error("Handler error: " + e.getMessage());
|
Logger.error("Handler error: " + e.getMessage());
|
||||||
//e.printStackTrace();
|
e.printStackTrace();
|
||||||
try {
|
try {
|
||||||
exchange.sendResponseHeaders(500, 0);
|
exchange.sendResponseHeaders(500, 0);
|
||||||
exchange.close();
|
exchange.close();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.adrianvictor.livingroom.http.handlers;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
import org.adrianvictor.livingroom.Main;
|
||||||
|
import org.adrianvictor.livingroom.auth.Role;
|
||||||
|
import org.adrianvictor.livingroom.auth.Session;
|
||||||
|
import org.adrianvictor.livingroom.auth.User;
|
||||||
|
import org.adrianvictor.livingroom.http.Handler;
|
||||||
|
import org.adrianvictor.livingroom.http.HttpResponse;
|
||||||
|
import org.adrianvictor.livingroom.http.utils.AuthenticationHelper;
|
||||||
|
import org.adrianvictor.livingroom.services.UserService;
|
||||||
|
|
||||||
|
public class UserHandler implements Handler {
|
||||||
|
@Override
|
||||||
|
public HttpResponse result(String baseAddress, String path, HttpExchange exchange) {
|
||||||
|
String[] parts = path.split("/");
|
||||||
|
Session session = AuthenticationHelper.getAuthenticatedSession(exchange);
|
||||||
|
String username = session.getUsername();
|
||||||
|
|
||||||
|
if (parts.length < 2) {
|
||||||
|
return HttpResponse.json(400, "Usage: '.../user/<promote|demote>/<username>'");
|
||||||
|
}
|
||||||
|
if (UserService.getInstance().getUser(username).role() != Role.ADMIN) {
|
||||||
|
return HttpResponse.json(401, "You are not an administrator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = UserService.getInstance().getUser(parts[1]);
|
||||||
|
if (user == null) {
|
||||||
|
return HttpResponse.json(401, "This user does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (parts[0]) {
|
||||||
|
case "promote":
|
||||||
|
user.setRole(Role.ADMIN);
|
||||||
|
break;
|
||||||
|
case "demote":
|
||||||
|
user.setRole(Role.USER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return HttpResponse.json(400, "Usage: '.../user/<promote|demote>/<username>'");
|
||||||
|
}
|
||||||
|
|
||||||
|
Main.getConfig().addUser(user.getName(), user.toConfig());
|
||||||
|
Main.getConfig().saveConfig();
|
||||||
|
|
||||||
|
return HttpResponse.json(200, "Success.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return HttpResponse.json(500, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ public class UserService {
|
||||||
public User getUser(String user) {
|
public User getUser(String user) {
|
||||||
AppConfig.UserConfig raw = users.get(user);
|
AppConfig.UserConfig raw = users.get(user);
|
||||||
|
|
||||||
if (user == null) {
|
if (raw == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue