implement CSRF per docs - doesnt work. css,js files 404 and get csrf invalid errors on form submit
This commit is contained in:
parent
11c85d110f
commit
1709429e98
6
main.go
6
main.go
|
@ -5,8 +5,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/sessions"
|
|
||||||
"github.com/gorilla/csrf"
|
"github.com/gorilla/csrf"
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -45,7 +45,7 @@ func loadConfig(env string) {
|
||||||
fmt.Println("Error: cannot open config file: config/" + env + ".json")
|
fmt.Println("Error: cannot open config file: config/" + env + ".json")
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
defer file.Close();
|
defer file.Close()
|
||||||
decoder := json.NewDecoder(file)
|
decoder := json.NewDecoder(file)
|
||||||
err = decoder.Decode(&config)
|
err = decoder.Decode(&config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -75,7 +75,7 @@ func csrfSecret() string {
|
||||||
fmt.Println("Error: cannot open csrf-secret.txt (run gen-csrf.sh to generate)")
|
fmt.Println("Error: cannot open csrf-secret.txt (run gen-csrf.sh to generate)")
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
defer file.Close();
|
defer file.Close()
|
||||||
var bytes []byte = make([]byte, 32)
|
var bytes []byte = make([]byte, 32)
|
||||||
n, err := file.Read(bytes)
|
n, err := file.Read(bytes)
|
||||||
if err != nil || n != 32 {
|
if err != nil || n != 32 {
|
||||||
|
|
|
@ -69,7 +69,7 @@ func LoginFormHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
flashes := GetFlashes(session)
|
flashes := GetFlashes(session)
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
|
|
||||||
ShowTemplate("login", w, map[string]interface{}{"flashes": flashes})
|
ShowTemplate("login", w, r, map[string]interface{}{"flashes": flashes})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler for login POST
|
// handler for login POST
|
||||||
|
@ -146,7 +146,7 @@ func addFormHandler(w http.ResponseWriter, r *http.Request, user *user.User, ses
|
||||||
|
|
||||||
popup := r.URL.Query().Get("popup")
|
popup := r.URL.Query().Get("popup")
|
||||||
|
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": url, "categories": categories.CategoriesTree, "title": title, "popup": popup, "category_id": -1})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": url, "categories": categories.CategoriesTree, "title": title, "popup": popup, "category_id": -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func addPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
|
@ -159,8 +159,8 @@ func addPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, ses
|
||||||
category_id, err := strconv.Atoi(r.FormValue("category"))
|
category_id, err := strconv.Atoi(r.FormValue("category"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var flashes = make(map[string]interface{})
|
var flashes = make(map[string]interface{})
|
||||||
flashes["error"] = []string{ "Category required: " +err.Error() }
|
flashes["error"] = []string{"Category required: " + err.Error()}
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": popup, "notes": news.Notes, "category_id": news.Category_id})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": popup, "notes": news.Notes, "category_id": news.Category_id})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
news.Category_id = category_id
|
news.Category_id = category_id
|
||||||
|
@ -168,8 +168,8 @@ func addPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, ses
|
||||||
err = news.Insert(db)
|
err = news.Insert(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var flashes = make(map[string]interface{})
|
var flashes = make(map[string]interface{})
|
||||||
flashes["error"] = []string{ "Error saving news: "+err.Error() }
|
flashes["error"] = []string{"Error saving news: " + err.Error()}
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": popup, "notes": news.Notes, "category_id": news.Category_id})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "add", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": popup, "notes": news.Notes, "category_id": news.Category_id})
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
session.AddFlash("Added news \""+news.Title+"\"", flash_info)
|
session.AddFlash("Added news \""+news.Title+"\"", flash_info)
|
||||||
|
@ -197,14 +197,14 @@ func editFormHandler(w http.ResponseWriter, r *http.Request, user *user.User, se
|
||||||
|
|
||||||
newsItem, err := news.Get(db, id)
|
newsItem, err := news.Get(db, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.AddFlash("Could not load news item " + strconv.Itoa(id), flash_err)
|
session.AddFlash("Could not load news item "+strconv.Itoa(id), flash_err)
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
http.Redirect(w, r, "/news", http.StatusFound)
|
http.Redirect(w, r, "/news", http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "categories": categories.CategoriesTree, "link": newsItem.Url, "title": newsItem.Title, "notes": newsItem.Notes, "popup": false, "category_id": newsItem.Category_id, "id": newsItem.Id()})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "categories": categories.CategoriesTree, "link": newsItem.Url, "title": newsItem.Title, "notes": newsItem.Notes, "popup": false, "category_id": newsItem.Category_id, "id": newsItem.Id()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +233,8 @@ func editPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, se
|
||||||
category_id, err := strconv.Atoi(r.FormValue("category"))
|
category_id, err := strconv.Atoi(r.FormValue("category"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var flashes = make(map[string]interface{})
|
var flashes = make(map[string]interface{})
|
||||||
flashes["error"] = []string{ "Category required: " +err.Error() }
|
flashes["error"] = []string{"Category required: " + err.Error()}
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": false, "notes": news.Notes, "category_id": news.Category_id, "id": news.Id()})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": false, "notes": news.Notes, "category_id": news.Category_id, "id": news.Id()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
news.Category_id = category_id
|
news.Category_id = category_id
|
||||||
|
@ -242,8 +242,8 @@ func editPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, se
|
||||||
err = news.Update(db)
|
err = news.Update(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var flashes = make(map[string]interface{})
|
var flashes = make(map[string]interface{})
|
||||||
flashes["error"] = []string{ "Error saving news: "+err.Error() }
|
flashes["error"] = []string{"Error saving news: " + err.Error()}
|
||||||
ShowTemplate("post", w, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": false, "notes": news.Notes, "category_id": news.Category_id, "id": news.Id()})
|
ShowTemplate("post", w, r, map[string]interface{}{"mode": "edit", "user": user, "flashes": flashes, "link": news.Url, "categories": categories.CategoriesTree, "title": news.Title, "popup": false, "notes": news.Notes, "category_id": news.Category_id, "id": news.Id()})
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
session.AddFlash("Updated news \""+news.Title+"\"", flash_info)
|
session.AddFlash("Updated news \""+news.Title+"\"", flash_info)
|
||||||
|
@ -252,7 +252,6 @@ func editPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func templateFormHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func templateFormHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
flashes := GetFlashes(session)
|
flashes := GetFlashes(session)
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
|
@ -272,7 +271,7 @@ func templateFormHandler(w http.ResponseWriter, r *http.Request, user *user.User
|
||||||
fmt.Println("Exec err: ", err)
|
fmt.Println("Exec err: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowTemplate("export", w, map[string]interface{}{"user": user, "flashes": flashes, "template": &templateBuf, "count": count, "url": config.Url})
|
ShowTemplate("export", w, r, map[string]interface{}{"user": user, "flashes": flashes, "template": &templateBuf, "count": count, "url": config.Url})
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func exportHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
|
@ -290,7 +289,7 @@ func exportHandler(w http.ResponseWriter, r *http.Request, user *user.User, sess
|
||||||
func addedHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func addedHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
flashes := GetFlashes(session)
|
flashes := GetFlashes(session)
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
ShowTemplate("added", w, map[string]interface{}{"user": user, "flashes": flashes})
|
ShowTemplate("added", w, r, map[string]interface{}{"user": user, "flashes": flashes})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func deleteHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
|
@ -316,7 +315,7 @@ func categoriesFormHandler(w http.ResponseWriter, r *http.Request, user *user.Us
|
||||||
session.Save(r, w)
|
session.Save(r, w)
|
||||||
categories.LoadCategories(db)
|
categories.LoadCategories(db)
|
||||||
|
|
||||||
ShowTemplate("categories", w, map[string]interface{}{"user": user, "flashes": flashes, "categories": categories.CategoriesTree})
|
ShowTemplate("categories", w, r, map[string]interface{}{"user": user, "flashes": flashes, "categories": categories.CategoriesTree})
|
||||||
}
|
}
|
||||||
|
|
||||||
func categoriesPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
func categoriesPostHandler(w http.ResponseWriter, r *http.Request, user *user.User, session *sessions.Session) {
|
||||||
|
@ -411,7 +410,7 @@ func newsFormHandler(w http.ResponseWriter, r *http.Request, user *user.User, se
|
||||||
session.AddFlash("Error loading news", flash_err)
|
session.AddFlash("Error loading news", flash_err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowTemplate("news", w, map[string]interface{}{"user": user, "flashes": flashes, "news": news, "count": count, "categories": categories.CategoriesFlat})
|
ShowTemplate("news", w, r, map[string]interface{}{"user": user, "flashes": flashes, "news": news, "count": count, "categories": categories.CategoriesFlat})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,14 +420,13 @@ func ServeFileHandler(res http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init_route_handlers() *mux.Router {
|
func init_route_handlers() *mux.Router {
|
||||||
http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("js/"))))
|
|
||||||
http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("css/"))))
|
|
||||||
http.Handle("/fonts/", http.StripPrefix("/fonts", http.FileServer(http.Dir("fonts/"))))
|
|
||||||
http.HandleFunc("/favicon.ico", ServeFileHandler)
|
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
|
||||||
// TODO: CSRF
|
r.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("js/"))))
|
||||||
|
r.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("css/"))))
|
||||||
|
r.Handle("/fonts/", http.StripPrefix("/fonts", http.FileServer(http.Dir("fonts/"))))
|
||||||
|
r.HandleFunc("/favicon.ico", ServeFileHandler)
|
||||||
|
|
||||||
r.HandleFunc("/login", getPostHandler(LoginFormHandler, LoginPostHandler))
|
r.HandleFunc("/login", getPostHandler(LoginFormHandler, LoginPostHandler))
|
||||||
r.HandleFunc("/logout", userHandler(LogoutHandler))
|
r.HandleFunc("/logout", userHandler(LogoutHandler))
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dballard/transmet/categories"
|
"github.com/dballard/transmet/categories"
|
||||||
|
"github.com/gorilla/csrf"
|
||||||
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -86,7 +88,8 @@ func initTemplates() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShowTemplate(template string, w http.ResponseWriter, data map[string]interface{}) {
|
func ShowTemplate(template string, w http.ResponseWriter, r *http.Request, data map[string]interface{}) {
|
||||||
|
data[csrf.TemplateTag] = csrf.TemplateField(r)
|
||||||
err := templates[template].ExecuteTemplate(w, "layout.html", data)
|
err := templates[template].ExecuteTemplate(w, "layout.html", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Exec err: ", err)
|
fmt.Println("Exec err: ", err)
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
{{template "select-category" dict "categories" .categories "id" -1}}
|
{{template "select-category" dict "categories" .categories "id" -1}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-2">
|
||||||
|
{{ .csrfField }}
|
||||||
<input type="submit" class="add-submit btn btn-primary btn-block" value="Add Category" />
|
<input type="submit" class="add-submit btn btn-primary btn-block" value="Add Category" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -37,6 +38,7 @@ new category select
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<form action="/categories/change-parent?cid={{.category.Id}}" method="POST">
|
<form action="/categories/change-parent?cid={{.category.Id}}" method="POST">
|
||||||
|
{{ .csrfField }}
|
||||||
{{if $.category.Parent.Valid }}
|
{{if $.category.Parent.Valid }}
|
||||||
{{template "select-category" dict "categories" .categories "id" $.category.Parent.Value}}
|
{{template "select-category" dict "categories" .categories "id" $.category.Parent.Value}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
{{template "flashes" .}}
|
{{template "flashes" .}}
|
||||||
<input type="text" class="form-control" name="username" placeholder="Username"/>
|
<input type="text" class="form-control" name="username" placeholder="Username"/>
|
||||||
<input type="password" class="form-control" name="password" placeholder="Password"/>
|
<input type="password" class="form-control" name="password" placeholder="Password"/>
|
||||||
|
{{ .csrfField }}
|
||||||
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Login" />
|
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Login" />
|
||||||
</form>
|
</form>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-2">Notes:</div><div class="col-xs-10"><textarea class="form-control" name="notes" placeholder="Notes" rows="5" cols="80">{{.notes}}</textarea></div>
|
<div class="col-xs-2">Notes:</div><div class="col-xs-10"><textarea class="form-control" name="notes" placeholder="Notes" rows="5" cols="80">{{.notes}}</textarea></div>
|
||||||
<div class="col-xs-2"></div><div class="col-xs-10"><input class="add-submit btn btn-lg btn-primary btn-block" type="submit" value="{{if eq .mode "add"}}Add Link{{else}}Commit Edit{{end}}" /></div>
|
<div class="col-xs-2"></div><div class="col-xs-10">{{ .csrfField }}<input class="add-submit btn btn-lg btn-primary btn-block" type="submit" value="{{if eq .mode "add"}}Add Link{{else}}Commit Edit{{end}}" /></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in New Issue