vcs_info.zsh 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. # Don't skip this file until a Zsh release does the necessary quoting.
  2. # This is because even though 5.8.1 undid recursive prompt_subst inside
  3. # prompt sequences, % characters in relevant fields will still be rendered
  4. # incorrectly in vcs_info, on all Zsh releases up to writing this.
  5. #
  6. # There is no release yet that does this right, since it requires changing
  7. # how what vcs_info hooks expect to receive. Even so, I'd rather be correct
  8. # and break custom vcs_info hooks than have a broken prompt.
  9. # Quote necessary $hook_com[<field>] items just before they are used
  10. # in the line "VCS_INFO_hook 'post-backend'" of the VCS_INFO_formats
  11. # function, where <field> is:
  12. #
  13. # base: the full path of the repository's root directory.
  14. # base-name: the name of the repository's root directory.
  15. # branch: the name of the currently checked out branch.
  16. # misc: a string that may contain anything the vcs_info backend wants.
  17. # revision: an identifier of the currently checked out revision.
  18. # subdir: the path of the current directory relative to the
  19. # repository's root directory.
  20. #
  21. # This patch %-quotes these fields previous to their use in vcs_info hooks and
  22. # the zformat call and, eventually, when they get expanded in the prompt.
  23. # It's important to quote these here, and not later after hooks have modified the
  24. # fields, because then we could be quoting % characters from valid prompt sequences,
  25. # like %F{color}, %B, etc.
  26. #
  27. # 32 │ hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})"
  28. # 33 │ hook_com[subdir_orig]="${hook_com[subdir]}"
  29. # 34 │
  30. # 35 + │ for tmp in base base-name branch misc revision subdir; do
  31. # 36 + │ hook_com[$tmp]="${hook_com[$tmp]//\%/%%}"
  32. # 37 + │ done
  33. # 38 + │
  34. # 39 │ VCS_INFO_hook 'post-backend'
  35. #
  36. # This is especially important so that no command substitution is performed
  37. # due to malicious input as a consequence of CVE-2021-45444, which affects
  38. # zsh versions from 5.0.3 to 5.8.
  39. #
  40. autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return 0
  41. # We use $tmp here because it's already a local variable in VCS_INFO_formats
  42. typeset PATCH='for tmp (base base-name branch misc revision subdir) hook_com[$tmp]="${hook_com[$tmp]//\%/%%}"'
  43. # Unique string to avoid reapplying the patch if this code gets called twice
  44. typeset PATCH_ID=vcs_info-patch-9b9840f2-91e5-4471-af84-9e9a0dc68c1b
  45. # Only patch the VCS_INFO_formats function if not already patched
  46. if [[ "$functions[VCS_INFO_formats]" != *$PATCH_ID* ]]; then
  47. regexp-replace 'functions[VCS_INFO_formats]' \
  48. "VCS_INFO_hook 'post-backend'" \
  49. ': ${PATCH_ID}; ${PATCH}; ${MATCH}'
  50. fi
  51. unset PATCH PATCH_ID