1
0
mirror of https://github.com/schollz/cowyo.git synced 2023-08-10 21:13:00 +03:00

Allow raw to get locked copy

Former-commit-id: 685117ffd3
This commit is contained in:
Zack Scholl 2017-03-23 17:47:41 -06:00
parent 11b671423c
commit e066ad23cc

View File

@ -1,352 +1,353 @@
package main package main
import ( import (
"html/template" "html/template"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time" "time"
// "github.com/gin-contrib/static" // "github.com/gin-contrib/static"
"github.com/gin-contrib/multitemplate" "github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func serve(port string) { func serve(port string) {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
router := gin.Default() router := gin.Default()
router.HTMLRender = loadTemplates("index.tmpl") router.HTMLRender = loadTemplates("index.tmpl")
// router.Use(static.Serve("/static/", static.LocalFile("./static", true))) // router.Use(static.Serve("/static/", static.LocalFile("./static", true)))
router.GET("/", func(c *gin.Context) { router.GET("/", func(c *gin.Context) {
c.Redirect(302, "/"+randomAlliterateCombo()) c.Redirect(302, "/"+randomAlliterateCombo())
}) })
router.GET("/:page", func(c *gin.Context) { router.GET("/:page", func(c *gin.Context) {
page := c.Param("page") page := c.Param("page")
c.Redirect(302, "/"+page+"/edit") c.Redirect(302, "/"+page+"/edit")
}) })
router.GET("/:page/*command", handlePageRequest) router.GET("/:page/*command", handlePageRequest)
router.POST("/update", handlePageUpdate) router.POST("/update", handlePageUpdate)
router.POST("/prime", handlePrime) router.POST("/prime", handlePrime)
router.POST("/lock", handleLock) router.POST("/lock", handleLock)
router.POST("/encrypt", handleEncrypt) router.POST("/encrypt", handleEncrypt)
router.DELETE("/oldlist", handleClearOldListItems) router.DELETE("/oldlist", handleClearOldListItems)
router.DELETE("/listitem", deleteListItem) router.DELETE("/listitem", deleteListItem)
router.Run(":" + port) router.Run(":" + port)
} }
func loadTemplates(list ...string) multitemplate.Render { func loadTemplates(list ...string) multitemplate.Render {
r := multitemplate.New() r := multitemplate.New()
for _, x := range list { for _, x := range list {
templateString, err := Asset("templates/" + x) templateString, err := Asset("templates/" + x)
if err != nil { if err != nil {
panic(err) panic(err)
} }
tmplMessage, err := template.New(x).Parse(string(templateString)) tmplMessage, err := template.New(x).Parse(string(templateString))
if err != nil { if err != nil {
panic(err) panic(err)
} }
r.Add(x, tmplMessage) r.Add(x, tmplMessage)
} }
return r return r
} }
func handlePageRequest(c *gin.Context) { func handlePageRequest(c *gin.Context) {
page := c.Param("page") page := c.Param("page")
command := c.Param("command") command := c.Param("command")
if len(command) < 2 { if len(command) < 2 {
command = "/ " command = "/ "
} }
// Serve static content from memory // Serve static content from memory
if page == "static" { if page == "static" {
filename := page + command filename := page + command
data, err := Asset(filename) data, err := Asset(filename)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, "Could not find data") c.String(http.StatusInternalServerError, "Could not find data")
} }
c.Data(http.StatusOK, contentType(filename), data) c.Data(http.StatusOK, contentType(filename), data)
return return
} }
version := c.DefaultQuery("version", "ajksldfjl") version := c.DefaultQuery("version", "ajksldfjl")
p := Open(page) p := Open(page)
// Disallow anything but viewing locked/encrypted pages // Disallow anything but viewing locked/encrypted pages
if (p.IsEncrypted || p.IsLocked) && command[0:2] != "/v" { if (p.IsEncrypted || p.IsLocked) &&
c.Redirect(302, "/"+page+"/view") (command[0:2] != "/v" && command[0:2] != "/r") {
return c.Redirect(302, "/"+page+"/view")
} return
}
// Destroy page if it is opened and primed
if p.IsPrimedForSelfDestruct && !p.IsLocked && !p.IsEncrypted { // Destroy page if it is opened and primed
p.Update("*This page has self-destructed. You can not return to it.*\n\n" + p.Text.GetCurrent()) if p.IsPrimedForSelfDestruct && !p.IsLocked && !p.IsEncrypted {
p.Erase() p.Update("*This page has self-destructed. You can not return to it.*\n\n" + p.Text.GetCurrent())
} p.Erase()
if command == "/erase" { }
if !p.IsLocked && !p.IsEncrypted { if command == "/erase" {
p.Erase() if !p.IsLocked && !p.IsEncrypted {
c.Redirect(302, "/"+page+"/edit") p.Erase()
} else { c.Redirect(302, "/"+page+"/edit")
c.Redirect(302, "/"+page+"/view") } else {
} c.Redirect(302, "/"+page+"/view")
return }
} return
rawText := p.Text.GetCurrent() }
rawHTML := p.RenderedPage rawText := p.Text.GetCurrent()
rawHTML := p.RenderedPage
// Check to see if an old version is requested
versionInt, versionErr := strconv.Atoi(version) // Check to see if an old version is requested
if versionErr == nil && versionInt > 0 { versionInt, versionErr := strconv.Atoi(version)
versionText, err := p.Text.GetPreviousByTimestamp(int64(versionInt)) if versionErr == nil && versionInt > 0 {
if err == nil { versionText, err := p.Text.GetPreviousByTimestamp(int64(versionInt))
rawText = versionText if err == nil {
rawHTML = GithubMarkdownToHTML(rawText) rawText = versionText
} rawHTML = GithubMarkdownToHTML(rawText)
} }
versionsInt64 := p.Text.GetMajorSnapshots(60) // get snapshots 60 seconds apart }
versionsText := make([]string, len(versionsInt64)) versionsInt64 := p.Text.GetMajorSnapshots(60) // get snapshots 60 seconds apart
for i, v := range versionsInt64 { versionsText := make([]string, len(versionsInt64))
versionsText[i] = time.Unix(v/1000000000, 0).String() for i, v := range versionsInt64 {
} versionsText[i] = time.Unix(v/1000000000, 0).String()
}
if command[0:2] == "/r" {
c.Writer.Header().Set("Content-Type", contentType(p.Name)) if command[0:2] == "/r" {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Content-Type", contentType(p.Name))
c.Writer.Header().Set("Access-Control-Max-Age", "86400") c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") c.Writer.Header().Set("Access-Control-Max-Age", "86400")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Max")
c.Data(200, contentType(p.Name), []byte(rawText)) c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
return c.Data(200, contentType(p.Name), []byte(rawText))
} return
log.Debug(command) }
log.Debug("%v", command[0:2] != "/e" && log.Debug(command)
command[0:2] != "/v" && log.Debug("%v", command[0:2] != "/e" &&
command[0:2] != "/l" && command[0:2] != "/v" &&
command[0:2] != "/h") command[0:2] != "/l" &&
command[0:2] != "/h")
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"EditPage": command[0:2] == "/e", // /edit c.HTML(http.StatusOK, "index.tmpl", gin.H{
"ViewPage": command[0:2] == "/v", // /view "EditPage": command[0:2] == "/e", // /edit
"ListPage": command[0:2] == "/l", // /list "ViewPage": command[0:2] == "/v", // /view
"HistoryPage": command[0:2] == "/h", // /history "ListPage": command[0:2] == "/l", // /list
"DontKnowPage": command[0:2] != "/e" && "HistoryPage": command[0:2] == "/h", // /history
command[0:2] != "/v" && "DontKnowPage": command[0:2] != "/e" &&
command[0:2] != "/l" && command[0:2] != "/v" &&
command[0:2] != "/h", command[0:2] != "/l" &&
"Page": p.Name, command[0:2] != "/h",
"RenderedPage": template.HTML([]byte(rawHTML)), "Page": p.Name,
"RawPage": rawText, "RenderedPage": template.HTML([]byte(rawHTML)),
"Versions": versionsInt64, "RawPage": rawText,
"VersionsText": versionsText, "Versions": versionsInt64,
"IsLocked": p.IsLocked, "VersionsText": versionsText,
"IsEncrypted": p.IsEncrypted, "IsLocked": p.IsLocked,
"ListItems": renderList(rawText), "IsEncrypted": p.IsEncrypted,
"Route": "/" + page + command, "ListItems": renderList(rawText),
"HasDotInName": strings.Contains(page, "."), "Route": "/" + page + command,
}) "HasDotInName": strings.Contains(page, "."),
} })
}
func handlePageUpdate(c *gin.Context) {
type QueryJSON struct { func handlePageUpdate(c *gin.Context) {
Page string `json:"page"` type QueryJSON struct {
NewText string `json:"new_text"` Page string `json:"page"`
} NewText string `json:"new_text"`
var json QueryJSON }
if c.BindJSON(&json) != nil { var json QueryJSON
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong JSON"}) if c.BindJSON(&json) != nil {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong JSON"})
} return
if len(json.NewText) > 100000 { }
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Too much"}) if len(json.NewText) > 100000 {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Too much"})
} return
log.Trace("Update: %v", json) }
p := Open(json.Page) log.Trace("Update: %v", json)
var message string p := Open(json.Page)
if p.IsLocked { var message string
message = "Locked" if p.IsLocked {
} else if p.IsEncrypted { message = "Locked"
message = "Encrypted" } else if p.IsEncrypted {
} else { message = "Encrypted"
p.Update(json.NewText) } else {
p.Save() p.Update(json.NewText)
message = "Saved" p.Save()
} message = "Saved"
c.JSON(http.StatusOK, gin.H{"success": true, "message": message}) }
} c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
}
func handlePrime(c *gin.Context) {
type QueryJSON struct { func handlePrime(c *gin.Context) {
Page string `json:"page"` type QueryJSON struct {
} Page string `json:"page"`
var json QueryJSON }
if c.BindJSON(&json) != nil { var json QueryJSON
c.String(http.StatusBadRequest, "Problem binding keys") if c.BindJSON(&json) != nil {
return c.String(http.StatusBadRequest, "Problem binding keys")
} return
log.Trace("Update: %v", json) }
p := Open(json.Page) log.Trace("Update: %v", json)
if p.IsLocked { p := Open(json.Page)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) if p.IsLocked {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
} else if p.IsEncrypted { return
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"}) } else if p.IsEncrypted {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"})
} return
p.IsPrimedForSelfDestruct = true }
p.Save() p.IsPrimedForSelfDestruct = true
c.JSON(http.StatusOK, gin.H{"success": true, "message": "Primed"}) p.Save()
} c.JSON(http.StatusOK, gin.H{"success": true, "message": "Primed"})
}
func handleLock(c *gin.Context) {
type QueryJSON struct { func handleLock(c *gin.Context) {
Page string `json:"page"` type QueryJSON struct {
Passphrase string `json:"passphrase"` Page string `json:"page"`
} Passphrase string `json:"passphrase"`
}
var json QueryJSON
if c.BindJSON(&json) != nil { var json QueryJSON
c.String(http.StatusBadRequest, "Problem binding keys") if c.BindJSON(&json) != nil {
return c.String(http.StatusBadRequest, "Problem binding keys")
} return
p := Open(json.Page) }
if p.IsEncrypted { p := Open(json.Page)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"}) if p.IsEncrypted {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"})
} return
var message string }
if p.IsLocked { var message string
err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock) if p.IsLocked {
if err2 != nil { err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"}) if err2 != nil {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"})
} return
p.IsLocked = false }
message = "Unlocked" p.IsLocked = false
} else { message = "Unlocked"
p.IsLocked = true } else {
p.PassphraseToUnlock = HashPassword(json.Passphrase) p.IsLocked = true
message = "Locked" p.PassphraseToUnlock = HashPassword(json.Passphrase)
} message = "Locked"
p.Save() }
c.JSON(http.StatusOK, gin.H{"success": true, "message": message}) p.Save()
} c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
}
func handleEncrypt(c *gin.Context) {
type QueryJSON struct { func handleEncrypt(c *gin.Context) {
Page string `json:"page"` type QueryJSON struct {
Passphrase string `json:"passphrase"` Page string `json:"page"`
} Passphrase string `json:"passphrase"`
}
var json QueryJSON
if c.BindJSON(&json) != nil { var json QueryJSON
c.String(http.StatusBadRequest, "Problem binding keys") if c.BindJSON(&json) != nil {
return c.String(http.StatusBadRequest, "Problem binding keys")
} return
p := Open(json.Page) }
if p.IsLocked { p := Open(json.Page)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) if p.IsLocked {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
} return
q := Open(json.Page) }
var message string q := Open(json.Page)
if p.IsEncrypted { var message string
decrypted, err2 := DecryptString(p.Text.GetCurrent(), json.Passphrase) if p.IsEncrypted {
if err2 != nil { decrypted, err2 := DecryptString(p.Text.GetCurrent(), json.Passphrase)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong password"}) if err2 != nil {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong password"})
} return
q.Erase() }
q = Open(json.Page) q.Erase()
q.Update(decrypted) q = Open(json.Page)
q.IsEncrypted = false q.Update(decrypted)
q.IsLocked = p.IsLocked q.IsEncrypted = false
q.IsPrimedForSelfDestruct = p.IsPrimedForSelfDestruct q.IsLocked = p.IsLocked
message = "Decrypted" q.IsPrimedForSelfDestruct = p.IsPrimedForSelfDestruct
} else { message = "Decrypted"
currentText := p.Text.GetCurrent() } else {
encrypted, _ := EncryptString(currentText, json.Passphrase) currentText := p.Text.GetCurrent()
q.Erase() encrypted, _ := EncryptString(currentText, json.Passphrase)
q = Open(json.Page) q.Erase()
q.Update(encrypted) q = Open(json.Page)
q.IsEncrypted = true q.Update(encrypted)
q.IsLocked = p.IsLocked q.IsEncrypted = true
q.IsPrimedForSelfDestruct = p.IsPrimedForSelfDestruct q.IsLocked = p.IsLocked
message = "Encrypted" q.IsPrimedForSelfDestruct = p.IsPrimedForSelfDestruct
} message = "Encrypted"
q.Save() }
c.JSON(http.StatusOK, gin.H{"success": true, "message": message}) q.Save()
} c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
}
func deleteListItem(c *gin.Context) {
lineNum, err := strconv.Atoi(c.DefaultQuery("lineNum", "None")) func deleteListItem(c *gin.Context) {
page := c.Query("page") // shortcut for c.Request.URL.Query().Get("lastname") lineNum, err := strconv.Atoi(c.DefaultQuery("lineNum", "None"))
if err == nil { page := c.Query("page") // shortcut for c.Request.URL.Query().Get("lastname")
p := Open(page) if err == nil {
p := Open(page)
_, listItems := reorderList(p.Text.GetCurrent())
newText := p.Text.GetCurrent() _, listItems := reorderList(p.Text.GetCurrent())
for i, lineString := range listItems { newText := p.Text.GetCurrent()
// fmt.Println(i, lineString, lineNum) for i, lineString := range listItems {
if i+1 == lineNum { // fmt.Println(i, lineString, lineNum)
// fmt.Println("MATCHED") if i+1 == lineNum {
if strings.Contains(lineString, "~~") == false { // fmt.Println("MATCHED")
// fmt.Println(p.Text, "("+lineString[2:]+"\n"+")", "~~"+lineString[2:]+"~~"+"\n") if strings.Contains(lineString, "~~") == false {
newText = strings.Replace(newText+"\n", lineString[2:]+"\n", "~~"+strings.TrimSpace(lineString[2:])+"~~"+"\n", 1) // fmt.Println(p.Text, "("+lineString[2:]+"\n"+")", "~~"+lineString[2:]+"~~"+"\n")
} else { newText = strings.Replace(newText+"\n", lineString[2:]+"\n", "~~"+strings.TrimSpace(lineString[2:])+"~~"+"\n", 1)
newText = strings.Replace(newText+"\n", lineString[2:]+"\n", lineString[4:len(lineString)-2]+"\n", 1) } else {
} newText = strings.Replace(newText+"\n", lineString[2:]+"\n", lineString[4:len(lineString)-2]+"\n", 1)
p.Update(newText) }
break p.Update(newText)
} break
} }
}
c.JSON(200, gin.H{
"success": true, c.JSON(200, gin.H{
"message": "Done.", "success": true,
}) "message": "Done.",
} else { })
c.JSON(200, gin.H{ } else {
"success": false, c.JSON(200, gin.H{
"message": err.Error(), "success": false,
}) "message": err.Error(),
} })
} }
}
func handleClearOldListItems(c *gin.Context) {
type QueryJSON struct { func handleClearOldListItems(c *gin.Context) {
Page string `json:"page"` type QueryJSON struct {
} Page string `json:"page"`
}
var json QueryJSON
if c.BindJSON(&json) != nil { var json QueryJSON
c.String(http.StatusBadRequest, "Problem binding keys") if c.BindJSON(&json) != nil {
return c.String(http.StatusBadRequest, "Problem binding keys")
} return
p := Open(json.Page) }
if p.IsEncrypted { p := Open(json.Page)
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"}) if p.IsEncrypted {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"})
} return
if p.IsLocked { }
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) if p.IsLocked {
return c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
} return
lines := strings.Split(p.Text.GetCurrent(), "\n") }
newLines := make([]string, len(lines)) lines := strings.Split(p.Text.GetCurrent(), "\n")
newLinesI := 0 newLines := make([]string, len(lines))
for _, line := range lines { newLinesI := 0
if strings.Count(line, "~~") != 2 { for _, line := range lines {
newLines[newLinesI] = line if strings.Count(line, "~~") != 2 {
newLinesI++ newLines[newLinesI] = line
} newLinesI++
} }
p.Update(strings.Join(newLines[0:newLinesI], "\n")) }
p.Save() p.Update(strings.Join(newLines[0:newLinesI], "\n"))
c.JSON(http.StatusOK, gin.H{"success": true, "message": "Cleared"}) p.Save()
} c.JSON(http.StatusOK, gin.H{"success": true, "message": "Cleared"})
}