|
@@ -189,15 +189,11 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
|
189
|
189
|
certFPKey := fmt.Sprintf(keyCertToAccount, certfp)
|
190
|
190
|
|
191
|
191
|
var creds AccountCredentials
|
192
|
|
- // always set passphrase salt
|
193
|
|
- creds.PassphraseSalt, err = passwd.NewSalt()
|
194
|
|
- if err != nil {
|
195
|
|
- return errAccountCreation
|
196
|
|
- }
|
197
|
192
|
// it's fine if this is empty, that just means no certificate is authorized
|
198
|
193
|
creds.Certificate = certfp
|
199
|
194
|
if passphrase != "" {
|
200
|
|
- creds.PassphraseHash, err = am.server.passwords.GenerateFromPassword(creds.PassphraseSalt, passphrase)
|
|
195
|
+ creds.PassphraseHash, err = passwd.GenerateEncodedPasswordBytes(passphrase)
|
|
196
|
+ creds.PassphraseIsV2 = true
|
201
|
197
|
if err != nil {
|
202
|
198
|
am.server.logger.Error("internal", fmt.Sprintf("could not hash password: %v", err))
|
203
|
199
|
return errAccountCreation
|
|
@@ -522,8 +518,50 @@ func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName s
|
522
|
518
|
return errAccountUnverified
|
523
|
519
|
}
|
524
|
520
|
|
525
|
|
- err = am.server.passwords.CompareHashAndPassword(
|
526
|
|
- account.Credentials.PassphraseHash, account.Credentials.PassphraseSalt, passphrase)
|
|
521
|
+ if account.Credentials.PassphraseIsV2 {
|
|
522
|
+ err = passwd.ComparePassword(account.Credentials.PassphraseHash, []byte(passphrase))
|
|
523
|
+ } else {
|
|
524
|
+ // compare using legacy method
|
|
525
|
+ err = am.server.passwords.CompareHashAndPassword(account.Credentials.PassphraseHash, account.Credentials.PassphraseSalt, passphrase)
|
|
526
|
+ if err == nil {
|
|
527
|
+ // passphrase worked! silently upgrade them to use v2 hashing going forward.
|
|
528
|
+ //TODO(dan): in future, replace this with an am.updatePassphrase(blah) function, which we can reuse in /ns update pass?
|
|
529
|
+ err = am.server.store.Update(func(tx *buntdb.Tx) error {
|
|
530
|
+ var creds AccountCredentials
|
|
531
|
+ creds.Certificate = account.Credentials.Certificate
|
|
532
|
+ creds.PassphraseHash, err = passwd.GenerateEncodedPasswordBytes(passphrase)
|
|
533
|
+ creds.PassphraseIsV2 = true
|
|
534
|
+ if err != nil {
|
|
535
|
+ am.server.logger.Error("internal", fmt.Sprintf("could not hash password (updating existing hash version): %v", err))
|
|
536
|
+ return errAccountCredUpdate
|
|
537
|
+ }
|
|
538
|
+
|
|
539
|
+ credText, err := json.Marshal(creds)
|
|
540
|
+ if err != nil {
|
|
541
|
+ am.server.logger.Error("internal", fmt.Sprintf("could not marshal credentials (updating existing hash version): %v", err))
|
|
542
|
+ return errAccountCredUpdate
|
|
543
|
+ }
|
|
544
|
+ credStr := string(credText)
|
|
545
|
+
|
|
546
|
+ // we know the account name is valid if this line is reached, otherwise the
|
|
547
|
+ // above would have failed. as such, chuck out and ignore err on casefolding
|
|
548
|
+ casefoldedAccountName, _ := CasefoldName(accountName)
|
|
549
|
+ credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccountName)
|
|
550
|
+
|
|
551
|
+ //TODO(dan): sling, can you please checkout this mutex usage, see if it
|
|
552
|
+ // makes sense or not? bleh
|
|
553
|
+ am.serialCacheUpdateMutex.Lock()
|
|
554
|
+ defer am.serialCacheUpdateMutex.Unlock()
|
|
555
|
+
|
|
556
|
+ tx.Set(credentialsKey, credStr, nil)
|
|
557
|
+
|
|
558
|
+ return nil
|
|
559
|
+ })
|
|
560
|
+ }
|
|
561
|
+ if err != nil {
|
|
562
|
+ return err
|
|
563
|
+ }
|
|
564
|
+ }
|
527
|
565
|
if err != nil {
|
528
|
566
|
return errAccountInvalidCredentials
|
529
|
567
|
}
|
|
@@ -984,6 +1022,7 @@ var (
|
984
|
1022
|
type AccountCredentials struct {
|
985
|
1023
|
PassphraseSalt []byte
|
986
|
1024
|
PassphraseHash []byte
|
|
1025
|
+ PassphraseIsV2 bool `json:"passphrase-is-v2"`
|
987
|
1026
|
Certificate string // fingerprint
|
988
|
1027
|
}
|
989
|
1028
|
|