| 150 | 150 | | .replace(QUERY, `$1${REDACTED}`) |
| 151 | 151 | | .replace(FLAG, keep) |
| 152 | 152 | | .replace(/((?:^|\s)(?:-u|--user)\s+[^\s:]+:)\S+/g, `$1${REDACTED}`) |
| 153 | | − | .replace(ASSIGNED, (whole, head, value) => (TYPES.has(value) ? whole : keep(whole, head, value))); |
| 153 | + | .replace(ASSIGNED, (whole, head, value) => (TYPES.has(value) || prose(head, value) ? whole : keep(whole, head, value))); |
| 154 | + | } |
| 155 | + | |
| 156 | + | /** |
| 157 | + | * `secret: the` in a sentence: after a colon, an unquoted plain word short |
| 158 | + | * of a password's length is the sentence going on, not a value. |
| 159 | + | * `password: hunter2!` and a long run still count; after `=` everything does. |
| 160 | + | */ |
| 161 | + | function prose(head, value) { |
| 162 | + | return head.trimEnd().endsWith(":") && !/^["'`]/.test(value) && [...value].length < 16 && /^[\p{L}'’-]+$/u.test(value); |
| 154 | 163 | | } |
| 155 | 164 | | |
| 156 | 165 | | /** Text a person or an agent wrote, as it is sent: credentials out, cut to `limit`. */ |