diff --git a/assets/web/login.html b/assets/web/login.html new file mode 100644 index 0000000..14bbadf --- /dev/null +++ b/assets/web/login.html @@ -0,0 +1,25 @@ + + + + + Login to Pogo Admin Page + + + +

Login

+ +
+ + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/auth/auth.go b/auth/auth.go index 2580d90..f354faa 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -1,17 +1,36 @@ package auth import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "log" "net/http" + "strings" "github.com/ishanjain28/pogo/common" ) func RequireAuthorization() common.Handler { return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { - if usr := DecryptSession(r); usr != nil { + if usr := decryptSession(r); usr != nil { rc.User = usr return nil } + + if strings.Contains(r.Header.Get("Accept"), "html") || r.Method == "GET" { + http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) + return nil + } else { + return &common.HTTPError{ + Message: "Unauthorized!", + StatusCode: http.StatusUnauthorized, + } + } + return &common.HTTPError{ Message: "Unauthorized!", StatusCode: http.StatusUnauthorized, @@ -19,12 +38,53 @@ func RequireAuthorization() common.Handler { } } -func CreateSession() common.Handler { - return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { - return nil +func CreateSession(u *common.User, w http.ResponseWriter) error { + + // n_J6vaKjmmw4WB95DMorjQ.UMYdBLfttwPgQw9T0u0wdK7bGwDT9vwxoPAKWhjSAcpoiMsjh4eSfBkA4WB2deSoQu_cjCaJrcp77rvG67xkOeXsYpiclx2b-Oi7MHM3Kms.1507140277977.604800000.2CdxwiKAJT4SYJTVK-Du5jokr-CCnxo1ukdaVBkLRJg + + iv, err := generateRandomString(16) + if err != nil { + return err + } + userJSON, err := json.Marshal(u) + if err != nil { + return err + + } + var hexedJSON []byte + hex.Encode(hexedJSON, userJSON) + + fmt.Println(iv, string(userJSON), hexedJSON) + + block, err := aes.NewCipher(hexedJSON) + if err != nil { + return err } + mode := cipher.NewCBCEncrypter(block, iv) + + return nil } -func DecryptSession(r *http.Request) *common.User { +func decryptSession(r *http.Request) *common.User { + + c, err := r.Cookie("POGO_SESSION") + if err != nil { + if err != http.ErrNoCookie { + log.Printf("error in reading Cookie: %v", err) + } + return nil + } + fmt.Println(c) + return nil } + +func generateRandomString(l int) ([]byte, error) { + rBytes := make([]byte, l) + + _, err := rand.Read(rBytes) + if err != nil { + return nil, err + } + return rBytes, nil +} diff --git a/common/common.go b/common/common.go index 68bccb9..8b5b198 100644 --- a/common/common.go +++ b/common/common.go @@ -29,7 +29,7 @@ type RouterContext struct { // User struct denotes the data is stored in the cookie type User struct { - Name string `json:"name"` + Username string `json:"username"` } // ReadAndServeFile reads the file from specified location and sends it in response diff --git a/router/router.go b/router/router.go index 1cc79d8..5a63fc3 100644 --- a/router/router.go +++ b/router/router.go @@ -65,9 +65,14 @@ func Init() *mux.Router { // Authenticated endpoints should be passed to BasicAuth() // first r.Handle("/admin", Handle( - auth.RequireAuthorization(), + // auth.RequireAuthorization(), adminHandler(), )) + + r.Handle("/login", Handle( + loginHandler(), + )) + // r.HandleFunc("/admin/publish", BasicAuth(CreateEpisode)) // r.HandleFunc("/admin/delete", BasicAuth(RemoveEpisode)) // r.HandleFunc("/admin/css", BasicAuth(CustomCss)) @@ -79,6 +84,71 @@ func Init() *mux.Router { return r } +func loginHandler() common.Handler { + return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { + + if r.Method == "GET" { + w.Header().Set("Content-Type", "text/html") + return common.ReadAndServeFile("assets/web/login.html", w) + } + + d, err := ioutil.ReadFile("assets/config/users.json") + if err != nil { + + return &common.HTTPError{ + Message: fmt.Sprintf("error in reading users.json: %v", err), + StatusCode: http.StatusInternalServerError, + } + + } + + err = r.ParseForm() + + if err != nil { + return &common.HTTPError{ + Message: fmt.Sprintf("error in parsing form: %v", err), + StatusCode: http.StatusBadRequest, + } + } + + username := r.Form.Get("username") + password := r.Form.Get("password") + if username == "" || password == "" { + return &common.HTTPError{ + Message: "username or password is empty", + StatusCode: http.StatusBadRequest, + } + } + + var u map[string]string + err = json.Unmarshal(d, &u) // Unmarshal into interface + + // Iterate through map until we find matching username + for k, v := range u { + if k == username && v == password { + // Create a cookie here because the credentials are correct + err = auth.CreateSession(&common.User{ + Username: k, + }, w) + if err != nil { + return &common.HTTPError{ + Message: err.Error(), + StatusCode: http.StatusInternalServerError, + } + } + // And now redirect the user to admin page + http.Redirect(w, r, "/admin", http.StatusTemporaryRedirect) + return nil + } + } + + return &common.HTTPError{ + Message: "Invalid credentials!", + StatusCode: http.StatusUnauthorized, + } + } +} + // Handles /, /feed and /json endpoints func rootHandler() common.Handler { return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { @@ -139,10 +209,3 @@ func serveSetup() common.Handler { return nil } } - -func redirectHandler() common.Handler { - return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { - - return nil - } -}