package main import ( "errors" "fmt" "github.com/google/uuid" "go-nkode/hashset" "go-nkode/models" py_builtin "go-nkode/py-builtin" "go-nkode/util" ) type UserSignSession struct { SessionId uuid.UUID CustomerId uuid.UUID LoginInterface UserInterface KeypadSize models.KeypadSize SetInterface []int ConfirmInterface []int SetKeyEntry []int Username string } func NewSignupSession(keypadSize models.KeypadSize, customerId uuid.UUID) (*UserSignSession, error) { loginInterface, err := NewUserInterface(keypadSize) if err != nil { return nil, err } signupInter, err := signupInterface(*loginInterface) session := UserSignSession{ SessionId: uuid.New(), CustomerId: customerId, LoginInterface: *loginInterface, SetInterface: signupInter.IdxInterface, ConfirmInterface: nil, SetKeyEntry: nil, Username: "", KeypadSize: signupInter.KeypadSize, } return &session, nil } func (s *UserSignSession) DeducePasscode(confirmKeyEntry []int) ([]int, error) { validEntry := py_builtin.All[int](confirmKeyEntry, func(i int) bool { return 0 <= i && i < s.LoginInterface.KeypadSize.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.LoginInterface.KeypadSize.NumbOfKeys)) } if s.SetInterface == nil { return nil, errors.New("signup session set interface is nil") } if s.ConfirmInterface == nil { return nil, errors.New("signup session confirm interface is nil") } if s.SetKeyEntry == nil { return nil, errors.New("signup session set key entry is nil") } if s.Username == "" { return nil, errors.New("signup session username is nil") } if len(confirmKeyEntry) == len(s.SetKeyEntry) { return nil, errors.New(fmt.Sprintf("confirm and set key entry lenght mismatch %d != %d", len(confirmKeyEntry), len(s.SetKeyEntry))) } passcodeLen := len(confirmKeyEntry) setKeyVals, err := s.getSelectedKeyVals(s.SetKeyEntry, s.SetInterface) if err != nil { return nil, err } confirmKeyVals, err := s.getSelectedKeyVals(confirmKeyEntry, s.ConfirmInterface) 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(username string, keySelection []int) ([]int, error) { validKeySelection := py_builtin.All[int](keySelection, func(i int) bool { return 0 <= i && i < s.KeypadSize.NumbOfKeys }) if !validKeySelection { return nil, errors.New(fmt.Sprintf("one or key selection is out of range 0-%d", s.KeypadSize.NumbOfKeys-1)) } s.SetKeyEntry = keySelection s.Username = username setInterface := UserInterface{IdxInterface: s.SetInterface, KeypadSize: s.KeypadSize} err := setInterface.DisperseInterface() if err != nil { return nil, err } s.ConfirmInterface = setInterface.IdxInterface return s.ConfirmInterface, nil } func (s *UserSignSession) getSelectedKeyVals(keySelections []int, userInterface []int) ([][]int, error) { keypadInterface, err := util.ListToMatrix(userInterface, s.KeypadSize.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) (*UserInterface, error) { if baseUserInterface.KeypadSize.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 := baseUserInterface.KeypadSize.NumbOfKeys attrSetView = attrSetView[:numbOfKeys] attrSetView, err = util.MatrixTranspose(attrSetView) if err != nil { return nil, err } signupUserInterface := UserInterface{ IdxInterface: util.MatrixToList(attrSetView), KeypadSize: models.KeypadSize{ AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys, }, } return &signupUserInterface, nil }