Skip to content
This repository was archived by the owner on Sep 23, 2021. It is now read-only.

Commit 39531f0

Browse files
authored
Merge pull request #25 from msoedov/restore_session
Restore previous session
2 parents ce0bc91 + d477077 commit 39531f0

File tree

6 files changed

+110
-60
lines changed

6 files changed

+110
-60
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ src/
2525
slides/
2626
main
2727
node_modules
28+
hacker-slides

app_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ func Test(t *testing.T) {
3434
g.Describe("App api", func() {
3535
var cookie string
3636

37-
g.It("Should return 200 on / ", func() {
37+
g.It("Should return 302 on / to redirect to file name ", func() {
3838
w := client("GET", "/", "")
3939

40-
g.Assert(w.Code).Equal(200)
40+
g.Assert(w.Code).Equal(302)
4141
cookie = w.HeaderMap.Get(Cookie)
4242
})
4343

auth/auth.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package auth
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
9+
log "github.com/Sirupsen/logrus"
10+
"github.com/gin-gonic/gin"
11+
)
12+
13+
func Header(c *gin.Context, key string) string {
14+
if values, _ := c.Request.Header[key]; len(values) > 0 {
15+
return values[0]
16+
}
17+
return ""
18+
}
19+
20+
func BasicAuth() gin.HandlerFunc {
21+
realm := "Authorization Required"
22+
realm = "Basic realm=" + strconv.Quote(realm)
23+
user := os.Getenv("USER")
24+
password := os.Getenv("PASSWORD")
25+
enabled := isEnabled(user, password)
26+
if enabled {
27+
log.Warn("Auth mode enabled")
28+
log.Warn(fmt.Sprintf("Visit http://%s:%s@0.0.0.0:8080", user, password))
29+
}
30+
return func(c *gin.Context) {
31+
header := Header(c, "Authorization")
32+
if enabled && header != authorizationHeader(user, password) {
33+
// Credentials doesn't match, we return 401 and abort handlers chain.
34+
c.Header("WWW-Authenticate", realm)
35+
c.AbortWithStatus(401)
36+
return
37+
}
38+
c.Next()
39+
}
40+
}
41+
42+
func isEnabled(user, password string) bool {
43+
switch {
44+
case user == "":
45+
return false
46+
case password == "":
47+
return false
48+
default:
49+
return true
50+
}
51+
}
52+
53+
func authorizationHeader(user, password string) string {
54+
base := user + ":" + password
55+
return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
56+
}

files/query.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package files
2+
3+
import (
4+
"io/ioutil"
5+
"time"
6+
)
7+
8+
var epoch = time.Unix(1494505756, 0)
9+
10+
func LatestFileIn(path string) (latest string) {
11+
files, err := ioutil.ReadDir(path)
12+
if err != nil {
13+
return ""
14+
}
15+
latestTime := epoch
16+
for _, f := range files {
17+
path := f.Name()
18+
pathModifiedAt := f.ModTime()
19+
if pathModifiedAt.After(latestTime) {
20+
latestTime = pathModifiedAt
21+
latest = path
22+
}
23+
}
24+
return
25+
}

main.go

Lines changed: 24 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,24 @@
11
package main
22

33
import (
4-
"encoding/base64"
54
"errors"
65
"fmt"
76
"io/ioutil"
87
"os"
9-
"strconv"
108
"strings"
119

1210
log "github.com/Sirupsen/logrus"
1311
haikunator "github.com/atrox/haikunatorgo"
1412
"github.com/gin-contrib/sessions"
1513
"github.com/gin-gonic/gin"
14+
"github.com/msoedov/hacker-slides/auth"
15+
"github.com/msoedov/hacker-slides/files"
1616
)
1717

1818
const sessionHeader = "slide-session"
1919

20-
func Header(c *gin.Context, key string) string {
21-
if values, _ := c.Request.Header[key]; len(values) > 0 {
22-
return values[0]
23-
}
24-
return ""
25-
}
26-
27-
func BasicAuth() gin.HandlerFunc {
28-
realm := "Authorization Required"
29-
realm = "Basic realm=" + strconv.Quote(realm)
30-
user := os.Getenv("USER")
31-
password := os.Getenv("PASSWORD")
32-
enabled := isEnabled(user, password)
33-
if enabled {
34-
log.Warn("Auth mode enabled")
35-
log.Warn(fmt.Sprintf("Visit http://%s:%s@0.0.0.0:8080", user, password))
36-
}
37-
return func(c *gin.Context) {
38-
header := Header(c, "Authorization")
39-
if enabled && header != authorizationHeader(user, password) {
40-
// Credentials doesn't match, we return 401 and abort handlers chain.
41-
c.Header("WWW-Authenticate", realm)
42-
c.AbortWithStatus(401)
43-
return
44-
}
45-
c.Next()
46-
}
47-
}
48-
49-
func isEnabled(user, password string) bool {
50-
switch {
51-
case user == "":
52-
return false
53-
case password == "":
54-
return false
55-
default:
56-
return true
57-
}
58-
}
59-
60-
func authorizationHeader(user, password string) string {
61-
base := user + ":" + password
62-
return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
20+
func SlidePath(name string) string {
21+
return fmt.Sprintf("slides/%s.md", name)
6322
}
6423

6524
func NewApp() *gin.Engine {
@@ -68,30 +27,38 @@ func NewApp() *gin.Engine {
6827

6928
store := sessions.NewCookieStore([]byte("secret"))
7029
r.Use(sessions.Sessions(sessionHeader, store))
71-
r.Use(BasicAuth())
30+
r.Use(auth.BasicAuth())
7231

7332
r.LoadHTMLGlob("templates/*.tmpl")
7433
r.Static("/static", "./static")
7534

7635
r.GET("/", func(c *gin.Context) {
77-
78-
fname := c.Param("name")
36+
isNew := c.Query("new")
37+
latest := files.LatestFileIn("slides")
7938
log.WithFields(log.Fields{
80-
"name": fname,
81-
}).Info("Restore?")
39+
"name": latest,
40+
"isNew": isNew,
41+
}).Info("Restoring latest point")
42+
43+
var path, name string
44+
if latest == "" || isNew != "" {
45+
haikunator := haikunator.New()
46+
haikunator.TokenLength = 0
47+
name = haikunator.Haikunate()
48+
} else {
49+
name = strings.Replace(latest, ".md", "", 1)
50+
}
51+
path = SlidePath(name)
8252

83-
haikunator := haikunator.New()
84-
haikunator.TokenLength = 0
85-
name := haikunator.Haikunate()
86-
path := fmt.Sprintf("slides/%s.md", name)
8753
log.WithFields(log.Fields{
8854
"path": path,
8955
}).Info("A new session")
9056
session := sessions.Default(c)
9157
session.Set("name", path)
9258
session.Save()
9359

94-
c.HTML(200, "index.tmpl", gin.H{
60+
c.Writer.Header().Set("Location", fmt.Sprintf("/stash/edit/%s", name))
61+
c.HTML(302, "index.tmpl", gin.H{
9562
"pubTo": path,
9663
})
9764
})
@@ -176,7 +143,7 @@ func NewApp() *gin.Engine {
176143
if strings.HasSuffix(name, ".md") {
177144
name = name[0 : len(name)-3]
178145
}
179-
path := fmt.Sprintf("slides/%s.md", name)
146+
path := SlidePath(name)
180147
session := sessions.Default(c)
181148
session.Set("name", path)
182149
session.Save()
@@ -196,7 +163,7 @@ func NewApp() *gin.Engine {
196163
if strings.HasSuffix(name, ".md") {
197164
name = name[0 : len(name)-3]
198165
}
199-
path := fmt.Sprintf("slides/%s.md", name)
166+
path := SlidePath(name)
200167
session := sessions.Default(c)
201168
session.Set("name", path)
202169
session.Save()

templates/index.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
<body>
1515
<div id="edit-pane">
1616
<div id="controls">
17-
<a href="/stash" target="_blank" onclick="save();"> Stash</a> |
17+
<a href="/?new=true" target="_blank" onclick="save();"> New</a> |
18+
<a href="/stash" target="_blank" onclick="save();"> Stash</a> |
1819
<a href="/published/{{ .pubTo}}" target="_blank" onclick="save();"> Present</a> |
1920
<a href="/published/{{ .pubTo}}?print-pdf" target="_blank" onclick="save();"> Pdf</a>
2021
</div>

0 commit comments

Comments
 (0)