Skip to content

Commit

Permalink
PACUtils (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
kober32 authored Nov 29, 2023
1 parent df03d45 commit f045278
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 160 deletions.
16 changes: 8 additions & 8 deletions WultraMobileTokenSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
EA6DDF1A29F804D60011E234 /* WMTPostApprovalScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6DDF1929F804D60011E234 /* WMTPostApprovalScreen.swift */; };
EA6DDF1C29F807230011E234 /* OperationUIDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6DDF1B29F807230011E234 /* OperationUIDataTests.swift */; };
EA9CE2BE2AEAA9FD00FE4E35 /* WMTProximityCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9CE2BD2AEAA9FD00FE4E35 /* WMTProximityCheck.swift */; };
EA9CE2C22AEBDB0D00FE4E35 /* WMTTOTPUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9CE2C12AEBDB0D00FE4E35 /* WMTTOTPUtils.swift */; };
EAB7054A2AF1161500756AC2 /* TOTPParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB705492AF1161500756AC2 /* TOTPParserTests.swift */; };
EA9CE2C22AEBDB0D00FE4E35 /* WMTPACUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9CE2C12AEBDB0D00FE4E35 /* WMTPACUtils.swift */; };
EAB7054A2AF1161500756AC2 /* PACParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB705492AF1161500756AC2 /* PACParserTests.swift */; };
EACAF7B02A126B7D0021CA54 /* WMTJsonValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACAF7AF2A126B7D0021CA54 /* WMTJsonValue.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -158,8 +158,8 @@
EA6DDF1929F804D60011E234 /* WMTPostApprovalScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WMTPostApprovalScreen.swift; sourceTree = "<group>"; };
EA6DDF1B29F807230011E234 /* OperationUIDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationUIDataTests.swift; sourceTree = "<group>"; };
EA9CE2BD2AEAA9FD00FE4E35 /* WMTProximityCheck.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WMTProximityCheck.swift; sourceTree = "<group>"; };
EA9CE2C12AEBDB0D00FE4E35 /* WMTTOTPUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WMTTOTPUtils.swift; sourceTree = "<group>"; };
EAB705492AF1161500756AC2 /* TOTPParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TOTPParserTests.swift; sourceTree = "<group>"; };
EA9CE2C12AEBDB0D00FE4E35 /* WMTPACUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WMTPACUtils.swift; sourceTree = "<group>"; };
EAB705492AF1161500756AC2 /* PACParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PACParserTests.swift; sourceTree = "<group>"; };
EACAF7AF2A126B7D0021CA54 /* WMTJsonValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WMTJsonValue.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -277,7 +277,7 @@
DC395C0924E55B9B0007C36E /* PushParserTests.swift */,
DC6EDB7825A49ED900A229E4 /* OperationExpirationTests.swift */,
DC616235248508F8000DED17 /* QROperationParserTests.swift */,
EAB705492AF1161500756AC2 /* TOTPParserTests.swift */,
EAB705492AF1161500756AC2 /* PACParserTests.swift */,
);
path = WultraMobileTokenSDKTests;
sourceTree = "<group>";
Expand All @@ -295,7 +295,7 @@
DC6E52D4259C959900FC25BE /* Utils */ = {
isa = PBXGroup;
children = (
EA9CE2C12AEBDB0D00FE4E35 /* WMTTOTPUtils.swift */,
EA9CE2C12AEBDB0D00FE4E35 /* WMTPACUtils.swift */,
DC6E52D5259C964600FC25BE /* WMTOperationExpirationWatcher.swift */,
EACAF7AF2A126B7D0021CA54 /* WMTJsonValue.swift */,
);
Expand Down Expand Up @@ -587,7 +587,7 @@
DC61624224852B6D000DED17 /* NetworkingObjectsTests.swift in Sources */,
DC395C0A24E55B9B0007C36E /* PushParserTests.swift in Sources */,
DC6EDB7925A49ED900A229E4 /* OperationExpirationTests.swift in Sources */,
EAB7054A2AF1161500756AC2 /* TOTPParserTests.swift in Sources */,
EAB7054A2AF1161500756AC2 /* PACParserTests.swift in Sources */,
DC616236248508F8000DED17 /* QROperationParserTests.swift in Sources */,
EA6DDF1C29F807230011E234 /* OperationUIDataTests.swift in Sources */,
DCE660D124CEBECA00870E53 /* IntegrationTests.swift in Sources */,
Expand Down Expand Up @@ -628,7 +628,7 @@
BFEEB2092937A2680047941D /* WMTInboxGetList.swift in Sources */,
BFEEB20729379F960047941D /* WMTInboxSetMessageRead.swift in Sources */,
EA44366A29F9294600DDEC1C /* WMTPostApprovaScreenReview.swift in Sources */,
EA9CE2C22AEBDB0D00FE4E35 /* WMTTOTPUtils.swift in Sources */,
EA9CE2C22AEBDB0D00FE4E35 /* WMTPACUtils.swift in Sources */,
EA294F3D29F6A07A00A0494E /* WMTOperationUIData.swift in Sources */,
DCC5CCB32449F8CD004679AC /* WMTOperationAttribute.swift in Sources */,
DCC5CCAC2449F765004679AC /* WMTOperationsImpl.swift in Sources */,
Expand Down
122 changes: 122 additions & 0 deletions WultraMobileTokenSDK/Operations/Utils/WMTPACUtils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// Copyright 2023 Wultra s.r.o.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions
// and limitations under the License.
//

import Foundation

/// Utility class used for handling Proximity Antifraud Check
public class WMTPACUtils {

/// Method accepts deeplink URL and returns PAC data
public static func parseDeeplink(url: URL) -> WMTPACData? {

guard let components = URLComponents(string: url.absoluteString) else {
D.error("Failed to get URLComponents: URLString is malformed \(url)")
return nil
}

guard let queryItems = components.queryItems else {
D.error("Failed to get URLComponents queryItems for \(url)")
return nil
}

// Deeplink can have two query items with operationId & optional totp or single query item with JWT value
if let operationId = queryItems.first(where: { $0.name == "oid" })?.value?.removingPercentEncoding {
let totp = queryItems.first(where: { $0.name == "totp" || $0.name == "potp" })?.value?.removingPercentEncoding
return WMTPACData(operationId: operationId, totp: totp)
} else if let code = queryItems.first?.value {
return parseJWT(code: code)
} else {
D.error("Failed to get Query Items values for parsing")
return nil
}
}

/// Method accepts scanned code as a String and returns PAC data - it can be in deeplink format or JWT
public static func parseQRCode(code: String) -> WMTPACData? {
guard let encodedURLString = code.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: encodedURLString) else {
return parseJWT(code: code)
}
// if the QR code is in the deeplink format parse it the same way as the deeplink
if url.scheme != nil {
return parseDeeplink(url: url)
} else {
return parseJWT(code: code)
}
}

private static func parseJWT(code: String) -> WMTPACData? {
let jwtParts = code.split(separator: ".")

// At this moment we dont care about header, we want only payload which is the second part of JWT
let jwtBase64String = jwtParts.count > 1 ? String(jwtParts[1]) : ""

if let dataPayload = Data(base64Encoded: jwtBase64String.addBase64Padding) {
do {
return try JSONDecoder().decode(WMTPACData.self, from: dataPayload)
} catch {
D.error("Failed to decode JWT from: \(code)")
D.error("With error: \(error)")
return nil
}
}

D.error("Failed to decode QR JWT from: \(jwtBase64String)")
return nil
}
}

/// Data which is returned from parsing PAC code
public struct WMTPACData: Decodable {

/// The ID of the operation associated with the PAC
public let operationId: String

/// Time-based one time password used for Proximity antifraud check
public let totp: String?

enum Keys: String, CodingKey {
case totp = "totp"
case potp = "potp" // to keep backward compatibility
case operationId = "oid"
}

public init(operationId: String, totp: String?) {
self.operationId = operationId
self.totp = totp
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Keys.self)
operationId = try container.decode(String.self, forKey: .operationId)
if let t = try container.decodeIfPresent(String.self, forKey: .totp) {
totp = t
} else if let p = try container.decodeIfPresent(String.self, forKey: .potp) {
totp = p
} else {
totp = nil
}
}
}

private extension String {
var addBase64Padding: String {
let offset = count % 4
if offset > 0 {
return padding(toLength: count + 4 - offset, withPad: "=", startingAt: 0)
}
return self
}
}
91 changes: 0 additions & 91 deletions WultraMobileTokenSDK/Operations/Utils/WMTTOTPUtils.swift

This file was deleted.

Loading

0 comments on commit f045278

Please sign in to comment.