You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

legacy.go 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // Copyright (c) 2018 Shivaram Lingamneni
  2. package irc
  3. import (
  4. "encoding/base64"
  5. "errors"
  6. "fmt"
  7. "github.com/tidwall/buntdb"
  8. "golang.org/x/crypto/bcrypt"
  9. )
  10. var (
  11. errInvalidPasswordHash = errors.New("invalid password hash")
  12. )
  13. // Decode a hashed passphrase as it would appear in a config file,
  14. // retaining compatibility with old versions of `oragono genpasswd`
  15. // that used to apply a redundant layer of base64
  16. func decodeLegacyPasswordHash(hash string) ([]byte, error) {
  17. // a correctly formatted bcrypt hash is 60 bytes of printable ASCII
  18. if len(hash) == 80 {
  19. // double-base64, remove the outer layer:
  20. return base64.StdEncoding.DecodeString(hash)
  21. } else if len(hash) == 60 {
  22. return []byte(hash), nil
  23. } else {
  24. return nil, errInvalidPasswordHash
  25. }
  26. }
  27. // helper to check a version 0 password hash, with global and per-passphrase salts
  28. func checkLegacyPasswordV0(hashedPassword, globalSalt, passphraseSalt []byte, passphrase string) error {
  29. var assembledPasswordBytes []byte
  30. assembledPasswordBytes = append(assembledPasswordBytes, globalSalt...)
  31. assembledPasswordBytes = append(assembledPasswordBytes, '-')
  32. assembledPasswordBytes = append(assembledPasswordBytes, passphraseSalt...)
  33. assembledPasswordBytes = append(assembledPasswordBytes, '-')
  34. assembledPasswordBytes = append(assembledPasswordBytes, []byte(passphrase)...)
  35. return bcrypt.CompareHashAndPassword(hashedPassword, assembledPasswordBytes)
  36. }
  37. // checks a version 0 password hash; if successful, upgrades the database entry to version 1
  38. func handleLegacyPasswordV0(server *Server, account string, credentials AccountCredentials, passphrase string) (err error) {
  39. var globalSaltString string
  40. err = server.store.View(func(tx *buntdb.Tx) (err error) {
  41. globalSaltString, err = tx.Get("crypto.salt")
  42. return err
  43. })
  44. if err != nil {
  45. return err
  46. }
  47. globalSalt, err := base64.StdEncoding.DecodeString(globalSaltString)
  48. if err != nil {
  49. return err
  50. }
  51. err = checkLegacyPasswordV0(credentials.PassphraseHash, globalSalt, credentials.PassphraseSalt, passphrase)
  52. if err != nil {
  53. // invalid password
  54. return err
  55. }
  56. // upgrade credentials
  57. err = server.accounts.setPassword(account, passphrase)
  58. if err != nil {
  59. server.logger.Error("internal", fmt.Sprintf("could not upgrade user password: %v", err))
  60. }
  61. return nil
  62. }