Smail/server/controllers/setup.go

195 lines
5.1 KiB
Go

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
}
}