Phase 2-6: Git sync, sharing, 2FA, AI integration
- Git: init, commit, log, diff, restore, remotes, push/pull - Auto-commit on every file save - Sharing: share/unshare files with other users (ro/rw) - Shared documents view in sidebar - 2FA: TOTP setup/verify/disable, enforced at login - AI: verify spec endpoint (LiteLLM), generate (summarize/prompt/expand) - Light/dark theme with CSS variables - File delete (recursive for folders) - Admin panel + preferences panel - File creation timestamp display
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base32"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GenerateTOTPSecret creates a random base32-encoded secret.
|
||||
func GenerateTOTPSecret() string {
|
||||
b := make([]byte, 20)
|
||||
for i := range b {
|
||||
b[i] = byte(rand.Intn(256))
|
||||
}
|
||||
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(b)
|
||||
}
|
||||
|
||||
// ValidateTOTP checks if the provided code matches the secret for the current time window.
|
||||
func ValidateTOTP(secret, code string) bool {
|
||||
secret = strings.ToUpper(strings.TrimSpace(secret))
|
||||
key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
now := time.Now().Unix() / 30
|
||||
// Check current window and ±1 for clock drift
|
||||
for _, offset := range []int64{-1, 0, 1} {
|
||||
if generateCode(key, now+offset) == code {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TOTPUri generates an otpauth:// URI for QR code generation.
|
||||
func TOTPUri(secret, email, issuer string) string {
|
||||
return fmt.Sprintf("otpauth://totp/%s:%s?secret=%s&issuer=%s&algorithm=SHA1&digits=6&period=30",
|
||||
issuer, email, secret, issuer)
|
||||
}
|
||||
|
||||
func generateCode(key []byte, counter int64) string {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(counter))
|
||||
|
||||
mac := hmac.New(sha1.New, key)
|
||||
mac.Write(buf)
|
||||
hash := mac.Sum(nil)
|
||||
|
||||
offset := hash[len(hash)-1] & 0x0f
|
||||
code := binary.BigEndian.Uint32(hash[offset:offset+4]) & 0x7fffffff
|
||||
return fmt.Sprintf("%06d", code%1000000)
|
||||
}
|
||||
Reference in New Issue
Block a user