Add token-based authentication (without rejection handling)

This commit is contained in:
2020-09-19 11:37:42 +02:00
parent 31cb22035b
commit f21d077522
10 changed files with 178 additions and 35 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
/**

View File

@ -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;
}