diff options
| author | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2023-10-04 21:33:42 +0530 | 
|---|---|---|
| committer | Vidhu Kant Sharma <vidhukant@vidhukant.com> | 2023-10-04 21:33:42 +0530 | 
| commit | d8c1d5fedfac65a79490120195e273b5d5fc75e9 (patch) | |
| tree | 7b2b4c6042c693cdd4c827ea9989cfc1bd82ca5d /auth/:w | |
| parent | a0613bfd790b27f313470bddc08371bcbf54968d (diff) | |
added basic token refreshing
Diffstat (limited to 'auth/:w')
| -rw-r--r-- | auth/:w | 182 | 
1 files changed, 182 insertions, 0 deletions
@@ -0,0 +1,182 @@ +/* openbills - Server for web based Libre Billing Software + * Copyright (C) 2023  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +package auth + +import ( +	"github.com/gin-gonic/gin" +	"github.com/golang-jwt/jwt/v5" +	"github.com/spf13/viper" +	"golang.org/x/crypto/bcrypt" +	"vidhukant.com/openbills/user" +	"net/http" +	"time" +	"vidhukant.com/openbills/errors" +) + +var ( +	COST int +	AUTH_KEY, REFRESH_KEY []byte +) +func init() { +	COST = viper.GetInt("cryptography.password_hashing_cost") +	AUTH_KEY = []byte(viper.GetString("cryptography.auth_key")) +	REFRESH_KEY = []byte(viper.GetString("cryptography.refresh_key")) +} + +func handleSignUp (ctx *gin.Context) { +	var user user.User +	ctx.Bind(&user) + +	var err error + +	// hash password +	var bytes []byte +	bytes, err = bcrypt.GenerateFromPassword([]byte(user.Password), 14) +	if err != nil { +		// TODO: handle potential errors +		ctx.Error(err) +		ctx.Abort() +		return +	} +	user.Password = string(bytes) + +	err = user.Create() +	if err != nil { +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	// remove password hash from response +	user.Password = "" + +	ctx.JSON(http.StatusOK, gin.H{ +		"message": "success", +		"data": user, +	}) +} + +func handleSignIn (ctx *gin.Context) { +	var req LoginReq +	ctx.Bind(&req) + +	var err error +	var u user.User + +	err = user.CheckPassword(&u, req.AccountName, req.Method, req.Password) +	if err != nil { +		// TODO: handle potential errors +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	authToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, +		AuthClaims { +			jwt.RegisteredClaims { +				IssuedAt: jwt.NewNumericDate(time.Now()), +				ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 2)), +			}, +			u.ID, +		}, +	).SignedString(AUTH_KEY) +	if err != nil { +		// TODO: handle potential errors +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	refreshToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, +		AuthClaims { +			jwt.RegisteredClaims { +				IssuedAt: jwt.NewNumericDate(time.Now()), +			  ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 6)), +			}, +			u.ID, +		}, +	).SignedString(REFRESH_KEY) +	if err != nil { +		// TODO: handle potential errors +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	// remove password hash from response +	u.Password = "" + +	ctx.JSON(http.StatusOK, gin.H{ +		"auth_token": authToken, +		"refresh_token": refreshToken, +		"message": "success", +		"data": u, +	}) +} + +func handleRefresh (ctx *gin.Context) { +	var req RefreshReq +	ctx.Bind(&req) + +	tk, _ := jwt.ParseWithClaims(req.RefreshToken, &AuthClaims{}, func (token *jwt.Token) (interface{}, error) { +		return []byte(REFRESH_KEY), nil +	}) + +	claims, ok := tk.Claims.(*AuthClaims) +	if !ok { +		ctx.Error(errors.ErrUnauthorized) +		ctx.Abort() +		return +	} + +	if !tk.Valid { +		eat := claims.ExpiresAt.Unix() +		if eat != 0 && eat < time.Now().Unix() { +			ctx.Error(errors.ErrSessionExpired) +		} else { +			ctx.Error(errors.ErrUnauthorized) +		} + +		ctx.Abort() +		return +	} + +	// TODO: if token is valid, check if user even exists before generating authToken + +	authToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, +		AuthClaims { +			jwt.RegisteredClaims { +				IssuedAt: jwt.NewNumericDate(time.Now()), +				ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 2)), +			}, +			claims.UserID, +		}, +	).SignedString(AUTH_KEY) +	if err != nil { +		// TODO: handle potential errors +		ctx.Error(err) +		ctx.Abort() +		return +	} + +	ctx.JSON(http.StatusOK, gin.H{ +		"auth_token": authToken, +		"message": "success", +		//"data": u, +	}) +}  |