Add API Keys for fzf --listen (#3374)

This commit is contained in:
Boaz Yaniv
2023-07-20 23:42:09 +09:00
committed by GitHub
parent 3c09c77269
commit c0435fdff4
5 changed files with 83 additions and 9 deletions

View File

@@ -3,9 +3,11 @@ package fzf
import (
"bufio"
"bytes"
"crypto/subtle"
"errors"
"fmt"
"net"
"os"
"strconv"
"strings"
"time"
@@ -15,10 +17,16 @@ const (
crlf = "\r\n"
httpOk = "HTTP/1.1 200 OK" + crlf
httpBadRequest = "HTTP/1.1 400 Bad Request" + crlf
httpUnauthorized = "HTTP/1.1 401 Unauthorized" + crlf
httpReadTimeout = 10 * time.Second
maxContentLength = 1024 * 1024
)
type httpServer struct {
apiKey []byte
channel chan []*action
}
func startHttpServer(port int, channel chan []*action) (error, int) {
if port < 0 {
return nil, port
@@ -41,6 +49,11 @@ func startHttpServer(port int, channel chan []*action) (error, int) {
}
}
server := httpServer{
apiKey: []byte(os.Getenv("FZF_API_KEY")),
channel: channel,
}
go func() {
for {
conn, err := listener.Accept()
@@ -51,7 +64,7 @@ func startHttpServer(port int, channel chan []*action) (error, int) {
continue
}
}
conn.Write([]byte(handleHttpRequest(conn, channel)))
conn.Write([]byte(server.handleHttpRequest(conn)))
conn.Close()
}
listener.Close()
@@ -66,9 +79,14 @@ func startHttpServer(port int, channel chan []*action) (error, int) {
// * No --listen: 2.8MB
// * --listen with net/http: 5.7MB
// * --listen w/o net/http: 3.3MB
func handleHttpRequest(conn net.Conn, channel chan []*action) string {
func (server *httpServer) handleHttpRequest(conn net.Conn) string {
contentLength := 0
apiKey := ""
body := ""
unauthorized := func(message string) string {
message += "\n"
return httpUnauthorized + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message)
}
bad := func(message string) string {
message += "\n"
return httpBadRequest + fmt.Sprintf("Content-Length: %d%s", len(message), crlf+crlf+message)
@@ -105,18 +123,27 @@ func handleHttpRequest(conn net.Conn, channel chan []*action) string {
continue
}
pair := strings.SplitN(text, ":", 2)
if len(pair) == 2 && strings.ToLower(pair[0]) == "content-length" {
length, err := strconv.Atoi(strings.TrimSpace(pair[1]))
if err != nil || length <= 0 || length > maxContentLength {
return bad("invalid content length")
if len(pair) == 2 {
switch strings.ToLower(pair[0]) {
case "content-length":
length, err := strconv.Atoi(strings.TrimSpace(pair[1]))
if err != nil || length <= 0 || length > maxContentLength {
return bad("invalid content length")
}
contentLength = length
case "x-api-key":
apiKey = strings.TrimSpace(pair[1])
}
contentLength = length
}
case 2:
body += text
}
}
if len(server.apiKey) != 0 && subtle.ConstantTimeCompare([]byte(apiKey), server.apiKey) != 1 {
return unauthorized("invalid api key")
}
if len(body) < contentLength {
return bad("incomplete request")
}
@@ -133,6 +160,6 @@ func handleHttpRequest(conn net.Conn, channel chan []*action) string {
return bad("no action specified")
}
channel <- actions
server.channel <- actions
return httpOk
}