Skip to content

Commit

Permalink
Always keep an in-memory history of all commands in redis-cli (redis#…
Browse files Browse the repository at this point in the history
…12862)

redis-cli avoids saving sensitive commands in it's history (doesn't
persist them to the history file).
this means that if you had a typo and you wanna re-run the command, you
can't easily do that.
This PR changes that to keep an in-memory history of all the redacted
commands, and just
not persist them to disk. This way we would be able to press the up
arrow and
re-try the command freely, and it'll just not survive a redis-cli
restart.
  • Loading branch information
enjoy-binbin authored Dec 15, 2023
1 parent d8a21c5 commit adbb534
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 12 deletions.
2 changes: 1 addition & 1 deletion deps/linenoise/README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ to search and re-edit already inserted lines of text.

The followings are the history API calls:

int linenoiseHistoryAdd(const char *line);
int linenoiseHistoryAdd(const char *line, int is_sensitive);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
Expand Down
32 changes: 27 additions & 5 deletions deps/linenoise/linenoise.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ static int atexit_registered = 0; /* Register atexit just 1 time. */
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int history_len = 0;
static char **history = NULL;
static int *history_sensitive = NULL; /* An array records whether each line in
* history is sensitive. */

/* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing
Expand Down Expand Up @@ -177,7 +179,7 @@ enum KEY_ACTION{
};

static void linenoiseAtExit(void);
int linenoiseHistoryAdd(const char *line);
int linenoiseHistoryAdd(const char *line, int is_sensitive);
static void refreshLine(struct linenoiseState *l);

/* Debugging macro. */
Expand Down Expand Up @@ -818,7 +820,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,

/* The latest history entry is always our current buffer, that
* initially is just an empty string. */
linenoiseHistoryAdd("");
linenoiseHistoryAdd("", 0);

if (write(l.ofd,prompt,l.plen) == -1) return -1;
while(1) {
Expand Down Expand Up @@ -1112,6 +1114,7 @@ static void freeHistory(void) {
for (j = 0; j < history_len; j++)
free(history[j]);
free(history);
free(history_sensitive);
}
}

Expand All @@ -1128,7 +1131,7 @@ static void linenoiseAtExit(void) {
* histories, but will work well for a few hundred of entries.
*
* Using a circular buffer is smarter, but a bit more complex to handle. */
int linenoiseHistoryAdd(const char *line) {
int linenoiseHistoryAdd(const char *line, int is_sensitive) {
char *linecopy;

if (history_max_len == 0) return 0;
Expand All @@ -1137,7 +1140,14 @@ int linenoiseHistoryAdd(const char *line) {
if (history == NULL) {
history = malloc(sizeof(char*)*history_max_len);
if (history == NULL) return 0;
history_sensitive = malloc(sizeof(int)*history_max_len);
if (history_sensitive == NULL) {
free(history);
history = NULL;
return 0;
}
memset(history,0,(sizeof(char*)*history_max_len));
memset(history_sensitive,0,(sizeof(int)*history_max_len));
}

/* Don't add duplicated lines. */
Expand All @@ -1150,9 +1160,11 @@ int linenoiseHistoryAdd(const char *line) {
if (history_len == history_max_len) {
free(history[0]);
memmove(history,history+1,sizeof(char*)*(history_max_len-1));
memmove(history_sensitive,history_sensitive+1,sizeof(int)*(history_max_len-1));
history_len--;
}
history[history_len] = linecopy;
history_sensitive[history_len] = is_sensitive;
history_len++;
return 1;
}
Expand All @@ -1163,13 +1175,19 @@ int linenoiseHistoryAdd(const char *line) {
* than the amount of items already inside the history. */
int linenoiseHistorySetMaxLen(int len) {
char **new;
int *new_sensitive;

if (len < 1) return 0;
if (history) {
int tocopy = history_len;

new = malloc(sizeof(char*)*len);
if (new == NULL) return 0;
new_sensitive = malloc(sizeof(int)*len);
if (new_sensitive == NULL) {
free(new);
return 0;
}

/* If we can't copy everything, free the elements we'll not use. */
if (len < tocopy) {
Expand All @@ -1179,9 +1197,13 @@ int linenoiseHistorySetMaxLen(int len) {
tocopy = len;
}
memset(new,0,sizeof(char*)*len);
memset(new_sensitive,0,sizeof(int)*len);
memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
memcpy(new_sensitive,history_sensitive+(history_len-tocopy), sizeof(int)*tocopy);
free(history);
free(history_sensitive);
history = new;
history_sensitive = new_sensitive;
}
history_max_len = len;
if (history_len > history_max_len)
Expand All @@ -1201,7 +1223,7 @@ int linenoiseHistorySave(const char *filename) {
if (fp == NULL) return -1;
fchmod(fileno(fp),S_IRUSR|S_IWUSR);
for (j = 0; j < history_len; j++)
fprintf(fp,"%s\n",history[j]);
if (!history_sensitive[j]) fprintf(fp,"%s\n",history[j]);
fclose(fp);
return 0;
}
Expand All @@ -1223,7 +1245,7 @@ int linenoiseHistoryLoad(const char *filename) {
p = strchr(buf,'\r');
if (!p) p = strchr(buf,'\n');
if (p) *p = '\0';
linenoiseHistoryAdd(buf);
linenoiseHistoryAdd(buf, 0);
}
fclose(fp);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion deps/linenoise/linenoise.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void linenoiseAddCompletion(linenoiseCompletions *, const char *);

char *linenoise(const char *prompt);
void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line);
int linenoiseHistoryAdd(const char *line, int is_sensitive);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
Expand Down
11 changes: 6 additions & 5 deletions src/redis-cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -3394,7 +3394,7 @@ static void repl(void) {
if (argv == NULL) {
printf("Invalid argument(s)\n");
fflush(stdout);
if (history) linenoiseHistoryAdd(line);
if (history) linenoiseHistoryAdd(line, 0);
if (historyfile) linenoiseHistorySave(historyfile);
linenoiseFree(line);
continue;
Expand All @@ -3420,10 +3420,11 @@ static void repl(void) {
repeat = 1;
}

if (!isSensitiveCommand(argc - skipargs, argv + skipargs)) {
if (history) linenoiseHistoryAdd(line);
if (historyfile) linenoiseHistorySave(historyfile);
}
/* Always keep in-memory history. But for commands with sensitive information,
* avoid writing them to the history file. */
int is_sensitive = isSensitiveCommand(argc - skipargs, argv + skipargs);
if (history) linenoiseHistoryAdd(line, is_sensitive);
if (!is_sensitive && historyfile) linenoiseHistorySave(historyfile);

if (strcasecmp(argv[0],"quit") == 0 ||
strcasecmp(argv[0],"exit") == 0)
Expand Down

0 comments on commit adbb534

Please sign in to comment.