emails.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/gob"
  5. "encoding/json"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/google/uuid"
  11. "imuslab.com/zoraxy/mod/email"
  12. "imuslab.com/zoraxy/mod/utils"
  13. )
  14. /*
  15. SMTP Settings and Test Email Handlers
  16. */
  17. func HandleSMTPSet(w http.ResponseWriter, r *http.Request) {
  18. hostname, err := utils.PostPara(r, "hostname")
  19. if err != nil {
  20. utils.SendErrorResponse(w, "hostname cannot be empty")
  21. return
  22. }
  23. portString, err := utils.PostPara(r, "port")
  24. if err != nil {
  25. utils.SendErrorResponse(w, "port must be a valid integer")
  26. return
  27. }
  28. port, err := strconv.Atoi(portString)
  29. if err != nil {
  30. utils.SendErrorResponse(w, "port must be a valid integer")
  31. return
  32. }
  33. username, err := utils.PostPara(r, "username")
  34. if err != nil {
  35. utils.SendErrorResponse(w, "username cannot be empty")
  36. return
  37. }
  38. password, err := utils.PostPara(r, "password")
  39. if err != nil {
  40. //Empty password. Use old one if exists
  41. oldConfig := loadSMTPConfig()
  42. if oldConfig.Password == "" {
  43. utils.SendErrorResponse(w, "password cannot be empty")
  44. return
  45. } else {
  46. password = oldConfig.Password
  47. }
  48. }
  49. senderAddr, err := utils.PostPara(r, "senderAddr")
  50. if err != nil {
  51. utils.SendErrorResponse(w, "senderAddr cannot be empty")
  52. return
  53. }
  54. adminAddr, err := utils.PostPara(r, "adminAddr")
  55. if err != nil {
  56. utils.SendErrorResponse(w, "adminAddr cannot be empty")
  57. return
  58. }
  59. //Set the email sender properties
  60. thisEmailSender := email.Sender{
  61. Hostname: strings.TrimSpace(hostname),
  62. Port: port,
  63. Username: strings.TrimSpace(username),
  64. Password: strings.TrimSpace(password),
  65. SenderAddr: strings.TrimSpace(senderAddr),
  66. }
  67. //Write this into database
  68. setSMTPConfig(&thisEmailSender)
  69. //Update the current EmailSender
  70. EmailSender = &thisEmailSender
  71. //Set the admin address of password reset
  72. setSMTPAdminAddress(adminAddr)
  73. //Reply ok
  74. utils.SendOK(w)
  75. }
  76. func HandleSMTPGet(w http.ResponseWriter, r *http.Request) {
  77. // Create a buffer to store the encoded value
  78. var buf bytes.Buffer
  79. // Encode the original object into the buffer
  80. encoder := gob.NewEncoder(&buf)
  81. err := encoder.Encode(*EmailSender)
  82. if err != nil {
  83. utils.SendErrorResponse(w, "Internal encode error")
  84. return
  85. }
  86. // Decode the buffer into a new object
  87. var copied email.Sender
  88. decoder := gob.NewDecoder(&buf)
  89. err = decoder.Decode(&copied)
  90. if err != nil {
  91. utils.SendErrorResponse(w, "Internal decode error")
  92. return
  93. }
  94. copied.Password = ""
  95. js, _ := json.Marshal(copied)
  96. utils.SendJSONResponse(w, string(js))
  97. }
  98. func HandleAdminEmailGet(w http.ResponseWriter, r *http.Request) {
  99. js, _ := json.Marshal(loadSMTPAdminAddr())
  100. utils.SendJSONResponse(w, string(js))
  101. }
  102. func HandleTestEmailSend(w http.ResponseWriter, r *http.Request) {
  103. adminEmailAccount := loadSMTPAdminAddr()
  104. if adminEmailAccount == "" {
  105. utils.SendErrorResponse(w, "Management account not set")
  106. return
  107. }
  108. err := EmailSender.SendEmail(adminEmailAccount,
  109. "SMTP Testing Email | Zoraxy", "This is a test email sent by Zoraxy. Please do not reply to this email.<br>Zoraxy からのテストメールです。このメールには返信しないでください。<br>這是由 Zoraxy 發送的測試電子郵件。請勿回覆此郵件。<br>Ceci est un email de test envoyé par Zoraxy. Merci de ne pas répondre à cet email.<br>Dies ist eine Test-E-Mail, die von Zoraxy gesendet wurde. Bitte antworten Sie nicht auf diese E-Mail.")
  110. if err != nil {
  111. utils.SendErrorResponse(w, err.Error())
  112. return
  113. }
  114. utils.SendOK(w)
  115. }
  116. /*
  117. SMTP config
  118. The following handle SMTP configs
  119. */
  120. func setSMTPConfig(config *email.Sender) error {
  121. return sysdb.Write("smtp", "config", config)
  122. }
  123. func loadSMTPConfig() *email.Sender {
  124. if sysdb.KeyExists("smtp", "config") {
  125. thisEmailSender := email.Sender{
  126. Port: 587,
  127. }
  128. err := sysdb.Read("smtp", "config", &thisEmailSender)
  129. if err != nil {
  130. return &email.Sender{
  131. Port: 587,
  132. }
  133. }
  134. return &thisEmailSender
  135. } else {
  136. //Not set. Return an empty one
  137. return &email.Sender{
  138. Port: 587,
  139. }
  140. }
  141. }
  142. func setSMTPAdminAddress(adminAddr string) error {
  143. return sysdb.Write("smtp", "admin", adminAddr)
  144. }
  145. // Load SMTP admin address. Return empty string if not set
  146. func loadSMTPAdminAddr() string {
  147. adminAddr := ""
  148. if sysdb.KeyExists("smtp", "admin") {
  149. err := sysdb.Read("smtp", "admin", &adminAddr)
  150. if err != nil {
  151. return ""
  152. }
  153. return adminAddr
  154. } else {
  155. return ""
  156. }
  157. }
  158. /*
  159. Admin Account Reset
  160. */
  161. var (
  162. accountResetEmailDelay int64 = 30 //Delay between each account reset email, default 30s
  163. tokenValidDuration int64 = 15 * 60 //Duration of the token, default 15 minutes
  164. lastAccountResetEmail int64 = 0 //Timestamp for last sent account reset email
  165. passwordResetAccessToken string = "" //Access token for resetting password
  166. )
  167. func HandleAdminAccountResetEmail(w http.ResponseWriter, r *http.Request) {
  168. if EmailSender.Username == "" {
  169. //Reset account not setup
  170. utils.SendErrorResponse(w, "Reset account not setup.")
  171. return
  172. }
  173. if loadSMTPAdminAddr() == "" {
  174. utils.SendErrorResponse(w, "Reset account not setup.")
  175. }
  176. //Check if the delay expired
  177. if lastAccountResetEmail+accountResetEmailDelay > time.Now().Unix() {
  178. //Too frequent
  179. utils.SendErrorResponse(w, "You cannot send another account reset email in cooldown time")
  180. return
  181. }
  182. passwordResetAccessToken = uuid.New().String()
  183. //SMTP info exists. Send reset account email
  184. lastAccountResetEmail = time.Now().Unix()
  185. EmailSender.SendEmail(loadSMTPAdminAddr(), "Management Account Reset | Zoraxy",
  186. "Enter the following reset token to reset your password on your Zoraxy router.<br>"+passwordResetAccessToken+"<br><br> This is an automated generated email. DO NOT REPLY TO THIS EMAIL.")
  187. utils.SendOK(w)
  188. }
  189. func HandleNewPasswordSetup(w http.ResponseWriter, r *http.Request) {
  190. if passwordResetAccessToken == "" {
  191. //Not initiated
  192. utils.SendErrorResponse(w, "Invalid usage")
  193. return
  194. }
  195. username, err := utils.PostPara(r, "username")
  196. if err != nil {
  197. utils.SendErrorResponse(w, "Invalid username given")
  198. return
  199. }
  200. token, err := utils.PostPara(r, "token")
  201. if err != nil {
  202. utils.SendErrorResponse(w, "Invalid token given")
  203. return
  204. }
  205. newPassword, err := utils.PostPara(r, "newpw")
  206. if err != nil {
  207. utils.SendErrorResponse(w, "Invalid new password given")
  208. return
  209. }
  210. token = strings.TrimSpace(token)
  211. username = strings.TrimSpace(username)
  212. //Validate the token
  213. if token != passwordResetAccessToken {
  214. utils.SendErrorResponse(w, "Invalid Token")
  215. return
  216. }
  217. //Check if time expired
  218. if lastAccountResetEmail+tokenValidDuration < time.Now().Unix() {
  219. //Expired
  220. utils.SendErrorResponse(w, "Token expired")
  221. return
  222. }
  223. //Check if user exists
  224. if !authAgent.UserExists(username) {
  225. //Invalid admin account name
  226. utils.SendErrorResponse(w, "Invalid Username")
  227. return
  228. }
  229. // Un register the user account
  230. if err := authAgent.UnregisterUser(username); err != nil {
  231. utils.SendErrorResponse(w, err.Error())
  232. return
  233. }
  234. //Ok. Set the new password
  235. if err := authAgent.CreateUserAccount(username, newPassword, ""); err != nil {
  236. utils.SendErrorResponse(w, err.Error())
  237. return
  238. }
  239. utils.SendOK(w)
  240. }