Skip to content

Commit 4a69ea3

Browse files
committedApr 26, 2021
doc, fix tests, and improve errors for '-d DELIM' change in #150
1 parent 4114e32 commit 4a69ea3

File tree

10 files changed

+112
-18
lines changed

10 files changed

+112
-18
lines changed
 

‎CHANGES.md

+45-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,51 @@
22

33
## not yet released
44

5-
(nothing yet)
5+
- **Backward incompatible** and **security-related** change to parsing the
6+
`-d DELIM` option. ([#148](https://github.com/trentm/json/issues/148))
7+
8+
The `-d DELIM` option allows specifying the field delimiter in output:
9+
10+
% echo '{"name":"trent","age":38}' | json -a name age
11+
trent 38
12+
% echo '{"name":"trent","age":38}' | json -a name age -d,
13+
trent,38
14+
15+
The given "DELIM" string is parsed to allow escapes. For example:
16+
17+
% echo '{"name":"trent","age":38}' | json -a name age -d'\t'
18+
trent 38
19+
% echo '{"name":"trent","age":38}' | json -a name age -d'\n'
20+
trent
21+
38
22+
23+
Before this change, that parsing used `eval()`, which allowed for unintended
24+
code execution if an untrusted argument to `-d` was provided. The fix for
25+
this vulnerability changes to use `JSON.parse()` to support escapes. However
26+
that results in a backward incompatible change, because the set
27+
[JSON escapes](https://tools.ietf.org/html/rfc7159#section-7) is a subset of
28+
[JavaScript escapes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#escape_notation).
29+
30+
The only escape I expect that would affect any current user would be the
31+
null byte escape (`\0`) which can be useful for processing values that may
32+
have spaces or other likely delimiter characters. For example:
33+
34+
# BEFORE
35+
% echo '{"title":"Monsters, Inc.","year":"2001"}' \
36+
| json -a title year -d'\0' \
37+
| xargs -0 node -e 'console.log(process.argv)'
38+
[ 'node', 'Monsters, Inc.', '2001\n' ]
39+
40+
# AFTER
41+
% echo '{"title":"Monsters, Inc.","year":"2001"}' | json -a title year -d'\0'
42+
json: error: Unexpected number in JSON at position 2
43+
44+
One must now use the JSON unicode escape syntax, '\u0000':
45+
46+
% echo '{"title":"Monsters, Inc.","year":"2001"}' \
47+
| json -a title year -d'\u0000' \
48+
| xargs -0 node -e 'console.log(process.argv)'
49+
[ 'node', 'Monsters, Inc.', '2001\n' ]
650

751

852
## 10.0.0

‎README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ Features:
3030
- natural syntax (like JS code) for extracting particular values
3131
- get details on JSON syntax errors (handy for config files)
3232
- filter input JSON (see `-e` and `-c` options)
33-
- fast stream processing
33+
- fast stream processing (see `-ga`)
3434
- JSON validation
3535
- in-place file editing
3636

37-
See <http://trentm.com/json> for full docs and examples as a man page.
37+
See <https://trentm.com/json> for full docs and examples as a man page.
3838

3939
Follow <a href="https://twitter.com/intent/user?screen_name=trentmick" target="_blank">@trentmick</a>
4040
for updates to json.

‎docs/json.1.html

+5-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs/json.1.ronn

+4-3
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,9 @@ output:
499499
Process input as an array of separate inputs and output in tabular form.
500500

501501
* `-d DELIM`:
502-
Delimiter character for tabular output (default is ' ').
502+
Delimiter character for tabular output (default is ' '). This supports
503+
[JSON escapes](https://tools.ietf.org/html/rfc7159#section-7), e.g.:
504+
'\t' for tab or '\u0000' for the null byte.
503505

504506
* `-A`:
505507
Process input as a single object, i.e. stop `-e` and `-c` automatically
@@ -786,5 +788,4 @@ MIT License (see <https://github.com/trentm/json/blob/master/LICENSE.txt>)
786788

787789
## COPYRIGHT
788790

789-
json is Copyright (c) 2014 Trent Mick and Copyright (c) 2014 Joyent Inc.
790-
All rights reserved.
791+
json is Copyright 2021 Trent Mick and Copyright 2020 Joyent Inc.

‎lib/json.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
/**
3-
* Copyright 2020 Trent Mick.
3+
* Copyright 2021 Trent Mick.
44
* Copyright 2020 Joyent Inc.
55
*
66
* json -- JSON love for your command line.
@@ -122,10 +122,12 @@ if (util.format) {
122122

123123
/**
124124
* Parse the given string into a JS string. Basically: handle escapes.
125+
* Note that this only handles JSON escapes, which are a subset of all
126+
* JavaScript-supported string escapes.
125127
*/
126128
function _parseString(s) {
127129
/* JSSTYLED */
128-
var quoted = '"' + s.replace(/\\"/, '"').replace('"', '\\"') + '"';
130+
var quoted = '"' + s.replace(/\\"/g, '"').replace(/"/g, '\\"') + '"';
129131
return JSON.parse(quoted);
130132
}
131133

@@ -409,7 +411,13 @@ function parseArgv(argv) {
409411
parsed.array = false;
410412
break;
411413
case '-d':
412-
parsed.delim = _parseString(args.shift());
414+
var outputDelim = args.shift()
415+
try {
416+
parsed.delim = _parseString(outputDelim);
417+
} catch (parseErr) {
418+
throw new Error(format('could not parse delim "%s": %s',
419+
outputDelim, parseErr));
420+
}
413421
break;
414422
case '-D':
415423
parsed.lookupDelim = args.shift();

‎man/man1/json.1

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.\" generated with Ronn/v0.7.3
22
.\" http://github.com/rtomayko/ronn/tree/0.7.3
33
.
4-
.TH "JSON" "1" "August 2014" "" "json tool manual"
4+
.TH "JSON" "1" "April 2021" "" "json tool manual"
55
.
66
.SH "NAME"
77
\fBjson\fR \- JSON love for your command line
@@ -766,7 +766,7 @@ Process input as an array of separate inputs and output in tabular form\.
766766
.
767767
.TP
768768
\fB\-d DELIM\fR
769-
Delimiter character for tabular output (default is \' \')\.
769+
Delimiter character for tabular output (default is \' \')\. This supports JSON escapes \fIhttps://tools\.ietf\.org/html/rfc7159#section\-7\fR, e\.g\.: \'\et\' for tab or \'\eu0000\' for the null byte\.
770770
.
771771
.TP
772772
\fB\-A\fR
@@ -1148,4 +1148,4 @@ This project lives at \fIhttps://github\.com/trentm/json\fR\. Please report bugs
11481148
MIT License (see \fIhttps://github\.com/trentm/json/blob/master/LICENSE\.txt\fR)
11491149
.
11501150
.SH "COPYRIGHT"
1151-
json is Copyright (c) 2014 Trent Mick and Copyright (c) 2014 Joyent Inc\. All rights reserved\.
1151+
json is Copyright 2021 Trent Mick and Copyright 2020 Joyent Inc\.

‎test/array-processing/cmd

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ echo '{"name":"Trent","id":12,"email":"trent@example.com"}' | $JSON -a name emai
1818
echo ""
1919
echo '[{"name":"Trent","id":12,"email":"trent@example.com"},
2020
{"name":"Mark","id":13,"email":"mark@example.com"}]' \
21-
| $JSON -d, -a name email # TODO: how to spec '\0' as delim (a la -print0)?
21+
| $JSON -d, -a name email
2222

2323
# Delims (issue #26)
2424
echo ''
@@ -29,7 +29,7 @@ echo '[{"name":"trent","age":38},{"name":"ewan", "age":4}]' | $JSON -a name age
2929
echo '# newline'
3030
echo '[{"name":"trent","age":38},{"name":"ewan", "age":4}]' | $JSON -a name age -d '\n'
3131
echo '# nul to xargs'
32-
echo '[{"name":"trent","age":38},{"name":"ewan", "age":4}]' | $JSON -a name age -d '\0' | xargs -0 && echo 'end-of-xargs-output'
32+
echo '[{"name":"trent","age":38},{"name":"ewan", "age":4}]' | $JSON -a name age -d '\u0000' | xargs -0 && echo 'end-of-xargs-output'
3333

3434
echo ""
3535
echo '[{"foo": "bar"}, {"foo": "baz"}]' | $JSON -a

‎test/output-delim/cmd

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
JSON=../../lib/json.js
2+
3+
echo "# simple -d DELIM"
4+
echo '{"name":"trent", "age":38}' | $JSON -a name age
5+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d' '
6+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d,
7+
8+
echo "# -d DELIM with escapes"
9+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d'\t'
10+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d'\n'
11+
echo '{"title":"Monsters, Inc.","year":"2001"}' \
12+
| json -a title year -d'\u0000' \
13+
| xargs -0 && echo "eof"
14+
15+
echo "# -d DELIM edge cases"
16+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d'"'
17+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d'""' # had a bug in this at one point
18+
19+
echo "# unsupported JavaScript-only escapes in -d DELIM" >&2
20+
echo '{"title":"Monsters, Inc.","year":"2001"}' \
21+
| $JSON -a title year -d'\0' \
22+
| xargs -0 node -e 'console.log(process.argv)'
23+
echo '{"name":"trent", "age":38}' | $JSON -a name age -d'\x2c'

‎test/output-delim/expected.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# unsupported JavaScript-only escapes in -d DELIM
2+
json: error: could not parse delim "\0": SyntaxError: Unexpected number in JSON at position 2
3+
json: error: could not parse delim "\x2c": SyntaxError: Unexpected token x in JSON at position 2

‎test/output-delim/expected.stdout

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# simple -d DELIM
2+
trent 38
3+
trent 38
4+
trent,38
5+
# -d DELIM with escapes
6+
trent 38
7+
trent
8+
38
9+
Monsters, Inc. 2001
10+
11+
eof
12+
# -d DELIM edge cases
13+
trent"38
14+
trent""38

0 commit comments

Comments
 (0)
Please sign in to comment.