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:
parent
f350d0bbad
commit
c64e54a991
98
handlers.go
98
handlers.go
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user