Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly print arbitrary strings as valid JSON. #1362

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

emanuele6
Copy link
Contributor

@emanuele6 emanuele6 commented Feb 15, 2022

..instead of injecting them in the output between a pair of '"' charcters.

This prevents windows with a " character in their class or instance name (e.g. urxvt -name 'quote "'), or desktop and monitors with " character in their name from generating invalid or "malicious" JSON.

The main problems that this was causing were:

  • JSON tools like jq were not able to parse the JSON output of "query -T" and "wm -d";

  • if the JSON was invalid (e.g. one extra quote or \ at the end of desktop name), bspwm would not adopt orphans after a "wm -r" command.

  • if the arbitrary strings contained JSON code: e.g.

    bspc desktop -n '","name":"hello'

    the JSON will be interpreted by bspwm after a reload. (in the example above, that desktop will be renamed to "hello" after a reload.)

@emanuele6
Copy link
Contributor Author

emanuele6 commented Feb 15, 2022

This patch simply prints all the (C locale) control characters as \u00XX and adds a backslash in front of \ and " characters, some of the control characters (but not all) have special sequences in JSON: e.g. \n, \t, etc.

JSON string syntax diagram from json.org

json-string-white

We could print these special sequences when possible if we want, but it is not necessary. (passing the JSON through jq will convert them automatically.)

Here is a possible implementation if we want to do it:

#define SPECIAL_SEQUENCE(f, c, json) \
	case c: \
		fputs(json, f); \
		continue;
void print_string_as_json(FILE *f, char *str)
{
	fputc('"', f);
	for (char *ptr = str; *ptr != '\0'; ++ptr) {
		switch (*ptr) {
			SPECIAL_SEQUENCE(f, '"', "\\\"")
			SPECIAL_SEQUENCE(f, '\\', "\\\\")
			SPECIAL_SEQUENCE(f, '\b', "\\b")
			SPECIAL_SEQUENCE(f, '\f', "\\f")
			SPECIAL_SEQUENCE(f, '\n', "\\n")
			SPECIAL_SEQUENCE(f, '\r', "\\r")
			SPECIAL_SEQUENCE(f, '\t', "\\t")
		}
		if (*ptr == '\x7f' || (*ptr >= '\x01' && *ptr <= '\x1f')) {
			fprintf(f, "\\u%04x", *ptr);
			continue;
		}
		fputc(*ptr, f);
	}
	fputc('"', f);
}
#undef SPECIAL_SEQUENCE

..instead of injecting them in the output between a pair of `"`
charcters.

This prevents windows with a `"` character in their class or instance
name, or desktop and monitors with `"` character in their name from
generating invalid or "malicious" JSON.

The main problems that this was causing were:
* JSON tools like jq were not able to parse the JSON output of
  "query -T" and "wm -d";
* if the JSON was invalid (e.g. one extra quote or `\` at the end of
  desktop name), bspwm would not adopt orphans after a "wm -r" command;
* if the arbitrary strings contained JSON code: e.g.

    bspc desktop -n '","name":"hello'

  the JSON will be interpreted by bspwm after a reload. (in the example
  above, that desktop will be renamed to "hello" after a reload.)
@emanuele6
Copy link
Contributor Author

emanuele6 commented Mar 1, 2022

I just realised that bspwm is loading back the json strings by copying the bytes between the starting and ending quotes. that should also be changed otherwise these backslash sequences will not be expanded and restarts will cause bspwm to e.g. rename desktops from desktop "1" to desktop \"1\" to desktop \\\"1\\\" to desktop \\\\\\\"1\\\\\\\" and so on

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.

1 participant