added mfa

This commit is contained in:
2026-05-24 08:37:27 +00:00
parent a1d9ed86e1
commit 3ab54f812a
10 changed files with 398 additions and 33 deletions
+50
View File
@@ -9,7 +9,10 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"time"
qrcode "github.com/skip2/go-qrcode"
)
// Run is the application entry point, called from main().
@@ -21,6 +24,7 @@ func Run() {
cetkeyFlag := flag.String("certkey", "", "set custom TLS private key PEM file")
certreset := flag.Bool("certreset", false, "remove stored custom certificate, revert to self-signed")
logFlag := flag.String("log", "", "auth log file path; 'off' disables file logging (default: gotermix.log next to binary)")
mfaFlag := flag.String("mfa", "", "manage MFA for a user: -mfa <username> on|off")
flag.Parse()
initialCwd, _ = os.Getwd()
@@ -91,6 +95,52 @@ func Run() {
os.Exit(0)
}
// ── -mfa <username> on|off ────────────────────────────────────────
if *mfaFlag != "" {
args := flag.Args()
if len(args) < 1 || (args[0] != "on" && args[0] != "off") {
fmt.Fprintln(os.Stderr, "usage: -mfa <username> on|off")
os.Exit(1)
}
c := loadCreds()
if !strings.EqualFold(c.Username, *mfaFlag) {
fmt.Fprintf(os.Stderr, "unknown user %q (current user is %q)\n", *mfaFlag, c.Username)
os.Exit(1)
}
if args[0] == "off" {
c.MFAEnabled = false
c.MFASecret = ""
if err := saveCreds(c); err != nil {
fmt.Fprintf(os.Stderr, "error saving credentials: %v\n", err)
os.Exit(1)
}
fmt.Printf("MFA disabled for user %q\n", c.Username)
os.Exit(0)
}
// on: generate new secret
secret := newTOTPSecret()
c.MFASecret = secret
c.MFAEnabled = true
if err := saveCreds(c); err != nil {
fmt.Fprintf(os.Stderr, "error saving credentials: %v\n", err)
os.Exit(1)
}
otpauthURL := totpOtpauthURL(secret, c.Username, "GoTermix")
fmt.Printf("MFA enabled for user %q\n\n", c.Username)
fmt.Printf("Secret (manual entry): %s\n\n", secret)
fmt.Printf("otpauth URL: %s\n\n", otpauthURL)
fmt.Println("Scan with your authenticator app (Google Authenticator, Aegis, Authy ...):")
fmt.Println()
qr, err := qrcode.New(otpauthURL, qrcode.Medium)
if err != nil {
fmt.Fprintf(os.Stderr, "QR error: %v\n", err)
} else {
fmt.Println(qr.ToSmallString(false))
}
fmt.Println("If the QR code does not render, enter the secret manually in your app.")
os.Exit(0)
}
nopwMode = *nopw
appCreds = loadCreds()
initAuthSecret()