feat: sync public links and phone change updates
This commit is contained in:
parent
41c7f1d018
commit
da04c0fa6a
53 changed files with 3029 additions and 111 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package links
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
|
@ -19,13 +20,40 @@ func NormalizeBaseURL(raw string) string {
|
|||
return strings.TrimRight(raw, "/")
|
||||
}
|
||||
|
||||
func Build(baseURL, path string, query url.Values) string {
|
||||
baseURL = NormalizeBaseURL(baseURL)
|
||||
parsed, err := url.Parse(baseURL)
|
||||
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
||||
baseURL = DefaultPublicBaseURL
|
||||
parsed, _ = url.Parse(baseURL)
|
||||
// ValidateBaseURL normalizes and validates a client-visible HTTP(S) base URL.
|
||||
// A path prefix is allowed, but credentials, query parameters, and fragments
|
||||
// are not part of a stable public-link root.
|
||||
func ValidateBaseURL(raw string) (string, error) {
|
||||
normalized := NormalizeBaseURL(raw)
|
||||
parsed, err := url.Parse(normalized)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse URL: %w", err)
|
||||
}
|
||||
if parsed.Opaque != "" || (parsed.Scheme != "http" && parsed.Scheme != "https") {
|
||||
return "", fmt.Errorf("scheme must be http or https")
|
||||
}
|
||||
if parsed.Host == "" || parsed.Hostname() == "" {
|
||||
return "", fmt.Errorf("host is required")
|
||||
}
|
||||
if parsed.User != nil {
|
||||
return "", fmt.Errorf("credentials are not allowed")
|
||||
}
|
||||
if parsed.RawQuery != "" || parsed.ForceQuery {
|
||||
return "", fmt.Errorf("query parameters are not allowed")
|
||||
}
|
||||
if parsed.Fragment != "" {
|
||||
return "", fmt.Errorf("fragment is not allowed")
|
||||
}
|
||||
parsed.Path = strings.TrimRight(parsed.Path, "/")
|
||||
return strings.TrimRight(parsed.String(), "/"), nil
|
||||
}
|
||||
|
||||
func Build(baseURL, path string, query url.Values) string {
|
||||
baseURL, err := ValidateBaseURL(baseURL)
|
||||
if err != nil {
|
||||
baseURL = DefaultPublicBaseURL
|
||||
}
|
||||
parsed, _ := url.Parse(baseURL)
|
||||
basePath := strings.TrimRight(parsed.Path, "/")
|
||||
path = strings.TrimLeft(path, "/")
|
||||
if path != "" {
|
||||
|
|
@ -38,10 +66,11 @@ func Build(baseURL, path string, query url.Values) string {
|
|||
}
|
||||
|
||||
func Host(baseURL string) string {
|
||||
parsed, err := url.Parse(NormalizeBaseURL(baseURL))
|
||||
if err != nil || parsed.Host == "" {
|
||||
baseURL, err := ValidateBaseURL(baseURL)
|
||||
if err != nil {
|
||||
return "telesrv.net"
|
||||
}
|
||||
parsed, _ := url.Parse(baseURL)
|
||||
if host := parsed.Hostname(); host != "" {
|
||||
return host
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,41 @@ func TestNormalizeBaseURL(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateBaseURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "default", raw: "", want: "https://telesrv.net"},
|
||||
{name: "host and path", raw: "links.example.test/root/", want: "https://links.example.test/root"},
|
||||
{name: "local HTTP", raw: "http://127.0.0.1:2401/", want: "http://127.0.0.1:2401"},
|
||||
{name: "missing host", raw: "https://", wantErr: true},
|
||||
{name: "unsupported scheme", raw: "ftp://links.example.test", wantErr: true},
|
||||
{name: "credentials", raw: "https://user:pass@links.example.test", wantErr: true},
|
||||
{name: "query", raw: "https://links.example.test/root?tenant=one", wantErr: true},
|
||||
{name: "fragment", raw: "https://links.example.test/root#links", wantErr: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ValidateBaseURL(tt.raw)
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Fatalf("ValidateBaseURL(%q) succeeded with %q", tt.raw, got)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateBaseURL(%q): %v", tt.raw, err)
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Fatalf("ValidateBaseURL(%q) = %q, want %q", tt.raw, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPreservesBasePathAndQuery(t *testing.T) {
|
||||
got := Build("http://127.0.0.1:2401/root/", "/call/abc", url.Values{"slug": []string{"abc"}})
|
||||
if want := "http://127.0.0.1:2401/root/call/abc?slug=abc"; got != want {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue