feat: Implement S2A, Rod, and Chromedp based authentication for external services, and introduce new frontend pages and backend APIs for monitoring, configuration, upload, and team processes.
This commit is contained in:
107
backend/internal/proxyutil/proxy.go
Normal file
107
backend/internal/proxyutil/proxy.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package proxyutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Info is a parsed proxy configuration.
|
||||
//
|
||||
// It supports the following input formats:
|
||||
// - http://host:port
|
||||
// - http://user:pass@host:port
|
||||
// - host:port (defaults to http)
|
||||
// - host:port:user:pass (defaults to http; password may contain ':')
|
||||
// - user:pass@host:port (defaults to http)
|
||||
type Info struct {
|
||||
// URL is the normalized proxy URL (may include credentials).
|
||||
URL *url.URL
|
||||
// Server is the proxy server URL without credentials (scheme + host:port).
|
||||
Server *url.URL
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
func Parse(raw string) (*Info, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return &Info{}, nil
|
||||
}
|
||||
|
||||
// URL-style proxy (has scheme)
|
||||
if strings.Contains(raw, "://") {
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse proxy url: %w", err)
|
||||
}
|
||||
if u.Scheme == "" || u.Host == "" {
|
||||
return nil, fmt.Errorf("invalid proxy url: %q", raw)
|
||||
}
|
||||
|
||||
u = &url.URL{
|
||||
Scheme: strings.ToLower(u.Scheme),
|
||||
Host: u.Host,
|
||||
User: u.User,
|
||||
}
|
||||
|
||||
user := ""
|
||||
pass := ""
|
||||
if u.User != nil {
|
||||
user = u.User.Username()
|
||||
pass, _ = u.User.Password()
|
||||
}
|
||||
|
||||
server := &url.URL{Scheme: u.Scheme, Host: u.Host}
|
||||
return &Info{
|
||||
URL: u,
|
||||
Server: server,
|
||||
Username: user,
|
||||
Password: pass,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// user:pass@host:port (no scheme)
|
||||
if strings.Contains(raw, "@") {
|
||||
return Parse("http://" + raw)
|
||||
}
|
||||
|
||||
// host:port[:user:pass]
|
||||
parts := strings.Split(raw, ":")
|
||||
switch {
|
||||
case len(parts) == 2:
|
||||
host, port := parts[0], parts[1]
|
||||
hp := net.JoinHostPort(host, port)
|
||||
u := &url.URL{Scheme: "http", Host: hp}
|
||||
return &Info{URL: u, Server: &url.URL{Scheme: u.Scheme, Host: u.Host}}, nil
|
||||
case len(parts) >= 4:
|
||||
host, port := parts[0], parts[1]
|
||||
user := parts[2]
|
||||
pass := strings.Join(parts[3:], ":")
|
||||
hp := net.JoinHostPort(host, port)
|
||||
u := &url.URL{Scheme: "http", Host: hp, User: url.UserPassword(user, pass)}
|
||||
return &Info{
|
||||
URL: u,
|
||||
Server: &url.URL{Scheme: u.Scheme, Host: u.Host},
|
||||
Username: user,
|
||||
Password: pass,
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported proxy format: %q", raw)
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize returns a normalized proxy URL string.
|
||||
// Empty input returns empty output.
|
||||
func Normalize(raw string) (string, error) {
|
||||
info, err := Parse(raw)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if info.URL == nil {
|
||||
return "", nil
|
||||
}
|
||||
return info.URL.String(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user