40 lines
1.2 KiB
Go
40 lines
1.2 KiB
Go
package api
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"regexp"
|
|
|
|
"github.com/cli/cli/v2/internal/asciisanitizer"
|
|
"golang.org/x/text/transform"
|
|
)
|
|
|
|
var jsonTypeRE = regexp.MustCompile(`[/+]json($|;)`)
|
|
|
|
// GitHub servers do not sanitize their API output for terminal display
|
|
// and leave in unescaped ASCII control characters.
|
|
// These control characters will be interpreted by the terminal, this behaviour can be
|
|
// used maliciously as an attack vector, especially the control characters \u001B and \u009B.
|
|
// This function wraps JSON response bodies in a ReadCloser that transforms C0 and C1
|
|
// control characters to their caret notations respectively so that the terminal will not
|
|
// interpret them.
|
|
func AddASCIISanitizer(rt http.RoundTripper) http.RoundTripper {
|
|
return &funcTripper{roundTrip: func(req *http.Request) (*http.Response, error) {
|
|
res, err := rt.RoundTrip(req)
|
|
if err != nil || !jsonTypeRE.MatchString(res.Header.Get("Content-Type")) {
|
|
return res, err
|
|
}
|
|
res.Body = sanitizedReadCloser(res.Body)
|
|
return res, err
|
|
}}
|
|
}
|
|
|
|
func sanitizedReadCloser(rc io.ReadCloser) io.ReadCloser {
|
|
return struct {
|
|
io.Reader
|
|
io.Closer
|
|
}{
|
|
Reader: transform.NewReader(rc, &asciisanitizer.Sanitizer{}),
|
|
Closer: rc,
|
|
}
|
|
}
|