Personal book of passwords

handlers.go 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "os"
  7. "strconv"
  8. "text/template"
  9. )
  10. type Page struct {
  11. Profile string
  12. Passphrase string
  13. Sites []Site
  14. }
  15. func GenerateHandler(w http.ResponseWriter, r *http.Request) {
  16. profile := r.FormValue("profile")
  17. passphrase := r.FormValue("p")
  18. host := r.FormValue("host")
  19. minimumLength, _ := strconv.Atoi(r.FormValue("minimumLength"))
  20. maximumLength, _ := strconv.Atoi(r.FormValue("maximumLength"))
  21. minimumDigits, _ := strconv.Atoi(r.FormValue("minimumDigits"))
  22. minimumUppercase, _ := strconv.Atoi(r.FormValue("minimumUppercase"))
  23. minimumSpecialCharacters, _ := strconv.Atoi(r.FormValue("minimumSpecialCharacters"))
  24. specialCharacters := r.FormValue("specialCharacters")
  25. if profile == "" || passphrase == "" || host == "" {
  26. http.Error(w, "Missing credentials", http.StatusUnauthorized)
  27. return
  28. }
  29. u, err := url.Parse(host)
  30. if err != nil {
  31. http.Error(w, err.Error(), http.StatusInternalServerError)
  32. return
  33. }
  34. if u.Host == "" {
  35. host = u.Path
  36. } else {
  37. host = u.Host
  38. }
  39. site := Site{
  40. Host: host,
  41. MinimumLength: minimumLength,
  42. MaximumLength: maximumLength,
  43. SpecialCharacters: specialCharacters,
  44. NumberOfSpecialCharacters: minimumSpecialCharacters,
  45. NumberOfDigits: minimumDigits,
  46. NumberOfUpperCase: minimumUppercase,
  47. Revision: 0,
  48. }
  49. book := getBookname(profile)
  50. sites, err := read(book, passphrase)
  51. if err != nil {
  52. http.Error(w, err.Error(), http.StatusInternalServerError)
  53. return
  54. }
  55. sites = append(sites, site)
  56. err = save(book, passphrase, sites)
  57. if err != nil {
  58. http.Error(w, err.Error(), http.StatusInternalServerError)
  59. return
  60. }
  61. http.Redirect(w, r, "/book", http.StatusSeeOther)
  62. }
  63. func ProfileHandler(w http.ResponseWriter, r *http.Request) {
  64. profile := r.FormValue("profile")
  65. passphrase := r.FormValue("p")
  66. newPassphrase := r.FormValue("newPassphrase")
  67. confirmPassphrase := r.FormValue("confirmPassphrase")
  68. cmd := r.FormValue("cmd")
  69. if profile == "" || passphrase == "" {
  70. http.Error(w, "Missing credentials", http.StatusUnauthorized)
  71. return
  72. }
  73. book := getBookname(profile)
  74. if cmd == "delete" {
  75. err := os.Remove(book)
  76. if err != nil {
  77. // Return an error
  78. http.Error(w, err.Error(), http.StatusInternalServerError)
  79. return
  80. }
  81. http.Redirect(w, r, "/", http.StatusSeeOther)
  82. } else if cmd == "update" {
  83. if newPassphrase == "" || confirmPassphrase == "" || newPassphrase != confirmPassphrase {
  84. http.Error(w, "Invalid passphrase provided", http.StatusInternalServerError)
  85. return
  86. }
  87. sites, err := read(book, passphrase)
  88. if err != nil {
  89. http.Error(w, err.Error(), http.StatusInternalServerError)
  90. return
  91. }
  92. err = save(book, newPassphrase, sites)
  93. if err != nil {
  94. http.Error(w, err.Error(), http.StatusInternalServerError)
  95. return
  96. }
  97. http.Redirect(w, r, "/book", http.StatusSeeOther)
  98. } else {
  99. // This should never happen, but just in case send them back
  100. http.Redirect(w, r, "/book", http.StatusSeeOther)
  101. }
  102. }
  103. func RefreshHandler(w http.ResponseWriter, r *http.Request) {
  104. profile := r.FormValue("profile")
  105. passphrase := r.FormValue("p")
  106. host := r.FormValue("host")
  107. if profile == "" || passphrase == "" || host == "" {
  108. http.Error(w, "Missing credentials", http.StatusUnauthorized)
  109. return
  110. }
  111. // Update the revision number and generate a new password
  112. book := getBookname(profile)
  113. sites, err := read(book, passphrase)
  114. if err != nil {
  115. http.Error(w, err.Error(), http.StatusInternalServerError)
  116. return
  117. }
  118. for i, s := range sites {
  119. if s.Host == host {
  120. sites[i].Revision++
  121. break
  122. }
  123. }
  124. err = save(book, passphrase, sites)
  125. if err != nil {
  126. http.Error(w, err.Error(), http.StatusInternalServerError)
  127. return
  128. }
  129. http.Redirect(w, r, "/book", http.StatusSeeOther)
  130. }
  131. func RemoveHandler(w http.ResponseWriter, r *http.Request) {
  132. profile := r.FormValue("profile")
  133. passphrase := r.FormValue("p")
  134. host := r.FormValue("host")
  135. if profile == "" || passphrase == "" || host == "host" {
  136. http.Error(w, "Missing credentials", http.StatusUnauthorized)
  137. return
  138. }
  139. // Remove the site from our book and save it
  140. book := getBookname(profile)
  141. sites, err := read(book, passphrase)
  142. if err != nil {
  143. http.Error(w, err.Error(), http.StatusInternalServerError)
  144. return
  145. }
  146. for i, site := range sites {
  147. if site.Host == host {
  148. sites = append(sites[:i], sites[i+1:]...)
  149. break
  150. }
  151. }
  152. err = save(book, passphrase, sites)
  153. if err != nil {
  154. http.Error(w, err.Error(), http.StatusInternalServerError)
  155. return
  156. }
  157. http.Redirect(w, r, "/book", http.StatusSeeOther)
  158. }
  159. func SignOffHandler(w http.ResponseWriter, r *http.Request) {
  160. cookieProfile := &http.Cookie{
  161. Name: "profile",
  162. MaxAge: -1,
  163. }
  164. cookiePassphrase := &http.Cookie{
  165. Name: "passphrase",
  166. MaxAge: -1,
  167. }
  168. http.SetCookie(w, cookieProfile)
  169. http.SetCookie(w, cookiePassphrase)
  170. http.Redirect(w, r, "/", http.StatusSeeOther)
  171. }
  172. func BookHandler(w http.ResponseWriter, r *http.Request) {
  173. profile := r.FormValue("profile")
  174. passphrase := r.FormValue("p")
  175. if profile == "" || passphrase == "" {
  176. c, err := r.Cookie("profile")
  177. if err == nil {
  178. profile = c.Value
  179. }
  180. c, err = r.Cookie("passphrase")
  181. if err == nil {
  182. passphrase = c.Value
  183. }
  184. }
  185. if profile == "" || passphrase == "" {
  186. http.Redirect(w, r, "/book", http.StatusSeeOther)
  187. return
  188. }
  189. // Set cookies
  190. //expire := time.Now().AddDate(0, 0, 1)
  191. cookieProfile := &http.Cookie{
  192. Name: "profile",
  193. Value: profile,
  194. //Path: "/",
  195. //Domain: "localhost",
  196. //Expires: expire,
  197. //RawExpires: expire.Format(time.UnixDate),
  198. //MaxAge: 0,
  199. //Secure: false,
  200. //HttpOnly: true,
  201. }
  202. http.SetCookie(w, cookieProfile)
  203. cookiePassphrase := &http.Cookie{
  204. Name: "passphrase",
  205. Value: passphrase,
  206. //Path: "/",
  207. //Domain: "localhost",
  208. //Expires: expire,
  209. //RawExpires: expire.Format(time.UnixDate),
  210. //MaxAge: 0,
  211. //Secure: false,
  212. //HttpOnly: true,
  213. }
  214. http.SetCookie(w, cookiePassphrase)
  215. book := getBookname(profile)
  216. sites, err := read(book, passphrase)
  217. if err != nil {
  218. http.Error(w, err.Error(), http.StatusInternalServerError)
  219. return
  220. }
  221. for i, s := range sites {
  222. p := s.generatePassphrase(profile, passphrase)
  223. sites[i].Password = fmt.Sprintf("%s", string(p))
  224. }
  225. page := Page{
  226. Profile: profile,
  227. Passphrase: passphrase,
  228. Sites: sites,
  229. }
  230. t := template.Must(template.New("book").Parse(templateBook))
  231. err = t.Execute(w, page)
  232. if err != nil {
  233. http.Error(w, err.Error(), http.StatusInternalServerError)
  234. return
  235. }
  236. }
  237. func DefaultHandler(w http.ResponseWriter, r *http.Request) {
  238. fmt.Fprintf(w, templateIndex)
  239. }