Add token-based authentication (without rejection handling)
This commit is contained in:
@ -8,6 +8,10 @@ import envoy.data.*;
|
||||
import envoy.event.*;
|
||||
import envoy.util.SerializationUtils;
|
||||
|
||||
import dev.kske.eventbus.Event;
|
||||
import dev.kske.eventbus.EventBus;
|
||||
import dev.kske.eventbus.EventListener;
|
||||
|
||||
/**
|
||||
* Stores information about the current {@link User} and their {@link Chat}s.
|
||||
* For message ID generation a {@link IDGenerator} is stored as well.
|
||||
@ -21,7 +25,7 @@ import envoy.util.SerializationUtils;
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public final class LocalDB {
|
||||
public final class LocalDB implements EventListener {
|
||||
|
||||
private User user;
|
||||
private Map<String, User> users = new HashMap<>();
|
||||
@ -29,7 +33,8 @@ public final class LocalDB {
|
||||
private IDGenerator idGenerator;
|
||||
private CacheMap cacheMap = new CacheMap();
|
||||
private Instant lastSync = Instant.EPOCH;
|
||||
private File dbDir, userFile, idGeneratorFile, usersFile;
|
||||
private String authToken;
|
||||
private File dbDir, userFile, idGeneratorFile, lastLoginFile, usersFile;
|
||||
|
||||
/**
|
||||
* Constructs an empty local database. To serialize any user-specific data to
|
||||
@ -42,6 +47,7 @@ public final class LocalDB {
|
||||
*/
|
||||
public LocalDB(File dbDir) throws IOException {
|
||||
this.dbDir = dbDir;
|
||||
EventBus.getInstance().registerListener(this);
|
||||
|
||||
// Test if the database directory is actually a directory
|
||||
if (dbDir.exists() && !dbDir.isDirectory())
|
||||
@ -49,6 +55,7 @@ public final class LocalDB {
|
||||
|
||||
// Initialize global files
|
||||
idGeneratorFile = new File(dbDir, "id_gen.db");
|
||||
lastLoginFile = new File(dbDir, "last_login.db");
|
||||
usersFile = new File(dbDir, "users.db");
|
||||
|
||||
// Initialize offline caches
|
||||
@ -76,12 +83,16 @@ public final class LocalDB {
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void save(boolean isOnline) throws IOException {
|
||||
|
||||
// Save users
|
||||
SerializationUtils.write(usersFile, users);
|
||||
|
||||
// Save user data and last sync time stamp
|
||||
if (user != null) SerializationUtils.write(userFile, chats, cacheMap, isOnline ? Instant.now() : lastSync);
|
||||
|
||||
// Save last login information
|
||||
if (authToken != null) SerializationUtils.write(lastLoginFile, user, authToken);
|
||||
|
||||
// Save id generator
|
||||
if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
|
||||
}
|
||||
@ -120,10 +131,24 @@ public final class LocalDB {
|
||||
idGenerator = SerializationUtils.read(idGeneratorFile, IDGenerator.class);
|
||||
} catch (ClassNotFoundException | IOException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the last login information. Any exception thrown during this process is
|
||||
* ignored.
|
||||
*
|
||||
* @since Envoy Client v0.2-beta
|
||||
*/
|
||||
public void loadLastLogin() {
|
||||
try (var in = new ObjectInputStream(new FileInputStream(lastLoginFile))) {
|
||||
user = (User) in.readObject();
|
||||
authToken = (String) in.readObject();
|
||||
} catch (ClassNotFoundException | IOException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the contact list of the client user with the chat and user
|
||||
* storage.
|
||||
*
|
||||
*
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public void synchronize() {
|
||||
@ -143,6 +168,11 @@ public final class LocalDB {
|
||||
.forEach(chats::add);
|
||||
}
|
||||
|
||||
@Event
|
||||
private void onNewAuthToken(NewAuthToken evt) {
|
||||
authToken = evt.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a {@code Map<String, User>} of all users stored locally with their
|
||||
* user names as keys
|
||||
@ -204,6 +234,12 @@ public final class LocalDB {
|
||||
*/
|
||||
public Instant getLastSync() { return lastSync; }
|
||||
|
||||
/**
|
||||
* @return the authentication token of the user
|
||||
* @since Envoy Client v0.2-beta
|
||||
*/
|
||||
public String getAuthToken() { return authToken; }
|
||||
|
||||
/**
|
||||
* Searches for a message by ID.
|
||||
*
|
||||
@ -217,7 +253,7 @@ public final class LocalDB {
|
||||
|
||||
/**
|
||||
* Searches for a chat by recipient ID.
|
||||
*
|
||||
*
|
||||
* @param recipientID the ID of the chat's recipient
|
||||
* @return an optional containing the chat
|
||||
* @since Envoy Client v0.1-beta
|
||||
|
@ -77,10 +77,12 @@ public final class Client implements EventListener, Closeable {
|
||||
// Create object receiver
|
||||
receiver = new Receiver(socket.getInputStream());
|
||||
|
||||
// Register user creation processor, contact list processor and message cache
|
||||
// Register user creation processor, contact list processor, message cache and
|
||||
// authentication token
|
||||
receiver.registerProcessor(User.class, sender -> this.sender = sender);
|
||||
receiver.registerProcessors(cacheMap.getMap());
|
||||
receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); });
|
||||
receiver.registerProcessor(NewAuthToken.class, eventBus::dispatch);
|
||||
|
||||
rejected = false;
|
||||
|
||||
@ -173,8 +175,7 @@ public final class Client implements EventListener, Closeable {
|
||||
receiver.registerProcessor(ProfilePicChange.class, eventBus::dispatch);
|
||||
|
||||
// Process requests to not send any more attachments as they will not be shown
|
||||
// to
|
||||
// other users
|
||||
// to other users
|
||||
receiver.registerProcessor(NoAttachments.class, eventBus::dispatch);
|
||||
|
||||
// Process group creation results - they might have been disabled on the server
|
||||
|
@ -77,6 +77,7 @@ public final class Startup extends Application {
|
||||
|
||||
// Prepare handshake
|
||||
localDB.loadIDGenerator();
|
||||
localDB.loadLastLogin();
|
||||
context.setLocalDB(localDB);
|
||||
|
||||
// Configure stage
|
||||
@ -87,8 +88,18 @@ public final class Startup extends Application {
|
||||
final var sceneContext = new SceneContext(stage);
|
||||
context.setSceneContext(sceneContext);
|
||||
|
||||
// Load login scene
|
||||
sceneContext.load(SceneInfo.LOGIN_SCENE);
|
||||
// Authenticate with token if present
|
||||
if (localDB.getAuthToken() != null) {
|
||||
logger.info("Attempting authentication with token...");
|
||||
localDB.initializeUserStorage();
|
||||
localDB.loadUserData();
|
||||
performHandshake(LoginCredentials.loginWithToken(localDB.getUser().getName(), localDB.getAuthToken(), VERSION, localDB.getLastSync()));
|
||||
// TODO: handle unsuccessful handshake
|
||||
} else {
|
||||
|
||||
// Load login scene
|
||||
sceneContext.load(SceneInfo.LOGIN_SCENE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,4 +23,5 @@ module envoy.client {
|
||||
opens envoy.client.ui.custom to javafx.graphics, javafx.fxml;
|
||||
opens envoy.client.ui.settings to envoy.client.util;
|
||||
opens envoy.client.net to dev.kske.eventbus;
|
||||
opens envoy.client.data to dev.kske.eventbus;
|
||||
}
|
||||
|
Reference in New Issue
Block a user