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  }