Skip to content

fix: Update build_form function to sort signature params alphabetically#54

Open
J0Z14H wants to merge 1 commit intoLurk:mainfrom
J0Z14H:fix/timestamp-ordering
Open

fix: Update build_form function to sort signature params alphabetically#54
J0Z14H wants to merge 1 commit intoLurk:mainfrom
J0Z14H:fix/timestamp-ordering

Conversation

@J0Z14H
Copy link
Copy Markdown

@J0Z14H J0Z14H commented Apr 8, 2026

See: https://cloudinary.com/documentation/authentication_signatures

Fixes issue of invalid signatures when using OptionalParameters that alphabetically come after timestamp
(Example: Using OptionalParameters::UseAssetFolderAsPublicIdPrefix currently throws an InvalidSignature error)

See: https://cloudinary.com/documentation/authentication_signatures
Fixes issue of invalid signatures when using OptionalParameters that alphabetically come
after timestamp
Copilot AI review requested due to automatic review settings April 8, 2026 17:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Cloudinary upload signature generation by ensuring all signed parameters (including timestamp) are sorted alphabetically, preventing invalid signatures when optional parameter keys come after timestamp.

Changes:

  • Collects all signed key=value parts (excluding resource_type), adds timestamp, sorts them, and hashes the joined string plus api_secret.
  • Removes incremental hashing with interleaved & updates in favor of hashing a single canonical parameter string.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/upload/mod.rs
Comment on lines 123 to +142
fn build_form(&self, options: &BTreeSet<OptionalParameters>) -> Form {
let mut form = Form::new();
let mut hasher = Sha1::new();
let timestamp = Utc::now().timestamp_millis().to_string();
let mut parts: Vec<String> = Vec::new();

for option in options {
let (key, value) = option.get_pair();
if key != "resource_type" {
hasher.update(option.to_string());
hasher.update("&");
parts.push(option.to_string());
};

form = form.text(key, value);
}

hasher.update(format!("timestamp={}{}", timestamp, self.api_secret));
parts.push(format!("timestamp={}", timestamp));
parts.sort();

let params_string = format!("{}{}", parts.join("&"), self.api_secret);
hasher.update(&params_string);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature-ordering fix is critical for auth correctness, but there’s no deterministic test guarding the parameter sorting (e.g., a case where an option key alphabetically follows timestamp, like use_asset_folder_as_public_id_prefix). Consider extracting the signature param-string construction into a small helper that accepts a fixed timestamp (or injecting a clock) so you can add a unit test asserting the exact signed string / signature ordering without needing live Cloudinary credentials.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants