import 'dart:convert'; import 'dart:typed_data'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:pointycastle/impl.dart'; import '/components/flash_message.dart'; import '/components/custom_title_bar.dart'; import '/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/session_cookie.dart'; @immutable class ChangePassword extends StatelessWidget { ChangePassword({ Key? key, required this.privateKey }) : super(key: key); final RSAPrivateKey privateKey; final _formKey = GlobalKey(); final TextEditingController _currentPasswordController = TextEditingController(); final TextEditingController _newPasswordController = TextEditingController(); final TextEditingController _newPasswordConfirmController = TextEditingController(); bool invalidCurrentPassword = false; @override Widget build(BuildContext context) { return Scaffold( appBar: const CustomTitleBar( title: Text( 'Profile', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold ) ), showBack: true, backgroundColor: Colors.transparent, ), body: Form( key: _formKey, child: Padding( padding: const EdgeInsets.only( left: 20, right: 20, top: 30, ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'Change Password', style: TextStyle( fontSize: 25, ), ), const SizedBox(height: 30), TextFormField( controller: _currentPasswordController, decoration: const InputDecoration( hintText: 'Current Password', ), // The validator receives the text that the user has entered. validator: (value) { if (value == null || value.isEmpty) { return 'Enter your current password'; } if (invalidCurrentPassword) { return 'Invalid password'; } return null; }, ), const SizedBox(height: 10), TextFormField( controller: _newPasswordController, obscureText: true, enableSuggestions: false, autocorrect: false, decoration: const InputDecoration( hintText: 'New Password', ), // The validator receives the text that the user has entered. validator: (value) { if (value == null || value.isEmpty) { return 'Enter a new password'; } return null; }, ), const SizedBox(height: 10), TextFormField( controller: _newPasswordConfirmController, obscureText: true, enableSuggestions: false, autocorrect: false, decoration: const InputDecoration( hintText: 'Confirm Password', ), // The validator receives the text that the user has entered. validator: (value) { if (value == null || value.isEmpty) { return 'Confirm your password'; } if (value != _newPasswordController.text) { return 'Passwords do not match'; } return null; }, ), const SizedBox(height: 15), ElevatedButton( onPressed: () { if (!_formKey.currentState!.validate()) { return; } ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Processing Data')), ); _changePassword(context) .then((dynamic) { Navigator.of(context).pop(); }); }, child: const Text('Submit'), ), ], ) ) ) ); } Future _changePassword(BuildContext context) async { String privateKeyPem = CryptoUtils.encodeRSAPrivateKeyToPem(privateKey); String privateKeyEncrypted = AesHelper.aesEncrypt( _newPasswordController.text, Uint8List.fromList(privateKeyPem.codeUnits), ); String payload = jsonEncode({ 'old_password': _currentPasswordController.text, 'new_password': _newPasswordController.text, 'new_password_confirm': _newPasswordConfirmController.text, 'private_key': privateKeyEncrypted, }); var resp = await http.post( await MyProfile.getServerUrl('api/v1/auth/change_password'), headers: { 'Content-Type': 'application/json; charset=UTF-8', 'cookie': await getSessionCookie(), }, body: payload, ); if (resp.statusCode == 403) { invalidCurrentPassword = true; _formKey.currentState!.validate(); return; } if (resp.statusCode != 204) { showMessage( 'An unexpected error occured, please try again later.', context, ); } } }