From 9b8e1392e6865404a78bec4e8814c1f2a96f3c1a Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Fri, 17 Aug 2018 08:46:10 +0100
Subject: [PATCH] Add the "has_otp" attribute to the user type

---
 actions.go       |  3 +++
 backend/model.go |  5 ++---
 types.go         | 16 +++++++++++++---
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/actions.go b/actions.go
index 62e2b201..5277b4a9 100644
--- a/actions.go
+++ b/actions.go
@@ -177,6 +177,8 @@ type PasswordRecoveryResponse struct {
 // RecoverPassword lets users reset their password by providing
 // secondary credentials, which we authenticate ourselves.
 //
+// Two-factor authentication is disabled on successful recovery.
+//
 // TODO: call out to auth-server for secondary authentication?
 func (s *AccountService) RecoverPassword(ctx context.Context, tx TX, req *PasswordRecoveryRequest) (*PasswordRecoveryResponse, error) {
 	user, err := getUserOrDie(ctx, tx, req.Username)
@@ -208,6 +210,7 @@ func (s *AccountService) RecoverPassword(ctx context.Context, tx TX, req *Passwo
 		if err := s.changeUserPasswordAndUpdateEncryptionKeys(ctx, tx, user, req.RecoveryPassword, req.Password); err != nil {
 			return err
 		}
+
 		// Disable 2FA.
 		return s.disable2FA(ctx, tx, user)
 	})
diff --git a/backend/model.go b/backend/model.go
index d467ae7d..31a07bce 100644
--- a/backend/model.go
+++ b/backend/model.go
@@ -128,12 +128,11 @@ func newUser(entry *ldap.Entry) (*accountserver.User, error) {
 		UID:                  uidNumber,
 		PasswordRecoveryHint: entry.GetAttributeValue(recoveryHintLDAPAttr),
 		U2FRegistrations:     decodeU2FRegistrations(entry.GetAttributeValues(u2fRegistrationsLDAPAttr)),
+		HasOTP:               entry.GetAttributeValue(totpSecretLDAPAttr) != "",
 	}
 
 	// The user has 2FA enabled if it has a TOTP secret or U2F keys.
-	if (entry.GetAttributeValue(totpSecretLDAPAttr) != "") || (len(user.U2FRegistrations) > 0) {
-		user.Has2FA = true
-	}
+	user.Has2FA = (user.HasOTP || (len(user.U2FRegistrations) > 0))
 
 	if user.Lang == "" {
 		user.Lang = "en"
diff --git a/types.go b/types.go
index 91adf6a0..2bb3d7f4 100644
--- a/types.go
+++ b/types.go
@@ -30,13 +30,23 @@ type User struct {
 	// UNIX user id.
 	UID int `json:"uid"`
 
-	Has2FA               bool   `json:"has_2fa"`
-	HasEncryptionKeys    bool   `json:"has_encryption_keys"`
+	// Has2FA is true if the user has a second-factor authentication
+	// mechanism properly set up. In practice, this is the case if either
+	// HasOTP is true, or len(U2FRegistrations) > 0.
+	Has2FA bool `json:"has_2fa"`
+
+	// HasOTP is true if TOTP is set up.
+	HasOTP bool `json:"has_otp"`
+
+	// HasEncryptionKeys is true if encryption keys are properly set up for
+	// this user.  TODO: consider disabling it.
+	HasEncryptionKeys bool `json:"has_encryption_keys"`
+
 	PasswordRecoveryHint string `json:"password_recovery_hint"`
 
 	AppSpecificPasswords []*AppSpecificPasswordInfo `json:"app_specific_passwords,omitempty"`
 
-	U2FRegistrations []*u2f.Registration `json:"u2f_registrations"`
+	U2FRegistrations []*u2f.Registration `json:"u2f_registrations,omitempty"`
 
 	Resources []*Resource `json:"resources,omitempty"`
 }
-- 
GitLab