pinning + new version of backups
This commit is contained in:
@@ -8,8 +8,6 @@ import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -29,6 +27,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
agentRuntime "overlord-client/cmd/agent/runtime"
|
||||
agentTLS "overlord-client/cmd/agent/tlsconfig"
|
||||
"overlord-client/cmd/agent/wire"
|
||||
)
|
||||
|
||||
@@ -769,17 +768,13 @@ func HandleFileUploadHTTP(ctx context.Context, env *agentRuntime.Env, cmdID stri
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: "unsupported upload url scheme"})
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{InsecureSkipVerify: env.Cfg.TLSInsecureSkipVerify, MinVersion: tls.VersionTLS12}
|
||||
if caPath := strings.TrimSpace(env.Cfg.TLSCAPath); caPath != "" {
|
||||
caBytes, err := os.ReadFile(caPath)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: fmt.Sprintf("failed to read TLS CA: %v", err)})
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
if !pool.AppendCertsFromPEM(caBytes) {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: "failed to parse TLS CA"})
|
||||
}
|
||||
tlsConfig.RootCAs = pool
|
||||
tlsConfig, err := agentTLS.Build(agentTLS.Options{
|
||||
InsecureSkipVerify: env.Cfg.TLSInsecureSkipVerify,
|
||||
CAPath: env.Cfg.TLSCAPath,
|
||||
SPKIPins: env.Cfg.TLSSPKIPins,
|
||||
})
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: fmt.Sprintf("invalid TLS configuration: %v", err)})
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
@@ -986,6 +981,9 @@ func resolveUploadPullURL(env *agentRuntime.Env, raw string) (string, error) {
|
||||
if scheme != "http" && scheme != "https" {
|
||||
return "", fmt.Errorf("unsupported upload url scheme: %s", parsed.Scheme)
|
||||
}
|
||||
if scheme == "http" && !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext file transfers are disabled; use https")
|
||||
}
|
||||
if !strings.HasPrefix(parsed.Path, "/api/file/upload/pull/") {
|
||||
return parsed.String(), nil
|
||||
}
|
||||
@@ -1010,8 +1008,15 @@ func resolveUploadPullURL(env *agentRuntime.Env, raw string) (string, error) {
|
||||
case "wss":
|
||||
server.Scheme = "https"
|
||||
case "ws":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext file transfers are disabled; use wss")
|
||||
}
|
||||
server.Scheme = "http"
|
||||
case "https", "http":
|
||||
case "https":
|
||||
case "http":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext file transfers are disabled; use https")
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported agent server scheme: %s", server.Scheme)
|
||||
}
|
||||
|
||||
@@ -545,7 +545,8 @@ func TestHandleFileUploadHTTP_RewritesUploadPullURLToAgentServer(t *testing.T) {
|
||||
env := &rt.Env{
|
||||
Conn: writer,
|
||||
Cfg: config.Config{
|
||||
ServerURLs: []string{strings.Replace(ts.URL, "http://", "ws://", 1)},
|
||||
ServerURLs: []string{strings.Replace(ts.URL, "http://", "ws://", 1)},
|
||||
TLSInsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -2,19 +2,17 @@ package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"overlord-client/cmd/agent/plugins"
|
||||
agentRuntime "overlord-client/cmd/agent/runtime"
|
||||
agentTLS "overlord-client/cmd/agent/tlsconfig"
|
||||
"overlord-client/cmd/agent/wire"
|
||||
)
|
||||
|
||||
@@ -31,17 +29,13 @@ func HandlePluginLoadHTTP(ctx context.Context, env *agentRuntime.Env, cmdID stri
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: err.Error()})
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{InsecureSkipVerify: env.Cfg.TLSInsecureSkipVerify, MinVersion: tls.VersionTLS12}
|
||||
if caPath := strings.TrimSpace(env.Cfg.TLSCAPath); caPath != "" {
|
||||
caBytes, err := os.ReadFile(caPath)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: fmt.Sprintf("failed to read TLS CA: %v", err)})
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
if !pool.AppendCertsFromPEM(caBytes) {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: "failed to parse TLS CA"})
|
||||
}
|
||||
tlsConfig.RootCAs = pool
|
||||
tlsConfig, err := agentTLS.Build(agentTLS.Options{
|
||||
InsecureSkipVerify: env.Cfg.TLSInsecureSkipVerify,
|
||||
CAPath: env.Cfg.TLSCAPath,
|
||||
SPKIPins: env.Cfg.TLSSPKIPins,
|
||||
})
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: false, Message: fmt.Sprintf("invalid TLS configuration: %v", err)})
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
|
||||
@@ -114,6 +108,9 @@ func resolvePluginPullURL(env *agentRuntime.Env, raw string) (string, error) {
|
||||
if scheme != "http" && scheme != "https" {
|
||||
return "", fmt.Errorf("unsupported plugin pull scheme: %s", parsed.Scheme)
|
||||
}
|
||||
if scheme == "http" && !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext plugin downloads are disabled; use https")
|
||||
}
|
||||
return parsed.String(), nil
|
||||
}
|
||||
|
||||
@@ -132,8 +129,15 @@ func resolvePluginPullURL(env *agentRuntime.Env, raw string) (string, error) {
|
||||
case "wss":
|
||||
server.Scheme = "https"
|
||||
case "ws":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext plugin downloads are disabled; use wss")
|
||||
}
|
||||
server.Scheme = "http"
|
||||
case "https", "http":
|
||||
case "https":
|
||||
case "http":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", errors.New("plaintext plugin downloads are disabled; use https")
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported agent server scheme: %s", server.Scheme)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"overlord-client/cmd/agent/config"
|
||||
agentRuntime "overlord-client/cmd/agent/runtime"
|
||||
)
|
||||
|
||||
func TestSensitiveTransfersRejectPlaintextByDefault(t *testing.T) {
|
||||
env := &agentRuntime.Env{Cfg: config.Config{
|
||||
ServerURLs: []string{"ws://server.example.test:5173"},
|
||||
}}
|
||||
|
||||
if _, err := resolveUploadPullURL(env, "/api/file/upload/pull/id"); err == nil ||
|
||||
!strings.Contains(err.Error(), "plaintext") {
|
||||
t.Fatalf("expected plaintext file transfer rejection, got %v", err)
|
||||
}
|
||||
if _, err := resolvePluginPullURL(env, "/api/plugins/pull/id"); err == nil ||
|
||||
!strings.Contains(err.Error(), "plaintext") {
|
||||
t.Fatalf("expected plaintext plugin transfer rejection, got %v", err)
|
||||
}
|
||||
if _, err := buildWhipURL(env, "/api/webrtc/whip"); err == nil ||
|
||||
!strings.Contains(err.Error(), "plaintext") {
|
||||
t.Fatalf("expected plaintext WebRTC signaling rejection, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSensitiveTransfersAllowExplicitDevelopmentOptOut(t *testing.T) {
|
||||
env := &agentRuntime.Env{Cfg: config.Config{
|
||||
ServerURLs: []string{"ws://127.0.0.1:5173"},
|
||||
TLSInsecureSkipVerify: true,
|
||||
}}
|
||||
|
||||
if resolved, err := resolveUploadPullURL(env, "/api/file/upload/pull/id"); err != nil ||
|
||||
!strings.HasPrefix(resolved, "http://") {
|
||||
t.Fatalf("expected explicit plaintext file transfer, got %q, %v", resolved, err)
|
||||
}
|
||||
if resolved, err := resolvePluginPullURL(env, "/api/plugins/pull/id"); err != nil ||
|
||||
!strings.HasPrefix(resolved, "http://") {
|
||||
t.Fatalf("expected explicit plaintext plugin transfer, got %q, %v", resolved, err)
|
||||
}
|
||||
if resolved, err := buildWhipURL(env, "/api/webrtc/whip"); err != nil ||
|
||||
!strings.HasPrefix(resolved, "http://") {
|
||||
t.Fatalf("expected explicit plaintext signaling, got %q, %v", resolved, err)
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@ func handleWebrtcPublish(ctx context.Context, env *runtime.Env, cmdID string, pa
|
||||
PublishToken: token,
|
||||
TLSInsecureSkipVerify: env.Cfg.TLSInsecureSkipVerify,
|
||||
TLSCAPath: env.Cfg.TLSCAPath,
|
||||
TLSSPKIPins: env.Cfg.TLSSPKIPins,
|
||||
ICEServers: parseICEServers(payload["iceServers"]),
|
||||
HasVideo: hasVideo,
|
||||
HasAudio: hasAudio,
|
||||
@@ -309,7 +310,17 @@ func buildWhipURL(env *runtime.Env, whipPath string) (string, error) {
|
||||
case "wss":
|
||||
base.Scheme = "https"
|
||||
case "ws":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", fmt.Errorf("plaintext WebRTC signaling is disabled; use wss")
|
||||
}
|
||||
base.Scheme = "http"
|
||||
case "http":
|
||||
if !env.Cfg.TLSInsecureSkipVerify {
|
||||
return "", fmt.Errorf("plaintext WebRTC signaling is disabled; use https")
|
||||
}
|
||||
case "https":
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported WebRTC signaling scheme: %s", base.Scheme)
|
||||
}
|
||||
if !strings.HasPrefix(whipPath, "/") {
|
||||
whipPath = "/" + whipPath
|
||||
|
||||
Reference in New Issue
Block a user