package core import ( "errors" "fmt" "github.com/google/uuid" "go-nkode/hashset" py "go-nkode/py-builtin" "go-nkode/util" ) type UserSignSession struct { Id SessionId CustomerId CustomerId LoginUserInterface UserInterface Kp KeypadDimension SetIdxInterface IdxInterface ConfirmIdxInterface IdxInterface SetKeySelection KeySelection UserEmail Email Reset bool Expire int } func NewSignupResetSession(userEmail Email, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) { loginInterface, err := NewUserInterface(&kp, svgInterface) if err != nil { return nil, err } signupInterface, err := signupInterface(*loginInterface, kp) if err != nil { return nil, err } session := UserSignSession{ Id: SessionId(uuid.New()), CustomerId: customerId, LoginUserInterface: *loginInterface, SetIdxInterface: signupInterface.IdxInterface, ConfirmIdxInterface: nil, SetKeySelection: nil, UserEmail: userEmail, Kp: kp, Reset: reset, } return &session, nil } func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) { validEntry := py.All[int](confirmKeyEntry, func(i int) bool { return 0 <= i && i < s.Kp.NumbOfKeys }) if !validEntry { return nil, errors.New(fmt.Sprintf("Invalid Key entry. One or more key index: %#v, not in range 0-%d", confirmKeyEntry, s.Kp.NumbOfKeys)) } if s.SetIdxInterface == nil { return nil, errors.New("signup session set interface is nil") } if s.ConfirmIdxInterface == nil { return nil, errors.New("signup session confirm interface is nil") } if s.SetKeySelection == nil { return nil, errors.New("signup session set key entry is nil") } if s.UserEmail == "" { return nil, errors.New("signup session username is nil") } if len(confirmKeyEntry) != len(s.SetKeySelection) { return nil, errors.New(fmt.Sprintf("confirm and set key entry lenght mismatch %d != %d", len(confirmKeyEntry), len(s.SetKeySelection))) } passcodeLen := len(confirmKeyEntry) setKeyVals, err := s.getSelectedKeyVals(s.SetKeySelection, s.SetIdxInterface) if err != nil { return nil, err } confirmKeyVals, err := s.getSelectedKeyVals(confirmKeyEntry, s.ConfirmIdxInterface) passcode := make([]int, passcodeLen) for idx := 0; idx < passcodeLen; idx++ { setKey := hashset.NewSetFromSlice[int](setKeyVals[idx]) confirmKey := hashset.NewSetFromSlice[int](confirmKeyVals[idx]) intersection := setKey.Intersect(confirmKey) if intersection.Size() < 1 { return nil, errors.New(fmt.Sprintf("set and confirm do not intersect at index %d", idx)) } if intersection.Size() > 1 { return nil, errors.New(fmt.Sprintf("set and confirm intersect at more than one point at index %d", idx)) } intersectionSlice := intersection.ToSlice() passcode[idx] = intersectionSlice[0] } return passcode, nil } func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) { validKeySelection := py.All[int](keySelection, func(i int) bool { return 0 <= i && i < s.Kp.NumbOfKeys }) if !validKeySelection { return nil, errors.New(fmt.Sprintf("one or key selection is out of range 0-%d", s.Kp.NumbOfKeys-1)) } s.SetKeySelection = keySelection setKp := s.SignupKeypad() setInterface := UserInterface{IdxInterface: s.SetIdxInterface, Kp: &setKp} err := setInterface.DisperseInterface() if err != nil { return nil, err } s.ConfirmIdxInterface = setInterface.IdxInterface return s.ConfirmIdxInterface, nil } func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInterface []int) ([][]int, error) { signupKp := s.SignupKeypad() keypadInterface, err := util.ListToMatrix(userInterface, signupKp.AttrsPerKey) if err != nil { return nil, err } keyVals := make([][]int, len(keySelections)) for idx, keyIdx := range keySelections { keyVals[idx] = keypadInterface[keyIdx] } return keyVals, nil } func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, error) { if kp.IsDispersable() { return nil, errors.New("keypad is dispersable, can't use signupInterface") } err := baseUserInterface.RandomShuffle() if err != nil { return nil, err } interfaceMatrix, err := baseUserInterface.InterfaceMatrix() if err != nil { return nil, err } attrSetView, err := util.MatrixTranspose(interfaceMatrix) if err != nil { return nil, err } err = util.FisherYatesShuffle[[]int](&attrSetView) if err != nil { return nil, err } numbOfKeys := kp.NumbOfKeys attrSetView = attrSetView[:numbOfKeys] attrSetView, err = util.MatrixTranspose(attrSetView) if err != nil { return nil, err } signupUserInterface := UserInterface{ IdxInterface: util.MatrixToList(attrSetView), Kp: &KeypadDimension{ AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys, }, } return &signupUserInterface, nil } func (s *UserSignSession) SignupKeypad() KeypadDimension { return KeypadDimension{ AttrsPerKey: s.Kp.NumbOfKeys, NumbOfKeys: s.Kp.NumbOfKeys, } }