stringToSign function

String stringToSign(
  1. Map<String, dynamic> params, {
  2. int version = 2,
})

Builds the canonical string Cloudinary signs.

Parameters sort by key, null and empty values drop out, and iterables join with commas. Signature version 2 and above escapes & within each pair, which is what stops a parameter value from smuggling additional parameters into the signed string.

Implementation

String stringToSign(Map<String, dynamic> params, {int version = 2}) {
  final pairs = <MapEntry<String, String>>[];
  for (final entry in params.entries) {
    final value = entry.value;
    if (value == null) continue;
    final rendered = value is Iterable ? value.join(',') : '$value';
    if (rendered.isEmpty) continue;
    pairs.add(MapEntry(entry.key, rendered));
  }

  // Sort by key, as Cloudinary's Node and Ruby SDKs do. Python sorts the
  // joined "key=value" strings; the orders diverge only where one key prefixes
  // another before a character below '=', which no Cloudinary parameter is.
  pairs.sort((a, b) => a.key.compareTo(b.key));

  return pairs
      .map((p) {
        final pair = '${p.key}=${p.value}';
        return version >= 2 ? pair.replaceAll('&', '%26') : pair;
      })
      .join('&');
}