feat(api): improve verification

master
Xeronith 2023-06-19 11:32:56 +03:30
rodzic d7d2804b24
commit a5e7c8953b
18 zmienionych plików z 717 dodań i 393 usunięć

Wyświetl plik

@ -0,0 +1,32 @@
package commands
import (
. "github.com/reiver/greatape/components/constants"
. "github.com/reiver/greatape/components/contracts"
)
func ResendVerificationCode(x IDispatcher, email string) (IResendVerificationCodeResult, error) {
identities := x.FilterIdentities(func(identity IIdentity) bool {
return identity.Email() == email
})
x.Assert(identities.HasExactlyOneItem()).Or(ERROR_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE)
identity := identities.First()
code := identity.Token()
if len(code) >= 10 {
return nil, ERROR_USERNAME_OR_EMAIL_ALREADY_REGISTERED
}
if x.IsStagingEnvironment() || x.IsProductionEnvironment() {
x.Email(email, "resend-verification-code",
map[string]interface{}{
"app": "GreatApe",
"code": code,
})
code = "000000"
}
return x.NewResendVerificationCodeResult(code), nil
}

Wyświetl plik

@ -10,6 +10,7 @@ func (factory *operationFactory) Operations() []IOperation {
EchoOperation(),
CheckUsernameAvailabilityOperation(),
SignupOperation(),
ResendVerificationCodeOperation(),
VerifyOperation(),
LoginOperation(),
GetProfileByUserOperation(),

Wyświetl plik

@ -0,0 +1,39 @@
package operations
import (
. "github.com/reiver/greatape/components/api/protobuf"
. "github.com/reiver/greatape/components/api/services"
. "github.com/reiver/greatape/components/contracts"
. "github.com/xeronith/diamante/contracts/operation"
. "github.com/xeronith/diamante/contracts/service"
. "github.com/xeronith/diamante/contracts/system"
. "github.com/xeronith/diamante/operation"
)
type resendVerificationCodeOperation struct {
Operation
run func(IContext, *ResendVerificationCodeRequest) (*ResendVerificationCodeResult, error)
}
func ResendVerificationCodeOperation() IOperation {
return &resendVerificationCodeOperation{
run: ResendVerificationCodeService,
}
}
func (operation *resendVerificationCodeOperation) Id() (ID, ID) {
return RESEND_VERIFICATION_CODE_REQUEST, RESEND_VERIFICATION_CODE_RESULT
}
func (operation *resendVerificationCodeOperation) InputContainer() Pointer {
return new(ResendVerificationCodeRequest)
}
func (operation *resendVerificationCodeOperation) OutputContainer() Pointer {
return new(ResendVerificationCodeResult)
}
func (operation *resendVerificationCodeOperation) Execute(context IContext, payload Pointer) (Pointer, error) {
return operation.run(context, payload.(*ResendVerificationCodeRequest))
}

Wyświetl plik

@ -48,6 +48,16 @@ message SignupResult {
string code = 0x00000002;
}
// API: ResendVerificationCode
//-----------------------------------------------------------
message ResendVerificationCodeRequest {
string email = 0x00000001;
}
message ResendVerificationCodeResult {
string code = 0x00000001;
}
// API: Verify
//-----------------------------------------------------------
message VerifyRequest {

Wyświetl plik

@ -0,0 +1,23 @@
package services
import (
. "github.com/reiver/greatape/components/api/protobuf"
. "github.com/reiver/greatape/components/contracts"
. "github.com/reiver/greatape/components/core"
. "github.com/xeronith/diamante/contracts/service"
)
func ResendVerificationCodeService(context IContext, input *ResendVerificationCodeRequest) (result *ResendVerificationCodeResult, err error) {
source := "resend_verification_code"
/* //////// */ Conductor.LogRemoteCall(context, INIT, source, input, result, err)
defer func() { Conductor.LogRemoteCall(context, DONE, source, input, result, err) }()
commandResult, err := Conductor.ResendVerificationCode(input.Email, context.Identity())
if err != nil {
return nil, err
}
result = context.ResultContainer().(*ResendVerificationCodeResult)
result.Code = commandResult.Code()
return result, nil
}

Wyświetl plik

@ -51,6 +51,7 @@ const (
ERROR_MESSAGE_INVALID_USERNAME_FOR_SIGNUP = "ERROR_MESSAGE_INVALID_USERNAME_FOR_SIGNUP"
ERROR_MESSAGE_INVALID_EMAIL_FOR_SIGNUP = "ERROR_MESSAGE_INVALID_EMAIL_FOR_SIGNUP"
ERROR_MESSAGE_INVALID_PASSWORD_FOR_SIGNUP = "ERROR_MESSAGE_INVALID_PASSWORD_FOR_SIGNUP"
ERROR_MESSAGE_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE = "ERROR_MESSAGE_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE"
ERROR_MESSAGE_INVALID_EMAIL_FOR_VERIFY = "ERROR_MESSAGE_INVALID_EMAIL_FOR_VERIFY"
ERROR_MESSAGE_INVALID_EMAIL_FOR_LOGIN = "ERROR_MESSAGE_INVALID_EMAIL_FOR_LOGIN"
ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN = "ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN"
@ -120,6 +121,7 @@ var (
ERROR_INVALID_USERNAME_FOR_SIGNUP = errors.New(ERROR_MESSAGE_INVALID_USERNAME_FOR_SIGNUP)
ERROR_INVALID_EMAIL_FOR_SIGNUP = errors.New(ERROR_MESSAGE_INVALID_EMAIL_FOR_SIGNUP)
ERROR_INVALID_PASSWORD_FOR_SIGNUP = errors.New(ERROR_MESSAGE_INVALID_PASSWORD_FOR_SIGNUP)
ERROR_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE = errors.New(ERROR_MESSAGE_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE)
ERROR_INVALID_EMAIL_FOR_VERIFY = errors.New(ERROR_MESSAGE_INVALID_EMAIL_FOR_VERIFY)
ERROR_INVALID_EMAIL_FOR_LOGIN = errors.New(ERROR_MESSAGE_INVALID_EMAIL_FOR_LOGIN)
ERROR_INVALID_PASSWORD_FOR_LOGIN = errors.New(ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN)

Wyświetl plik

@ -51,6 +51,7 @@ var Errors = Resource{
ERROR_MESSAGE_INVALID_USERNAME_FOR_SIGNUP: "invalid_username",
ERROR_MESSAGE_INVALID_EMAIL_FOR_SIGNUP: "invalid_email",
ERROR_MESSAGE_INVALID_PASSWORD_FOR_SIGNUP: "invalid_password",
ERROR_MESSAGE_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE: "invalid_email",
ERROR_MESSAGE_INVALID_EMAIL_FOR_VERIFY: "invalid_email",
ERROR_MESSAGE_INVALID_EMAIL_FOR_LOGIN: "invalid_email",
ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN: "invalid_password",

Wyświetl plik

@ -10,6 +10,7 @@ type IApi interface {
Echo(*EchoRequest) (*EchoResult, error)
CheckUsernameAvailability(*CheckUsernameAvailabilityRequest) (*CheckUsernameAvailabilityResult, error)
Signup(*SignupRequest) (*SignupResult, error)
ResendVerificationCode(*ResendVerificationCodeRequest) (*ResendVerificationCodeResult, error)
Verify(*VerifyRequest) (*VerifyResult, error)
Login(*LoginRequest) (*LoginResult, error)
GetProfileByUser(*GetProfileByUserRequest) (*GetProfileByUserResult, error)

Wyświetl plik

@ -20,6 +20,10 @@ const (
SIGNUP_REQUEST = 0x48DB23BF
SIGNUP_RESULT = 0x83D062B4
//ResendVerificationCodeOperation
RESEND_VERIFICATION_CODE_REQUEST = 0x03373782
RESEND_VERIFICATION_CODE_RESULT = 0x6B101891
//VerifyOperation
VERIFY_REQUEST = 0x8B78F7F6
VERIFY_RESULT = 0x2C8A8A49
@ -101,6 +105,8 @@ var OPCODES = Opcodes{
0x067190FF: "CheckUsernameAvailability",
0x48DB23BF: "SIGNUP",
0x83D062B4: "Signup",
0x03373782: "RESEND_VERIFICATION_CODE",
0x6B101891: "ResendVerificationCode",
0x8B78F7F6: "VERIFY",
0x2C8A8A49: "Verify",
0xF480F151: "LOGIN",

Wyświetl plik

@ -58,6 +58,7 @@ type (
Echo(document IDocument, editor Identity) (IEchoResult, error)
CheckUsernameAvailability(username string, editor Identity) (ICheckUsernameAvailabilityResult, error)
Signup(username string, email string, password string, editor Identity) (ISignupResult, error)
ResendVerificationCode(email string, editor Identity) (IResendVerificationCodeResult, error)
Verify(email string, token string, code string, editor Identity) (IVerifyResult, error)
Login(email string, password string, editor Identity) (ILoginResult, error)
GetProfileByUser(editor Identity) (IGetProfileByUserResult, error)
@ -91,6 +92,10 @@ type (
Code() string
}
IResendVerificationCodeResult interface {
Code() string
}
IVerifyResult interface {
Token() string
}

Wyświetl plik

@ -260,6 +260,7 @@ type (
Echo(document IDocument, editor Identity) (IEchoResult, error)
CheckUsernameAvailability(username string, editor Identity) (ICheckUsernameAvailabilityResult, error)
Signup(username string, email string, password string, editor Identity) (ISignupResult, error)
ResendVerificationCode(email string, editor Identity) (IResendVerificationCodeResult, error)
Verify(email string, token string, code string, editor Identity) (IVerifyResult, error)
Login(email string, password string, editor Identity) (ILoginResult, error)
GetProfileByUser(editor Identity) (IGetProfileByUserResult, error)
@ -299,6 +300,7 @@ type (
NewEchoResult(document IDocument, ignored interface{}) IEchoResult
NewCheckUsernameAvailabilityResult(isAvailable bool, ignored interface{}) ICheckUsernameAvailabilityResult
NewSignupResult(token string, code string, ignored interface{}) ISignupResult
NewResendVerificationCodeResult(code string, ignored interface{}) IResendVerificationCodeResult
NewVerifyResult(token string, ignored interface{}) IVerifyResult
NewLoginResult(username string, token string, ignored interface{}) ILoginResult
NewGetProfileByUserResult(username string, displayName string, avatar string, banner string, summary string, github string, ignored interface{}) IGetProfileByUserResult

Wyświetl plik

@ -1035,6 +1035,7 @@ type IDispatcher interface {
Echo(document IDocument) (IEchoResult, error)
CheckUsernameAvailability(username string) (ICheckUsernameAvailabilityResult, error)
Signup(username string, email string, password string) (ISignupResult, error)
ResendVerificationCode(email string) (IResendVerificationCodeResult, error)
Verify(email string, token string, code string) (IVerifyResult, error)
Login(email string, password string) (ILoginResult, error)
GetProfileByUser() (IGetProfileByUserResult, error)
@ -1128,6 +1129,8 @@ type IDispatcher interface {
NewCheckUsernameAvailabilityResult(isAvailable bool) ICheckUsernameAvailabilityResult
// NewSignupResult creates a new result container for 'Signup' system action.
NewSignupResult(token string, code string) ISignupResult
// NewResendVerificationCodeResult creates a new result container for 'Resend Verification Code' system action.
NewResendVerificationCodeResult(code string) IResendVerificationCodeResult
// NewVerifyResult creates a new result container for 'Verify' system action.
NewVerifyResult(token string) IVerifyResult
// NewLoginResult creates a new result container for 'Login' system action.

Wyświetl plik

@ -45,6 +45,16 @@ func (api *api) Signup(request *SignupRequest) (*SignupResult, error) {
}
}
func (api *api) ResendVerificationCode(request *ResendVerificationCodeRequest) (*ResendVerificationCodeResult, error) {
result, err := api.call(RESEND_VERIFICATION_CODE_REQUEST, request)
if err != nil {
return nil, err
} else {
return result.(*ResendVerificationCodeResult), nil
}
}
func (api *api) Verify(request *VerifyRequest) (*VerifyResult, error) {
result, err := api.call(VERIFY_REQUEST, request)
@ -230,6 +240,7 @@ func init() {
API_RESULT[ECHO_RESULT] = EchoResult{}
API_RESULT[CHECK_USERNAME_AVAILABILITY_RESULT] = CheckUsernameAvailabilityResult{}
API_RESULT[SIGNUP_RESULT] = SignupResult{}
API_RESULT[RESEND_VERIFICATION_CODE_RESULT] = ResendVerificationCodeResult{}
API_RESULT[VERIFY_RESULT] = VerifyResult{}
API_RESULT[LOGIN_RESULT] = LoginResult{}
API_RESULT[GET_PROFILE_BY_USER_RESULT] = GetProfileByUserResult{}

Wyświetl plik

@ -1106,6 +1106,10 @@ func (conductor *conductor) Signup(username string, email string, password strin
return conductor.spiManager.Signup(username, email, password, editor)
}
func (conductor *conductor) ResendVerificationCode(email string, editor Identity) (IResendVerificationCodeResult, error) {
return conductor.spiManager.ResendVerificationCode(email, editor)
}
func (conductor *conductor) Verify(email string, token string, code string, editor Identity) (IVerifyResult, error) {
return conductor.spiManager.Verify(email, token, code, editor)
}
@ -1258,6 +1262,10 @@ func (conductor *conductor) NewSignupResult(token string, code string, _ interfa
return NewSignupResult(token, code, nil)
}
func (conductor *conductor) NewResendVerificationCodeResult(code string, _ interface{}) IResendVerificationCodeResult {
return NewResendVerificationCodeResult(code, nil)
}
func (conductor *conductor) NewVerifyResult(token string, _ interface{}) IVerifyResult {
return NewVerifyResult(token, nil)
}

Wyświetl plik

@ -252,6 +252,10 @@ func (dispatcher *dispatcher) Signup(username string, email string, password str
return dispatcher.conductor.SpiManager().Signup(username, email, password, dispatcher.identity)
}
func (dispatcher *dispatcher) ResendVerificationCode(email string) (IResendVerificationCodeResult, error) {
return dispatcher.conductor.SpiManager().ResendVerificationCode(email, dispatcher.identity)
}
func (dispatcher *dispatcher) Verify(email string, token string, code string) (IVerifyResult, error) {
return dispatcher.conductor.SpiManager().Verify(email, token, code, dispatcher.identity)
}

Wyświetl plik

@ -324,6 +324,49 @@ func (manager *spiManager) Signup(username string, email string, password string
}
}
//region IResendVerificationCodeResult Implementation
type resendVerificationCodeResult struct {
code string
}
func NewResendVerificationCodeResult(code string, _ interface{}) IResendVerificationCodeResult {
return &resendVerificationCodeResult{
code: code,
}
}
func (result resendVerificationCodeResult) Code() string {
return result.code
}
//endregion
func (manager *spiManager) ResendVerificationCode(email string, editor Identity) (result IResendVerificationCodeResult, err error) {
if email != "" {
if match, err := manager.Match(EMAIL, email); err != nil {
return nil, err
} else if !match {
return nil, ERROR_INVALID_EMAIL_FOR_RESEND_VERIFICATION_CODE
}
}
defer func() {
if reason := recover(); reason != nil {
err = manager.Error(reason)
}
}()
editor.Lock(RESEND_VERIFICATION_CODE_REQUEST)
defer editor.Unlock(RESEND_VERIFICATION_CODE_REQUEST)
if result, err = commands.ResendVerificationCode(NewDispatcher(Conductor, editor), email); err != nil {
return nil, err
} else {
return result, nil
}
}
//region IVerifyResult Implementation
type verifyResult struct {

Wyświetl plik

@ -16,6 +16,10 @@ func (dispatcher *dispatcher) NewSignupResult(token string, code string) ISignup
return NewSignupResult(token, code, nil)
}
func (dispatcher *dispatcher) NewResendVerificationCodeResult(code string) IResendVerificationCodeResult {
return NewResendVerificationCodeResult(code, nil)
}
func (dispatcher *dispatcher) NewVerifyResult(token string) IVerifyResult {
return NewVerifyResult(token, nil)
}