finish with create user and start with user login

master
Alex 2021-05-15 22:56:28 +02:00
parent 71fe2a5e46
commit e0266d9788
8 changed files with 185 additions and 76 deletions

View File

@ -1,7 +1,6 @@
[server]
debug = true
host = "127.0.0.1:3000"
secret = "KAWXQHtKaz8BmWksXsQFPrdE78ptBuwBsaUNt8XcKGZt44QbUp"
[database]
host = "127.0.0.1:3306"

View File

@ -1,17 +1,27 @@
###
#### user login
GET http://localhost:3000/api/v1/users
Content-Type: application/xml
# Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjEyNTAxODcsInVzZXJfaGFzaHRhZyI6IjRIUVQ3NSIsInVzZXJfaWQiOiJhZDAyYzY2NzRmYjI0OWY0YWI4NWU1MjYzZDUyMzAwZiIsInVzZXJuYW1lIjoicnVpc3BpcGUxIn0.wJJO_2maGG_1h2hingzZm3VmNJnmQnpzknU4dnw-8IE
Cookie: session_id=b81aedb75b084d01945ee45134ddbc39;
###
POST http://localhost:3000/api/v1/users
POST http://localhost:3000/api/v1/user/login
Content-Type: application/json
{
"username": "183",
"email": "183@roese.dev",
"password": "teksmkamsdkasd- a , ' . + * maskdmaskdm"
"username": "107",
"password": "my-passworda"
}
### get users
POST http://localhost:3000/api/v1/users
Content-Type: application/xml
Cookie: session_id=5CLPfNbit0SCNoyRy2AWslJSWTascm3q
#### create user
POST http://localhost:3000/api/v1/users
Content-Type: application/json
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36
{
"username": "107",
"email": "107@roese.dev",
"password": "my-password"
}

1
go.mod
View File

@ -12,6 +12,7 @@ require (
github.com/google/uuid v1.2.0
github.com/klauspost/compress v1.12.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mileusna/useragent v1.0.2 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect

2
go.sum
View File

@ -28,6 +28,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mileusna/useragent v1.0.2 h1:DgVKtiPnjxlb73z9bCwgdUvU2nQNQ97uhgfO8l9uz/w=
github.com/mileusna/useragent v1.0.2/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View File

@ -13,9 +13,8 @@ type Config struct {
}
type server struct {
Debug bool
Host string
Secret string
Debug bool
Host string
}
type database struct {

View File

@ -2,7 +2,6 @@ package database
import (
"database/sql"
"errors"
"fmt"
"git.umbach.dev/app-idea/rest-api/modules/config"
@ -20,7 +19,7 @@ func GetDatabase() (*sql.DB, error) {
if err := db.Ping(); err != nil {
log.Warnln("DB Connection error:", err.Error())
return nil, errors.New(err.Error())
return nil, err
}
return db, nil

View File

@ -1,9 +1,11 @@
package user
import (
"crypto/rand"
"database/sql"
"encoding/base64"
"errors"
"fmt"
"math/big"
"regexp"
"strings"
"time"
@ -12,14 +14,11 @@ import (
"git.umbach.dev/app-idea/rest-api/modules/database"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
ua "github.com/mileusna/useragent"
log "github.com/sirupsen/logrus"
"github.com/zhengxiaowai/shortuuid"
"golang.org/x/crypto/bcrypt"
)
//err = bcrypt.CompareHashAndPassword(hashedPassword, []byte("hello wolrd"))
//fmt.Println(err)
type LoginInput struct {
Username string `json:"username"`
Email string `json:"email"`
@ -92,7 +91,12 @@ func NewUser(c *fiber.Ctx) error {
}
if input.Hashtag == "" {
input.Hashtag = RandomHashtag(db, 6)
input.Hashtag, err = generateRandomHashtag(db, 6)
if err != nil {
log.Warn(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
} else if !isHashtagValid(db, input.Hashtag) {
return c.SendStatus(fiber.StatusUnprocessableEntity)
}
@ -101,49 +105,67 @@ func NewUser(c *fiber.Ctx) error {
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
log.Warnln("bcrypt password error", err)
log.Warnln("Failed to bcrypt password", err)
return c.SendStatus(fiber.StatusInternalServerError)
}
user_id := strings.Replace(uuid.New().String(), "-", "", -1)
userId := strings.Replace(uuid.New().String(), "-", "", -1)
created := time.Now().Format("2006-01-02 15:04:05") // YYYY-MM-DD hh:mm:ss
stmt, err := db.Prepare("INSERT INTO users (user_id, user_hashtag, username, email, password, created) VALUES (?, ?, ?, ?, ?, ?);")
stmt.Exec(user_id, input.Hashtag, input.Username, input.Email, hashedPassword, created)
stmt.Exec(userId, input.Hashtag, input.Username, input.Email, hashedPassword, created)
stmt.Close()
expires := time.Now().Add(time.Hour * 72)
session_id := strings.Replace(uuid.New().String(), "-", "", -1)
if err != nil {
log.Warnln("Failed to insert user to db", err.Error())
return c.SendStatus(fiber.StatusInternalServerError)
}
//h := sha256.New()
//h.Write([]byte(config.GetConfig().Server.Secret))
//b := h.Sum([]byte(session_id))
sessionId, err := createUserSession(db, userId, c.IP(), string(c.Context().UserAgent()))
//log.Infoln("sha256", h, base64.StdEncoding.EncodeToString(b))
if err != nil {
log.Warnln(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
stmt2, err := db.Prepare("INSERT INTO sessions (user_id, session_id, expires) VALUES (?, ?, ?);")
stmt2.Exec(user_id, session_id, expires)
expires := getExpiresTime()
stmt2.Close()
log.Debugln("user created", user_id, input.Hashtag, input.Username, input.Email)
c.Cookie(&fiber.Cookie{Name: "session_id", Value: base64.StdEncoding.EncodeToString(b), Secure: true, HTTPOnly: true, Expires: expires})
c.Cookie(&fiber.Cookie{Name: "session_id", Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires})
c.Cookie(&fiber.Cookie{Name: "username", Value: input.Username, Secure: true, Expires: expires})
c.Cookie(&fiber.Cookie{Name: "user_hashtag", Value: input.Hashtag, Secure: true, Expires: expires})
log.Debugln("user created", userId, input.Hashtag, input.Username, input.Email)
return c.SendStatus(fiber.StatusCreated)
}
func RandomHashtag(db *sql.DB, n int) string {
func generateRandomString(n int) (string, error) {
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
r := make([]byte, n)
for i := 0; i < n; i++ {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
if err != nil {
return "", err
}
r[i] = letters[num.Int64()]
}
return string(r), nil
}
func generateRandomHashtag(db *sql.DB, n int) (string, error) {
c := make(chan bool)
var s string
var err error
for {
su := shortuuid.NewShortUUID()
su.SetAlphabet("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
s = su.Random(n)
s, err = generateRandomString(6)
if err != nil {
return "", errors.New("Error generating Hashtag " + err.Error())
}
go func() {
err := db.QueryRow("SELECT user_hashtag FROM users WHERE user_hashtag = ?", s).Scan(&s)
@ -160,7 +182,7 @@ func RandomHashtag(db *sql.DB, n int) string {
}
}
return s
return s, nil
}
func isHashtagValid(db *sql.DB, h string) bool {
@ -170,8 +192,6 @@ func isHashtagValid(db *sql.DB, h string) bool {
err := db.QueryRow("SELECT user_hashtag FROM users WHERE user_hashtag = ?", h).Scan(&h)
fmt.Println("isHashtagValid", err == sql.ErrNoRows)
if err == sql.ErrNoRows {
return true
}
@ -213,9 +233,84 @@ func isEmailAvailable(db *sql.DB, e string) bool {
}
func SessionIdCheck(c *fiber.Ctx) error {
session_id := c.Cookies("session_id")
valid, err := isSessionIdValid(c.Cookies("session_id"))
log.Infoln("session_id", session_id)
if err != nil {
log.Warn(err)
return fiber.ErrInternalServerError
}
if valid {
return c.Next()
}
return fiber.ErrUnauthorized
}
func isSessionIdValid(sessionId string) (bool, error) {
db, err := database.GetDatabase()
if db == nil || err != nil {
return false, errors.New("DB error " + err.Error())
}
defer db.Close()
err = db.QueryRow("SELECT session_id FROM sessions WHERE session_id = ?", sessionId).Scan(&sessionId)
if err == sql.ErrNoRows {
return false, nil
}
return true, nil
}
func createUserSession(db *sql.DB, userId string, ip string, userAgent string) (string, error) {
sessionId, err := generateRandomString(32)
if err != nil {
return "", errors.New("Failed to generate user session " + err.Error())
}
log.Info(time.Now().String())
log.Info(getExpiresTime())
stmt, err := db.Prepare("INSERT INTO sessions (user_id, session_id, ip, user_agent, last_login, expires) VALUES (?, ?, ?, ?, ?, ?);")
if err != nil {
return "", errors.New("Failed to insert user into db " + err.Error())
}
ua := ua.Parse(userAgent)
stmt.Exec(userId, sessionId, ip, ua.OS+" "+ua.Name, time.Now(), getExpiresTime())
stmt.Close()
return "", nil
}
func getExpiresTime() time.Time {
// TODO: db default
return time.Now().Add(time.Hour * 72)
}
func Login(c *fiber.Ctx) error {
var input LoginInput
if err := c.BodyParser(&input); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
log.Println(input)
if input.Username != "" && !isValid(input.Username, 3, 30) {
log.Info("for1")
return c.SendStatus(fiber.StatusBadRequest)
}
if input.Email != "" && !isEmailValid(input.Email) {
log.Info("for2")
return c.SendStatus(fiber.StatusForbidden)
}
db, err := database.GetDatabase()
@ -223,9 +318,36 @@ func SessionIdCheck(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusInternalServerError)
}
var hashedPassword string
if input.Username != "" {
err = db.QueryRow("SELECT password FROM users WHERE username = ?", input.Username).Scan(&hashedPassword)
log.Info(hashedPassword)
} else {
}
if err != nil {
log.Infoln("una", err)
return c.SendStatus(fiber.StatusUnauthorized)
}
err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(input.Password))
if err != nil {
log.Warnln("Failed to comapare bcrypt password", err)
return c.SendStatus(fiber.StatusUnauthorized)
}
log.Info("password correct")
//err = bcrypt.CompareHashAndPassword(hashedPassword, []byte("hello wolrd"))
//fmt.Println(err)
defer db.Close()
return fiber.ErrUnauthorized
return c.JSON(fiber.Map{"test": hashedPassword})
}
func GetUser(c *fiber.Ctx) error {

View File

@ -3,38 +3,15 @@ package router
import (
"git.umbach.dev/app-idea/rest-api/routers/api/v1/user"
jwt "github.com/form3tech-oss/jwt-go"
"github.com/gofiber/fiber/v2"
)
/*
func Protected() fiber.Handler {
return jwtware.New(jwtware.Config{
SigningKey: []byte(config.GetConfig().Server.Secret),
ErrorHandler: jwtError,
})
}
func jwtError(c *fiber.Ctx, err error) error {
if err.Error() == "Missing or malformed JWT" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"message": "Missing or malformed JWT"})
}
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"message": "Invalid or expired JWT"})
} */
func Test(c *fiber.Ctx) error {
usert := c.Locals("user").(*jwt.Token)
claims := usert.Claims.(jwt.MapClaims)
name := claims["username"].(string)
return c.SendString("Welcome" + name)
}
func SetupRoutes(app *fiber.App) {
api := app.Group("/api/v1")
/* Unauthenticated routes */
app.Get("/user", user.GetUser)
u := api.Group("/user")
u.Get("/user", user.GetUser)
u.Post("/login", user.Login)
users := api.Group("/users")
users.Post("/", user.NewUser)