verify_identity_dialog.dart 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import "dart:convert";
  2. import 'package:bip39/bip39.dart' as bip39;
  3. import "package:crypto/crypto.dart";
  4. import "package:dotted_border/dotted_border.dart";
  5. import "package:flutter/material.dart";
  6. import "package:flutter/services.dart";
  7. import "package:logging/logging.dart";
  8. import "package:photos/core/configuration.dart";
  9. import "package:photos/services/user_service.dart";
  10. import "package:photos/theme/ente_theme.dart";
  11. import "package:photos/ui/common/loading_widget.dart";
  12. import 'package:photos/ui/components/buttons/button_widget.dart';
  13. import "package:photos/ui/components/models/button_type.dart";
  14. import "package:photos/utils/share_util.dart";
  15. class VerifyIdentifyDialog extends StatefulWidget {
  16. // email id of the user who's verification ID is being displayed for
  17. // verification
  18. final String email;
  19. // self is true when the user is viewing their own verification ID
  20. final bool self;
  21. VerifyIdentifyDialog({
  22. Key? key,
  23. required this.self,
  24. this.email = '',
  25. }) : super(key: key) {
  26. if (!self && email.isEmpty) {
  27. throw ArgumentError("email cannot be empty when self is false");
  28. }
  29. }
  30. @override
  31. State<VerifyIdentifyDialog> createState() => _VerifyIdentifyDialogState();
  32. }
  33. class _VerifyIdentifyDialogState extends State<VerifyIdentifyDialog> {
  34. final bool doesUserExist = true;
  35. @override
  36. Widget build(BuildContext context) {
  37. final textStyle = getEnteTextTheme(context);
  38. final String subTitle = widget.self
  39. ? "This is your Verification ID"
  40. : "This is ${widget.email}'s Verification ID";
  41. final String bottomText = widget.self
  42. ? "Someone sharing albums with you should see the same ID on their "
  43. "device."
  44. : "Please ask them to long-press their email address on the settings "
  45. "screen, and verify that the IDs on both devices match.";
  46. final AlertDialog alert = AlertDialog(
  47. title: Text(widget.self ? "Verification ID" : "Verify ${widget.email}"),
  48. content: Column(
  49. crossAxisAlignment: CrossAxisAlignment.start,
  50. mainAxisSize: MainAxisSize.min,
  51. children: [
  52. FutureBuilder<String>(
  53. future: _getPublicKey(),
  54. builder: (context, snapshot) {
  55. if (snapshot.hasData) {
  56. final publicKey = snapshot.data!;
  57. if (publicKey.isEmpty) {
  58. return Column(
  59. mainAxisSize: MainAxisSize.min,
  60. children: [
  61. Text(
  62. "${widget.email} does not have an ente "
  63. "account.\n"
  64. "\nSend them an invite to share photos.",
  65. ),
  66. const SizedBox(height: 24),
  67. ButtonWidget(
  68. buttonType: ButtonType.neutral,
  69. icon: Icons.adaptive.share,
  70. labelText: "Send invite",
  71. isInAlert: true,
  72. onTap: () async {
  73. shareText(
  74. "Download ente so we can easily share original quality photos"
  75. " and videos\n\nhttps://ente.io/",
  76. );
  77. },
  78. ),
  79. ],
  80. );
  81. } else {
  82. return Column(
  83. crossAxisAlignment: CrossAxisAlignment.start,
  84. children: [
  85. Text(
  86. subTitle,
  87. style: textStyle.bodyMuted,
  88. ),
  89. const SizedBox(height: 20),
  90. _verificationIDWidget(context, publicKey),
  91. const SizedBox(height: 16),
  92. Text(
  93. bottomText,
  94. style: textStyle.bodyMuted,
  95. ),
  96. const SizedBox(height: 24),
  97. ButtonWidget(
  98. buttonType: ButtonType.neutral,
  99. isInAlert: true,
  100. labelText: widget.self ? "OK" : "Done",
  101. ),
  102. ],
  103. );
  104. }
  105. } else if (snapshot.hasError) {
  106. Logger("VerificationID")
  107. .severe("failed to end userID", snapshot.error);
  108. return Text(
  109. "Something went wrong",
  110. style: textStyle.bodyMuted,
  111. );
  112. } else {
  113. return const SizedBox(
  114. height: 200,
  115. child: EnteLoadingWidget(),
  116. );
  117. }
  118. },
  119. ),
  120. ],
  121. ),
  122. );
  123. return alert;
  124. }
  125. Future<String> _getPublicKey() async {
  126. if (widget.self) {
  127. return Configuration.instance.getKeyAttributes()!.publicKey;
  128. }
  129. final String? userPublicKey =
  130. await UserService.instance.getPublicKey(widget.email);
  131. if (userPublicKey == null) {
  132. // user not found
  133. return "";
  134. }
  135. return userPublicKey;
  136. }
  137. Widget _verificationIDWidget(BuildContext context, String publicKey) {
  138. final colorScheme = getEnteColorScheme(context);
  139. final textStyle = getEnteTextTheme(context);
  140. final String verificationID = _generateVerificationID(publicKey);
  141. return DottedBorder(
  142. color: colorScheme.strokeMuted,
  143. //color of dotted/dash line
  144. strokeWidth: 1,
  145. dashPattern: const [12, 6],
  146. radius: const Radius.circular(8),
  147. //dash patterns, 10 is dash width, 6 is space width
  148. child: Column(
  149. children: [
  150. GestureDetector(
  151. onTap: () async {
  152. if (verificationID.isEmpty) {
  153. return;
  154. }
  155. await Clipboard.setData(
  156. ClipboardData(text: verificationID),
  157. );
  158. shareText(
  159. widget.self
  160. ? "Here's my verification ID: "
  161. "$verificationID for ente.io."
  162. : "Hey, "
  163. "can you confirm that "
  164. "this is your ente.io verification "
  165. "ID: $verificationID",
  166. );
  167. },
  168. child: Container(
  169. decoration: BoxDecoration(
  170. borderRadius: const BorderRadius.all(
  171. Radius.circular(2),
  172. ),
  173. color: colorScheme.backgroundElevated2,
  174. ),
  175. padding: const EdgeInsets.all(20),
  176. width: double.infinity,
  177. child: Text(
  178. verificationID,
  179. style: textStyle.bodyBold,
  180. ),
  181. ),
  182. ),
  183. ],
  184. ),
  185. );
  186. }
  187. String _generateVerificationID(String publicKey) {
  188. final inputBytes = base64.decode(publicKey);
  189. final shaValue = sha256.convert(inputBytes);
  190. return bip39.generateMnemonic(
  191. strength: 256,
  192. randomBytes: (int size) {
  193. return Uint8List.fromList(shaValue.bytes);
  194. },
  195. );
  196. }
  197. }