package main import ( "net/http" "strings" ) type protocolProfile struct { Host string `json:"host"` Port int `json:"port"` Username string `json:"username"` PublicIP string `json:"publicIP,omitempty"` PassivePorts string `json:"passivePorts,omitempty"` ExplicitTLS bool `json:"explicitTLS,omitempty"` ForceTLS bool `json:"forceTLS,omitempty"` } type userProtocolsResponse struct { FTP *protocolProfile `json:"ftp,omitempty"` FTPS *protocolProfile `json:"ftps,omitempty"` } func (s *Server) handleUserProtocols(w http.ResponseWriter, r *http.Request) { uid := userIDFromContext(r.Context()) user, err := s.findUser(uid) if err != nil { writeErr(w, http.StatusNotFound, "user not found") return } out := userProtocolsResponse{} if s.config.FTPEnabled { out.FTP = &protocolProfile{ Host: protocolHostForClient(s.config.FTPHost, s.config.FTPPublicIP, s.config.AppDomain, r), Port: s.config.FTPPort, Username: user.Username, PublicIP: strings.TrimSpace(s.config.FTPPublicIP), PassivePorts: strings.TrimSpace(s.config.FTPPassivePorts), } } if s.config.FTPSEnabled { out.FTPS = &protocolProfile{ Host: protocolHostForClient(s.config.FTPSHost, s.config.FTPSPublicIP, s.config.AppDomain, r), Port: s.config.FTPSPort, Username: user.Username, PublicIP: strings.TrimSpace(s.config.FTPSPublicIP), PassivePorts: strings.TrimSpace(s.config.FTPSPassivePorts), ExplicitTLS: s.config.FTPSExplicit, ForceTLS: s.config.FTPSForceTLS, } } writeJSON(w, http.StatusOK, out) } func protocolHostForClient(bindHost, publicIP, appDomain string, r *http.Request) string { if v := strings.TrimSpace(publicIP); v != "" { return v } if v := strings.TrimSpace(appDomain); v != "" { return v } if v := strings.TrimSpace(hostOnly(r.Host)); v != "" { return v } v := strings.TrimSpace(bindHost) if v == "" || v == "0.0.0.0" || v == "::" || v == "[::]" { return "localhost" } return v }