Remember me + encrypt password in json file !
This commit is contained in:
parent
d9fc06b126
commit
86e4beb362
@ -9,6 +9,7 @@ class RoundedInputField extends StatelessWidget {
|
||||
final String initialValue;
|
||||
final Color color, textColor, iconColor;
|
||||
final int maxLength;
|
||||
final bool isEmail;
|
||||
const RoundedInputField({
|
||||
Key key,
|
||||
this.hintText,
|
||||
@ -19,6 +20,7 @@ class RoundedInputField extends StatelessWidget {
|
||||
this.iconColor = kPrimaryColor,
|
||||
this.onChanged,
|
||||
this.maxLength, // 50
|
||||
this.isEmail = false
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -30,6 +32,7 @@ class RoundedInputField extends StatelessWidget {
|
||||
initialValue: initialValue,
|
||||
cursorColor: textColor,
|
||||
maxLength: maxLength,
|
||||
keyboardType: isEmail ? TextInputType.emailAddress : TextInputType.text,
|
||||
style: TextStyle(fontSize: 20, color: textColor),
|
||||
decoration: InputDecoration(
|
||||
icon: icon != null ? Icon(
|
||||
|
||||
@ -4,9 +4,11 @@ import 'package:manager_app/constants.dart';
|
||||
|
||||
class RoundedPasswordField extends StatefulWidget {
|
||||
final ValueChanged<String> onChanged;
|
||||
final String initialValue;
|
||||
const RoundedPasswordField({
|
||||
Key key,
|
||||
this.onChanged,
|
||||
this.initialValue,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -19,9 +21,10 @@ class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFieldContainer(
|
||||
child: TextField(
|
||||
child: TextFormField(
|
||||
obscureText: isVisible,
|
||||
onChanged: widget.onChanged,
|
||||
initialValue: widget.initialValue,
|
||||
cursorColor: kPrimaryColor,
|
||||
style: TextStyle(fontSize: 20, color: kBlack),
|
||||
decoration: InputDecoration(
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:encrypt/encrypt.dart';
|
||||
import 'package:manager_app/Models/session.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class SessionHelper {
|
||||
// TODO instance LOAD FILE..
|
||||
final key = Key.fromUtf8('aVs:ZMe3EK-yS<y:;k>vCGrj3T8]yG6E');
|
||||
final iv = IV.fromLength(16);
|
||||
|
||||
|
||||
Future<String> get _localPath async {
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
|
||||
@ -19,21 +24,40 @@ class SessionHelper {
|
||||
Future<File> writeSession(Session session) async {
|
||||
final file = await _localFile;
|
||||
|
||||
if (session.password != null) {
|
||||
var encrypter = Encrypter(AES(key));
|
||||
var encrypted = encrypter.encrypt(session.password, iv: iv);
|
||||
|
||||
session.password = encrypted.base64;
|
||||
}
|
||||
// Write the file
|
||||
return file.writeAsString(session.toString());
|
||||
return file.writeAsString(jsonEncode(session.toMap()));
|
||||
}
|
||||
|
||||
Future<int> readSession() async {
|
||||
Future<Session> readSession() async {
|
||||
try {
|
||||
final file = await _localFile;
|
||||
|
||||
// Read the file
|
||||
final contents = await file.readAsString();
|
||||
|
||||
return int.parse(contents);
|
||||
Session session = Session.fromJson(jsonDecode(contents));
|
||||
|
||||
var encrypter = Encrypter(AES(key));
|
||||
|
||||
if (session.password != null) {
|
||||
session.password = encrypter.decrypt64(session.password, iv: iv);
|
||||
}
|
||||
|
||||
return session;
|
||||
} catch (e) {
|
||||
if (e.toString().contains("cannot find the file")) {
|
||||
final path = await _localPath;
|
||||
new File('$path/session.json').createSync(recursive: true);
|
||||
print("file created");
|
||||
await writeSession(new Session(rememberMe: false));
|
||||
}
|
||||
// If encountering an error, return 0
|
||||
return 0;
|
||||
return Session(rememberMe: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:manager_app/Models/session.dart';
|
||||
import 'package:manager_app/client.dart';
|
||||
import 'package:managerapi/api.dart';
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
class Session {
|
||||
bool isRememberMe;
|
||||
bool rememberMe;
|
||||
String host;
|
||||
String email;
|
||||
String password;
|
||||
|
||||
Session({this.isRememberMe, this.host, this.email, this.password});
|
||||
Session({this.rememberMe, this.host, this.email, this.password});
|
||||
|
||||
factory Session.fromJson(Map<String, dynamic> json) {
|
||||
return new Session(
|
||||
isRememberMe: json['isRememberMe'] as bool,
|
||||
rememberMe: json['rememberMe'] as bool,
|
||||
host: json['host'] as String,
|
||||
email: json['email'] as String,
|
||||
password: json['password'] as String
|
||||
@ -17,7 +17,7 @@ class Session {
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'isRememberMe': isRememberMe,
|
||||
'rememberMe': rememberMe,
|
||||
'host': host,
|
||||
'email': email,
|
||||
'password': password
|
||||
@ -26,6 +26,6 @@ class Session {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{isRememberMe: $isRememberMe, host: $host, email: $email, password: $password}';
|
||||
return '{rememberMe: $rememberMe, host: $host, email: $email, password: $password}';
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,7 @@ import 'package:manager_app/Screens/Resources/resources_screen.dart';
|
||||
import 'package:manager_app/Screens/login_screen.dart';
|
||||
import 'package:manager_app/app_context.dart';
|
||||
import 'package:manager_app/constants.dart';
|
||||
import 'package:manager_app/main.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
||||
@ -129,7 +130,9 @@ class _BodyState extends State<Body> {
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.logout),
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
var session = await loadJsonSessionFile();
|
||||
|
||||
setState(() {
|
||||
print("Logout");
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
@ -140,7 +143,7 @@ class _BodyState extends State<Body> {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return LoginScreen();
|
||||
return LoginScreen(session: session);
|
||||
},
|
||||
),
|
||||
(Route<dynamic> route) => false // For pushAndRemoveUntil
|
||||
|
||||
@ -1,24 +1,22 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:manager_app/Components/loading.dart';
|
||||
import 'package:manager_app/Components/message_notification.dart';
|
||||
import 'package:manager_app/Components/rounded_button.dart';
|
||||
import 'package:manager_app/Components/rounded_input_field.dart';
|
||||
import 'package:manager_app/Components/rounded_password_field.dart';
|
||||
import 'package:manager_app/Helpers/SessionHelper.dart';
|
||||
import 'package:manager_app/Models/managerContext.dart';
|
||||
import 'package:manager_app/Models/session.dart';
|
||||
import 'package:manager_app/Screens/Main/main_screen.dart';
|
||||
import 'package:manager_app/app_context.dart';
|
||||
import 'package:manager_app/client.dart';
|
||||
import 'package:manager_app/constants.dart';
|
||||
import 'package:managerapi/api.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
LoginScreen({Key key}) : super(key: key);
|
||||
final Session session;
|
||||
LoginScreen({Key key, this.session}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LoginScreenState createState() => _LoginScreenState();
|
||||
@ -39,7 +37,6 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
|
||||
clientAPI = Client(this.host);
|
||||
|
||||
var isError = true;
|
||||
if (this.email != null && this.password != null && this.host != null) {
|
||||
|
||||
// if () {} // Add if token exist and not null + not expired
|
||||
@ -55,12 +52,14 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
setAccessToken(token.accessToken);
|
||||
|
||||
if (isRememberMe) {
|
||||
Session updatedSession = new Session(rememberMe: isRememberMe, host: host, email: email, password: password);
|
||||
print("REMBER ME TEST SESSIOn");
|
||||
// update JSON FILE
|
||||
SessionHelper().writeSession(updatedSession);
|
||||
}
|
||||
|
||||
showNotification(Colors.lightGreen, kWhite, 'Connexion réussie', context);
|
||||
|
||||
isError = false;
|
||||
// Set the appContext
|
||||
if (appContext.getContext() == null) {
|
||||
ManagerAppContext managerAppContext = new ManagerAppContext();
|
||||
@ -97,40 +96,6 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!isError) {
|
||||
/*UserDetailDTO user = await clientAPI.userApi.userGetDetail("6071f74aaf542f03116f2b9b");
|
||||
print("user values ??");
|
||||
print(user.email);
|
||||
print(user.id);
|
||||
|
||||
List<ConfigurationDTO> configurations = await clientAPI.configurationApi.configurationGet();
|
||||
print("number of configurations " + configurations.length.toString());
|
||||
configurations.forEach((element) {
|
||||
print(element);
|
||||
});
|
||||
|
||||
/*List<SectionDTO> sections = await clientAPI.sectionApi.sectionGetFromConfiguration(id);
|
||||
print("number of sections " + sections.length.toString());
|
||||
sections.forEach((element) {
|
||||
print(element);
|
||||
});*/
|
||||
|
||||
SectionDTO section = await clientAPI.sectionApi.sectionGetDetail("60916249494b9eaf283b44f7");
|
||||
print(section);
|
||||
|
||||
List<ResourceDTO> resources = await clientAPI.resourceApi.resourceGet();
|
||||
print("number of resources " + resources.length.toString());
|
||||
resources.forEach((element) {
|
||||
print(element);
|
||||
});
|
||||
|
||||
List<DeviceDTO> devices = await clientAPI.deviceApi.deviceGet();
|
||||
print("number of devices " + devices.length.toString());
|
||||
devices.forEach((element) {
|
||||
print(element);
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
||||
void setAccessToken(String accessToken) {
|
||||
@ -143,140 +108,101 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_loadFromAsset();
|
||||
this.isRememberMe = widget.session.rememberMe;
|
||||
this.host = widget.session.host;
|
||||
this.email = widget.session.email;
|
||||
this.password = widget.session.password;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Future<String>_loadFromAsset() async { // TODO remove and use JsonHelper
|
||||
return await rootBundle.loadString("assets/files/session.json");
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
return Scaffold(
|
||||
body: FutureBuilder( // TODO REMOVE IT and replace by JSON Helper (load file in main) (to setState ok rememberMe)
|
||||
future: loadJsonSessionFile(),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
return Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
height: size.height *0.5,
|
||||
width: size.width *0.5,
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kWhite.withOpacity(0.3),
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 0.5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
height: size.height *0.65,
|
||||
width: size.width *0.5,
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kWhite.withOpacity(0.3),
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 0.5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 60.0, right: 60.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RoundedInputField(
|
||||
hintText: "Host",
|
||||
onChanged: (value) {
|
||||
host = value;
|
||||
},
|
||||
initialValue: host,
|
||||
icon: Icons.home
|
||||
),
|
||||
RoundedInputField(
|
||||
hintText: "Email",
|
||||
onChanged: (value) {
|
||||
email = value;
|
||||
},
|
||||
icon: Icons.person,
|
||||
initialValue: email,
|
||||
isEmail: true,
|
||||
),
|
||||
RoundedPasswordField(
|
||||
initialValue: password,
|
||||
onChanged: (value) {
|
||||
password = value;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Checkbox(
|
||||
checkColor: kTextLightColor,
|
||||
activeColor: kPrimaryColor,
|
||||
value: this.isRememberMe,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
this.isRememberMe = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
Text("Se souvenir de moi", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 60.0, right: 60.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RoundedInputField(
|
||||
hintText: "Host",
|
||||
onChanged: (value) {
|
||||
host = value;
|
||||
},
|
||||
icon: Icons.home
|
||||
),
|
||||
RoundedInputField(
|
||||
hintText: "Email",
|
||||
onChanged: (value) {
|
||||
email = value;
|
||||
},
|
||||
icon: Icons.person
|
||||
),
|
||||
RoundedPasswordField(
|
||||
onChanged: (value) {
|
||||
password = value;
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Checkbox(
|
||||
checkColor: kTextLightColor,
|
||||
activeColor: kPrimaryColor,
|
||||
value: this.isRememberMe,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
this.isRememberMe = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
Text("Se souvenir de moi", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: size.height * 0.02),
|
||||
!isLoading ? RoundedButton(
|
||||
text: "LOGIN",
|
||||
fontSize: 25,
|
||||
press: () {
|
||||
authenticateTRY(appContext);
|
||||
},
|
||||
): Container(
|
||||
height: size.height * 0.1,
|
||||
child: Loading()
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text("No data");
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: size.height * 0.2,
|
||||
SizedBox(height: size.height * 0.05),
|
||||
!isLoading ? RoundedButton(
|
||||
text: "LOGIN",
|
||||
fontSize: 25,
|
||||
press: () {
|
||||
authenticateTRY(appContext);
|
||||
},
|
||||
): Container(
|
||||
height: size.height * 0.1,
|
||||
child: Loading()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Future loadJsonSessionFile() async { // TODO use jsonHelper in this method
|
||||
String jsonString = await _loadFromAsset();
|
||||
final jsonResponse = jsonDecode(jsonString);
|
||||
|
||||
try{
|
||||
var rememberMeJson = jsonResponse.rememberMe != null ? jsonResponse.rememberMe : false;
|
||||
var hostJson = jsonResponse.host;
|
||||
var emailJson = jsonResponse.email;
|
||||
var passwordJson = jsonResponse.password;
|
||||
|
||||
if (rememberMeJson && hostJson != null && emailJson != null && passwordJson != null) {
|
||||
setState(() {
|
||||
isRememberMe = rememberMeJson;
|
||||
host = hostJson;
|
||||
email = emailJson;
|
||||
password = passwordJson;
|
||||
});
|
||||
}
|
||||
|
||||
} catch(Exception) {
|
||||
|
||||
}
|
||||
|
||||
print(jsonResponse);
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,8 @@ import 'package:manager_app/Models/managerContext.dart';
|
||||
import 'package:manager_app/Screens/Main/main_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'Helpers/SessionHelper.dart';
|
||||
import 'Models/session.dart';
|
||||
import 'Screens/login_screen.dart';
|
||||
import 'app_context.dart';
|
||||
import 'constants.dart';
|
||||
@ -21,8 +23,11 @@ Future<void> main() async {
|
||||
|
||||
initialRoute = '/welcome';
|
||||
|
||||
var session = await loadJsonSessionFile();
|
||||
|
||||
final MyApp myApp = MyApp(
|
||||
initialRoute: initialRoute,
|
||||
session: session
|
||||
//context: localContext,
|
||||
);
|
||||
|
||||
@ -31,8 +36,9 @@ Future<void> main() async {
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
final String initialRoute;
|
||||
final Session session;
|
||||
final ManagerAppContext managerAppContext;
|
||||
MyApp({this.initialRoute, this.managerAppContext});
|
||||
MyApp({this.initialRoute, this.session, this.managerAppContext});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
@ -60,7 +66,7 @@ class _MyAppState extends State<MyApp> {
|
||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
),
|
||||
routes: {
|
||||
'/welcome': (context) => LoginScreen(),
|
||||
'/welcome': (context) => LoginScreen(session: widget.session),
|
||||
'/main': (context) => MainScreen()
|
||||
}
|
||||
),
|
||||
@ -68,3 +74,9 @@ class _MyAppState extends State<MyApp> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Session> loadJsonSessionFile() async {
|
||||
Session session = await SessionHelper().readSession();
|
||||
print(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
35
pubspec.lock
35
pubspec.lock
@ -1,6 +1,20 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -64,13 +78,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
crypt:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: crypt
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -106,6 +113,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
encrypt:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: encrypt
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -296,6 +310,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -38,7 +38,7 @@ dependencies:
|
||||
video_player: ^2.1.1
|
||||
drag_and_drop_lists: ^0.3.2
|
||||
path_provider: ^2.0.2
|
||||
crypt: ^4.0.1
|
||||
encrypt: ^5.0.0
|
||||
window_size:
|
||||
git:
|
||||
url: git://github.com/google/flutter-desktop-embedding.git
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user