Installation
Swift Package Manager
Select File
> Swift Packages
> Add Package Dependency...
and add a repository URL:
dependencies: [
// Standard version
.package(url: "https://repo.paycontrol.org/git/ios/pcsdk.git", from: "6.0.0")
// Gost version
.package(url: "https://repo.paycontrol.org/git/ios/pcsdk-gost.git", from: "6.0.0")
]
CocoaPods
Add the following line to your Podfile:
# Standard version
pod 'PCSDKModule', :git => 'https://repo.paycontrol.org/git/ios/pcsdk.git'
# Gost version
pod 'PCSDKGost', :git => 'https://repo.paycontrol.org/git/ios/pcsdk-gost.git'
Manual
Download the latest PCSDKModule or PCSDKGost framework and add it to the project.
Initialization
To inialize PC SDK library you just call PCSDK.initialize(...)
method.
If you need to set log level for PC SDK, then you sould call setLogLevel
method and set log level.
:::caution
Do NOT use .sensitive
log level in release builds.
This option will log out keys values and password values into logging system.
:::
#if DEBUG
PCSDK.setLogLevel([.debug, .sensitive])
#endif
PCSDK.initialize()
Also, you can provide additional parameters during initialization:
databaseURL
: The url for storing users data. If it is not set - SDK will use the default URL provided byPCSDK.defaultDatabaseURL
propertyaccessGroup
: The access group to store new Keychain's keys. If not set, the default access group will be used (app ID or Keychain Access Group).
Detailed: How to use PCSDK in extensions
User registration
User registration process contains followings steps:
- Importing personalization data got from the PC Server (via QR, QR + activation code, JSON-value)
- Activation the user if needed
- Registering PC User on PC Server
- Store user's keys in internal storage for futher using
The activation code could be delivered by other channel (SMS, Push Notifications)
// 1. Importing JSON info
let userJSON = ... // User's data from the server
let user = try PCUsersManager.importUser(from: userJSON)
// 2. Activating the user
if !user.isActivated {
try await PCUsersManager.activate(user: user, using: activationCode)
}
// 3. Registering
try await PCUsersManager.register(
user: user, // The imported user
deviceToken: deviceToken // The device token for PUSH notifications
)
// 4. Storing
try await PCUsersManager.store(
user: user, // The imported user
name: storingName, // The friendly name to store user
password: storingPassword // The password to store
)
Transactions
Online
// Getting the apropriate user.
// We are using the first stored user in this example
guard let user = PCUsersManager.users.first
else { ... }
// Getting the available transactions list for this user
let transactionsList = try await PCTransactionsManager.getTransactionList(for: user)
// Getting transaction's data
// We are using the first transaction in the list in this example
guard let firstTransactionID = transactionsList.first else { ... }
let transaction = try await PCTransactionsManager.getTranaction(
for: firstTransactionID,
user: user
)
// Transaction may contain the binary data
// It is necessary to download it before confirming or declining
if transaction.hasBinaryData {
try await PCTransactionsManager.getTransactionBinaryData(
for: transaction,
user: user
)
}
// Providing password before processing
if !user.isReadyToSign {
try await PCUsersManager.submit(password: password, for: user)
}
// Confirming
try await PCTransactionsManager.sign(
transaction: transaction,
by: user
)
Offline
If a device is offline, then PC can calculate offline confirmation/declination code for a transaction.
In this case PC SDK can not get the transaction's data from PC Server, and you should use QR-code scanner to get the transaction's data.
Calculated confirmation/declination code should be provided to a user. The user will input this code manually into Application web-site. After this Application can verify it using PC Server API.
Flow will be following
// Scan QR-code with app's QR scanner, get qrValue
let transactionQRValue = ...
// Validation the value
guard PCSDK.analyzeQR(userJSON) == .transaction
else { ... }
// Importing the QR-code value
let transaction = try PCTransactionsManager.importTransaction(from: transactionQRValue)
// Choosing the apropriate user to process tranaction
// The user and the transaction must have the identical systemID value
// We use the first apropriate user in this example
guard let user = PCUsersManager.first(where: { $0.systemID == transaction.systemID })
else { ... }
// Providing password before processing
if !user.isReadyToSign {
try await PCUsersManager.submit(password: password, for: user)
}
// Confirming
let confirmation = try await PCTransactionManager.signOffline(
transaction: transaction,
by: user
)
// Getting the code to confirm the transaction offline
let code = confirmation.confirmationCode
Logging
SDK has an option to use an external logger. The external logger must inherit the PCLoggerProtocol
protocol.
public protocol PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory)
func error(_ message: String, category: PCLoggingCategory)
func sensitive(_ message: String, category: PCLoggingCategory)
}
/// Example logger
final class MyLogger: PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory) {
...
}
func error(_ message: String, category: PCLoggingCategory) {
...
}
func sensitive(_ message: String, category: PCLoggingCategory) {
#if DEBUG
// Process sensitive information only in DEBUG mode to keep safe
// user's sensitive data, e.g. symmetric keys values, personal data etc.
...
#endif
}
}
After defining your logger, you must pass it to the method PCSDK.setLogger(...)
:
let myLogger = MyLogger()
// PCSDK.setLogLevels([.debug, .keys]) <- This should be removed from your code
PCSDK.setLogger(myLogger, options: [.debug, .sensitive])
After that, all messages will be sent to your logger.
Saving to file
There are no internal methods to persist logs in files in SDK. But you can adopt any third-party logger to PCLoggerProtocol
protocol.
E.g. you can use CocoaLumberjack. To use it, firstly, confgure CocoaLumberjack's file logger:
import CocoaLumberjack
import CocoaLumberjackSwift
...
let fileLogger = DDFileLogger()
fileLogger.logFileManager.maximumNumberOfLogFiles = 2 // Keeping only 2 files
fileLogger.maximumFileSize = 256 * 1024 // 256kb each one
fileLogger.rollingFrequency = 60 * 60 * 24 // with messages for last 24h
DDLog.add(fileLogger)
Now your logger should just translate messages to CocoaLumberjack's methods:
final class MyLogger: PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory) {
DDLogInfo("[SDK][\(category.rawValue)] \(message)")
}
func error(_ message: String, category: PCLoggingCategory) {
DDLogError("[SDK][\(category.rawValue)] \(message)")
}
func sensitive(_ message: String, category: PCLoggingCategory) {
#if DEBUG
DDLogInfo("[SDK][Sensitive][\(category.rawValue)] \(message)")
#endif
}
}
After that you will be able to get persisted logs using CocoaLumberjack`s API:
fileLogger
.logFileManager
.sortedLogFileInfos
.compactMap { (info: DDInfo) -> Data in
FileManager.default.contents(atPath: info.filePath) // Reading logs content
}
.forEach { (logData: Data) in
... // Process the log's data
}
An additional information about using CocoaLumberjack`s you can read at its GitHub page.
Using PCSDK In Extensions
To use PCSDK in extensions it necessarry to have the shared db and the same access group to the app and the extension.
To do that you must use App Groups and initialize the app and the extension in different ways.
The preparations for both the app and the extension
// Making the shared path to the DB
let appGroupIdentifier = ... // The App Group identifier
guard let sharedContainer = FileManager
.default
.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
else { ... }
let sharedDatabaseURL = sharedContainer.appendingPathComponent(PCSDK.defaultDatabaseFileName)
Initializing app and extensions
PCSDK.initialize(
databaseURL: sharedDatabaseURL,
accessGroup: appGroupIdentifier
)
Process Transaction by Push notification
PC Server can send push notification when transaction was created.
In this case Application can get User ID and Transaction ID from notification and process only one transaction.
The default iOS push template:
{
"aps": {
"alert": "%PUSH_TEXT%",
"sound": "%PUSH_SOUND%",
"badge": 1
},
"type": "PayControl",
"userid": "%USER_ID%",
"transactionid": "%TRANSACTION_ID%"
}
Please, be noticed, that push templates can be changed for your app by PC Server configuration.# PCSDK iOS
Gost
To use GOST algorithms is neccessary to add additional resources to the project from the Resources
folder of the repository.
- The entire
locale
folder (should be placed to the root of the app bundle) config.ini
- Localizations folders
en.lproj
andru.lproj
RndmBioViewController.xib
andRndmBioViewControllerIPhone.xib
KYC
Description
KYC is a part of PC Platform which allows to perform remote identification in the mobile application based on verifying client's photos and/or videos alongside with their scanned documents. The remote identification is intended to be performed prior to issuing keys by the PC Server and personalizing the mobile application.
KYC extension interacts with eKYC Connector which receives data from the application and performs the analysis. Refer to this page to find out more about eKYC Connector and the general description of the KYC concept.
The KYC extension initiates a session with initial data (which may be delivered e.g. by QR code) and asks the KYC Connector about the required data for remote identification. The KYC Connector sends the list of necessary media files (which usually includes a short live video and a photo of the passport) and KYC extension, in turn, collects the required sources and sends them to the analysis. After the KYC Connector has verified that the person in a video and on a passport photo is the same, it starts OCR procedure to retrieve the information from the passport. After OCR is done, the mobile application receives a notification, so that the client can confirm that all the fields in the password have been recognized properly. After performing a successful OCR procedure, the KYC Extension requests the list of available options for verifying documents. The client is supposed to choose a preferable way to get ther documents verified. Once verification method is defined, KYC Connector sends the documents for verification and notifies the application about results. Upon a successful verification, the KYC Extension requests the keys from the Connector and the app may be personalized with a retrieved PCUser
.
Installation
Manual
Download the latest PCKYCModule.xcframework
and add it to the project.
CocoaPods
Add the following line to your Podfile:
pod 'PCKYCModule', :git => 'https://repo.paycontrol.org/git/ios/kyc.git'
Swift Package Manager
Select File
> Swift Packages
> Add Package Dependency...
and add a repository URL:
https://repo.paycontrol.org/git/ios/kyc.git
Carthage
Since Carthage does not support distribution of binary frameworks this integration way is not supported.
Usage
Classes overview
While using KYC Extension in your app, you are going to interact with the following objects:
KYCSession
- Struct which represents a separate session established with KYC Connector.PCKYCManager
- Struct which manages your sessions. The follwoing guide is primarily devoted to showing proper usage of this class.PCKYCError
- Enum which represents errors.
Step 1. Add logging
To receive logs from this framework you should set the PCKYCManager.externalLogger
parameter. See Logging section for the example of PCLoggerProtocol
realisation.
Step 2. Get KYC info
Each session requires configuration which describes analysers and verifiers to use. To determine which analysers and verifiers are available invoke PCKYCManager.getKYCInfo
method.
PCKYCManager.getKYCInfo(
kycConnectorURL: self.connectorURL, // The KYC connector URL
completion: { result in
switch result {
case let .success(kycInfo): ... // KYC info
case let .failure(error): ... // Error
}
}
)
Step 3. Create a session
To start a session, you call PCKYCManager.startSession()
method.
let sessionParameters = KYCSessionParameters(
analyser: analyser, // Choosen analyser
preliminaryVerifier: verifier, // Choosen preliminary verifier
verifiers: [verifier], // Verifiers to use
ocrRetriever: ocrRetriever // Choosen ocr retriever
)
PCKYCManager.startSession(
kycInfoJSON: jsonValue, // The JSON string with KYC connector's data
deviceToken: deviceToken, // Device token to receive push notifications
parameters: sessionParameters, // The session parameters
completion: { result in
switch result {
case let .success(newSession): ... // Successfuly created session
case let .failure(error): ... // Error
}
}
)
Step 4. Get required sources
The first thing to do with a just created session is to determine which types of sources the client will be asked to upload.
// You may get required sources from `session` instance
let requiredSources: Set<PCKYCMediaType> = session.requiredSources
// ... or calling the PCKYCManager's method
PCKYCManager.getRequiredSources(
session: session, // The session instance
completion: { result in
switch result {
case let .success(sources): ... // Sources
case let .failure(error): ... // Error
}
}
)
Then you should prepare required sources: capture videos, take photos, etc. See the list of available sources.
Step 5. Upload the collected sources
Once the media files are collected, they must be uploaded for analysis.
// Uploading media from url
PCKYCManager.uploadMedia(
mediaURL: url, // URL to media file (e.g. video)
type: mediaType, // The type of the uploading media
session: session, // The session instance
completion: { result in
switch result {
case .success: ... // Done
case let .failure(error): ... // Error
}
)
// Uploading media from data
PCKYCManager.uploadMedia(
data: data, // Binary data of media (e.g. photo)
extension: "jpg", // The extension of the media, e.g. "jpg"
type: mediaType, // The type of the uploading media
session: session, // The session instance
completion: { result in
switch result {
case .success: ... // Done
case let .failure(error): ... // Error
}
)
Step 6. Check the session status
In your app, you are supposed to check the session status from time to time so as that you are able to handle any changes with the session.
To learn about possible session statuses, refer to the API documentation on PCKYCSessionStatus.Status.
PCKYCManager.getSessionStatus(
session: session, // The session instance
completion: { result in
switch result {
case let .success(status): ... // Session status
case let .failure(error): ... // Error
}
)
Step 7. Download OCR results
After uploading required media files, the KYC connector will perform the analysis. Once, the analysis is successful, you will receive the status .ocrSuccess
which means, your passport has been scanned successfully. You are supposed to download scanning results and show it to a client so that they can confirm the correctness of the OCR results.
PCKYCManager.getOCRResults(
session: session, // The session instance
completion: { result in
switch result {
case let .success(orcResults): ... // OCR results [String: Any]
case let .failure(error): ... // Error
}
)
Normally, the result dictionary contains keys with data from the passport: name
, dateofbirth
, sex
, address
, number
, dateofissue
, placeofissue
, issuecode
.
Step 8. Approve OCR results
After the client has checked the OCR results, their validity must be approved by the application. To approve the OCR results, just call KYCManager.approveOCRResults(session:completion:)
.
In case the OCR results are invalid, you have to provide an opportunity for a client to notify the KYC Connector about the problem. Call KYCManager.declineOCRResults(session:completion:)
In some cases it is possible that the OCR fails (e.g., the quality of uploaded photo was poor). Then instead of .ocrSuccess
the session will come to .ocrFailed
. It is also possible that the client rejects OCR results and the session gets its .ocrRejectedByUser
status. Your application may behave the same way in both cases: it can restart an OCR procedure. To do this, you must call KYCManager.getRequiredSources(session:completion:)
to see which pages of the passport must be uploaded again. Then call KYCManager.uploadMedia(...)
to resend required photos.
Step 9. Verify documents validity
Once, the OCR results have been approved by the client, the session status turns to .ocrApprovedByUser
. The next step is to get documents verified by government authorities. The KYC Connector can support several ways of documents verification. To find out which ways can be applied, KYCManager.getVerifiers(session:completion:)
should be called. The method returns the list of available verifiers in a callback.
After getting the list of supported verifiers you should provide the opportunity to choose the most suitable verifier for your clients. Refer to documentation on KYC Connector to learn more about each verifier.
The following code snippet shows how to start documents verification with a particular verifier:
PCKYCManager.startValidation(
session: session, // The session instance
verifier: verifier, // Verifier to validate
completion: { result in
switch result {
case .success: ... // Validation started
case let .failure(error): ... // Error
}
)
Step 10. Handle validation
Additional steps may be required after starting validation — providing an additional data or following link to the other app.
You can get and additional data invoking PCKYCManager.getSessionStatus
method and getting value of KYCSessionStatus.credentials
value.
Step 11. Obtain your keys
Once the documents verification has started you should wait until the session reaches .pckeyReady
status. This means, the PC symmetric keys have been issued and you can register them on a device. This is a final step. As a result, you receive PCUser
object and pass it to PCUsersManager
for further processing.
PCKYCManager.getPCUser(
session: session, // The session instance
completion: { result in
switch result {
case let .success(user): ... // User to register
case let .failure(error): ... // Error
}
)
See Registration to learn about further actions with PCUser
object.
NFC via Rutoken
Installation
To use PCSDK with NFC cards install the RutokenModule
using following instructions and additional frameworks from the Rutoken's site:
rtpkcs11ecp.framework
RrPcsc.framework
Also, imported OpenSSL
library is required to use RutokenModule
.
Manual
Download the latest RutokenModule.xcframework
and add it to the project.
CocoaPods
Add the following line to your Podfile:
pod 'RutokenModule', :git => 'https://repo.paycontrol.org/git/ios/rutoken.git'
Swift Package Manager
Select File
> Swift Packages
> Add Package Dependency...
and add a repository URL:
https://repo.paycontrol.org/git/ios/rutoken.git
Carthage
Since Carthage does not support distribution of binary frameworks this integration way is not supported.
Using RutokenModule
... TBD ...
Changelog
6.0.13
- Added
PCUser.activationCodeLength
parameter - Added
PCTransactionsManager.getTransactionStatus(...)
method to check transaction status
6.0.7
Version 6.0. Supporting APIv7, GOST algorithms, async/await and more
- Added support of APIv7
- Added support of GOST algorithms
- Internals have been rewritten using the new Swift concurrency with async/await methods and
Sendable
conformance.
5.5.483
- Added additional logs at the checking api version step
5.5.482
- Fixed XML import for APIv1/v2
- Added
PCError.invalidSource
error. It appears if import source string is wrong.
5.5.481
- Fixed submitting password issue when network is offline
- Added caching of local keypair to avoid extensive logging
5.5.480
- Moved assigning access group process to initialization method
- Updated internal finding keypairs methods to avoid working issues of apps extensions
5.5.479
- Fixed collecting device info for APIv1/v2
- Updated
PCSDK.initialize(...)
method - removedmode
parameter to use in extensions - Added access group migration method
5.5.478
- Fixed resetting fingerprint
- Updated collecting memory information
5.5.477
- Updated
BuildInfo.plist
version to avoid iOS 13 launch bug
5.5.476
- Added
PCSDK.reset()
method to reset all in-memory values. - Updated
PCSDK.removeAllUsers()
implementation. Now it removes all persisted data - users with keys and DB, local encryption keypair and caches.
5.5.475
- Added Indonesian locale
5.5.475
- Added Indonesian locale
5.5.474
- Added
PCSDK.buildInfo
parameter reflectingBuildInfo.plist
values
5.5.473
- Removed bitcode
5.5.470
- Updated methods using online credentials
- Fixed handling APIv1/v2 responces
- Fixed decoding APIv1/v2 errors
5.5.465
- Set minimum supported iOS version to
11.0
- Changed
PCParameters
name toExtraParameters
to reflect server api
5.5.464
- Fixed issue with empty public key registration
5.5.463
- Resetting handles after user deletion
- Updated server error codes to match server changes
5.5.462
- Updated user activation to avoid issues with APIv6
5.5.459
- Added missing errors localization
5.5.458
- Implemented
submit(...)
andstore(...)
methods with callback to support APIv6 online credentials - Deprecated old methods
- Added new error codes
- Fixed updating user and renew
- Added default confirmationCodeLength constant
5.5.457
- Fixed
PCServerError
switch statements matching
5.5.454
Version 5.5. Supporting APIv6
- Added support of APIv6
- Added new method
PCUsersManager.activate(...)
with callback to support APIv6 online credentials check. - Changed
PCServerError
type tostruct
. - Added new errors of APIv6
5.4.453
- Managing of handles has been improved
5.4.452
- Supporting new transaction types
- Supporting of custom push notifications services and Edna push notifications service
- Supporting of
appExtra
parameter inPCTransaction
andPCOperation
PCUser
registration result type has been changed to RegistrationResult which contains appExtra values- Internal fixes and improvements
5.4.444
Version 5.4. Support APIv5, fixes and improvements
- Added support of APIv5
- Added the
PCSDK.clearCaches
public method for clearing caches - Added the
PCUser.reset
public method for reseting PCUser's handles - Internal fixes and improvements
- Updated errors descriptions
5.3.441
- Added the new parameter
PCSDK.fixedAPI
5.3.440
- Fixed the default value of the
confirmationCodeLength
parameter
5.3.439
- Improved management and security of handles
5.3.438
- Fixed the updating of password when using PCUsersManager.store method
- Fixed the collection of a location data
- Fixed isReadyToSign parameter
- Fixed parsing of XML data
- Fixed installation path
- Added Chinese localization
5.3.429
- Added new method for renewing
PCUser
5.3.426
Version 5.3. External keys processors, new events, fixes and improvements
- Added methods to process multiple transactions at once:
PCTransactionManager.sign(transactions:user:completion)
andPCTransactionManager.decline(transactions:user:completion)
- Sync methods
PCTransactionManager.signOffline
andPCTransactionManager.declineOffline
have been marked as deprecated. Added new async methods. - Refactored internal architecture to support external keys processors via
KeysProcessor
protocol. PCKYCManager
has been extracted to the separate framework- Added new events (
password_correct
andpassword_changed
) - Removed deeplinks from sdk
- Updated dependencies
- Other minor fixes and improvements
5.2.414
Supporting of Server API v4 has been added:
- Operations have been added. Operation is generally a bunch of related transactions which can be processed altogether. Refer to documentation on PCOperationsManager and PCOperation for more details.
- eKYC module has been added. This module provides functionality for remote identification which can be used as a preliminary step before issuing the keys. Refer to documentation on PCKYCManager and PCKYCSession for more details.
- Key backups have been added. Now, the key can be backed up and restored later (provided that the server supports this functionality and backups are enabled). Refer to documentation on PCUserBackupData and PCUserRestore for more details.
- Calculation of signature has been extended for CMS, CSR and standard types
- Parameters
type
andcmsAuthenticatedAttributes
have been added toPCTransaction
PCUsersManager.getCertificateInfo
method has been added. The transaction type property has been added. Tests has been added.- A
snippet
parameter has been added toPCTransaction
- The
suggestedUserName
property has been added toPCUser
Other improvements:
- Now you can attach external logger to SDK using PCSDK.setLogger
method.
- Stream-based confirming, declining and autosigning have been implemented
- Downloading binary data to file has been implemented
- Errors list has been updated
- Target queue has been added to async methods
- Other internal optimisations, fixes and improvements have been added