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

Lock page with respect to session

This commit is contained in:
Tomas Peterka 2018-03-11 23:46:29 +01:00
parent f350d0bbad
commit c64e54a991
2 changed files with 77 additions and 24 deletions

View File

@ -22,6 +22,8 @@ import (
"github.com/schollz/cowyo/encrypt" "github.com/schollz/cowyo/encrypt"
) )
const minutesToUnlock = 10.0
var customCSS []byte var customCSS []byte
var defaultLock string var defaultLock string
var debounceTime int var debounceTime int
@ -169,6 +171,13 @@ func loadTemplates(list ...string) multitemplate.Render {
return r return r
} }
func pageIsLocked(p *Page, c *gin.Context) bool {
// it is easier to reason about when the page is actually unlocked
var unlocked = !p.IsLocked ||
(p.IsLocked && p.UnlockedFor == getSetSessionID(c))
return !unlocked
}
func handlePageRelinquish(c *gin.Context) { func handlePageRelinquish(c *gin.Context) {
type QueryJSON struct { type QueryJSON struct {
Page string `json:"page"` Page string `json:"page"`
@ -191,10 +200,10 @@ func handlePageRelinquish(c *gin.Context) {
name = json.Page name = json.Page
} }
text := p.Text.GetCurrent() text := p.Text.GetCurrent()
isLocked := p.IsEncrypted isLocked := pageIsLocked(p, c)
isEncrypted := p.IsEncrypted isEncrypted := p.IsEncrypted
destroyed := p.IsPrimedForSelfDestruct destroyed := p.IsPrimedForSelfDestruct
if !p.IsLocked && p.IsPrimedForSelfDestruct { if !isLocked && p.IsPrimedForSelfDestruct {
p.Erase() p.Erase()
message = "Relinquished and erased" message = "Relinquished and erased"
} }
@ -207,6 +216,22 @@ func handlePageRelinquish(c *gin.Context) {
"destroyed": destroyed}) "destroyed": destroyed})
} }
func getSetSessionID(c *gin.Context) (sid string) {
var (
session = sessions.Default(c)
v = session.Get("sid")
)
if v != nil {
sid = v.(string)
}
if v == nil || sid == "" {
sid = RandStringBytesMaskImprSrc(8)
session.Set("sid", sid)
session.Save()
}
return sid
}
func thread_SiteMap() { func thread_SiteMap() {
for { for {
log.Info("Generating sitemap...") log.Info("Generating sitemap...")
@ -307,23 +332,24 @@ func handlePageRequest(c *gin.Context) {
return return
} }
version := c.DefaultQuery("version", "ajksldfjl")
// use the default lock // use the default lock
if defaultLock != "" && p.IsNew() { if defaultLock != "" && p.IsNew() {
p.IsLocked = true p.IsLocked = true
p.PassphraseToUnlock = defaultLock p.PassphraseToUnlock = defaultLock
} }
version := c.DefaultQuery("version", "ajksldfjl")
isLocked := pageIsLocked(p, c)
// Disallow anything but viewing locked/encrypted pages // Disallow anything but viewing locked/encrypted pages
if (p.IsEncrypted || p.IsLocked) && if (p.IsEncrypted || isLocked) &&
(command[0:2] != "/v" && command[0:2] != "/r") { (command[0:2] != "/v" && command[0:2] != "/r") {
c.Redirect(302, "/"+page+"/view") c.Redirect(302, "/"+page+"/view")
return return
} }
// Destroy page if it is opened and primed // Destroy page if it is opened and primed
if p.IsPrimedForSelfDestruct && !p.IsLocked && !p.IsEncrypted { if p.IsPrimedForSelfDestruct && !isLocked && !p.IsEncrypted {
p.Update("<center><em>This page has self-destructed. You cannot return to it.</em></center>\n\n" + p.Text.GetCurrent()) p.Update("<center><em>This page has self-destructed. You cannot return to it.</em></center>\n\n" + p.Text.GetCurrent())
p.Erase() p.Erase()
if p.IsPublished { if p.IsPublished {
@ -333,7 +359,7 @@ func handlePageRequest(c *gin.Context) {
} }
} }
if command == "/erase" { if command == "/erase" {
if !p.IsLocked && !p.IsEncrypted { if !isLocked && !p.IsEncrypted {
p.Erase() p.Erase()
c.Redirect(302, "/"+page+"/edit") c.Redirect(302, "/"+page+"/edit")
} else { } else {
@ -410,7 +436,7 @@ func handlePageRequest(c *gin.Context) {
"Versions": versionsInt64, "Versions": versionsInt64,
"VersionsText": versionsText, "VersionsText": versionsText,
"VersionsChangeSums": versionsChangeSums, "VersionsChangeSums": versionsChangeSums,
"IsLocked": p.IsLocked, "IsLocked": isLocked,
"IsEncrypted": p.IsEncrypted, "IsEncrypted": p.IsEncrypted,
"ListItems": renderList(rawText), "ListItems": renderList(rawText),
"Route": "/" + page + command, "Route": "/" + page + command,
@ -506,10 +532,19 @@ func handlePageUpdate(c *gin.Context) {
} }
log.Trace("Update: %v", json) log.Trace("Update: %v", json)
p := Open(json.Page) p := Open(json.Page)
var message string var (
message string
sinceLastEdit = time.Since(p.LastEditTime())
)
success := false success := false
if p.IsLocked { if pageIsLocked(p, c) {
if sinceLastEdit < minutesToUnlock {
message = "This page is being edited by someone else"
} else {
// here what might have happened is that two people unlock without
// editing thus they both suceeds but only one is able to edit
message = "Locked, must unlock first" message = "Locked, must unlock first"
}
} else if p.IsEncrypted { } else if p.IsEncrypted {
message = "Encrypted, must decrypt first" message = "Encrypted, must decrypt first"
} else if json.FetchedAt > 0 && p.LastEditUnixTime() > json.FetchedAt { } else if json.FetchedAt > 0 && p.LastEditUnixTime() > json.FetchedAt {
@ -541,7 +576,7 @@ func handlePrime(c *gin.Context) {
} }
log.Trace("Update: %v", json) log.Trace("Update: %v", json)
p := Open(json.Page) p := Open(json.Page)
if p.IsLocked { if pageIsLocked(p, c) {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
return return
} else if p.IsEncrypted { } else if p.IsEncrypted {
@ -566,7 +601,7 @@ func handleLock(c *gin.Context) {
} }
p := Open(json.Page) p := Open(json.Page)
if defaultLock != "" && p.IsNew() { if defaultLock != "" && p.IsNew() {
p.IsLocked = true p.IsLocked = true // IsLocked was replaced by variable wrt Context
p.PassphraseToUnlock = defaultLock p.PassphraseToUnlock = defaultLock
} }
@ -574,21 +609,38 @@ func handleLock(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"})
return return
} }
var message string var (
if p.IsLocked { message string
sessionID = getSetSessionID(c)
sinceLastEdit = time.Since(p.LastEditTime())
)
// both lock/unlock ends here on locked&timeout combination
if p.IsLocked &&
p.UnlockedFor != sessionID &&
p.UnlockedFor != "" &&
sinceLastEdit.Minutes() < minutesToUnlock {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": fmt.Sprintf("This page is being edited by someone else! Will unlock automatically %2.0f minutes after the last change.", minutesToUnlock-sinceLastEdit.Minutes()),
})
return
}
if !pageIsLocked(p, c) {
p.IsLocked = true
p.PassphraseToUnlock = HashPassword(json.Passphrase)
p.UnlockedFor = ""
message = "Locked"
} else {
err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock) err2 := CheckPasswordHash(json.Passphrase, p.PassphraseToUnlock)
if err2 != nil { if err2 != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Can't unlock"})
return return
} }
p.IsLocked = false p.UnlockedFor = sessionID
message = "Unlocked" message = "Unlocked only for you"
} else {
p.IsLocked = true
p.PassphraseToUnlock = HashPassword(json.Passphrase)
message = "Locked"
} }
fmt.Println(p)
p.Save() p.Save()
c.JSON(http.StatusOK, gin.H{"success": true, "message": message}) c.JSON(http.StatusOK, gin.H{"success": true, "message": message})
} }
@ -665,7 +717,7 @@ func handleEncrypt(c *gin.Context) {
return return
} }
p := Open(json.Page) p := Open(json.Page)
if p.IsLocked { if pageIsLocked(p, c) {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
return return
} }
@ -749,7 +801,7 @@ func handleClearOldListItems(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Encrypted"})
return return
} }
if p.IsLocked { if pageIsLocked(p, c) {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"}) c.JSON(http.StatusOK, gin.H{"success": false, "message": "Locked"})
return return
} }

View File

@ -26,6 +26,7 @@ type Page struct {
IsEncrypted bool IsEncrypted bool
IsPrimedForSelfDestruct bool IsPrimedForSelfDestruct bool
IsPublished bool IsPublished bool
UnlockedFor string
} }
func (p Page) LastEditTime() time.Time { func (p Page) LastEditTime() time.Time {