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