TOTP methods can now be created on the frontend!

This commit is contained in:
ari melody 2025-01-23 12:09:33 +00:00
parent e457e979ff
commit 50cbce92fc
Signed by: ari
GPG key ID: CF99829C92678188
11 changed files with 295 additions and 56 deletions

View file

@ -17,9 +17,9 @@ import (
"github.com/jmoiron/sqlx"
)
const TOTP_SECRET_LENGTH = 64
const TIME_STEP int64 = 30
const CODE_LENGTH = 6
const TOTP_SECRET_LENGTH = 32
const TOTP_TIME_STEP int64 = 30
const TOTP_CODE_LENGTH = 6
func GenerateTOTP(secret string, timeStepOffset int) string {
decodedSecret, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
@ -27,7 +27,7 @@ func GenerateTOTP(secret string, timeStepOffset int) string {
fmt.Fprintf(os.Stderr, "WARN: Invalid Base32 secret\n")
}
counter := time.Now().Unix() / TIME_STEP - int64(timeStepOffset)
counter := time.Now().Unix() / TOTP_TIME_STEP - int64(timeStepOffset)
counterBytes := make([]byte, 8)
binary.BigEndian.PutUint64(counterBytes, uint64(counter))
@ -37,9 +37,9 @@ func GenerateTOTP(secret string, timeStepOffset int) string {
offset := hash[len(hash) - 1] & 0x0f
binaryCode := int32(binary.BigEndian.Uint32(hash[offset : offset + 4]) & 0x7FFFFFFF)
code := binaryCode % int32(math.Pow10(CODE_LENGTH))
code := binaryCode % int32(math.Pow10(TOTP_CODE_LENGTH))
return fmt.Sprintf(fmt.Sprintf("%%0%dd", CODE_LENGTH), code)
return fmt.Sprintf(fmt.Sprintf("%%0%dd", TOTP_CODE_LENGTH), code)
}
func GenerateTOTPSecret(length int) string {
@ -65,8 +65,8 @@ func GenerateTOTPURI(username string, secret string) string {
query.Set("secret", secret)
query.Set("issuer", "arimelody.me")
query.Set("algorithm", "SHA1")
query.Set("digits", fmt.Sprintf("%d", CODE_LENGTH))
query.Set("period", fmt.Sprintf("%d", TIME_STEP))
query.Set("digits", fmt.Sprintf("%d", TOTP_CODE_LENGTH))
query.Set("period", fmt.Sprintf("%d", TOTP_TIME_STEP))
url.RawQuery = query.Encode()
return url.String()
@ -98,7 +98,11 @@ func CheckTOTPForAccount(db *sqlx.DB, accountID string, totp string) (*model.TOT
for _, method := range totps {
check := GenerateTOTP(method.Secret, 0)
if check == totp {
// return the whole TOTP method as it may be useful for logging
return &method, nil
}
// try again with offset- maybe user input the code late?
check = GenerateTOTP(method.Secret, 1)
if check == totp {
return &method, nil
}
}