json_canonicalizer 1.1.0
json_canonicalizer: ^1.1.0 copied to clipboard
A dependency-free RFC 8785 JSON Canonicalization Scheme implementation for Dart.
json_canonicalizer #
A dependency-free RFC 8785 JSON Canonicalization Scheme implementation for Dart.
Install #
dart pub add json_canonicalizer
Usage #
Both accept an already-parsed JSON value.
canonicalize(value)returns canonical JSON as aString.canonicalizeUtf8(value)returns the same JSON as UTF-8 bytes for hashing or signing.
Both also take allowInvalidUnicode. Pass true to escape a lone UTF-16
surrogate as \uXXXX instead of throwing. RFC 8785 requires rejecting a lone
surrogate, but Dart strings can contain one from truncated or malformed input.
Examples #
import 'package:json_canonicalizer/json_canonicalizer.dart';
// Sorts object keys by UTF-16 order and removes extra spaces.
canonicalize({'b': 1, '\u{e000}': 'private use', 'π³': 'flushed', 'a': 2});
// {"a":2,"b":1,"π³":"flushed","ξ":"private use"}
// Formats numbers the same way as JavaScript JSON.
canonicalize(<Object?>[-0.0, 333333333.33333329, 1e30, 0.000001]);
// [0,333333333.3333333,1e+30,0.000001]
// Returns UTF-8 bytes for hashing or signing.
canonicalizeUtf8({'currency': 'β¬'});
// [123, 34, 99, 117, 114, 114, 101, 110, 99, 121, 34, 58, 34, 226, 130, 172, 34, 125]
// A lone surrogate throws by default.
canonicalize('a\ud800b');
// Throws JsonCanonicalizationException.
// allowInvalidUnicode escapes it instead.
canonicalize('a\ud800b', allowInvalidUnicode: true);
// "a\ud800b"
Boundaries #
Pass in a JSON value that has already been parsed. It can contain null,
booleans, finite numbers, valid Unicode strings, lists, and maps with string
keys. This package only canonicalizes the value; it does not parse, normalize,
hash, sign, or call toJson.
| Case | Result |
|---|---|
| Arrays | Preserve their original order. |
| Object keys | Sort by UTF-16 code units. |
| Strings | Escape control characters, quotes, and backslashes. Keep other Unicode unchanged. |
-0.0 |
Writes 0. |
NaN, infinity, lossy int, non-string key, cycle |
Throw JsonCanonicalizationException. |
| Lone surrogate | Throws, unless you pass allowInvalidUnicode. |
| Nested lists and maps | Work up to 100,000 levels deep. |
Errors point to the invalid value with an RFC 6901 path:
try {
canonicalize({
'payload': [
{'a/b~c': double.nan},
],
});
} on JsonCanonicalizationException catch (error) {
print(error.path);
// /payload/0/a~1b~0c
}
The test suite
covers RFC 8785 examples,
Appendix B number vectors, the upstream JCS corpus, Unicode, escaping, invalid
input, cycles, shared subtrees, allowInvalidUnicode, and 100,000-level lists
and maps.
License #
Unlicense. Upstream test vectors in test/ are Apache-2.0.