github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/registry/impl_resetpassword.go (about) 1 /* 2 * Copyright (c) 2020-present unTill Pro, Ltd. 3 */ 4 5 package registry 6 7 import ( 8 "context" 9 "fmt" 10 "net/http" 11 12 "github.com/voedger/voedger/pkg/istructs" 13 "github.com/voedger/voedger/pkg/istructsmem" 14 "github.com/voedger/voedger/pkg/itokens" 15 payloads "github.com/voedger/voedger/pkg/itokens-payloads" 16 "github.com/voedger/voedger/pkg/state" 17 "github.com/voedger/voedger/pkg/sys/authnz" 18 coreutils "github.com/voedger/voedger/pkg/utils" 19 "github.com/voedger/voedger/pkg/utils/federation" 20 ) 21 22 func provideResetPassword(cfgRegistry *istructsmem.AppConfigType, itokens itokens.ITokens, federation federation.IFederation) { 23 24 // sys/registry/pseudoProfileWSID/q.sys.InitiateResetPasswordByEmail 25 // null auth 26 cfgRegistry.Resources.Add(istructsmem.NewQueryFunction( 27 QNameQueryInitiateResetPasswordByEmail, 28 provideQryInitiateResetPasswordByEmailExec(itokens, federation), 29 )) 30 31 // sys/registry/pseudoProfileWSID/q.registry.IssueVerifiedValueTokenForResetPassword 32 // null auth 33 cfgRegistry.Resources.Add(istructsmem.NewQueryFunction( 34 QNameQueryIssueVerifiedValueTokenForResetPassword, 35 provideIssueVerifiedValueTokenForResetPasswordExec(itokens, federation), 36 )) 37 38 cfgRegistry.Resources.Add(istructsmem.NewCommandFunction( 39 QNameCommandResetPasswordByEmail, 40 cmdResetPasswordByEmailExec, 41 )) 42 } 43 44 // sys/registry/pseudoWSID 45 // null auth 46 func provideQryInitiateResetPasswordByEmailExec(itokens itokens.ITokens, federation federation.IFederation) istructsmem.ExecQueryClosure { 47 return func(ctx context.Context, args istructs.ExecQueryArgs, callback istructs.ExecQueryCallback) (err error) { 48 loginAppStr := args.ArgumentObject.AsString(authnz.Field_AppName) 49 email := args.ArgumentObject.AsString(field_Email) 50 language := args.ArgumentObject.AsString(field_Language) 51 login := email // TODO: considering login is email 52 53 loginAppQName, err := istructs.ParseAppQName(loginAppStr) 54 if err != nil { 55 return coreutils.NewHTTPError(http.StatusBadRequest, err) 56 } 57 58 cdocLoginID, err := GetCDocLoginID(args.State, args.WSID, loginAppStr, login) 59 if err != nil { 60 return err 61 } 62 if cdocLoginID == 0 { 63 return coreutils.NewHTTPErrorf(http.StatusBadRequest, "login does not exist") 64 } 65 66 // check CDoc<registry.Login>.WSID != 0 67 kb, err := args.State.KeyBuilder(state.Record, QNameCDocLogin) 68 if err != nil { 69 return err 70 } 71 kb.PutRecordID(state.Field_ID, cdocLoginID) 72 sv, err := args.State.MustExist(kb) 73 if err != nil { 74 return err 75 } 76 profileWSID := sv.AsInt64(authnz.Field_WSID) 77 if profileWSID == 0 { 78 return coreutils.NewHTTPErrorf(http.StatusLocked, "login profile is not initialized") 79 } 80 81 sysToken, err := payloads.GetSystemPrincipalToken(itokens, loginAppQName) 82 if err != nil { 83 return err 84 } 85 body := fmt.Sprintf(`{"args":{"Entity":"%s","Field":"%s","Email":"%s","TargetWSID":%d,"ForRegistry":true,"Language":"%s"},"elements":[{"fields":["VerificationToken"]}]}`, 86 QNameCommandResetPasswordByEmailUnloggedParams, field_Email, email, profileWSID, language) // targetWSID - is the workspace we're going to use the verified value at 87 resp, err := federation.Func(fmt.Sprintf("api/%s/%d/q.sys.InitiateEmailVerification", loginAppQName, profileWSID), body, coreutils.WithAuthorizeBy(sysToken)) 88 if err != nil { 89 return fmt.Errorf("q.sys.InitiateEmailVerification failed: %w", err) 90 } 91 92 verificationToken := resp.SectionRow()[0].(string) 93 return callback(&result{token: verificationToken, profileWSID: profileWSID}) 94 } 95 } 96 97 // sys/registry/pseudoWSID 98 // null auth 99 func provideIssueVerifiedValueTokenForResetPasswordExec(itokens itokens.ITokens, federation federation.IFederation) istructsmem.ExecQueryClosure { 100 return func(ctx context.Context, args istructs.ExecQueryArgs, callback istructs.ExecQueryCallback) (err error) { 101 token := args.ArgumentObject.AsString(field_VerificationToken) 102 code := args.ArgumentObject.AsString(field_VerificationCode) 103 profileWSID := args.ArgumentObject.AsInt64(field_ProfileWSID) 104 loginAppStr := args.ArgumentObject.AsString(authnz.Field_AppName) 105 106 loginAppQName, err := istructs.ParseAppQName(loginAppStr) 107 if err != nil { 108 return coreutils.NewHTTPError(http.StatusBadRequest, err) 109 } 110 111 sysToken, err := payloads.GetSystemPrincipalToken(itokens, loginAppQName) 112 if err != nil { 113 return err 114 } 115 116 body := fmt.Sprintf(`{"args":{"VerificationToken":"%s","VerificationCode":"%s","ForRegistry":true},"elements":[{"fields":["VerifiedValueToken"]}]}`, token, code) 117 resp, err := federation.Func(fmt.Sprintf("api/%s/%d/q.sys.IssueVerifiedValueToken", loginAppQName, profileWSID), body, coreutils.WithAuthorizeBy(sysToken)) 118 if err != nil { 119 return err 120 } 121 verificationToken := resp.SectionRow()[0].(string) 122 return callback(&result{token: verificationToken}) 123 } 124 } 125 126 // sys/registry/pseudoWSID 127 // null auth 128 func cmdResetPasswordByEmailExec(args istructs.ExecCommandArgs) (err error) { 129 email := args.ArgumentUnloggedObject.AsString(field_Email) 130 newPwd := args.ArgumentUnloggedObject.AsString(field_NewPwd) 131 appName := args.ArgumentObject.AsString(authnz.Field_AppName) 132 login := email 133 134 return ChangePassword(login, args.State, args.Intents, args.WSID, appName, newPwd) 135 } 136 137 func (r *result) AsString(string) string { 138 return r.token 139 } 140 141 func (r *result) AsInt64(string) int64 { 142 return r.profileWSID 143 }