fix: token 改为配置文件读取,不再自动生成;UI 全部汉化
This commit is contained in:
@@ -11,3 +11,7 @@ doubao:
|
||||
server:
|
||||
port: 8443 # env: PORT
|
||||
tls_auto: true # env: TLS_AUTO — 自动 TLS (AnyIP + 自签名降级)
|
||||
|
||||
# 安全配置
|
||||
security:
|
||||
token: "" # 留空则不需要认证;填写后访问需携带 token 参数
|
||||
|
||||
@@ -11,6 +11,11 @@ type DoubaoConfig struct {
|
||||
ResourceID string `yaml:"resource_id"`
|
||||
}
|
||||
|
||||
// SecurityConfig holds authentication settings.
|
||||
type SecurityConfig struct {
|
||||
Token string `yaml:"token"`
|
||||
}
|
||||
|
||||
// ServerConfig holds server settings.
|
||||
type ServerConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
@@ -21,6 +26,7 @@ type ServerConfig struct {
|
||||
type Config struct {
|
||||
Doubao DoubaoConfig `yaml:"doubao"`
|
||||
Server ServerConfig `yaml:"server"`
|
||||
Security SecurityConfig `yaml:"security"`
|
||||
}
|
||||
|
||||
// defaults returns a Config with default values.
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
)
|
||||
|
||||
@@ -22,13 +19,3 @@ func GetLANIP() (string, error) {
|
||||
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
28
main.go
@@ -49,8 +49,8 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Generate auth token
|
||||
token := server.GenerateToken()
|
||||
// Read token from config (empty = no auth required)
|
||||
token := cfg.Security.Token
|
||||
|
||||
// TLS setup
|
||||
var tlsResult *vpTLS.Result
|
||||
@@ -67,24 +67,34 @@ func main() {
|
||||
host = tlsResult.Host
|
||||
}
|
||||
// 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
|
||||
fmt.Println()
|
||||
fmt.Println("╔══════════════════════════════════════╗")
|
||||
fmt.Println("║ VoicePaste Ready ║")
|
||||
fmt.Println("║ VoicePaste 就绪 ║")
|
||||
fmt.Println("╚══════════════════════════════════════╝")
|
||||
fmt.Println()
|
||||
fmt.Printf(" URL: %s\n", url)
|
||||
fmt.Printf(" 地址: %s\n", url)
|
||||
if tlsResult != nil && tlsResult.AnyIP {
|
||||
fmt.Println(" TLS: AnyIP (browser-trusted)")
|
||||
fmt.Println(" 证书: AnyIP(浏览器信任)")
|
||||
} 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()
|
||||
printQRCode(url)
|
||||
fmt.Println()
|
||||
fmt.Println(" Scan QR code with your phone to connect.")
|
||||
fmt.Println(" Press Ctrl+C to stop.")
|
||||
fmt.Println(" 用手机扫描二维码连接")
|
||||
fmt.Println(" 按 Ctrl+C 停止服务")
|
||||
fmt.Println()
|
||||
// Create and start server
|
||||
webContent, _ := fs.Sub(webFS, "web")
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
<h1>VoicePaste</h1>
|
||||
<div id="status" class="status disconnected">
|
||||
<span class="dot"></span>
|
||||
<span id="status-text">Connecting...</span>
|
||||
<span id="status-text">连接中…</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="preview-section">
|
||||
<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>
|
||||
</section>
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
|
||||
<section id="history-section">
|
||||
<div class="history-header">
|
||||
<h2>History</h2>
|
||||
<button id="clear-history" class="text-btn">Clear</button>
|
||||
<h2>历史记录</h2>
|
||||
<button id="clear-history" class="text-btn">清空</button>
|
||||
</div>
|
||||
<ul id="history-list"></ul>
|
||||
<p id="history-empty" class="placeholder">No history yet</p>
|
||||
<p id="history-empty" class="placeholder">暂无记录</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user