diff --git a/photoblog/admin/admin.go b/photoblog/admin/admin.go index 589ed61..044c27d 100644 --- a/photoblog/admin/admin.go +++ b/photoblog/admin/admin.go @@ -1,31 +1,35 @@ package admin import ( + "crypto/hmac" + "crypto/sha256" + "errors" + "fmt" "html/template" + "io/ioutil" + "log" "net/http" + "os" + "path/filepath" "github.com/gorilla/sessions" ) type AuthCookie struct { - Templates *template.Template - Store *sessions.CookieStore + Templates *template.Template + Store *sessions.CookieStore + DataDir *os.File + PasswordSecret string } func (app *AuthCookie) LoginPage(res http.ResponseWriter, req *http.Request) { - formErr := make(map[string]string) + formErr := make(map[string]error) switch req.Method { case "POST": username := req.FormValue("username") - if username == "" { - formErr["username"] = "Empty username" - } - password := req.FormValue("password") - if password == "" { - formErr["password"] = "Empty password" - } - // FIXME verifiy password with file in data dir - if len(formErr) == 0 { + formErr["username"] = app.VerifyUsername(username) + formErr["password"] = app.VerifyPassword(username, req.FormValue("password"), res, req) + if formErr["username"] == nil && formErr["password"] == nil { app.SaveUsername(username, res, req) RedirectHome(res, req) return @@ -39,6 +43,44 @@ func (app *AuthCookie) LogoutPage(res http.ResponseWriter, req *http.Request) { app.SaveUsername("", res, req) RedirectHome(res, req) } +func (app *AuthCookie) VerifyUsername(username string) error { + if username == "" { + return errors.New("Empty username") + } + return nil +} +func (app *AuthCookie) VerifyPassword(username, password string, res http.ResponseWriter, req *http.Request) error { + if password == "" { + return errors.New("Empty password") + } + passfile, err := os.Open(filepath.Join(app.DataDir.Name(), username, ".password")) + if err != nil { + log.Println("Cannot open password file", err) + return errors.New("Authentification failed") + } + defer passfile.Close() + + if username == "" { + return nil + } + expected, err := ioutil.ReadAll(passfile) + if err != nil { + log.Println("Cannot read password file", err) + return errors.New("Authentification failed") + } + expectedStr := string(expected) + var expectedMAC []byte + fmt.Sscanf(expectedStr, "%x", &expectedMAC) + mac := hmac.New(sha256.New, []byte(app.PasswordSecret)) + mac.Write([]byte(password)) + passwordMAC := mac.Sum(nil) + if !hmac.Equal(passwordMAC, expectedMAC) { + log.Printf("Unmatched password for %s: %x - %x\n", username, passwordMAC, expectedMAC) + return errors.New("Authentification failed") + } + log.Printf("Authentification successful") + return nil +} func (app *AuthCookie) CurrentSession(res http.ResponseWriter, req *http.Request) *sessions.Session { session, _ := app.Store.Get(req, "session") return session diff --git a/photoblog/main.go b/photoblog/main.go index 119fbc3..efc645d 100644 --- a/photoblog/main.go +++ b/photoblog/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "html/template" "log" "net/http" @@ -29,20 +28,17 @@ func main() { } defer data.Close() - admin := admin.AuthCookie{ - Templates: tpl, - Store: sessions.NewCookieStore([]byte("flQ6QzM/c3Jtdl9ycDx6OXRIfFgK")), - } app := photo.PhotoBlog{ - AuthCookie: &admin, - Templates: tpl, - DataDir: data, + admin.AuthCookie{Templates: tpl, + Store: sessions.NewCookieStore([]byte("flQ6QzM/c3Jtdl9ycDx6OXRIfFgK")), + DataDir: data, + PasswordSecret: "d2xnNSwoREQhfSxBVDQ0bF0yb2AK", + }, } fileServer := http.FileServer(http.Dir(data.Name())) http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) { - fmt.Println(req.RequestURI) if strings.HasPrefix(req.RequestURI, "/data") { http.StripPrefix("/data/", fileServer).ServeHTTP(res, req) } else { diff --git a/photoblog/photo/photo.go b/photoblog/photo/photo.go index 1fe8dc2..be7cdca 100644 --- a/photoblog/photo/photo.go +++ b/photoblog/photo/photo.go @@ -2,7 +2,6 @@ package photo import ( "fmt" - "html/template" "io" "net/http" "os" @@ -25,8 +24,8 @@ var ( type AppData struct { Username string Photos []string - errors []error - messages []string + Err error + Message string } type TimedFile struct { @@ -47,9 +46,7 @@ func (m timeMap) Swap(i, j int) { } type PhotoBlog struct { - *admin.AuthCookie - Templates *template.Template - DataDir *os.File + admin.AuthCookie } func RedirectHome(res http.ResponseWriter, req *http.Request) { @@ -99,14 +96,16 @@ func (app *PhotoBlog) UploadPage(res http.ResponseWriter, req *http.Request) { RedirectHome(res, req) return } - data := make(map[string]string) + data := AppData{ + Username: app.Username(res, req), + } switch req.Method { case "POST": message, err := app.NewPhoto(res, req) if err != nil { - data["error"] = err.Error() + data.Err = err } - data["message"] = message + data.Message = message fallthrough case "GET": app.Templates.ExecuteTemplate(res, "upload.html", data) diff --git a/photoblog/templates/footer.html b/photoblog/templates/footer.html index b605728..645a773 100644 --- a/photoblog/templates/footer.html +++ b/photoblog/templates/footer.html @@ -1,2 +1,87 @@ + + diff --git a/photoblog/templates/header.html b/photoblog/templates/header.html index ec83884..975f599 100644 --- a/photoblog/templates/header.html +++ b/photoblog/templates/header.html @@ -2,3 +2,16 @@ Photo blog +
+ +
+
diff --git a/photoblog/templates/home.html b/photoblog/templates/home.html index cce94c8..20f90d6 100644 --- a/photoblog/templates/home.html +++ b/photoblog/templates/home.html @@ -1,24 +1,13 @@ -{{ template "header.html" }} -
-{{ if .Username }} -

Hello {{ .Username }}

-Logout -{{ else }} -

You are not logged in

-Login -{{ end }} -

-
-
+{{ template "header.html" . }}

Photo blog

{{ if .Username }} -Add photo -{{ end }} -