diff --git a/common/lib/src/backend.dart b/common/lib/src/backend.dart index f1ed9aa..ea3b447 100644 --- a/common/lib/src/backend.dart +++ b/common/lib/src/backend.dart @@ -141,6 +141,19 @@ class MusicusBackendState extends State { _updateClient(serverSettings); }); + settings.account.listen((accountSettings) { + if (accountSettings != null) { + client.user = User( + name: accountSettings.username, + email: accountSettings.email, + password: accountSettings.password, + ); + } else { + client.user = null; + } + }); + + // This will also check for existing account settings. _updateClient(settings.server.value); final path = settings.musicLibraryPath.value; @@ -168,13 +181,26 @@ class MusicusBackendState extends State { } } - /// Create a new client based on [settings]. - void _updateClient(MusicusServerSettings settings) { + /// Create a new client based on [serverSettings]. + void _updateClient(MusicusServerSettings serverSettings) { client?.dispose(); + + User user; + + final accountSettings = settings.account.value; + if (accountSettings != null) { + user = User( + name: accountSettings.username, + email: accountSettings.email, + password: accountSettings.password, + ); + } + client = MusicusClient( - host: settings.host, - port: settings.port, - basePath: settings.apiPath, + host: serverSettings.host, + port: serverSettings.port, + basePath: serverSettings.apiPath, + user: user, ); } diff --git a/common/lib/src/settings.dart b/common/lib/src/settings.dart index 4f40ab0..df9ef54 100644 --- a/common/lib/src/settings.dart +++ b/common/lib/src/settings.dart @@ -1,8 +1,10 @@ +import 'dart:convert'; + import 'package:meta/meta.dart'; import 'package:rxdart/rxdart.dart'; /// Interface for persisting settings. -/// +/// /// The methods should return null, if there is no value associated with the /// provided key. abstract class MusicusSettingsStorage { @@ -36,6 +38,24 @@ class MusicusServerSettings { }); } +/// Settings concerning the Musicus account. +class MusicusAccountSettings { + /// The user name to login as. + final String username; + + /// An optional email address. + final String email; + + /// The password for authentication. + final String password; + + MusicusAccountSettings({ + this.username, + this.email, + this.password, + }); +} + /// Manager for all settings that are persisted. class MusicusSettings { static const defaultHost = 'musicus.johrpan.de'; @@ -46,7 +66,7 @@ class MusicusSettings { final MusicusSettingsStorage storage; /// A identifier for the base path of the music library. - /// + /// /// This could be a file path on destop systems or a tree URI in terms of the /// Android storage access framework. final musicLibraryPath = BehaviorSubject(); @@ -54,13 +74,16 @@ class MusicusSettings { /// Musicus server to connect to. final server = BehaviorSubject(); + /// Musicus account to login with. + final account = BehaviorSubject(); + /// Create a settings instance. MusicusSettings(this.storage); /// Initialize the settings. Future load() async { await storage.load(); - + final path = await storage.getString('musicLibraryPath'); if (path != null) { musicLibraryPath.add(path); @@ -75,10 +98,22 @@ class MusicusSettings { port: port, apiPath: apiPath, )); + + final username = await storage.getString('accountUsername'); + final email = await storage.getString('accountEmail'); + final passwordBase64 = await storage.getString('accountPassword'); + + if (username != null) { + account.add(MusicusAccountSettings( + username: username, + email: email, + password: utf8.decode(base64Decode(passwordBase64)), + )); + } } /// Set a new music library path. - /// + /// /// This will persist the new value and update the stream. Future setMusicLibraryPath(String path) async { await storage.setString('musicLibraryPath', path); @@ -86,7 +121,7 @@ class MusicusSettings { } /// Update the server settings. - /// + /// /// This will persist the new values and update the stream. Future setServer(MusicusServerSettings serverSettings) async { await storage.setString('serverHost', serverSettings.host); @@ -104,9 +139,37 @@ class MusicusSettings { )); } + /// Update the account settings. + /// + /// This will persist the new values and update the stream. + Future setAccount(MusicusAccountSettings accountSettings) async { + await storage.setString('accountUsername', accountSettings.username); + await storage.setString('accountEmail', accountSettings.email); + + // IMPORTANT NOTE: We encode the password using Base64 to defend just the + // simplest of simplest attacks. This provides no additional security + // besides the fact that the password looks a little bit encrypted. + await storage.setString( + 'accountPassword', + base64Encode(utf8.encode(accountSettings.password)), + ); + + account.add(accountSettings); + } + + /// Delete the current account settings. + Future clearAccount() async { + await storage.setString('accountUsername', null); + await storage.setString('accountEmail', null); + await storage.setString('accountPassword', null); + + account.add(null); + } + /// Tidy up. void dispose() { musicLibraryPath.close(); server.close(); + account.close(); } }