Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
ae0ab09b48
|
23
.golangci.yml
Normal file
23
.golangci.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
version: "2"
|
||||
linters:
|
||||
default: standard
|
||||
enable:
|
||||
- staticcheck
|
||||
- gosec
|
||||
exclusions:
|
||||
rules:
|
||||
- linters:
|
||||
- gosec
|
||||
text: "G304:"
|
||||
- linters:
|
||||
- errcheck
|
||||
text: "is not checked"
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gci
|
||||
- golines
|
||||
output:
|
||||
path-mode: abs
|
||||
@@ -3,12 +3,12 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"mesh-drop/internal/security"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"mesh-drop/internal/security"
|
||||
)
|
||||
|
||||
// WindowState 定义窗口状态
|
||||
@@ -66,7 +66,7 @@ func GetUserHomeDir() string {
|
||||
// New 读取配置
|
||||
func Load(defaultState WindowState) *Config {
|
||||
configDir := GetConfigDir()
|
||||
_ = os.MkdirAll(configDir, 0755)
|
||||
_ = os.MkdirAll(configDir, 0o750)
|
||||
configFile := filepath.Join(configDir, "config.json")
|
||||
|
||||
// 设置默认值
|
||||
@@ -88,7 +88,9 @@ func Load(defaultState WindowState) *Config {
|
||||
TrustedPeer: make(map[string]string),
|
||||
}
|
||||
|
||||
fileBytes, err := os.ReadFile(configFile)
|
||||
fileBytes, err := os.ReadFile(
|
||||
configFile,
|
||||
)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
slog.Error("Failed to read config file", "error", err)
|
||||
@@ -107,7 +109,7 @@ func Load(defaultState WindowState) *Config {
|
||||
}
|
||||
|
||||
// 确保默认保存路径存在
|
||||
err = os.MkdirAll(defaultSavePath, 0755)
|
||||
err = os.MkdirAll(defaultSavePath, 0o750)
|
||||
if err != nil {
|
||||
slog.Error("Failed to create default save path", "path", defaultSavePath, "error", err)
|
||||
}
|
||||
@@ -145,7 +147,7 @@ func (c *Config) Save() error {
|
||||
|
||||
func (c *Config) save() error {
|
||||
dir := filepath.Dir(c.configPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
if err := os.MkdirAll(dir, 0o750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -156,7 +158,7 @@ func (c *Config) save() error {
|
||||
|
||||
// 设置配置文件权限为 0600 (仅所有者读写)
|
||||
if c.configPath != "" {
|
||||
if err := os.WriteFile(c.configPath, jsonData, 0600); err != nil {
|
||||
if err := os.WriteFile(c.configPath, jsonData, 0o600); err != nil {
|
||||
slog.Warn("Failed to write config file", "error", err)
|
||||
return err
|
||||
}
|
||||
@@ -181,7 +183,7 @@ func (c *Config) update(fn func()) {
|
||||
func (c *Config) SetSavePath(savePath string) {
|
||||
c.update(func() {
|
||||
c.data.SavePath = savePath
|
||||
_ = os.MkdirAll(savePath, 0755)
|
||||
_ = os.MkdirAll(savePath, 0o750)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/security"
|
||||
"net"
|
||||
"runtime"
|
||||
"sort"
|
||||
@@ -13,6 +11,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/security"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -112,7 +112,13 @@ func (s *Service) GetLocalIPInSameSubnet(receiverIP string) (string, bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
slog.Error("Failed to get local IP in same subnet", "receiverIP", receiverIP, "component", "discovery")
|
||||
slog.Error(
|
||||
"Failed to get local IP in same subnet",
|
||||
"receiverIP",
|
||||
receiverIP,
|
||||
"component",
|
||||
"discovery",
|
||||
)
|
||||
return "", false
|
||||
}
|
||||
|
||||
@@ -222,7 +228,13 @@ func (s *Service) startListening() {
|
||||
sigData := packet.SignPayload()
|
||||
valid, err := security.Verify(packet.PublicKey, sigData, sig)
|
||||
if err != nil || !valid {
|
||||
slog.Warn("Received invalid discovery packet signature", "id", packet.ID, "ip", remoteAddr.IP.String())
|
||||
slog.Warn(
|
||||
"Received invalid discovery packet signature",
|
||||
"id",
|
||||
packet.ID,
|
||||
"ip",
|
||||
remoteAddr.IP.String(),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -231,7 +243,15 @@ func (s *Service) startListening() {
|
||||
trustedKeys := s.config.GetTrusted()
|
||||
if knownKey, ok := trustedKeys[packet.ID]; ok {
|
||||
if knownKey != packet.PublicKey {
|
||||
slog.Warn("SECURITY ALERT: Peer ID mismatch with known public key (Spoofing attempt?)", "id", packet.ID, "known_key", knownKey, "received_key", packet.PublicKey)
|
||||
slog.Warn(
|
||||
"SECURITY ALERT: Peer ID mismatch with known public key (Spoofing attempt?)",
|
||||
"id",
|
||||
packet.ID,
|
||||
"known_key",
|
||||
knownKey,
|
||||
"received_key",
|
||||
packet.PublicKey,
|
||||
)
|
||||
trustMismatch = true
|
||||
// 当发现 ID 欺骗时,不更新 peer,而是标记为 trustMismatch
|
||||
// 用户可以手动重新添加信任
|
||||
|
||||
@@ -52,7 +52,13 @@ func generateSelfSignedCert(certPath, keyPath string) error {
|
||||
// 在实际的动态环境中,我们可能希望添加所有当前接口的 IP 地址
|
||||
// 实际上,在客户端跳过 IP 验证对于本地 P2P 来说是很常见的。
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
derBytes, err := x509.CreateCertificate(
|
||||
rand.Reader,
|
||||
&template,
|
||||
&template,
|
||||
&priv.PublicKey,
|
||||
priv,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -73,7 +79,10 @@ func generateSelfSignedCert(certPath, keyPath string) error {
|
||||
return err
|
||||
}
|
||||
defer keyOut.Close()
|
||||
if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
|
||||
if err := pem.Encode(
|
||||
keyOut,
|
||||
&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"math"
|
||||
"mesh-drop/internal/discovery"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"mesh-drop/internal/discovery"
|
||||
)
|
||||
|
||||
func (s *Service) SendFiles(target *discovery.Peer, targetIP string, filePaths []string) {
|
||||
@@ -32,7 +32,15 @@ func (s *Service) SendFile(target *discovery.Peer, targetIP string, filePath str
|
||||
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
slog.Error("Failed to open file", "path", filePath, "error", err, "component", "transfer-client")
|
||||
slog.Error(
|
||||
"Failed to open file",
|
||||
"path",
|
||||
filePath,
|
||||
"error",
|
||||
err,
|
||||
"component",
|
||||
"transfer-client",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,7 +109,15 @@ func (s *Service) SendFolder(target *discovery.Peer, targetIP string, folderPath
|
||||
|
||||
size, err := calculateTarSize(ctx, folderPath)
|
||||
if err != nil {
|
||||
slog.Error("Failed to calculate folder size", "path", folderPath, "error", err, "component", "transfer-client")
|
||||
slog.Error(
|
||||
"Failed to calculate folder size",
|
||||
"path",
|
||||
folderPath,
|
||||
"error",
|
||||
err,
|
||||
"component",
|
||||
"transfer-client",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,7 +153,13 @@ func (s *Service) SendFolder(target *discovery.Peer, targetIP string, folderPath
|
||||
go func(ctx context.Context) {
|
||||
defer w.Close()
|
||||
if err := streamFolderToTar(ctx, w, folderPath); err != nil {
|
||||
slog.Error("Failed to stream folder to tar", "error", err, "component", "transfer-client")
|
||||
slog.Error(
|
||||
"Failed to stream folder to tar",
|
||||
"error",
|
||||
err,
|
||||
"component",
|
||||
"transfer-client",
|
||||
)
|
||||
w.CloseWithError(err)
|
||||
}
|
||||
}(ctx)
|
||||
@@ -199,7 +221,12 @@ func (s *Service) SendText(target *discovery.Peer, targetIP string, text string)
|
||||
}
|
||||
|
||||
// ask 向接收端发送传输请求
|
||||
func (s *Service) ask(ctx context.Context, target *discovery.Peer, targetIP string, task *Transfer) (TransferAskResponse, error) {
|
||||
func (s *Service) ask(
|
||||
ctx context.Context,
|
||||
target *discovery.Peer,
|
||||
targetIP string,
|
||||
task *Transfer,
|
||||
) (TransferAskResponse, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return TransferAskResponse{}, err
|
||||
}
|
||||
@@ -232,7 +259,14 @@ func (s *Service) ask(ctx context.Context, target *discovery.Peer, targetIP stri
|
||||
}
|
||||
|
||||
// processTransfer 传输数据
|
||||
func (s *Service) processTransfer(ctx context.Context, askResp TransferAskResponse, target *discovery.Peer, targetIP string, task *Transfer, payload io.Reader) {
|
||||
func (s *Service) processTransfer(
|
||||
ctx context.Context,
|
||||
askResp TransferAskResponse,
|
||||
target *discovery.Peer,
|
||||
targetIP string,
|
||||
task *Transfer,
|
||||
payload io.Reader,
|
||||
) {
|
||||
defer func() {
|
||||
s.NotifyTransferListUpdate()
|
||||
}()
|
||||
@@ -240,7 +274,9 @@ func (s *Service) processTransfer(ctx context.Context, askResp TransferAskRespon
|
||||
if err := ctx.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
uploadUrl, _ := url.Parse(fmt.Sprintf("https://%s:%d/transfer/upload/%s", targetIP, target.Port, task.ID))
|
||||
uploadUrl, _ := url.Parse(
|
||||
fmt.Sprintf("https://%s:%d/transfer/upload/%s", targetIP, target.Port, task.ID),
|
||||
)
|
||||
query := uploadUrl.Query()
|
||||
query.Add("token", askResp.Token)
|
||||
uploadUrl.RawQuery = query.Encode()
|
||||
@@ -273,7 +309,15 @@ func (s *Service) processTransfer(ctx context.Context, askResp TransferAskRespon
|
||||
} else {
|
||||
task.Status = TransferStatusError
|
||||
task.ErrorMsg = fmt.Sprintf("Failed to upload file: %v", err)
|
||||
slog.Error("Failed to upload file", "url", uploadUrl.String(), "error", err, "component", "transfer-client")
|
||||
slog.Error(
|
||||
"Failed to upload file",
|
||||
"url",
|
||||
uploadUrl.String(),
|
||||
"error",
|
||||
err,
|
||||
"component",
|
||||
"transfer-client",
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -384,7 +428,15 @@ func streamFolderToTar(ctx context.Context, w io.Writer, srcPath string) error {
|
||||
if relPath == "." {
|
||||
return nil
|
||||
}
|
||||
slog.Debug("Processing file", "path", path, "relPath", relPath, "component", "transfer-client")
|
||||
slog.Debug(
|
||||
"Processing file",
|
||||
"path",
|
||||
path,
|
||||
"relPath",
|
||||
relPath,
|
||||
"component",
|
||||
"transfer-client",
|
||||
)
|
||||
|
||||
header, err := tar.FileInfoHeader(info, "")
|
||||
if err != nil {
|
||||
|
||||
@@ -3,9 +3,10 @@ package transfer
|
||||
import (
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"mesh-drop/internal/config"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"mesh-drop/internal/config"
|
||||
)
|
||||
|
||||
func (s *Service) SaveHistory() {
|
||||
@@ -24,7 +25,7 @@ func (s *Service) SaveHistory() {
|
||||
}
|
||||
|
||||
// 写入临时文件
|
||||
if err := os.WriteFile(tempPath, historyJson, 0644); err != nil {
|
||||
if err := os.WriteFile(tempPath, historyJson, 0o600); err != nil {
|
||||
slog.Error("Failed to write temp history file", "error", err, "component", "transfer")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package transfer
|
||||
|
||||
import (
|
||||
"mesh-drop/internal/discovery"
|
||||
"time"
|
||||
|
||||
"mesh-drop/internal/discovery"
|
||||
)
|
||||
|
||||
type TransferStatus string
|
||||
|
||||
@@ -49,7 +49,8 @@ func (s *Service) handleAsk(c *gin.Context) {
|
||||
task.Sender.TrustMismatch = peer.TrustMismatch
|
||||
}
|
||||
|
||||
if s.config.GetAutoAccept() || (s.config.IsTrusted(task.Sender.ID) && !task.Sender.TrustMismatch) {
|
||||
if s.config.GetAutoAccept() ||
|
||||
(s.config.IsTrusted(task.Sender.ID) && !task.Sender.TrustMismatch) {
|
||||
task.DecisionChan <- Decision{
|
||||
ID: task.ID,
|
||||
Accepted: true,
|
||||
@@ -179,7 +180,15 @@ func (s *Service) handleUpload(c *gin.Context) {
|
||||
_, err := os.Stat(destPath)
|
||||
counter := 1
|
||||
for err == nil {
|
||||
destPath = filepath.Join(savePath, fmt.Sprintf("%s (%d)%s", strings.TrimSuffix(task.FileName, filepath.Ext(task.FileName)), counter, filepath.Ext(task.FileName)))
|
||||
destPath = filepath.Join(
|
||||
savePath,
|
||||
fmt.Sprintf(
|
||||
"%s (%d)%s",
|
||||
strings.TrimSuffix(task.FileName, filepath.Ext(task.FileName)),
|
||||
counter,
|
||||
filepath.Ext(task.FileName),
|
||||
),
|
||||
)
|
||||
counter++
|
||||
_, err = os.Stat(destPath)
|
||||
}
|
||||
@@ -227,7 +236,13 @@ func (s *Service) receive(c *gin.Context, task *Transfer, writer Writer, ctxRead
|
||||
if err != nil {
|
||||
// 发送端断线,任务取消
|
||||
if c.Request.Context().Err() != nil {
|
||||
slog.Info("Sender canceled transfer (Network/Context disconnected)", "id", task.ID, "raw_err", err)
|
||||
slog.Info(
|
||||
"Sender canceled transfer (Network/Context disconnected)",
|
||||
"id",
|
||||
task.ID,
|
||||
"raw_err",
|
||||
err,
|
||||
)
|
||||
task.ErrorMsg = "Sender disconnected"
|
||||
task.Status = TransferStatusCanceled
|
||||
return
|
||||
@@ -273,7 +288,12 @@ func (s *Service) receive(c *gin.Context, task *Transfer, writer Writer, ctxRead
|
||||
task.Status = TransferStatusCompleted
|
||||
}
|
||||
|
||||
func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer, ctxReader io.Reader) {
|
||||
func (s *Service) receiveFolder(
|
||||
c *gin.Context,
|
||||
savePath string,
|
||||
task *Transfer,
|
||||
ctxReader io.Reader,
|
||||
) {
|
||||
defer s.NotifyTransferListUpdate()
|
||||
|
||||
// 创建根目录
|
||||
@@ -286,7 +306,7 @@ func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer,
|
||||
counter++
|
||||
_, err = os.Stat(destPath)
|
||||
}
|
||||
if err := os.MkdirAll(destPath, 0755); err != nil {
|
||||
if err := os.MkdirAll(destPath, 0o750); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, TransferUploadResponse{
|
||||
ID: task.ID,
|
||||
Message: "Receiver failed to create folder",
|
||||
@@ -318,7 +338,13 @@ func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer,
|
||||
return false
|
||||
}
|
||||
if c.Request.Context().Err() != nil {
|
||||
slog.Info("Transfer canceled by sender (Network disconnect)", "id", task.ID, "stage", stage)
|
||||
slog.Info(
|
||||
"Transfer canceled by sender (Network disconnect)",
|
||||
"id",
|
||||
task.ID,
|
||||
"stage",
|
||||
stage,
|
||||
)
|
||||
task.Status = TransferStatusCanceled
|
||||
task.ErrorMsg = "Sender disconnected"
|
||||
// 发送端已断开,无需也不应再发送 c.JSON
|
||||
@@ -350,6 +376,14 @@ func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer,
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取绝对路径以防止 Zip Slip (G305)
|
||||
// 必须先转换成绝对路径再判断
|
||||
absDestPath, err := filepath.Abs(destPath)
|
||||
if err != nil {
|
||||
handleError(err, "resolve_abs_path")
|
||||
return
|
||||
}
|
||||
|
||||
tr := tar.NewReader(reader)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
@@ -360,32 +394,52 @@ func (s *Service) receiveFolder(c *gin.Context, savePath string, task *Transfer,
|
||||
return
|
||||
}
|
||||
|
||||
target := filepath.Join(destPath, header.Name)
|
||||
// 确保路径没有越界
|
||||
if !strings.HasPrefix(target, filepath.Clean(destPath)+string(os.PathSeparator)) {
|
||||
// 非法路径
|
||||
target := filepath.Join(destPath, filepath.Clean(header.Name))
|
||||
absTarget, err := filepath.Abs(target)
|
||||
if err != nil {
|
||||
slog.Error("Failed to resolve absolute path", "path", target, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 确保路径在目标目录内
|
||||
if !strings.HasPrefix(absTarget, absDestPath+string(os.PathSeparator)) {
|
||||
slog.Warn(
|
||||
"Zip Slip attempt detected",
|
||||
"header_name",
|
||||
header.Name,
|
||||
"resolved_path",
|
||||
absTarget,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// 使用安全的绝对路径
|
||||
target = absTarget
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
if err := os.MkdirAll(target, 0o750); err != nil {
|
||||
slog.Error("Failed to create dir", "path", target, "error", err)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
||||
f, err := os.OpenFile(
|
||||
target,
|
||||
os.O_CREATE|os.O_RDWR,
|
||||
os.FileMode(header.Mode),
|
||||
) //nolint:gosec
|
||||
if err != nil {
|
||||
slog.Error("Failed to create file", "path", target, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// nolint: gosec
|
||||
if _, err := io.Copy(f, tr); err != nil {
|
||||
f.Close()
|
||||
_ = f.Close()
|
||||
if handleError(err, "write_file_content") {
|
||||
return
|
||||
}
|
||||
}
|
||||
f.Close()
|
||||
_ = f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/discovery"
|
||||
"mesh-drop/internal/security"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -16,6 +13,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/notifications"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/discovery"
|
||||
"mesh-drop/internal/security"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
@@ -37,12 +37,18 @@ type Service struct {
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func NewService(config *config.Config, app *application.App, notifier *notifications.NotificationService, port int, discoveryService *discovery.Service) *Service {
|
||||
func NewService(
|
||||
config *config.Config,
|
||||
app *application.App,
|
||||
notifier *notifications.NotificationService,
|
||||
port int,
|
||||
discoveryService *discovery.Service,
|
||||
) *Service {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
// 配置自定义 HTTP 客户端以跳过自签名证书验证
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
Transport: tr,
|
||||
@@ -95,7 +101,7 @@ func (s *Service) GetTransferSyncMap() *sync.Map {
|
||||
}
|
||||
|
||||
func (s *Service) GetTransferList() []*Transfer {
|
||||
var requests []*Transfer = make([]*Transfer, 0)
|
||||
requests := make([]*Transfer, 0)
|
||||
s.transfers.Range(func(key, value any) bool {
|
||||
transfer := value.(*Transfer)
|
||||
requests = append(requests, transfer)
|
||||
|
||||
25
main.go
25
main.go
@@ -3,15 +3,15 @@ package main
|
||||
import (
|
||||
"embed"
|
||||
"log/slog"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/discovery"
|
||||
"mesh-drop/internal/transfer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/pkg/events"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/notifications"
|
||||
"mesh-drop/internal/config"
|
||||
"mesh-drop/internal/discovery"
|
||||
"mesh-drop/internal/transfer"
|
||||
)
|
||||
|
||||
//go:embed all:frontend/dist
|
||||
@@ -67,7 +67,17 @@ func NewApp() *App {
|
||||
if screen != nil {
|
||||
defaultWidth = int(float64(screen.Size.Width) * 0.8)
|
||||
defaultHeight = int(float64(screen.Size.Height) * 0.8)
|
||||
slog.Info("Primary screen found", "width", screen.Size.Width, "height", screen.Size.Height, "defaultWidth", defaultWidth, "defaultHeight", defaultHeight)
|
||||
slog.Info(
|
||||
"Primary screen found",
|
||||
"width",
|
||||
screen.Size.Width,
|
||||
"height",
|
||||
screen.Size.Height,
|
||||
"defaultWidth",
|
||||
defaultWidth,
|
||||
"defaultHeight",
|
||||
defaultHeight,
|
||||
)
|
||||
} else {
|
||||
slog.Info("No primary screen found, using defaults")
|
||||
}
|
||||
@@ -137,7 +147,9 @@ func (a *App) registerCustomEvents() {
|
||||
|
||||
func (a *App) setupEvents() {
|
||||
// 窗口文件拖拽事件
|
||||
a.mainWindows.OnWindowEvent(events.Common.WindowFilesDropped, func(event *application.WindowEvent) {
|
||||
a.mainWindows.OnWindowEvent(
|
||||
events.Common.WindowFilesDropped,
|
||||
func(event *application.WindowEvent) {
|
||||
files := make([]File, 0)
|
||||
for _, file := range event.Context().DroppedFiles() {
|
||||
files = append(files, File{
|
||||
@@ -150,7 +162,8 @@ func (a *App) setupEvents() {
|
||||
Files: files,
|
||||
Target: details.ElementID,
|
||||
})
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
// 窗口关闭事件
|
||||
a.mainWindows.OnWindowEvent(events.Common.WindowClosing, func(event *application.WindowEvent) {
|
||||
|
||||
Reference in New Issue
Block a user