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:
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);

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_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
@ -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. */
@ -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) {
@ -1112,6 +1114,7 @@ static void freeHistory(void) {
for (j = 0; j < history_len; j++)
free(history[j]);
free(history);
free(history_sensitive);
}
}
@ -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;
@ -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. */
@ -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;
}
@ -1163,6 +1175,7 @@ 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) {
@ -1170,6 +1183,11 @@ int linenoiseHistorySetMaxLen(int 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) {
@ -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)
@ -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;
}
@ -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;

View File

@ -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);

View File

@ -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;
@ -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)