Files
go-nkode/pkg/nkode-core/entities/user_signup_session.go
2025-01-21 01:19:27 -06:00

202 lines
6.0 KiB
Go

package entities
import (
"github.com/DonovanKelly/sugar-n-spice/all"
"github.com/DonovanKelly/sugar-n-spice/set"
"github.com/google/uuid"
"go-nkode/config"
"go-nkode/pkg/nkode-core/security"
"log"
"sort"
)
type UserSignSession struct {
Id SessionId
CustomerId CustomerId
LoginUserInterface UserInterface
Kp KeypadDimension
SetIdxInterface IdxInterface
ConfirmIdxInterface IdxInterface
SetKeySelection KeySelection
UserEmail UserEmail
Reset bool
Expire int
Colors []RGBColor
}
func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(&kp, svgInterface)
if err != nil {
return nil, err
}
signupInterface, colors, 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,
Colors: colors,
}
return &session, nil
}
func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) {
validEntry := all.All[int](confirmKeyEntry, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
if !validEntry {
log.Printf("Invalid Key entry. One or more key index: %#v, not in range 0-%d", confirmKeyEntry, s.Kp.NumbOfKeys)
return nil, config.ErrKeyIndexOutOfRange
}
if s.SetIdxInterface == nil {
log.Print("signup session set interface is nil")
return nil, config.ErrIncompleteUserSignupSession
}
if s.ConfirmIdxInterface == nil {
log.Print("signup session confirm interface is nil")
return nil, config.ErrIncompleteUserSignupSession
}
if s.SetKeySelection == nil {
log.Print("signup session set key entry is nil")
return nil, config.ErrIncompleteUserSignupSession
}
if s.UserEmail == "" {
log.Print("signup session username is nil")
return nil, config.ErrIncompleteUserSignupSession
}
if len(confirmKeyEntry) != len(s.SetKeySelection) {
log.Printf("confirm and set key entry length mismatch %d != %d", len(confirmKeyEntry), len(s.SetKeySelection))
return nil, config.ErrSetConfirmSignupMismatch
}
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 := set.NewSetFromSlice[int](setKeyVals[idx])
confirmKey := set.NewSetFromSlice[int](confirmKeyVals[idx])
intersection := setKey.Intersect(confirmKey)
if intersection.Size() < 1 {
log.Printf("set and confirm do not intersect at index %d", idx)
return nil, config.ErrSetConfirmSignupMismatch
}
if intersection.Size() > 1 {
log.Printf("set and confirm intersect at more than one point at index %d", idx)
return nil, config.ErrSetConfirmSignupMismatch
}
intersectionSlice := intersection.ToSlice()
passcode[idx] = intersectionSlice[0]
}
return passcode, nil
}
func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) {
validKeySelection := all.All[int](keySelection, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
if !validKeySelection {
log.Printf("one or key selection is out of range 0-%d", s.Kp.NumbOfKeys-1)
return nil, config.ErrKeyIndexOutOfRange
}
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 := security.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, []RGBColor, error) {
// This method randomly drops sets from the base user interface so it is a square and dispersable matrix
if kp.IsDispersable() {
return nil, nil, config.ErrKeypadIsNotDispersible
}
err := baseUserInterface.RandomShuffle()
if err != nil {
return nil, nil, err
}
// attributes are arranged by key interfaceMatrix
interfaceMatrix, err := baseUserInterface.InterfaceMatrix()
if err != nil {
return nil, nil, err
}
// attributes are arranged by set
attrSetView, err := security.MatrixTranspose(interfaceMatrix)
if err != nil {
return nil, nil, err
}
setIdxs := security.IdentityArray(kp.AttrsPerKey)
if err := security.FisherYatesShuffle[int](&setIdxs); err != nil {
return nil, nil, err
}
setIdxs = setIdxs[:kp.NumbOfKeys]
sort.Ints(setIdxs)
selectedSets := make([][]int, kp.NumbOfKeys)
selectedColors := make([]RGBColor, kp.NumbOfKeys)
for idx, setIdx := range setIdxs {
selectedSets[idx] = attrSetView[setIdx]
selectedColors[idx] = SetColors[setIdx]
}
// convert set view back into key view
selectedSets, err = security.MatrixTranspose(selectedSets)
if err != nil {
return nil, nil, err
}
signupUserInterface := UserInterface{
IdxInterface: security.MatrixToList(selectedSets),
Kp: &KeypadDimension{
AttrsPerKey: kp.NumbOfKeys,
NumbOfKeys: kp.NumbOfKeys,
},
}
return &signupUserInterface, selectedColors, nil
}
func (s *UserSignSession) SignupKeypad() KeypadDimension {
return KeypadDimension{
AttrsPerKey: s.Kp.NumbOfKeys,
NumbOfKeys: s.Kp.NumbOfKeys,
}
}