So we are unable to actually validate that what we are doing is right.
I checked on the bug referenced above (r. 66808193) and it’s reported as fixed so I sat down to try this for myself. Pasted in below is some Swift code that verifies the example in the documentation. I built this using Xcode 12.5. When I run it on my Mac, running macOS 11.6, it prints:
Postback(version: "3.0", adNetworkID: "example123.skadnetwork", campaignID: 42, transactionID: "6aafb7a5-0170-41b5-bbe4-fe71dedf1e28", appID: 525463029, attributionSignature: 70 bytes, redownload: true, sourceAppID: 1234567891, fidelityType: 1, conversionValue: 20, didWin: true)
I’m not sure why it’s not working for you but this snippet should give you a baseline to work from.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
import Foundation
import CryptoKit
struct Postback: Codable {
var version: String
var adNetworkID: String
var campaignID: Int
var transactionID: String
var appID: Int
var attributionSignature: Data
var redownload: Bool
var sourceAppID: Int
var fidelityType: Int
var conversionValue: Int
var didWin: Bool
enum CodingKeys: String, CodingKey {
case version = "version"
case adNetworkID = "ad-network-id"
case campaignID = "campaign-id"
case transactionID = "transaction-id"
case appID = "app-id"
case attributionSignature = "attribution-signature"
case redownload = "redownload"
case sourceAppID = "source-app-id"
case fidelityType = "fidelity-type"
case conversionValue = "conversion-value"
case didWin = "did-win"
}
}
extension Postback {
private static let keyBytes = Data(base64Encoded: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdp8GPcGqmhgzEFj9Z2nSpQVddayaPe4FMzqM9wib1+aHaaIzoHoLN9zW4K8y4SPykE3YVK3sVqW6Af0lfx3gg==")!
private static let publicKeyFor2point1AndLater = try! P256.Signing.PublicKey(derRepresentation: keyBytes)
init(verifyingJSON: Data) throws {
let decoder = JSONDecoder()
self = try decoder.decode(Postback.self, from: verifyingJSON)
// The key works for version 2.1 and up, but I’m chosing to only support
// version 3.0.
guard self.version == "3.0" else {
// Clearly a better error is called for (-:
throw NSError(domain: NSPOSIXErrorDomain, code: Int(ENOTTY), userInfo: nil)
}
let message = [
self.version,
self.adNetworkID,
String(self.campaignID),
String(self.appID),
self.transactionID,
self.redownload ? "true" : "false",
String(self.fidelityType),
self.didWin ? "true" : "false"
].joined(separator: "\u{2063}")
let signature = try P256.Signing.ECDSASignature(derRepresentation: self.attributionSignature)
let isValid = Self.publicKeyFor2point1AndLater.isValidSignature(signature, for: Data(message.utf8))
guard isValid else {
throw NSError(domain: NSPOSIXErrorDomain, code: Int(ENOTTY), userInfo: nil)
}
}
}
func main() throws {
let postbackJSON = """
{
"version": "3.0",
"ad-network-id": "example123.skadnetwork",
"campaign-id": 42,
"transaction-id": "6aafb7a5-0170-41b5-bbe4-fe71dedf1e28",
"app-id": 525463029,
"attribution-signature": "MEQCIE0nS32ZERP3oKRi/A8omsYq259wWJb7GIsW1/ULsEqoAiAQrBlTZTJNK25MtnGDRwoldRy1CwkFIEMXJAzLRchx0Q==",
"redownload": true,
"source-app-id": 1234567891,
"fidelity-type": 1,
"conversion-value": 20,
"did-win": true
}
"""
let pb = try Postback(verifyingJSON: Data(postbackJSON.utf8))
print(pb)
}
try! main()