Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
7.6 KiB

  1. import 'dart:convert';
  2. import 'package:flutter/material.dart';
  3. import 'package:http/http.dart' as http;
  4. import 'package:flutter_dotenv/flutter_dotenv.dart';
  5. import '/models/my_profile.dart';
  6. import '/utils/storage/session_cookie.dart';
  7. class LoginResponse {
  8. final String status;
  9. final String message;
  10. final String publicKey;
  11. final String privateKey;
  12. final String userId;
  13. final String username;
  14. const LoginResponse({
  15. required this.status,
  16. required this.message,
  17. required this.publicKey,
  18. required this.privateKey,
  19. required this.userId,
  20. required this.username,
  21. });
  22. factory LoginResponse.fromJson(Map<String, dynamic> json) {
  23. return LoginResponse(
  24. status: json['status'],
  25. message: json['message'],
  26. publicKey: json['asymmetric_public_key'],
  27. privateKey: json['asymmetric_private_key'],
  28. userId: json['user_id'],
  29. username: json['username'],
  30. );
  31. }
  32. }
  33. Future<dynamic> login(context, String username, String password) async {
  34. final resp = await http.post(
  35. Uri.parse('${dotenv.env["SERVER_URL"]}api/v1/login'),
  36. headers: <String, String>{
  37. 'Content-Type': 'application/json; charset=UTF-8',
  38. },
  39. body: jsonEncode(<String, String>{
  40. 'username': username,
  41. 'password': password,
  42. }),
  43. );
  44. if (resp.statusCode != 200) {
  45. throw Exception(resp.body);
  46. }
  47. String? rawCookie = resp.headers['set-cookie'];
  48. if (rawCookie != null) {
  49. int index = rawCookie.indexOf(';');
  50. setSessionCookie((index == -1) ? rawCookie : rawCookie.substring(0, index));
  51. }
  52. return await MyProfile.login(json.decode(resp.body), password);
  53. }
  54. class Login extends StatelessWidget {
  55. const Login({Key? key}) : super(key: key);
  56. @override
  57. Widget build(BuildContext context) {
  58. return Scaffold(
  59. appBar: AppBar(
  60. title: null,
  61. automaticallyImplyLeading: true,
  62. leading: IconButton(icon: const Icon(Icons.arrow_back),
  63. onPressed:() => {
  64. Navigator.pop(context)
  65. }
  66. ),
  67. backgroundColor: Colors.transparent,
  68. shadowColor: Colors.transparent,
  69. ),
  70. body: const SafeArea(
  71. child: LoginWidget(),
  72. ),
  73. );
  74. }
  75. }
  76. class LoginWidget extends StatefulWidget {
  77. const LoginWidget({Key? key}) : super(key: key);
  78. @override
  79. State<LoginWidget> createState() => _LoginWidgetState();
  80. }
  81. class _LoginWidgetState extends State<LoginWidget> {
  82. final _formKey = GlobalKey<FormState>();
  83. TextEditingController usernameController = TextEditingController();
  84. TextEditingController passwordController = TextEditingController();
  85. @override
  86. Widget build(BuildContext context) {
  87. const TextStyle inputTextStyle = TextStyle(
  88. fontSize: 18,
  89. );
  90. final OutlineInputBorder inputBorderStyle = OutlineInputBorder(
  91. borderRadius: BorderRadius.circular(5),
  92. borderSide: const BorderSide(
  93. color: Colors.transparent,
  94. )
  95. );
  96. final ButtonStyle buttonStyle = ElevatedButton.styleFrom(
  97. primary: Theme.of(context).colorScheme.surface,
  98. onPrimary: Theme.of(context).colorScheme.onSurface,
  99. minimumSize: const Size.fromHeight(50),
  100. padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
  101. textStyle: TextStyle(
  102. fontSize: 20,
  103. fontWeight: FontWeight.bold,
  104. color: Theme.of(context).colorScheme.error,
  105. ),
  106. );
  107. return Center(
  108. child: Form(
  109. key: _formKey,
  110. child: Center(
  111. child: Padding(
  112. padding: const EdgeInsets.only(
  113. left: 20,
  114. right: 20,
  115. top: 0,
  116. bottom: 80,
  117. ),
  118. child: Column(
  119. mainAxisAlignment: MainAxisAlignment.center,
  120. crossAxisAlignment: CrossAxisAlignment.center,
  121. children: [
  122. Text(
  123. 'Login',
  124. style: TextStyle(
  125. fontSize: 35,
  126. color: Theme.of(context).colorScheme.onBackground,
  127. ),
  128. ),
  129. const SizedBox(height: 30),
  130. TextFormField(
  131. controller: usernameController,
  132. decoration: InputDecoration(
  133. hintText: 'Username',
  134. enabledBorder: inputBorderStyle,
  135. focusedBorder: inputBorderStyle,
  136. ),
  137. style: inputTextStyle,
  138. // The validator receives the text that the user has entered.
  139. validator: (value) {
  140. if (value == null || value.isEmpty) {
  141. return 'Enter a username';
  142. }
  143. return null;
  144. },
  145. ),
  146. const SizedBox(height: 10),
  147. TextFormField(
  148. controller: passwordController,
  149. obscureText: true,
  150. enableSuggestions: false,
  151. autocorrect: false,
  152. decoration: InputDecoration(
  153. hintText: 'Password',
  154. enabledBorder: inputBorderStyle,
  155. focusedBorder: inputBorderStyle,
  156. ),
  157. style: inputTextStyle,
  158. // The validator receives the text that the user has entered.
  159. validator: (value) {
  160. if (value == null || value.isEmpty) {
  161. return 'Enter a password';
  162. }
  163. return null;
  164. },
  165. ),
  166. const SizedBox(height: 15),
  167. ElevatedButton(
  168. style: buttonStyle,
  169. onPressed: () {
  170. if (_formKey.currentState!.validate()) {
  171. ScaffoldMessenger.of(context).showSnackBar(
  172. const SnackBar(content: Text('Processing Data')),
  173. );
  174. login(
  175. context,
  176. usernameController.text,
  177. passwordController.text,
  178. ).then((val) {
  179. Navigator.
  180. pushNamedAndRemoveUntil(
  181. context,
  182. '/home',
  183. ModalRoute.withName('/home'),
  184. );
  185. }).catchError((error) {
  186. print(error); // TODO: Show error on interface
  187. });
  188. }
  189. },
  190. child: const Text('Submit'),
  191. ),
  192. ],
  193. )
  194. )
  195. )
  196. )
  197. );
  198. }
  199. }