mirror of
https://github.com/schollz/cowyo.git
synced 2023-08-10 21:13:00 +03:00
Reorganize and add migration
Former-commit-id: 807d525f11b5306c2a4a2e7097a8d92d026fc9df [formerly 9c40fcf478e90dd062c9a173b4d563a4ba15b8bc] [formerly 0c56b23e0782fe14717c243d149983185fe9ad2d [formerly 7f4acdda9a
]]
Former-commit-id: 71ae3d9712ec1b7203e6483ad586aeef319fba08 [formerly e633558e9a7491044e324ceeb2cb699b2130f1c8]
Former-commit-id: 8e483f94bf5c75d62d00219085d1e68c4e5683c7
This commit is contained in:
parent
97edbd73a8
commit
8a7803250f
178
handlers.go
Executable file
178
handlers.go
Executable file
@ -0,0 +1,178 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/static"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func serve() {
|
||||||
|
router := gin.Default()
|
||||||
|
router.LoadHTMLGlob("templates/*")
|
||||||
|
router.Use(static.Serve("/static/", static.LocalFile("./static", true)))
|
||||||
|
|
||||||
|
router.GET("/", func(c *gin.Context) {
|
||||||
|
c.Redirect(302, "/"+randomAlliterateCombo())
|
||||||
|
})
|
||||||
|
router.GET("/:page", func(c *gin.Context) {
|
||||||
|
page := c.Param("page")
|
||||||
|
c.Redirect(302, "/"+page+"/edit")
|
||||||
|
})
|
||||||
|
router.GET("/:page/:command", handlePageRequest)
|
||||||
|
router.POST("/update", handlePageUpdate)
|
||||||
|
router.POST("/prime", handlePrime)
|
||||||
|
router.POST("/lock", handleLock)
|
||||||
|
router.POST("/encrypt", handleEncrypt)
|
||||||
|
|
||||||
|
router.Run(":8050")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePageRequest(c *gin.Context) {
|
||||||
|
page := c.Param("page")
|
||||||
|
command := c.Param("command")
|
||||||
|
version := c.DefaultQuery("version", "ajksldfjl")
|
||||||
|
p := Open(page)
|
||||||
|
if p.IsPrimedForSelfDestruct && !p.IsLocked {
|
||||||
|
p.Update("*This page has now self-destructed.*\n\n" + p.Text.GetCurrent())
|
||||||
|
p.Erase()
|
||||||
|
}
|
||||||
|
if command == "erase" && !p.IsLocked {
|
||||||
|
p.Erase()
|
||||||
|
c.Redirect(302, "/"+page+"/edit")
|
||||||
|
}
|
||||||
|
rawText := p.Text.GetCurrent()
|
||||||
|
rawHTML := p.RenderedPage
|
||||||
|
|
||||||
|
// Check to see if an old version is requested
|
||||||
|
versionInt, versionErr := strconv.Atoi(version)
|
||||||
|
if versionErr == nil && versionInt > 0 {
|
||||||
|
versionText, err := p.Text.GetPreviousByTimestamp(int64(versionInt))
|
||||||
|
if err == nil {
|
||||||
|
rawText = versionText
|
||||||
|
rawHTML = MarkdownToHtml(rawText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.HTML(http.StatusOK, "index.html", gin.H{
|
||||||
|
"EditPage": command == "edit",
|
||||||
|
"ViewPage": command == "view",
|
||||||
|
"ListPage": command == "list",
|
||||||
|
"HistoryPage": command == "history",
|
||||||
|
"Page": p.Name,
|
||||||
|
"RenderedPage": template.HTML([]byte(rawHTML)),
|
||||||
|
"RawPage": rawText,
|
||||||
|
"Versions": p.Text.GetSnapshots(),
|
||||||
|
"IsLocked": p.IsLocked,
|
||||||
|
"IsEncrypted": p.IsEncrypted,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePageUpdate(c *gin.Context) {
|
||||||
|
type QueryJSON struct {
|
||||||
|
Page string `json:"page"`
|
||||||
|
NewText string `json:"new_text"`
|
||||||
|
}
|
||||||
|
var json QueryJSON
|
||||||
|
if c.BindJSON(&json) != nil {
|
||||||
|
c.String(http.StatusBadRequest, "Problem binding keys")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("Update: %v", json)
|
||||||
|
p := Open(json.Page)
|
||||||
|
var message string
|
||||||
|
if p.IsLocked {
|
||||||
|
message = "Locked"
|
||||||
|
} else if p.IsEncrypted {
|
||||||
|
message = "Encrypted"
|
||||||
|
} else {
|
||||||
|
p.Update(json.NewText)
|
||||||
|
p.Save()
|
||||||
|
message = "Saved"
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": false, "message": message})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePrime(c *gin.Context) {
|
||||||
|
type QueryJSON struct {
|
||||||
|
Page string `json:"page"`
|
||||||
|
}
|
||||||
|
var json QueryJSON
|
||||||
|
if c.BindJSON(&json) != nil {
|
||||||
|
c.String(http.StatusBadRequest, "Problem binding keys")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("Update: %v", json)
|
||||||
|
p := Open(json.Page)
|
||||||
|
p.IsPrimedForSelfDestruct = true
|
||||||
|
p.Save()
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleLock(c *gin.Context) {
|
||||||
|
type QueryJSON struct {
|
||||||
|
Page string `json:"page"`
|
||||||
|
Passphrase string `json:"passphrase"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var json QueryJSON
|
||||||
|
if c.BindJSON(&json) != nil {
|
||||||
|
c.String(http.StatusBadRequest, "Problem binding keys")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p := Open(json.Page)
|
||||||
|
var message string
|
||||||
|
if p.IsLocked {
|
||||||
|
err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.IsLocked = false
|
||||||
|
message = "Unlocked"
|
||||||
|
} else {
|
||||||
|
p.IsLocked = true
|
||||||
|
p.PassphraseToUnlock = HashPassword(json.Passphrase)
|
||||||
|
message = "Locked"
|
||||||
|
}
|
||||||
|
p.Save()
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEncrypt(c *gin.Context) {
|
||||||
|
type QueryJSON struct {
|
||||||
|
Page string `json:"page"`
|
||||||
|
Passphrase string `json:"passphrase"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var json QueryJSON
|
||||||
|
if c.BindJSON(&json) != nil {
|
||||||
|
c.String(http.StatusBadRequest, "Problem binding keys")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p := Open(json.Page)
|
||||||
|
var message string
|
||||||
|
if p.IsEncrypted {
|
||||||
|
decrypted, err2 := DecryptString(p.Text.GetCurrent(), json.Passphrase)
|
||||||
|
if err2 != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong password"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Erase()
|
||||||
|
p = Open(json.Page)
|
||||||
|
p.Update(decrypted)
|
||||||
|
p.IsEncrypted = false
|
||||||
|
message = "Decrypted"
|
||||||
|
} else {
|
||||||
|
currentText := p.Text.GetCurrent()
|
||||||
|
p.Erase()
|
||||||
|
p = Open(json.Page)
|
||||||
|
p.IsEncrypted = true
|
||||||
|
encrypted, _ := EncryptString(currentText, json.Passphrase)
|
||||||
|
p.Update(encrypted)
|
||||||
|
message = "Encrypted"
|
||||||
|
}
|
||||||
|
p.Save()
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
|
||||||
|
}
|
234
main.go
234
main.go
@ -1,178 +1,76 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"fmt"
|
||||||
"net/http"
|
"os"
|
||||||
"strconv"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-contrib/static"
|
"gopkg.in/urfave/cli.v1"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var version string
|
||||||
|
var pathToData string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
router := gin.Default()
|
app := cli.NewApp()
|
||||||
router.LoadHTMLGlob("templates/*")
|
app.Name = "linkcrawler"
|
||||||
router.Use(static.Serve("/static/", static.LocalFile("./static", true)))
|
app.Usage = "crawl a site for links, or download a list of sites"
|
||||||
|
app.Version = version
|
||||||
|
app.Compiled = time.Now()
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
cli.ShowSubcommandHelp(c)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "data",
|
||||||
|
Value: "data",
|
||||||
|
Usage: "data folder to use",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "olddata",
|
||||||
|
Value: "",
|
||||||
|
Usage: "data folder for migrating",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "debug, d",
|
||||||
|
Usage: "turn on debugging",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "serve",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Usage: "start a cowyo server",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
pathToData = c.GlobalString("data")
|
||||||
|
os.MkdirAll(pathToData, 0755)
|
||||||
|
serve()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "migrate",
|
||||||
|
Aliases: []string{"m"},
|
||||||
|
Usage: "migrate from the old cowyo",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
pathToData = c.GlobalString("data")
|
||||||
|
pathToOldData := c.GlobalString("olddata")
|
||||||
|
if len(pathToOldData) == 0 {
|
||||||
|
fmt.Printf("You need to specify folder with -olddata")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
os.MkdirAll(pathToData, 0755)
|
||||||
|
if !exists(pathToOldData) {
|
||||||
|
fmt.Printf("Can not find '%s', does it exist?", pathToOldData)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
migrate(pathToOldData, pathToData)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
router.GET("/", func(c *gin.Context) {
|
app.Run(os.Args)
|
||||||
c.Redirect(302, "/"+randomAlliterateCombo())
|
|
||||||
})
|
|
||||||
router.GET("/:page", func(c *gin.Context) {
|
|
||||||
page := c.Param("page")
|
|
||||||
c.Redirect(302, "/"+page+"/edit")
|
|
||||||
})
|
|
||||||
router.GET("/:page/:command", handlePageRequest)
|
|
||||||
router.POST("/update", handlePageUpdate)
|
|
||||||
router.POST("/prime", handlePrime)
|
|
||||||
router.POST("/lock", handleLock)
|
|
||||||
router.POST("/encrypt", handleEncrypt)
|
|
||||||
|
|
||||||
router.Run(":8050")
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePageRequest(c *gin.Context) {
|
|
||||||
page := c.Param("page")
|
|
||||||
command := c.Param("command")
|
|
||||||
version := c.DefaultQuery("version", "ajksldfjl")
|
|
||||||
p := Open(page)
|
|
||||||
if p.IsPrimedForSelfDestruct && !p.IsLocked {
|
|
||||||
p.Update("*This page has now self-destructed.*\n\n" + p.Text.GetCurrent())
|
|
||||||
p.Erase()
|
|
||||||
}
|
|
||||||
if command == "erase" && !p.IsLocked {
|
|
||||||
p.Erase()
|
|
||||||
c.Redirect(302, "/"+page+"/edit")
|
|
||||||
}
|
|
||||||
rawText := p.Text.GetCurrent()
|
|
||||||
rawHTML := p.RenderedPage
|
|
||||||
|
|
||||||
// Check to see if an old version is requested
|
|
||||||
versionInt, versionErr := strconv.Atoi(version)
|
|
||||||
if versionErr == nil && versionInt > 0 {
|
|
||||||
versionText, err := p.Text.GetPreviousByTimestamp(int64(versionInt))
|
|
||||||
if err == nil {
|
|
||||||
rawText = versionText
|
|
||||||
rawHTML = MarkdownToHtml(rawText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.HTML(http.StatusOK, "index.html", gin.H{
|
|
||||||
"EditPage": command == "edit",
|
|
||||||
"ViewPage": command == "view",
|
|
||||||
"ListPage": command == "list",
|
|
||||||
"HistoryPage": command == "history",
|
|
||||||
"Page": p.Name,
|
|
||||||
"RenderedPage": template.HTML([]byte(rawHTML)),
|
|
||||||
"RawPage": rawText,
|
|
||||||
"Versions": p.Text.GetSnapshots(),
|
|
||||||
"IsLocked": p.IsLocked,
|
|
||||||
"IsEncrypted": p.IsEncrypted,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePageUpdate(c *gin.Context) {
|
|
||||||
type QueryJSON struct {
|
|
||||||
Page string `json:"page"`
|
|
||||||
NewText string `json:"new_text"`
|
|
||||||
}
|
|
||||||
var json QueryJSON
|
|
||||||
if c.BindJSON(&json) != nil {
|
|
||||||
c.String(http.StatusBadRequest, "Problem binding keys")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Trace("Update: %v", json)
|
|
||||||
p := Open(json.Page)
|
|
||||||
var message string
|
|
||||||
if p.IsLocked {
|
|
||||||
message = "Locked"
|
|
||||||
} else if p.IsEncrypted {
|
|
||||||
message = "Encrypted"
|
|
||||||
} else {
|
|
||||||
p.Update(json.NewText)
|
|
||||||
p.Save()
|
|
||||||
message = "Saved"
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": false, "message": message})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePrime(c *gin.Context) {
|
|
||||||
type QueryJSON struct {
|
|
||||||
Page string `json:"page"`
|
|
||||||
}
|
|
||||||
var json QueryJSON
|
|
||||||
if c.BindJSON(&json) != nil {
|
|
||||||
c.String(http.StatusBadRequest, "Problem binding keys")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Trace("Update: %v", json)
|
|
||||||
p := Open(json.Page)
|
|
||||||
p.IsPrimedForSelfDestruct = true
|
|
||||||
p.Save()
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleLock(c *gin.Context) {
|
|
||||||
type QueryJSON struct {
|
|
||||||
Page string `json:"page"`
|
|
||||||
Passphrase string `json:"passphrase"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var json QueryJSON
|
|
||||||
if c.BindJSON(&json) != nil {
|
|
||||||
c.String(http.StatusBadRequest, "Problem binding keys")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p := Open(json.Page)
|
|
||||||
var message string
|
|
||||||
if p.IsLocked {
|
|
||||||
err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock)
|
|
||||||
if err2 != nil {
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.IsLocked = false
|
|
||||||
message = "Unlocked"
|
|
||||||
} else {
|
|
||||||
p.IsLocked = true
|
|
||||||
p.PassphraseToUnlock = HashPassword(json.Passphrase)
|
|
||||||
message = "Locked"
|
|
||||||
}
|
|
||||||
p.Save()
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleEncrypt(c *gin.Context) {
|
|
||||||
type QueryJSON struct {
|
|
||||||
Page string `json:"page"`
|
|
||||||
Passphrase string `json:"passphrase"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var json QueryJSON
|
|
||||||
if c.BindJSON(&json) != nil {
|
|
||||||
c.String(http.StatusBadRequest, "Problem binding keys")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p := Open(json.Page)
|
|
||||||
var message string
|
|
||||||
if p.IsEncrypted {
|
|
||||||
decrypted, err2 := DecryptString(p.Text.GetCurrent(), json.Passphrase)
|
|
||||||
if err2 != nil {
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Wrong password"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Erase()
|
|
||||||
p = Open(json.Page)
|
|
||||||
p.Update(decrypted)
|
|
||||||
p.IsEncrypted = false
|
|
||||||
message = "Decrypted"
|
|
||||||
} else {
|
|
||||||
currentText := p.Text.GetCurrent()
|
|
||||||
p.Erase()
|
|
||||||
p = Open(json.Page)
|
|
||||||
p.IsEncrypted = true
|
|
||||||
encrypted, _ := EncryptString(currentText, json.Passphrase)
|
|
||||||
p.Update(encrypted)
|
|
||||||
message = "Encrypted"
|
|
||||||
}
|
|
||||||
p.Save()
|
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
|
|
||||||
}
|
}
|
||||||
|
25
migrate.go
Executable file
25
migrate.go
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func migrate(pathToOldData, pathToData string) error {
|
||||||
|
files, _ := ioutil.ReadDir(pathToOldData)
|
||||||
|
for _, f := range files {
|
||||||
|
fmt.Printf("Migrating %s", f.Name())
|
||||||
|
p := Open(f.Name())
|
||||||
|
bData, err := ioutil.ReadFile(path.Join(pathToOldData, f.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = p.Update(string(bData))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Save()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
6
page.go
6
page.go
@ -12,12 +12,6 @@ import (
|
|||||||
"github.com/schollz/versionedtext"
|
"github.com/schollz/versionedtext"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pathToData = "data"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
os.MkdirAll(pathToData, 0755)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
Name string
|
Name string
|
||||||
Text versionedtext.VersionedText
|
Text versionedtext.VersionedText
|
||||||
|
13
utils.go
13
utils.go
@ -7,6 +7,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -201,3 +202,15 @@ func DecryptString(toDecrypt string, password string) (string, error) {
|
|||||||
bDecrypted, err := cryptopasta.Decrypt(contentData, &key)
|
bDecrypted, err := cryptopasta.Decrypt(contentData, &key)
|
||||||
return string(bDecrypted), err
|
return string(bDecrypted), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exists returns whether the given file or directory exists or not
|
||||||
|
func exists(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user