sideband.allowControlCharacters::
By default, control characters that are delivered via the sideband
- are masked, to prevent potentially unwanted ANSI escape sequences
- from being sent to the terminal. Use this config setting to override
- this behavior.
+ are masked, except ANSI color sequences. This prevents potentially
+ unwanted ANSI escape sequences from being sent to the terminal. Use
+ this config setting to override this behavior:
++
+--
+ default::
+ color::
+ Allow ANSI color sequences, line feeds and horizontal tabs,
+ but mask all other control characters. This is the default.
+ false::
+ Mask all control characters other than line feeds and
+ horizontal tabs.
+ true::
+ Allow all control characters to be sent to the terminal.
+--
{ "error", GIT_COLOR_BOLD_RED },
};
-static int allow_control_characters;
+static enum {
+ ALLOW_NO_CONTROL_CHARACTERS = 0,
+ ALLOW_ANSI_COLOR_SEQUENCES = 1<<0,
+ ALLOW_DEFAULT_ANSI_SEQUENCES = ALLOW_ANSI_COLOR_SEQUENCES,
+ ALLOW_ALL_CONTROL_CHARACTERS = 1<<1,
+} allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
static int use_sideband_colors(void)
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
- git_config_get_bool("sideband.allowcontrolcharacters",
- &allow_control_characters);
+ switch (git_config_get_maybe_bool("sideband.allowcontrolcharacters", &i)) {
+ case 0: /* Boolean value */
+ allow_control_characters = i ? ALLOW_ALL_CONTROL_CHARACTERS :
+ ALLOW_NO_CONTROL_CHARACTERS;
+ break;
+ case -1: /* non-Boolean value */
+ if (git_config_get_string_tmp("sideband.allowcontrolcharacters",
+ &value))
+ ; /* huh? `get_maybe_bool()` returned -1 */
+ else if (!strcmp(value, "default"))
+ allow_control_characters = ALLOW_DEFAULT_ANSI_SEQUENCES;
+ else if (!strcmp(value, "color"))
+ allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
+ else
+ warning(_("unrecognized value for `sideband."
+ "allowControlCharacters`: '%s'"), value);
+ break;
+ default:
+ break; /* not configured */
+ }
if (!git_config_get_string_tmp(key, &value))
use_sideband_colors_cached = git_config_colorbool(key, value);
list_config_item(list, prefix, keywords[i].keyword);
}
+static int handle_ansi_color_sequence(struct strbuf *dest, const char *src, int n)
+{
+ int i;
+
+ /*
+ * Valid ANSI color sequences are of the form
+ *
+ * ESC [ [<n> [; <n>]*] m
+ *
+ * These are part of the Select Graphic Rendition sequences which
+ * contain more than just color sequences, for more details see
+ * https://en.wikipedia.org/wiki/ANSI_escape_code#SGR.
+ */
+
+ if (allow_control_characters != ALLOW_ANSI_COLOR_SEQUENCES ||
+ n < 3 || src[0] != '\x1b' || src[1] != '[')
+ return 0;
+
+ for (i = 2; i < n; i++) {
+ if (src[i] == 'm') {
+ strbuf_add(dest, src, i + 1);
+ return i;
+ }
+ if (!isdigit(src[i]) && src[i] != ';')
+ break;
+ }
+
+ return 0;
+}
+
static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
{
- if (allow_control_characters) {
+ int i;
+
+ if (allow_control_characters == ALLOW_ALL_CONTROL_CHARACTERS) {
strbuf_add(dest, src, n);
return;
}
for (; n && *src; src++, n--) {
if (!iscntrl(*src) || *src == '\t' || *src == '\n')
strbuf_addch(dest, *src);
- else {
+ else if ((i = handle_ansi_color_sequence(dest, src, n))) {
+ src += i;
+ n -= i;
+ } else {
strbuf_addch(dest, '^');
strbuf_addch(dest, *src == 0x7f ? '?' : 0x40 + *src);
}
test_expect_success 'disallow (color) control sequences in sideband' '
write_script .git/color-me-surprised <<-\EOF &&
- printf "error: Have you \\033[31mread\\033[m this?\\n" >&2
+ printf "error: Have you \\033[31mread\\033[m this?\\a\\n" >&2
exec "$@"
EOF
test_config_global uploadPack.packObjectsHook ./color-me-surprised &&
git clone --no-local . throw-away 2>stderr &&
test_decode_color <stderr >decoded &&
+ test_grep RED decoded &&
+ test_grep "\\^G" stderr &&
+ tr -dc "\\007" <stderr >actual &&
+ test_must_be_empty actual &&
+
+ rm -rf throw-away &&
+ git -c sideband.allowControlCharacters=false \
+ clone --no-local . throw-away 2>stderr &&
+ test_decode_color <stderr >decoded &&
test_grep ! RED decoded &&
+ test_grep "\\^G" stderr &&
rm -rf throw-away &&
git -c sideband.allowControlCharacters clone --no-local . throw-away 2>stderr &&
test_decode_color <stderr >decoded &&
- test_grep RED decoded
+ test_grep RED decoded &&
+ tr -dc "\\007" <stderr >actual &&
+ test_file_not_empty actual
'
test_done