Skip to content

Commit

Permalink
Better timing algo
Browse files Browse the repository at this point in the history
  • Loading branch information
Mobilpadde committed Jan 13, 2023
1 parent 8a60d78 commit c179409
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 63 deletions.
16 changes: 10 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
)

func main() {
// log.SetFlags(log.Flags() | log.Llongfile)

secret := os.Getenv("MOTHS_SECRET")
amount := 10

generationInterval := time.Second * 10
generationTicker := time.NewTicker(generationInterval)
validationInterval := time.Second * 3
generationInterval := time.Second * 4

validationInterval := time.Second * 7
generationTicker := time.NewTicker(generationInterval)
validationTicker := time.NewTicker(validationInterval)

var err error
Expand All @@ -26,6 +28,7 @@ func main() {
moths.OptionWithInterval(generationInterval),
moths.OptionWithAmount(amount),
moths.OptionWithEmojies(emojies.CATS),
moths.OptionWithTime(time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)),
); err != nil {
log.Fatalln(err)
}
Expand All @@ -37,20 +40,21 @@ func main() {
validationInterval,
)
log.Printf("Every moth is %d emoji long", amount)
log.Println()

for {
log.Println()
otp, err := gen.Next()
if err != nil {
log.Fatalln(err)
}

log.Printf(`Your moth is "%s" and code is %s`, otp.SpacedString(), otp.Token())
validationTicker.Reset(validationInterval)
<-validationTicker.C

log.Printf("Is this still valid after %s? %t", validationInterval, gen.Validate(otp.String()))
log.Println()
<-validationTicker.C

log.Printf("Is this still valid after %s? %t", validationInterval*2, gen.Validate(otp.String()))
<-generationTicker.C
}
}
4 changes: 3 additions & 1 deletion moths/errs/errors.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package errs

import "errors"
import (
"errors"
)

const (
// Secret must have 32 characters
Expand Down
16 changes: 8 additions & 8 deletions moths/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import (
func NewMoths(opts ...option) (*Moths, error) {
m := &Moths{
interval: 0,
amount: 0,
time: time.Now(),
amount: 6, // Defaults to `6` as most other services uses that
}

for _, opt := range opts {
Expand All @@ -19,6 +18,10 @@ func NewMoths(opts ...option) (*Moths, error) {
}
}

now := time.Now().UTC()
m.timing.curr = now
m.timing.last = now.Add(-m.interval)

if err := checks.CheckSecretKey(m.secret); err != nil {
return nil, err
}
Expand All @@ -31,13 +34,10 @@ func NewMoths(opts ...option) (*Moths, error) {
return nil, err
}

if err := checks.CheckAmount(m.amount); err != nil {
// Checks if everything is working
if _, err := m.getToken(); err != nil {
return nil, err
}

// check if everything is working
_, err := m.getToken(true)

// go m.update()
return m, err
return m, nil
}
23 changes: 15 additions & 8 deletions moths/next.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,27 @@ import (
)

func (m *Moths) Next() (otp.OTP, error) {
token, err := m.getToken(true)
token, err := m.getToken()
if err != nil {
return otp.OTP{}, err
}

return otp.NewOTP(token, m.amount, m.emojies)
}

func (m *Moths) getToken(bump bool) (string, error) {
// Bump the time on every run
if bump {
// TODO: Remove this and refactor to auto-update after each interval (`m.interval`) has passes
m.time = m.time.Add(time.Since(m.time))
func (m *Moths) getToken() (string, error) {
m.timing.curr = time.Now().UTC()

since := m.timing.curr.Sub(m.timing.last)
if since < m.interval {
return m.lastToken, nil
}

m.timing.last = m.timing.curr
m.timing.time = m.timing.time.Add(since)

b := make([]byte, 8)
interval := uint64(m.time.Unix() / int64(m.interval.Seconds()))
interval := uint64(m.timing.time.Unix() / int64(m.interval.Seconds()))
binary.BigEndian.PutUint64(b, interval)

hash := hmac.New(sha1.New, m.secret)
Expand All @@ -45,5 +49,8 @@ func (m *Moths) getToken(bump bool) (string, error) {
}

otp := (int(header) & 0x7fffffff) % 1000000
return fmt.Sprintf("%06d", otp), nil
pad := fmt.Sprintf("%06d", otp)

m.lastToken = pad
return pad, nil
}
15 changes: 8 additions & 7 deletions moths/next_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/Mobilpadde/moths/moths/emojies"
)

func TestNextOk(t *testing.T) {
func TestNextAndValidate(t *testing.T) {
amount := 6
secret := strings.Repeat("a", 32)

Expand All @@ -28,13 +28,14 @@ func TestNextOk(t *testing.T) {
t.Error("Expected to not return an error when creating new OTP:", err)
}

correct := "158415"
if otp.Token() != correct {
t.Error("Expected token to be", correct, "not", otp.Token())
errStr := "Expected %s to be %s not %s"
correct := "😸🙀😸😻🙀😻"
if !gen.Validate(correct) {
t.Errorf(errStr, "moth", correct, otp)
}

correct = "🙀🙀😺😼😽😻"
if otp.String() != correct {
t.Error("Expected moth to be", correct, "not", otp.String())
correct = "113694"
if !gen.ValidateToken(correct) {
t.Errorf(errStr, "token", correct, otp.Token())
}
}
19 changes: 13 additions & 6 deletions moths/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ import (
)

type Moths struct {
secret []byte
interval time.Duration
amount int
emojies emojies.Emojies
time time.Time
secret []byte
amount int
emojies emojies.Emojies

interval time.Duration
lastToken string

timing struct {
time time.Time
curr time.Time
last time.Time
}
}

type option func(*Moths) error
Expand Down Expand Up @@ -72,7 +79,7 @@ func OptionWithEmojies(emojies emojies.Emojies) option {

func OptionWithTime(t time.Time) option {
return func(m *Moths) error {
m.time = t
m.timing.time = t
return nil
}
}
17 changes: 0 additions & 17 deletions moths/update.go

This file was deleted.

22 changes: 12 additions & 10 deletions moths/validate.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package moths

import (
"time"

"github.com/Mobilpadde/moths/moths/otp"
)

Expand All @@ -11,7 +9,7 @@ func (m *Moths) Validate(moth string) bool {
return false
}

token, err := m.getToken(false)
token, err := m.getToken()
if err != nil {
return false
}
Expand All @@ -21,18 +19,22 @@ func (m *Moths) Validate(moth string) bool {
return false
}

// Bump the time
// m.getToken(true)
m.time = m.time.Add(time.Since(m.time))

return same.Validate(moth)
}

func (m *Moths) ValidateToken(code string) bool {
token, err := m.getToken(false)
// This should maybe not be used
// as you should not really expose the `token`
// to your users
func (m *Moths) ValidateToken(oldToken string) bool {
token, err := m.getToken()
if err != nil {
return false
}

same, err := otp.NewOTP(token, m.amount, m.emojies)
if err != nil {
return false
}

return token == code
return same.ValidateToken(oldToken)
}

0 comments on commit c179409

Please sign in to comment.