1
package models
2

3
import (
4
    "fmt"
5
    "strings"
6

7
    "golang.org/x/crypto/bcrypt"
8
    "github.com/jinzhu/gorm"
9
    "github.com/pquerna/otp"
10
    "github.com/pquerna/otp/totp"
11

12
    "github.com/earaujoassis/space/security"
13
)
14

15
// User model/struct
16
type User struct {
17
    Model
18
    UUID string                 `gorm:"not null;unique;index" validate:"omitempty,uuid4" json:"-"`
19
    PublicID string             `gorm:"not null;unique;index" json:"public_id"`
20
    Username string             `gorm:"not null;unique;index" validate:"required,alphanum,max=60" json:"-"`
21
    FirstName string            `gorm:"not null" validate:"required,min=3,max=20" essential:"required,min=3,max=20" json:"first_name"`
22
    LastName string             `gorm:"not null" validate:"required,min=3,max=20" essential:"required,min=3,max=20" json:"last_name"`
23
    Email string                `gorm:"not null;unique;index" validate:"required,email" essential:"required,email" json:"email"`
24
    Passphrase string           `gorm:"not null" validate:"required" essential:"required,min=10" json:"-"`
25
    Active bool                 `gorm:"not null;default:false" json:"active"`
26
    Admin bool                  `gorm:"not null;default:false" json:"-"`
27
    Client Client               `gorm:"not null" validate:"exists" json:"-"`
28
    ClientID uint               `gorm:"not null" json:"-"`
29
    Language Language           `gorm:"not null" validate:"exists" json:"-"`
30
    LanguageID uint             `gorm:"not null" json:"-"`
31
    TimezoneIdentifier string   `gorm:"not null;default:'GMT'" json:"timezone_identifier"`
32
    CodeSecret string           `gorm:"not null" validate:"required" json:"-"`
33
    RecoverSecret string        `gorm:"not null" validate:"required" json:"-"`
34
}
35

36
// Authentic checks if a password + passcode combination is valid for a given User
37 0
func (user *User) Authentic(password, passcode string) bool {
38 0
    var validPasscode bool
39 0
    validPassword := bcrypt.CompareHashAndPassword([]byte(user.Passphrase), []byte(password)) == nil
40 0
    codeSecret, err := security.Decrypt(defaultKey(), user.CodeSecret)
41 0
    if err != nil {
42 0
        return false
43
    }
44

45 0
    validPasscode = totp.Validate(passcode, string(codeSecret))
46 0
    return validPasscode && validPassword
47
}
48

49
// UpdatePassword updates an User's password
50 0
func (user *User) UpdatePassword(password string) error {
51 0
    crypted, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
52 0
    if err == nil {
53 0
        user.Passphrase = string(crypted)
54 0
        return nil
55
    }
56 0
    return err
57
}
58

59
// GenerateCodeSecret generates a code secret for an user, in order to generate and validate passcodes
60 0
func (user *User) GenerateCodeSecret() *otp.Key {
61 0
    key, err := totp.Generate(totp.GenerateOpts{
62 0
        Issuer:      "quatroLABS.com",
63 0
        AccountName: user.Username,
64 0
    })
65 0
    codeSecret := key.Secret()
66 0
    if cryptedCodeSecret, err := security.Encrypt(defaultKey(), []byte(codeSecret)); err == nil {
67 0
        user.CodeSecret = string(cryptedCodeSecret)
68 0
    } else {
69 0
        user.CodeSecret = codeSecret
70
    }
71 0
    if err != nil {
72 0
        return nil
73
    }
74 0
    return key
75
}
76

77
// GenerateRecoverSecret generates a recover secret string for an user
78 0
func (user *User) GenerateRecoverSecret() (string, error) {
79 0
    var secret = strings.ToUpper(fmt.Sprintf("%s-%s-%s-%s",
80 0
        GenerateRandomString(4),
81 0
        GenerateRandomString(4),
82 0
        GenerateRandomString(4),
83 0
        GenerateRandomString(4),))
84 0
    if cryptedRecoverSecret, err := bcrypt.GenerateFromPassword([]byte(secret), bcrypt.DefaultCost); err == nil {
85 0
        user.RecoverSecret = string(cryptedRecoverSecret)
86 0
    } else {
87 0
        return secret, err
88
    }
89 0
    return secret, nil
90
}
91

92
// BeforeSave User model/struct hook
93 0
func (user *User) BeforeSave(scope *gorm.Scope) error {
94 0
    return validateModel("validate", user)
95
}
96

97
// BeforeCreate User model/struct hook
98 0
func (user *User) BeforeCreate(scope *gorm.Scope) error {
99 0
    scope.SetColumn("UUID", generateUUID())
100 0
    scope.SetColumn("PublicID", GenerateRandomString(32))
101 0
    if cryptedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Passphrase), bcrypt.DefaultCost); err == nil {
102 0
        scope.SetColumn("Passphrase", cryptedPassword)
103 0
    } else {
104 0
        return err
105
    }
106 0
    return nil
107
}

Read our documentation on viewing source code .

Loading