fix: token 改为配置文件读取,不再自动生成;UI 全部汉化

This commit is contained in:
2026-03-01 04:09:55 +08:00
parent 2ce0323ba5
commit 9420d43392
5 changed files with 36 additions and 29 deletions

View File

@@ -11,3 +11,7 @@ doubao:
server: server:
port: 8443 # env: PORT port: 8443 # env: PORT
tls_auto: true # env: TLS_AUTO — 自动 TLS (AnyIP + 自签名降级) tls_auto: true # env: TLS_AUTO — 自动 TLS (AnyIP + 自签名降级)
# 安全配置
security:
token: "" # 留空则不需要认证;填写后访问需携带 token 参数

View File

@@ -11,6 +11,11 @@ type DoubaoConfig struct {
ResourceID string `yaml:"resource_id"` ResourceID string `yaml:"resource_id"`
} }
// SecurityConfig holds authentication settings.
type SecurityConfig struct {
Token string `yaml:"token"`
}
// ServerConfig holds server settings. // ServerConfig holds server settings.
type ServerConfig struct { type ServerConfig struct {
Port int `yaml:"port"` Port int `yaml:"port"`
@@ -19,8 +24,9 @@ type ServerConfig struct {
// Config is the top-level configuration. // Config is the top-level configuration.
type Config struct { type Config struct {
Doubao DoubaoConfig `yaml:"doubao"` Doubao DoubaoConfig `yaml:"doubao"`
Server ServerConfig `yaml:"server"` Server ServerConfig `yaml:"server"`
Security SecurityConfig `yaml:"security"`
} }
// defaults returns a Config with default values. // defaults returns a Config with default values.

View File

@@ -1,10 +1,7 @@
package server package server
import ( import (
"crypto/rand"
"encoding/hex"
"fmt" "fmt"
"log/slog"
"net" "net"
) )
@@ -22,13 +19,3 @@ func GetLANIP() (string, error) {
return "", fmt.Errorf("no LAN IP found") return "", fmt.Errorf("no LAN IP found")
} }
// GenerateToken creates a cryptographically random token for WS auth.
func GenerateToken() string {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
slog.Error("failed to generate token", "error", err)
// Fallback to a less secure but functional token
return "voicepaste-fallback-token"
}
return hex.EncodeToString(b)
}

28
main.go
View File

@@ -49,8 +49,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// Generate auth token // Read token from config (empty = no auth required)
token := server.GenerateToken() token := cfg.Security.Token
// TLS setup // TLS setup
var tlsResult *vpTLS.Result var tlsResult *vpTLS.Result
@@ -67,24 +67,34 @@ func main() {
host = tlsResult.Host host = tlsResult.Host
} }
// Build URL // Build URL
url := fmt.Sprintf("%s://%s:%d/?token=%s", scheme, host, cfg.Server.Port, token) var url string
if token != "" {
url = fmt.Sprintf("%s://%s:%d/?token=%s", scheme, host, cfg.Server.Port, token)
} else {
url = fmt.Sprintf("%s://%s:%d/", scheme, host, cfg.Server.Port)
}
// Print connection info // Print connection info
fmt.Println() fmt.Println()
fmt.Println("╔══════════════════════════════════════╗") fmt.Println("╔══════════════════════════════════════╗")
fmt.Println("║ VoicePaste Ready ║") fmt.Println("║ VoicePaste 就绪 ║")
fmt.Println("╚══════════════════════════════════════╝") fmt.Println("╚══════════════════════════════════════╝")
fmt.Println() fmt.Println()
fmt.Printf(" URL: %s\n", url) fmt.Printf(" 地址: %s\n", url)
if tlsResult != nil && tlsResult.AnyIP { if tlsResult != nil && tlsResult.AnyIP {
fmt.Println(" TLS: AnyIP (browser-trusted)") fmt.Println(" 证书: AnyIP(浏览器信任)")
} else if cfg.Server.TLSAuto { } else if cfg.Server.TLSAuto {
fmt.Println(" TLS: self-signed (browser will warn)") fmt.Println(" 证书: 自签名(浏览器会警告)")
}
if token != "" {
fmt.Println(" 认证: 已启用")
} else {
fmt.Println(" 认证: 未启用(无需 token")
} }
fmt.Println() fmt.Println()
printQRCode(url) printQRCode(url)
fmt.Println() fmt.Println()
fmt.Println(" Scan QR code with your phone to connect.") fmt.Println(" 用手机扫描二维码连接")
fmt.Println(" Press Ctrl+C to stop.") fmt.Println(" Ctrl+C 停止服务")
fmt.Println() fmt.Println()
// Create and start server // Create and start server
webContent, _ := fs.Sub(webFS, "web") webContent, _ := fs.Sub(webFS, "web")

View File

@@ -14,13 +14,13 @@
<h1>VoicePaste</h1> <h1>VoicePaste</h1>
<div id="status" class="status disconnected"> <div id="status" class="status disconnected">
<span class="dot"></span> <span class="dot"></span>
<span id="status-text">Connecting...</span> <span id="status-text">连接中…</span>
</div> </div>
</header> </header>
<section id="preview-section"> <section id="preview-section">
<div id="preview" class="preview-box"> <div id="preview" class="preview-box">
<p id="preview-text" class="placeholder">Press and hold to speak</p> <p id="preview-text" class="placeholder">按住说话…</p>
</div> </div>
</section> </section>
@@ -35,11 +35,11 @@
<section id="history-section"> <section id="history-section">
<div class="history-header"> <div class="history-header">
<h2>History</h2> <h2>历史记录</h2>
<button id="clear-history" class="text-btn">Clear</button> <button id="clear-history" class="text-btn">清空</button>
</div> </div>
<ul id="history-list"></ul> <ul id="history-list"></ul>
<p id="history-empty" class="placeholder">No history yet</p> <p id="history-empty" class="placeholder">暂无记录</p>
</section> </section>
</div> </div>