hugo-encrypt.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package main
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/rand"
  7. "crypto/sha256"
  8. "encoding/hex"
  9. "fmt"
  10. "io/ioutil"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. "github.com/PuerkitoBio/goquery"
  15. "golang.org/x/crypto/pbkdf2"
  16. )
  17. func deriveKey(passphrase string, salt []byte) ([]byte, []byte) {
  18. if salt == nil {
  19. salt = make([]byte, 8)
  20. // http://www.ietf.org/rfc/rfc2898.txt
  21. // Salt.
  22. rand.Read(salt)
  23. }
  24. return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), salt
  25. }
  26. func encrypt(passphrase, plaintext string) string {
  27. key, salt := deriveKey(passphrase, nil)
  28. iv := make([]byte, 12)
  29. // http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
  30. // Section 8.2
  31. rand.Read(iv)
  32. b, _ := aes.NewCipher(key)
  33. aesgcm, _ := cipher.NewGCM(b)
  34. data := aesgcm.Seal(nil, iv, []byte(plaintext), nil)
  35. return hex.EncodeToString(salt) + "-" + hex.EncodeToString(iv) + "-" + hex.EncodeToString(data)
  36. }
  37. func encryptPage(path string) {
  38. content, err := ioutil.ReadFile(path)
  39. if err != nil {
  40. panic(err)
  41. }
  42. doc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(content))
  43. if err != nil {
  44. panic(err)
  45. }
  46. block := doc.Find("cipher-text")
  47. if len(block.Nodes) == 1 {
  48. fmt.Printf("Processing %s\n", path)
  49. password, _ := block.Attr("data-password")
  50. blockhtml, _ := block.Html()
  51. enchtml := encrypt(password, blockhtml)
  52. block.RemoveAttr("data-password")
  53. block.SetHtml(enchtml)
  54. wholehtml, _ := doc.Html()
  55. ioutil.WriteFile(path, []byte(wholehtml), 0644)
  56. }
  57. }
  58. type stringFlag struct {
  59. set bool
  60. value string
  61. }
  62. func (sf *stringFlag) Set(x string) error {
  63. sf.value = x
  64. sf.set = true
  65. return nil
  66. }
  67. func (sf *stringFlag) String() string {
  68. return sf.value
  69. }
  70. var sitepath stringFlag
  71. func init() {
  72. flag.Var(&sitepath, "sitepath", "the sitepath")
  73. type stringFlag struct {
  74. set bool
  75. value string
  76. }
  77. func (sf *stringFlag) Set(x string) error {
  78. sf.value = x
  79. sf.set = true
  80. return nil
  81. }
  82. func (sf *stringFlag) String() string {
  83. return sf.value
  84. }
  85. var sitepath stringFlag
  86. func init() {
  87. flag.Var(&sitepath, "sitepath", "the sitepath")
  88. }
  89. func main() {
  90. flag.Parse()
  91. if !sitepath.set {
  92. fmt.Println("--sitepath not set")
  93. os.Exit(1)
  94. } else {
  95. fmt.Printf("--sitepath set to %q\n", sitepath.value)
  96. }
  97. err := filepath.Walk(sitepath.value, func(path string, f os.FileInfo, err error) error {
  98. if f == nil {
  99. return err
  100. }
  101. if f.IsDir() {
  102. return nil
  103. }
  104. ok := strings.HasSuffix(f.Name(), ".html")
  105. if ok {
  106. encryptPage(path)
  107. }
  108. return nil
  109. })
  110. if err != nil {
  111. fmt.Printf("filepath.Walk() returned %v\n", err)
  112. }
  113. }