https_server.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package http_server
  2. import (
  3. "bytes"
  4. "embed"
  5. "encoding/hex"
  6. "encoding/json"
  7. "fmt"
  8. log "github.com/sirupsen/logrus"
  9. "github.com/spf13/cast"
  10. "io/fs"
  11. olog "log"
  12. "math/rand"
  13. "net"
  14. "net/http"
  15. "os"
  16. "pmail/config"
  17. "pmail/controllers"
  18. "pmail/controllers/email"
  19. "pmail/dto"
  20. "pmail/dto/response"
  21. "pmail/i18n"
  22. "pmail/session"
  23. "time"
  24. )
  25. //go:embed dist/*
  26. var local embed.FS
  27. const HttpsPort = 443
  28. var httpsServer *http.Server
  29. type nullWrite struct {
  30. }
  31. func (w *nullWrite) Write(p []byte) (int, error) {
  32. return len(p), nil
  33. }
  34. func HttpsStart() {
  35. log.Infof("Http Server Start")
  36. mux := http.NewServeMux()
  37. fe, err := fs.Sub(local, "dist")
  38. if err != nil {
  39. panic(err)
  40. }
  41. mux.Handle("/", http.FileServer(http.FS(fe)))
  42. mux.HandleFunc("/api/ping", contextIterceptor(controllers.Ping))
  43. mux.HandleFunc("/api/login", contextIterceptor(controllers.Login))
  44. mux.HandleFunc("/api/group", contextIterceptor(controllers.GetUserGroup))
  45. mux.HandleFunc("/api/group/list", contextIterceptor(controllers.GetUserGroupList))
  46. mux.HandleFunc("/api/group/add", contextIterceptor(controllers.AddGroup))
  47. mux.HandleFunc("/api/group/del", contextIterceptor(controllers.DelGroup))
  48. mux.HandleFunc("/api/email/list", contextIterceptor(email.EmailList))
  49. mux.HandleFunc("/api/email/read", contextIterceptor(email.MarkRead))
  50. mux.HandleFunc("/api/email/del", contextIterceptor(email.EmailDelete))
  51. mux.HandleFunc("/api/email/detail", contextIterceptor(email.EmailDetail))
  52. mux.HandleFunc("/api/email/send", contextIterceptor(email.Send))
  53. mux.HandleFunc("/api/email/move", contextIterceptor(email.Move))
  54. mux.HandleFunc("/api/settings/modify_password", contextIterceptor(controllers.ModifyPassword))
  55. mux.HandleFunc("/attachments/", contextIterceptor(controllers.GetAttachments))
  56. mux.HandleFunc("/attachments/download/", contextIterceptor(controllers.Download))
  57. // go http server会打一堆没用的日志,写一个空的日志处理器,屏蔽掉日志输出
  58. nullLog := olog.New(&nullWrite{}, "", olog.Ldate)
  59. if config.Instance.HttpsEnabled != 2 {
  60. httpsServer = &http.Server{
  61. Addr: fmt.Sprintf(":%d", HttpsPort),
  62. Handler: session.Instance.LoadAndSave(mux),
  63. ReadTimeout: time.Second * 60,
  64. WriteTimeout: time.Second * 60,
  65. ErrorLog: nullLog,
  66. }
  67. err = httpsServer.ListenAndServeTLS("config/ssl/public.crt", "config/ssl/private.key")
  68. if err != nil {
  69. panic(err)
  70. }
  71. }
  72. }
  73. func HttpsStop() {
  74. if httpsServer != nil {
  75. httpsServer.Close()
  76. }
  77. }
  78. func genLogID() string {
  79. r := rand.New(rand.NewSource(time.Now().UnixMicro()))
  80. if ip == "" {
  81. ip = getLocalIP()
  82. }
  83. now := time.Now()
  84. timestamp := uint32(now.Unix())
  85. timeNano := now.UnixNano()
  86. pid := os.Getpid()
  87. b := bytes.Buffer{}
  88. b.WriteString(hex.EncodeToString(net.ParseIP(ip).To4()))
  89. b.WriteString(fmt.Sprintf("%x", timestamp&0xffffffff))
  90. b.WriteString(fmt.Sprintf("%04x", timeNano&0xffff))
  91. b.WriteString(fmt.Sprintf("%04x", pid&0xffff))
  92. b.WriteString(fmt.Sprintf("%06x", r.Int31n(1<<24)))
  93. b.WriteString("b0")
  94. return b.String()
  95. }
  96. // 注入context
  97. func contextIterceptor(h controllers.HandlerFunc) http.HandlerFunc {
  98. return func(w http.ResponseWriter, r *http.Request) {
  99. if w.Header().Get("Content-Type") == "" {
  100. w.Header().Set("Content-Type", "application/json")
  101. }
  102. ctx := &dto.Context{}
  103. ctx.Context = r.Context()
  104. ctx.SetValue(dto.LogID, genLogID())
  105. lang := r.Header.Get("Lang")
  106. if lang == "" {
  107. lang = "en"
  108. }
  109. ctx.Lang = lang
  110. if config.IsInit {
  111. user := cast.ToString(session.Instance.Get(ctx, "user"))
  112. if user != "" {
  113. _ = json.Unmarshal([]byte(user), &ctx.UserInfo)
  114. }
  115. if ctx.UserInfo == nil || ctx.UserInfo.ID == 0 {
  116. if r.URL.Path != "/api/ping" && r.URL.Path != "/api/login" {
  117. response.NewErrorResponse(response.NeedLogin, i18n.GetText(ctx.Lang, "login_exp"), "").FPrint(w)
  118. return
  119. }
  120. }
  121. } else if r.URL.Path != "/api/setup" {
  122. response.NewErrorResponse(response.NeedSetup, "", "").FPrint(w)
  123. return
  124. }
  125. h(ctx, w, r)
  126. }
  127. }