diff --git a/Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift b/Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift index 6ab11bf..71c6c1d 100644 --- a/Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift +++ b/Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift @@ -136,8 +136,6 @@ class AnalyticsClient: AnalyticsClientBehaviour { } } event.setUserAttribute(userAttributes) - let objId = ObjectIdentifier(event) - event.hashCode = objId.hashValue try eventRecorder.save(event) } diff --git a/Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift b/Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift index 967a821..09bdf20 100644 --- a/Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift +++ b/Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift @@ -11,8 +11,7 @@ import Foundation private typealias Limit = Event.Limit typealias JsonObject = [String: Any] -class ClickstreamEvent: AnalyticsPropertiesModel, Hashable { - var hashCode: Int! +class ClickstreamEvent: AnalyticsPropertiesModel { let eventId: String let appId: String let uniqueId: String @@ -65,14 +64,9 @@ class ClickstreamEvent: AnalyticsPropertiesModel, Hashable { attributes[key] } - func toJson(forHashCode: Bool = false) -> String { + func toJson() -> String { var event = JsonObject() - if !forHashCode { - if hashCode == nil { - hashCode = hashValue - } - event["hashCode"] = String(format: "%08X", hashCode) - } + event["hashCode"] = "" event["unique_id"] = uniqueId event["event_type"] = eventType event["event_id"] = eventId @@ -100,6 +94,8 @@ class ClickstreamEvent: AnalyticsPropertiesModel, Hashable { event["app_title"] = systemInfo.appTitle event["user"] = userAttributes event["attributes"] = getAttributeObject(from: attributes) + let eventJson = getJsonStringFromObject(jsonObject: event) + event["hashCode"] = eventJson.hashCode() return getJsonStringFromObject(jsonObject: event) } @@ -134,10 +130,6 @@ class ClickstreamEvent: AnalyticsPropertiesModel, Hashable { return attribute } - func hash(into hasher: inout Hasher) { - hasher.combine(toJson(forHashCode: true)) - } - static func == (lhs: ClickstreamEvent, rhs: ClickstreamEvent) -> Bool { lhs.toJson() == rhs.toJson() } diff --git a/Sources/Clickstream/Support/Extension/String+HashCode.swift b/Sources/Clickstream/Support/Extension/String+HashCode.swift new file mode 100644 index 0000000..f831857 --- /dev/null +++ b/Sources/Clickstream/Support/Extension/String+HashCode.swift @@ -0,0 +1,20 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import CryptoKit +import Foundation + +extension String { + func hashCode() -> String { + if let data = data(using: .utf8) { + let hashed = SHA256.hash(data: data) + let hashString = hashed.compactMap { String(format: "%02x", $0) }.joined() + return String(hashString.prefix(8)) + } + return "" + } +} diff --git a/Tests/ClickstreamTests/Clickstream/ClickstreamEventTest.swift b/Tests/ClickstreamTests/Clickstream/ClickstreamEventTest.swift index a9c8890..04a5237 100644 --- a/Tests/ClickstreamTests/Clickstream/ClickstreamEventTest.swift +++ b/Tests/ClickstreamTests/Clickstream/ClickstreamEventTest.swift @@ -64,7 +64,7 @@ class ClickstreamEventTest: XCTestCase { } func testEventEqualsFail() { - let event1 = clickstreamEvent + let event1 = clickstreamEvent! let event2 = ClickstreamEvent(eventType: "testEvent", appId: testAppId, uniqueId: UUID().uuidString, diff --git a/Tests/ClickstreamTests/Clickstream/EventRecorderTest.swift b/Tests/ClickstreamTests/Clickstream/EventRecorderTest.swift index e71e65a..5ea37d9 100644 --- a/Tests/ClickstreamTests/Clickstream/EventRecorderTest.swift +++ b/Tests/ClickstreamTests/Clickstream/EventRecorderTest.swift @@ -412,6 +412,36 @@ class EventRecorderTest: XCTestCase { activityTracker.callback?(.runningInBackground) XCTAssertTrue(eventRecorder.queue.operationCount > 0) } + + func testGetEventHashCodeTwice() { + let eventJson = clickstreamEvent.toJson() + let hashCode1 = eventJson.hashCode() + let hashCode2 = eventJson.hashCode() + XCTAssertEqual(hashCode1, hashCode2) + } + + func testEventModified() throws { + let originJson = clickstreamEvent.toJson() + let originJsonData = originJson.data(using: .utf8)! + var jsonObject = try JSONSerialization.jsonObject(with: originJsonData, options: []) as! [String: Any] + let originHashCode = jsonObject["hashCode"] as! String + jsonObject["hashCode"] = "" + jsonObject["event_type"] = "testEvent1" + let jsonWithoutHashCode = clickstreamEvent.getJsonStringFromObject(jsonObject: jsonObject) + let computedHashCode = jsonWithoutHashCode.hashCode() + XCTAssertNotEqual(originHashCode, computedHashCode) + } + + func testEventNotModified() throws { + let originJson = clickstreamEvent.toJson() + let originJsonData = originJson.data(using: .utf8)! + var jsonObject = try JSONSerialization.jsonObject(with: originJsonData, options: []) as! [String: Any] + let originHashCode = jsonObject["hashCode"] as! String + jsonObject["hashCode"] = "" + let jsonWithoutHashCode = clickstreamEvent.getJsonStringFromObject(jsonObject: jsonObject) + let computedHashCode = jsonWithoutHashCode.hashCode() + XCTAssertEqual(originHashCode, computedHashCode) + } } extension String {