mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-16 21:14:36 +00:00
add otp service (#88)
This commit is contained in:
92
otp/handler/otp.go
Normal file
92
otp/handler/otp.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/micro/v3/service/errors"
|
||||
"github.com/micro/micro/v3/service/logger"
|
||||
pb "github.com/micro/services/otp/proto"
|
||||
"github.com/micro/services/pkg/cache"
|
||||
|
||||
"github.com/pquerna/otp"
|
||||
"github.com/pquerna/otp/totp"
|
||||
)
|
||||
|
||||
type Otp struct{}
|
||||
|
||||
func (e *Otp) Generate(ctx context.Context, req *pb.GenerateRequest, rsp *pb.GenerateResponse) error {
|
||||
if len(req.Id) == 0 {
|
||||
return errors.BadRequest("otp.generate", "missing id")
|
||||
}
|
||||
|
||||
// check if a key exists for the user
|
||||
var secret string
|
||||
|
||||
if err := cache.Get(req.Id, &secret); err != nil {
|
||||
// generate a key
|
||||
key, err := totp.Generate(totp.GenerateOpts{
|
||||
Issuer: "Micro",
|
||||
AccountName: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error("Failed to generate secret: %v", err)
|
||||
return errors.InternalServerError("otp.generate", "failed to generate code")
|
||||
}
|
||||
|
||||
secret = key.Secret()
|
||||
|
||||
if err := cache.Put(req.Id, secret, time.Now().Add(time.Minute*5)); err != nil {
|
||||
logger.Error("Failed to store secret: %v", err)
|
||||
return errors.InternalServerError("otp.generate", "failed to generate code")
|
||||
}
|
||||
}
|
||||
|
||||
// generate a new code
|
||||
code, err := totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{
|
||||
Period: 60,
|
||||
Skew: 1,
|
||||
Digits: otp.DigitsSix,
|
||||
Algorithm: otp.AlgorithmSHA512,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.InternalServerError("otp.generate", "failed to generate code: %v", err)
|
||||
}
|
||||
|
||||
// return the code
|
||||
rsp.Code = code
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Otp) Validate(ctx context.Context, req *pb.ValidateRequest, rsp *pb.ValidateResponse) error {
|
||||
if len(req.Id) == 0 {
|
||||
return errors.BadRequest("otp.generate", "missing id")
|
||||
}
|
||||
if len(req.Code) == 0 {
|
||||
return errors.BadRequest("otp.generate", "missing code")
|
||||
}
|
||||
|
||||
var secret string
|
||||
|
||||
if err := cache.Get(req.Id, &secret); err != nil {
|
||||
logger.Error("Failed to get secret from store: %v", err)
|
||||
return errors.InternalServerError("otp.generate", "failed to validate code")
|
||||
}
|
||||
|
||||
ok, err := totp.ValidateCustom(req.Code, secret, time.Now(), totp.ValidateOpts{
|
||||
Period: 60,
|
||||
Skew: 1,
|
||||
Digits: otp.DigitsSix,
|
||||
Algorithm: otp.AlgorithmSHA1,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServerError("otp.generate", "failed to validate code")
|
||||
}
|
||||
|
||||
// set the response
|
||||
rsp.Success = ok
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user