diff --git a/lib/backend/request.dart b/lib/backend/request.dart index 39df13f..faf76e5 100644 --- a/lib/backend/request.dart +++ b/lib/backend/request.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'dart:convert'; import './resolve_url.dart'; -import './storage.dart'; +import './user.dart'; enum Result { ok, @@ -29,11 +29,11 @@ Future postWithCreadentials( {required OutbagServer target, String path = '', required Map body, - required LoginDetails credentials}) async { + required User credentials}) async { Map headers = { "Content-Type": "application/json", 'Authorization': - 'Digest name=${credentials.username} server=${target.base} accountKey=${credentials.password}' + 'Digest name=${credentials.username} server=${target.tag} accountKey=${credentials.password}' }; return await usePostApi( target: target, path: path, headers: headers, body: body); diff --git a/lib/backend/resolve_url.dart b/lib/backend/resolve_url.dart index 0f87ccd..53d2f04 100644 --- a/lib/backend/resolve_url.dart +++ b/lib/backend/resolve_url.dart @@ -2,6 +2,8 @@ import 'package:localstore/localstore.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; +import 'package:outbag_app/main.dart'; + const String wellKnownPath = "/.well-known/outbag/server"; const int defaultPort = 7223; @@ -21,7 +23,7 @@ class OutbagServer { final String tag; const OutbagServer( - {required this.host, + {required this.host, required this.port, required this.path, required this.tag}); @@ -35,23 +37,28 @@ class OutbagServer { ).toString(); } - void toDisk() async { + factory OutbagServer.fromMap(Map data) { + return OutbagServer( + tag: data['tag'], + host: data['host'], + path: data['path'], + port: data['port']); + } + + Map toMap() { + return {'host': host, 'port': port, 'path': path, 'tag': tag}; + } + + Future toDisk() async { final db = Localstore.instance; - await db - .collection('meta') - .doc('server') - .set({'host': host, 'port': port, 'path': path, 'tag': tag}); + await db.collection('meta').doc('server').set(toMap()); } static Future fromDisk() async { final db = Localstore.instance; final data = await db.collection('meta').doc('server').get(); - return OutbagServer( - tag: data?['tag'], - host: data?['host'], - path: data?['path'], - port: data?['port']); + return OutbagServer.fromMap(data!); } } @@ -63,18 +70,18 @@ Future getOutbagServerUrl(String tag) async { try { final uri = await fetchWellKnown(rootUri.host, rootUri.port); return OutbagServer( - host: rootUri.host, - port: uri.port, - path: uri.path, - tag: onRoot ? rootUri.host : '$rootUri.host:$uri.port'); + host: rootUri.host, + port: uri.port, + path: uri.path, + tag: onRoot ? rootUri.host : '${rootUri.host}:${uri.port}'); } catch (_) { if (onRoot) { final uri = await fetchWellKnown(rootUri.host, defaultPort); return OutbagServer( - host: rootUri.host, - port: uri.port, - path: uri.path, - tag: onRoot ? rootUri.host : '$rootUri.host:$uri.port'); + host: rootUri.host, + port: uri.port, + path: uri.path, + tag: onRoot ? rootUri.host : '${rootUri.host}:${uri.port}'); } } throw Error(); diff --git a/lib/backend/storage.dart b/lib/backend/storage.dart deleted file mode 100644 index d12a0e9..0000000 --- a/lib/backend/storage.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:localstore/localstore.dart'; -import './resolve_url.dart'; - -class LoginDetails { - const LoginDetails( - {required this.username, required this.password, required this.server}); - - final String username; - final String password; - final OutbagServer server; - - void toDisk() async { - final db = Localstore.instance; - await db - .collection('meta') - .doc('auth') - .set({'username': username, 'password': password}); - server.toDisk(); - } - - static Future fromDisk() async { - final db = Localstore.instance; - final data = await db.collection('meta').doc('auth').get(); - final server = await OutbagServer.fromDisk(); - - return LoginDetails( - username: data?['username'], - password: data?['password'], - server: server, - ); - } -} - -// obtain room list -Future?> getRooms() async { - final db = Localstore.instance; - return await db.collection('rooms').get(); -} diff --git a/lib/backend/user.dart b/lib/backend/user.dart new file mode 100644 index 0000000..659ca52 --- /dev/null +++ b/lib/backend/user.dart @@ -0,0 +1,38 @@ +import 'package:localstore/localstore.dart'; +import './resolve_url.dart'; + +class User { + const User( + {required this.username, required this.password, required this.server}); + + final String username; + final String password; + final OutbagServer server; + + Future toDisk() async { + final db = Localstore.instance; + await db + .collection('meta') + .doc('auth') + .set({'username': username, 'password': password}); + await server.toDisk(); + } + + static Future fromDisk() async { + final db = Localstore.instance; + final data = await db.collection('meta').doc('auth').get(); + final server = await OutbagServer.fromDisk(); + + return User( + username: data?['username'], + password: data?['password'], + server: server, + ); + } + + static listen(Function(Map) cb) async { + final db = Localstore.instance; + final stream = db.collection('meta').stream; + stream.listen(cb); + } +} diff --git a/lib/main.dart b/lib/main.dart index d7235c3..9c207a3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,22 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:outbag_app/backend/storage.dart'; +import 'package:outbag_app/backend/user.dart'; +import 'package:outbag_app/screens/room/new.dart'; import './screens/home.dart'; import './screens/welcome.dart'; import './screens/room.dart'; import './screens/auth.dart'; import './backend/request.dart'; import 'package:routemaster/routemaster.dart'; -import 'package:localstore/localstore.dart'; -// routes when user is logged in -final routesLoggedIn = RouteMap(routes: { - '/': (_) => const MaterialPage(child: HomePage()), - '/r/:server/:tag/:page': (info) => MaterialPage( - child: RoomPage(info.pathParameters['server'] ?? "", - info.pathParameters['tag'] ?? "", - page: info.pathParameters['page'] ?? ""), - ) - }, onUnknownRoute: (_) => const Redirect('/')); // routes when user is not logged in final routesUnauthorized = RouteMap(routes: { '/welcome/': (_) => const MaterialPage(child: WelcomePage()), @@ -24,7 +15,23 @@ final routesUnauthorized = RouteMap(routes: { '/signupOTA': (_) => const MaterialPage(child: AuthPage(mode: Mode.signupOTA)), '/signin': (_) => const MaterialPage(child: AuthPage(mode: Mode.signin)), - }, onUnknownRoute: (_) => const Redirect('/welcome')); + }, onUnknownRoute: (_) => const MaterialPage(child: WelcomePage())); + +// routes when user is logged in +final routesLoggedIn = RouteMap(routes: { + '/': (_) => const MaterialPage(child: HomePage()), + '/new': (_) => const MaterialPage(child: NewRoomPage()), + '/r/:server/:tag/:page?': (info) => MaterialPage( + child: RoomPage(info.pathParameters['server'] ?? "", + info.pathParameters['tag'] ?? "", + page: info.pathParameters['page'] ?? ""), + ), + '/r/:server/:tag/': (info) => MaterialPage( + child: RoomPage(info.pathParameters['server'] ?? "", + info.pathParameters['tag'] ?? "", + page: 'list'), + ), + }, onUnknownRoute: (_) => const Redirect('/')); void main() { WidgetsFlutterBinding.ensureInitialized(); @@ -39,7 +46,10 @@ class OutbagApp extends StatefulWidget { } class _OutbagAppState extends State { - bool isAuthorized = false; + // assume user is logged in + // unless not userdata is found + // or the userdata turns out to be wrong + bool isAuthorized = true; @override void initState() { @@ -49,8 +59,18 @@ class _OutbagAppState extends State { // with existing details (() async { + User credentials; + try { + credentials = await User.fromDisk(); + } catch (_) { + // invalid credentials + // log out + setState(() { + isAuthorized = false; + }); + return; + } try { - final credentials = await LoginDetails.fromDisk(); final resp = await postUnauthorized( target: credentials.server, path: 'signin', @@ -63,6 +83,12 @@ class _OutbagAppState extends State { setState(() { isAuthorized = true; }); + } else { + // credentials are wrong + // log out + setState(() { + isAuthorized = true; + }); } } catch (_) { // user is currently offline @@ -76,11 +102,9 @@ class _OutbagAppState extends State { })(); // wait for user to be authorized - final db = Localstore.instance; - final stream = db.collection('meta').stream; - stream.listen((data) async { + User.listen((data) async { try { - await LoginDetails.fromDisk(); + await User.fromDisk(); setState(() { isAuthorized = true; });