From 4ec22256a57b6061314382d0bbc904d2d88f87cb Mon Sep 17 00:00:00 2001 From: andriikuliahin Date: Wed, 27 Sep 2023 13:22:38 +0300 Subject: [PATCH] Added types, updated Android and iOS SDK-s, updated package.json --- README.md | 141 ++++--- package.json | 2 +- plugin.xml | 14 +- .../keyri/cordova/plugin/CordovaKeyri.swift | 353 ++++++++++++------ www/CordovaKeyri.ts | 81 ---- www/index.ts | 89 +++++ www/types.ts | 32 -- 7 files changed, 432 insertions(+), 280 deletions(-) delete mode 100644 www/CordovaKeyri.ts create mode 100644 www/index.ts diff --git a/README.md b/README.md index 0155eeb..7a713b8 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,113 @@ ## **System Requirements** -* iOS 14+, Swift 5.3 -* Android API level 23 or higher, AndroidX, Kotlin coroutines compatability +* iOS 14+, Swift 5.3 +* Android API level 23 or higher, target sdk 33 or higher AndroidX, Kotlin coroutines compatability ## **Interacting with the Plugin** -Please see the examples below as well as a full set of method examples here: https://github.com/Keyri-Co/sample-cordova-app/blob/main/keyriSample/www/js/index.js +Please see the examples below as well as a full set of method examples +here: https://github.com/Keyri-Co/sample-cordova-app/blob/main/keyriSample/www/js/index.js ### Initialize Keyri -To initialize the Keyri object, simply call the initialize method, and pass in your app key and api key, generated in the Keyri dashboard -```JS -let Keyri; -let appKey = 'your_app_key' -let publicApiKey = 'your_api_key' - -Keyri.initialize(appKey, publicApiKey, true, (message) => { - console.log('CordovaKeyri.initialize', message); -}, (e) => { - console.log('CordovaKeyri.initialize', e); + +To initialize the Keyri object, simply call the initialize method, and pass in your app key and api key, generated in +the Keyri dashboard + +```javascript +Keyri.initialize({ + appKey: appKey, + publicApiKey: publicApiKey, + serviceEncryptionKey: serviceEncryptionKey, + blockEmulatorDetection: true }) + .then((message) => { + console.log('CordovaKeyri.initialize', message); + isInitialized(); + }) + .catch((e) => { + console.log('CordovaKeyri.initialize', e); + }); ``` ### Generate and retrieve association key -The association key is the cryptographic identity we use to identify users. It sits in the Trusted Development Environment, a hardware separated chip shielded from attacks to the main perating system. The key functions as a P256 Curve signing key. To generate: -```JS -Keyri.generateAssociationKey('kuliahin.andrew@gmail.com', (key) => { - console.log('CordovaKeyri.generateAssociationKey', key); - alert('Key generated: ' + key) -}, (e) => { - console.log('CordovaKeyri.generateAssociationKey', e); -}) + +The association key is the cryptographic identity we use to identify users. It sits in the Trusted Development +Environment, a hardware separated chip shielded from attacks to the main perating system. The key functions as a P256 +Curve signing key. To generate: + +```javascript +Keyri.generateAssociationKey('kuliahin.andrew@gmail.com') + .then((key) => { + console.log('CordovaKeyri.generateAssociationKey', key); + alert('Key generated: ' + key) + }) + .catch((e) => { + console.log('CordovaKeyri.generateAssociationKey', e); + }); ``` To look up an existing user's key: -```JS - Keyri.getAssociationKey('kuliahin.andrew@gmail.com', (key) => { - console.log('CordovaKeyri.getAssociationKey', key); - alert('Association key: ' + key); - }, (e) => { - console.log('CordovaKeyri.getAssociationKey', e); - }) + +```javascript +Keyri.getAssociationKey('kuliahin.andrew@gmail.com') + .then((key) => { + console.log('CordovaKeyri.getAssociationKey', key); + alert('Association key: ' + key); + }) + .catch((e) => { + console.log('CordovaKeyri.getAssociationKey', e); + }); ``` ### Enable QR Auth -QR Auth can be enabled with a single function call. This process handles scanning the code, generating the session info, displaying a confirmation screen to the user, and, if the user confirms, sending the encrypted payload you provide to the Keyri widget in your browser. -```JS - Keyri.easyKeyriAuth(appKey, publicAppKey, 'Some Payload', 'kulahin.andrew@gmail.com', () => { - console.log('CordovaKeyri.easyKeyriAuth', 'ok'); - alert('Payload sent'); - }, (e) => { - console.log('CordovaKeyri.easyKeyriAuth', e); - }) + +QR Auth can be enabled with a single function call. This process handles scanning the code, generating the session info, +displaying a confirmation screen to the user, and, if the user confirms, sending the encrypted payload you provide to +the Keyri widget in your browser. + +```javascript +Keyri.easyKeyriAuth('Payload', 'kulagin.andrew38@gmail.com') + .then(() => { + console.log('CordovaKeyri.easyKeyriAuth', 'ok'); + alert('Authorized'); + }) + .catch((e) => { + console.log('CordovaKeyri.easyKeyriAuth', e); + }); ``` ### User Signatures -The association keys can be used to sign data to send to a remote server. If the server has the user's public key (see above), it can then verify the identity of the user as a security measure. Below is an example of how to create a signature of some data, passed in as a string -```JS - Keyri.getUserSignature('kuliahin.andrew@gmail.com', 'Custom data', (signature) => { - console.log('CordovaKeyri.getUserSignature', signature); - alert('Signature generated: ' + signature); - }, (e) => { - console.log('CordovaKeyri.getUserSignature', e); - }) + +The association keys can be used to sign data to send to a remote server. If the server has the user's public key (see +above), it can then verify the identity of the user as a security measure. Below is an example of how to create a +signature of some data, passed in as a string + +```javascript +Keyri.generateUserSignature('kuliahin.andrew@gmail.com', 'Custom data') + .then((signature) => { + console.log('CordovaKeyri.generateUserSignature', signature); + alert('Signature generated: ' + signature) + }) + .catch((e) => { + console.log('CordovaKeyri.generateUserSignature', e); + }); +``` + +### Fingerprint Events + +You can send an event containing a device snapshot to our dashboard. The response you receive will be sent, as +is, to your own backend, where you can utilize our scripts to help you decrypt. See the code sample below +and https://docs.keyri.com/fraud-prevention for more + +```javascript +Keyri.sendEvent({publicUserId: 'kuliahin.andrew@gmail.com', eventType: 'visits', success: true}) + .then(() => { + console.log('CordovaKeyri.sendEvent', 'ok'); + alert('Event sent!'); + }) + .catch((e) => { + console.log('CordovaKeyri.sendEvent', e); + }); ``` ## License @@ -87,7 +133,10 @@ What's not allowed under the license: * Indemnification: using this free software is ‘at your own risk’, so you can’t sue Keyri, Inc. for problems caused by this library - ### Disclaimer -We care deeply about the quality of our product and rigorously test every piece of functionality we offer. That said, every integration is different. Every app on the App Store has a different permutation of build settings, compiler flags, processor requirements, compatability issues etc and it's impossible for us to cover all of those bases, so we strongly recommend thourough testing of your integration before shipping to production. Please feel free to file a bug or issue if you notice anything that seems wrong or weird on GitHub 🙂 +We care deeply about the quality of our product and rigorously test every piece of functionality we offer. That said, +every integration is different. Every app on the App Store has a different permutation of build settings, compiler +flags, processor requirements, compatability issues etc and it's impossible for us to cover all of those bases, so we +strongly recommend thorough testing of your integration before shipping to production. Please feel free to file a bug +or issue if you notice anything that seems wrong or weird on GitHub 🙂 diff --git a/package.json b/package.json index d121423..6d67bb5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.0", + "version": "0.1.3", "name": "@keyri/cordova-keyri", "cordova_name": "Cordova Keyri Plugin", "description": "Cordova Keyri SDK Plugin for QR login", diff --git a/plugin.xml b/plugin.xml index 5a8de5e..42599ba 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,11 +1,11 @@ + version="0.1.3"> CordovaKeyri Cordova Keyri SDK Plugin - + authentication, qr-login, passwordless, multifactor-authentication, mobile-authentication, ecosystem:cordova, cordova-android, cordova, camera, cordova-ios MIT @@ -13,10 +13,12 @@ - - + + + + @@ -27,7 +29,7 @@ - + @@ -50,7 +52,7 @@ - + diff --git a/src/iOS/com/keyri/cordova/plugin/CordovaKeyri.swift b/src/iOS/com/keyri/cordova/plugin/CordovaKeyri.swift index 6b1c152..15f3986 100644 --- a/src/iOS/com/keyri/cordova/plugin/CordovaKeyri.swift +++ b/src/iOS/com/keyri/cordova/plugin/CordovaKeyri.swift @@ -1,193 +1,318 @@ import Foundation -import keyri_pod +import Keyri @objc(CordovaKeyri) class CordovaKeyri : CDVPlugin { var keyri: KeyriInterface? + var activeSession: Session? @objc(initialize:) func initialize(command: CDVInvokedUrlCommand) { - guard let appKey = command.arguments[0] as? String else { - let error = "initialize, No app key provided" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + guard let arguments = command.arguments else { + processError(error: "initialize, no arguments provided", command: command) return } - let publicApiKey = command.arguments[1] as? String - let serviceEncryptionKey = command.arguments[2] as? String - let blockEmulatorDetection = command.arguments[3] as? Boolean + if arguments.count < 1 || !(arguments[0] is String) { + processError(error: "initialize, first parameter must be a String", command: command) + return + } - keyri = KeyriInterface(appKey: appKey, publicApiKey: publicApiKey, serviceEncryptionKey: serviceEncryptionKey, blockEmulatorDetection: blockEmulatorDetection ?? true) - commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK), callbackId: command.callbackId) + let appKey = arguments[0] as! String + let publicApiKey = arguments[1] as? String + let serviceEncryptionKey = arguments[2] as? String + let blockEmulatorDetection = arguments[3] as? Bool ?? true + + keyri = KeyriInterface(appKey: appKey, publicApiKey: publicApiKey, serviceEncryptionKey: serviceEncryptionKey, blockEmulatorDetection: blockEmulatorDetection) + + processResult(command: command) } @objc(isInitialized:) func isInitialized(command: CDVInvokedUrlCommand) { - if (keyri != nil) { - commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK), callbackId: command.callbackId) - } else { - let error = "isInitialized, Keyri is not initialized" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) - } + if (keyri != nil) { + processResult(command: command) + } else { + sendIsNotInitialized(methodName: "isInitialized", command: command) + } } @objc(easyKeyriAuth:) func easyKeyriAuth(command: CDVInvokedUrlCommand) { guard let payload = command.arguments[0] as? String else { - let error = "easyKeyriAuth, payload must not be nil" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + processError(error: "easyKeyriAuth, payload must not be nil", command: command) return } let publicUserId = command.arguments[1] as? String - keyri.easyKeyriAuth(publicUserId: publicUserId, payload: payload) { result in + keyri?.easyKeyriAuth(payload: payload, publicUserId: publicUserId) { result in switch result { - case .success(_): - self.commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK), callbackId: command.callbackId) - return - case .failure(_): - self.commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_ERROR), callbackId: command.callbackId) + case .success: + self.processResult(command: command) + case .failure(let error): + self.processError(error: error, command: command) } - } + } ?? sendIsNotInitialized(methodName: "easyKeyriAuth", command: command) } -// TODO: Review and test @objc(generateAssociationKey:) func generateAssociationKey(command: CDVInvokedUrlCommand) { guard let publicUserId = command.arguments[0] as? String else { - let error = "generateAssociationKey, no publicUserId provided" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + processError(error: "generateAssociationKey, publicUserId must not be nil", command: command) return } - keyri.generateAssociationKey(publicUserId: publicUserId) { result in + keyri?.generateAssociationKey(publicUserId: publicUserId) { result in switch result { - case .success(let key): - self.commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK), messageAs: key.rawRepresentation.base64EncodedString()) - case .failure(_): - self.commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_ERROR), callbackId: command.callbackId) + case .success(let key): + self.processResult(message: key.rawRepresentation.base64EncodedString(), command: command) + case .failure(let error): + self.processError(error: error, command: command) } - } - - return + } ?? sendIsNotInitialized(methodName: "generateAssociationKey", command: command) } - @objc(listAssociationKey:) - func listAssociationKey(command: CDVInvokedUrlCommand) { - guard let keyri = keyri else { - let error = "Keyri object not initialized. Please call InitializeKeyri first" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + @objc(generateUserSignature:) + func generateUserSignature(command: CDVInvokedUrlCommand) { + guard let publicUserId = command.arguments[0] as? String else { + processError(error: "generateUserSignature, publicUserId must not be nil", command: command) return } - let list = keyri.listAssociactionKeys() - let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: list ?? [:]) - commandDelegate.send(result, callbackId: command.callbackId) + guard let dataStr = command.arguments[1] as? String, + let data = dataStr.data(using: .utf8) else { + processError(error: "generateUserSignature, data must not be nil", command: command) + return + } + + keyri?.generateUserSignature(publicUserId: publicUserId, data: data) { result in + switch result { + case .success(let signature): + self.processResult(message: signature.derRepresentation.base64EncodedString(), command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "generateUserSignature", command: command) + } + + @objc(listAssociationKeys:) + func listAssociationKeys(command: CDVInvokedUrlCommand) { + keyri?.listAssociactionKeys() { result in + switch result { + case .success(let list): + self.processResult(message: list ?? [:], command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "listAssociationKeys", command: command) } @objc(listUniqueAccounts:) func listUniqueAccounts(command: CDVInvokedUrlCommand) { - guard let keyri = keyri else { - let error = "Keyri object not initialized. Please call InitializeKeyri first" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) - return - } - - let list = keyri.listUniqueAccounts() - let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: list ?? [:]) - commandDelegate.send(result, callbackId: command.callbackId) + keyri?.listUniqueAccounts() { result in + switch result { + case .success(let list): + self.processResult(message: list ?? [:], command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "listUniqueAccounts", command: command) } @objc(getAssociationKey:) func getAssociationKey(command: CDVInvokedUrlCommand) { - guard let keyri = keyri else { - let error = "Keyri object not initialized. Please call InitializeKeyri first" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + let publicUserId = command.arguments[0] as? String + + keyri?.getAssociationKey(publicUserId: publicUserId ?? "") { result in + switch result { + case .success(let key): + self.processResult(message: key?.rawRepresentation.base64EncodedString(), command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "getAssociationKey", command: command) + } + + @objc(removeAssociationKey:) + func removeAssociationKey(command: CDVInvokedUrlCommand) { + guard let publicUserId = command.arguments[0] as? String else { + processError(error: "removeAssociationKey, publicUserId must not be nil", command: command) return } - guard let username = command.arguments[0] as? String else { - let error = "No username provided" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + keyri?.removeAssociationKey(publicUserId: publicUserId) { result in + switch result { + case .success: + self.processResult(command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "removeAssociationKey", command: command) + } + + @objc(sendEvent:) + func sendEvent(command: CDVInvokedUrlCommand) { + guard let publicUserId = command.arguments[0] as? String else { + processError(error: "sendEvent, publicUserId must not be nil", command: command) return } - do { - let key = try keyri.getAssociationKey(username: username) - if let key = key { - let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: key.rawRepresentation.base64EncodedString()) - commandDelegate.send(result, callbackId: command.callbackId) + guard let eventType = command.arguments[1] as? String else { + processError(error: "sendEvent, eventType must not be nil", command: command) return } - } catch { - print(error) - } - let error = "No key found for user" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) - return + + let success = command.arguments[2] as? String ?? "true" + + keyri?.sendEvent(publicUserId: publicUserId, eventType: EventType(rawValue: eventType) ?? .visits, success: Bool(success) ?? true) { result in + switch result { + case .success(let fingerprintResponse): + self.processResult(message: fingerprintResponse.asDictionary(), command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "sendEvent", command: command) } - @objc(removeAssociationKey:) - func removeAssociationKey(command: CDVInvokedUrlCommand) { - guard let keyri = keyri else { - let error = "Keyri object not initialized. Please call InitializeKeyri first" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + @objc(initiateQrSession:) + func initiateQrSession(command: CDVInvokedUrlCommand) { + guard let sessionId = command.arguments[0] as? String else { + processError(error: "initiateQrSession, sessionId must not be nil", command: command) return } - guard let username = command.arguments[0] as? String else { - let error = "Invalid arguments" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + let publicUserId = command.arguments[1] as? String + + keyri?.initiateQrSession(sessionId: sessionId, publicUserId: publicUserId) { result in + switch result { + case .success(let session): + self.activeSession = session + self.processResult(message: session.asDictionary(), command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "initiateQrSession", command: command) + } + + @objc(initializeDefaultConfirmationScreen:) + func initializeDefaultConfirmationScreen(command: CDVInvokedUrlCommand) { + guard let session = activeSession else { + processError(error: "initializeDefaultConfirmationScreen, activeSession must not be nil", command: command) return } - do { - try keyri.removeAssociationKey(publicUserId: username) - let result = CDVPluginResult(status: CDVCommandStatus_OK) - commandDelegate.send(result, callbackId: command.callbackId) - } catch { - let result = CDVPluginResult(status: CDVCommandStatus_ERROR) - commandDelegate.send(result, callbackId: command.callbackId) + guard let payload = command.arguments[0] as? String else { + processError(error: "initializeDefaultConfirmationScreen, payload must not be nil", command: command) + return } + + keyri?.initializeDefaultConfirmationScreen(session: session, payload: payload) { result in + switch result { + case .success: + self.processResult(command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "initializeDefaultConfirmationScreen", command: command) } - @objc(getUserSignature:) - func getUserSignature(command: CDVInvokedUrlCommand) { - guard let keyri = keyri else { - let error = "Keyri object not initialized. Please call InitializeKeyri first" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + @objc(processLink:) + func processLink(command: CDVInvokedUrlCommand) { + guard let link = command.arguments[0] as? String, + let url = URL(string: link) else { + processError(error: "processLink, link must not be nil", command: command) return } - guard let username = command.arguments[0] as? String, - let dataStr = command.arguments[1] as? String, - let customData = dataStr.data(using: .utf8) else { - let error = "Invalid arguments" - let pluginResult = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error) - commandDelegate.send(pluginResult, callbackId: command.callbackId) + guard let payload = command.arguments[1] as? String else { + processError(error: "processLink, payload must not be nil", command: command) return } - do { - let signature = try keyri.generateUserSignature(for: username, data: customData) - let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: signature.rawRepresentation.base64EncodedString()) - commandDelegate.send(result, callbackId: command.callbackId) - } catch { - let result = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: "User not found") - commandDelegate.send(result, callbackId: command.callbackId) + guard let publicUserId = command.arguments[2] as? String else { + processError(error: "processLink, publicUserId must not be nil", command: command) + return } + + keyri?.processLink(url: url, payload: payload, publicUserId: publicUserId) { result in + switch result { + case .success: + self.processResult(command: command) + case .failure(let error): + self.processError(error: error, command: command) + } + } ?? sendIsNotInitialized(methodName: "processLink", command: command) + } + + @objc(confirmSession:) + func confirmSession(command: CDVInvokedUrlCommand) { + guard let payload = command.arguments[0] as? String, + let trustNewBrowserString = command.arguments[1] as? String, + let trustNewBrowser = Bool(trustNewBrowserString) else { + processError(error: "confirmSession, payload must not be nil", command: command) + return + } + + activeSession?.confirm(payload: payload, trustNewBrowser: trustNewBrowser) { result in + switch result { + case .some(let error): + self.processError(error: error, command: command) + case .none: + self.processResult(command: command) + } + } ?? processError(error: "confirmSession, activeSession is nil", command: command) + } + + @objc(denySession:) + func denySession(command: CDVInvokedUrlCommand) { + guard let payload = command.arguments[0] as? String else { + processError(error: "denySession, payload must not be nil", command: command) + return + } + + activeSession?.deny(payload: payload) { result in + switch result { + case .some(let error): + self.processError(error: error, command: command) + case .none: + self.processResult(command: command) + } + } ?? processError(error: "denySession, activeSession is nil", command: command) + } + + private func processResult(message: String?, command: CDVInvokedUrlCommand) { + commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK, messageAs: message), callbackId: command.callbackId) + } + + private func processResult(message: [String : String]?, command: CDVInvokedUrlCommand) { + commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK, messageAs: message), callbackId: command.callbackId) + } + + private func processResult(command: CDVInvokedUrlCommand) { + commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_OK), callbackId: command.callbackId) + } + + private func processError(error: String, command: CDVInvokedUrlCommand) { + commandDelegate.send(CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: error), callbackId: command.callbackId) + } + + private func sendIsNotInitialized(methodName: String, command: CDVInvokedUrlCommand) { + processError(error: methodName + ", Keyri is not initialized", command: command) + } + + private func processError(error: Error, command: CDVInvokedUrlCommand) { + processError(error: error.localizedDescription, command: command) } } +extension Encodable { + func asDictionary() -> [String: String]? { + guard let data = try? JSONEncoder().encode(self) else { + return nil + } + guard let dictionary = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: String] else { + return nil + } + return dictionary + } +} diff --git a/www/CordovaKeyri.ts b/www/CordovaKeyri.ts deleted file mode 100644 index 288ceb8..0000000 --- a/www/CordovaKeyri.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { - KeyriModule, - ProcessLinkOptions, - InitializeKeyriOptions, - SendEventOptions, -} from './types'; - -declare let window: any; - -function asPromise (action: string, args: any[] = []): Promise { - return new Promise((resolve, reject) => { - console.log('Executing interface method', action, args); - window.cordova.exec(resolve, reject, 'CordovaKeyri', action, args); - }); -} - -const Keyri: KeyriModule = { - initialize: (options: InitializeKeyriOptions) => { - return asPromise('initialize', [options.appKey, options.publicApiKey, options.serviceEncryptionKey, options.blockEmulatorDetection]); - }, - - isInitialized: () => { - return asPromise('isInitialized'); - }, - - generateAssociationKey: (publicUserId?: string) => { - return asPromise('generateAssociationKey', [publicUserId]); - }, - - generateUserSignature: (publicUserId?: string, data?: string) => { - return asPromise('generateUserSignature', [publicUserId, data]); - }, - - listAssociationKeys: () => { - return asPromise('listAssociationKeys'); - }, - - listUniqueAccounts: () => { - return asPromise('listUniqueAccounts'); - }, - - getAssociationKey: (publicUserId?: string) => { - return asPromise('getAssociationKey', [publicUserId]); - }, - - removeAssociationKey: (publicUserId: string) => { - return asPromise('removeAssociationKey', [publicUserId]); - }, - - sendEvent: (data: SendEventOptions) => { - return asPromise('sendEvent', [data.publicUserId, data.eventType, data.success]); - }, - - initiateQrSession: (sessionId: string, publicUserId?: string) => { - return asPromise('initiateQrSession', [sessionId, publicUserId]); - }, - - initializeDefaultConfirmationScreen: (payload: string) => { - return asPromise('initializeDefaultConfirmationScreen', [payload]); - }, - - confirmSession: (payload: string, trustNewBrowser?: boolean) => { - return asPromise('confirmSession', [payload, trustNewBrowser]); - }, - - denySession: (payload: string) => { - return asPromise('denySession', [payload]); - }, - - easyKeyriAuth: (publicUserId: string, payload: string) => { - return asPromise('easyKeyriAuth', [publicUserId, payload]); - }, - - processLink: (options: ProcessLinkOptions) => { - return asPromise('processLink', [options.link, options.payload, options.publicUserId]); - }, -}; - -export default Keyri; - -export * from './types'; diff --git a/www/index.ts b/www/index.ts new file mode 100644 index 0000000..c1f5e18 --- /dev/null +++ b/www/index.ts @@ -0,0 +1,89 @@ +import type { + ProcessLinkOptions, + InitializeKeyriOptions, + SendEventOptions, +} from './types'; +import {KeyriFingerprintEventResponse, KeyriSession} from "./types"; + +declare let window: any; + +function asPromise(action: string, args: any[] = []): Promise { + return new Promise((resolve, reject) => { + console.log('Executing interface method', action, args); + window.cordova.exec(resolve, reject, 'CordovaKeyri', action, args); + }); +} + +export class CordovaKeyriPlugin { + initialize(options: InitializeKeyriOptions): Promise { + return asPromise('initialize', [options.appKey, options.publicApiKey, options.serviceEncryptionKey, String(options.blockEmulatorDetection)]); + }; + + isInitialized(): Promise { + return asPromise('isInitialized'); + }; + + generateAssociationKey(publicUserId?: string): Promise { + return asPromise('generateAssociationKey', [publicUserId]); + }; + + generateUserSignature(publicUserId?: string, data?: string): Promise { + return asPromise('generateUserSignature', [publicUserId, data]); + }; + + listAssociationKeys(): Promise { + return asPromise('listAssociationKeys'); + }; + + listUniqueAccounts(): Promise { + return asPromise('listUniqueAccounts'); + }; + + getAssociationKey(publicUserId?: string): Promise { + return asPromise('getAssociationKey', [publicUserId]); + }; + + removeAssociationKey(publicUserId: string): Promise { + return asPromise('removeAssociationKey', [publicUserId]); + }; + + sendEvent(data: SendEventOptions): Promise { + return asPromise('sendEvent', [data.publicUserId, data.eventType, String(data.success)]); + }; + + initiateQrSession(sessionId: string, publicUserId?: string): Promise { + return asPromise('initiateQrSession', [sessionId, publicUserId]); + }; + + initializeDefaultConfirmationScreen(payload: string): Promise { + return asPromise('initializeDefaultConfirmationScreen', [payload]); + }; + + confirmSession(payload: string, trustNewBrowser?: boolean): Promise { + return asPromise('confirmSession', [payload, trustNewBrowser]); + }; + + denySession(payload: string): Promise { + return asPromise('denySession', [payload]); + }; + + easyKeyriAuth(publicUserId: string, payload: string): Promise { + return asPromise('easyKeyriAuth', [publicUserId, payload]); + }; + + processLink(options: ProcessLinkOptions): Promise { + return asPromise('processLink', [options.link, options.payload, options.publicUserId]); + }; +} + +const CordovaKeyri = new CordovaKeyriPlugin(); + +if (!window.plugins) { + window.plugins = {}; +} + +if (!window.plugins.CordovaKeyri) { + window.plugins.CordovaKeyri = CordovaKeyri; +} + +export default CordovaKeyri; diff --git a/www/types.ts b/www/types.ts index c7c9fb4..116ae2a 100644 --- a/www/types.ts +++ b/www/types.ts @@ -61,38 +61,6 @@ export interface KeyriGeoData { regionCode?: string; } -export interface KeyriModule { - initialize: (data: InitializeKeyriOptions) => Promise; - - isInitialized: () => Promise; - - generateAssociationKey: (publicUserId?: string) => Promise; - - generateUserSignature: (publicUserId?: string, data?: string) => Promise; - - listAssociationKeys: () => Promise; - - listUniqueAccounts: () => Promise; - - getAssociationKey: (publicUserId?: string) => Promise; - - removeAssociationKey: (publicUserId: string) => Promise; - - sendEvent: (data: SendEventOptions) => Promise; - - initiateQrSession: (sessionId: string, publicUserId?: string) => Promise; - - initializeDefaultConfirmationScreen: (payload: string) => Promise; - - confirmSession: (payload: string, trustNewBrowser?: boolean) => Promise; - - denySession: (payload: string) => Promise; - - easyKeyriAuth: (publicUserId: string, payload: string) => Promise; - - processLink: (options: ProcessLinkOptions) => Promise; -} - export interface ProcessLinkOptions { link: string; payload: string;