Style, auth with file
This commit is contained in:
parent
ee2bfd95cb
commit
8ec59e4826
@ -1,8 +1,16 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
@ -10,22 +18,18 @@ import (
|
||||
type AuthCookie struct {
|
||||
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
|
||||
|
@ -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,
|
||||
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 {
|
||||
|
@ -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)
|
||||
|
@ -1,2 +1,87 @@
|
||||
</main>
|
||||
</body>
|
||||
<style>
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
ul.photos {
|
||||
list-style-type: none;
|
||||
}
|
||||
img {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
width: 400px;
|
||||
}
|
||||
main {
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
header {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
margin:0;
|
||||
font-family: Verdana,sans-serif;
|
||||
}
|
||||
header ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
header li {
|
||||
float: left;
|
||||
}
|
||||
header p {
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
margin: 0
|
||||
}
|
||||
header a {
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.form-container {
|
||||
border-radius: 5px;
|
||||
background-color: #f2f2f2;
|
||||
padding: 20px;
|
||||
}
|
||||
input[type=submit] {
|
||||
width: 50%;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=submit]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
input[type=text], input[type=password] {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
a.mainlink {
|
||||
color: #4CAF50;
|
||||
}
|
||||
.form-container a {
|
||||
color: #4CAF50;
|
||||
padding-left: 100px;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
|
@ -2,3 +2,16 @@
|
||||
<html>
|
||||
<head><title>Photo blog</title></head>
|
||||
<body>
|
||||
<header>
|
||||
<ul>
|
||||
<li><p>Home</p></li>
|
||||
{{ if .Username }}
|
||||
<li><p>Hello {{ .Username }}</p></li>
|
||||
<li style="float: right"><a href="/logout">Logout</a></li>
|
||||
{{ else }}
|
||||
<li><p>You are not logged in</p></li>
|
||||
<li style="float: right"><a href="/login">Login</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</header>
|
||||
<main>
|
||||
|
@ -1,24 +1,13 @@
|
||||
{{ template "header.html" }}
|
||||
<header>
|
||||
{{ if .Username }}
|
||||
<p>Hello {{ .Username }}</p>
|
||||
<a href="/logout">Logout</a>
|
||||
{{ else }}
|
||||
<p>You are not logged in<p>
|
||||
<a href="/login">Login</a>
|
||||
{{ end }}
|
||||
</header>
|
||||
<div>
|
||||
</div>
|
||||
{{ template "header.html" . }}
|
||||
<h1>Photo blog</h1>
|
||||
{{ if .Username }}
|
||||
<a href="upload">Add photo</a>
|
||||
{{ end }}
|
||||
<ul>
|
||||
{{ range .Photos }}
|
||||
<li><img src="{{ . }}" style="width:320px;height:200px;"></li>
|
||||
{{ else }}
|
||||
<li>No photos</li>
|
||||
<a class="mainlink" href="upload">Add photo</a>
|
||||
{{ end }}
|
||||
<ul class="photos">
|
||||
{{ range .Photos }}
|
||||
<li><a href="{{ . }}"><img src="{{ . }}"></a></li>
|
||||
{{ else }}
|
||||
<li>No photos</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ template "footer.html" }}
|
||||
|
@ -1,16 +1,19 @@
|
||||
{{ template "header.html" }}
|
||||
{{ template "header.html" . }}
|
||||
<h1>Authentification</h1>
|
||||
<form action="/login" method="POST">
|
||||
<div class="form-container">
|
||||
<form action="/login" method="POST">
|
||||
<label>
|
||||
Username: {{ if .username }}<b>{{ .username }}</b>{{ end }}
|
||||
<input type="text" name="username">
|
||||
Username: {{ if .username }}<b class="error">{{ .username }}</b>{{ end }}
|
||||
<input type="text" name="username" placeholder="login...">
|
||||
</label>
|
||||
<br>
|
||||
<label>
|
||||
Password: {{ if .password }}<b>{{ .password }}</b>{{ end }}
|
||||
<input type="password" name="password">
|
||||
Password: {{ if .password }}<b class="error">{{ .password }}</b>{{ end }}
|
||||
<input type="password" name="password" placeholder="password...">
|
||||
</label>
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
<a href="/">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "footer.html" }}
|
||||
|
@ -1,14 +1,16 @@
|
||||
{{ template "header.html" }}
|
||||
{{ template "header.html" . }}
|
||||
<h1>Send photo</h1>
|
||||
<form action="/upload" method="POST" enctype="multipart/form-data">
|
||||
{{ if .message }}<p class="message">{{ .message }}</p>{{ end }}
|
||||
{{ if .error }}<p class="errormsg">{{ .error }}</p>{{ end }}
|
||||
<div class="form-container">
|
||||
<form action="/upload" method="POST" enctype="multipart/form-data">
|
||||
{{ if .Message }}<p class="message">{{ .Message }}</p>{{ end }}
|
||||
{{ if .Err }}<p class="error">{{ .Err }}</p>{{ end }}
|
||||
<label>
|
||||
Select photo: {{ if .file }}<b>{{ .file }}</b>{{ end }}
|
||||
Select photo:
|
||||
<input type="file" name="file">
|
||||
</label>
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
<input type="submit" value="Send">
|
||||
<a href="/">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
{{ template "footer.html" }}
|
||||
|
Loading…
Reference in New Issue
Block a user