prepair to using go concurrent

This commit is contained in:
Trần Duy Linh 2023-12-06 20:27:34 +07:00
parent ce0508294c
commit 47816debd3
10 changed files with 222 additions and 139 deletions

2
.env
View File

@ -1,5 +1,5 @@
MONGO_URI="mongodb://adminLinh:linhporo1@localhost:27017" MONGO_URI="mongodb://adminLinh:linhporo1@localhost:27017"
API_TEST_PORT=":8080" API_TEST_PORT=":8080"
REDIS_URI="redis://localhost:6479/0" REDIS_URI="redis://localhost:6379/0"
STMP_PASS="btmp judz ebys pfxw" STMP_PASS="btmp judz ebys pfxw"
EMAIL_VERIFY_SECRET="WDc&4+&vYP(n'}?LHNE#5M?IE|g(c812" EMAIL_VERIFY_SECRET="WDc&4+&vYP(n'}?LHNE#5M?IE|g(c812"

3
go.mod
View File

@ -11,14 +11,17 @@ require (
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pquerna/otp v1.4.0 // indirect github.com/pquerna/otp v1.4.0 // indirect
github.com/redis/go-redis/v9 v9.3.0 // indirect github.com/redis/go-redis/v9 v9.3.0 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect

6
go.sum
View File

@ -18,6 +18,8 @@ github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqR
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -29,6 +31,8 @@ github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQ
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1 h1:RLYNaO6dcj6hms2FSzwsXlZsyjxQBJi8qO/8Vkilhz0=
github.com/mervick/aes-everywhere/go/aes256 v0.0.0-20220903070135-f13ed3789ae1/go.mod h1:Eb5RMoo9kOQra/2uRiUTGP+LfNuM13Vqm7y7P34+KKo=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -36,6 +40,8 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0=
github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

View File

@ -16,6 +16,7 @@ type PreusersMongo struct {
HashPassword string `bson:"hash_password" json:"hash_password"` HashPassword string `bson:"hash_password" json:"hash_password"`
PhoneNumber string `bson:"phone_number" json:"phone_number"` PhoneNumber string `bson:"phone_number" json:"phone_number"`
CreatedDate time.Time `bson:"created_date" json:"created_date"` CreatedDate time.Time `bson:"created_date" json:"created_date"`
UpdateDate time.Time `bson:"update_date" json:"update_date"`
VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"` VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"`
} }
@ -27,6 +28,7 @@ type UsersMongo struct {
PhoneNumber string `bson:"phone_number" json:"phone_number"` PhoneNumber string `bson:"phone_number" json:"phone_number"`
Active bool `bson:"active" json:"active"` Active bool `bson:"active" json:"active"`
CreatedDate time.Time `bson:"created_date" json:"created_date"` CreatedDate time.Time `bson:"created_date" json:"created_date"`
UpdateDate time.Time `bson:"update_date" json:"update_date"`
VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"` VerifySentCount int `bson:"verify_sent_count" json:"verify_sent_count"`
} }

View File

@ -3,9 +3,13 @@ package rest_api
import ( import (
"fmt" "fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"linhdevtran99/rest-api/models"
"linhdevtran99/rest-api/rest-api/routes" "linhdevtran99/rest-api/rest-api/routes"
"linhdevtran99/rest-api/rest-api/services"
"linhdevtran99/rest-api/utils"
"log" "log"
"net/http" "net/http"
"time"
) )
type APIServer struct { type APIServer struct {
@ -30,11 +34,13 @@ func (s *APIServer) Run() {
router := mux.NewRouter() router := mux.NewRouter()
routes.AuthRouterSetup(router) routes.AuthRouterSetup(router)
router.HandleFunc("/test", utils.MakeHTTPHandlerFn(s.TestRoute))
startMuxServer(s, router) startMuxServer(s, router)
} }
func (s *APIServer) AuthRoute(w http.ResponseWriter, r *http.Request) error { func (s *APIServer) TestRoute(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Content-Type", "application/json")
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
fmt.Println("hit") fmt.Println("hit")
@ -56,23 +62,29 @@ func (s *APIServer) AuthRoute(w http.ResponseWriter, r *http.Request) error {
//} //}
//serect := os.Getenv("EMAIL_VERIFY_SECRET") //serect := os.Getenv("EMAIL_VERIFY_SECRET")
//isPass, _ := generatorOtp("hello", "nhocdl.poro1@gmail.com", 12, serect)
//fmt.Println(isPass) //_, otp := services.GeneratorOtp("hello", "nhocdl.poro1@gmail.com", 12, serect)
//cipherBase64 := createLinkVerify(&models.CreateUser{ //fmt.Println(otp.HashOTP)
// Username: "thewind121212", //fmt.Println(otp.PureOTP)
// Email: "nhocdl.poro1@gmail.com",
// Password: "linhporoQ1@", //utils.EncryptAESMailLink("nhocdl.poro2@gmail.com", serect, w)
// ConfirmPassword: "linhporoQ1@",
//}, serect) //jsonData, _ := json.Marshal(map[string]string{"email": "nhocdl.poro1@gmail.com", "user": "thewind121212"})
////
//utils.Redis.Set(context.Background(), "otp:nhocdl.poro1@gmail.com", string(jsonData), time.Minute)
// //
//key := []byte(serect) //utils.CheckAndWriteRedis("nhocdl.poro1@gmail.com", "thewind121212", "lasdjflasdjlfj")
services.CheckAndWritePreuser(&models.PreusersMongo{
Username: "thewind121212",
Email: "nhocdl.poro2@gmail.com",
PhoneNumber: "0918327132",
VerifySentCount: 0,
CreatedDate: time.Now(),
UpdateDate: time.Now(),
})
// //
//i, err := utils.DecryptAES(cipherBase64, key)
//if err != nil {
// return err
//}
//
//fmt.Println(string(i))
} }

View File

@ -2,28 +2,47 @@ package routes
import ( import (
"encoding/json" "encoding/json"
"errors"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"linhdevtran99/rest-api/models" "linhdevtran99/rest-api/models"
"linhdevtran99/rest-api/rest-api/services" "linhdevtran99/rest-api/rest-api/services"
"linhdevtran99/rest-api/utils" "linhdevtran99/rest-api/utils"
"net/http" "net/http"
"time"
) )
func RegisterNewAccount(w http.ResponseWriter, r *http.Request) error { func RegisterNewAccount(w http.ResponseWriter, r *http.Request) error {
client := utils.MongoDB
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
var registerInfo models.CreateUser var registerInfo models.CreateUser
_ = json.NewDecoder(r.Body).Decode(&registerInfo) _ = json.NewDecoder(r.Body).Decode(&registerInfo)
//call function check info user type in //call function check info user type in
validRegisterInfo := services.CheckAndValidRegisterFiled(&registerInfo, w) validRegisterInfo, responseAPI := services.CheckAndValidRegisterFiled(&registerInfo)
//call function check data user use in past or not if responseAPI != nil {
isValidData := services.CheckAccountExist(client, registerInfo.Username, registerInfo.Email, w) return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err.Error())
if isValidData == false || validRegisterInfo == false {
return errors.New("USER DON'T HAVE VALID INFO FOR REGISTER ACCOUNT")
} }
//call function check data user use in past or not
isValidData, responseAPI := services.CheckAccountExist(utils.MongoDB, registerInfo.Username, registerInfo.Email)
if responseAPI != nil {
return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err.Error())
}
preUserData := &models.PreusersMongo{
Username: registerInfo.Username,
Email: registerInfo.Email,
PhoneNumber: registerInfo.PhoneNumber,
HashPassword: registerInfo.Password,
CreatedDate: time.Now(),
UpdateDate: time.Now(),
VerifySentCount: 1,
}
services.CheckAndWritePreuser(preUserData)
//debug
if isValidData == true || validRegisterInfo == true {
return utils.WriteJSON(w, http.StatusOK, "USER HAVE VALID INFO FOR REGISTER ACCOUNT")
}
//debug
} }
return nil return nil

View File

@ -3,8 +3,8 @@ package services
import ( import (
"context" "context"
"encoding/base32" "encoding/base32"
"encoding/base64"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/pquerna/otp" "github.com/pquerna/otp"
@ -15,10 +15,16 @@ import (
"linhdevtran99/rest-api/models" "linhdevtran99/rest-api/models"
"linhdevtran99/rest-api/utils" "linhdevtran99/rest-api/utils"
"net/http" "net/http"
"time"
) )
// Check the user register field is valid or not type ResponseError struct {
func CheckAndValidRegisterFiled(registerData *models.CreateUser, w http.ResponseWriter) bool { Code int
Err error
}
// CheckAndValidRegisterFiled Check the user register field is valid or not
func CheckAndValidRegisterFiled(registerData *models.CreateUser) (bool, *ResponseError) {
_ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator) _ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator)
errs := models.Validate.Struct(registerData) errs := models.Validate.Struct(registerData)
var errStack []string var errStack []string
@ -27,49 +33,45 @@ func CheckAndValidRegisterFiled(registerData *models.CreateUser, w http.Response
switch err.Field() { switch err.Field() {
case "Email": case "Email":
{ {
fmt.Println("Email không hợp lệ") fmt.Println("Internal Log: Email không hợp lệ")
errStack = append(errStack, "Email") errStack = append(errStack, "Email")
} }
case "Username": case "Username":
{ {
fmt.Println("User không hợp lệ") fmt.Println("Internal Log: User không hợp lệ")
errStack = append(errStack, "User") errStack = append(errStack, "User")
} }
case "Password": case "Password":
{ {
fmt.Println("Password không hợp lệ") fmt.Println("Internal Log: Password không hợp lệ")
errStack = append(errStack, "Password") errStack = append(errStack, "Password")
} }
case "ConfirmPassword": case "ConfirmPassword":
{ {
fmt.Println("Nhập lại mật khẩu sai") fmt.Println("Internal Log: Nhập lại mật khẩu sai")
errStack = append(errStack, "ConfirmPassword") errStack = append(errStack, "ConfirmPassword")
} }
case "PhoneNumber": case "PhoneNumber":
{ {
fmt.Println("SĐT không hợp lệ") fmt.Println("Internal Log: SĐT không hợp lệ")
errStack = append(errStack, "PhoneNumber") errStack = append(errStack, "PhoneNumber")
} }
} }
} }
//handle repose error //handle repose error
w.WriteHeader(http.StatusBadRequest) jsonData, _ := json.Marshal(errStack)
err := json.NewEncoder(w).Encode(errStack) return false, &ResponseError{Code: http.StatusBadRequest, Err: errors.New(string(jsonData))}
if err != nil {
fmt.Println("There is error in write reponse at checking info user")
}
return false
} }
return true return true, nil
} }
// Checking in db is user input same data in // CheckAccountExist Checking in db is user input same data in
func CheckAccountExist(mongoClient *mongo.Client, userName string, email string, w http.ResponseWriter) bool { func CheckAccountExist(mongoClient *mongo.Client, userName string, email string) (bool, *ResponseError) {
//filter in mongodb //filter in mongodb
var isValid bool var isValid bool
var errAPI *ResponseError
filter := bson.D{ filter := bson.D{
{"$or", bson.A{ {"$or", bson.A{
@ -78,27 +80,24 @@ func CheckAccountExist(mongoClient *mongo.Client, userName string, email string,
}}, }},
} }
userData := mongoClient.Database("Totoday-shop").Collection("users") _, err := utils.PreUserData.FindOne(context.TODO(), filter).Raw()
var result models.UsersMongo
err := userData.FindOne(context.TODO(), filter).Decode(&result)
if err != nil { if err != nil {
isValid = true isValid = true
} errAPI = nil
if err == nil { } else {
fmt.Println("Email or username already had register") fmt.Println("Internal Log: Email or username already had register")
w.WriteHeader(http.StatusBadRequest)
err := json.NewEncoder(w).Encode("Your username or email had been register before")
if err != nil {
fmt.Println("There is error in write reponse at checking data user register")
}
isValid = false isValid = false
errAPI = &ResponseError{
Code: http.StatusBadRequest,
Err: errors.New("your username or email had been register before"),
}
} }
return isValid return isValid, errAPI
} }
// Generate HOtp for confirm infomation // GeneratorOtp Generate HOtp for confirm information
func GeneratorOtp(userName string, email string, counter uint64, serect string) (bool, *models.OtpGenerate) { func GeneratorOtp(userName string, email string, counter uint64, serect string) (bool, *models.OtpGenerate) {
serectBase32 := base32.StdEncoding.EncodeToString([]byte(serect + userName + email)) serectBase32 := base32.StdEncoding.EncodeToString([]byte(serect + userName + email))
@ -109,19 +108,13 @@ func GeneratorOtp(userName string, email string, counter uint64, serect string)
if err != nil { if err != nil {
fmt.Println("Fail to create OTP") fmt.Println("Fail to create OTP")
return false, &models.OtpGenerate{ return false, nil
PureOTP: "none",
HashOTP: "none",
}
} }
hashed, err := bcrypt.GenerateFromPassword([]byte(passCode), 5) hashed, err := bcrypt.GenerateFromPassword([]byte(passCode), 5)
if err != nil { if err != nil {
fmt.Println("Fail to create OTP") fmt.Println("Fail to create OTP")
return false, &models.OtpGenerate{ return false, nil
PureOTP: "none",
HashOTP: "none",
}
} }
return true, &models.OtpGenerate{ return true, &models.OtpGenerate{
@ -130,15 +123,43 @@ func GeneratorOtp(userName string, email string, counter uint64, serect string)
} }
} }
// Create a alternative verify link // CreateLinkVerify Create a alternative verify link
func CreateLinkVerify(registerInfo *models.CreateUser, secrect string) string { func CreateLinkVerify(registerInfo string, secrect string) string {
return "linh"
}
// check and write pre use into mongo db
func CheckAndWritePreuser(registerInfo *models.PreusersMongo) {
//checking
email := registerInfo.Email
filter := bson.D{{"email", email}}
_, err := utils.PreUserData.FindOne(context.Background(), filter).Raw()
if err != nil {
hashed, err := bcrypt.GenerateFromPassword([]byte(registerInfo.HashPassword), 10)
if err != nil {
fmt.Println("Fail to create OTP")
}
registerInfo.HashPassword = string(hashed)
_, err = utils.PreUserData.InsertOne(context.Background(), registerInfo)
if err != nil {
fmt.Println("Something Went Wrong")
}
} else {
update := bson.D{
{"$inc", bson.D{
{"verify_sent_count", 1},
}},
{"$set", bson.D{
{"update_date", time.Now()},
},
}}
_, err := utils.PreUserData.UpdateOne(context.Background(), filter, update)
if err != nil {
fmt.Println("Internal log: update document fail")
}
}
data, _ := json.Marshal(registerInfo)
key := []byte(secrect)
ciphertext, _ := utils.EncryptAES(data, key)
cipherTextBase64 := base64.StdEncoding.EncodeToString(ciphertext)
return cipherTextBase64
} }

View File

@ -1,79 +1,83 @@
package utils package utils
import ( import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"github.com/golang-jwt/jwt/v5"
"github.com/skip2/go-qrcode"
"net/http"
"strings"
"time"
) )
func EncryptAES(data []byte, key []byte) ([]byte, error) { //Mail
block, err := aes.NewCipher(key)
type MyCustomClaims struct {
Email string `json:"email"`
jwt.RegisteredClaims
}
func buildTokenLink(token string, w http.ResponseWriter) (string, string) {
tokenCustomTrim := strings.ReplaceAll(token, ".", "&")
emailVerifyLink := "http://www.totoday.com/?p=" + tokenCustomTrim
fmt.Println(emailVerifyLink)
png, err := qrcode.Encode(emailVerifyLink, qrcode.Low, 200)
if err != nil { if err != nil {
return nil, err fmt.Println("Internal log: error create qr ")
_ = WriteJSONInternalError(w, "error create QR code")
} }
base64Image := base64.StdEncoding.EncodeToString(png)
dataURL := "data:image/png;base64," + base64Image
// Generate a random IV (Initialization Vector) return emailVerifyLink, dataURL
iv := make([]byte, aes.BlockSize)
if _, err := rand.Read(iv); err != nil {
fmt.Println("error generating IV:", err)
}
// Pad the data to a multiple of the block size
data = pkcs7Pad(data, aes.BlockSize)
// Create a CBC mode cipher block
mode := cipher.NewCBCEncrypter(block, iv)
// Encrypt the data
ciphertext := make([]byte, len(data))
mode.CryptBlocks(ciphertext, data)
// Prepend the IV to the ciphertext
ciphertext = append(iv, ciphertext...)
return ciphertext, nil
} }
func DecryptAES(base64Ciphertext string, key []byte) ([]byte, error) { func EncryptAESMailLink(data string, key string, w http.ResponseWriter) (string, string) {
block, err := aes.NewCipher(key) claims := MyCustomClaims{
data,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
Issuer: "totodayShop",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token.Header["purpose"] = "Email_Verify"
tokenString, err := token.SignedString([]byte(key))
if err != nil { if err != nil {
return nil, err fmt.Println("Internal Log: Error signed token fail", err.Error())
_ = WriteJSONInternalError(w, "Error signing token fail")
} }
// Decode base64 return buildTokenLink(tokenString, w)
ciphertext, err := base64.StdEncoding.DecodeString(base64Ciphertext)
if err != nil {
fmt.Println("error decoding base64:", err)
}
// Extract the IV from the ciphertext
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
// Create a CBC mode cipher block
mode := cipher.NewCBCDecrypter(block, iv)
// Decrypt the data
mode.CryptBlocks(ciphertext, ciphertext)
// Remove padding
ciphertext = pkcs7Unpad(ciphertext)
return ciphertext, nil
} }
// pkcs7Pad pads the input to a multiple of blockSize using PKCS#7 padding //
func pkcs7Pad(data []byte, blockSize int) []byte { //func DecryptAESMailLink(data string, key string) string {
padding := blockSize - len(data)%blockSize //}
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
// pkcs7Unpad removes PKCS#7 padding from the input //OTP
func pkcs7Unpad(data []byte) []byte { //Write preuser to mongo db
padding := int(data[len(data)-1])
return data[:len(data)-padding] //func WriteToMongo(registerInfo *models.PreusersMongo) {
} //
//
//}
//Write otp to redis
//func CheckAndWriteRedis(email string, username string, hashOTP string) {
// //checking does it valid or have in redis or not
// //var count int
// exists, err := Redis.Exists(context.Background(), "otp:nhocdl.poro1@gmail.com").Result()
// if err != nil {
// fmt.Println("something went wrong")
// }
// if exists == 0 {
// //count = 0
//
// }
//}

View File

@ -11,6 +11,7 @@ import (
) )
var MongoDB *mongo.Client var MongoDB *mongo.Client
var PreUserData *mongo.Collection
func InitMongoDriver(mongoUri string) *mongo.Client { func InitMongoDriver(mongoUri string) *mongo.Client {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
@ -30,6 +31,7 @@ func InitMongoDriver(mongoUri string) *mongo.Client {
} }
MongoDB = client MongoDB = client
PreUserData = MongoDB.Database("Totoday-shop").Collection("preusers")
return client return client
} }

View File

@ -9,7 +9,21 @@ import (
func WriteJSON(w http.ResponseWriter, status int, v any) error { func WriteJSON(w http.ResponseWriter, status int, v any) error {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status) w.WriteHeader(status)
return json.NewEncoder(w).Encode(v) err := json.NewEncoder(w).Encode(v)
if err != nil {
return err
}
return nil
}
func WriteJSONInternalError(w http.ResponseWriter, v any) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
err := json.NewEncoder(w).Encode(v)
if err != nil {
return err
}
return nil
} }
type ApiError struct { type ApiError struct {