1
0

initial commit

This commit is contained in:
konrad
2018-06-10 11:11:41 +02:00
committed by kolaente
commit 479cf54ada
595 changed files with 427508 additions and 0 deletions

View File

@ -0,0 +1,18 @@
package v1
import (
"fmt"
"git.kolaente.de/konrad/list/models"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
)
// CheckToken checks prints a message if the token is valid or not. Currently only used for testing pourposes.
func CheckToken(c echo.Context) error {
user := c.Get("user").(*jwt.Token)
fmt.Println(user.Valid)
return c.JSON(418, models.Message{"🍵"})
}

View File

@ -0,0 +1,101 @@
package v1
import (
"encoding/json"
"git.kolaente.de/konrad/list/models"
"github.com/labstack/echo"
"net/http"
"strconv"
"strings"
)
// UserAddOrUpdate is the handler to add a user
func UserAddOrUpdate(c echo.Context) error {
// TODO: prevent everyone from updating users
// Check for Request Content
userFromString := c.FormValue("user")
var datUser *models.User
if userFromString == "" {
// b := new(models.User)
if err := c.Bind(&datUser); err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"No user model provided."})
}
} else {
// Decode the JSON
dec := json.NewDecoder(strings.NewReader(userFromString))
err := dec.Decode(&datUser)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"Error decoding user: " + err.Error()})
}
}
// Check if we have an ID other than the one in the struct
id := c.Param("id")
if id != "" {
// Make int
userID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"Invalid ID."})
}
datUser.ID = userID
}
// Check if the user exists
_, exists, err := models.GetUserByID(datUser.ID)
if err != nil {
return c.JSON(http.StatusInternalServerError, models.Message{"Could not check if the user exists."})
}
// Get the doer options
doer, err := models.GetCurrentUser(c)
if err != nil {
return err
}
// Insert or update the user
var newUser models.User
if exists {
newUser, err = models.UpdateUser(*datUser, &doer)
} else {
newUser, err = models.CreateUser(*datUser, &doer)
}
if err != nil {
// Check for user already exists
if models.IsErrUsernameExists(err) {
return c.JSON(http.StatusBadRequest, models.Message{"A user with this username already exists."})
}
// Check for user with that email already exists
if models.IsErrUserEmailExists(err) {
return c.JSON(http.StatusBadRequest, models.Message{"A user with this email address already exists."})
}
// Check for no username provided
if models.IsErrNoUsername(err) {
return c.JSON(http.StatusBadRequest, models.Message{"Please specify a username."})
}
// Check for no username or password provided
if models.IsErrNoUsernamePassword(err) {
return c.JSON(http.StatusBadRequest, models.Message{"Please specify a username and a password."})
}
// Check for user does not exist
if models.IsErrUserDoesNotExist(err) {
return c.JSON(http.StatusBadRequest, models.Message{"The user does not exist."})
}
return c.JSON(http.StatusInternalServerError, models.Message{"Error"})
}
// Obfuscate his password
newUser.Password = ""
return c.JSON(http.StatusOK, newUser)
}

View File

@ -0,0 +1,57 @@
package v1
import (
"git.kolaente.de/konrad/list/models"
"github.com/labstack/echo"
"net/http"
"strconv"
)
// UserDelete is the handler to delete a user
func UserDelete(c echo.Context) error {
// TODO: only allow users to allow itself
id := c.Param("id")
// Make int
userID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"User ID is invalid."})
}
// Check if the user exists
_, exists, err := models.GetUserByID(userID)
if err != nil {
return c.JSON(http.StatusInternalServerError, models.Message{"Could not get user."})
}
if !exists {
return c.JSON(http.StatusNotFound, models.Message{"The user does not exist."})
}
// Get the doer options
doer, err := models.GetCurrentUser(c)
if err != nil {
return err
}
// Delete it
err = models.DeleteUserByID(userID, &doer)
if err != nil {
if models.IsErrIDCannotBeZero(err) {
return c.JSON(http.StatusBadRequest, models.Message{"Id cannot be 0"})
}
if models.IsErrCannotDeleteLastUser(err) {
return c.JSON(http.StatusBadRequest, models.Message{"Cannot delete last user."})
}
return c.JSON(http.StatusInternalServerError, models.Message{"Could not delete user."})
}
return c.JSON(http.StatusOK, models.Message{"success"})
}

View File

@ -0,0 +1,43 @@
package v1
import (
"git.kolaente.de/konrad/list/models"
"github.com/labstack/echo"
"net/http"
"strconv"
)
// UserShow gets all informations about a user
func UserShow(c echo.Context) error {
// TODO: only allow users to show itself/with privacy options
user := c.Param("id")
if user == "" {
return c.JSON(http.StatusBadRequest, models.Message{"User ID cannot be empty."})
}
// Make int
userID, err := strconv.ParseInt(user, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"User ID is invalid."})
}
// Get User Infos
userInfos, exists, err := models.GetUserByID(userID)
if err != nil {
return c.JSON(http.StatusInternalServerError, models.Message{"Error getting user infos."})
}
// Check if it exists
if !exists {
return c.JSON(http.StatusNotFound, models.Message{"User not found."})
}
// Obfucate his password
userInfos.Password = ""
return c.JSON(http.StatusOK, userInfos)
}

View File

@ -0,0 +1,76 @@
package v1
import (
"net/http"
"strconv"
"git.kolaente.de/konrad/list/models"
"github.com/labstack/echo"
)
type datPassword struct {
Password string `json:"password"`
}
// UserChangePassword is the handler to add a user
func UserChangePassword(c echo.Context) error {
// Get the ID
user := c.Param("id")
if user == "" {
return c.JSON(http.StatusBadRequest, models.Message{"User ID cannot be empty."})
}
// Make int
userID, err := strconv.ParseInt(user, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"User ID is invalid."})
}
// Check if the user is itself
userJWTinfo, err := models.GetCurrentUser(c)
if userJWTinfo.ID != userID {
return echo.ErrUnauthorized
}
// Check for Request Content
pwFromString := c.FormValue("password")
var datPw datPassword
if pwFromString == "" {
if err := c.Bind(&datPw); err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"No password provided."})
}
} else {
// Take the value directly from the input
datPw.Password = pwFromString
}
// Get User Infos
_, exists, err := models.GetUserByID(userID)
if err != nil {
return c.JSON(http.StatusInternalServerError, models.Message{"Error getting user infos."})
}
// Check if it exists
if !exists {
return c.JSON(http.StatusNotFound, models.Message{"User not found."})
}
// Get the doer options
doer, err := models.GetCurrentUser(c)
if err != nil {
return err
}
err = models.UpdateUserPassword(userID, datPw.Password, &doer)
if err != nil {
return err
}
return c.JSON(http.StatusOK, models.Message{"The password was updated successfully"})
}

16
routes/cors.go Normal file
View File

@ -0,0 +1,16 @@
package routes
import (
"github.com/labstack/echo"
"net/http"
)
// SetCORSHeader sets relevant CORS headers for Cross-Site-Requests to the api
func SetCORSHeader(c echo.Context) error {
res := c.Response()
res.Header().Set("Access-Control-Allow-Origin", "*")
res.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
res.Header().Set("Access-Control-Allow-Headers", "authorization,content-type")
res.Header().Set("Access-Control-Expose-Headers", "authorization,content-type")
return c.String(http.StatusOK, "")
}

51
routes/login.go Normal file
View File

@ -0,0 +1,51 @@
package routes
import (
"crypto/md5"
"encoding/hex"
"git.kolaente.de/konrad/list/models"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
"net/http"
"time"
)
// Login is the login handler
func Login(c echo.Context) error {
u := new(models.UserLogin)
if err := c.Bind(u); err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."})
}
// Check user
user, err := models.CheckUserCredentials(u)
if err != nil {
return c.JSON(http.StatusUnauthorized, models.Message{"Wrong username or password."})
}
// Create token
token := jwt.New(jwt.SigningMethodHS256)
// Set claims
claims := token.Claims.(jwt.MapClaims)
claims["name"] = user.Name
claims["username"] = user.Username
claims["email"] = user.Email
claims["id"] = user.ID
claims["admin"] = user.IsAdmin
claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
avatar := md5.Sum([]byte(user.Email))
claims["avatar"] = hex.EncodeToString(avatar[:])
// Generate encoded token and send it as response.
t, err := token.SignedString(models.Config.JWTLoginSecret)
if err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{
"token": t,
})
}

51
routes/routes.go Normal file
View File

@ -0,0 +1,51 @@
package routes
import (
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"git.kolaente.de/konrad/list/models"
apiv1 "git.kolaente.de/konrad/list/routes/api/v1"
)
// NewEcho registers a new Echo instance
func NewEcho() *echo.Echo {
e := echo.New()
// Logger
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: "${time_rfc3339}: ${remote_ip} ${method} ${status} ${uri} ${latency_human} - ${user_agent}\n",
}))
return e
}
// RegisterRoutes registers all routes for the application
func RegisterRoutes(e *echo.Echo) {
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
res := c.Response()
res.Header().Set("Access-Control-Allow-Origin", "*")
res.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
res.Header().Set("Access-Control-Allow-Headers", "authorization,content-type")
res.Header().Set("Access-Control-Expose-Headers", "authorization,content-type")
return next(c)
}
})
// API Routes
a := e.Group("/api/v1")
// CORS_SHIT
a.OPTIONS("/login", SetCORSHeader)
a.OPTIONS("/users", SetCORSHeader)
a.OPTIONS("/users/:id", SetCORSHeader)
a.POST("/login", Login)
// ===== Routes with Authetification =====
// Authetification
a.Use(middleware.JWT(models.Config.JWTLoginSecret))
a.POST("/tokenTest", apiv1.CheckToken)
}