mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-05-17 22:37:36 +08:00
Add complete MFA support with TOTP, recovery codes, WebAuthn, trusted-device cookie flow, and email/SMS OTP delivery via notification channels. Security follow-up: trusted device tokens are stored in HttpOnly cookies, and SMS OTP reuses the existing Webhook notifier to avoid introducing a new dynamic URL sink.
69 lines
1.4 KiB
Go
69 lines
1.4 KiB
Go
package security
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"image/png"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
|
|
"github.com/pquerna/otp"
|
|
"github.com/pquerna/otp/totp"
|
|
)
|
|
|
|
const TOTPIssuer = "BackupX"
|
|
|
|
type TOTPEnrollment struct {
|
|
Secret string
|
|
OTPAuthURL string
|
|
QRCodeDataURL string
|
|
}
|
|
|
|
func GenerateTOTPEnrollment(accountName string) (*TOTPEnrollment, error) {
|
|
key, err := totp.Generate(totp.GenerateOpts{
|
|
Issuer: TOTPIssuer,
|
|
AccountName: accountName,
|
|
Period: 30,
|
|
SecretSize: 20,
|
|
Digits: otp.DigitsSix,
|
|
Algorithm: otp.AlgorithmSHA1,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
image, err := key.Image(220, 220)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := png.Encode(&buf, image); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &TOTPEnrollment{
|
|
Secret: key.Secret(),
|
|
OTPAuthURL: key.URL(),
|
|
QRCodeDataURL: "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()),
|
|
}, nil
|
|
}
|
|
|
|
func ValidateTOTPCode(secret string, code string) (bool, error) {
|
|
return totp.ValidateCustom(NormalizeTOTPCode(code), secret, time.Now().UTC(), totp.ValidateOpts{
|
|
Period: 30,
|
|
Skew: 1,
|
|
Digits: otp.DigitsSix,
|
|
Algorithm: otp.AlgorithmSHA1,
|
|
})
|
|
}
|
|
|
|
func NormalizeTOTPCode(code string) string {
|
|
return strings.Map(func(r rune) rune {
|
|
if unicode.IsSpace(r) {
|
|
return -1
|
|
}
|
|
return r
|
|
}, strings.TrimSpace(code))
|
|
}
|