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"` } func writeSetupError(ctx *context.Context, w http.ResponseWriter, err error) { log.WithContext(ctx).WithError(err).Error("setup request failed") response.NewErrorResponse(response.ServerError, "\u521d\u59cb\u5316\u64cd\u4f5c\u5931\u8d25", "").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" { dbType, dbDSN, err := setup.GetDatabaseSettings(ctx) if err != nil { writeSetupError(ctx, w, err) return } response.NewSuccessResponse(map[string]string{ "db_type": dbType, "db_dsn": dbDSN, }).FPrint(w) return } if reqData["step"] == "database" && reqData["action"] == "set" { err := setup.SetDatabaseSettings(ctx, cast.ToString(reqData["db_type"]), cast.ToString(reqData["db_dsn"])) 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(), } 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 } }