Skip to content

Commit

Permalink
Configure AppInfo for IdentityAPIClient (#814)
Browse files Browse the repository at this point in the history
Creates an `IdentityAPIClientImpl` implementation
of the `IdentityAPIClient` protocol which wraps
an `STPAPIClient` and configures the beta headers
and appInfo. This also simplifies the Identity
code by making all of the networking logic
self-contained in `IdentityAPIClient`.

Because none of the Identity API requests use a
public key but instead use an ephemeral key
secret, we're able to instantiate an APIClient
using the ephemeral key secret in place of the
public key.
  • Loading branch information
mludowise-stripe authored Mar 1, 2022
1 parent b38ab85 commit 03636f7
Show file tree
Hide file tree
Showing 15 changed files with 398 additions and 355 deletions.
16 changes: 8 additions & 8 deletions StripeIdentity/StripeIdentity.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
E6548E5E27279DFF00F399B2 /* VerificationPageStaticContentDocumentSelectPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548E5427279DFE00F399B2 /* VerificationPageStaticContentDocumentSelectPage.swift */; };
E6548E5F27279DFF00F399B2 /* VerificationPageRequirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548E5527279DFF00F399B2 /* VerificationPageRequirements.swift */; };
E6548E6027279DFF00F399B2 /* VerificationPageStaticContentDocumentCaptureModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548E5627279DFF00F399B2 /* VerificationPageStaticContentDocumentCaptureModels.swift */; };
E6548E6927288C0D00F399B2 /* STPAPIClient+Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548E6827288C0D00F399B2 /* STPAPIClient+Identity.swift */; };
E6548E6927288C0D00F399B2 /* IdentityAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548E6827288C0D00F399B2 /* IdentityAPIClient.swift */; };
E6548EEA2729025000F399B2 /* StripeCore+Import.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548EE92729025000F399B2 /* StripeCore+Import.swift */; };
E6548EED2729BB2100F399B2 /* VerificationPage_200.json in Resources */ = {isa = PBXBuildFile; fileRef = E6548EEC2729BB2100F399B2 /* VerificationPage_200.json */; };
E6548EF52729BE6B00F399B2 /* IdentityMockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548EF42729BE6B00F399B2 /* IdentityMockData.swift */; };
E6548EF82729BFC500F399B2 /* VerificationSheetControllerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548EF72729BFC500F399B2 /* VerificationSheetControllerTest.swift */; };
E6548EFD272A074D00F399B2 /* STPAPIClient+IdentityTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548EFC272A074D00F399B2 /* STPAPIClient+IdentityTest.swift */; };
E6548EFD272A074D00F399B2 /* IdentityAPIClientTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548EFC272A074D00F399B2 /* IdentityAPIClientTest.swift */; };
E6548F33272C89FE00F399B2 /* IdentityFlowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548F2D272C89FE00F399B2 /* IdentityFlowViewController.swift */; };
E6548F35272C89FE00F399B2 /* IndividualViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548F2F272C89FE00F399B2 /* IndividualViewController.swift */; };
E6548F36272C89FE00F399B2 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6548F30272C89FE00F399B2 /* LoadingViewController.swift */; };
Expand Down Expand Up @@ -242,12 +242,12 @@
E6548E5427279DFE00F399B2 /* VerificationPageStaticContentDocumentSelectPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationPageStaticContentDocumentSelectPage.swift; sourceTree = "<group>"; };
E6548E5527279DFF00F399B2 /* VerificationPageRequirements.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationPageRequirements.swift; sourceTree = "<group>"; };
E6548E5627279DFF00F399B2 /* VerificationPageStaticContentDocumentCaptureModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationPageStaticContentDocumentCaptureModels.swift; sourceTree = "<group>"; };
E6548E6827288C0D00F399B2 /* STPAPIClient+Identity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "STPAPIClient+Identity.swift"; sourceTree = "<group>"; };
E6548E6827288C0D00F399B2 /* IdentityAPIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityAPIClient.swift; sourceTree = "<group>"; };
E6548EE92729025000F399B2 /* StripeCore+Import.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StripeCore+Import.swift"; sourceTree = "<group>"; };
E6548EEC2729BB2100F399B2 /* VerificationPage_200.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VerificationPage_200.json; sourceTree = "<group>"; };
E6548EF42729BE6B00F399B2 /* IdentityMockData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityMockData.swift; sourceTree = "<group>"; };
E6548EF72729BFC500F399B2 /* VerificationSheetControllerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationSheetControllerTest.swift; sourceTree = "<group>"; };
E6548EFC272A074D00F399B2 /* STPAPIClient+IdentityTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "STPAPIClient+IdentityTest.swift"; sourceTree = "<group>"; };
E6548EFC272A074D00F399B2 /* IdentityAPIClientTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityAPIClientTest.swift; sourceTree = "<group>"; };
E6548F2D272C89FE00F399B2 /* IdentityFlowViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityFlowViewController.swift; sourceTree = "<group>"; };
E6548F2F272C89FE00F399B2 /* IndividualViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndividualViewController.swift; sourceTree = "<group>"; };
E6548F30272C89FE00F399B2 /* LoadingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -461,7 +461,7 @@
isa = PBXGroup;
children = (
E6548DCD27276E2900F399B2 /* Models */,
E6548E6827288C0D00F399B2 /* STPAPIClient+Identity.swift */,
E6548E6827288C0D00F399B2 /* IdentityAPIClient.swift */,
E651A4C62787D7FE0009506E /* DocumentUploader+API.swift */,
E662FC91278E48DB005B0DAD /* DocumentType+StripeIdentity.swift */,
);
Expand Down Expand Up @@ -521,7 +521,7 @@
E6548EFB272A073C00F399B2 /* API Bindings */ = {
isa = PBXGroup;
children = (
E6548EFC272A074D00F399B2 /* STPAPIClient+IdentityTest.swift */,
E6548EFC272A074D00F399B2 /* IdentityAPIClientTest.swift */,
E6A50DB327B4858A00D7BDED /* TruncatedDecimalTest.swift */,
);
path = "API Bindings";
Expand Down Expand Up @@ -1072,7 +1072,7 @@
E61ADAD3270F6293004ED998 /* VerificationSheetController.swift in Sources */,
E666A52A273A0951001DE130 /* Image.swift in Sources */,
E6548F852734541F00F399B2 /* ErrorViewController.swift in Sources */,
E6548E6927288C0D00F399B2 /* STPAPIClient+Identity.swift in Sources */,
E6548E6927288C0D00F399B2 /* IdentityAPIClient.swift in Sources */,
E6465122269E202A002EC424 /* STPLocalizedString.swift in Sources */,
E6548F36272C89FE00F399B2 /* LoadingViewController.swift in Sources */,
F383FB4927B5E7FA00E19E52 /* UINavigationController+StripeIdentity.swift in Sources */,
Expand Down Expand Up @@ -1153,7 +1153,7 @@
F3FA474527ADD5DA0045AB4B /* IdentityFlowViewSnapshotTest.swift in Sources */,
F3680E0027A9C6ED00A8796A /* HeaderIconViewSnapshotTest.swift in Sources */,
E6ABED6D276C1BF8007F6D89 /* DocumentUploaderMock.swift in Sources */,
E6548EFD272A074D00F399B2 /* STPAPIClient+IdentityTest.swift in Sources */,
E6548EFD272A074D00F399B2 /* IdentityAPIClientTest.swift in Sources */,
E666A51A2736243D001DE130 /* VerificationSheetFlowControllerMock.swift in Sources */,
E651A4C927890BAB0009506E /* DocumentUploaderTest.swift in Sources */,
F383FB4727B5D52C00E19E52 /* ErrorViewSnapshotTest.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//
// IdentityAPIClient.swift
// StripeIdentity
//
// Created by Mel Ludowise on 10/26/21.
//

import Foundation
import UIKit
@_spi(STP) import StripeCore

protocol IdentityAPIClient {
var verificationSessionId: String { get }

func getIdentityVerificationPage() -> Promise<VerificationPage>

func updateIdentityVerificationPageData(
updating verificationData: VerificationPageDataUpdate
) -> Promise<VerificationPageData>

func submitIdentityVerificationPage() -> Promise<VerificationPageData>

func uploadImage(
_ image: UIImage,
compressionQuality: CGFloat,
purpose: String,
fileName: String
) -> Promise<StripeFile>
}

final class IdentityAPIClientImpl: IdentityAPIClient {
static let apiVersion: Int = 1

static var betas: Set<String> {
return ["identity_client_api=v\(apiVersion)"]
}

let apiClient: STPAPIClient
let verificationSessionId: String

private init(
verificationSessionId: String,
apiClient: STPAPIClient
) {
self.verificationSessionId = verificationSessionId
self.apiClient = apiClient
}

convenience init(
verificationSessionId: String,
ephemeralKeySecret: String
) {
let apiClient = STPAPIClient(publishableKey: ephemeralKeySecret)
apiClient.betas = IdentityAPIClientImpl.betas
apiClient.appInfo = STPAPIClient.shared.appInfo

self.init(
verificationSessionId: verificationSessionId,
apiClient: apiClient
)
}

func getIdentityVerificationPage() -> Promise<VerificationPage> {
return apiClient.get(
resource: APIEndpointVerificationPage(id: verificationSessionId),
parameters: [:]
)
}

func updateIdentityVerificationPageData(
updating verificationData: VerificationPageDataUpdate
) -> Promise<VerificationPageData> {
return apiClient.post(
resource: APIEndpointVerificationPageData(id: verificationSessionId),
object: verificationData
)
}

func submitIdentityVerificationPage() -> Promise<VerificationPageData> {
return apiClient.post(
resource: APIEndpointVerificationPageSubmit(id: verificationSessionId),
parameters: [:]
)
}

func uploadImage(
_ image: UIImage,
compressionQuality: CGFloat,
purpose: String,
fileName: String
) -> Promise<StripeFile> {
return apiClient.uploadImage(
image,
compressionQuality: compressionQuality,
purpose: purpose,
fileName: fileName,
ownedBy: verificationSessionId
)
}


}

private func APIEndpointVerificationPage(id: String) -> String {
return "identity/verification_pages/\(id)"
}
private func APIEndpointVerificationPageData(id: String) -> String {
return "identity/verification_pages/\(id)/data"
}
private func APIEndpointVerificationPageSubmit(id: String) -> String {
return "identity/verification_pages/\(id)/submit"
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ final public class IdentityVerificationSheet {
self.init(
verificationSessionClientSecret: "",
verificationSheetController: VerificationSheetController(
verificationSessionId: verificationSessionId,
ephemeralKeySecret: ephemeralKeySecret,
apiClient: STPAPIClient.makeIdentityClient(),
apiClient: IdentityAPIClientImpl(
verificationSessionId: verificationSessionId,
ephemeralKeySecret: ephemeralKeySecret
),
flowController: VerificationSheetFlowController(
merchantLogo: configuration.merchantLogo
),
Expand Down Expand Up @@ -132,7 +133,7 @@ final public class IdentityVerificationSheet {
// Overwrite completion closure to retain self until called
let completion: (VerificationFlowResult) -> Void = { result in
let verificationSessionId = self.clientSecret?.verificationSessionId
?? self.verificationSheetController?.verificationSessionId
?? self.verificationSheetController?.apiClient.verificationSessionId
self.analyticsClient.log(analytic: VerificationSheetCompletionAnalytic.make(
verificationSessionId: verificationSessionId,
sessionResult: result
Expand Down Expand Up @@ -160,7 +161,7 @@ final public class IdentityVerificationSheet {

if let verificationSheetController = verificationSheetController {
// Use native UI
verificationSessionId = verificationSheetController.verificationSessionId
verificationSessionId = verificationSheetController.apiClient.verificationSessionId
navigationController = verificationSheetController.flowController.navigationController
verificationSheetController.loadAndUpdateUI()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ final class DocumentUploader: DocumentUploaderProtocol {
let configuration: Configuration

let apiClient: IdentityAPIClient
let verificationSessionId: String
let ephemeralKeySecret: String

/// Worker queue to encode the image to jpeg
let imageEncodingQueue = DispatchQueue(label: "com.stripe.identity.image-encoding")
Expand Down Expand Up @@ -150,14 +148,10 @@ final class DocumentUploader: DocumentUploaderProtocol {

init(
configuration: Configuration,
apiClient: IdentityAPIClient,
verificationSessionId: String,
ephemeralKeySecret: String
apiClient: IdentityAPIClient
) {
self.configuration = configuration
self.apiClient = apiClient
self.verificationSessionId = verificationSessionId
self.ephemeralKeySecret = ephemeralKeySecret
}

/**
Expand All @@ -183,7 +177,7 @@ final class DocumentUploader: DocumentUploaderProtocol {
originalImage,
documentScannerOutput: documentScannerOutput,
method: method,
fileNamePrefix: "\(verificationSessionId)_\(side.rawValue)"
fileNamePrefix: "\(apiClient.verificationSessionId)_\(side.rawValue)"
)

switch side {
Expand Down Expand Up @@ -286,9 +280,7 @@ final class DocumentUploader: DocumentUploaderProtocol {
uiImage,
compressionQuality: jpegCompressionQuality,
purpose: self.configuration.filePurpose,
fileName: fileName,
ownedBy: self.verificationSessionId,
ephemeralKeySecret: self.ephemeralKeySecret
fileName: fileName
).observe { result in
promise.fullfill(with: result)
}
Expand Down
Loading

0 comments on commit 03636f7

Please sign in to comment.