Always keep an in-memory history of all commands in redis-cli (#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.
This commit is contained in:
Binbin 2023-12-15 23:22:02 +08:00 committed by GitHub
parent d8a21c5767
commit adbb534f03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 12 deletions

View File

@ -108,7 +108,7 @@ to search and re-edit already inserted lines of text.
The followings are the history API calls: 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 linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename); int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename); int linenoiseHistoryLoad(const char *filename);

View File

@ -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_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int history_len = 0; static int history_len = 0;
static char **history = NULL; 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. /* The linenoiseState structure represents the state during line editing.
* We pass this state to functions implementing specific editing * We pass this state to functions implementing specific editing
@ -177,7 +179,7 @@ enum KEY_ACTION{
}; };
static void linenoiseAtExit(void); static void linenoiseAtExit(void);
int linenoiseHistoryAdd(const char *line); int linenoiseHistoryAdd(const char *line, int is_sensitive);
static void refreshLine(struct linenoiseState *l); static void refreshLine(struct linenoiseState *l);
/* Debugging macro. */ /* Debugging macro. */
@ -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 /* The latest history entry is always our current buffer, that
* initially is just an empty string. */ * initially is just an empty string. */
linenoiseHistoryAdd(""); linenoiseHistoryAdd("", 0);
if (write(l.ofd,prompt,l.plen) == -1) return -1; if (write(l.ofd,prompt,l.plen) == -1) return -1;
while(1) { while(1) {
@ -1112,6 +1114,7 @@ static void freeHistory(void) {
for (j = 0; j < history_len; j++) for (j = 0; j < history_len; j++)
free(history[j]); free(history[j]);
free(history); free(history);
free(history_sensitive);
} }
} }
@ -1128,7 +1131,7 @@ static void linenoiseAtExit(void) {
* histories, but will work well for a few hundred of entries. * histories, but will work well for a few hundred of entries.
* *
* Using a circular buffer is smarter, but a bit more complex to handle. */ * 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; char *linecopy;
if (history_max_len == 0) return 0; if (history_max_len == 0) return 0;
@ -1137,7 +1140,14 @@ int linenoiseHistoryAdd(const char *line) {
if (history == NULL) { if (history == NULL) {
history = malloc(sizeof(char*)*history_max_len); history = malloc(sizeof(char*)*history_max_len);
if (history == NULL) return 0; 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,0,(sizeof(char*)*history_max_len));
memset(history_sensitive,0,(sizeof(int)*history_max_len));
} }
/* Don't add duplicated lines. */ /* Don't add duplicated lines. */
@ -1150,9 +1160,11 @@ int linenoiseHistoryAdd(const char *line) {
if (history_len == history_max_len) { if (history_len == history_max_len) {
free(history[0]); free(history[0]);
memmove(history,history+1,sizeof(char*)*(history_max_len-1)); 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_len--;
} }
history[history_len] = linecopy; history[history_len] = linecopy;
history_sensitive[history_len] = is_sensitive;
history_len++; history_len++;
return 1; return 1;
} }
@ -1163,6 +1175,7 @@ int linenoiseHistoryAdd(const char *line) {
* than the amount of items already inside the history. */ * than the amount of items already inside the history. */
int linenoiseHistorySetMaxLen(int len) { int linenoiseHistorySetMaxLen(int len) {
char **new; char **new;
int *new_sensitive;
if (len < 1) return 0; if (len < 1) return 0;
if (history) { if (history) {
@ -1170,6 +1183,11 @@ int linenoiseHistorySetMaxLen(int len) {
new = malloc(sizeof(char*)*len); new = malloc(sizeof(char*)*len);
if (new == NULL) return 0; 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 we can't copy everything, free the elements we'll not use. */
if (len < tocopy) { if (len < tocopy) {
@ -1179,9 +1197,13 @@ int linenoiseHistorySetMaxLen(int len) {
tocopy = len; tocopy = len;
} }
memset(new,0,sizeof(char*)*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,history+(history_len-tocopy), sizeof(char*)*tocopy);
memcpy(new_sensitive,history_sensitive+(history_len-tocopy), sizeof(int)*tocopy);
free(history); free(history);
free(history_sensitive);
history = new; history = new;
history_sensitive = new_sensitive;
} }
history_max_len = len; history_max_len = len;
if (history_len > history_max_len) if (history_len > history_max_len)
@ -1201,7 +1223,7 @@ int linenoiseHistorySave(const char *filename) {
if (fp == NULL) return -1; if (fp == NULL) return -1;
fchmod(fileno(fp),S_IRUSR|S_IWUSR); fchmod(fileno(fp),S_IRUSR|S_IWUSR);
for (j = 0; j < history_len; j++) 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); fclose(fp);
return 0; return 0;
} }
@ -1223,7 +1245,7 @@ int linenoiseHistoryLoad(const char *filename) {
p = strchr(buf,'\r'); p = strchr(buf,'\r');
if (!p) p = strchr(buf,'\n'); if (!p) p = strchr(buf,'\n');
if (p) *p = '\0'; if (p) *p = '\0';
linenoiseHistoryAdd(buf); linenoiseHistoryAdd(buf, 0);
} }
fclose(fp); fclose(fp);
return 0; return 0;

View File

@ -58,7 +58,7 @@ void linenoiseAddCompletion(linenoiseCompletions *, const char *);
char *linenoise(const char *prompt); char *linenoise(const char *prompt);
void linenoiseFree(void *ptr); void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line); int linenoiseHistoryAdd(const char *line, int is_sensitive);
int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename); int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename); int linenoiseHistoryLoad(const char *filename);

View File

@ -3394,7 +3394,7 @@ static void repl(void) {
if (argv == NULL) { if (argv == NULL) {
printf("Invalid argument(s)\n"); printf("Invalid argument(s)\n");
fflush(stdout); fflush(stdout);
if (history) linenoiseHistoryAdd(line); if (history) linenoiseHistoryAdd(line, 0);
if (historyfile) linenoiseHistorySave(historyfile); if (historyfile) linenoiseHistorySave(historyfile);
linenoiseFree(line); linenoiseFree(line);
continue; continue;
@ -3420,10 +3420,11 @@ static void repl(void) {
repeat = 1; repeat = 1;
} }
if (!isSensitiveCommand(argc - skipargs, argv + skipargs)) { /* Always keep in-memory history. But for commands with sensitive information,
if (history) linenoiseHistoryAdd(line); * avoid writing them to the history file. */
if (historyfile) linenoiseHistorySave(historyfile); 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 || if (strcasecmp(argv[0],"quit") == 0 ||
strcasecmp(argv[0],"exit") == 0) strcasecmp(argv[0],"exit") == 0)