@@ 1,6 1,7 @@
package main
import (
+ b64 "encoding/base64"
"fmt"
"html"
"html/template"
@@ 8,6 9,7 @@ import (
"log"
"math/rand"
"net/http"
+ "net/url"
"os"
"path/filepath"
"regexp"
@@ 16,15 18,115 @@ import (
"strings"
"time"
+ "github.com/dgrijalva/jwt-go"
"github.com/gernest/front"
"github.com/gorilla/mux"
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
+ "golang.org/x/crypto/bcrypt"
+ "gopkg.in/yaml.v2"
)
+var SECRET_KEY = []byte(os.Getenv("JWT_TOKEN"))
+
+var redir string
+
+type Credentials struct {
+ Username string `yaml:"username"`
+ Password string `yaml:"password"`
+}
+
+type Claims struct {
+ Username string `json:"username"`
+ Name string `json:"name"`
+ Email string `json:"email"`
+ Status string `jsoin:"status"`
+ Auth bool `json:"authenticated"`
+ jwt.StandardClaims
+}
+
+type UserInfo struct {
+ Username string `yaml:"username"`
+ Name string `yaml:"name"`
+ Email string `yaml:"email"`
+ Social string `yaml:"social"`
+ Homepage string `yaml:"homepage"`
+ Git string `yaml:"git"`
+ Status string `yaml:"status"`
+ Auth bool
+}
+
+type Data struct {
+ UserInfo UserInfo
+ Comments []Comment
+ Submissions []Submission
+ Error ReturnError
+}
+
+type ReturnError struct {
+ Title string
+ Body template.HTML
+ Auth bool
+}
+
var NotImplemented = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- tmpl := template.Must(template.New("not.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseFiles("not.html"))
- err := tmpl.ExecuteTemplate(w, "not.html", nil)
+ userInfo := getLoggedInInfo(r)
+ tmpl := template.Must(template.New("not.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ returnedData := Data{
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ },
+ }
+ err := tmpl.ExecuteTemplate(w, "not.html", returnedData)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+})
+
+func getLoggedInInfo(r *http.Request) UserInfo {
+ cookie, _ := r.Cookie("token")
+ if cookie != nil {
+ token, err := jwt.Parse(cookie.Value, func(token *jwt.Token) (interface{}, error) {
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+ return nil, fmt.Errorf("Error parsing token")
+ }
+ return SECRET_KEY, nil
+ })
+
+ if err != nil {
+ log.Println(err)
+ }
+
+ if token.Valid {
+ username := token.Claims.(jwt.MapClaims)["username"]
+ name := token.Claims.(jwt.MapClaims)["name"]
+ email := token.Claims.(jwt.MapClaims)["email"]
+ auth := token.Claims.(jwt.MapClaims)["authenticated"]
+ if auth == nil {
+ auth = false
+ }
+ userInfo := UserInfo{
+ Username: username.(string),
+ Name: name.(string),
+ Email: email.(string),
+ Auth: auth.(bool),
+ }
+ return userInfo
+ }
+ }
+ userInfo := UserInfo{}
+ return userInfo
+}
+
+var loginPage = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
+ tmpl := template.Must(template.New("login.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ returnedData := Data{
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ },
+ }
+ err := tmpl.ExecuteTemplate(w, "login.html", returnedData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@@ 33,10 135,11 @@ var NotImplemented = http.HandlerFunc(func(w http.ResponseWriter, r *http.Reques
var Scores = map[string]uint64{}
type Submission struct {
- Title, Url, Body, Slug, Submitter string
- Author, Visible bool
- Score uint64
- Created string
+ Title, Host, Scheme, Body, Slug, Submitter string
+ Url template.URL
+ Author, Visible bool
+ Score uint64
+ Created string
// Created time.Time
Tags []string
}
@@ 49,10 152,75 @@ type Comment struct {
type ByScore []Submission
func (a ByScore) Len() int { return len(a) }
-func (a ByScore) Less(i, j int) bool { return a[i].Score > a[j].Score }
+func (a ByScore) Less(i, j int) bool { return a[i].Created > a[j].Created }
func (a ByScore) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+var displaySubmissionsBySource = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
+ vars := mux.Vars(r)
+ source := vars["source"]
+ m := front.NewMatter()
+ submissions := LoadSubmissions("./submissions")
+ var returnedSubmissions []Submission
+ for _, submission := range submissions {
+
+ rawSubmission, _ := os.Open(submission)
+ m.Handle("---", front.YAMLHandler)
+ fm, bd, err := m.Parse(rawSubmission)
+ if err != nil {
+ log.Println(err)
+ }
+
+ u, _ := url.Parse(fm["url"].(string))
+ if u.Host == source {
+
+ author, _ := strconv.ParseBool(fm["author"].(string))
+ visible, _ := strconv.ParseBool(fm["visible"].(string))
+
+ // Assert front-matter tags as an []interface{}
+ // so that we can iterate over it and add to a []string
+ tagSlice := fm["tags"].([]interface{})
+ var submissionTags []string
+ for _, eachTag := range tagSlice {
+ submissionTags = append(submissionTags, eachTag.(string))
+ }
+
+ decodedBody, _ := b64.StdEncoding.DecodeString(bd)
+
+ scheme := u.Scheme
+ data := Submission{
+ Title: fm["title"].(string),
+ Submitter: fm["submitter"].(string),
+ Url: template.URL(fm["url"].(string)),
+ Author: author,
+ Score: Scores[fm["slug"].(string)],
+ Created: fm["created"].(string),
+ Body: string(decodedBody),
+ Slug: fm["slug"].(string),
+ Tags: submissionTags,
+ Visible: visible,
+ Host: u.Host,
+ Scheme: scheme,
+ }
+ returnedSubmissions = append(returnedSubmissions, data)
+ }
+ }
+ returnedData := Data{
+ Submissions: returnedSubmissions,
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ },
+ }
+ sort.Sort(ByScore(returnedSubmissions))
+ tmpl := template.Must(template.New("index.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "index.html", returnedData)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+})
+
var displaySubmissions = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
m := front.NewMatter()
submissions := LoadSubmissions("./submissions")
var returnedSubmissions []Submission
@@ 76,30 244,42 @@ var displaySubmissions = http.HandlerFunc(func(w http.ResponseWriter, r *http.Re
submissionTags = append(submissionTags, eachTag.(string))
}
+ decodedBody, _ := b64.StdEncoding.DecodeString(bd)
+
+ u, _ := url.Parse(fm["url"].(string))
+ scheme := u.Scheme
data := Submission{
Title: fm["title"].(string),
Submitter: fm["submitter"].(string),
- Url: fm["url"].(string),
+ Url: template.URL(fm["url"].(string)),
Author: author,
Score: Scores[fm["slug"].(string)],
Created: fm["created"].(string),
- Body: bd,
+ Body: string(decodedBody),
Slug: fm["slug"].(string),
Tags: submissionTags,
Visible: visible,
+ Host: u.Host,
+ Scheme: scheme,
}
-
returnedSubmissions = append(returnedSubmissions, data)
}
+ returnedData := Data{
+ Submissions: returnedSubmissions,
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ },
+ }
sort.Sort(ByScore(returnedSubmissions))
- tmpl := template.Must(template.New("index.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseFiles("index.html"))
- err := tmpl.ExecuteTemplate(w, "index.html", returnedSubmissions)
+ tmpl := template.Must(template.New("index.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "index.html", returnedData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var individualSubmission = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
m := front.NewMatter()
vars := mux.Vars(r)
slug := vars["slug"]
@@ 122,35 302,52 @@ var individualSubmission = http.HandlerFunc(func(w http.ResponseWriter, r *http.
submissionTags = append(submissionTags, eachTag.(string))
}
+ decodedBody, _ := b64.StdEncoding.DecodeString(bd)
+
data := Submission{
Title: fm["title"].(string),
Submitter: fm["submitter"].(string),
- Url: fm["url"].(string),
+ Url: template.URL(fm["url"].(string)),
Author: author,
Score: Scores[fm["slug"].(string)],
Created: fm["created"].(string),
- Body: bd,
+ Body: string(decodedBody),
Slug: fm["slug"].(string),
Tags: submissionTags,
Visible: visible,
}
- tmpl := template.Must(template.New("post.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseFiles("post.html"))
- err = tmpl.ExecuteTemplate(w, "post.html", data)
+ returnedSubmissions := []Submission{data}
+
+ returnedData := Data{
+ Submissions: returnedSubmissions,
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ Username: userInfo.Username,
+ },
+ }
+
+ tmpl := template.Must(template.New("post.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ err = tmpl.ExecuteTemplate(w, "post.html", returnedData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var submitPage = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- tmpl := template.Must(template.New("submit.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseFiles("submit.html"))
- err := tmpl.ExecuteTemplate(w, "submit.html", nil)
+ userInfo := getLoggedInInfo(r)
+ tmpl := template.Must(template.New("submit.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ data := Data{
+ UserInfo: userInfo,
+ }
+ err := tmpl.ExecuteTemplate(w, "submit.html", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var submissionComments = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
m := front.NewMatter()
vars := mux.Vars(r)
slug := vars["slug"]
@@ 175,8 372,16 @@ var submissionComments = http.HandlerFunc(func(w http.ResponseWriter, r *http.Re
submissionComments = append(submissionComments, comment)
}
- tmpl := template.Must(template.New("comments.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseFiles("comments.html"))
- err = tmpl.ExecuteTemplate(w, "comments.html", submissionComments)
+ returnedData := Data{
+ Comments: submissionComments,
+ UserInfo: UserInfo{
+ Auth: userInfo.Auth,
+ Username: userInfo.Username,
+ },
+ }
+
+ tmpl := template.Must(template.New("comments.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("views/*.html"))
+ err = tmpl.ExecuteTemplate(w, "comments.html", returnedData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@@ 253,19 458,14 @@ var upSubmission = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request)
})
var addComment = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
vars := mux.Vars(r)
slug := vars["slug"]
reg, err := regexp.Compile(`[^a-zA-Z0-9 '"?!,.()$&]+`)
if err != nil {
log.Fatal(err)
}
- name := html.EscapeString(reg.ReplaceAllString(r.FormValue("name"), ""))
- if len(name) < 1 {
- name = "Coward"
- }
- if len(name) > 50 {
- name = "Troublemaker"
- }
+ name := userInfo.Username
comment := html.EscapeString(reg.ReplaceAllString(r.FormValue("comment"), ""))
if len(comment) < 1 {
w.Write([]byte("You need a comment"))
@@ 305,13 505,14 @@ func StringWithCharset(length int, charset string) string {
}
var actuallySubmit = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
reg, err := regexp.Compile(`[^a-zA-Z0-9 '"?!,.()$&]+`)
if err != nil {
log.Fatal(err)
}
title := html.EscapeString(reg.ReplaceAllString(r.FormValue("title"), ""))
url := html.EscapeString(r.FormValue("url"))
- submitter := html.EscapeString(reg.ReplaceAllString(r.FormValue("submitter"), ""))
+ submitter := userInfo.Username
author := r.FormValue("author")
var authorBool bool
if author == "on" {
@@ 332,21 533,21 @@ var actuallySubmit = http.HandlerFunc(func(w http.ResponseWriter, r *http.Reques
submissionTags := strings.Split(tags, ",")
+ body := b64.StdEncoding.EncodeToString([]byte(r.FormValue("context")))
+
data := Submission{
Title: title,
Submitter: submitter,
- Url: url,
+ Url: template.URL(url),
Author: authorBool,
Score: 1,
- Created: string(currentTime.Format("2006-01-02")),
- Body: "",
+ Created: string(currentTime.Format("2006-01-02 15:04:05")),
+ Body: body,
Slug: slug,
Tags: submissionTags,
Visible: true,
}
- log.Println(data)
-
log.Printf("Would submit %s (%s) from %s (author %t) with tags %s", title, url, submitter, author, tags)
t, err := template.ParseFiles("submission.yaml")
@@ 371,43 572,331 @@ var actuallySubmit = http.HandlerFunc(func(w http.ResponseWriter, r *http.Reques
http.Redirect(w, r, redirPath, 302)
})
-func main() {
+func isAuthorised(endpoint func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ cookie, _ := r.Cookie("token")
+ if cookie != nil {
+ token, err := jwt.Parse(cookie.Value, func(token *jwt.Token) (interface{}, error) {
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+ return nil, fmt.Errorf("Error parsing token")
+ }
+ return SECRET_KEY, nil
+ })
+
+ if err != nil {
+ fmt.Fprintf(w, err.Error())
+ }
- InitialiseScoreMap()
-
- ticker := time.NewTicker(30 * time.Second)
- quit := make(chan struct{})
- go func() {
- for {
- select {
- case <-ticker.C:
- WriteScores()
- case <-quit:
- ticker.Stop()
- return
+ if token.Valid {
+ endpoint(w, r)
+ }
+ } else {
+ returnError := ReturnError{
+ Title: "Access denied",
+ Body: template.HTML(`You don't have permission to see this page. Try <a href="/login">logging in</a>.`),
+ Auth: false,
+ }
+ data := Data{
+ UserInfo: UserInfo{
+ Auth: false,
+ },
+ Error: returnError,
+ }
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", data)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
}
+ return
+ }
+ })
+}
+
+var logout = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ c := &http.Cookie{
+ Name: "token",
+ Value: "",
+ Path: "/",
+ Expires: time.Unix(0, 0),
+
+ HttpOnly: true,
+ }
+
+ http.SetCookie(w, c)
+ http.Redirect(w, r, "/", 302)
+})
+
+var userPage = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ userInfo := getLoggedInInfo(r)
+ auth := userInfo.Auth
+ vars := mux.Vars(r)
+ user := vars["user"]
+ re := regexp.MustCompile("^[a-zA-Z0-9_]*$")
+ if !re.MatchString(user) {
+ log.Printf("Not attempting to read file for %s", user)
+ returnError := ReturnError{
+ Title: "Error displaying user",
+ Body: template.HTML("Unable to display an Account page for " + user),
+ Auth: auth,
+ }
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", returnError)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ userPageInfo := UserInfo{}
+ file, err := ioutil.ReadFile("./users/" + user + ".yaml")
+ if err != nil {
+ log.Printf("File read error for %s: %s", user, err)
+ returnError := ReturnError{
+ Title: "Error displaying user",
+ Body: template.HTML("Unable to display an Account page for " + user),
+ Auth: auth,
}
- }()
+ log.Printf("File read error for %s: %s", user, err)
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", returnError)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ err = yaml.Unmarshal([]byte(file), &userPageInfo)
+ if err != nil {
+ log.Printf("YAML unmarshal error for %s: %s", user, err)
+ returnError := ReturnError{
+ Title: "Error displaying user",
+ Body: template.HTML("Unable to display an Account page for " + user),
+ Auth: auth,
+ }
+ log.Printf("File read error for %s: %s", user, err)
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", returnError)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ userPageInfo = UserInfo{
+ Username: userPageInfo.Username,
+ Name: userPageInfo.Name,
+ Status: userPageInfo.Status,
+ Social: userPageInfo.Social,
+ Homepage: userPageInfo.Homepage,
+ Git: userPageInfo.Git,
+ Auth: auth,
+ }
+ returnedData := Data{
+ UserInfo: userPageInfo,
+ }
+ tmpl := template.Must(template.New("profile.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err = tmpl.ExecuteTemplate(w, "profile.html", returnedData)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ log.Printf("%s opened account page for %s", userInfo.Username, userPageInfo.Username)
+})
+
+var account = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ user := getLoggedInInfo(r)
+ username := user.Username
+ auth := user.Auth
+ userInfo := UserInfo{}
+ file, err := ioutil.ReadFile("./users/" + username + ".yaml")
+ if err != nil {
+ returnError := ReturnError{
+ Title: "Error displaying user",
+ Body: template.HTML("Unable to display an Account page for " + username),
+ }
+ log.Printf("File read error for %s: %s", user, err)
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", returnError)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ err = yaml.Unmarshal([]byte(file), &userInfo)
+ if err != nil {
+ log.Printf("YAML unmarshal error for %s: %s", user, err)
+ returnError := ReturnError{
+ Title: "Error displaying user",
+ Body: template.HTML("Unable to display an Account page for " + username),
+ Auth: auth,
+ }
+ data := Data{
+ UserInfo: UserInfo{
+ Auth: auth,
+ },
+ Error: returnError,
+ }
+ log.Printf("File read error for %s: %s", user, err)
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", data)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ userInfo = UserInfo{
+ Username: userInfo.Username,
+ Name: userInfo.Name,
+ Email: userInfo.Email,
+ Status: userInfo.Status,
+ Social: userInfo.Social,
+ Homepage: userInfo.Homepage,
+ Git: userInfo.Git,
+ Auth: auth,
+ }
+ returnedData := Data{
+ UserInfo: userInfo,
+ }
+ tmpl := template.Must(template.New("account.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err = tmpl.ExecuteTemplate(w, "account.html", returnedData)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ log.Printf("%s opened account page", userInfo.Username)
+})
+
+var login = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ user := r.FormValue("username")
+ re := regexp.MustCompile("^[a-zA-Z0-9_]*$")
+ if !re.MatchString(user) {
+ log.Printf("Not attempting to read file for %s", user)
+ returnError := ReturnError{
+ Title: "Access denied",
+ Body: template.HTML(""),
+ Auth: false,
+ }
+ tmpl := template.Must(template.New("error.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "error.html", returnError)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ password := []byte(r.FormValue("password"))
+ hashedPassword, err := getHashedPassword(user)
+ if err != nil {
+ log.Printf("Credentials error for %s: %s", user, err)
+ tmpl := template.Must(template.New("denied.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "denied.html", nil)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ passErr := bcrypt.CompareHashAndPassword(hashedPassword, password)
+ if passErr != nil {
+ log.Printf("Credentials error for %s: %s", user, passErr)
+ tmpl := template.Must(template.New("denied.html").Funcs(template.FuncMap{"markDown": markDowner}).ParseGlob("./views/*.html"))
+ err := tmpl.ExecuteTemplate(w, "denied.html", nil)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ } else {
+ log.Printf("%s logged in", user)
+ jwt, expirationTime, _ := generateJWT(user)
+ http.SetCookie(w, &http.Cookie{
+ Name: "token",
+ Value: jwt,
+ Expires: expirationTime,
+ })
+ http.Redirect(w, r, redir, 302)
+ }
+})
+
+func getHashedPassword(user string) ([]byte, error) {
+ credentials := Credentials{}
+ log.Printf("Attempting to load user file for %s", user)
+ file, err := ioutil.ReadFile("./users/" + user + ".yaml")
+ if err != nil {
+ log.Printf("File read error for %s: %s", user, err)
+ return []byte(""), err
+ }
+ err = yaml.Unmarshal([]byte(file), &credentials)
+ if err != nil {
+ log.Printf("YAML unmarshal error for %s: %s", user, err)
+ return []byte(""), err
+ }
+ return []byte(credentials.Password), nil
+}
+
+func generateJWT(user string) (string, time.Time, error) {
+ userInfo := UserInfo{}
+ file, err := ioutil.ReadFile("./users/" + user + ".yaml")
+ if err != nil {
+ log.Printf("File read error for %s: %s", user, err)
+ return "", time.Now(), err
+ }
+ err = yaml.Unmarshal([]byte(file), &userInfo)
+ if err != nil {
+ log.Printf("YAML unmarshal error for %s: %s", user, err)
+ return "", time.Now(), err
+ }
+ expirationTime := time.Now().Add(48 * time.Hour)
+ claims := &Claims{
+ Username: user,
+ Name: userInfo.Name,
+ Email: userInfo.Email,
+ Auth: true,
+ StandardClaims: jwt.StandardClaims{
+ ExpiresAt: expirationTime.Unix(),
+ },
+ }
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ tokenString, err := token.SignedString(SECRET_KEY)
+ if err != nil {
+ log.Println("Error in JWT token generation")
+ return "", time.Now(), err
+ }
+ return tokenString, expirationTime, nil
+}
+
+func main() {
+
+ // InitialiseScoreMap()
+ //
+ // ticker := time.NewTicker(30 * time.Second)
+ // quit := make(chan struct{})
+ // go func() {
+ // for {
+ // select {
+ // case <-ticker.C:
+ // WriteScores()
+ // case <-quit:
+ // ticker.Stop()
+ // return
+ // }
+ // }
+ // }()
r := mux.NewRouter()
r.Handle("/", displaySubmissions).Methods("GET")
- r.Handle("/up/{slug}", upSubmission).Methods("GET")
- r.Handle("/comment/{slug}", addComment).Methods("POST")
- r.Handle("/actuallysubmit", actuallySubmit).Methods("POST")
+ r.Handle("/up/{slug}", isAuthorised(upSubmission)).Methods("GET")
+ r.Handle("/comment/{slug}", isAuthorised(addComment)).Methods("POST")
+ r.Handle("/actuallysubmit", isAuthorised(actuallySubmit)).Methods("POST")
r.Handle("/s/{slug}", individualSubmission).Methods("GET")
r.Handle("/comments/{slug}", submissionComments).Methods("GET")
r.Handle("/status", NotImplemented).Methods("GET")
- r.Handle("/recent", NotImplemented).Methods("GET")
- r.Handle("/submit", submitPage).Methods("GET")
- r.Handle("/saved", NotImplemented).Methods("GET")
- r.Handle("/search", NotImplemented).Methods("GET")
- r.Handle("/messages", NotImplemented).Methods("GET")
- r.Handle("/account", NotImplemented).Methods("GET")
+ r.Handle("/submit", isAuthorised(submitPage)).Methods("GET")
+ r.HandleFunc("/account", isAuthorised(account)).Methods("GET")
+ r.Handle("/source", NotImplemented).Methods("GET")
+ r.Handle("/source/{source}", displaySubmissionsBySource).Methods("GET")
r.Handle("/tags", NotImplemented).Methods("GET")
r.Handle("/tags/{tag}", NotImplemented).Methods("GET")
+ r.HandleFunc("/logout", isAuthorised(logout)).Methods("GET")
+ r.Handle("/u/{user}", userPage).Methods("GET")
+
+ r.Handle("/login", loginPage).Methods("GET")
+ r.Handle("/login", login).Methods("POST")
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))