package controllers import ( "addrss/pkg/auth" "addrss/pkg/router" "fmt" "strings" ) type Auth struct{} func (a Auth) AddRoutes() { router.AddPost(`/auth/guest`, guest).Anonymous() router.AddPost(`/auth/login`, login).Anonymous() router.AddPost(`/auth/logout`, logout).Anonymous() router.AddPost(`/auth/refresh`, refresh).Anonymous() router.AddPut(`/auth/password`, changePassword) } func guest(ctx *router.Context) { tokens, err := auth.AuthenticateGuest() if err != nil { ctx.Response.Unauthorized(err) return } ctx.Response.OK(tokens) } func login(ctx *router.Context) { user := auth.UserLogin{} if err := ctx.Request.Bind(user); err != nil { ctx.Response.BadRequest(err) } tokens, err := auth.AuthenticateUserLogin(user) if err != nil { switch err.(type) { case *auth.ErrorUnauthorized: ctx.Response.Unauthorized(err) case *auth.ErrorForbidden: ctx.Response.Forbidden(err) } return } ctx.Response.OK(tokens) } func logout(ctx *router.Context) { // Logout uses the refresh token authSegments := strings.Split(ctx.Request.Header.Get("Authorization"), " ") if len(authSegments) != 2 || authSegments[0] != "Bearer" { ctx.Response.BadRequest(fmt.Errorf("invalid token")) } claims := auth.RefreshClaims{} if err := auth.ValidateJwtToken(authSegments[1], &claims); err != nil { ctx.Response.Unauthorized(fmt.Errorf("invalid token signature")) } if err := auth.DestroySession(claims.Sub); err != nil { ctx.Response.BadRequest(fmt.Errorf("failed to destroy session")) } ctx.Response.NoContent() } func refresh(ctx *router.Context) { tokens := auth.Tokens{} if err := ctx.Request.Bind(&tokens); err != nil { ctx.Response.BadRequest(err) } tokens, err := auth.AuthenticateUserRefresh(tokens.RefreshToken) if err != nil { ctx.Response.Unauthorized(err) } ctx.Response.OK(tokens) } func changePassword(ctx *router.Context) { pc := auth.PasswordChange{} if err := ctx.Request.Bind(&pc); err != nil { ctx.Response.BadRequest(err) } if pc.UserId != ctx.Claims.Sub { err := fmt.Errorf("user id/sub claim mismatch") ctx.Response.Forbidden(err) } if err := auth.ChangePassword(pc); err != nil { ctx.Response.BadRequest(err) } ctx.Response.NoContent() }