feat: otp api support
This commit is contained in:
parent
16689f6c31
commit
431dec55f9
|
@ -0,0 +1,19 @@
|
||||||
|
package account
|
||||||
|
|
||||||
|
import "github.com/pquerna/otp/totp"
|
||||||
|
|
||||||
|
func TOTPGenerate(domain string, email string) (string, error) {
|
||||||
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
|
Issuer: domain,
|
||||||
|
AccountName: email,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return key.Secret(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TOTPValidate(secret string, code string) bool {
|
||||||
|
return totp.Validate(code, secret)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package account
|
||||||
|
|
||||||
|
import "go.sia.tech/jape"
|
||||||
|
|
||||||
|
func SendJWT(jc jape.Context, jwt string) {
|
||||||
|
jc.ResponseWriter.Header().Set("Authorization", "Bearer "+jwt)
|
||||||
|
}
|
|
@ -74,7 +74,11 @@ func (a AccountAPI) Stop(ctx context.Context) error {
|
||||||
|
|
||||||
func getRoutes(a *AccountAPI) map[string]jape.Handler {
|
func getRoutes(a *AccountAPI) map[string]jape.Handler {
|
||||||
return map[string]jape.Handler{
|
return map[string]jape.Handler{
|
||||||
"/api/login": a.httpHandler.login,
|
"/api/auth/login": a.httpHandler.login,
|
||||||
"api/register": a.httpHandler.register,
|
"/api/auth/register": a.httpHandler.register,
|
||||||
|
"/api/auth/otp/generate": a.httpHandler.otpGenerate,
|
||||||
|
"/api/auth/otp/verify": a.httpHandler.otpVerify,
|
||||||
|
"/api/auth/otp/validate": a.httpHandler.otpValidate,
|
||||||
|
"/api/auth/otp/disable": a.httpHandler.otpDisable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package account
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"git.lumeweb.com/LumeWeb/portal/account"
|
"git.lumeweb.com/LumeWeb/portal/account"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/api/middleware"
|
||||||
"go.sia.tech/jape"
|
"go.sia.tech/jape"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -78,3 +79,76 @@ func (h *HttpHandler) register(jc jape.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) otpGenerate(jc jape.Context) {
|
||||||
|
user := middleware.GetUserFromContext(jc.Request.Context())
|
||||||
|
|
||||||
|
otp, err := h.accounts.OTPGenerate(user)
|
||||||
|
if jc.Check("failed to generate otp", err) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jc.Encode(&OTPGenerateResponse{
|
||||||
|
OTP: otp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) otpVerify(jc jape.Context) {
|
||||||
|
user := middleware.GetUserFromContext(jc.Request.Context())
|
||||||
|
|
||||||
|
var request OTPVerifyRequest
|
||||||
|
|
||||||
|
if jc.Decode(&request) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.accounts.OTPEnable(user, request.OTP)
|
||||||
|
|
||||||
|
if jc.Check("failed to verify otp", err) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) otpValidate(jc jape.Context) {
|
||||||
|
user := middleware.GetUserFromContext(jc.Request.Context())
|
||||||
|
|
||||||
|
var request OTPValidateRequest
|
||||||
|
|
||||||
|
if jc.Decode(&request) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt, err := h.accounts.LoginOTP(user, request.OTP)
|
||||||
|
if jc.Check("failed to validate otp", err) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
account.SendJWT(jc, jwt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandler) otpDisable(jc jape.Context) {
|
||||||
|
user := middleware.GetUserFromContext(jc.Request.Context())
|
||||||
|
|
||||||
|
var request OTPDisableRequest
|
||||||
|
|
||||||
|
if jc.Decode(&request) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
valid, _, err := h.accounts.ValidLoginByUserID(user, request.Password)
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(errInvalidLogin, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if jc.Check("failed to validate password", err) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.accounts.OTPDisable(user)
|
||||||
|
if jc.Check("failed to disable otp", err) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,3 +11,18 @@ type RegisterRequest struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OTPGenerateResponse struct {
|
||||||
|
OTP string `json:"otp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OTPVerifyRequest struct {
|
||||||
|
OTP string `json:"otp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OTPValidateRequest struct {
|
||||||
|
OTP string `json:"otp"`
|
||||||
|
}
|
||||||
|
type OTPDisableRequest struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -20,6 +20,7 @@ require (
|
||||||
github.com/google/uuid v1.5.0
|
github.com/google/uuid v1.5.0
|
||||||
github.com/hashicorp/go-plugin v1.6.0
|
github.com/hashicorp/go-plugin v1.6.0
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/rs/cors v1.10.1
|
github.com/rs/cors v1.10.1
|
||||||
github.com/samber/lo v1.39.0
|
github.com/samber/lo v1.39.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
|
@ -58,6 +59,7 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect
|
||||||
github.com/aws/smithy-go v1.19.0 // indirect
|
github.com/aws/smithy-go v1.19.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/casbin/govaluate v1.1.0 // indirect
|
github.com/casbin/govaluate v1.1.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/dchest/threefish v0.0.0-20120919164726-3ecf4c494abf // indirect
|
github.com/dchest/threefish v0.0.0-20120919164726-3ecf4c494abf // indirect
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -62,6 +62,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
||||||
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
||||||
github.com/casbin/casbin/v2 v2.81.0 h1:vNwJXK7a+TJZElZ5saP+SFJvweZNtJ3MlVP6P4IuRqE=
|
github.com/casbin/casbin/v2 v2.81.0 h1:vNwJXK7a+TJZElZ5saP+SFJvweZNtJ3MlVP6P4IuRqE=
|
||||||
|
@ -260,6 +262,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
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=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||||
|
@ -320,6 +324,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
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=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
|
Loading…
Reference in New Issue