From 1868f4e7228f1421e29b899aebfe030eb67d9b9f Mon Sep 17 00:00:00 2001 From: blallo Date: Sun, 18 Aug 2019 18:06:25 -0300 Subject: [PATCH] Added server data form. --- lib/main.dart | 20 +++-- lib/ui/server_form.dart | 153 +++++++++++++++++++++++++++++++++++ lib/utils/verify_server.dart | 42 ++++++++++ pubspec.lock | 7 ++ pubspec.yaml | 1 + 5 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 lib/ui/server_form.dart create mode 100644 lib/utils/verify_server.dart diff --git a/lib/main.dart b/lib/main.dart index 96452e1..774f506 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,29 @@ import 'package:flutter/material.dart'; +import 'ui/server_form.dart'; +import 'ui/dialog.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { + final title = 'Welcome page test'; @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.green, - ), - home: MyHomePage(title: 'Flutter Demo Home Page'), - ); + title: title, + theme: ThemeData( + primarySwatch: Colors.green, + dialogTheme: baseDialogTheme, + ), + home: Scaffold( + appBar: AppBar(title: Text(title)), + body: ServerForm(), + )); } } + + class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); diff --git a/lib/ui/server_form.dart b/lib/ui/server_form.dart new file mode 100644 index 0000000..e38d869 --- /dev/null +++ b/lib/ui/server_form.dart @@ -0,0 +1,153 @@ +import 'package:flutter/material.dart'; +import 'package:logger/logger.dart'; +import 'dart:convert'; + +import 'dialog.dart'; +import '../utils/verify_server.dart'; + +final log = Logger(); + +class ServerForm extends StatefulWidget { + ServerForm({Key key}) : super(key: key); + + @override + _ServerFormState createState() => _ServerFormState(); +} + +class _ServerFormState extends State { + Uri zAddress; + Uri botZAddress; + bool _autoValidate = false; + bool _disableFields = false; + final _serverFormKey = GlobalKey(); + + final zController = TextEditingController(); + final botZController = TextEditingController(); + + InputDecoration _textFieldDecoration(String label, IconData icon) { + return InputDecoration( + labelText: label, + icon: Icon(icon), + hintText: 'Please, insert $label address', + ); + } + + SnackBar showProgress() { + return SnackBar( + content: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CircularProgressIndicator( + value: null, + strokeWidth: 7.0, + ), + Text('Processing Data') + ], + )); + } + + String validateServer(String address) { + if (address.isEmpty) { + return 'Server address must not be empty'; + } + try { + Uri.parse(address); + } on FormatException catch (e) { + return e.toString(); + } + return null; + } + + String validateZServer(String address) { + String baseValidation = this.validateServer(address); + if (baseValidation != null) { + return baseValidation; + } + if (utf8.encode(address).length > 72) { + return "Server address string length is > 72 bytes. Refusing to go on."; + } + return null; + } + + Future _onPressed() async { + log.d("Button pressed"); + setState(() { + _disableFields = true; + }); + Scaffold.of(context).showSnackBar(this.showProgress()); + if (!_serverFormKey.currentState.validate()) { + setState(() { + _autoValidate = true; + _disableFields = false; + }); + Scaffold.of(context).hideCurrentSnackBar(); + return; + } + + bool resp; + Uri _botZAddr = Uri.parse(botZController.text); + Uri _zAddr = Uri.parse(zController.text); + log.d("Received botZAddr: $_botZAddr\tzAddr: $_zAddr"); + try { + resp = await verifyServer(_botZAddr, _zAddr); + log.i("Secret is${resp ? ' ' : ' NOT '}a match"); + } catch (err) { + log.e("Error: ${err.toString()}"); + showDialog( + context: context, + builder: errorDialogBuilder("Error", "${err.toString()}")); + } finally { + log.d("Clean the state"); + setState(() { + _disableFields = false; + }); + Scaffold.of(context).hideCurrentSnackBar(); + } + + if (!resp) { + showDialog( + context: context, + builder: errorDialogBuilder("Error", + "The BotZ server does not target the provided Z server.")); + } else { + _serverFormKey.currentState.save(); + // TODO: go to the next window. + } + + log.d("Done"); + } + + @override + Widget build(BuildContext context) { + return Form( + key: _serverFormKey, + child: Column(children: [ + TextFormField( + autofocus: true, + autocorrect: false, + controller: zController, + enabled: !_disableFields, + decoration: this._textFieldDecoration("Z server", Icons.http), + validator: this.validateZServer, + autovalidate: _autoValidate, + onSaved: (String addr) { + zAddress = Uri.parse(addr); + }), + TextFormField( + autocorrect: false, + controller: botZController, + enabled: !_disableFields, + decoration: this._textFieldDecoration("BotZ server", Icons.http), + validator: this.validateServer, + autovalidate: _autoValidate, + onSaved: (String addr) { + botZAddress = Uri.parse(addr); + }), + RaisedButton( + onPressed: _onPressed, + child: Text('Save'), + ), + ]), + ); + } +} diff --git a/lib/utils/verify_server.dart b/lib/utils/verify_server.dart new file mode 100644 index 0000000..dfc1253 --- /dev/null +++ b/lib/utils/verify_server.dart @@ -0,0 +1,42 @@ +import 'package:http/http.dart'; +import 'package:logger/logger.dart'; +import 'dart:convert'; +import 'package:dbcrypt/dbcrypt.dart'; + +import 'connection.dart'; + + +final log = Logger(); + +Future verifyServer(Uri serverAddr, Uri zTargetAddr, {Map routes=defaultRoutes}) async { + String botZTargetUri = serverAddr.toString() + routes['ping']; + + log.d("botZ server uri: $botZTargetUri"); + log.d("z server: ${zTargetAddr.toString()}"); + + var resp = await get( + botZTargetUri, + ); + + log.d("Status code: ${resp.statusCode}"); + if (resp.statusCode >= 300 || resp.statusCode < 200) { + log.d("Status code is not 2xx: $resp.statusCode"); + return false; + } + + Map respData = jsonDecode(resp.body); + + log.d("Response: ${respData.toString()}"); + if (!respData.containsKey('hash')) { + log.d("Response is malformed: ${respData.toString()}"); + return false; + } + + if (!DBCrypt().checkpw(zTargetAddr.toString(), respData['hash'])) { + log.d("The server answer do not match the expected response: ${respData.toString()}"); + return false; + } + + log.d("Response is ok!"); + return true; +} diff --git a/pubspec.lock b/pubspec.lock index 59d4665..9a6ded2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,6 +36,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + dbcrypt: + dependency: "direct main" + description: + name: dbcrypt + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 5088dce..ec82414 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: http: ^0.12.0+2 logger: ^0.7.0+2 + dbcrypt: ^1.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2