7
7
using System . Diagnostics ;
8
8
using System . IO ;
9
9
using System . Linq ;
10
+ using System . Management . Automation ;
10
11
using System . Text ;
12
+ using System . Text . RegularExpressions ;
11
13
using System . Threading ;
12
14
using Microsoft . PowerShell . PSReadLine ;
13
15
@@ -51,6 +53,7 @@ public class HistoryItem
51
53
public bool FromHistoryFile { get ; internal set ; }
52
54
53
55
internal bool _saved ;
56
+ internal bool _sensitive ;
54
57
internal List < EditItem > _edits ;
55
58
internal int _undoEditIndex ;
56
59
}
@@ -76,29 +79,60 @@ public class HistoryItem
76
79
private const string _failedForwardISearchPrompt = "failed-fwd-i-search: " ;
77
80
private const string _failedBackwardISearchPrompt = "failed-bck-i-search: " ;
78
81
79
- private string MaybeAddToHistory (
80
- string result ,
81
- List < EditItem > edits ,
82
- int undoEditIndex ,
83
- bool fromDifferentSession = false ,
84
- bool fromInitialRead = false )
82
+ // Pattern used to check for sensitive inputs.
83
+ private static readonly Regex s_sensitivePattern = new Regex (
84
+ "password|asplaintext|token|key|secret" ,
85
+ RegexOptions . Compiled | RegexOptions . IgnoreCase ) ;
86
+
87
+ private AddToHistoryOption GetAddToHistoryOption ( string line )
85
88
{
86
- bool AddToHistory ( string line )
89
+ // Whitespace only is useless, never add.
90
+ if ( string . IsNullOrWhiteSpace ( line ) )
91
+ {
92
+ return AddToHistoryOption . SkipAdding ;
93
+ }
94
+
95
+ // Under "no dupes" (which is on by default), immediately drop dupes of the previous line.
96
+ if ( Options . HistoryNoDuplicates && _history . Count > 0 &&
97
+ string . Equals ( _history [ _history . Count - 1 ] . CommandLine , line , StringComparison . Ordinal ) )
87
98
{
88
- // Whitespace only is useless, never add.
89
- if ( string . IsNullOrWhiteSpace ( line ) ) return false ;
99
+ return AddToHistoryOption . SkipAdding ;
100
+ }
90
101
91
- // If the user says don't add it, then don't.
92
- if ( Options . AddToHistoryHandler != null && ! Options . AddToHistoryHandler ( result ) ) return false ;
102
+ if ( Options . AddToHistoryHandler != null )
103
+ {
104
+ if ( Options . AddToHistoryHandler == PSConsoleReadLineOptions . DefaultAddToHistoryHandler )
105
+ {
106
+ // Avoid boxing if it's the default handler.
107
+ return GetDefaultAddToHistoryOption ( line ) ;
108
+ }
93
109
94
- // Under "no dupes" (which is on by default), immediately drop dupes of the previous line.
95
- if ( Options . HistoryNoDuplicates && _history . Count > 0 )
96
- return ! string . Equals ( _history [ _history . Count - 1 ] . CommandLine , result , StringComparison . Ordinal ) ;
110
+ object value = Options . AddToHistoryHandler ( line ) ;
97
111
98
- return true ;
112
+ if ( LanguagePrimitives . TryConvertTo ( value , out AddToHistoryOption enumValue ) )
113
+ {
114
+ return enumValue ;
115
+ }
116
+
117
+ if ( value is bool boolValue && ! boolValue )
118
+ {
119
+ return AddToHistoryOption . SkipAdding ;
120
+ }
99
121
}
100
122
101
- if ( AddToHistory ( result ) )
123
+ // Add to both history queue and file by default.
124
+ return AddToHistoryOption . MemoryAndFile ;
125
+ }
126
+
127
+ private string MaybeAddToHistory (
128
+ string result ,
129
+ List < EditItem > edits ,
130
+ int undoEditIndex ,
131
+ bool fromDifferentSession = false ,
132
+ bool fromInitialRead = false )
133
+ {
134
+ var addToHistoryOption = GetAddToHistoryOption ( result ) ;
135
+ if ( addToHistoryOption != AddToHistoryOption . SkipAdding )
102
136
{
103
137
var fromHistoryFile = fromDifferentSession || fromInitialRead ;
104
138
_previousHistoryItem = new HistoryItem
@@ -110,14 +144,16 @@ bool AddToHistory(string line)
110
144
FromOtherSession = fromDifferentSession ,
111
145
FromHistoryFile = fromInitialRead ,
112
146
} ;
147
+
113
148
if ( ! fromHistoryFile )
114
149
{
150
+ // 'MemoryOnly' indicates sensitive content in the command line
151
+ _previousHistoryItem . _sensitive = addToHistoryOption == AddToHistoryOption . MemoryOnly ;
115
152
_previousHistoryItem . StartTime = DateTime . UtcNow ;
116
153
}
117
154
118
155
_history . Enqueue ( _previousHistoryItem ) ;
119
156
120
-
121
157
_currentHistoryIndex = _history . Count ;
122
158
123
159
if ( _options . HistorySaveStyle == HistorySaveStyle . SaveIncrementally && ! fromHistoryFile )
@@ -169,7 +205,6 @@ private void SaveHistoryAtExit()
169
205
WriteHistoryRange ( 0 , _history . Count - 1 , File . CreateText ) ;
170
206
}
171
207
172
-
173
208
private int historyErrorReportedCount ;
174
209
private void ReportHistoryFileError ( Exception e )
175
210
{
@@ -241,8 +276,13 @@ private void WriteHistoryRange(int start, int end, Func<string, StreamWriter> fi
241
276
{
242
277
for ( var i = start ; i <= end ; i ++ )
243
278
{
244
- _history [ i ] . _saved = true ;
245
- var line = _history [ i ] . CommandLine . Replace ( "\n " , "`\n " ) ;
279
+ HistoryItem item = _history [ i ] ;
280
+ item . _saved = true ;
281
+
282
+ // Actually, skip writing sensitive items to file.
283
+ if ( item . _sensitive ) { continue ; }
284
+
285
+ var line = item . CommandLine . Replace ( "\n " , "`\n " ) ;
246
286
file . WriteLine ( line ) ;
247
287
}
248
288
}
@@ -335,6 +375,13 @@ void UpdateHistoryFromFile(IEnumerable<string> historyLines, bool fromDifferentS
335
375
}
336
376
}
337
377
378
+ public static AddToHistoryOption GetDefaultAddToHistoryOption ( string line )
379
+ {
380
+ return s_sensitivePattern . IsMatch ( line )
381
+ ? AddToHistoryOption . MemoryOnly
382
+ : AddToHistoryOption . MemoryAndFile ;
383
+ }
384
+
338
385
/// <summary>
339
386
/// Add a command to the history - typically used to restore
340
387
/// history from a previous session.
0 commit comments