github.com/condensat/bank-core@v0.1.0/database/query/credential.go (about)

     1  // Copyright 2020 Condensat Tech. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  package query
     6  
     7  import (
     8  	"context"
     9  	"encoding/hex"
    10  	"errors"
    11  
    12  	"github.com/condensat/bank-core/database"
    13  	"github.com/condensat/bank-core/database/model"
    14  
    15  	"github.com/condensat/bank-core/security"
    16  	"github.com/condensat/bank-core/security/utils"
    17  
    18  	"github.com/jinzhu/gorm"
    19  	"github.com/shengdoushi/base58"
    20  )
    21  
    22  var (
    23  	ErrUserNotFound        = errors.New("User not found")
    24  	ErrInvalidPasswordHash = errors.New("Invalid PasswordHash")
    25  	ErrDatabaseError       = errors.New("Database Operation failed")
    26  )
    27  
    28  func HashEntry(entry model.Base58) model.Base58 {
    29  	hash := utils.HashBytes([]byte(entry))
    30  	return model.Base58(hex.EncodeToString(hash[:]))
    31  }
    32  
    33  func CreateOrUpdatedCredential(ctx context.Context, db database.Context, credential model.Credential) (model.Credential, error) {
    34  	switch gdb := db.DB().(type) {
    35  	case *gorm.DB:
    36  
    37  		// perform a sha512 hex digest of login and password
    38  		login := HashEntry(credential.LoginHash)
    39  		password := HashEntry(credential.PasswordHash)
    40  		password = login + password // password prefixed with login for uniqueness
    41  		loginHash := security.SaltedHash(ctx, []byte(login))
    42  		passwordHash := security.SaltedHash(ctx, []byte(password))
    43  		defer utils.Memzero(loginHash)
    44  		defer utils.Memzero(passwordHash)
    45  
    46  		var result model.Credential
    47  		err := gdb.
    48  			Where(&model.Credential{UserID: credential.UserID}).
    49  			Assign(&model.Credential{
    50  				LoginHash:    model.Base58(base58.Encode(loginHash, base58.BitcoinAlphabet)),
    51  				PasswordHash: model.Base58(base58.Encode(passwordHash, base58.BitcoinAlphabet)),
    52  				TOTPSecret:   credential.TOTPSecret,
    53  			}).
    54  			FirstOrCreate(&result).Error
    55  
    56  		return result, err
    57  
    58  	default:
    59  		return model.Credential{}, database.ErrInvalidDatabase
    60  	}
    61  }
    62  
    63  func CheckCredential(ctx context.Context, db database.Context, login, password model.Base58) (model.UserID, bool, error) {
    64  	switch gdb := db.DB().(type) {
    65  	case *gorm.DB:
    66  
    67  		// client should send a sha512 hex digest of the password
    68  		// login = hashEntry(login)
    69  		// password = hashEntry(password)
    70  
    71  		password = login + password // password prefixed with login for uniqueness
    72  		loginHash := security.SaltedHash(ctx, []byte(login))
    73  		defer utils.Memzero(loginHash)
    74  
    75  		var cred model.Credential
    76  		err := gdb.
    77  			Where(&model.Credential{LoginHash: model.Base58(base58.Encode(loginHash, base58.BitcoinAlphabet))}).
    78  			First(&cred).Error
    79  		if err != nil {
    80  			return 0, false, ErrDatabaseError
    81  		}
    82  		if cred.UserID == 0 {
    83  			return 0, false, ErrUserNotFound
    84  		}
    85  
    86  		passwordHash, err := base58.Decode(string(cred.PasswordHash), base58.BitcoinAlphabet)
    87  		defer utils.Memzero(passwordHash)
    88  		if err != nil {
    89  			return 0, false, ErrInvalidPasswordHash
    90  		}
    91  
    92  		return cred.UserID, security.SaltedHashVerify(ctx, []byte(password), passwordHash), nil
    93  
    94  	default:
    95  		return 0, false, database.ErrInvalidDatabase
    96  	}
    97  }