From e72437eff82197f156659144eb024ed130aa485e Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:01:02 -0500 Subject: [PATCH 1/8] Add files utils --- files/query.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 files/query.go diff --git a/files/query.go b/files/query.go new file mode 100644 index 0000000..060474f --- /dev/null +++ b/files/query.go @@ -0,0 +1,25 @@ +package files + +import ( + "io/ioutil" + "time" +) + +var epoch = time.Unix(1494505756, 0) + +func LatestFileIn(path string) (latest string) { + files, err := ioutil.ReadDir(path) + if err != nil { + return "" + } + latestTime := epoch + for _, f := range files { + path := f.Name() + pathModifiedAt := f.ModTime() + if pathModifiedAt.After(latestTime) { + latestTime = pathModifiedAt + latest = path + } + } + return +} From 4e0b63b38ba0e356c7eba9bfbaad70319a3b1142 Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:01:16 -0500 Subject: [PATCH 2/8] Changed session logic --- main.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 39707ac..1ff7682 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( haikunator "github.com/atrox/haikunatorgo" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" + "github.com/msoedov/hacker-slides/files" ) const sessionHeader = "slide-session" @@ -75,15 +76,23 @@ func NewApp() *gin.Engine { r.GET("/", func(c *gin.Context) { - fname := c.Param("name") + latest := files.LatestFileIn("slides") log.WithFields(log.Fields{ - "name": fname, - }).Info("Restore?") + "name": latest, + }).Info("Restoring latest point") + + var path string + if latest == "" { + haikunator := haikunator.New() + haikunator.TokenLength = 0 + name := haikunator.Haikunate() + path = fmt.Sprintf("slides/%s.md", name) + } else { + name := latest + path = fmt.Sprintf("slides/%s", name) + + } - haikunator := haikunator.New() - haikunator.TokenLength = 0 - name := haikunator.Haikunate() - path := fmt.Sprintf("slides/%s.md", name) log.WithFields(log.Fields{ "path": path, }).Info("A new session") From f6dc3a04e3a9f425507f77eb7f6eaafb32d60f1b Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:15:19 -0500 Subject: [PATCH 3/8] Test for redirect --- app_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app_test.go b/app_test.go index c6edb76..1a85d7d 100644 --- a/app_test.go +++ b/app_test.go @@ -34,10 +34,10 @@ func Test(t *testing.T) { g.Describe("App api", func() { var cookie string - g.It("Should return 200 on / ", func() { + g.It("Should return 302 on / to redirect to file name ", func() { w := client("GET", "/", "") - g.Assert(w.Code).Equal(200) + g.Assert(w.Code).Equal(302) cookie = w.HeaderMap.Get(Cookie) }) From a2c5c788d212a600f760d6829770ad24b77b501f Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:15:34 -0500 Subject: [PATCH 4/8] Add new slide btn --- templates/index.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/index.tmpl b/templates/index.tmpl index d607b1f..8da3312 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -14,7 +14,8 @@
From d844211d220f0a9a254d5c5eb13dac7f5e693df0 Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:15:44 -0500 Subject: [PATCH 5/8] Change / logic --- main.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index 1ff7682..92acc86 100644 --- a/main.go +++ b/main.go @@ -75,23 +75,22 @@ func NewApp() *gin.Engine { r.Static("/static", "./static") r.GET("/", func(c *gin.Context) { - + isNew := c.Query("new") latest := files.LatestFileIn("slides") log.WithFields(log.Fields{ - "name": latest, + "name": latest, + "isNew": isNew, }).Info("Restoring latest point") - var path string - if latest == "" { + var path, name string + if latest == "" || isNew != "" { haikunator := haikunator.New() haikunator.TokenLength = 0 - name := haikunator.Haikunate() - path = fmt.Sprintf("slides/%s.md", name) + name = haikunator.Haikunate() } else { - name := latest - path = fmt.Sprintf("slides/%s", name) - + name = strings.Replace(latest, ".md", "", 1) } + path = fmt.Sprintf("slides/%s.md", name) log.WithFields(log.Fields{ "path": path, @@ -100,7 +99,8 @@ func NewApp() *gin.Engine { session.Set("name", path) session.Save() - c.HTML(200, "index.tmpl", gin.H{ + c.Writer.Header().Set("Location", fmt.Sprintf("/stash/edit/%s", name)) + c.HTML(302, "index.tmpl", gin.H{ "pubTo": path, }) }) From 0a5d7931e4cc7514e63e18b31e8954eca3ce02be Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:18:50 -0500 Subject: [PATCH 6/8] Add Path function --- main.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 92acc86..6669046 100644 --- a/main.go +++ b/main.go @@ -63,6 +63,10 @@ func authorizationHeader(user, password string) string { return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) } +func SlidePath(name string) string { + return fmt.Sprintf("slides/%s.md", name) +} + func NewApp() *gin.Engine { r := gin.Default() @@ -90,7 +94,7 @@ func NewApp() *gin.Engine { } else { name = strings.Replace(latest, ".md", "", 1) } - path = fmt.Sprintf("slides/%s.md", name) + path = SlidePath(name) log.WithFields(log.Fields{ "path": path, @@ -185,7 +189,7 @@ func NewApp() *gin.Engine { if strings.HasSuffix(name, ".md") { name = name[0 : len(name)-3] } - path := fmt.Sprintf("slides/%s.md", name) + path := SlidePath(name) session := sessions.Default(c) session.Set("name", path) session.Save() @@ -205,7 +209,7 @@ func NewApp() *gin.Engine { if strings.HasSuffix(name, ".md") { name = name[0 : len(name)-3] } - path := fmt.Sprintf("slides/%s.md", name) + path := SlidePath(name) session := sessions.Default(c) session.Set("name", path) session.Save() From 2be7f11e572f67bb438394ca8b545c5f61075040 Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:22:15 -0500 Subject: [PATCH 7/8] Auth module --- auth/auth.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 50 ++-------------------------------------------- 2 files changed, 58 insertions(+), 48 deletions(-) create mode 100644 auth/auth.go diff --git a/auth/auth.go b/auth/auth.go new file mode 100644 index 0000000..c384a40 --- /dev/null +++ b/auth/auth.go @@ -0,0 +1,56 @@ +package auth + +import ( + "encoding/base64" + "fmt" + "os" + "strconv" + + log "github.com/Sirupsen/logrus" + "github.com/gin-gonic/gin" +) + +func Header(c *gin.Context, key string) string { + if values, _ := c.Request.Header[key]; len(values) > 0 { + return values[0] + } + return "" +} + +func BasicAuth() gin.HandlerFunc { + realm := "Authorization Required" + realm = "Basic realm=" + strconv.Quote(realm) + user := os.Getenv("USER") + password := os.Getenv("PASSWORD") + enabled := isEnabled(user, password) + if enabled { + log.Warn("Auth mode enabled") + log.Warn(fmt.Sprintf("Visit http://%s:%s@0.0.0.0:8080", user, password)) + } + return func(c *gin.Context) { + header := Header(c, "Authorization") + if enabled && header != authorizationHeader(user, password) { + // Credentials doesn't match, we return 401 and abort handlers chain. + c.Header("WWW-Authenticate", realm) + c.AbortWithStatus(401) + return + } + c.Next() + } +} + +func isEnabled(user, password string) bool { + switch { + case user == "": + return false + case password == "": + return false + default: + return true + } +} + +func authorizationHeader(user, password string) string { + base := user + ":" + password + return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) +} diff --git a/main.go b/main.go index 6669046..1f6ca11 100644 --- a/main.go +++ b/main.go @@ -1,68 +1,22 @@ package main import ( - "encoding/base64" "errors" "fmt" "io/ioutil" "os" - "strconv" "strings" log "github.com/Sirupsen/logrus" haikunator "github.com/atrox/haikunatorgo" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" + "github.com/msoedov/hacker-slides/auth" "github.com/msoedov/hacker-slides/files" ) const sessionHeader = "slide-session" -func Header(c *gin.Context, key string) string { - if values, _ := c.Request.Header[key]; len(values) > 0 { - return values[0] - } - return "" -} - -func BasicAuth() gin.HandlerFunc { - realm := "Authorization Required" - realm = "Basic realm=" + strconv.Quote(realm) - user := os.Getenv("USER") - password := os.Getenv("PASSWORD") - enabled := isEnabled(user, password) - if enabled { - log.Warn("Auth mode enabled") - log.Warn(fmt.Sprintf("Visit http://%s:%s@0.0.0.0:8080", user, password)) - } - return func(c *gin.Context) { - header := Header(c, "Authorization") - if enabled && header != authorizationHeader(user, password) { - // Credentials doesn't match, we return 401 and abort handlers chain. - c.Header("WWW-Authenticate", realm) - c.AbortWithStatus(401) - return - } - c.Next() - } -} - -func isEnabled(user, password string) bool { - switch { - case user == "": - return false - case password == "": - return false - default: - return true - } -} - -func authorizationHeader(user, password string) string { - base := user + ":" + password - return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) -} - func SlidePath(name string) string { return fmt.Sprintf("slides/%s.md", name) } @@ -73,7 +27,7 @@ func NewApp() *gin.Engine { store := sessions.NewCookieStore([]byte("secret")) r.Use(sessions.Sessions(sessionHeader, store)) - r.Use(BasicAuth()) + r.Use(auth.BasicAuth()) r.LoadHTMLGlob("templates/*.tmpl") r.Static("/static", "./static") From d477077c932756bb2097011b9f93b36fcc6a06c2 Mon Sep 17 00:00:00 2001 From: Alex Myasoedov Date: Thu, 18 Jan 2018 20:22:24 -0500 Subject: [PATCH 8/8] Gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4fae73f..1479763 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ src/ slides/ main node_modules +hacker-slides