From 1e1ece8f3dce8ed9958f3bd5823c135d1c19eb49 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Wed, 2 May 2018 18:02:02 +0300 Subject: [PATCH] Do not allow to reuse TOTP passcode (#3878) --- models/migrations/migrations.go | 2 ++ models/migrations/v62.go | 22 ++++++++++++++++++++++ models/twofactor.go | 13 +++++++------ routers/user/auth.go | 8 +++++++- 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 models/migrations/v62.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 16037e147..522086a52 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -176,6 +176,8 @@ var migrations = []Migration{ NewMigration("add is_fsck_enabled column for repos", addFsckEnabledToRepo), // v61 -> v62 NewMigration("add size column for attachments", addSizeToAttachment), + // v62 -> v63 + NewMigration("add last used passcode column for TOTP", addLastUsedPasscodeTOTP), } // Migrate database to current version diff --git a/models/migrations/v62.go b/models/migrations/v62.go new file mode 100644 index 000000000..0c2966854 --- /dev/null +++ b/models/migrations/v62.go @@ -0,0 +1,22 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + + "github.com/go-xorm/xorm" +) + +func addLastUsedPasscodeTOTP(x *xorm.Engine) error { + type TwoFactor struct { + LastUsedPasscode string `xorm:"VARCHAR(10)"` + } + + if err := x.Sync2(new(TwoFactor)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + return nil +} diff --git a/models/twofactor.go b/models/twofactor.go index 789315021..5f3c6efc2 100644 --- a/models/twofactor.go +++ b/models/twofactor.go @@ -23,12 +23,13 @@ import ( // TwoFactor represents a two-factor authentication token. type TwoFactor struct { - ID int64 `xorm:"pk autoincr"` - UID int64 `xorm:"UNIQUE"` - Secret string - ScratchToken string - CreatedUnix util.TimeStamp `xorm:"INDEX created"` - UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"UNIQUE"` + Secret string + ScratchToken string + LastUsedPasscode string `xorm:"VARCHAR(10)"` + CreatedUnix util.TimeStamp `xorm:"INDEX created"` + UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` } // GenerateScratchToken recreates the scratch token the user is using. diff --git a/routers/user/auth.go b/routers/user/auth.go index d44939f50..4249f9e5f 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -221,7 +221,7 @@ func TwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) { return } - if ok { + if ok && twofa.LastUsedPasscode != form.Passcode { remember := ctx.Session.Get("twofaRemember").(bool) u, err := models.GetUserByID(id) if err != nil { @@ -243,6 +243,12 @@ func TwoFactorPost(ctx *context.Context, form auth.TwoFactorAuthForm) { } } + twofa.LastUsedPasscode = form.Passcode + if err = models.UpdateTwoFactor(twofa); err != nil { + ctx.ServerError("UserSignIn", err) + return + } + handleSignIn(ctx, u, remember) return }