feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

+90 -6
View File
@@ -6,6 +6,7 @@ import (
"net"
"net/http"
"net/url"
"slices"
"strings"
"time"
@@ -16,27 +17,45 @@ import (
webauthn "github.com/go-webauthn/webauthn/webauthn"
)
var ErrRPIDUnavailable = system_setting.ErrPasskeyRPIDUnavailable
// BuildWebAuthn constructs a WebAuthn instance using the current passkey settings and request context.
func BuildWebAuthn(r *http.Request) (*webauthn.WebAuthn, error) {
settings := system_setting.GetPasskeySettings()
if settings == nil {
return nil, errors.New("未找到 Passkey 设置")
}
return BuildWebAuthnForRPID(r, "")
}
// BuildWebAuthnForRPID uses a single configured RP ID, never a list of IDs to
// try against the same signed response. An empty ID is for new registrations.
func BuildWebAuthnForRPID(r *http.Request, selectedRPID string) (*webauthn.WebAuthn, error) {
settings := system_setting.PasskeySettingsSnapshot()
displayName := strings.TrimSpace(settings.RPDisplayName)
if displayName == "" {
displayName = common.SystemName
}
origins, err := resolveOrigins(r, settings)
origins, err := resolveOrigins(r, &settings)
if err != nil {
return nil, err
}
rpID, err := resolveRPID(r, settings, origins)
rpID, err := resolveRPID(r, &settings, origins)
if err != nil {
return nil, err
}
if selectedRPID != "" && selectedRPID != rpID {
if !slices.Contains(settings.RelyingPartyIDs(), selectedRPID) {
return nil, ErrRPIDUnavailable
}
rpID = selectedRPID
}
origins = originsForRPID(origins, rpID)
if len(origins) == 0 {
return nil, ErrRPIDUnavailable
}
if origin := r.Header.Get("Origin"); origin != "" && !protocol.IsOriginInHaystack(origin, origins) {
return nil, ErrRPIDUnavailable
}
selection := protocol.AuthenticatorSelection{
ResidentKey: protocol.ResidentKeyRequirementRequired,
@@ -73,6 +92,71 @@ func BuildWebAuthn(r *http.Request) (*webauthn.WebAuthn, error) {
return webauthn.New(config)
}
// BuildLoginWebAuthn gives a known credential's binding precedence over a
// browser's last-successful-domain hint. All choices remain server controlled.
func BuildLoginWebAuthn(r *http.Request, hint, credentialRPID string) (*webauthn.WebAuthn, []string, error) {
settings := system_setting.PasskeySettingsSnapshot()
origins, err := resolveOrigins(r, &settings)
if err != nil {
return nil, nil, err
}
primary, err := resolveRPID(r, &settings, origins)
if err != nil {
return nil, nil, err
}
configured := append([]string{primary}, settings.RelyingPartyIDs()...)
available := []string{}
for _, id := range configured {
if credentialRPID != "" && id != credentialRPID {
continue
}
allowedOrigins := originsForRPID(origins, id)
if len(allowedOrigins) == 0 || (r.Header.Get("Origin") != "" && !protocol.IsOriginInHaystack(r.Header.Get("Origin"), allowedOrigins)) {
continue
}
if !slices.Contains(available, id) {
available = append(available, id)
}
}
if len(available) == 0 {
return nil, nil, ErrRPIDUnavailable
}
selected := credentialRPID
if selected == "" {
selected = hint
}
if selected == "" {
selected = available[0]
}
if !slices.Contains(available, selected) {
return nil, nil, ErrRPIDUnavailable
}
wa, err := BuildWebAuthnForRPID(r, selected)
return wa, available, err
}
func originsForRPID(origins []string, rpID string) []string {
allowed := []string{}
for _, origin := range origins {
parsed, err := url.Parse(origin)
if err != nil || (parsed.Scheme != "https" && parsed.Scheme != "http") || parsed.User != nil {
continue
}
host := strings.ToLower(parsed.Hostname())
domain := strings.ToLower(rpID)
if !strings.Contains(domain, ".") && domain != "localhost" {
if host == domain && parsed.Scheme == "https" {
allowed = append(allowed, origin)
}
continue
}
if host == domain || strings.HasSuffix(host, "."+domain) {
allowed = append(allowed, origin)
}
}
return allowed
}
func resolveOrigins(r *http.Request, settings *system_setting.PasskeySettings) ([]string, error) {
originsStr := strings.TrimSpace(settings.Origins)
if originsStr != "" {
+6
View File
@@ -72,6 +72,12 @@ func PopSessionDataFlow(token, purpose string, identity model.AuthSessionIdentit
if err := common.UnmarshalJsonStr(flow.Payload, &payload); err != nil {
return err
}
if payload.SessionData.RelyingPartyID == "" || payload.SessionData.Expires.IsZero() {
return model.ErrAuthFlowInvalid
}
if !time.Now().Before(payload.SessionData.Expires) {
return model.ErrAuthFlowExpired
}
if purpose == model.AuthFlowPurposePasskeyLogin {
return nil
}