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.

166 lines
4.7 KiB

  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:Envelope/utils/storage/get_file.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_dotenv/flutter_dotenv.dart';
  6. import 'package:pointycastle/impl.dart';
  7. import 'package:shared_preferences/shared_preferences.dart';
  8. import '/utils/encryption/aes_helper.dart';
  9. import '/utils/encryption/crypto_utils.dart';
  10. // TODO: Replace this with the prod url when server is deployed
  11. String defaultServerUrl = dotenv.env['SERVER_URL'] ?? 'http://192.168.1.5:8080';
  12. class MyProfile {
  13. String id;
  14. String username;
  15. String? friendId;
  16. RSAPrivateKey? privateKey;
  17. RSAPublicKey? publicKey;
  18. String? symmetricKey;
  19. DateTime? loggedInAt;
  20. File? image;
  21. String messageExpiryDefault = 'no_expiry';
  22. MyProfile({
  23. required this.id,
  24. required this.username,
  25. this.friendId,
  26. this.privateKey,
  27. this.publicKey,
  28. this.symmetricKey,
  29. this.loggedInAt,
  30. this.image,
  31. required this.messageExpiryDefault,
  32. });
  33. factory MyProfile._fromJson(Map<String, dynamic> json) {
  34. DateTime loggedInAt = DateTime.now();
  35. if (json.containsKey('logged_in_at')) {
  36. loggedInAt = DateTime.parse(json['logged_in_at']);
  37. }
  38. RSAPrivateKey privateKey = CryptoUtils.rsaPrivateKeyFromPem(json['asymmetric_private_key']);
  39. RSAPublicKey publicKey = CryptoUtils.rsaPublicKeyFromPem(json['asymmetric_public_key']);
  40. return MyProfile(
  41. id: json['user_id'],
  42. username: json['username'],
  43. privateKey: privateKey,
  44. publicKey: publicKey,
  45. symmetricKey: json['symmetric_key'],
  46. loggedInAt: loggedInAt,
  47. messageExpiryDefault: json['message_expiry_default'],
  48. image: json['file'] != null ? File(json['file']) : null,
  49. );
  50. }
  51. @override
  52. String toString() {
  53. return '''
  54. user_id: $id
  55. username: $username
  56. logged_in_at: $loggedInAt
  57. public_key: $publicKey
  58. private_key: $privateKey
  59. ''';
  60. }
  61. String toJson() {
  62. return jsonEncode(<String, dynamic>{
  63. 'user_id': id,
  64. 'username': username,
  65. 'asymmetric_private_key': privateKey != null ?
  66. CryptoUtils.encodeRSAPrivateKeyToPem(privateKey!) :
  67. null,
  68. 'asymmetric_public_key': publicKey != null ?
  69. CryptoUtils.encodeRSAPublicKeyToPem(publicKey!) :
  70. null,
  71. 'symmetric_key': symmetricKey,
  72. 'logged_in_at': loggedInAt?.toIso8601String(),
  73. 'message_expiry_default': messageExpiryDefault,
  74. 'file': image?.path,
  75. });
  76. }
  77. static Future<MyProfile> login(Map<String, dynamic> json, String password) async {
  78. json['asymmetric_private_key'] = AesHelper.aesDecrypt(
  79. password,
  80. base64.decode(json['asymmetric_private_key'])
  81. );
  82. json['symmetric_key'] = base64.encode(CryptoUtils.rsaDecrypt(
  83. base64.decode(json['symmetric_key']),
  84. CryptoUtils.rsaPrivateKeyFromPem(json['asymmetric_private_key']),
  85. ));
  86. if (json['image_link'] != '') {
  87. File profileIcon = await getFile(
  88. json['image_link'],
  89. json['user_id'],
  90. json['symmetric_key'],
  91. );
  92. json['file'] = profileIcon.path;
  93. }
  94. MyProfile profile = MyProfile._fromJson(json);
  95. final preferences = await SharedPreferences.getInstance();
  96. preferences.setString('profile', profile.toJson());
  97. return profile;
  98. }
  99. static Future<void> logout() async {
  100. final preferences = await SharedPreferences.getInstance();
  101. preferences.remove('profile');
  102. }
  103. static Future<MyProfile> getProfile() async {
  104. final preferences = await SharedPreferences.getInstance();
  105. String? profileJson = preferences.getString('profile');
  106. if (profileJson == null) {
  107. throw Exception('No profile');
  108. }
  109. return MyProfile._fromJson(json.decode(profileJson));
  110. }
  111. static Future<bool> isLoggedIn() async {
  112. MyProfile profile = await MyProfile.getProfile();
  113. if (profile.loggedInAt == null) {
  114. return false;
  115. }
  116. return profile.loggedInAt!.add(const Duration(hours: 12)).isAfter(
  117. (DateTime.now())
  118. );
  119. }
  120. static Future<RSAPrivateKey> getPrivateKey() async {
  121. MyProfile profile = await MyProfile.getProfile();
  122. if (profile.privateKey == null) {
  123. throw Exception('Could not get privateKey');
  124. }
  125. return profile.privateKey!;
  126. }
  127. static setServerUrl(String url) async {
  128. final preferences = await SharedPreferences.getInstance();
  129. preferences.setString('server_url', url);
  130. }
  131. static Future<Uri> getServerUrl(String path) async {
  132. final preferences = await SharedPreferences.getInstance();
  133. String? baseUrl = preferences.getString('server_url');
  134. if (baseUrl == null) {
  135. setServerUrl(defaultServerUrl);
  136. return Uri.parse('$defaultServerUrl$path');
  137. }
  138. return Uri.parse('$baseUrl$path');
  139. }
  140. }