A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

112 line
2.5 KiB

  1. /*
  2. * Copyright © 2018 A Bunch Tell LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "crypto/rand"
  13. "github.com/writeas/web-core/log"
  14. "io/ioutil"
  15. "os"
  16. "path/filepath"
  17. )
  18. const (
  19. keysDir = "keys"
  20. encKeysBytes = 32
  21. )
  22. var (
  23. emailKeyPath = filepath.Join(keysDir, "email.aes256")
  24. cookieAuthKeyPath = filepath.Join(keysDir, "cookies_auth.aes256")
  25. cookieKeyPath = filepath.Join(keysDir, "cookies_enc.aes256")
  26. )
  27. type keychain struct {
  28. emailKey, cookieAuthKey, cookieKey []byte
  29. }
  30. func initKeyPaths(app *app) {
  31. emailKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, emailKeyPath)
  32. cookieAuthKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieAuthKeyPath)
  33. cookieKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieKeyPath)
  34. }
  35. func initKeys(app *app) error {
  36. var err error
  37. app.keys = &keychain{}
  38. if debugging {
  39. log.Info(" %s", emailKeyPath)
  40. }
  41. app.keys.emailKey, err = ioutil.ReadFile(emailKeyPath)
  42. if err != nil {
  43. return err
  44. }
  45. if debugging {
  46. log.Info(" %s", cookieAuthKeyPath)
  47. }
  48. app.keys.cookieAuthKey, err = ioutil.ReadFile(cookieAuthKeyPath)
  49. if err != nil {
  50. return err
  51. }
  52. if debugging {
  53. log.Info(" %s", cookieKeyPath)
  54. }
  55. app.keys.cookieKey, err = ioutil.ReadFile(cookieKeyPath)
  56. if err != nil {
  57. return err
  58. }
  59. return nil
  60. }
  61. // generateKey generates a key at the given path used for the encryption of
  62. // certain user data. Because user data becomes unrecoverable without these
  63. // keys, this won't overwrite any existing key, and instead outputs a message.
  64. func generateKey(path string) error {
  65. // Check if key file exists
  66. if _, err := os.Stat(path); err == nil {
  67. log.Info("%s already exists. rm the file if you understand the consquences.", path)
  68. return nil
  69. } else if !os.IsNotExist(err) {
  70. log.Error("%s", err)
  71. return err
  72. }
  73. log.Info("Generating %s.", path)
  74. b, err := generateBytes(encKeysBytes)
  75. if err != nil {
  76. log.Error("FAILED. %s. Run writefreely --gen-keys again.", err)
  77. return err
  78. }
  79. err = ioutil.WriteFile(path, b, 0600)
  80. if err != nil {
  81. log.Error("FAILED writing file: %s", err)
  82. return err
  83. }
  84. log.Info("Success.")
  85. return nil
  86. }
  87. // generateBytes returns securely generated random bytes.
  88. func generateBytes(n int) ([]byte, error) {
  89. b := make([]byte, n)
  90. _, err := rand.Read(b)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return b, nil
  95. }