Properly handle error and improve error messages

This commit is contained in:
2024-09-21 11:26:25 +07:00
parent 557e7313b2
commit bcdcbd5049
25 changed files with 258 additions and 234 deletions

View File

@ -7,7 +7,6 @@ import (
"fmt"
"github.com/fossyy/filekeeper/app"
googleOauthSetupHandler "github.com/fossyy/filekeeper/handler/auth/google/setup"
signinHandler "github.com/fossyy/filekeeper/handler/signin"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
@ -49,7 +48,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
_, err := app.Server.Cache.GetCache(r.Context(), "CsrfTokens:"+r.URL.Query().Get("state"))
if err != nil {
if errors.Is(err, redis.Nil) {
w.WriteHeader(http.StatusUnauthorized)
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", "csrf_token_error"), http.StatusFound)
return
}
w.WriteHeader(http.StatusInternalServerError)
@ -155,7 +154,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
}
userAgent := r.Header.Get("User-Agent")
browserInfo, osInfo := signinHandler.ParseUserAgent(userAgent)
browserInfo, osInfo := utils.ParseUserAgent(userAgent)
sessionInfo := session.SessionInfo{
SessionID: storeSession.ID,
@ -168,17 +167,24 @@ func GET(w http.ResponseWriter, r *http.Request) {
}
storeSession.Save(w)
session.AddSessionInfo(oauthUser.Email, &sessionInfo)
err = session.AddSessionInfo(oauthUser.Email, &sessionInfo)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
cookie, err := r.Cookie("redirect")
if errors.Is(err, http.ErrNoCookie) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
http.SetCookie(w, &http.Cookie{
Name: "redirect",
MaxAge: -1,
})
http.Redirect(w, r, cookie.Value, http.StatusSeeOther)
return
}

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"errors"
"github.com/fossyy/filekeeper/app"
signinHandler "github.com/fossyy/filekeeper/handler/signin"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/types/models"
@ -121,11 +120,12 @@ func POST(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
userAgent := r.Header.Get("User-Agent")
browserInfo, osInfo := signinHandler.ParseUserAgent(userAgent)
browserInfo, osInfo := utils.ParseUserAgent(userAgent)
sessionInfo := session.SessionInfo{
SessionID: storeSession.ID,
@ -138,7 +138,12 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
storeSession.Save(w)
session.AddSessionInfo(unregisteredUser.Email, &sessionInfo)
err = session.AddSessionInfo(unregisteredUser.Email, &sessionInfo)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
http.Redirect(w, r, "/user", http.StatusSeeOther)
return

View File

@ -2,13 +2,13 @@ package totpHandler
import (
"errors"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/totp"
"github.com/xlzd/gotp"
"net/http"
"strings"
"time"
)
@ -31,7 +31,12 @@ func GET(w http.ResponseWriter, r *http.Request) {
}
func POST(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
err := r.ParseForm()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
code := r.Form.Get("code")
_, user, key := session.GetSession(r)
totp := gotp.NewDefaultTOTP(user.Totp)
@ -46,13 +51,12 @@ func POST(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
if err != nil {
return
}
userAgent := r.Header.Get("User-Agent")
browserInfo, osInfo := ParseUserAgent(userAgent)
browserInfo, osInfo := utils.ParseUserAgent(userAgent)
sessionInfo := session.SessionInfo{
SessionID: storeSession.ID,
@ -65,7 +69,12 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
storeSession.Save(w)
session.AddSessionInfo(user.Email, &sessionInfo)
err = session.AddSessionInfo(user.Email, &sessionInfo)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
cookie, err := r.Cookie("redirect")
if errors.Is(err, http.ErrNoCookie) {
@ -91,64 +100,3 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
}
func ParseUserAgent(userAgent string) (map[string]string, map[string]string) {
browserInfo := make(map[string]string)
osInfo := make(map[string]string)
if strings.Contains(userAgent, "Firefox") {
browserInfo["browser"] = "Firefox"
parts := strings.Split(userAgent, "Firefox/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else if strings.Contains(userAgent, "Chrome") {
browserInfo["browser"] = "Chrome"
parts := strings.Split(userAgent, "Chrome/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else {
browserInfo["browser"] = "Unknown"
browserInfo["version"] = "Unknown"
}
if strings.Contains(userAgent, "Windows") {
osInfo["os"] = "Windows"
parts := strings.Split(userAgent, "Windows ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Macintosh") {
osInfo["os"] = "Mac OS"
parts := strings.Split(userAgent, "Mac OS X ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Linux") {
osInfo["os"] = "Linux"
osInfo["version"] = "Unknown"
} else if strings.Contains(userAgent, "Android") {
osInfo["os"] = "Android"
parts := strings.Split(userAgent, "Android ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "iPhone") || strings.Contains(userAgent, "iPad") || strings.Contains(userAgent, "iPod") {
osInfo["os"] = "iOS"
parts := strings.Split(userAgent, "OS ")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
osInfo["version"] = version
}
} else {
osInfo["os"] = "Unknown"
osInfo["version"] = "Unknown"
}
return browserInfo, osInfo
}

View File

@ -15,6 +15,7 @@ func DELETE(w http.ResponseWriter, r *http.Request) {
file, err := app.Server.Database.GetFile(fileID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -26,12 +27,14 @@ func DELETE(w http.ResponseWriter, r *http.Request) {
err = app.Server.Database.DeleteFile(fileID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err = app.Server.Storage.Delete(r.Context(), fmt.Sprintf("%s/%s", file.OwnerID.String(), file.ID.String()))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}

View File

@ -15,7 +15,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
fileID := r.PathValue("id")
file, err := app.Server.Database.GetFile(fileID)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -31,17 +31,6 @@ func GET(w http.ResponseWriter, r *http.Request) {
}
}
//uploadDir := "uploads"
//currentDir, _ := os.Getwd()
//basePath := filepath.Join(currentDir, uploadDir)
//saveFolder := filepath.Join(basePath, file.OwnerID.String(), file.ID.String())
//
//if filepath.Dir(saveFolder) != filepath.Join(basePath, file.OwnerID.String()) {
// http.Error(w, "Invalid Path", http.StatusInternalServerError)
// app.Server.Logger.Error("invalid path")
// return
//}
rangeHeader := r.Header.Get("Range")
if rangeHeader != "" {
rangeParts := strings.Split(strings.TrimPrefix(rangeHeader, "bytes="), "-")
@ -94,7 +83,7 @@ func sendFileChunk(w http.ResponseWriter, file *models.File, start, end int64) {
chunkKey := fmt.Sprintf("%s/%s/chunk_%d", file.OwnerID.String(), file.ID.String(), i)
chunkData, err := app.Server.Storage.Get(context.TODO(), chunkKey)
if err != nil {
http.Error(w, fmt.Sprintf("Error retrieving chunk: %v", err), http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -112,7 +101,7 @@ func sendFileChunk(w http.ResponseWriter, file *models.File, start, end int64) {
_, err = w.Write(dataToSend)
if err != nil {
http.Error(w, fmt.Sprintf("Error writing chunk: %v", err), http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -120,7 +109,6 @@ func sendFileChunk(w http.ResponseWriter, file *models.File, start, end int64) {
if i == int64(file.TotalChunk)-1 {
err := app.Server.Database.IncrementDownloadCount(file.ID.String())
if err != nil {
http.Error(w, fmt.Sprintf("Error updating download count: %v", err), http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}

View File

@ -15,8 +15,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
files, err := app.Server.Database.GetFiles(userSession.UserID.String(), "", types.All)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
var filesData []types.FileData
@ -46,13 +46,14 @@ func GET(w http.ResponseWriter, r *http.Request) {
allowance, err := app.Server.Database.GetAllowance(userSession.UserID)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
usage, err := app.Server.Service.GetUserStorageUsage(userSession.UserID.String())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -71,8 +72,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
err = component.Render(r.Context(), w)
if err != nil {
fmt.Println(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
}

View File

@ -26,8 +26,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
files, err := app.Server.Database.GetFiles(userSession.UserID.String(), query, fileStatus)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -38,8 +38,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
existingChunks, err := app.Server.Storage.ListObjects(r.Context(), prefix)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -61,10 +61,12 @@ func GET(w http.ResponseWriter, r *http.Request) {
err := component.Render(r.Context(), w)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
return
}
w.WriteHeader(http.StatusForbidden)
return
}

View File

@ -18,6 +18,7 @@ func PATCH(w http.ResponseWriter, r *http.Request) {
file, err := app.Server.Database.GetFile(fileID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -34,6 +35,7 @@ func PATCH(w http.ResponseWriter, r *http.Request) {
newFile, err := app.Server.Database.RenameFile(fileID, newName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -41,8 +43,8 @@ func PATCH(w http.ResponseWriter, r *http.Request) {
existingChunks, err := app.Server.Storage.ListObjects(r.Context(), prefix)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -62,8 +64,8 @@ func PATCH(w http.ResponseWriter, r *http.Request) {
err = component.Render(r.Context(), w)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
fileView.JustFile(fileData)
w.WriteHeader(http.StatusOK)
return
}

View File

@ -12,6 +12,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
fileID := r.PathValue("id")
if err := r.ParseMultipartForm(32 << 20); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -25,28 +26,30 @@ func POST(w http.ResponseWriter, r *http.Request) {
rawIndex := r.FormValue("index")
index, err := strconv.Atoi(rawIndex)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
fileByte, _, err := r.FormFile("chunk")
if err != nil {
app.Server.Logger.Error("error getting upload info: " + err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error("error getting upload info: " + err.Error())
return
}
defer fileByte.Close()
buffer, err := io.ReadAll(fileByte)
if err != nil {
app.Server.Logger.Error("error copying byte to file dst: " + err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error("error copying byte to file dst: " + err.Error())
return
}
err = app.Server.Storage.Add(r.Context(), fmt.Sprintf("%s/%s/chunk_%d", file.OwnerID.String(), file.ID.String(), index), buffer)
if err != nil {
app.Server.Logger.Error("error copying byte to file dst: " + err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error("error copying byte to file dst: " + err.Error())
return
}

View File

@ -36,8 +36,8 @@ func PUT(w http.ResponseWriter, r *http.Request) {
existingChunks, err := app.Server.Storage.ListObjects(r.Context(), prefix)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -55,6 +55,7 @@ func PUT(w http.ResponseWriter, r *http.Request) {
err = component.Render(r.Context(), w)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
}

View File

@ -12,7 +12,6 @@ import (
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"net/http"
"sync"
"time"
"github.com/fossyy/filekeeper/types"
@ -24,8 +23,6 @@ import (
type ForgotPassword struct {
User *models.User
Code string
mu sync.Mutex
CreateTime time.Time
}
func GET(w http.ResponseWriter, r *http.Request) {
@ -39,6 +36,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}
func POST(w http.ResponseWriter, r *http.Request) {
@ -52,6 +50,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
emailForm := r.Form.Get("email")
user, err := app.Server.Service.GetUser(r.Context(), emailForm)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
component := forgotPasswordView.Main("Filekeeper - Forgot Password Page", types.Message{
Code: 0,
@ -65,6 +64,10 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
return
}
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
userData := &models.User{
UserID: uuid.UUID{},
@ -101,7 +104,6 @@ func verifyForgot(user *models.User) error {
userData = &ForgotPassword{
User: user,
Code: code,
CreateTime: time.Now(),
}
newForgotUser, err := json.Marshal(userData)

View File

@ -30,6 +30,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
return
}
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -43,6 +44,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}
func POST(w http.ResponseWriter, r *http.Request) {
@ -58,6 +60,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal([]byte(data), &userData)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -98,12 +101,33 @@ func POST(w http.ResponseWriter, r *http.Request) {
return
}
app.Server.Cache.DeleteCache(r.Context(), "ForgotPasswordCode:"+userData.User.Email)
app.Server.Cache.DeleteCache(r.Context(), "ForgotPassword:"+code)
err = app.Server.Cache.DeleteCache(r.Context(), "ForgotPasswordCode:"+userData.User.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
session.RemoveAllSessions(userData.User.Email)
err = app.Server.Cache.DeleteCache(r.Context(), "ForgotPassword:"+code)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
app.Server.Service.DeleteUser(userData.User.Email)
err = session.RemoveAllSessions(userData.User.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err = app.Server.Service.DeleteUser(userData.User.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
component := forgotPasswordView.ChangeSuccess("Filekeeper - Forgot Password Page")
err = component.Render(r.Context(), w)

View File

@ -16,4 +16,5 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}

View File

@ -1,7 +1,6 @@
package logoutHandler
import (
"errors"
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/types"
"net/http"
@ -14,25 +13,23 @@ func GET(w http.ResponseWriter, r *http.Request) {
userSession := r.Context().Value("user").(types.User)
cookie, err := r.Cookie("Session")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
storeSession := session.Get(cookie.Value)
if err != nil {
if errors.Is(err, &session.SessionNotFoundError{}) {
storeSession.Destroy(w)
}
w.WriteHeader(http.StatusInternalServerError)
return
}
err = storeSession.Delete()
if err != nil {
app.Server.Logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err = session.RemoveSessionInfo(userSession.Email, cookie.Value)
if err != nil {
app.Server.Logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}

View File

@ -9,15 +9,10 @@ import (
"github.com/fossyy/filekeeper/utils"
"github.com/fossyy/filekeeper/view/client/signin"
"net/http"
"strings"
)
var errorMessages = make(map[string]string)
func init() {
}
func init() {
errorMessages = map[string]string{
"redirect_uri_mismatch": "The redirect URI provided does not match the one registered with our service. Please contact the administrator for assistance.",
@ -36,7 +31,7 @@ func init() {
"login_required": "You need to log in again to proceed. Please try logging in again.",
"account_selection_required": "Please select an account to proceed with the request.",
"consent_required": "Consent is required to proceed. Please provide consent to continue.",
"csrf_token_error": "The CSRF token is missing or invalid. Please refresh the page and try again.",
"csrf_token_error": "The CSRF token is missing or invalid. Please try again.",
"suspicious_session": "We've detected unusual activity on your account. Please log in again to confirm it's you.",
}
}
@ -49,7 +44,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
message = "Unknown error occurred. Please contact support at bagas@fossy.my.id for assistance."
}
component = signinView.Main("Sign in Page", types.Message{
component = signinView.Main("Filekeeper - Sign in Page", types.Message{
Code: 0,
Message: message,
})
@ -66,6 +61,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}
func POST(w http.ResponseWriter, r *http.Request) {
@ -95,7 +91,6 @@ func POST(w http.ResponseWriter, r *http.Request) {
if email == userData.Email && utils.CheckPasswordHash(password, userData.Password) {
if userData.Totp != "" {
storeSession, err := session.Create(types.User{
UserID: userData.UserID,
Email: email,
@ -105,6 +100,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
storeSession.Save(w)
@ -120,10 +116,11 @@ func POST(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
userAgent := r.Header.Get("User-Agent")
browserInfo, osInfo := ParseUserAgent(userAgent)
browserInfo, osInfo := utils.ParseUserAgent(userAgent)
sessionInfo := session.SessionInfo{
SessionID: storeSession.ID,
@ -136,7 +133,12 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
storeSession.Save(w)
session.AddSessionInfo(email, &sessionInfo)
err = session.AddSessionInfo(email, &sessionInfo)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
cookie, err := r.Cookie("redirect")
if errors.Is(err, http.ErrNoCookie) {
@ -160,65 +162,5 @@ func POST(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
}
func ParseUserAgent(userAgent string) (map[string]string, map[string]string) {
browserInfo := make(map[string]string)
osInfo := make(map[string]string)
if strings.Contains(userAgent, "Firefox") {
browserInfo["browser"] = "Firefox"
parts := strings.Split(userAgent, "Firefox/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else if strings.Contains(userAgent, "Chrome") {
browserInfo["browser"] = "Chrome"
parts := strings.Split(userAgent, "Chrome/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else {
browserInfo["browser"] = "Unknown"
browserInfo["version"] = "Unknown"
}
if strings.Contains(userAgent, "Windows") {
osInfo["os"] = "Windows"
parts := strings.Split(userAgent, "Windows ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Macintosh") {
osInfo["os"] = "Mac OS"
parts := strings.Split(userAgent, "Mac OS X ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Linux") {
osInfo["os"] = "Linux"
osInfo["version"] = "Unknown"
} else if strings.Contains(userAgent, "Android") {
osInfo["os"] = "Android"
parts := strings.Split(userAgent, "Android ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "iPhone") || strings.Contains(userAgent, "iPad") || strings.Contains(userAgent, "iPod") {
osInfo["os"] = "iOS"
parts := strings.Split(userAgent, "OS ")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
osInfo["version"] = version
}
} else {
osInfo["os"] = "Unknown"
osInfo["version"] = "Unknown"
}
return browserInfo, osInfo
return
}

View File

@ -22,7 +22,6 @@ import (
type UnverifiedUser struct {
User *models.User
Code string
CreateTime time.Time
}
func GET(w http.ResponseWriter, r *http.Request) {
@ -36,6 +35,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}
func POST(w http.ResponseWriter, r *http.Request) {
@ -125,7 +125,6 @@ func verifyEmail(user *models.User) error {
unverifiedUser := UnverifiedUser{
User: user,
Code: code,
CreateTime: time.Now(),
}
newUnverifiedUser, err := json.Marshal(unverifiedUser)
if err != nil {

View File

@ -15,7 +15,6 @@ import (
func GET(w http.ResponseWriter, r *http.Request) {
code := r.PathValue("code")
userDataStr, err := app.Server.Cache.GetCache(context.Background(), "UnverifiedUser:"+code)
if err != nil {
if errors.Is(err, redis.Nil) {
@ -53,11 +52,15 @@ func GET(w http.ResponseWriter, r *http.Request) {
err = app.Server.Cache.DeleteCache(context.Background(), "UnverifiedUser:"+code)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
err = app.Server.Cache.DeleteCache(context.Background(), "VerificationCode:"+unverifiedUser.User.Email)
if err != nil {
app.Server.Logger.Error(err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
component := signupView.VerifySuccess("Filekeeper - Verify Page")
@ -67,4 +70,5 @@ func GET(w http.ResponseWriter, r *http.Request) {
app.Server.Logger.Error(err.Error())
return
}
return
}

View File

@ -9,19 +9,26 @@ import (
)
func POST(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
err := r.ParseForm()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
userSession := r.Context().Value("user").(types.User)
currentPassword := r.Form.Get("currentPassword")
password := r.Form.Get("password")
user, err := app.Server.Service.GetUser(r.Context(), userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
hashPassword, err := utils.HashPassword(password)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -33,11 +40,23 @@ func POST(w http.ResponseWriter, r *http.Request) {
err = app.Server.Database.UpdateUserPassword(user.Email, hashPassword)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
session.RemoveAllSessions(userSession.Email)
app.Server.Service.DeleteUser(userSession.Email)
err = session.RemoveAllSessions(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err = app.Server.Service.DeleteUser(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
http.Redirect(w, r, "/signin", http.StatusSeeOther)
return

View File

@ -1,6 +1,7 @@
package userSessionTerminateHandler
import (
"github.com/fossyy/filekeeper/app"
"github.com/fossyy/filekeeper/session"
"github.com/fossyy/filekeeper/types"
"github.com/fossyy/filekeeper/view/client/user"
@ -16,11 +17,24 @@ func DELETE(w http.ResponseWriter, r *http.Request) {
return
}
otherSession.Delete()
session.RemoveSessionInfo(mySession.Email, otherSession.ID)
err := otherSession.Delete()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err = session.RemoveSessionInfo(mySession.Email, otherSession.ID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
sessions, err := session.GetSessions(mySession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
component := userView.SessionTable(sessions)
@ -30,4 +44,5 @@ func DELETE(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
return
}
return
}

View File

@ -37,8 +37,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
uri := totp.ProvisioningUri(userSession.Email, "filekeeper")
base64Str, err := generateQRCode(uri)
if err != nil {
fmt.Printf("%v\n", err)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -56,6 +56,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
}
if err := component.Render(r.Context(), w); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
}
@ -63,6 +64,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
func POST(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
@ -74,17 +76,23 @@ func POST(w http.ResponseWriter, r *http.Request) {
base64Str, err := generateQRCode(uri)
if err != nil {
fmt.Printf("%v\n", err)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
var component templ.Component
if totp.Verify(code, time.Now().Unix()) {
if err := app.Server.Database.InitializeTotp(userSession.Email, secret); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
err := app.Server.Service.DeleteUser(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
app.Server.Service.DeleteUser(userSession.Email)
if r.Header.Get("hx-request") == "true" {
component = userTotpSetupView.MainContent("Filekeeper - 2FA Setup Page", base64Str, secret, userSession, types.Message{
Code: 1,
@ -99,6 +107,7 @@ func POST(w http.ResponseWriter, r *http.Request) {
if err := component.Render(r.Context(), w); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
return
@ -116,7 +125,9 @@ func POST(w http.ResponseWriter, r *http.Request) {
}
if err := component.Render(r.Context(), w); err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
return
}
}
}

View File

@ -55,7 +55,8 @@ func GET(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("upgrade") == "websocket" {
upgrade, err := upgrader.Upgrade(w, r, nil)
if err != nil {
panic(err)
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
handlerWS(upgrade, userSession)
@ -64,18 +65,21 @@ func GET(w http.ResponseWriter, r *http.Request) {
sessions, err := session.GetSessions(userSession.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
allowance, err := app.Server.Database.GetAllowance(userSession.UserID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}
usage, err := app.Server.Service.GetUserStorageUsage(userSession.UserID.String())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
app.Server.Logger.Error(err.Error())
return
}

View File

@ -59,11 +59,12 @@ func (r *Service) GetUser(ctx context.Context, email string) (*models.User, erro
return &user, nil
}
func (r *Service) DeleteUser(email string) {
func (r *Service) DeleteUser(email string) error {
err := r.cache.DeleteCache(context.Background(), "UserCache:"+email)
if err != nil {
return
return err
}
return nil
}
func (r *Service) GetUserStorageUsage(ownerID string) (uint64, error) {

View File

@ -31,7 +31,6 @@ type SessionInfo struct {
}
type UserStatus string
type SessionNotFoundError struct{}
const (
Authorized UserStatus = "authorized"
@ -40,10 +39,6 @@ const (
Suspicious UserStatus = "suspicious"
)
func (e *SessionNotFoundError) Error() string {
return "session not found"
}
func Get(id string) *Session {
return &Session{ID: id}
}

View File

@ -88,7 +88,7 @@ type CachingServer interface {
type Services interface {
GetUser(ctx context.Context, email string) (*models.User, error)
DeleteUser(email string)
DeleteUser(email string) error
GetFile(id string) (*models.File, error)
GetUserFile(name, ownerID string) (*FileWithDetail, error)
GetUserStorageUsage(ownerID string) (uint64, error)

View File

@ -145,12 +145,63 @@ func GenerateCSRFToken() (string, error) {
return csrfToken, nil
}
func SanitizeFilename(filename string) string {
invalidChars := []string{"\\", "/", ":", "*", "?", "\"", "<", ">", "|"}
for _, char := range invalidChars {
filename = strings.ReplaceAll(filename, char, "_")
func ParseUserAgent(userAgent string) (map[string]string, map[string]string) {
browserInfo := make(map[string]string)
osInfo := make(map[string]string)
if strings.Contains(userAgent, "Firefox") {
browserInfo["browser"] = "Firefox"
parts := strings.Split(userAgent, "Firefox/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else if strings.Contains(userAgent, "Chrome") {
browserInfo["browser"] = "Chrome"
parts := strings.Split(userAgent, "Chrome/")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
browserInfo["version"] = version
}
} else {
browserInfo["browser"] = "Unknown"
browserInfo["version"] = "Unknown"
}
return filename
if strings.Contains(userAgent, "Windows") {
osInfo["os"] = "Windows"
parts := strings.Split(userAgent, "Windows ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Macintosh") {
osInfo["os"] = "Mac OS"
parts := strings.Split(userAgent, "Mac OS X ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "Linux") {
osInfo["os"] = "Linux"
osInfo["version"] = "Unknown"
} else if strings.Contains(userAgent, "Android") {
osInfo["os"] = "Android"
parts := strings.Split(userAgent, "Android ")
if len(parts) > 1 {
version := strings.Split(parts[1], ";")[0]
osInfo["version"] = version
}
} else if strings.Contains(userAgent, "iPhone") || strings.Contains(userAgent, "iPad") || strings.Contains(userAgent, "iPod") {
osInfo["os"] = "iOS"
parts := strings.Split(userAgent, "OS ")
if len(parts) > 1 {
version := strings.Split(parts[1], " ")[0]
osInfo["version"] = version
}
} else {
osInfo["os"] = "Unknown"
osInfo["version"] = "Unknown"
}
return browserInfo, osInfo
}