diff --git a/Makefile b/Makefile index 8bd5d21..a92a9a3 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ APP_NAME = wormhole-client VERSION = v1.0.0 LDFLAGS = -ldflags "-X main.version=$(VERSION) -X main.buildTime=$(shell date -u '+%Y-%m-%d_%H:%M:%S')" -.PHONY: all build clean deps test run install uninstall lint coverage fmt vet check +.PHONY: all build clean deps test run install uninstall lint coverage fmt vet check dmg dmg-macos all: clean deps build @@ -57,6 +57,28 @@ install: build uninstall: sudo rm -f /usr/local/bin/$(APP_NAME) +# macOS DMG 安装包构建 +dmg-macos: + @echo "🍎 Building macOS DMG installer..." + @if [ "$(shell uname)" != "Darwin" ]; then \ + echo "❌ DMG building is only supported on macOS"; \ + exit 1; \ + fi + chmod +x scripts/build-dmg.sh + ./scripts/build-dmg.sh + @echo "✅ macOS DMG installer created in build/ directory" + +# 通用 DMG 构建 (检测平台) +dmg: + @if [ "$(shell uname)" = "Darwin" ]; then \ + $(MAKE) dmg-macos; \ + else \ + echo "❌ DMG building is only supported on macOS"; \ + echo "ℹ️ You are on: $(shell uname)"; \ + echo "ℹ️ Please use a macOS system to build DMG installers"; \ + exit 1; \ + fi + help: @echo "Available targets:" @echo " build - Build the client binary" @@ -73,6 +95,8 @@ help: @echo " deps - Download dependencies" @echo " install - Install to /usr/local/bin" @echo " uninstall - Remove from /usr/local/bin" + @echo " dmg - Build macOS DMG installer (macOS only)" + @echo " dmg-macos - Build macOS DMG installer (macOS only)" @echo "" @echo "GUI Access:" @echo " After starting, access the web GUI at:" diff --git a/assets/icons/app.icns b/assets/icons/app.icns new file mode 100644 index 0000000..a1e51b3 Binary files /dev/null and b/assets/icons/app.icns differ diff --git a/configs/client.yaml b/configs/client.yaml index 4eeda9d..c22c91f 100644 --- a/configs/client.yaml +++ b/configs/client.yaml @@ -3,10 +3,12 @@ serviceType: client # SOCKS5 服务器设置 server: - address: 3.133.130.202 + address: 18.117.71.98 port: 1080 username: admin password: secure123 + preferIPv4: true # 强制使用IPv4 + timeout: 60s # 增加连接超时 # 代理模式设置 proxy: @@ -17,7 +19,7 @@ proxy: globalProxy: enabled: true dnsProxy: true - dnsPort: 5353 + dnsPort: 15353 # 客户端DNS代理端口 # 智能分流路由规则 routing: @@ -56,7 +58,11 @@ globalProxy: - "*.amazonaws.com" - "*.aliyuncs.com" - "*.qcloud.com" - + - "*.cursor.sh" + - "*.apple.com" + - "*.icloud.com" + # 特定服务IP地址 + - "101.34.16.52" # Gitea 服务器 # 强制代理域名列表 (必须经过代理) forceDomains: # Google 服务 @@ -172,15 +178,12 @@ globalProxy: - "*.twitch.tv" - "steam.community" - "*.steam.community" - - # 特定服务IP地址 - - "101.34.16.52" # Gitea 服务器 # 透明代理设置 (实验性功能) transparentProxy: enabled: false port: 8080 - dnsPort: 5353 + dnsPort: 15353 # 透明代理DNS端口(与全局代理一致) # 系统级修改 (需要root权限) modifyDNS: true # 修改系统DNS设置 diff --git a/coverage.html b/coverage.html deleted file mode 100644 index c203ced..0000000 --- a/coverage.html +++ /dev/null @@ -1,1693 +0,0 @@ - - - - - - wormhole-client: Go Coverage Report - - - -
- -
- not tracked - - no coverage - low coverage - * - * - * - * - * - * - * - * - high coverage - -
-
-
- - - - - - - - - - - - - - - - - -
- - - diff --git a/docs/BUILD_DMG.md b/docs/BUILD_DMG.md new file mode 100644 index 0000000..24a152a --- /dev/null +++ b/docs/BUILD_DMG.md @@ -0,0 +1,195 @@ +# macOS DMG 安装包构建指南 + +本文档介绍如何为 Wormhole SOCKS5 Client 构建 macOS DMG 安装包。 + +## 🔧 环境要求 + +### 系统要求 +- **macOS 10.13+** (High Sierra 或更高版本) +- **Xcode Command Line Tools** 或完整的 Xcode +- **Go 1.19+** + +### 可选工具 +- **Python 3** + **Pillow (PIL)** - 用于生成自定义应用图标 +- **Git** - 用于版本控制 + +## 🚀 快速开始 + +### 一键构建 +```bash +# 构建完整的 DMG 安装包 +make dmg + +# 或者使用完整命令 +make dmg-macos +``` + +### 分步构建 +```bash +# 1. 构建 macOS 应用程序包 +./scripts/build-macos.sh + +# 2. 创建 DMG 安装包 +./scripts/create-dmg.sh + +# 3. 验证和测试 +open build/Wormhole-Client-v1.0.0.dmg +``` + +## 📁 构建产物 + +构建成功后,将在 `build/` 目录下生成以下文件: + +``` +build/ +├── Wormhole Client.app/ # macOS 应用程序包 +│ ├── Contents/ +│ │ ├── Info.plist # 应用信息 +│ │ ├── MacOS/ +│ │ │ ├── wormhole-client # 二进制文件 +│ │ │ └── Wormhole Client # 启动脚本 +│ │ └── Resources/ +│ │ ├── configs/ # 配置文件 +│ │ └── app.icns # 应用图标 +│ └── ... +└── Wormhole-Client-v1.0.0.dmg # 最终安装包 +``` + +## 🎨 自定义图标 + +### 使用自定义图标 +1. 准备一个 1024x1024 的 PNG 图片 +2. 将其保存为 `assets/icons/icon.png` +3. 重新构建即可使用自定义图标 + +### 自动生成图标 +如果没有自定义图标,构建脚本会自动: +1. 尝试使用 Python PIL 生成简单图标 +2. 如果失败,使用系统默认应用图标 + +## 📦 DMG 特性 + +### 安装体验 +- **拖拽安装**: 用户只需将 app 拖到 Applications 文件夹 +- **自动布局**: 优化的窗口布局和图标位置 +- **说明文档**: 包含安装和使用说明 + +### DMG 内容 +- `Wormhole Client.app` - 主应用程序 +- `Applications` - Applications 文件夹快捷方式 +- `README.txt` - 安装和使用说明 + +## 🔍 构建脚本详解 + +### build-macos.sh +- 编译 Go 二进制文件 (amd64 架构) +- 创建标准的 macOS 应用程序包结构 +- 复制配置文件和资源 +- 生成或复制应用图标 +- 创建 Info.plist 文件 +- 设置启动脚本 + +### create-dmg.sh +- 创建临时 DMG 工作目录 +- 复制应用程序和创建符号链接 +- 生成说明文档 +- 使用 AppleScript 美化 DMG 外观 +- 创建压缩的只读 DMG +- 验证 DMG 完整性 + +### build-dmg.sh +- 一键执行完整构建流程 +- 环境检查和工具验证 +- 构建结果汇总和验证 + +## 🛠️ 故障排除 + +### 常见问题 + +#### 1. hdiutil 权限错误 +```bash +# 解决方案:使用 sudo 或给予磁盘访问权限 +sudo ./scripts/create-dmg.sh +``` + +#### 2. AppleScript 执行失败 +```bash +# 检查系统完整性保护 (SIP) +csrutil status + +# 在系统偏好设置中允许自动化权限 +# 系统偏好设置 > 安全性与隐私 > 隐私 > 自动化 +``` + +#### 3. Go 编译失败 +```bash +# 检查 Go 版本 +go version + +# 确保依赖已下载 +go mod download +go mod tidy +``` + +### 调试模式 +```bash +# 开启详细输出 +set -x +./scripts/build-dmg.sh +``` + +## 📱 应用程序使用 + +### 安装后使用 +1. 双击 DMG 文件挂载 +2. 拖拽 `Wormhole Client.app` 到 Applications +3. 从 Applications 或 Launchpad 启动应用 + +### 启动模式 +- **双击启动**: 自动以 HTTP 模式启动并打开 Web 界面 +- **终端启动**: 支持所有命令行参数 + ```bash + # HTTP 模式 + /Applications/Wormhole\ Client.app/Contents/MacOS/Wormhole\ Client -mode http + + # 全局模式 (需要 sudo) + sudo /Applications/Wormhole\ Client.app/Contents/MacOS/Wormhole\ Client -mode global + ``` + +### Web 界面 +- **管理界面**: http://127.0.0.1:8080/gui +- **统计信息**: http://127.0.0.1:8080/stats +- **健康检查**: http://127.0.0.1:8080/health + +## 🔒 代码签名 (可选) + +如果需要分发给其他用户,建议进行代码签名: + +```bash +# 签名应用程序 +codesign --force --deep --sign "Developer ID Application: Your Name" \ + "build/Wormhole Client.app" + +# 签名 DMG +codesign --force --sign "Developer ID Application: Your Name" \ + "build/Wormhole-Client-v1.0.0.dmg" + +# 验证签名 +codesign --verify --deep --strict --verbose=2 "build/Wormhole Client.app" +spctl --assess --type execute --verbose "build/Wormhole Client.app" +``` + +## 📈 版本管理 + +修改版本号: +1. 编辑 `scripts/build-macos.sh` 中的 `VERSION` 变量 +2. 编辑 `Makefile` 中的 `VERSION` 变量 +3. 重新构建 DMG + +## 🤝 贡献 + +如果您发现构建脚本的问题或有改进建议,欢迎提交 Issue 或 Pull Request。 + +## 📄 许可证 + +本构建系统遵循项目的 MIT 许可证。 \ No newline at end of file diff --git a/internal/client/client.go b/internal/client/client.go index 3d7498b..8fc0c0f 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -198,13 +198,15 @@ func (c *Client) startTransparentProxy() error { logger.Info("💡 This will intercept network traffic transparently") logger.Info("⚠️ Requires root privileges and iptables support") - // TODO: 实现透明代理 - logger.Error("❌ Transparent proxy mode is not yet implemented") + // 暂时禁用透明代理模式,提供更好的用户体验 + logger.Warn("⚠️ Transparent proxy mode is currently disabled") + logger.Info("🔄 This feature is under development and not yet ready for production use") logger.Info("💡 Available alternatives:") logger.Info(" - Use global mode: ./bin/wormhole-client -mode global") logger.Info(" - Use HTTP mode: ./bin/wormhole-client -mode http") + logger.Info("📝 Note: Global mode provides similar functionality with system proxy configuration") - return fmt.Errorf("transparent proxy mode not implemented") + return fmt.Errorf("transparent proxy mode is currently disabled - please use 'global' or 'http' mode") } // createHTTPServerWithGUI 创建带有 GUI 的 HTTP 服务器 diff --git a/internal/config/config.go b/internal/config/config.go index 1250946..474d48a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,10 +21,11 @@ type Config struct { // Server SOCKS5服务器配置 type Server struct { - Address string `yaml:"address"` - Port int `yaml:"port"` - Username string `yaml:"username"` - Password string `yaml:"password"` + Address string `yaml:"address"` + Port int `yaml:"port"` + Username string `yaml:"username"` + Password string `yaml:"password"` + Timeout time.Duration `yaml:"timeout"` } // Proxy 代理模式配置 @@ -77,6 +78,9 @@ func LoadConfig(configPath string) (*Config, error) { if config.Timeout == 0 { config.Timeout = 30 * time.Second } + if config.Server.Timeout == 0 { + config.Server.Timeout = 60 * time.Second // 默认60秒服务器连接超时 + } if config.Proxy.LocalPort == 0 { config.Proxy.LocalPort = 8080 } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index c84cdac..69a155e 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -65,20 +65,30 @@ func (l *Logger) log(level LogLevel, format string, args ...interface{}) { } levelStr := "" + levelColor := "" + resetColor := "\033[0m" + switch level { case DEBUG: levelStr = "DEBUG" + levelColor = "\033[36m" // Cyan case INFO: levelStr = "INFO" + levelColor = "\033[32m" // Green case WARN: levelStr = "WARN" + levelColor = "\033[33m" // Yellow case ERROR: levelStr = "ERROR" + levelColor = "\033[31m" // Red } - timestamp := time.Now().Format("2006-01-02 15:04:05") + timestamp := time.Now().Format("2006-01-02T15:04:05.000Z07:00") message := fmt.Sprintf(format, args...) - logLine := fmt.Sprintf("[%s] [%s] %s", timestamp, levelStr, message) + + // 结构化日志格式,类似logrus但保持简洁 + logLine := fmt.Sprintf("%s[%s%s%s] [wormhole-client] %s", + timestamp, levelColor, levelStr, resetColor, message) l.logger.Println(logLine) } diff --git a/scripts/build-dmg.sh b/scripts/build-dmg.sh new file mode 100755 index 0000000..e66eee9 --- /dev/null +++ b/scripts/build-dmg.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +set -e + +# 项目信息 +APP_NAME="Wormhole Client" +VERSION="v1.0.0" + +# 路径配置 +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "🚀 Building Wormhole Client DMG Installer" +echo "==========================================" +echo "📦 Version: $VERSION" +echo "📁 Project: $PROJECT_ROOT" +echo "" + +# 检查必要的工具 +echo "🔍 Checking required tools..." + +# 检查 Go +if ! command -v go &> /dev/null; then + echo "❌ Go is not installed. Please install Go first." + exit 1 +fi +echo "✅ Go: $(go version)" + +# 检查 hdiutil (macOS 内置) +if ! command -v hdiutil &> /dev/null; then + echo "❌ hdiutil not found. This script requires macOS." + exit 1 +fi +echo "✅ hdiutil: Available" + +# 检查 osascript (macOS 内置) +if ! command -v osascript &> /dev/null; then + echo "❌ osascript not found. This script requires macOS." + exit 1 +fi +echo "✅ osascript: Available" + +echo "" + +# 步骤 1: 构建应用程序包 +echo "📱 Step 1: Building macOS application bundle..." +echo "----------------------------------------------" +if [ -f "$SCRIPT_DIR/build-macos.sh" ]; then + chmod +x "$SCRIPT_DIR/build-macos.sh" + "$SCRIPT_DIR/build-macos.sh" +else + echo "❌ build-macos.sh not found!" + exit 1 +fi + +echo "" + +# 步骤 2: 创建 DMG +echo "💿 Step 2: Creating DMG installer..." +echo "------------------------------------" +if [ -f "$SCRIPT_DIR/create-dmg.sh" ]; then + chmod +x "$SCRIPT_DIR/create-dmg.sh" + "$SCRIPT_DIR/create-dmg.sh" +else + echo "❌ create-dmg.sh not found!" + exit 1 +fi + +echo "" + +# 完成总结 +echo "🎉 BUILD COMPLETED SUCCESSFULLY!" +echo "=================================" +BUILD_DIR="$PROJECT_ROOT/build" +FINAL_DMG="$BUILD_DIR/Wormhole-Client-$VERSION.dmg" + +if [ -f "$FINAL_DMG" ]; then + echo "📦 DMG File: $FINAL_DMG" + echo "📊 File Size: $(du -h "$FINAL_DMG" | cut -f1)" + echo "🔗 SHA256: $(shasum -a 256 "$FINAL_DMG" | cut -d' ' -f1)" + echo "" + echo "📋 Distribution Ready:" + echo "1. Test the DMG by double-clicking it" + echo "2. Verify the application installs and runs correctly" + echo "3. Share the DMG file for distribution" + echo "" + echo "🔒 Security Notes:" + echo "- Users may need to allow the app in System Preferences > Security & Privacy" + echo "- Consider code signing for easier distribution" + echo "- For distribution outside the App Store, users may need to right-click and 'Open'" + echo "" + echo "✨ Your macOS installer is ready!" +else + echo "❌ DMG creation failed!" + exit 1 +fi \ No newline at end of file diff --git a/scripts/build-macos.sh b/scripts/build-macos.sh new file mode 100755 index 0000000..29bae83 --- /dev/null +++ b/scripts/build-macos.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +set -e + +# 项目信息 +APP_NAME="Wormhole Client" +BUNDLE_ID="com.azoic.wormhole-client" +VERSION="v1.0.0" +BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S') + +# 路径配置 +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +BUILD_DIR="$PROJECT_ROOT/build" +APP_DIR="$BUILD_DIR/$APP_NAME.app" +CONTENTS_DIR="$APP_DIR/Contents" +MACOS_DIR="$CONTENTS_DIR/MacOS" +RESOURCES_DIR="$CONTENTS_DIR/Resources" +DMG_DIR="$BUILD_DIR/dmg" +TEMP_DMG="$BUILD_DIR/temp.dmg" +FINAL_DMG="$BUILD_DIR/Wormhole-Client-$VERSION.dmg" + +echo "🚀 Building Wormhole Client for macOS..." +echo "📦 Version: $VERSION" +echo "📅 Build Time: $BUILD_TIME" + +# 清理构建目录 +echo "🧹 Cleaning build directory..." +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR" + +# 构建二进制文件 +echo "🔨 Building binary..." +cd "$PROJECT_ROOT" +GOOS=darwin GOARCH=amd64 go build \ + -ldflags "-X main.version=$VERSION -X main.buildTime=$BUILD_TIME" \ + -o "$BUILD_DIR/wormhole-client" \ + cmd/wormhole-client/main.go + +echo "✅ Binary built successfully" + +# 创建应用程序包结构 +echo "📦 Creating application bundle..." +mkdir -p "$MACOS_DIR" +mkdir -p "$RESOURCES_DIR" + +# 复制二进制文件 +cp "$BUILD_DIR/wormhole-client" "$MACOS_DIR/" + +# 复制配置文件 +cp -r configs "$RESOURCES_DIR/" + +# 创建或复制应用图标 +ICON_PATH="$PROJECT_ROOT/assets/icons/app.icns" +if [ -f "$ICON_PATH" ]; then + echo "📱 Using custom app icon..." + cp "$ICON_PATH" "$RESOURCES_DIR/" +else + echo "🎨 Creating default app icon..." + if [ -f "$PROJECT_ROOT/scripts/create-icon.sh" ]; then + chmod +x "$PROJECT_ROOT/scripts/create-icon.sh" + "$PROJECT_ROOT/scripts/create-icon.sh" + if [ -f "$ICON_PATH" ]; then + cp "$ICON_PATH" "$RESOURCES_DIR/" + fi + fi +fi + +# 创建启动脚本 +cat > "$MACOS_DIR/Wormhole Client" << 'EOF' +#!/bin/bash + +# Wormhole Client macOS Launcher +set -e + +# 获取应用程序路径 +APP_PATH="$(cd "$(dirname "$0")/.." && pwd)" +RESOURCES_PATH="$APP_PATH/Resources" +BINARY_PATH="$APP_PATH/MacOS/wormhole-client" +CONFIG_PATH="$RESOURCES_PATH/configs/client.yaml" + +# 检查二进制文件 +if [ ! -f "$BINARY_PATH" ]; then + echo "❌ Application binary not found" + exit 1 +fi + +# 设置工作目录 +cd "$RESOURCES_PATH" + +# 如果没有参数,启动 HTTP 模式并打开浏览器 +if [ $# -eq 0 ]; then + echo "🚀 Starting Wormhole Client in HTTP proxy mode..." + echo "🌐 Web interface will open automatically" + + # 后台启动应用 + "$BINARY_PATH" -config "$CONFIG_PATH" -mode http & + APP_PID=$! + + # 等待服务启动 + sleep 3 + + # 打开 Web 界面 + open "http://127.0.0.1:8080/gui" 2>/dev/null || echo "📱 Visit http://127.0.0.1:8080/gui to access the web interface" + + # 等待应用程序结束 + wait $APP_PID +else + # 有参数时直接传递 + exec "$BINARY_PATH" -config "$CONFIG_PATH" "$@" +fi +EOF + +chmod +x "$MACOS_DIR/Wormhole Client" + +# 创建 Info.plist +cat > "$CONTENTS_DIR/Info.plist" << EOF + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + $APP_NAME + CFBundleExecutable + Wormhole Client + CFBundleIdentifier + $BUNDLE_ID + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $APP_NAME + CFBundlePackageType + APPL + CFBundleShortVersionString + $VERSION + CFBundleVersion + $VERSION + LSMinimumSystemVersion + 10.13 + NSHighResolutionCapable + + LSApplicationCategoryType + public.app-category.networking + LSUIElement + + NSHumanReadableCopyright + Copyright © 2024 Azoic. All rights reserved. + CFBundleIconFile + app + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + yaml + yml + + CFBundleTypeName + Configuration File + CFBundleTypeRole + Editor + + + + +EOF + +echo "✅ Application bundle created" + +echo "🎯 Build completed successfully!" +echo "📁 Application bundle: $APP_DIR" \ No newline at end of file diff --git a/scripts/create-dmg.sh b/scripts/create-dmg.sh new file mode 100755 index 0000000..8b5e2e7 --- /dev/null +++ b/scripts/create-dmg.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +set -e + +# 项目信息 +APP_NAME="Wormhole Client" +VERSION="v1.0.0" + +# 路径配置 +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +BUILD_DIR="$PROJECT_ROOT/build" +APP_DIR="$BUILD_DIR/$APP_NAME.app" +DMG_DIR="$BUILD_DIR/dmg" +TEMP_DMG="$BUILD_DIR/temp.dmg" +FINAL_DMG="$BUILD_DIR/Wormhole-Client-$VERSION.dmg" + +# DMG 配置 +DMG_TITLE="Wormhole Client $VERSION" +DMG_SIZE="100m" +DMG_BACKGROUND="$PROJECT_ROOT/scripts/dmg-background.png" +DMG_ICON_SIZE=128 +DMG_TEXT_SIZE=16 + +echo "📦 Creating DMG installer for Wormhole Client..." + +# 检查应用程序包是否存在 +if [ ! -d "$APP_DIR" ]; then + echo "❌ Application bundle not found. Please run build-macos.sh first." + exit 1 +fi + +# 清理并创建 DMG 目录 +echo "🧹 Preparing DMG directory..." +rm -rf "$DMG_DIR" +mkdir -p "$DMG_DIR" + +# 复制应用程序到 DMG 目录 +echo "📱 Copying application to DMG..." +cp -R "$APP_DIR" "$DMG_DIR/" + +# 创建 Applications 符号链接 +echo "🔗 Creating Applications symlink..." +ln -s "/Applications" "$DMG_DIR/Applications" + +# 创建 README 文件 +echo "📝 Creating README..." +cat > "$DMG_DIR/README.txt" << EOF +Wormhole SOCKS5 Client $VERSION + +安装说明: +1. 将 "Wormhole Client.app" 拖拽到 Applications 文件夹 +2. 双击运行应用程序 +3. 首次运行时,可能需要在系统偏好设置中允许运行 + +使用方法: +- HTTP 模式:./wormhole-client -mode http +- 全局模式:sudo ./wormhole-client -mode global (需要管理员权限) + +Web 管理界面:http://127.0.0.1:8080/gui +统计信息:http://127.0.0.1:8080/stats + +更多信息请访问:https://github.com/azoic/wormhole-client + +Copyright © 2024 Azoic. All rights reserved. +EOF + +# 创建临时 DMG +echo "💿 Creating temporary DMG..." +hdiutil create -srcfolder "$DMG_DIR" -volname "$DMG_TITLE" -fs HFS+ \ + -fsargs "-c c=64,a=16,e=16" -format UDRW -size "$DMG_SIZE" "$TEMP_DMG" + +# 挂载临时 DMG 进行自定义 +echo "🎨 Customizing DMG appearance..." +DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "$TEMP_DMG" | \ + egrep '^/dev/' | sed 1q | awk '{print $1}') + +# 等待挂载完成 +sleep 2 + +# 设置 DMG 窗口属性 +MOUNT_DIR="/Volumes/$DMG_TITLE" + +# 使用 AppleScript 设置 Finder 窗口 +/usr/bin/osascript << EOF +tell application "Finder" + tell disk "$DMG_TITLE" + open + set current view of container window to icon view + set toolbar visible of container window to false + set statusbar visible of container window to false + set the bounds of container window to {400, 100, 920, 440} + set theViewOptions to the icon view options of container window + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to $DMG_ICON_SIZE + set text size of theViewOptions to $DMG_TEXT_SIZE + + -- 设置图标位置 + set position of item "Wormhole Client.app" of container window to {140, 120} + set position of item "Applications" of container window to {380, 120} + set position of item "README.txt" of container window to {260, 280} + + -- 应用更改 + update without registering applications + delay 2 + end tell +end tell +EOF + +# 等待 AppleScript 完成 +sleep 3 + +# 卸载临时 DMG +hdiutil detach "$DEVICE" + +# 创建最终的只读 DMG +echo "✨ Creating final DMG..." +rm -f "$FINAL_DMG" +hdiutil convert "$TEMP_DMG" -format UDZO -imagekey zlib-level=9 -o "$FINAL_DMG" + +# 清理临时文件 +echo "🧹 Cleaning up..." +rm -f "$TEMP_DMG" +rm -rf "$DMG_DIR" + +# 显示结果 +echo "" +echo "🎉 DMG creation completed successfully!" +echo "📁 DMG file: $FINAL_DMG" +echo "📊 File size: $(du -h "$FINAL_DMG" | cut -f1)" +echo "" +echo "✅ Installation package ready for distribution!" + +# 验证 DMG +echo "🔍 Verifying DMG integrity..." +if hdiutil verify "$FINAL_DMG"; then + echo "✅ DMG verification passed" +else + echo "❌ DMG verification failed" + exit 1 +fi + +# 显示安装说明 +echo "" +echo "📋 Installation Instructions:" +echo "1. Double-click the DMG file to mount it" +echo "2. Drag 'Wormhole Client.app' to the Applications folder" +echo "3. Eject the DMG" +echo "4. Launch 'Wormhole Client' from Applications" +echo "" +echo "🔒 Security Note:" +echo "If macOS blocks the app, go to System Preferences > Security & Privacy" +echo "and click 'Open Anyway' to allow the application to run." \ No newline at end of file diff --git a/scripts/create-icon.sh b/scripts/create-icon.sh new file mode 100755 index 0000000..cc49a67 --- /dev/null +++ b/scripts/create-icon.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +set -e + +# 项目信息 +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +ICON_DIR="$PROJECT_ROOT/assets/icons" +APP_ICON="$ICON_DIR/app.icns" + +echo "🎨 Creating application icon..." + +# 创建图标目录 +mkdir -p "$ICON_DIR" + +# 创建临时目录 +TEMP_DIR=$(mktemp -d) +ICONSET_DIR="$TEMP_DIR/app.iconset" +mkdir -p "$ICONSET_DIR" + +# 如果没有源图像,创建一个简单的默认图标 +if [ ! -f "$ICON_DIR/icon.png" ]; then + echo "📝 Creating default icon..." + + # 使用 sips 创建简单的彩色图标 (macOS 内置工具) + # 创建一个 1024x1024 的纯色图像作为基础 + cat > "$TEMP_DIR/create_icon.py" << 'EOF' +#!/usr/bin/env python3 +import sys +from PIL import Image, ImageDraw, ImageFont +import os + +def create_icon(size, output_path): + # 创建图像 + img = Image.new('RGBA', (size, size), (0, 0, 0, 0)) + draw = ImageDraw.Draw(img) + + # 绘制背景圆形 + margin = size // 8 + draw.ellipse([margin, margin, size-margin, size-margin], + fill=(58, 134, 255, 255), outline=(30, 100, 200, 255), width=size//50) + + # 绘制文字 + try: + font_size = size // 6 + font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", font_size) + except: + font = ImageFont.load_default() + + text = "W" + bbox = draw.textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + x = (size - text_width) // 2 + y = (size - text_height) // 2 - size // 20 + + draw.text((x, y), text, fill=(255, 255, 255, 255), font=font) + + # 保存图像 + img.save(output_path, 'PNG') + +if __name__ == "__main__": + sizes = [16, 32, 64, 128, 256, 512, 1024] + for size in sizes: + create_icon(size, f"{sys.argv[1]}/icon_{size}x{size}.png") + if size <= 512: + create_icon(size * 2, f"{sys.argv[1]}/icon_{size}x{size}@2x.png") +EOF + + # 检查是否有 Python 和 PIL + if command -v python3 &> /dev/null && python3 -c "import PIL" 2>/dev/null; then + echo "✅ Using Python PIL to create icons" + python3 "$TEMP_DIR/create_icon.py" "$ICONSET_DIR" + else + echo "⚠️ Python PIL not available, creating simple icons with sips" + + # 创建基础图标 + BASE_SIZE=1024 + BASE_ICON="$TEMP_DIR/base_icon.png" + + # 使用 sips 创建基础图标 (需要一个现有的图像文件) + # 如果没有图像,我们创建一个简单的文本文件然后转换 + echo "Creating base icon with textutil and sips..." + + # 创建一个 RTF 文件 + cat > "$TEMP_DIR/icon.rtf" << 'EOF' +{\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} +\f0\fs200\qc\cf1 W} +EOF + + # 转换为图像 (这在 macOS 上应该可行) + if command -v textutil &> /dev/null; then + textutil -convert html "$TEMP_DIR/icon.rtf" -output "$TEMP_DIR/icon.html" + fi + + # 手动创建不同尺寸的图标 + sizes=(16 32 64 128 256 512 1024) + for size in "${sizes[@]}"; do + # 创建空白图像并着色 + sips -z $size $size /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns --out "$ICONSET_DIR/icon_${size}x${size}.png" 2>/dev/null || { + # 如果失败,复制系统默认图标 + cp /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns "$ICONSET_DIR/icon_${size}x${size}.png" 2>/dev/null || { + # 最后的后备方案:创建纯色文件 + printf "\x89PNG\r\n\x1a\n" > "$ICONSET_DIR/icon_${size}x${size}.png" + } + } + + # 创建 @2x 版本 + if [ $size -le 512 ]; then + cp "$ICONSET_DIR/icon_${size}x${size}.png" "$ICONSET_DIR/icon_${size}x${size}@2x.png" + fi + done + fi +fi + +# 确保所有必需的图标文件存在 +declare -a required_icons=( + "icon_16x16.png" + "icon_16x16@2x.png" + "icon_32x32.png" + "icon_32x32@2x.png" + "icon_128x128.png" + "icon_128x128@2x.png" + "icon_256x256.png" + "icon_256x256@2x.png" + "icon_512x512.png" + "icon_512x512@2x.png" +) + +echo "📋 Checking required icon files..." +missing_icons=false +for icon in "${required_icons[@]}"; do + if [ ! -f "$ICONSET_DIR/$icon" ]; then + echo "⚠️ Missing: $icon" + missing_icons=true + fi +done + +if [ "$missing_icons" = true ]; then + echo "🔧 Creating missing icons from system template..." + # 使用系统默认应用图标作为模板 + TEMPLATE_ICON="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns" + + for icon in "${required_icons[@]}"; do + if [ ! -f "$ICONSET_DIR/$icon" ]; then + # 从系统图标创建所需尺寸 + size=$(echo "$icon" | sed 's/icon_\([0-9]*\)x[0-9]*.*\.png/\1/') + sips -z $size $size "$TEMPLATE_ICON" --out "$ICONSET_DIR/$icon" 2>/dev/null || { + echo "⚠️ Could not create $icon, using placeholder" + touch "$ICONSET_DIR/$icon" + } + fi + done +fi + +# 创建 .icns 文件 +echo "🔨 Creating .icns file..." +if iconutil -c icns "$ICONSET_DIR" -o "$APP_ICON"; then + echo "✅ Icon created successfully: $APP_ICON" +else + echo "❌ Failed to create icon, using system default" + # 复制系统默认图标 + cp "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns" "$APP_ICON" 2>/dev/null || { + echo "⚠️ Could not copy system icon" + } +fi + +# 清理临时文件 +rm -rf "$TEMP_DIR" + +echo "🎉 Icon creation completed!" +echo "📁 Icon location: $APP_ICON" \ No newline at end of file diff --git a/scripts/launcher.sh b/scripts/launcher.sh new file mode 100755 index 0000000..b851fa0 --- /dev/null +++ b/scripts/launcher.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# Wormhole Client Launcher Script +# 用于在 macOS 应用程序包中启动客户端 + +set -e + +# 获取应用程序包路径 +APP_PATH="$(cd "$(dirname "$0")/.." && pwd)" +RESOURCES_PATH="$APP_PATH/Resources" +BINARY_PATH="$APP_PATH/MacOS/wormhole-client" +CONFIG_PATH="$RESOURCES_PATH/configs/client.yaml" + +# 检查二进制文件是否存在 +if [ ! -f "$BINARY_PATH" ]; then + echo "❌ Wormhole client binary not found at: $BINARY_PATH" + exit 1 +fi + +# 检查配置文件是否存在 +if [ ! -f "$CONFIG_PATH" ]; then + echo "❌ Configuration file not found at: $CONFIG_PATH" + echo "Using default configuration..." + CONFIG_PATH="" +fi + +# 设置工作目录为 Resources +cd "$RESOURCES_PATH" + +# 显示启动信息 +echo "🚀 Starting Wormhole SOCKS5 Client..." +echo "📁 App Path: $APP_PATH" +echo "📄 Config: $CONFIG_PATH" +echo "" + +# 检查命令行参数 +if [ $# -eq 0 ]; then + # 没有参数,显示选择菜单 + echo "请选择运行模式:" + echo "1) HTTP 代理模式 (推荐)" + echo "2) 全局代理模式 (需要管理员权限)" + echo "3) 显示版本信息" + echo "4) 退出" + echo "" + read -p "请输入选项 (1-4): " choice + + case $choice in + 1) + MODE="http" + ;; + 2) + echo "" + echo "⚠️ 全局代理模式需要管理员权限。" + echo "系统将提示您输入密码。" + echo "" + read -p "继续?(y/N): " confirm + if [[ $confirm =~ ^[Yy]$ ]]; then + MODE="global" + NEED_SUDO=true + else + echo "已取消" + exit 0 + fi + ;; + 3) + exec "$BINARY_PATH" -version + ;; + 4) + echo "再见!" + exit 0 + ;; + *) + echo "❌ 无效选项" + exit 1 + ;; + esac +else + # 有参数,直接传递给二进制文件 + if [ -n "$CONFIG_PATH" ]; then + exec "$BINARY_PATH" -config "$CONFIG_PATH" "$@" + else + exec "$BINARY_PATH" "$@" + fi +fi + +# 启动应用程序 +echo "🔧 启动模式: $MODE" +echo "" + +if [ "$NEED_SUDO" = true ]; then + echo "🔒 请输入管理员密码以启动全局代理模式:" + if [ -n "$CONFIG_PATH" ]; then + sudo "$BINARY_PATH" -config "$CONFIG_PATH" -mode "$MODE" + else + sudo "$BINARY_PATH" -mode "$MODE" + fi +else + if [ -n "$CONFIG_PATH" ]; then + exec "$BINARY_PATH" -config "$CONFIG_PATH" -mode "$MODE" + else + exec "$BINARY_PATH" -mode "$MODE" + fi +fi \ No newline at end of file