| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9d3aff0 commit 6c4cd6a
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -652,42 +652,60 @@ def expand_path(p: Union[None, PathLike], expand_vars: bool = True) -> Optional[ | |||
| 652 | 652 | return None | |
| 653 | 653 | ||
| 654 | 654 | ||
| 655 | + def _redact_url_credentials(text: str) -> Optional[str]: | ||
| 656 | + """Return `text` with the userinfo of a URL redacted, or ``None`` if it has none.""" | ||
| 657 | + try: | ||
| 658 | + url = urlsplit(text) | ||
| 659 | + except ValueError: | ||
| 660 | + # This is not a valid URL. | ||
| 661 | + return None | ||
| 662 | + if url.password is None and url.username is None: | ||
| 663 | + return None | ||
| 664 | + | ||
| 665 | + # Match urllib.parse's userinfo boundary. Keeping the raw hostinfo | ||
| 666 | + # preserves hostname case, IPv6 brackets, and port formatting. | ||
| 667 | + _, _, hostinfo = url.netloc.rpartition("@") | ||
| 668 | + redacted = "*****:*****" if url.password is not None else "*****" | ||
| 669 | + return urlunsplit(url._replace(netloc=f"{redacted}@{hostinfo}")) | ||
| 670 | + | ||
| 671 | + | ||
| 655 | 672 | def remove_password_if_present(cmdline: Sequence[str]) -> List[str]: | |
| 656 | 673 | """Redact credentials in URLs and HTTP Authorization extra headers in a command line. | |
| 657 | 674 | ||
| 675 | + URLs are also redacted when they are the value of a configuration assignment, such | ||
| 676 | + as ``http.proxy=<url>``, and assignments are recognized in both the ``-c <key>=<value>`` | ||
| 677 | + and the ``--config=<key>=<value>`` form. | ||
| 678 | + | ||
| 658 | 679 | If nothing is found, this just returns the command line as-is. | |
| 659 | 680 | ||
| 660 | 681 | This should be used for every log line that print a command line, as well as | |
| 661 | 682 | exception messages. | |
| 662 | 683 | """ | |
| 663 | 684 | new_cmdline = [] | |
| 664 | - for index, to_parse in enumerate(cmdline): | ||
| 665 | - new_cmdline.append(to_parse) | ||
| 666 | - config_key, separator, header = to_parse.partition("=") | ||
| 667 | - header_name, colon, _ = header.partition(":") | ||
| 685 | + for to_parse in cmdline: | ||
| 686 | + option = "--config=" if to_parse.startswith("--config=") else "" | ||
| 687 | + assignment = to_parse[len(option) :] | ||
| 688 | + config_key, separator, value = assignment.partition("=") | ||
| 689 | + header_name, colon, _ = value.partition(":") | ||
| 668 | 690 | if ( | |
| 669 | 691 | separator | |
| 670 | 692 | and colon | |
| 671 | 693 | and config_key.lower().endswith(".extraheader") | |
| 672 | 694 | and header_name.strip().lower() == "authorization" | |
| 673 | 695 | ): | |
| 674 | - new_cmdline[index] = "%s%s%s%s *****" % (config_key, separator, header_name, colon) | ||
| 675 | - continue | ||
| 676 | - try: | ||
| 677 | - url = urlsplit(to_parse) | ||
| 678 | - # Remove password from the URL if present. | ||
| 679 | - if url.password is None and url.username is None: | ||
| 680 | - continue | ||
| 681 | - | ||
| 682 | - # Match urllib.parse's userinfo boundary. Keeping the raw hostinfo | ||
| 683 | - # preserves hostname case, IPv6 brackets, and port formatting. | ||
| 684 | - _, _, hostinfo = url.netloc.rpartition("@") | ||
| 685 | - redacted = "*****:*****" if url.password is not None else "*****" | ||
| 686 | - url = url._replace(netloc=f"{redacted}@{hostinfo}") | ||
| 687 | - new_cmdline[index] = urlunsplit(url) | ||
| 688 | - except ValueError: | ||
| 689 | - # This is not a valid URL. | ||
| 696 | + new_cmdline.append("%s%s%s%s%s *****" % (option, config_key, separator, header_name, colon)) | ||
| 690 | 697 | continue | |
| 698 | + | ||
| 699 | + redacted = _redact_url_credentials(to_parse) | ||
| 700 | + if redacted is None and option: | ||
| 701 | + redacted = _redact_url_credentials(assignment) | ||
| 702 | + if redacted is not None: | ||
| 703 | + redacted = option + redacted | ||
| 704 | + if redacted is None and separator: | ||
| 705 | + redacted = _redact_url_credentials(value) | ||
| 706 | + if redacted is not None: | ||
| 707 | + redacted = option + config_key + separator + redacted | ||
| 708 | + new_cmdline.append(to_parse if redacted is None else redacted) | ||
| 691 | 709 | return new_cmdline | |
| 692 | 710 | ||
| 693 | 711 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -856,6 +856,33 @@ def test_remove_empty_password_keeps_host_intact(self): | |||
| 856 | 856 | def test_remove_password_preserves_url_components(self, url, expected): | |
| 857 | 857 | assert remove_password_if_present([url]) == [expected] | |
| 858 | 858 | ||
| 859 | + @ddt.data( | ||
| 860 | + ( | ||
| 861 | + ["-c", "http.proxy=http://user:pass@proxy.example.com:3128"], | ||
| 862 | + ["-c", "http.proxy=http://*****:*****@proxy.example.com:3128"], | ||
| 863 | + ), | ||
| 864 | + ( | ||
| 865 | + ["-c", "remote.origin.url=https://user:pass@example.com/repo"], | ||
| 866 | + ["-c", "remote.origin.url=https://*****:*****@example.com/repo"], | ||
| 867 | + ), | ||
| 868 | + ( | ||
| 869 | + ["--config=http.proxy=http://user:pass@proxy.example.com:3128"], | ||
| 870 | + ["--config=http.proxy=http://*****:*****@proxy.example.com:3128"], | ||
| 871 | + ), | ||
| 872 | + ( | ||
| 873 | + ["--config=url.https://user:pass@example.com/.insteadOf=https://example.com/"], | ||
| 874 | + ["--config=url.https://*****:*****@example.com/.insteadOf=https://example.com/"], | ||
| 875 | + ), | ||
| 876 | + ( | ||
| 877 | + ["--config=http.extraHeader=Authorization: Bearer pass"], | ||
| 878 | + ["--config=http.extraHeader=Authorization: *****"], | ||
| 879 | + ), | ||
| 880 | + (["-c", "user.name=pass"], ["-c", "user.name=pass"]), | ||
| 881 | + ) | ||
| 882 | + @ddt.unpack | ||
| 883 | + def test_remove_password_from_config_values(self, cmdline, expected): | ||
| 884 | + assert remove_password_if_present(cmdline) == expected | ||
| 885 | + | ||
| 859 | 886 | ||
| 860 | 887 | def test_mode_str_to_int_accepts_bytes(): | |
| 861 | 888 | assert mode_str_to_int("100644") == 0o100644 | |
| Back | FazBrowse Home | New Git URL |
0 commit comments