cloudinary / cloudinary_ios

Cloudinary iOS SDK
MIT License
165 stars 106 forks source link

Signed request error (timestamp=1) #61

Closed elijah-panfilow closed 6 years ago

elijah-panfilow commented 7 years ago

I am trying to use Safe mobile request to upload image.

let config = CLDConfiguration(cloudName: request.cloudName, apiKey: request.apiKey, apiSecret: nil)
let cloudinary = CLDCloudinary(configuration: config)
let signature = CLDSignature(signature: request.signature, timestamp: NSNumber(value: request.timestamp))))
let params = CLDUploadRequestParams()
params.setSignature(signature)
params.setParam("api_key", value: request.apiKey)
params.setPublicId(request.publicId)

cloudinary.createUploader().signedUpload(data: data, params: params, progress: nil) { (result, error) in
    print(error)
}

And getting error: Invalid Signature <my signature>. String to sign - 'public_id=<my public id>&timestamp=1

As I can see, there is a problem with timestamp parameter sending. Because I create CLDSignature object with correct timestamp and signature.

But in CLDNetworkDelegate on multipart request forming the timestamp parameter is being recognized as Bool. And it turns to 1 instead of 1485214919, for example.

chrisellsworth commented 7 years ago

Seconded. I was able to get around this by building the upload request manually (i.e. passing in a dictionary, like in the Objective-C SDK, and called upload instead of signedUpload) and converting the timestamp to a String. This seemed a bit hacky though, not to mention I had to set "" for the undocumented uploadPreset parameter :)

elijah-panfilow commented 7 years ago

I specified params as follows:

    let params = CLDUploadRequestParams()
    params.setParam("api_key", value: request.apiKey)
    params.setPublicId(request.publicId)
    params.setParam("timestamp", value: request.timestamp.description)

    cloudinary.createUploader().upload(data: data, uploadPreset: "", params: params, progress: nil) { (result, error) in }

But got another error: Upload preset must be specified when using unsigned upload

chrisellsworth commented 7 years ago

It doesn't look like you're passing the params to upload (should be the third parameter). I haven't seen that error though. Perhaps it's due to a setting on your Cloudinary account?

elijah-panfilow commented 7 years ago

Sorry, I abbreviated the code and made the mistake. Now it's corrected. I am passing params actually. Could you specify please what setting should I check?

chrisellsworth commented 7 years ago

This is my guess (under the Upload tab of Settings):

screen shot 2017-01-24 at 4 07 49 pm

Though it kind of sounds like Cloudinary is still not recognizing your upload as a "signed" upload. Did you set signature as a parameter?

chrisellsworth commented 7 years ago

I re-created what I used to have so I can better explain to you :) Essentially you want to create the CLDUploadRequestParams using exactly the params that your server sends, with the addition that timestamp is a String rather than Int.

var paramsFromServer: [String: AnyObject] = ... // from your server

if let timestamp = params["timestamp"] as? Int {
    paramsFromServer["timestamp"] = timestamp.description as AnyObject
}

let params = CLDUploadRequestParams(params: paramsFromServer)

let configuration = CLDConfiguration(cloudName: ...)
let cloudinary = CLDCloudinary(configuration: configuration)
cloudinary.createUploader().upload(data: data, uploadPreset: "", params: params, completionHandler: ...)
elijah-panfilow commented 7 years ago

The last one works for me. Thanks!

fordhurley commented 7 years ago

I couldn't get this working in any way except for the way shown by @chrisellsworth. This sounds like a bug in either the SDK or the README.

nadavofi commented 7 years ago

Thanks for pointing this out, our team is looking into this issue and will update accordingly. Note that for the meantime, the following should work for you (no need to modify the SDK):

    params.setParam("signature", value: signature)
    params.setParam("timestamp", value: NSNumber(value: timestamp).stringValue)
    params.setParam("api_key", value: apiKey)

We will update here when we have more insights regarding the reported issue.

Jiropole commented 7 years ago

Even this workaround is not working for me. It changed the error, but it's still rejecting my token (asterisks replacing valid numbers). No other code has been modified on backend in generating token, using cloudinary 1.7.0 for node.js.

Invalid Signature 42e0fce4202288aa7e2cbb81bae954b59eb35f**. String to sign - 'timestamp=14885705007**

It looks like this library is not getting much attention – better to drop back to v 1.x?

Jiropole commented 7 years ago

I personally dropped back to 1.x, due to budget constraints. Continues to work fine. Hopefully this library comes together for 2.x in the near future.

tapz commented 7 years ago

It amazed me how long it takes to make a new release, which fixes this. It didn't take me more than an hour to fix it in the pod source. And we are paying monthly to Cloudinary...

bohdanPaliychuk commented 7 years ago

Can't upload video, with signedUpload always get "Invalid Signature", with unsignedUpload "Invalid image file" even if set resource type to video. Is there any fixes ?

CaptainHunter commented 7 years ago

@ilia-dev @nadavofi is this error still not fixed on v2.0.1? I am still getting this error... @Jiropole Which version is working?? v1.?

Error: Error Domain=com.cloudinary.error Code=401 "(null)" UserInfo={message=Invalid Signature 6c59284428e5e4595510b2f9c5a4d1a92b6f31**. String to sign - 'timestamp=14942915**'.}

Jiropole commented 7 years ago

@CaptainHunter v1.0 is working fine still. I have a complete patch in my stashes to migrate to v2, as there were still persistent issues I last time I applied it.

CaptainHunter commented 7 years ago

@Jiropole I believe the initialisation's a little different on v1.0, how did you initiate yours?

screen shot 2017-05-09 at 5 35 43 pm
Jiropole commented 7 years ago

@CaptainHunter Here's what my initialization looks like:

    private let cloudinary: CLCloudinary!

    private static let cloudName = ???????
    private static let cloudinaryApiKey = ????????????????

    init() {
        cloudinary = CLCloudinary()

        cloudinary.config().setValue(ImageManager.cloudName, forKey: "cloud_name")
        cloudinary.config().setValue(true, forKey: "secure")
        cloudinary.config().setValue(ImageManager.cloudinaryApiKey, forKey: "api_key")
    }

However, I retrieve the signature dynamically from the server (using Cloudinary for node.js), then use the response dictionary parameters when I call e.g. upload:

            let uploader = CLUploader(self.cloudinary, delegate: nil)!
            uploader.upload(imageData, options: parameters, withCompletion: ...
CaptainHunter commented 7 years ago

@Jiropole I am still getting the same error. I am using v1.0.15, are you using this version?

Same, I am retrieving the signature dynamically from my server.

Error: Invalid Signature 4be7ceeb855e4d0d269445873828e68f492a7XXX. String to sign - 'timestamp=1494654XXX'

Response: 401

screen shot 2017-05-13 at 1 53 04 pm
Jiropole commented 7 years ago

Yes, I'm using 1.0.15. Here is how I'm generating the signature on the server:

    let parameters = {
        timestamp: Date.now(),
        public_id: ????
    };

    const signature = Cloudinary.v2.utils.api_sign_request(parameters, secret);

I add the signature as a property of parameters before sending it to the client, where it is used verbatim as the parameters argument to upload(). I see you're assembling your arguments dictionary on the client side, so maybe you're not using the same timestamp?

taragano commented 7 years ago

This issue should be resolved by the latest release, v2.0.2). Please let us know if it works for you now?

fordhurley commented 7 years ago

We upgraded to v2.0.2 and switched to building the request params using CLDSignature and setSignature. We no longer saw an error when trying to upload! Unfortunately, it seems like the upload was silently failing, because downloads would result in 404.

shirlymanor commented 7 years ago

@fordhurley Can you please share the URL's that experiencing the 404 errors? In case of security matter, you're more than welcomed to open a ticket and we'll be happy to assist you.

fordhurley commented 7 years ago

The workaround is perfectly acceptable for us at the moment, and I don't have the time right now to set up the test case again that failed. I noticed that the unit test only checks the error, not the uploaded file, so I can't help but suspect that it's providing some false confidence about the feature. Of course, we could very well have been doing something wrong from our end.

shirlymanor commented 7 years ago

Thanks for the update, glad to hear that the workaround is working. Please let us know if you have any question.

shirlymanor commented 6 years ago

Closing this issue due to the time elapsed. Please feel free to either re-open the issue, contact our support at http://support.cloudinary.com or create a new ticket if you have any additional issues.