226 lines
6.9 KiB
Go
226 lines
6.9 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/internal/models"
|
|
"go-nkode/internal/security"
|
|
"log"
|
|
"sort"
|
|
)
|
|
|
|
type UserSignSession struct {
|
|
Id models.SessionId
|
|
CustomerId models.CustomerID
|
|
LoginUserInterface UserInterface
|
|
Kp KeypadDimension
|
|
SetIdxInterface models.IdxInterface
|
|
ConfirmIdxInterface models.IdxInterface
|
|
SetKeySelection models.KeySelection
|
|
UserEmail models.UserEmail
|
|
Reset bool
|
|
Expire int
|
|
Colors []models.RGBColor
|
|
}
|
|
|
|
func NewSignupResetSessionRigged(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerID, svgInterface models.SvgIdInterface, reset bool) (*UserSignSession, error) {
|
|
loginInterface, err := NewUserInterface(&kp, svgInterface)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
setIdxInterface := make(models.IdxInterface, 36)
|
|
for idx := range 36 {
|
|
setIdxInterface[idx] = idx
|
|
}
|
|
session := UserSignSession{
|
|
Id: models.SessionId(uuid.New()),
|
|
CustomerId: customerId,
|
|
LoginUserInterface: *loginInterface,
|
|
SetIdxInterface: setIdxInterface,
|
|
ConfirmIdxInterface: nil,
|
|
SetKeySelection: nil,
|
|
UserEmail: userEmail,
|
|
Kp: kp,
|
|
Reset: reset,
|
|
Colors: []models.RGBColor{},
|
|
}
|
|
return &session, nil
|
|
}
|
|
|
|
func NewSignupResetSession(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerID, svgInterface models.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: models.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 models.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 models.KeySelection) (models.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 models.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, []models.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([]models.RGBColor, kp.NumbOfKeys)
|
|
|
|
for idx, setIdx := range setIdxs {
|
|
selectedSets[idx] = attrSetView[setIdx]
|
|
selectedColors[idx] = models.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,
|
|
}
|
|
}
|