1
0

emails.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/gob"
  5. "encoding/json"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "time"
  10. uuid "github.com/satori/go.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. domain, err := utils.PostPara(r, "domain")
  24. if err != nil {
  25. utils.SendErrorResponse(w, "domain cannot be empty")
  26. return
  27. }
  28. portString, err := utils.PostPara(r, "port")
  29. if err != nil {
  30. utils.SendErrorResponse(w, "port must be a valid integer")
  31. return
  32. }
  33. port, err := strconv.Atoi(portString)
  34. if err != nil {
  35. utils.SendErrorResponse(w, "port must be a valid integer")
  36. return
  37. }
  38. username, err := utils.PostPara(r, "username")
  39. if err != nil {
  40. utils.SendErrorResponse(w, "username cannot be empty")
  41. return
  42. }
  43. password, err := utils.PostPara(r, "password")
  44. if err != nil {
  45. //Empty password. Use old one if exists
  46. oldConfig := loadSMTPConfig()
  47. if oldConfig.Password == "" {
  48. utils.SendErrorResponse(w, "password cannot be empty")
  49. return
  50. } else {
  51. password = oldConfig.Password
  52. }
  53. }
  54. senderAddr, err := utils.PostPara(r, "senderAddr")
  55. if err != nil {
  56. utils.SendErrorResponse(w, "senderAddr cannot be empty")
  57. return
  58. }
  59. adminAddr, err := utils.PostPara(r, "adminAddr")
  60. if err != nil {
  61. utils.SendErrorResponse(w, "adminAddr cannot be empty")
  62. return
  63. }
  64. //Set the email sender properties
  65. thisEmailSender := email.Sender{
  66. Hostname: strings.TrimSpace(hostname),
  67. Domain: strings.TrimSpace(domain),
  68. Port: port,
  69. Username: strings.TrimSpace(username),
  70. Password: strings.TrimSpace(password),
  71. SenderAddr: strings.TrimSpace(senderAddr),
  72. }
  73. //Write this into database
  74. setSMTPConfig(&thisEmailSender)
  75. //Update the current EmailSender
  76. EmailSender = &thisEmailSender
  77. //Set the admin address of password reset
  78. setSMTPAdminAddress(adminAddr)
  79. //Reply ok
  80. utils.SendOK(w)
  81. }
  82. func HandleSMTPGet(w http.ResponseWriter, r *http.Request) {
  83. // Create a buffer to store the encoded value
  84. var buf bytes.Buffer
  85. // Encode the original object into the buffer
  86. encoder := gob.NewEncoder(&buf)
  87. err := encoder.Encode(*EmailSender)
  88. if err != nil {
  89. utils.SendErrorResponse(w, "Internal encode error")
  90. return
  91. }
  92. // Decode the buffer into a new object
  93. var copied email.Sender
  94. decoder := gob.NewDecoder(&buf)
  95. err = decoder.Decode(&copied)
  96. if err != nil {
  97. utils.SendErrorResponse(w, "Internal decode error")
  98. return
  99. }
  100. copied.Password = ""
  101. js, _ := json.Marshal(copied)
  102. utils.SendJSONResponse(w, string(js))
  103. }
  104. func HandleAdminEmailGet(w http.ResponseWriter, r *http.Request) {
  105. js, _ := json.Marshal(loadSMTPAdminAddr())
  106. utils.SendJSONResponse(w, string(js))
  107. }
  108. func HandleTestEmailSend(w http.ResponseWriter, r *http.Request) {
  109. adminEmailAccount := loadSMTPAdminAddr()
  110. if adminEmailAccount == "" {
  111. utils.SendErrorResponse(w, "Management account not set")
  112. return
  113. }
  114. err := EmailSender.SendEmail(adminEmailAccount,
  115. "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.")
  116. if err != nil {
  117. utils.SendErrorResponse(w, err.Error())
  118. return
  119. }
  120. utils.SendOK(w)
  121. }
  122. /*
  123. SMTP config
  124. The following handle SMTP configs
  125. */
  126. func setSMTPConfig(config *email.Sender) error {
  127. return sysdb.Write("smtp", "config", config)
  128. }
  129. func loadSMTPConfig() *email.Sender {
  130. if sysdb.KeyExists("smtp", "config") {
  131. thisEmailSender := email.Sender{
  132. Port: 587,
  133. }
  134. err := sysdb.Read("smtp", "config", &thisEmailSender)
  135. if err != nil {
  136. return &email.Sender{
  137. Port: 587,
  138. }
  139. }
  140. return &thisEmailSender
  141. } else {
  142. //Not set. Return an empty one
  143. return &email.Sender{
  144. Port: 587,
  145. }
  146. }
  147. }
  148. func setSMTPAdminAddress(adminAddr string) error {
  149. return sysdb.Write("smtp", "admin", adminAddr)
  150. }
  151. //Load SMTP admin address. Return empty string if not set
  152. func loadSMTPAdminAddr() string {
  153. adminAddr := ""
  154. if sysdb.KeyExists("smtp", "admin") {
  155. err := sysdb.Read("smtp", "admin", &adminAddr)
  156. if err != nil {
  157. return ""
  158. }
  159. return adminAddr
  160. } else {
  161. return ""
  162. }
  163. }
  164. /*
  165. Admin Account Reset
  166. */
  167. var (
  168. accountResetEmailDelay int64 = 30 //Delay between each account reset email, default 30s
  169. tokenValidDuration int64 = 15 * 60 //Duration of the token, default 15 minutes
  170. lastAccountResetEmail int64 = 0 //Timestamp for last sent account reset email
  171. passwordResetAccessToken string = "" //Access token for resetting password
  172. )
  173. func HandleAdminAccountResetEmail(w http.ResponseWriter, r *http.Request) {
  174. if EmailSender.Username == "" || EmailSender.Domain == "" {
  175. //Reset account not setup
  176. utils.SendErrorResponse(w, "Reset account not setup.")
  177. return
  178. }
  179. if loadSMTPAdminAddr() == "" {
  180. utils.SendErrorResponse(w, "Reset account not setup.")
  181. }
  182. //Check if the delay expired
  183. if lastAccountResetEmail+accountResetEmailDelay > time.Now().Unix() {
  184. //Too frequent
  185. utils.SendErrorResponse(w, "You cannot send another account reset email in cooldown time")
  186. return
  187. }
  188. passwordResetAccessToken = uuid.NewV4().String()
  189. //SMTP info exists. Send reset account email
  190. lastAccountResetEmail = time.Now().Unix()
  191. EmailSender.SendEmail(loadSMTPAdminAddr(), "Management Account Reset | Zoraxy",
  192. "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.")
  193. utils.SendOK(w)
  194. }
  195. func HandleNewPasswordSetup(w http.ResponseWriter, r *http.Request) {
  196. if passwordResetAccessToken == "" {
  197. //Not initiated
  198. utils.SendErrorResponse(w, "Invalid usage")
  199. return
  200. }
  201. username, err := utils.PostPara(r, "username")
  202. if err != nil {
  203. utils.SendErrorResponse(w, "Invalid username given")
  204. return
  205. }
  206. token, err := utils.PostPara(r, "token")
  207. if err != nil {
  208. utils.SendErrorResponse(w, "Invalid token given")
  209. return
  210. }
  211. newPassword, err := utils.PostPara(r, "newpw")
  212. if err != nil {
  213. utils.SendErrorResponse(w, "Invalid new password given")
  214. return
  215. }
  216. token = strings.TrimSpace(token)
  217. username = strings.TrimSpace(username)
  218. //Validate the token
  219. if token != passwordResetAccessToken {
  220. utils.SendErrorResponse(w, "Invalid Token")
  221. return
  222. }
  223. //Check if time expired
  224. if lastAccountResetEmail+tokenValidDuration < time.Now().Unix() {
  225. //Expired
  226. utils.SendErrorResponse(w, "Token expired")
  227. return
  228. }
  229. //Check if user exists
  230. if !authAgent.UserExists(username) {
  231. //Invalid admin account name
  232. utils.SendErrorResponse(w, "Invalid Username")
  233. return
  234. }
  235. //Delete the user account
  236. authAgent.UnregisterUser(username)
  237. //Ok. Set the new password
  238. err = authAgent.CreateUserAccount(username, newPassword, "")
  239. if err != nil {
  240. utils.SendErrorResponse(w, err.Error())
  241. return
  242. }
  243. if err != nil {
  244. utils.SendErrorResponse(w, err.Error())
  245. return
  246. }
  247. utils.SendOK(w)
  248. }