package controllers import ( "encoding/json" "git.pcux.cn/xuans/Smail/config" "git.pcux.cn/xuans/Smail/dto/response" "git.pcux.cn/xuans/Smail/services/setup" "git.pcux.cn/xuans/Smail/services/setup/ssl" "git.pcux.cn/xuans/Smail/utils/context" log "github.com/sirupsen/logrus" "github.com/spf13/cast" "io" "net/http" "strings" ) func AcmeChallenge(w http.ResponseWriter, r *http.Request) { const prefix = "/.well-known/acme-challenge/" if r.Method != http.MethodGet || !strings.HasPrefix(r.URL.Path, prefix) { http.NotFound(w, r) return } token := strings.TrimPrefix(r.URL.Path, prefix) if token == "" || len(token) > 256 || strings.ContainsAny(token, "/\\") { http.NotFound(w, r) return } instance := ssl.GetHttpChallengeInstance() keyAuth, exist := instance.KeyAuthorization(token) if exist { if _, err := w.Write([]byte(keyAuth)); err != nil { log.WithError(err).Warn("write ACME challenge response failed") } } else { log.Warn("ACME challenge token not found") http.NotFound(w, r) } } type sslResponse struct { Port int `json:"port"` Type string `json:"type"` Ready bool `json:"ready"` } func writeSetupError(ctx *context.Context, w http.ResponseWriter, err error) { log.WithContext(ctx).WithError(err).Error("setup request failed") message := setup.DatabaseSetupErrorMessage(err) if message == "" { message = "\u521d\u59cb\u5316\u64cd\u4f5c\u5931\u8d25" } response.NewErrorResponse(response.ServerError, message, "").FPrint(w) } func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) { req.Body = http.MaxBytesReader(w, req.Body, 64<<10) reqBytes, err := io.ReadAll(req.Body) if err != nil { log.WithContext(ctx).WithError(err).Info("setup request body rejected") response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) return } var reqData map[string]string err = json.Unmarshal(reqBytes, &reqData) if err != nil { log.WithContext(ctx).WithError(err).Info("setup request json rejected") response.NewErrorResponse(response.ParamsError, "\u53c2\u6570\u9519\u8bef", "").FPrint(w) return } if reqData["step"] == "database" && reqData["action"] == "get" { settings, err := setup.GetDatabaseSettingsDetail(ctx) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse(settings).FPrint(w) return } if reqData["step"] == "database" && reqData["action"] == "set" { err := setup.SetDatabaseSettingsWithOptions(ctx, setup.DatabaseSettings{ Type: cast.ToString(reqData["db_type"]), DSN: cast.ToString(reqData["db_dsn"]), Mode: cast.ToString(reqData["db_mode"]), User: cast.ToString(reqData["db_user"]), Host: cast.ToString(reqData["db_host"]), Port: cast.ToString(reqData["db_port"]), Password: cast.ToString(reqData["db_password"]), Name: cast.ToString(reqData["db_name"]), }) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse("Succ").FPrint(w) return } if reqData["step"] == "password" && reqData["action"] == "get" { ok, err := setup.GetAdminPassword(ctx) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse(ok).FPrint(w) return } if reqData["step"] == "password" && reqData["action"] == "set" { err := setup.SetAdminPassword(ctx, cast.ToString(reqData["account"]), cast.ToString(reqData["password"])) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse("Succ").FPrint(w) return } if reqData["step"] == "domain" && reqData["action"] == "get" { smtpDomain, webDomain, domains, err := setup.GetDomainSettings() if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse(map[string]any{ "smtp_domain": smtpDomain, "web_domain": webDomain, "domains": domains, }).FPrint(w) return } if reqData["step"] == "domain" && reqData["action"] == "set" { err := setup.SetDomainSettings(cast.ToString(reqData["smtp_domain"]), cast.ToString(reqData["web_domain"]), reqData["multi_domain"]) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse("Succ").FPrint(w) return } if reqData["step"] == "dns" && reqData["action"] == "get" { dnsInfos, err := setup.GetDNSSettings(ctx) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse(dnsInfos).FPrint(w) return } if reqData["step"] == "ssl" && reqData["action"] == "get" { sslType, err := ssl.GetSSL() if err != nil { writeSetupError(ctx, w, err) return } res := sslResponse{ Type: sslType, Port: config.CurrentConfig().GetSetupPort(), Ready: config.IsSetupReady(), } response.NewSuccessResponse(res).FPrint(w) return } if reqData["step"] == "ssl" && reqData["action"] == "getParams" { dnsChallenge := ssl.GetDnsChallengeInstance() response.NewSuccessResponse(dnsChallenge.GetDNSSettings(ctx)).FPrint(w) return } if reqData["step"] == "ssl" && reqData["action"] == "set" { err = ssl.SetSSL(cast.ToString(reqData["ssl_type"]), cast.ToString(reqData["key_path"]), cast.ToString(reqData["crt_path"])) if err != nil { writeSetupError(ctx, w, err) return } if reqData["ssl_type"] == config.SSLTypeAutoHTTP || reqData["ssl_type"] == config.SSLTypeAutoDNS { err = ssl.GenSSL(false) if err != nil { writeSetupError(ctx, w, err) return } } if reqData["ssl_type"] == config.SSLTypeUser { if err := setup.Finish(); err != nil { writeSetupError(ctx, w, err) return } } response.NewSuccessResponse("Succ").FPrint(w) return } }