309 lines
7.6 KiB
Go
309 lines
7.6 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
ratelimit "github.com/JGLTechnologies/gin-rate-limit"
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-contrib/sessions/cookie"
|
|
"github.com/gin-gonic/gin"
|
|
"html/template"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var sessionStore sessions.Store
|
|
var htmlRL gin.HandlerFunc
|
|
var jsonRL gin.HandlerFunc
|
|
|
|
func createSessionStore() {
|
|
secureBool, err := strconv.ParseBool(os.Getenv("SECURE_SESSION"))
|
|
if err != nil {
|
|
fmt.Printf("Unable to get Secure Session Env, defaulting to \"true\". Error: %v\n", err.Error())
|
|
secureBool = true
|
|
}
|
|
|
|
sessionStore = cookie.NewStore([]byte(os.Getenv("AUTHENTICATION_KEY")), []byte(os.Getenv("ENCRYPTION_KEY")))
|
|
sessionStore.Options(sessions.Options{
|
|
Path: "/",
|
|
MaxAge: 60 * 60 * 24, // 1 day
|
|
HttpOnly: true,
|
|
Secure: secureBool,
|
|
SameSite: http.SameSiteLaxMode,
|
|
})
|
|
}
|
|
|
|
func keyFunc(c *gin.Context) string {
|
|
return c.ClientIP()
|
|
}
|
|
|
|
func createRateLimiters() {
|
|
store := ratelimit.InMemoryStore(&ratelimit.InMemoryOptions{
|
|
Rate: time.Second,
|
|
Limit: 5,
|
|
})
|
|
htmlRL = ratelimit.RateLimiter(store, &ratelimit.Options{
|
|
ErrorHandler: func(c *gin.Context, info ratelimit.Info) {
|
|
c.HTML(http.StatusTooManyRequests, "base.html.tmpl", gin.H{
|
|
"header": "Error",
|
|
"body": fmt.Sprintf("Too many requests. Try again in %v", time.Until(info.ResetTime).String()),
|
|
})
|
|
},
|
|
KeyFunc: keyFunc,
|
|
})
|
|
jsonRL = ratelimit.RateLimiter(store, &ratelimit.Options{
|
|
ErrorHandler: func(c *gin.Context, info ratelimit.Info) {
|
|
c.JSON(http.StatusTooManyRequests, gin.H{})
|
|
},
|
|
KeyFunc: keyFunc,
|
|
})
|
|
}
|
|
|
|
func webRoot(c *gin.Context) {
|
|
c.File("./html/home.html")
|
|
}
|
|
|
|
func webRegister(c *gin.Context) {
|
|
c.File("./html/register.html")
|
|
}
|
|
|
|
func webRegisterSuccess(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "base.html.tmpl", gin.H{
|
|
"header": "Registration Success",
|
|
"body": "We will reach out soon to get your tag to you!",
|
|
})
|
|
}
|
|
|
|
func webQr(c *gin.Context) {
|
|
c.File("./html/genqr.html")
|
|
}
|
|
|
|
func webPing(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "pong",
|
|
})
|
|
}
|
|
|
|
func webUserApi(c *gin.Context) {
|
|
user, err := db.queryUser(strings.ToLower(c.Param("user")))
|
|
if err != nil {
|
|
if errors.Is(err, NoEntriesFoundError) {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
|
"status": 401,
|
|
"error": "Unauthorized",
|
|
})
|
|
return
|
|
}
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
|
"status": 500,
|
|
"error": fmt.Sprintf("Internal Server Error: %s", err.Error()),
|
|
})
|
|
return
|
|
}
|
|
if user.CurrentToken == nil {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
|
"status": 401,
|
|
"error": "Unauthorized",
|
|
})
|
|
return
|
|
}
|
|
if strings.Compare(c.Query("token"), *user.CurrentToken) == 0 {
|
|
user.Status = 200
|
|
c.JSON(http.StatusOK, user)
|
|
return
|
|
}
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
|
"status": 401,
|
|
"error": "Unauthorized",
|
|
})
|
|
}
|
|
|
|
func webVerifyUserApi(c *gin.Context) {
|
|
user, err := db.queryUser(strings.ToLower(c.Param("user")))
|
|
if err != nil {
|
|
if errors.Is(err, NoEntriesFoundError) {
|
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
|
"status": 404,
|
|
"user": "",
|
|
"error": "User not found",
|
|
})
|
|
return
|
|
}
|
|
fmt.Printf("Error: %s\n", err)
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
|
|
"status": 500,
|
|
"user": "",
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
codes := strings.Split(user.SecretCodes, ",")
|
|
codeHeader := c.GetHeader("Authorization")
|
|
reqCodeRaw := strings.Split(codeHeader, " ")
|
|
reqCode := strings.ReplaceAll(reqCodeRaw[len(reqCodeRaw)-1], " ", "")
|
|
for _, code := range codes {
|
|
if strings.Compare(code, reqCode) == 0 {
|
|
token, err := GenerateToken(16)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"status": 500,
|
|
"user": "",
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
err = db.updateToken(user.UserName, token) // TODO make a more robust system for authorizing info page
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"status": 500,
|
|
"user": "",
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
user.Status = 200
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"user": user.UserName,
|
|
"error": "",
|
|
"token": token,
|
|
})
|
|
return
|
|
}
|
|
}
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"status": 404,
|
|
"user": "",
|
|
"error": "User not found",
|
|
})
|
|
}
|
|
|
|
func webCheckNameApi(c *gin.Context) {
|
|
users, err := db.getUsers()
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"status": 500,
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
anyMatch := false
|
|
for _, user := range users {
|
|
if strings.Compare(user, strings.ToLower(c.Param("user"))) == 0 {
|
|
anyMatch = true
|
|
break
|
|
}
|
|
}
|
|
if anyMatch {
|
|
c.JSON(http.StatusConflict, gin.H{
|
|
"status": 409,
|
|
"error": "userid already exists",
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": 200,
|
|
"error": "",
|
|
})
|
|
}
|
|
|
|
func webRegisterApi(c *gin.Context) { //TODO refactor with JS form submission or under logged in user dashboard
|
|
var newUser User
|
|
err := c.ShouldBind(&newUser)
|
|
if err != nil {
|
|
fmt.Printf("Error: %v\n", err)
|
|
c.HTML(http.StatusInternalServerError, "base.html.tmpl", gin.H{
|
|
"header": "Registration Error",
|
|
"body": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
err = db.checkRegistrationCode(newUser.RegistrationCode)
|
|
if errors.Is(err, NoEntriesFoundError) {
|
|
c.HTML(http.StatusNotFound, "base.html.tmpl", gin.H{
|
|
"header": "Registration Error",
|
|
"body": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
c.Redirect(http.StatusSeeOther, "/register/success")
|
|
}
|
|
|
|
func webUser(c *gin.Context) {
|
|
c.File("./html/verify.html")
|
|
}
|
|
|
|
func webUserInfo(c *gin.Context) {
|
|
user, err := db.queryUser(strings.ToLower(c.Param("user")))
|
|
if err != nil {
|
|
if errors.Is(err, NoEntriesFoundError) {
|
|
body := template.HTML("The user searched is not found, please try again.")
|
|
c.HTML(http.StatusNotFound, "base.html.tmpl", gin.H{
|
|
"header": "User Not Found",
|
|
"body": body,
|
|
})
|
|
return
|
|
}
|
|
}
|
|
if user.CurrentToken == nil {
|
|
c.HTML(http.StatusUnauthorized, "base.html.tmpl", gin.H{
|
|
"header": "Unauthorized",
|
|
"body": "You don't have the right token, please try again.",
|
|
})
|
|
return
|
|
}
|
|
if strings.Compare(c.Query("token"), *user.CurrentToken) == 0 {
|
|
if err != nil {
|
|
if errors.Is(err, NoEntriesFoundError) {
|
|
c.HTML(http.StatusUnauthorized, "base.html.tmpl", gin.H{
|
|
"header": "Unauthorized",
|
|
"body": "You don't have the right token, please try again.",
|
|
})
|
|
return
|
|
}
|
|
fmt.Printf("Error: %s\n", err)
|
|
c.HTML(http.StatusInternalServerError, "base.html.tmpl", gin.H{
|
|
"header": "Error",
|
|
"body": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
addressStr := fmt.Sprintf("%s", user.MailingAddress.Street1)
|
|
if user.MailingAddress.Street2 == nil {
|
|
addressStr = fmt.Sprintf("%s, %s", addressStr, user.MailingAddress.City)
|
|
} else {
|
|
addressStr = fmt.Sprintf("%s, %s, %s", addressStr, *user.MailingAddress.Street2, user.MailingAddress.City)
|
|
}
|
|
if user.MailingAddress.State == nil {
|
|
addressStr = fmt.Sprintf("%s, %s, %s", addressStr, user.MailingAddress.PostalCode, user.MailingAddress.Country)
|
|
} else {
|
|
addressStr = fmt.Sprintf("%s, %s, %s, %s", addressStr, *user.MailingAddress.State, user.MailingAddress.PostalCode, user.MailingAddress.Country)
|
|
}
|
|
c.HTML(http.StatusOK, "info.html.tmpl", gin.H{
|
|
"contact_name": user.ContactName,
|
|
"phone_number": user.ContactNumber,
|
|
"email_address": user.EmailAddress,
|
|
"address": addressStr,
|
|
})
|
|
return
|
|
}
|
|
c.HTML(http.StatusUnauthorized, "base.html.tmpl", gin.H{
|
|
"header": "Unauthorized",
|
|
"body": "You don't have the right token :/",
|
|
})
|
|
}
|
|
|
|
func webLoginAuth(c *gin.Context) {
|
|
|
|
}
|
|
|
|
func webLoginAuthPost(c *gin.Context) {
|
|
|
|
}
|
|
|
|
func webLogoutAuth(c *gin.Context) {
|
|
|
|
}
|