rn-linkrunner 2.10.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LinkrunnerSDK.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/io/linkrunner/LinkrunnerModule.kt +37 -0
- package/ios/LinkrunnerSDK.m +4 -0
- package/ios/LinkrunnerSDK.swift +31 -4
- package/ios/Podfile +1 -1
- package/lib/commonjs/index.js +18 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +18 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +22 -0
- package/ios/Pods/LinkrunnerKit/LICENSE +0 -21
- package/ios/Pods/LinkrunnerKit/README.md +0 -15
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/HmacSignatureGenerator.swift +0 -95
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/Linkrunner.swift +0 -1109
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/Models.swift +0 -356
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/RequestSigningInterceptor.swift +0 -110
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/SHA256.swift +0 -12
- package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/SKAdNetworkService.swift +0 -428
- package/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -440
- package/ios/Pods/Pods.xcodeproj/xcuserdata/shofiyabootwala.xcuserdatad/xcschemes/LinkrunnerKit.xcscheme +0 -58
- package/ios/Pods/Pods.xcodeproj/xcuserdata/shofiyabootwala.xcuserdatad/xcschemes/xcschememanagement.plist +0 -16
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-Info.plist +0 -26
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-dummy.m +0 -5
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-prefix.pch +0 -12
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-umbrella.h +0 -16
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.debug.xcconfig +0 -17
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.modulemap +0 -6
- package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.release.xcconfig +0 -17
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
// MARK: - Error Types
|
|
4
|
-
|
|
5
|
-
public enum LinkrunnerError: Error {
|
|
6
|
-
case notInitialized
|
|
7
|
-
case invalidUrl
|
|
8
|
-
case httpError(Int)
|
|
9
|
-
case apiError(String)
|
|
10
|
-
case jsonEncodingFailed
|
|
11
|
-
case jsonDecodingFailed
|
|
12
|
-
case invalidResponse
|
|
13
|
-
case invalidParameters(String)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
extension LinkrunnerError: LocalizedError {
|
|
17
|
-
public var errorDescription: String? {
|
|
18
|
-
switch self {
|
|
19
|
-
case .notInitialized:
|
|
20
|
-
return "Linkrunner not initialized. Call initialize(token:) first."
|
|
21
|
-
case .invalidUrl:
|
|
22
|
-
return "Invalid URL"
|
|
23
|
-
case .httpError(let code):
|
|
24
|
-
return "HTTP error: \(code)"
|
|
25
|
-
case .apiError(let message):
|
|
26
|
-
return "API error: \(message)"
|
|
27
|
-
case .jsonEncodingFailed:
|
|
28
|
-
return "Failed to encode JSON"
|
|
29
|
-
case .jsonDecodingFailed:
|
|
30
|
-
return "Failed to decode JSON"
|
|
31
|
-
case .invalidResponse:
|
|
32
|
-
return "Invalid API response"
|
|
33
|
-
case .invalidParameters(let message):
|
|
34
|
-
return "Invalid parameters: \(message)"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Sendable dictionary type alias
|
|
40
|
-
public typealias SendableDictionary = [String: Any]
|
|
41
|
-
extension SendableDictionary: @unchecked Sendable {}
|
|
42
|
-
|
|
43
|
-
// MARK: - Model Types
|
|
44
|
-
|
|
45
|
-
public struct UserData: Sendable {
|
|
46
|
-
public let id: String
|
|
47
|
-
public let name: String?
|
|
48
|
-
public let phone: String?
|
|
49
|
-
public let email: String?
|
|
50
|
-
public let isFirstTimeUser: Bool?
|
|
51
|
-
public let userCreatedAt: String?
|
|
52
|
-
public let mixPanelDistinctId: String?
|
|
53
|
-
public let amplitudeDeviceId: String?
|
|
54
|
-
public let posthogDistinctId: String?
|
|
55
|
-
public let brazeDeviceId: String?
|
|
56
|
-
public let gaAppInstanceId: String?
|
|
57
|
-
|
|
58
|
-
public init(id: String, name: String? = nil, phone: String? = nil, email: String? = nil, isFirstTimeUser: Bool? = nil, userCreatedAt: String? = nil, mixPanelDistinctId: String? = nil, amplitudeDeviceId: String? = nil, posthogDistinctId: String? = nil, brazeDeviceId: String? = nil, gaAppInstanceId: String? = nil) {
|
|
59
|
-
self.id = id
|
|
60
|
-
self.name = name
|
|
61
|
-
self.phone = phone
|
|
62
|
-
self.email = email
|
|
63
|
-
self.isFirstTimeUser = isFirstTimeUser
|
|
64
|
-
self.userCreatedAt = userCreatedAt
|
|
65
|
-
self.mixPanelDistinctId = mixPanelDistinctId
|
|
66
|
-
self.amplitudeDeviceId = amplitudeDeviceId
|
|
67
|
-
self.posthogDistinctId = posthogDistinctId
|
|
68
|
-
self.brazeDeviceId = brazeDeviceId
|
|
69
|
-
self.gaAppInstanceId = gaAppInstanceId
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/// Converts UserData to a dictionary, optionally hashing PII fields
|
|
73
|
-
/// - Parameter hashPII: Whether to hash PII fields
|
|
74
|
-
/// - Returns: Dictionary representation of UserData
|
|
75
|
-
func toDictionary(hashPII: Bool = false) -> SendableDictionary {
|
|
76
|
-
var dict: SendableDictionary = ["id": id]
|
|
77
|
-
|
|
78
|
-
if let name = name {
|
|
79
|
-
dict["name"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(name) : name
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if let phone = phone {
|
|
83
|
-
dict["phone"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(phone) : phone
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if let email = email {
|
|
87
|
-
dict["email"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(email) : email
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if let isFirstTimeUser = isFirstTimeUser {
|
|
91
|
-
dict["is_first_time_user"] = isFirstTimeUser
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if let userCreatedAt = userCreatedAt {
|
|
95
|
-
dict["user_created_at"] = userCreatedAt
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if let mixPanelDistinctId = mixPanelDistinctId {
|
|
99
|
-
dict["mixpanel_distinct_id"] = mixPanelDistinctId
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if let amplitudeDeviceId = amplitudeDeviceId {
|
|
103
|
-
dict["amplitude_device_id"] = amplitudeDeviceId
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if let posthogDistinctId = posthogDistinctId {
|
|
107
|
-
dict["posthog_distinct_id"] = posthogDistinctId
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if let brazeDeviceId = brazeDeviceId {
|
|
111
|
-
dict["braze_device_id"] = brazeDeviceId
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if let gaAppInstanceId = gaAppInstanceId {
|
|
115
|
-
dict["ga_app_instance_id"] = gaAppInstanceId
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return dict
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/// Legacy dictionary property for backward compatibility
|
|
122
|
-
var dictionary: SendableDictionary {
|
|
123
|
-
return toDictionary(hashPII: false)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
public struct CampaignData: Codable, Sendable {
|
|
128
|
-
public let id: String
|
|
129
|
-
public let name: String
|
|
130
|
-
public let type: CampaignType
|
|
131
|
-
public let adNetwork: AdNetwork?
|
|
132
|
-
public let groupName: String?
|
|
133
|
-
public let assetGroupName: String?
|
|
134
|
-
public let assetName: String?
|
|
135
|
-
public let installedAt: Date?
|
|
136
|
-
public let storeClickAt: Date?
|
|
137
|
-
|
|
138
|
-
public enum CampaignType: String, Codable, Sendable {
|
|
139
|
-
case organic = "ORGANIC"
|
|
140
|
-
case inorganic = "INORGANIC"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
public enum AdNetwork: String, Codable, Sendable {
|
|
144
|
-
case meta = "META"
|
|
145
|
-
case google = "GOOGLE"
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
enum CodingKeys: String, CodingKey {
|
|
149
|
-
case id, name, type
|
|
150
|
-
case adNetwork = "ad_network"
|
|
151
|
-
case groupName = "group_name"
|
|
152
|
-
case assetGroupName = "asset_group_name"
|
|
153
|
-
case assetName = "asset_name"
|
|
154
|
-
case installedAt = "installed_at"
|
|
155
|
-
case storeClickAt = "store_click_at"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
init(dictionary: SendableDictionary) throws {
|
|
159
|
-
guard let id = dictionary["id"] as? String,
|
|
160
|
-
let name = dictionary["name"] as? String,
|
|
161
|
-
let type = dictionary["type"] as? String else {
|
|
162
|
-
throw LinkrunnerError.invalidResponse
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
self.id = id
|
|
166
|
-
self.name = name
|
|
167
|
-
self.type = CampaignType(rawValue: type) ?? .organic
|
|
168
|
-
self.adNetwork = (dictionary["ad_network"] as? String).flatMap { AdNetwork(rawValue: $0) }
|
|
169
|
-
self.groupName = dictionary["group_name"] as? String
|
|
170
|
-
self.assetGroupName = dictionary["asset_group_name"] as? String
|
|
171
|
-
self.assetName = dictionary["asset_name"] as? String
|
|
172
|
-
|
|
173
|
-
// Parse date strings
|
|
174
|
-
let dateFormatter = ISO8601DateFormatter()
|
|
175
|
-
|
|
176
|
-
if let installedAtString = dictionary["installed_at"] as? String, installedAtString != "<null>" {
|
|
177
|
-
self.installedAt = dateFormatter.date(from: installedAtString)
|
|
178
|
-
} else {
|
|
179
|
-
self.installedAt = nil
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if let storeClickAtString = dictionary["store_click_at"] as? String, storeClickAtString != "<null>" {
|
|
183
|
-
self.storeClickAt = dateFormatter.date(from: storeClickAtString)
|
|
184
|
-
} else {
|
|
185
|
-
self.storeClickAt = nil
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
public func toDictionary() -> SendableDictionary {
|
|
191
|
-
let dateFormatter = ISO8601DateFormatter()
|
|
192
|
-
dateFormatter.formatOptions = [.withInternetDateTime]
|
|
193
|
-
|
|
194
|
-
var dict: SendableDictionary = [
|
|
195
|
-
"id": id,
|
|
196
|
-
"name": name,
|
|
197
|
-
"type": type.rawValue
|
|
198
|
-
]
|
|
199
|
-
|
|
200
|
-
if let adNetwork = adNetwork {
|
|
201
|
-
dict["ad_network"] = adNetwork.rawValue
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if let groupName = groupName {
|
|
205
|
-
dict["group_name"] = groupName
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if let assetGroupName = assetGroupName {
|
|
209
|
-
dict["asset_group_name"] = assetGroupName
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if let assetName = assetName {
|
|
213
|
-
dict["asset_name"] = assetName
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if let installedAt = installedAt {
|
|
217
|
-
dict["installed_at"] = dateFormatter.string(from: installedAt)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if let storeClickAt = storeClickAt {
|
|
221
|
-
dict["store_click_at"] = dateFormatter.string(from: storeClickAt)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return dict
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
public struct IntegrationData: Sendable {
|
|
229
|
-
public let clevertapId: String?
|
|
230
|
-
|
|
231
|
-
public init(clevertapId: String? = nil) {
|
|
232
|
-
self.clevertapId = clevertapId
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
func toDictionary() -> SendableDictionary {
|
|
236
|
-
var dict: SendableDictionary = [:]
|
|
237
|
-
|
|
238
|
-
if let clevertapId = clevertapId {
|
|
239
|
-
dict["clevertap_id"] = clevertapId
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return dict
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
public enum PaymentType: String, Sendable {
|
|
247
|
-
case firstPayment = "FIRST_PAYMENT"
|
|
248
|
-
case secondPayment = "SECOND_PAYMENT"
|
|
249
|
-
case walletTopup = "WALLET_TOPUP"
|
|
250
|
-
case fundsWithdrawal = "FUNDS_WITHDRAWAL"
|
|
251
|
-
case subscriptionCreated = "SUBSCRIPTION_CREATED"
|
|
252
|
-
case subscriptionRenewed = "SUBSCRIPTION_RENEWED"
|
|
253
|
-
case oneTime = "ONE_TIME"
|
|
254
|
-
case recurring = "RECURRING"
|
|
255
|
-
case `default` = "DEFAULT"
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
public enum PaymentStatus: String, Sendable {
|
|
259
|
-
case initiated = "PAYMENT_INITIATED"
|
|
260
|
-
case completed = "PAYMENT_COMPLETED"
|
|
261
|
-
case failed = "PAYMENT_FAILED"
|
|
262
|
-
case cancelled = "PAYMENT_CANCELLED"
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// MARK: - API Response Models
|
|
266
|
-
|
|
267
|
-
/// Response model for capture-payment endpoint
|
|
268
|
-
public struct CapturePaymentResponse: Codable, Sendable {
|
|
269
|
-
public let success: Bool
|
|
270
|
-
public let message: String
|
|
271
|
-
public let data: String?
|
|
272
|
-
|
|
273
|
-
enum CodingKeys: String, CodingKey {
|
|
274
|
-
case success
|
|
275
|
-
case message
|
|
276
|
-
case data
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/// Response model for capture-event endpoint
|
|
281
|
-
public struct CaptureEventResponse: Codable, Sendable {
|
|
282
|
-
public let success: Bool
|
|
283
|
-
public let message: String
|
|
284
|
-
public let data: String?
|
|
285
|
-
|
|
286
|
-
enum CodingKeys: String, CodingKey {
|
|
287
|
-
case success
|
|
288
|
-
case message
|
|
289
|
-
case data
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/// Response model for attribution data
|
|
294
|
-
public struct LRAttributionDataResponse: Codable, Sendable {
|
|
295
|
-
|
|
296
|
-
public let attributionSource: String
|
|
297
|
-
public let campaignData: CampaignData?
|
|
298
|
-
public let deeplink: String?
|
|
299
|
-
|
|
300
|
-
enum CodingKeys: String, CodingKey {
|
|
301
|
-
case attributionSource = "attribution_source"
|
|
302
|
-
case campaignData = "campaign_data"
|
|
303
|
-
case deeplink
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Public initializer for creating empty/default responses
|
|
307
|
-
public init(attributionSource: String, campaignData: CampaignData?, deeplink: String?) {
|
|
308
|
-
self.attributionSource = attributionSource
|
|
309
|
-
self.campaignData = campaignData
|
|
310
|
-
self.deeplink = deeplink
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Custom decoder to handle Bool/Int conversion for rootDomain
|
|
314
|
-
public init(from decoder: Decoder) throws {
|
|
315
|
-
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
316
|
-
|
|
317
|
-
attributionSource = try container.decodeIfPresent(String.self, forKey: .attributionSource) ?? "UNKNOWN"
|
|
318
|
-
campaignData = try container.decodeIfPresent(CampaignData.self, forKey: .campaignData)
|
|
319
|
-
deeplink = try container.decodeIfPresent(String.self, forKey: .deeplink)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Legacy dictionary initializer for backward compatibility
|
|
323
|
-
init(dictionary: SendableDictionary) throws {
|
|
324
|
-
self.attributionSource = dictionary["attribution_source"] as? String ?? "UNKNOWN"
|
|
325
|
-
|
|
326
|
-
// Handle campaign_data - can be null
|
|
327
|
-
if let campaignDataDict = dictionary["campaign_data"] as? SendableDictionary {
|
|
328
|
-
self.campaignData = try CampaignData(dictionary: campaignDataDict)
|
|
329
|
-
} else {
|
|
330
|
-
self.campaignData = nil
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Handle deeplink - can be null
|
|
334
|
-
if let deeplink = dictionary["deeplink"] as? String, deeplink != "<null>" {
|
|
335
|
-
self.deeplink = deeplink
|
|
336
|
-
} else {
|
|
337
|
-
self.deeplink = nil
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
public func toDictionary() -> SendableDictionary {
|
|
342
|
-
var dict: SendableDictionary = [
|
|
343
|
-
"attribution_source": attributionSource
|
|
344
|
-
]
|
|
345
|
-
|
|
346
|
-
if let campaignData = campaignData {
|
|
347
|
-
dict["campaign_data"] = campaignData.toDictionary()
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
if let deeplink = deeplink {
|
|
351
|
-
dict["deeplink"] = deeplink
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return dict
|
|
355
|
-
}
|
|
356
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
public class RequestSigningInterceptor: NSObject {
|
|
4
|
-
// MARK: - Constants
|
|
5
|
-
private static let AUTHORIZATION_HEADER = "Authorization"
|
|
6
|
-
private static let TIMESTAMP_HEADER = "x-Timestamp"
|
|
7
|
-
private static let SIGNATURE_HEADER = "x-Signature"
|
|
8
|
-
private static let KEY_ID_HEADER = "x-Key-Id"
|
|
9
|
-
|
|
10
|
-
// MARK: - Properties
|
|
11
|
-
private var generator: HmacSignatureGenerator?
|
|
12
|
-
|
|
13
|
-
// Dedicated URLSession for the SDK to avoid interference with app's networking
|
|
14
|
-
private let sdkSession: URLSession
|
|
15
|
-
|
|
16
|
-
// MARK: - Initialization
|
|
17
|
-
public override init() {
|
|
18
|
-
// Create a dedicated URLSession with ephemeral configuration for the SDK
|
|
19
|
-
// This ensures it doesn't share cookies, cache or credentials with the app's sessions
|
|
20
|
-
let config = URLSessionConfiguration.ephemeral
|
|
21
|
-
config.timeoutIntervalForRequest = 30.0
|
|
22
|
-
|
|
23
|
-
self.sdkSession = URLSession(configuration: config)
|
|
24
|
-
super.init()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/// Configure the interceptor with the necessary credentials using raw data
|
|
29
|
-
/// - Parameters:
|
|
30
|
-
/// - secretKeyData: The raw secret key data
|
|
31
|
-
/// - keyId: The key ID for signing requests
|
|
32
|
-
public func configure(secretKey: String, keyId: String) {
|
|
33
|
-
self.generator = HmacSignatureGenerator(secretKey: secretKey, keyId: keyId)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/// Reset the interceptor configuration
|
|
37
|
-
public func reset() {
|
|
38
|
-
self.generator = nil
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// MARK: - Request Signing Methods
|
|
42
|
-
|
|
43
|
-
/// Sign a URL request with HMAC authentication
|
|
44
|
-
/// - Parameter request: The original request to sign
|
|
45
|
-
/// - Returns: A signed copy of the request, or the original if signing fails or credentials aren't set
|
|
46
|
-
public func signRequest(_ request: URLRequest) -> URLRequest {
|
|
47
|
-
// If the generator is not configured (no credentials set), return the original request
|
|
48
|
-
guard let generator = self.generator else {
|
|
49
|
-
return request
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Attempt to sign the request, but don't block the request if signing fails
|
|
53
|
-
do {
|
|
54
|
-
var requestBody: String? = nil
|
|
55
|
-
|
|
56
|
-
if let bodyData = request.httpBody {
|
|
57
|
-
requestBody = String(data: bodyData, encoding: .utf8)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let signedData = generator.signRequest(payload: requestBody)
|
|
61
|
-
|
|
62
|
-
let signedRequest = addSignatureHeaders(
|
|
63
|
-
originalRequest: request,
|
|
64
|
-
signature: signedData.signature,
|
|
65
|
-
timestamp: signedData.timestamp
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
return signedRequest
|
|
69
|
-
} catch {
|
|
70
|
-
return request
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private Methods
|
|
75
|
-
|
|
76
|
-
/// Add signature headers to the request
|
|
77
|
-
/// - Parameters:
|
|
78
|
-
/// - originalRequest: The original request
|
|
79
|
-
/// - signature: The generated signature
|
|
80
|
-
/// - timestamp: The timestamp used for signing
|
|
81
|
-
/// - Returns: A new request with signature headers
|
|
82
|
-
private func addSignatureHeaders(
|
|
83
|
-
originalRequest: URLRequest,
|
|
84
|
-
signature: String,
|
|
85
|
-
timestamp: Int64
|
|
86
|
-
) -> URLRequest {
|
|
87
|
-
var request = originalRequest
|
|
88
|
-
request.setValue("HMAC", forHTTPHeaderField: RequestSigningInterceptor.AUTHORIZATION_HEADER)
|
|
89
|
-
request.setValue(generator?.signRequest(payload: nil).keyId, forHTTPHeaderField: RequestSigningInterceptor.KEY_ID_HEADER)
|
|
90
|
-
request.setValue(String(timestamp), forHTTPHeaderField: RequestSigningInterceptor.TIMESTAMP_HEADER)
|
|
91
|
-
request.setValue(signature, forHTTPHeaderField: RequestSigningInterceptor.SIGNATURE_HEADER)
|
|
92
|
-
return request
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// MARK: - Request Signing Methods
|
|
97
|
-
|
|
98
|
-
@available(iOS 15.0, macOS 12.0, watchOS 8.0, tvOS 15.0, *)
|
|
99
|
-
extension RequestSigningInterceptor {
|
|
100
|
-
/// Sign and send a request using the SDK's dedicated URLSession
|
|
101
|
-
/// - Parameter request: The request to sign and send
|
|
102
|
-
/// - Returns: A tuple containing Data and URLResponse
|
|
103
|
-
public func signAndSendRequest(_ request: URLRequest) async throws -> (Data, URLResponse) {
|
|
104
|
-
let signedRequest = signRequest(request)
|
|
105
|
-
|
|
106
|
-
let (data, response) = try await sdkSession.data(for: signedRequest)
|
|
107
|
-
|
|
108
|
-
return (data, response)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import CryptoKit
|
|
3
|
-
|
|
4
|
-
/// Simple SHA-256 hashing utility for LinkrunnerSDK
|
|
5
|
-
enum SHA256 {
|
|
6
|
-
/// Hashes data using SHA-256 algorithm
|
|
7
|
-
/// - Parameter data: The data to hash
|
|
8
|
-
/// - Returns: The hashed data
|
|
9
|
-
static func hash(data: Data) -> Data {
|
|
10
|
-
return Data(CryptoKit.SHA256.hash(data: data))
|
|
11
|
-
}
|
|
12
|
-
}
|