Porównaj commity

...

3 Commity

Autor SHA1 Wiadomość Data
Xeronith 4aa1a79b64 test(components): 🧪 password change 2023-06-05 11:32:29 +03:30
Xeronith 03f12913da feat(app): 🔒 add password change command 2023-06-05 11:32:29 +03:30
Xeronith 7357551a76 feat(components): password change 2023-06-05 11:32:29 +03:30
21 zmienionych plików z 621 dodań i 260 usunięć

Wyświetl plik

@ -0,0 +1,29 @@
package commands
import (
. "github.com/reiver/greatape/components/constants"
. "github.com/reiver/greatape/components/contracts"
)
func ChangePassword(x IDispatcher, currentPassword string, newPassword string) (IChangePasswordResult, error) {
identity := x.Identity().(IIdentity)
if len(identity.Token()) < 10 {
return nil, ERROR_ACCOUNT_NOT_VERIFIED
}
if x.GenerateHash(currentPassword, identity.Salt()) != identity.Hash() {
return nil, ERROR_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD
}
hash := x.GenerateHash(newPassword, identity.Salt())
token := x.GenerateJwtToken()
x.Atomic(func() error {
identity.UpdateHashAtomic(x.Transaction(), hash, identity)
identity.UpdateTokenAtomic(x.Transaction(), token, identity)
x.IdentityManager().RefreshTokenCache(identity, token)
return nil
})
return x.NewChangePasswordResult(), nil
}

Wyświetl plik

@ -124,6 +124,19 @@ func TestUpdateProfileByUserApi(test *testing.T) {
}
}
func TestChangePasswordApi(test *testing.T) {
input := &ChangePasswordRequest{
CurrentPassword: "current_password",
NewPassword: "new_password",
}
if output, err := api.ChangePassword(input); err != nil {
test.Fatal(err)
} else if output == nil {
test.Fail()
}
}
func TestLogoutApi(test *testing.T) {
input := &LogoutRequest{}

Wyświetl plik

@ -0,0 +1,51 @@
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 changePasswordOperation struct {
SecureOperation
run func(IContext, *ChangePasswordRequest) (*ChangePasswordResult, error)
}
func ChangePasswordOperation() IOperation {
return &changePasswordOperation{
run: ChangePasswordService,
}
}
func (operation *changePasswordOperation) Id() (ID, ID) {
return CHANGE_PASSWORD_REQUEST, CHANGE_PASSWORD_RESULT
}
func (operation *changePasswordOperation) InputContainer() Pointer {
return new(ChangePasswordRequest)
}
func (operation *changePasswordOperation) OutputContainer() Pointer {
return new(ChangePasswordResult)
}
func (operation *changePasswordOperation) Execute(context IContext, payload Pointer) (Pointer, error) {
return operation.run(context, payload.(*ChangePasswordRequest))
}
/*
func (operation *changePasswordOperation) ExecutionTimeLimits() (Duration, Duration, Duration) {
var (
TIME_LIMIT_WARNING Duration = 20_000_000
TIME_LIMIT_ALERT Duration = 35_000_000
TIME_LIMIT_CRITICAL Duration = 50_000_000
)
return TIME_LIMIT_WARNING, TIME_LIMIT_ALERT, TIME_LIMIT_CRITICAL
}
*/

Wyświetl plik

@ -14,6 +14,7 @@ func (factory *operationFactory) Operations() []IOperation {
LoginOperation(),
GetProfileByUserOperation(),
UpdateProfileByUserOperation(),
ChangePasswordOperation(),
LogoutOperation(),
WebfingerOperation(),
GetPackagesOperation(),

Wyświetl plik

@ -104,6 +104,16 @@ message UpdateProfileByUserResult {
string github = 0x00000005;
}
// API: ChangePassword
//-----------------------------------------------------------
message ChangePasswordRequest {
string currentPassword = 0x00000001;
string newPassword = 0x00000002;
}
message ChangePasswordResult {
}
// API: Logout
//-----------------------------------------------------------
message LogoutRequest {

Wyświetl plik

@ -0,0 +1,27 @@
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"
)
// noinspection GoUnusedParameter
func ChangePasswordService(context IContext, input *ChangePasswordRequest) (result *ChangePasswordResult, err error) {
conductor := core.Conductor
conductor.LogRemoteCall(context, INITIALIZE, "change_password", input, result, err)
defer func() { conductor.LogRemoteCall(context, FINALIZE, "change_password", input, result, err) }()
_result, _err := conductor.ChangePassword(input.CurrentPassword, input.NewPassword, context.Identity())
if _err != nil {
err = _err
return nil, err
}
_ = _result
result = context.ResultContainer().(*ChangePasswordResult)
return result, nil
}

Wyświetl plik

@ -14,7 +14,6 @@ import (
// noinspection GoUnusedParameter
func SystemCallService(context IContext, input *SystemCallRequest) (result *SystemCallResult, err error) {
conductor := core.Conductor
_ = SYSTEM_CALL_REQUEST
conductor.LogRemoteCall(context, INITIALIZE, "system_call", input, result, err)
defer func() { conductor.LogRemoteCall(context, FINALIZE, "system_call", input, result, err) }()

Wyświetl plik

@ -54,6 +54,8 @@ const (
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"
ERROR_MESSAGE_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD = "ERROR_MESSAGE_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD"
ERROR_MESSAGE_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD = "ERROR_MESSAGE_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD"
ERROR_MESSAGE_INVALID_RESOURCE_FOR_WEBFINGER = "ERROR_MESSAGE_INVALID_RESOURCE_FOR_WEBFINGER"
// CUSTOM_ERRORS
ERROR_MESSAGE_DATA_INTEGRITY_VIOLATION = "ERROR_MESSAGE_DATA_INTEGRITY_VIOLATION"
@ -121,6 +123,8 @@ var (
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)
ERROR_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD = errors.New(ERROR_MESSAGE_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD)
ERROR_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD = errors.New(ERROR_MESSAGE_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD)
ERROR_INVALID_RESOURCE_FOR_WEBFINGER = errors.New(ERROR_MESSAGE_INVALID_RESOURCE_FOR_WEBFINGER)
// CUSTOM_ERRORS
ERROR_DATA_INTEGRITY_VIOLATION = errors.New(ERROR_MESSAGE_DATA_INTEGRITY_VIOLATION)

Wyświetl plik

@ -54,6 +54,8 @@ var Errors = Resource{
ERROR_MESSAGE_INVALID_EMAIL_FOR_VERIFY: "invalid_email",
ERROR_MESSAGE_INVALID_EMAIL_FOR_LOGIN: "invalid_email",
ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN: "invalid_password",
ERROR_MESSAGE_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD: "invalid_current_password",
ERROR_MESSAGE_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD: "invalid_new_password",
ERROR_MESSAGE_INVALID_RESOURCE_FOR_WEBFINGER: "invalid_resource",
// CUSTOM_ERRORS
ERROR_MESSAGE_DATA_INTEGRITY_VIOLATION: "data_integrity_violation",
@ -72,4 +74,6 @@ var Errors = Resource{
func init() {
// CUSTOM_ERRORS
Errors[ERROR_MESSAGE_DATA_INTEGRITY_VIOLATION] = "data_integrity_violation"
Errors[ERROR_MESSAGE_INVALID_PASSWORD_FOR_SIGNUP] = "Your password should be at least 7 characters long including uppercase and lowercase letters, numbers and special characters."
Errors[ERROR_MESSAGE_INVALID_PASSWORD_FOR_LOGIN] = "Your password should be at least 7 characters long including uppercase and lowercase letters, numbers and special characters."
}

Wyświetl plik

@ -14,6 +14,7 @@ type IApi interface {
Login(*LoginRequest) (*LoginResult, error)
GetProfileByUser(*GetProfileByUserRequest) (*GetProfileByUserResult, error)
UpdateProfileByUser(*UpdateProfileByUserRequest) (*UpdateProfileByUserResult, error)
ChangePassword(*ChangePasswordRequest) (*ChangePasswordResult, error)
Logout(*LogoutRequest) (*LogoutResult, error)
Webfinger(*WebfingerRequest) (*WebfingerResult, error)
GetPackages(*GetPackagesRequest) (*GetPackagesResult, error)

Wyświetl plik

@ -36,6 +36,10 @@ const (
UPDATE_PROFILE_BY_USER_REQUEST = 0xC25AB0BA
UPDATE_PROFILE_BY_USER_RESULT = 0x678A8BAF
//ChangePasswordOperation
CHANGE_PASSWORD_REQUEST = 0x926A5565
CHANGE_PASSWORD_RESULT = 0x521E68DF
//LogoutOperation
LOGOUT_REQUEST = 0x447AFA34
LOGOUT_RESULT = 0x9412D17F
@ -101,6 +105,8 @@ var OPCODES = Opcodes{
0x8EECDE97: "GetProfileByUser",
0xC25AB0BA: "UPDATE_PROFILE_BY_USER",
0x678A8BAF: "UpdateProfileByUser",
0x926A5565: "CHANGE_PASSWORD",
0x521E68DF: "ChangePassword",
0x447AFA34: "LOGOUT",
0x9412D17F: "Logout",
0x01FD357C: "WEBFINGER",

Wyświetl plik

@ -62,6 +62,7 @@ type (
Login(email string, password string, editor Identity) (ILoginResult, error)
GetProfileByUser(editor Identity) (IGetProfileByUserResult, error)
UpdateProfileByUser(displayName string, avatar string, banner string, summary string, github string, editor Identity) (IUpdateProfileByUserResult, error)
ChangePassword(currentPassword string, newPassword string, editor Identity) (IChangePasswordResult, error)
Logout(editor Identity) (ILogoutResult, error)
Webfinger(resource string, editor Identity) (IWebfingerResult, error)
GetPackages(editor Identity) (IGetPackagesResult, error)
@ -115,6 +116,9 @@ type (
Github() string
}
IChangePasswordResult interface {
}
ILogoutResult interface {
}

Wyświetl plik

@ -264,6 +264,7 @@ type (
Login(email string, password string, editor Identity) (ILoginResult, error)
GetProfileByUser(editor Identity) (IGetProfileByUserResult, error)
UpdateProfileByUser(displayName string, avatar string, banner string, summary string, github string, editor Identity) (IUpdateProfileByUserResult, error)
ChangePassword(currentPassword string, newPassword string, editor Identity) (IChangePasswordResult, error)
Logout(editor Identity) (ILogoutResult, error)
Webfinger(resource string, editor Identity) (IWebfingerResult, error)
GetPackages(editor Identity) (IGetPackagesResult, error)
@ -301,6 +302,7 @@ type (
NewLoginResult(username string, token string, ignored interface{}) ILoginResult
NewGetProfileByUserResult(username string, displayName string, avatar string, banner string, summary string, github string, ignored interface{}) IGetProfileByUserResult
NewUpdateProfileByUserResult(displayName string, avatar string, banner string, summary string, github string, ignored interface{}) IUpdateProfileByUserResult
NewChangePasswordResult(ignored interface{}) IChangePasswordResult
NewLogoutResult(ignored interface{}) ILogoutResult
NewWebfingerResult(aliases []string, links []IActivityPubLink, subject string, ignored interface{}) IWebfingerResult
NewGetPackagesResult(body []byte, ignored interface{}) IGetPackagesResult

Wyświetl plik

@ -1039,6 +1039,7 @@ type IDispatcher interface {
Login(email string, password string) (ILoginResult, error)
GetProfileByUser() (IGetProfileByUserResult, error)
UpdateProfileByUser(displayName string, avatar string, banner string, summary string, github string) (IUpdateProfileByUserResult, error)
ChangePassword(currentPassword string, newPassword string) (IChangePasswordResult, error)
Logout() (ILogoutResult, error)
Webfinger(resource string) (IWebfingerResult, error)
GetPackages() (IGetPackagesResult, error)
@ -1134,6 +1135,8 @@ type IDispatcher interface {
NewGetProfileByUserResult(username string, displayName string, avatar string, banner string, summary string, github string) IGetProfileByUserResult
// NewUpdateProfileByUserResult creates a new result container for 'Update Profile By User' system action.
NewUpdateProfileByUserResult(displayName string, avatar string, banner string, summary string, github string) IUpdateProfileByUserResult
// NewChangePasswordResult creates a new result container for 'Change Password' system action.
NewChangePasswordResult() IChangePasswordResult
// NewLogoutResult creates a new result container for 'Logout' system action.
NewLogoutResult() ILogoutResult
// NewWebfingerResult creates a new result container for 'Webfinger' system action.

Wyświetl plik

@ -85,6 +85,16 @@ func (api *api) UpdateProfileByUser(request *UpdateProfileByUserRequest) (*Updat
}
}
func (api *api) ChangePassword(request *ChangePasswordRequest) (*ChangePasswordResult, error) {
result, err := api.call(CHANGE_PASSWORD_REQUEST, request)
if err != nil {
return nil, err
} else {
return result.(*ChangePasswordResult), nil
}
}
func (api *api) Logout(request *LogoutRequest) (*LogoutResult, error) {
result, err := api.call(LOGOUT_REQUEST, request)
@ -214,6 +224,7 @@ func init() {
API_RESULT[LOGIN_RESULT] = LoginResult{}
API_RESULT[GET_PROFILE_BY_USER_RESULT] = GetProfileByUserResult{}
API_RESULT[UPDATE_PROFILE_BY_USER_RESULT] = UpdateProfileByUserResult{}
API_RESULT[CHANGE_PASSWORD_RESULT] = ChangePasswordResult{}
API_RESULT[LOGOUT_RESULT] = LogoutResult{}
API_RESULT[WEBFINGER_RESULT] = WebfingerResult{}
API_RESULT[GET_PACKAGES_RESULT] = GetPackagesResult{}

Wyświetl plik

@ -1122,6 +1122,10 @@ func (conductor *conductor) UpdateProfileByUser(displayName string, avatar strin
return conductor.spiManager.UpdateProfileByUser(displayName, avatar, banner, summary, github, editor)
}
func (conductor *conductor) ChangePassword(currentPassword string, newPassword string, editor Identity) (IChangePasswordResult, error) {
return conductor.spiManager.ChangePassword(currentPassword, newPassword, editor)
}
func (conductor *conductor) Logout(editor Identity) (ILogoutResult, error) {
return conductor.spiManager.Logout(editor)
}
@ -1266,6 +1270,10 @@ func (conductor *conductor) NewUpdateProfileByUserResult(displayName string, ava
return NewUpdateProfileByUserResult(displayName, avatar, banner, summary, github, nil)
}
func (conductor *conductor) NewChangePasswordResult(_ interface{}) IChangePasswordResult {
return NewChangePasswordResult(nil)
}
func (conductor *conductor) NewLogoutResult(_ interface{}) ILogoutResult {
return NewLogoutResult(nil)
}
@ -1315,6 +1323,10 @@ func (conductor *conductor) NewGetInboxResult(context string, id string, type_ s
}
func (conductor *conductor) LogRemoteCall(context IContext, eventType uint32, source string, input, result interface{}, err error) {
if !context.Configuration().IsTrafficRecordEnabled() {
return
}
errorMessage := ""
if err != nil {
errorMessage = strings.TrimPrefix(err.Error(), "ERROR_MESSAGE_")

Wyświetl plik

@ -268,6 +268,10 @@ func (dispatcher *dispatcher) UpdateProfileByUser(displayName string, avatar str
return dispatcher.conductor.SpiManager().UpdateProfileByUser(displayName, avatar, banner, summary, github, dispatcher.identity)
}
func (dispatcher *dispatcher) ChangePassword(currentPassword string, newPassword string) (IChangePasswordResult, error) {
return dispatcher.conductor.SpiManager().ChangePassword(currentPassword, newPassword, dispatcher.identity)
}
func (dispatcher *dispatcher) Logout() (ILogoutResult, error) {
return dispatcher.conductor.SpiManager().Logout(dispatcher.identity)
}

Wyświetl plik

@ -544,6 +544,42 @@ func (manager *spiManager) UpdateProfileByUser(displayName string, avatar string
}
}
//region IChangePasswordResult Implementation
type changePasswordResult struct {
}
func NewChangePasswordResult(_ interface{}) IChangePasswordResult {
return &changePasswordResult{}
}
//endregion
func (manager *spiManager) ChangePassword(currentPassword string, newPassword string, editor Identity) (result IChangePasswordResult, err error) {
if !validators.PasswordIsValid(currentPassword) {
return nil, ERROR_INVALID_CURRENT_PASSWORD_FOR_CHANGE_PASSWORD
}
if !validators.PasswordIsValid(newPassword) {
return nil, ERROR_INVALID_NEW_PASSWORD_FOR_CHANGE_PASSWORD
}
defer func() {
if reason := recover(); reason != nil {
err = manager.Error(reason)
}
}()
editor.Lock(CHANGE_PASSWORD_REQUEST)
defer editor.Unlock(CHANGE_PASSWORD_REQUEST)
if result, err = commands.ChangePassword(NewDispatcher(Conductor, editor), currentPassword, newPassword); err != nil {
return nil, err
} else {
return result, nil
}
}
//region ILogoutResult Implementation
type logoutResult struct {

Wyświetl plik

@ -226,6 +226,17 @@ func TestSpiManager_UpdateProfileByUser(test *testing.T) {
_ = result
}
func TestSpiManager_ChangePassword(test *testing.T) {
manager := Conductor.SpiManager()
result, err := manager.ChangePassword("current_password", "new_password", nil)
if err != nil {
test.Fatal(err)
}
_ = result
}
func TestSpiManager_Logout(test *testing.T) {
manager := Conductor.SpiManager()

Wyświetl plik

@ -32,6 +32,10 @@ func (dispatcher *dispatcher) NewUpdateProfileByUserResult(displayName string, a
return NewUpdateProfileByUserResult(displayName, avatar, banner, summary, github, nil)
}
func (dispatcher *dispatcher) NewChangePasswordResult() IChangePasswordResult {
return NewChangePasswordResult(nil)
}
func (dispatcher *dispatcher) NewLogoutResult() ILogoutResult {
return NewLogoutResult(nil)
}