From e97bfb05a92326aeef028f76fe8fc84ace672a4b Mon Sep 17 00:00:00 2001 From: Zack Scholl Date: Mon, 14 Mar 2016 09:42:19 -0400 Subject: [PATCH] Added encryption/decryption --- db.go | 9 ++-- encryption.go | 73 +++++++++++++++++++++++++++ main.go | 3 +- routes.go | 116 +++++++++++++++++++++++++++++++++---------- templates/index.tmpl | 113 +++++++++++++++++++++++++++++++---------- templates/view.tmpl | 47 ++++++++++++++++++ 6 files changed, 307 insertions(+), 54 deletions(-) create mode 100755 encryption.go diff --git a/db.go b/db.go index bb2b76d..0460467 100644 --- a/db.go +++ b/db.go @@ -39,6 +39,7 @@ type WikiData struct { CurrentText string Diffs []string Timestamps []string + Encrypted bool } func hasPassword(title string) (bool, error) { @@ -77,14 +78,15 @@ func hasPassword(title string) (bool, error) { return hasPassword, nil } -func getCurrentText(title string, version int) (string, []versionsInfo, bool, time.Duration) { +func getCurrentText(title string, version int) (string, []versionsInfo, bool, time.Duration, bool) { title = strings.ToLower(title) var vi []versionsInfo totalTime := time.Now().Sub(time.Now()) isCurrent := true currentText := "" + encrypted := false if !open { - return currentText, vi, isCurrent, totalTime + return currentText, vi, isCurrent, totalTime, encrypted } err := db.View(func(tx *bolt.Tx) error { var err error @@ -103,6 +105,7 @@ func getCurrentText(title string, version int) (string, []versionsInfo, bool, ti return err } currentText = p.CurrentText + encrypted = p.Encrypted if version > -1 && version < len(p.Diffs) { // get that version of text instead currentText = rebuildTextsToDiffN(p, version) @@ -115,7 +118,7 @@ func getCurrentText(title string, version int) (string, []versionsInfo, bool, ti if err != nil { fmt.Printf("Could not get WikiData: %s", err) } - return currentText, vi, isCurrent, totalTime + return currentText, vi, isCurrent, totalTime, encrypted } func (p *WikiData) load(title string) error { diff --git a/encryption.go b/encryption.go new file mode 100755 index 0000000..0680d85 --- /dev/null +++ b/encryption.go @@ -0,0 +1,73 @@ +package main + +import ( + "bytes" + "errors" + "io/ioutil" + "log" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/armor" +) + +var encryptionType string + +func init() { + encryptionType = "PGP SIGNATURE" +} + +func encryptString(encryptionText string, encryptionPassphraseString string) string { + encryptionPassphrase := []byte(encryptionPassphraseString) + encbuf := bytes.NewBuffer(nil) + w, err := armor.Encode(encbuf, encryptionType, nil) + if err != nil { + log.Fatal(err) + } + + plaintext, err := openpgp.SymmetricallyEncrypt(w, encryptionPassphrase, nil, nil) + if err != nil { + log.Fatal(err) + } + message := []byte(encryptionText) + _, err = plaintext.Write(message) + + plaintext.Close() + w.Close() + return encbuf.String() +} + +func decryptString(decryptionString string, encryptionPassphraseString string) (string, error) { + encryptionPassphrase := []byte(encryptionPassphraseString) + decbuf := bytes.NewBuffer([]byte(decryptionString)) + result, err := armor.Decode(decbuf) + if err != nil { + return "", err + } + + alreadyPrompted := false + md, err := openpgp.ReadMessage(result.Body, nil, func(keys []openpgp.Key, symmetric bool) ([]byte, error) { + if alreadyPrompted { + return nil, errors.New("Could not decrypt using passphrase") + } else { + alreadyPrompted = true + } + return encryptionPassphrase, nil + }, nil) + if err != nil { + return "", err + } + + bytes, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// func main() { +// test := encryptString("This is some string", "golang") +// fmt.Println(test) +// testD := decryptString(test, "golang") +// fmt.Println(testD) +// +// } diff --git a/main.go b/main.go index 32855af..5f181f7 100644 --- a/main.go +++ b/main.go @@ -90,7 +90,7 @@ Options:`) // Default page aboutFile, _ := ioutil.ReadFile(path.Join(RuntimeArgs.SourcePath, "templates/aboutpage.md")) - p := WikiData{"about", "", []string{}, []string{}} + p := WikiData{"about", "", []string{}, []string{}, false} p.save(string(aboutFile)) // var q WikiData @@ -103,6 +103,7 @@ Options:`) r.HEAD("/", func(c *gin.Context) { c.Status(200) }) r.GET("/:title", editNote) r.GET("/:title/*option", everythingElse) + r.POST("/:title/*option", encryptionRoute) r.DELETE("/listitem", deleteListItem) r.DELETE("/deletepage", deletePage) if RuntimeArgs.ServerCRT != "" && RuntimeArgs.ServerKey != "" { diff --git a/routes.go b/routes.go index c6bce93..f1194ee 100644 --- a/routes.go +++ b/routes.go @@ -18,6 +18,74 @@ import ( "github.com/russross/blackfriday" ) +type EncryptionPost struct { + Text string `form:"text" json:"text" binding:"required"` + Password string `form:"password" json:"password" binding:"required"` +} + +func encryptionRoute(c *gin.Context) { + title := c.Param("title") + option := c.Param("option") + fmt.Println(option, title) + var jsonLoad EncryptionPost + if option == "/decrypt" { + fmt.Println("Decrypting...") + if c.BindJSON(&jsonLoad) == nil { + var err error + currentText, _, _, _, encrypted := getCurrentText(title, -1) + fmt.Println(currentText, encrypted, jsonLoad.Password) + if encrypted == true { + currentText, err = decryptString(currentText, jsonLoad.Password) + if err != nil { + c.JSON(200, gin.H{ + "status": "Inorrect passphrase.", + "title": title, + "option": option, + "success": false, + }) + } else { + p := WikiData{strings.ToLower(title), "", []string{}, []string{}, false} + p.save(currentText) + c.JSON(200, gin.H{ + "status": "posted", + "title": title, + "option": option, + "success": true, + }) + } + } + } else { + c.JSON(200, gin.H{ + "status": "Could not bind", + "title": title, + "option": option, + "success": false, + }) + } + } + if option == "/encrypt" { + if c.BindJSON(&jsonLoad) == nil { + fmt.Println(jsonLoad) + p := WikiData{strings.ToLower(title), "", []string{}, []string{}, true} + p.save(encryptString(jsonLoad.Text, jsonLoad.Password)) + c.JSON(200, gin.H{ + "status": "posted", + "title": title, + "option": option, + "success": true, + }) + } else { + c.JSON(200, gin.H{ + "status": "posted", + "title": title, + "option": option, + "success": false, + }) + } + } + +} + func newNote(c *gin.Context) { title := randomAlliterateCombo() c.Redirect(302, "/"+title) @@ -38,7 +106,10 @@ func editNote(c *gin.Context) { } else { version := c.DefaultQuery("version", "-1") versionNum, _ := strconv.Atoi(version) - currentText, versions, currentVersion, totalTime := getCurrentText(title, versionNum) + currentText, versions, currentVersion, totalTime, encrypted := getCurrentText(title, versionNum) + if encrypted { + c.Redirect(302, "/"+title+"/view") + } if strings.Contains(currentText, "self-destruct\n") || strings.Contains(currentText, "\nself-destruct") { c.Redirect(302, "/"+title+"/view") } @@ -81,16 +152,16 @@ func everythingElse(c *gin.Context) { if strings.ToLower(title) == "about" { versionNum = -1 } - currentText, versions, _, totalTime := getCurrentText(title, versionNum) + currentText, versions, _, totalTime, encrypted := getCurrentText(title, versionNum) if (strings.Contains(currentText, "self-destruct\n") || strings.Contains(currentText, "\nself-destruct")) && strings.ToLower(title) != "about" { currentText = strings.Replace(currentText, "self-destruct\n", `> *This page has been deleted, you cannot return after closing.*`+"\n", 1) currentText = strings.Replace(currentText, "\nself-destruct", "\n"+`> *This page has been deleted, you cannot return after closing.*`, 1) - p := WikiData{strings.ToLower(title), "", []string{}, []string{}} + p := WikiData{strings.ToLower(title), "", []string{}, []string{}, false} p.save("") } - renderMarkdown(c, currentText, title, versions, "", totalTime) + renderMarkdown(c, currentText, title, versions, "", totalTime, encrypted) } else if title == "ls" && option == "/"+RuntimeArgs.AdminKey && len(RuntimeArgs.AdminKey) > 1 { - renderMarkdown(c, listEverything(), "ls", nil, RuntimeArgs.AdminKey, time.Now().Sub(time.Now())) + renderMarkdown(c, listEverything(), "ls", nil, RuntimeArgs.AdminKey, time.Now().Sub(time.Now()), false) } else if option == "/list" { renderList(c, title) } else if title == "static" { @@ -109,7 +180,7 @@ func serveStaticFile(c *gin.Context, option string) { } } -func renderMarkdown(c *gin.Context, currentText string, title string, versions []versionsInfo, AdminKey string, totalTime time.Duration) { +func renderMarkdown(c *gin.Context, currentText string, title string, versions []versionsInfo, AdminKey string, totalTime time.Duration, encrypted bool) { r, _ := regexp.Compile("\\[\\[(.*?)\\]\\]") for _, s := range r.FindAllString(currentText, -1) { currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1) @@ -139,24 +210,16 @@ func renderMarkdown(c *gin.Context, currentText string, title string, versions [ html2 = strings.Replace(html2, "&#93;", "]", -1) html2 = strings.Replace(html2, "&35;", "#", -1) - if AdminKey == "" { - c.HTML(http.StatusOK, "view.tmpl", gin.H{ - "Title": title, - "WikiName": RuntimeArgs.WikiName, - "Body": template.HTML([]byte(html2)), - "TotalTime": totalTime.String(), - "Versions": versions, - }) - } else { - c.HTML(http.StatusOK, "view.tmpl", gin.H{ - "Title": title, - "WikiName": RuntimeArgs.WikiName, - "Body": template.HTML([]byte(html2)), - "Versions": versions, - "TotalTime": totalTime.String(), - "AdminKey": AdminKey, - }) - } + c.HTML(http.StatusOK, "view.tmpl", gin.H{ + "Title": title, + "WikiName": RuntimeArgs.WikiName, + "Body": template.HTML([]byte(html2)), + "Versions": versions, + "TotalTime": totalTime.String(), + "AdminKey": AdminKey, + "Encrypted": encrypted, + }) + } func reorderList(text string) ([]template.HTML, []string) { @@ -214,6 +277,9 @@ func renderList(c *gin.Context, title string) { if strings.Contains(currentText, "self-destruct\n") || strings.Contains(currentText, "\nself-destruct") { c.Redirect(302, "/"+title+"/view") } + if p.Encrypted { + c.Redirect(302, "/"+title+"/view") + } pClean := bluemonday.UGCPolicy() pClean.AllowElements("img") @@ -277,7 +343,7 @@ func deletePage(c *gin.Context) { fmt.Println(deleteName) // if adminKey == RuntimeArgs.AdminKey || true == true { if strings.ToLower(deleteName) != "about" { - p := WikiData{strings.ToLower(deleteName), "", []string{}, []string{}} + p := WikiData{strings.ToLower(deleteName), "", []string{}, []string{}, false} p.save("") } // // remove from program data diff --git a/templates/index.tmpl b/templates/index.tmpl index d81adf0..d9d3384 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -9,7 +9,8 @@ - {{if .NoEdit}} {{else}} {{end}} + {{if .NoEdit}} {{else}} + {{end}} @@ -74,7 +73,7 @@