-1

I am attempting to convert a block of code from python and it involved encoding a json string to base64. My attempt on Swift does not produce the same base64 encoded string.

Python:

payload_nonce = datetime.datetime(2022, 10, 10, 0, 0, 0).timestamp()
payload = {"request": "/v1/mytrades", "nonce": payload_nonce}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
print(b64) 
//prints b'eyJyZXF1ZXN0IjogIi92MS9teXRyYWRlcyIsICJub25jZSI6IDE2NjUzMzEyMDAuMH0='

Swift:

let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
let date = formatter.date(from: "10/10/2022")

let payloadNonce = date!.timeIntervalSince1970
payload = [
    "request": "/v1/mytrades",
    "nonce": String(describing: payloadNonce)
]
            
do {
    let json = try JSONSerialization.data(withJSONObject: payload)
    let b64 = json.base64EncodedString()
    print(b64)
    //prints eyJyZXF1ZXN0IjoiXC92MVwvbXl0cmFkZXMiLCJub25jZSI6IjE2NjUzMzEyMDAuMCJ9
} catch {//handle error}

What am I missing?

Koh
  • 2,687
  • 1
  • 22
  • 62
  • 2
    Have you compared the two json strings the products produce before base64 encoding!? *They* are the thing with different behavior here. – luk2302 Jan 14 '23 at 08:07

2 Answers2

2

Decoding the Python payload:

{"request": "/v1/mytrades", "nonce": 1665331200.0}

Decoding the Swift payload:

{"request":"\/v1\/mytrades","nonce":"1665331200.0"}

Firstly, it's clear the payloads are different. You're using the String(describing:) initializer in Swift so nonce is being converted to a String rather than the raw floating-point value.

Secondly, JSONSerialization.data is escaping the forward slashes automatically when encoding. We can disable this optionally.

Now, other than the space between the keys in Python, the two outputs are the same. Fixed example:

let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
let date = formatter.date(from: "10/10/2022")

let payloadNonce = date!.timeIntervalSince1970
let payload: [String: Any] = [
    "request": "/v1/mytrades",
    "nonce": payloadNonce
]
            
do {
    let json = try JSONSerialization.data(withJSONObject: payload, options: .withoutEscapingSlashes)
    print(String(data: json, encoding: .utf8)!)
    let b64 = json.base64EncodedString()
    print(b64)
} catch {
}
Bradley Mackey
  • 6,777
  • 5
  • 31
  • 45
  • thanks for the answer. Not too sure if you tried testing out your code, but I tried your code and the print of the decoded json isn't correct either. I got `{"request":"/v1/mytrades","nonce":1665331200}` instead, where the payloadNonce is missing the decimal places ".0". Any idea how do I fix this? – Koh Jan 14 '23 at 14:31
  • 1
    What you `see` printed, is just an artifact of the printing. You actually get a `Double` for the `nonce`. See this post: https://stackoverflow.com/questions/46593244/swift-jsonserialization-implicitly-convert-double-value-to-string – workingdog support Ukraine Jan 15 '23 at 00:06
0

When I decode the base64 strings, I get this for the Python code:

echo "eyJyZXF1ZXN0IjogIi92MS9teXRyYWRlcyIsICJub25jZSI6IDE2NjUzMzEyMDAuMH0=" | base64 -d
{"request": "/v1/mytrades", "nonce": 1665331200.0}                      

And this for the Swift code:

echo "eyJyZXF1ZXN0IjoiXC92MVwvbXl0cmFkZXMiLCJub25jZSI6IjE2NjUzMzEyMDAuMCJ9" | base64 -d
{"request":"\/v1\/mytrades","nonce":"1665331200.0"}

It appears that the slashes in the Swift code are escaped. To fix that, see this Stack Overflow answer: Swift String escaping when serializing to JSON using Codable.

The nonce is also a float in the Python response and a string in the Swift response.

Julia
  • 1,950
  • 1
  • 9
  • 22