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.

170 lines
4.8 KiB

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