Skip to content

Commit 074827f

Browse files
committed
salty
1 parent 3193086 commit 074827f

File tree

4 files changed

+53
-37
lines changed

4 files changed

+53
-37
lines changed

auth/api_auth.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func init() {
3535
Fails{Err: "PasswordTooShort", If: ___yo_authRegisterPasswordPlain.StrLen().LessThan(Cfg.YO_AUTH_PWD_MIN_LEN)},
3636
Fails{Err: "PasswordTooLong", If: ___yo_authRegisterPasswordPlain.StrLen().GreaterThan(Cfg.YO_AUTH_PWD_MAX_LEN)},
3737
).
38-
CouldFailWith("EmailAddrAlreadyExists", "PasswordInvalid"),
38+
CouldFailWith("EmailAddrAlreadyExists"),
3939

4040
MethodPathLoginOrFinalizePwdReset: api(ApiUserLoginOrFinalizePwdReset,
4141
Fails{Err: "EmailRequiredButMissing", If: ___yo_authLoginOrFinalizePwdResetEmailAddr.Equal("")},
@@ -50,7 +50,7 @@ func init() {
5050
Fails{Err: "NewPasswordTooLong", If: ___yo_authLoginOrFinalizePwdResetPassword2Plain.StrLen().GreaterThan(Cfg.YO_AUTH_PWD_MAX_LEN)},
5151
Fails{Err: "NewPasswordExpectedToDiffer", If: ___yo_authLoginOrFinalizePwdResetPassword2Plain.Equal(___yo_authLoginOrFinalizePwdResetPasswordPlain)},
5252
).
53-
CouldFailWith(":"+yodb.ErrSetDbUpdate, "PwdReqExpired", "PwdResetRequired", "OkButFailedToCreateSignedToken", "AccountDoesNotExist", "NewPasswordInvalid", ErrUnauthorized),
53+
CouldFailWith(":"+yodb.ErrSetDbUpdate, "PwdReqExpired", "PwdResetRequired", "AccountDoesNotExist", ErrUnauthorized),
5454

5555
MethodPathChangePassword: api(apiChangePassword,
5656
Fails{Err: "NewPasswordExpectedToDiffer", If: ___yo_authChangePasswordPassword2Plain.Equal(___yo_authChangePasswordPasswordPlain)},
@@ -101,7 +101,7 @@ func ApiUserLoginOrFinalizePwdReset(this *ApiCtx[ApiAccountPayload, UserAccount]
101101
if this.Ret = account; (account != nil) && (jwt_token != nil) {
102102
jwt_signed, err := jwt_token.SignedString([]byte(Cfg.YO_AUTH_JWT_SIGN_KEY))
103103
if err != nil {
104-
panic(Err___yo_authLoginOrFinalizePwdReset_OkButFailedToCreateSignedToken)
104+
panic(err)
105105
}
106106
httpSetUser(this.Ctx, jwt_signed, true)
107107
}

auth/auth.go

+43-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package yoauth
22

33
import (
4+
"crypto/sha512"
45
"time"
56

67
. "yo/cfg"
@@ -84,18 +85,10 @@ func UserRegister(ctx *Ctx, emailAddr string, passwordPlain string) (ret yodb.I6
8485
panic(Err___yo_authRegister_EmailAddrAlreadyExists)
8586
}
8687

87-
pwd_hashed, err := bcrypt.GenerateFromPassword([]byte(passwordPlain), bcrypt.DefaultCost)
88-
if (err != nil) || (len(pwd_hashed) == 0) {
89-
if err == bcrypt.ErrPasswordTooLong {
90-
panic(Err___yo_authRegister_PasswordTooLong)
91-
} else {
92-
panic(Err___yo_authRegister_PasswordInvalid)
93-
}
94-
}
9588
Try(func() {
9689
ret = yodb.I64(yodb.CreateOne[UserAccount](ctx, &UserAccount{
9790
EmailAddr: yodb.Text(emailAddr),
98-
pwdHashed: pwd_hashed,
91+
pwdHashed: pwdHashStorable(passwordPlain),
9992
}))
10093
}, func(err any) {
10194
panic(If[any](EnforceGenericizedErrors, err, errGeneric))
@@ -117,8 +110,7 @@ func UserLogin(ctx *Ctx, emailAddr string, passwordPlain string) (*UserAccount,
117110
user_email_addr, account_id, user_pwd_hashed = account.EmailAddr.String(), account.Id, account.pwdHashed
118111
}
119112

120-
err := bcrypt.CompareHashAndPassword(user_pwd_hashed, []byte(passwordPlain))
121-
if err != nil {
113+
if !pwdHashVerify(user_pwd_hashed, passwordPlain) {
122114
if (account != nil) && (!account.Lockout) && (LoginThrottling.NumFailedAttemptsBeforeLockout > 0) && (LoginThrottling.WithinTimePeriod > 0) {
123115
account.FailedLoginAttempts = append(account.FailedLoginAttempts, yodb.I64(time.Now().UnixNano()))
124116
if idx_start := account.FailedLoginAttempts.Len() - LoginThrottling.NumFailedAttemptsBeforeLockout; idx_start >= 0 {
@@ -156,18 +148,10 @@ func UserLoginOrFinalizeRegisterOrPwdReset(ctx *Ctx, emailAddr string, passwordP
156148
panic(Err___yo_authLoginOrFinalizePwdReset_PwdReqExpired)
157149
}
158150
// check temp one-time pwd
159-
err := bcrypt.CompareHashAndPassword(pwd_reset_req.tmpPwdHashed, []byte(passwordPlain))
160-
if err != nil {
151+
if !pwdHashVerify(pwd_reset_req.tmpPwdHashed, passwordPlain) {
161152
panic(Err___yo_authLoginOrFinalizePwdReset_WrongPassword)
162153
}
163-
pwd_hash, err := bcrypt.GenerateFromPassword([]byte(password2Plain), bcrypt.DefaultCost)
164-
if (err != nil) || (len(pwd_hash) == 0) {
165-
if err == bcrypt.ErrPasswordTooLong {
166-
panic(Err___yo_authLoginOrFinalizePwdReset_NewPasswordTooLong)
167-
} else {
168-
panic(Err___yo_authLoginOrFinalizePwdReset_NewPasswordInvalid)
169-
}
170-
}
154+
pwd_hash := pwdHashStorable(password2Plain)
171155
ctx.DbTx(true)
172156
account := yodb.FindOne[UserAccount](ctx, UserAccountEmailAddr.Equal(emailAddr))
173157
if account != nil { // existing user: pwd-reset
@@ -203,14 +187,7 @@ func UserVerify(jwtRaw string) *JwtPayload {
203187
func UserChangePassword(ctx *Ctx, emailAddr string, passwordOldPlain string, passwordNewPlain string) {
204188
ctx.DbTx(true)
205189
user_account, _ := UserLogin(ctx, emailAddr, passwordOldPlain)
206-
hash, err := bcrypt.GenerateFromPassword([]byte(passwordNewPlain), bcrypt.DefaultCost)
207-
if (err != nil) || (len(hash) == 0) {
208-
if err == bcrypt.ErrPasswordTooLong {
209-
panic(Err___yo_authLoginOrFinalizePwdReset_NewPasswordTooLong)
210-
} else {
211-
panic(Err___yo_authLoginOrFinalizePwdReset_NewPasswordInvalid)
212-
}
213-
}
190+
hash := pwdHashStorable(passwordNewPlain)
214191
user_account.pwdHashed, user_account.FailedLoginAttempts, user_account.Lockout = hash, nil, false
215192
_ = yodb.Update[UserAccount](ctx, user_account, nil, true, UserAccountFields(userAccountPwdHashed, UserAccountFailedLoginAttempts, UserAccountLockout)...)
216193
}
@@ -222,3 +199,40 @@ func ById(ctx *Ctx, id yodb.I64) *UserAccount {
222199
func ByEmailAddr(ctx *Ctx, emailAddr string) *UserAccount {
223200
return yodb.FindOne[UserAccount](ctx, UserAccountEmailAddr.Equal(emailAddr))
224201
}
202+
203+
func pwdHashVerify(pwdHashStored []byte, passwordToCheckPlain string) bool {
204+
sha512 := sha512.New()
205+
_, err := sha512.Write([]byte(passwordToCheckPlain))
206+
if err != nil {
207+
panic(err)
208+
}
209+
return (err == bcrypt.CompareHashAndPassword(pwdHashStored, sha512.Sum(nil)))
210+
}
211+
212+
func pwdHashStorable(passwordPlain string, salt string) []byte {
213+
sha512 := sha512.New()
214+
_, err := sha512.Write([]byte(passwordPlain))
215+
if err != nil {
216+
panic(err)
217+
}
218+
sha512hash := sha512.Sum(nil)
219+
Assert(len(sha512hash) == 64, len(sha512hash))
220+
Assert(len(salt) > 0)
221+
222+
if (len(salt) % 2) == 0 {
223+
224+
}
225+
for len(salt) < 8 {
226+
salt += salt
227+
}
228+
bytes8 := []byte(salt[:8])
229+
if (len(salt) % 2) == 1 {
230+
bytes8 = []byte(salt[len(salt)-8:])
231+
}
232+
233+
ret, err := bcrypt.GenerateFromPassword(append(sha512hash, bytes8[:]...), bcrypt.DefaultCost)
234+
if err != nil {
235+
panic(err)
236+
}
237+
return ret
238+
}

auth/job_pwdreqs.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
. "yo/util"
1212
sl "yo/util/sl"
1313
"yo/util/str"
14-
15-
"golang.org/x/crypto/bcrypt"
1614
)
1715

1816
const (
@@ -93,7 +91,7 @@ func (me userPwdReqJob) TaskResults(ctx *Ctx, task yojobs.TaskDetails) yojobs.Ta
9391
var tmp_one_time_pwd_hashed []byte
9492
for len(tmp_one_time_pwd_hashed) == 0 {
9593
tmp_one_time_pwd_plain = str.AsciiRand(32, 0)
96-
tmp_one_time_pwd_hashed, _ = bcrypt.GenerateFromPassword([]byte(tmp_one_time_pwd_plain), bcrypt.DefaultCost)
94+
tmp_one_time_pwd_hashed = pwdHashStorable(tmp_one_time_pwd_plain, req.EmailAddr.String())
9795
}
9896

9997
tmpl_args := yodb.JsonMap[string]{MailTmplVarEmailAddr: string(req.EmailAddr), MailTmplVarName: string(req.EmailAddr)}

util/util.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ type (
1515
}
1616
)
1717

18-
func Assert(alwaysTrue bool, show func() any) {
18+
func Assert(alwaysTrue bool, show any) {
1919
if IsDevMode {
2020
if !alwaysTrue {
2121
var err any = "unreachable"
2222
if show != nil {
23-
err = show()
23+
if show_fn, _ := show.(func() any); show_fn != nil {
24+
err = show_fn()
25+
} else {
26+
err = show
27+
}
2428
}
2529
panic(str.FmtV(err))
2630
}

0 commit comments

Comments
 (0)