Skip to content

Commit

Permalink
Merge branch 'main' into SAC-13-Create-Tag-POST
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettladley authored Jan 21, 2024
2 parents 3e9945a + 91dea77 commit 9b78b72
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 5 deletions.
2 changes: 1 addition & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ require (
github.com/valyala/tcplisten v1.0.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/crypto v0.17.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
Expand Down
119 changes: 119 additions & 0 deletions backend/src/auth/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package auth

import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"fmt"
"strings"

"golang.org/x/crypto/argon2"
)

type params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}

func ComputePasswordHash(password string) (*string, error) {
p := &params{
memory: 64 * 1024,
iterations: 3,
parallelism: 2,
saltLength: 16,
keyLength: 32,
}

salt := make([]byte, p.saltLength)

if _, err := rand.Read(salt); err != nil {
return nil, err
}

hash := argon2.IDKey([]byte(password),
salt,
p.iterations,
p.memory,
p.parallelism,
p.keyLength,
)

b64Salt := base64.RawStdEncoding.EncodeToString(salt)

b64Hash := base64.RawStdEncoding.EncodeToString(hash)

encodedHash := fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, p.memory, p.iterations, p.parallelism, b64Salt, b64Hash)

return &encodedHash, nil
}

var (
ErrInvalidHash = errors.New("the encoded hash is not in the correct format")
ErrIncompatibleVersion = errors.New("incompatible version of argon2")
)

func ComparePasswordAndHash(password, encodedHash string) (bool, error) {
p, salt, hash, err := decodeHash(encodedHash)

if err != nil {
return false, err
}

otherHash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)

if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
return true, nil
}

return false, nil
}

func decodeHash(encodedHash string) (p *params, salt []byte, hash []byte, err error) {
vals := strings.Split(encodedHash, "$")

if len(vals) != 6 {
return nil, nil, nil, ErrInvalidHash
}

var version int

_, err = fmt.Sscanf(vals[2], "v=%d", &version)

if err != nil {
return nil, nil, nil, err
}

if version != argon2.Version {
return nil, nil, nil, ErrIncompatibleVersion
}

p = &params{}

_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.memory, &p.iterations, &p.parallelism)

if err != nil {
return nil, nil, nil, err
}

salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])

if err != nil {
return nil, nil, nil, err
}

p.saltLength = uint32(len(salt))

hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])

if err != nil {
return nil, nil, nil, err
}

p.keyLength = uint32(len(hash))

return p, salt, hash, nil
}
4 changes: 2 additions & 2 deletions backend/src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ func GetConfiguration(path string) (Settings, error) {
superUserPrefix := fmt.Sprintf("%sSUPERUSER__", appPrefix)

portStr := os.Getenv(fmt.Sprintf("%sPORT", appPrefix))
portInt, err := strconv.Atoi(portStr)
portInt, err := strconv.ParseUint(portStr, 10, 16)

if err != nil {
return Settings{}, fmt.Errorf("failed to parse port: %w", err)
}

return Settings{
Application: ApplicationSettings{
Port: prodSettings.Application.Port,
Port: uint16(portInt),
Host: prodSettings.Application.Host,
BaseUrl: os.Getenv(fmt.Sprintf("%sBASE_URL", applicationPrefix)),
},
Expand Down
15 changes: 14 additions & 1 deletion backend/src/database/db.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package database

import (
"github.com/GenerateNU/sac/backend/src/auth"
"github.com/GenerateNU/sac/backend/src/config"
"github.com/GenerateNU/sac/backend/src/models"

Expand Down Expand Up @@ -55,11 +56,23 @@ func MigrateDB(settings config.Settings, db *gorm.DB) error {
return err
}

tx := db.Begin()

if err := tx.Error; err != nil {
return err
}

passwordHash, err := auth.ComputePasswordHash(settings.SuperUser.Password)

if err != nil {
return err
}

superUser := models.User{
Role: models.Super,
NUID: "000000000",
Email: "[email protected]",
PasswordHash: settings.SuperUser.Password, // TODO: hash this
PasswordHash: *passwordHash,
FirstName: "SAC",
LastName: "Super",
College: models.KCCS,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type User struct {
FirstName string `gorm:"type:varchar(255)" json:"first_name" validate:"required,max=255"`
LastName string `gorm:"type:varchar(255)" json:"last_name" validate:"required,max=255"`
Email string `gorm:"type:varchar(255);unique" json:"email" validate:"required,email,max=255"`
PasswordHash string `gorm:"type:text" json:"-" validate:"required"`
PasswordHash string `gorm:"type:varchar(97)" json:"-" validate:"required,len=97"`
College College `gorm:"type:varchar(255)" json:"college" validate:"required,max=255"`
Year Year `gorm:"type:smallint" json:"year" validate:"required,min=1,max=6"`

Expand Down

0 comments on commit 9b78b72

Please sign in to comment.