From 5314d4986c07a4b794e5739b4c1ad98b897ec947 Mon Sep 17 00:00:00 2001 From: M <m@cakewallet.com> Date: Mon, 30 May 2022 14:34:21 +0100 Subject: [PATCH] Initial ionia service --- lib/ionia/ionia.dart | 62 +++++++++++++ lib/ionia/ionia_api.dart | 125 ++++++++++++++++++++++++++ lib/ionia/ionia_user_credentials.dart | 6 ++ lib/ionia/ionia_virtual_card.dart | 43 +++++++++ 4 files changed, 236 insertions(+) create mode 100644 lib/ionia/ionia.dart create mode 100644 lib/ionia/ionia_api.dart create mode 100644 lib/ionia/ionia_user_credentials.dart create mode 100644 lib/ionia/ionia_virtual_card.dart diff --git a/lib/ionia/ionia.dart b/lib/ionia/ionia.dart new file mode 100644 index 000000000..f55af0b17 --- /dev/null +++ b/lib/ionia/ionia.dart @@ -0,0 +1,62 @@ +import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:cake_wallet/.secrets.g.dart' as secrets; +import 'package:cake_wallet/ionia/ionia_api.dart'; + +class IoniaService { + IoniaService(this.secureStorage, this.ioniaApi); + + static const ioniaUsernameStorageKey = 'ionia_username'; + static const ioniaPasswordStorageKey = 'ionia_password'; + + static String get clientId => secrets.ioniaClientId; + + final FlutterSecureStorage secureStorage; + final IoniaApi ioniaApi; + + // Create user + + Future<void> createUser(String email) async { + final username = await ioniaApi.createUser(email, clientId: clientId); + await secureStorage.write(key: ioniaUsernameStorageKey, value: username); + } + + // Verify email + + Future<void> verifyEmail(String code) async { + final username = await secureStorage.read(key: ioniaUsernameStorageKey); + final credentials = await ioniaApi.verifyEmail(username: username, code: code, clientId: clientId); + await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password); + } + + // Check is user logined + + Future<bool> isLogined() async { + final username = await secureStorage.read(key: ioniaUsernameStorageKey) ?? ''; + final password = await secureStorage.read(key: ioniaPasswordStorageKey) ?? ''; + return username.isNotEmpty && password.isNotEmpty; + } + + // Logout + + Future<void> logout() async { + await secureStorage.delete(key: ioniaUsernameStorageKey); + await secureStorage.delete(key: ioniaPasswordStorageKey); + } + + // Create virtual card + + Future<IoniaVirtualCard> createCard() async { + final username = await secureStorage.read(key: ioniaUsernameStorageKey); + final password = await secureStorage.read(key: ioniaPasswordStorageKey); + return ioniaApi.createCard(username: username, password: password, clientId: clientId); + } + + // Get virtual card + + Future<IoniaVirtualCard> getCard() async { + final username = await secureStorage.read(key: ioniaUsernameStorageKey); + final password = await secureStorage.read(key: ioniaPasswordStorageKey); + return ioniaApi.getCards(username: username, password: password, clientId: clientId); + } +} \ No newline at end of file diff --git a/lib/ionia/ionia_api.dart b/lib/ionia/ionia_api.dart new file mode 100644 index 000000000..2ef367c36 --- /dev/null +++ b/lib/ionia/ionia_api.dart @@ -0,0 +1,125 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart'; +import 'package:cake_wallet/ionia/ionia_user_credentials.dart'; +import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; + +class IoniaApi { + static const baseUri = 'apidev.dashdirect.org'; + static const pathPrefix = 'cake'; + static final createUserUri = Uri.https(baseUri, '/$pathPrefix/CreateUser'); + static final verifyEmailUri = Uri.https(baseUri, '/$pathPrefix/VerifyEmail'); + static final createCardUri = Uri.https(baseUri, '/$pathPrefix/CreateCard'); + static final getCardsUri = Uri.https(baseUri, '/$pathPrefix/GetCards'); + + // Create user + + Future<String> createUser(String email, {@required String clientId}) async { + final headers = <String, String>{'clientId': clientId}; + final query = <String, String>{'emailAddress': email}; + final uri = createUserUri.replace(queryParameters: query); + final response = await put(uri, headers: headers); + + if (response.statusCode != 200) { + // throw exception + return null; + } + + final bodyJson = json.decode(response.body) as Map<String, Object>; + final data = bodyJson['Data'] as Map<String, Object>; + final isSuccessful = bodyJson['Successful'] as bool; + + if (!isSuccessful) { + throw Exception(data['ErrorMessage'] as String); + } + + return data['username'] as String; + } + + // Verify email + + Future<IoniaUserCredentials> verifyEmail({ + @required String username, + @required String code, + @required String clientId}) async { + final headers = <String, String>{ + 'clientId': clientId, + 'username': username}; + final query = <String, String>{'verificationCode': code}; + final uri = verifyEmailUri.replace(queryParameters: query); + final response = await put(uri, headers: headers); + + if (response.statusCode != 200) { + // throw exception + return null; + } + + final bodyJson = json.decode(response.body) as Map<String, Object>; + final data = bodyJson['Data'] as Map<String, Object>; + final isSuccessful = bodyJson['Successful'] as bool; + + if (!isSuccessful) { + throw Exception(data['ErrorMessage'] as String); + } + + final password = data['password'] as String; + return IoniaUserCredentials(username, password); + } + + // Get virtual card + + Future<IoniaVirtualCard> getCards({ + @required String username, + @required String password, + @required String clientId}) async { + final headers = <String, String>{ + 'clientId': clientId, + 'username': username, + 'password': password}; + final response = await post(getCardsUri, headers: headers); + + if (response.statusCode != 200) { + // throw exception + return null; + } + + final bodyJson = json.decode(response.body) as Map<String, Object>; + final data = bodyJson['Data'] as Map<String, Object>; + final isSuccessful = bodyJson['Successful'] as bool; + + if (!isSuccessful) { + throw Exception(data['ErrorMessage'] as String); + } + + final virtualCard = data['VirtualCard'] as Map<String, Object>; + return IoniaVirtualCard.fromMap(virtualCard); + } + + // Create virtual card + + Future<IoniaVirtualCard> createCard({ + @required String username, + @required String password, + @required String clientId}) async { + final headers = <String, String>{ + 'clientId': clientId, + 'username': username, + 'password': password}; + final response = await post(createCardUri, headers: headers); + + if (response.statusCode != 200) { + // throw exception + return null; + } + + final bodyJson = json.decode(response.body) as Map<String, Object>; + final data = bodyJson['Data'] as Map<String, Object>; + final isSuccessful = bodyJson['Successful'] as bool; + + if (!isSuccessful) { + throw Exception(data['ErrorMessage'] as String); + } + + return IoniaVirtualCard.fromMap(data); + } +} \ No newline at end of file diff --git a/lib/ionia/ionia_user_credentials.dart b/lib/ionia/ionia_user_credentials.dart new file mode 100644 index 000000000..c398385f5 --- /dev/null +++ b/lib/ionia/ionia_user_credentials.dart @@ -0,0 +1,6 @@ +class IoniaUserCredentials { + const IoniaUserCredentials(this.username, this.password); + + final String username; + final String password; +} \ No newline at end of file diff --git a/lib/ionia/ionia_virtual_card.dart b/lib/ionia/ionia_virtual_card.dart new file mode 100644 index 000000000..43cb07584 --- /dev/null +++ b/lib/ionia/ionia_virtual_card.dart @@ -0,0 +1,43 @@ +import 'package:flutter/foundation.dart'; + +class IoniaVirtualCard { + IoniaVirtualCard({ + @required this.token, + @required this.createdAt, + @required this.lastFour, + @required this.state, + @required this.pan, + @required this.cvv, + @required this.expirationMonth, + @required this.expirationYear, + @required this.fundsLimit, + @required this.spendLimit}); + + factory IoniaVirtualCard.fromMap(Map<String, Object> source) { + final created = source['created'] as String; + final createdAt = DateTime.tryParse(created); + + return IoniaVirtualCard( + token: source['token'] as String, + createdAt: createdAt, + lastFour: source['lastFour'] as String, + state: source['state'] as String, + pan: source['pan'] as String, + cvv: source['cvv'] as String, + expirationMonth: source['expirationMonth'] as String, + expirationYear: source['expirationYear'] as String, + fundsLimit: source['FundsLimit'] as double, + spendLimit: source['spend_limit'] as double); + } + + final String token; + final String lastFour; + final String state; + final String pan; + final String cvv; + final String expirationMonth; + final String expirationYear; + final DateTime createdAt; + final double fundsLimit; + final double spendLimit; +} \ No newline at end of file