@yufengtadian/freedom-cli 1.12.17 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/build.js +74 -9
- package/lib/cli.js +61 -3
- package/lib/init.js +9 -1
- package/lib/security.js +2 -2
- package/lib/utils.js +5 -2
- package/lib/verify.js +236 -0
- package/package.json +43 -39
- package/shell/darwin-arm64/freedom-shell +0 -0
- package/shell/linux-x64/freedom-shell +0 -0
- package/shell/win-x64/freedom-shell.exe +0 -0
- package/templates/go/go.mod +1 -7
- package/templates/go/go.sum +2 -2
- package/templates/go/main.go +22 -8
- package/templates/go/pkg/freedom/anti_debug_other.go +2 -3
- package/templates/go/pkg/freedom/anti_debug_windows.go +10 -12
- package/templates/go/pkg/freedom/assets/{index.html → default.html} +1 -1
- package/templates/go/pkg/freedom/assets/freedom.js +219 -21
- package/templates/go/pkg/freedom/assets_embed.go +11 -13
- package/templates/go/pkg/freedom/authenticode_other.go +11 -0
- package/templates/go/pkg/freedom/authenticode_windows.go +87 -0
- package/templates/go/pkg/freedom/backend_proc.go +295 -51
- package/templates/go/pkg/freedom/bridge.go +13 -2
- package/templates/go/pkg/freedom/capability.go +77 -0
- package/templates/go/pkg/freedom/center_other.go +3 -0
- package/templates/go/pkg/freedom/center_windows.go +64 -36
- package/templates/go/pkg/freedom/dispatch.go +60 -0
- package/templates/go/pkg/freedom/events_windows.go +319 -0
- package/templates/go/pkg/freedom/freedom.go +242 -92
- package/templates/go/pkg/freedom/msgwindow_windows.go +257 -0
- package/templates/go/pkg/freedom/osver_other.go +15 -0
- package/templates/go/pkg/freedom/osver_windows.go +121 -0
- package/templates/go/pkg/freedom/proc_hide_windows.go +2 -2
- package/templates/go/pkg/freedom/{configfile.go → resources.go} +56 -32
- package/templates/go/pkg/freedom/security.go +19 -12
- package/templates/go/pkg/freedom/singleinstance_other.go +10 -0
- package/templates/go/pkg/freedom/singleinstance_windows.go +145 -0
- package/templates/go/pkg/freedom/spawn_other.go +11 -0
- package/templates/go/pkg/freedom/spawn_windows.go +23 -0
- package/templates/go/pkg/freedom/store.go +458 -0
- package/templates/go/pkg/freedom/syscap_linux.go +278 -0
- package/templates/go/pkg/freedom/syscap_other.go +22 -0
- package/templates/go/pkg/freedom/syscap_windows.go +845 -0
- package/templates/go/pkg/freedom/sysint_common.go +70 -0
- package/templates/go/pkg/freedom/sysint_windows.go +426 -0
- package/templates/go/pkg/freedom/tray_common.go +12 -0
- package/templates/go/pkg/freedom/tray_linux.go +302 -0
- package/templates/go/pkg/freedom/tray_other.go +10 -0
- package/templates/go/pkg/freedom/tray_windows.go +536 -0
- package/templates/go/pkg/freedom/updater.go +372 -0
- package/templates/go/pkg/freedom/window_mgr.go +385 -0
- package/templates/go/pkg/freedom/window_other.go +32 -66
- package/templates/go/pkg/freedom/window_windows.go +406 -251
- package/templates/project-minimal/freedom.config.js +58 -0
- package/templates/project-minimal/index.html +41 -0
- package/templates/project-minimal/package.json +14 -0
- package/templates/project-minimal/src/main.js +19 -0
- package/templates/project-minimal/vite.config.js +18 -0
- package/templates/go/gen_config.go +0 -22
- package/templates/go/pkg/freedom/security_test.go +0 -153
- package/templates/go/webview_go/.github/workflows/ci.yaml +0 -62
- package/templates/go/webview_go/CHANGELOG.md +0 -15
- package/templates/go/webview_go/LICENSE +0 -22
- package/templates/go/webview_go/README.md +0 -50
- package/templates/go/webview_go/examples/basic/main.go +0 -12
- package/templates/go/webview_go/examples/bind/main.go +0 -38
- package/templates/go/webview_go/glue.c +0 -36
- package/templates/go/webview_go/go.mod +0 -3
- package/templates/go/webview_go/go.sum +0 -0
- package/templates/go/webview_go/libs/mswebview2/LICENSE +0 -27
- package/templates/go/webview_go/libs/mswebview2/include/WebView2.h +0 -23568
- package/templates/go/webview_go/libs/mswebview2/include/vendor.go +0 -2
- package/templates/go/webview_go/libs/mswebview2/vendor.go +0 -2
- package/templates/go/webview_go/libs/mswebview2/version.txt +0 -1
- package/templates/go/webview_go/libs/webview/LICENSE +0 -22
- package/templates/go/webview_go/libs/webview/include/vendor.go +0 -2
- package/templates/go/webview_go/libs/webview/include/webview.h +0 -3871
- package/templates/go/webview_go/libs/webview/vendor.go +0 -2
- package/templates/go/webview_go/libs/webview/version.txt +0 -1
- package/templates/go/webview_go/webview.cc +0 -1
- package/templates/go/webview_go/webview.go +0 -481
- package/templates/go/webview_go/webview_test.go +0 -50
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
//go:build linux
|
|
2
|
+
|
|
3
|
+
package freedom
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
#cgo pkg-config: gtk+-3.0
|
|
7
|
+
#cgo CFLAGS: -Wno-deprecated-declarations
|
|
8
|
+
#include <gtk/gtk.h>
|
|
9
|
+
|
|
10
|
+
extern void goTrayClick(void);
|
|
11
|
+
extern void goTrayMenuItemActivate(int idx);
|
|
12
|
+
|
|
13
|
+
// GtkStatusIcon 自 GTK3.14 起标记 deprecated,但 legacy tray 协议在 KDE/XFCE/
|
|
14
|
+
// WSLg 仍广泛可用;AppIndicator(GDBus) 适配在未来自成一档。
|
|
15
|
+
static int ensureGtk(void) { return gtk_init_check(NULL, NULL) ? 1 : 0; }
|
|
16
|
+
|
|
17
|
+
static void onTrayActivate(GtkStatusIcon *icon, gpointer data) {
|
|
18
|
+
(void)icon; (void)data;
|
|
19
|
+
goTrayClick();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 右键:弹出前端注册的菜单(popup-menu 信号),返回 TRUE 抑制默认行为。
|
|
23
|
+
static gboolean onTrayPopupMenu(GtkStatusIcon *icon, guint button, guint activate_time, gpointer data) {
|
|
24
|
+
(void)button; (void)activate_time; (void)data;
|
|
25
|
+
GtkWidget *menu = (GtkWidget*) g_object_get_data(G_OBJECT(icon), "freedom-menu");
|
|
26
|
+
if (menu != NULL) gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
|
|
27
|
+
return TRUE;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static void onMenuItemClick(GtkMenuItem *item, gpointer data) {
|
|
31
|
+
(void)item;
|
|
32
|
+
goTrayMenuItemActivate(GPOINTER_TO_INT(data));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static GtkStatusIcon* trayNewFromPng(const guint8 *png, gsize len) {
|
|
36
|
+
GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
|
|
37
|
+
gboolean ok = gdk_pixbuf_loader_write(loader, png, len, NULL);
|
|
38
|
+
ok = ok && gdk_pixbuf_loader_close(loader, NULL);
|
|
39
|
+
GdkPixbuf *pb = ok ? gdk_pixbuf_loader_get_pixbuf(loader) : NULL;
|
|
40
|
+
GtkStatusIcon *icon = pb ? gtk_status_icon_new_from_pixbuf(pb) : NULL;
|
|
41
|
+
g_object_unref(loader);
|
|
42
|
+
if (icon == NULL) return NULL;
|
|
43
|
+
g_signal_connect(icon, "activate", G_CALLBACK(onTrayActivate), NULL);
|
|
44
|
+
g_signal_connect(icon, "popup-menu", G_CALLBACK(onTrayPopupMenu), NULL);
|
|
45
|
+
gtk_status_icon_set_visible(icon, TRUE);
|
|
46
|
+
return icon;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static GtkStatusIcon* trayNewNamed(const char *name) {
|
|
50
|
+
GtkStatusIcon *icon = gtk_status_icon_new_from_icon_name(name);
|
|
51
|
+
g_signal_connect(icon, "activate", G_CALLBACK(onTrayActivate), NULL);
|
|
52
|
+
g_signal_connect(icon, "popup-menu", G_CALLBACK(onTrayPopupMenu), NULL);
|
|
53
|
+
gtk_status_icon_set_visible(icon, TRUE);
|
|
54
|
+
return icon;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static void traySetTooltip(GtkStatusIcon *icon, const char *tip) {
|
|
58
|
+
gtk_status_icon_set_tooltip_text(icon, tip);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static void trayDestroy(GtkStatusIcon *icon) {
|
|
62
|
+
gtk_status_icon_set_visible(icon, FALSE);
|
|
63
|
+
g_object_unref(icon);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 菜单所有权:attach 时 ref_sink + set_data_full,重复 attach 自动释放旧菜单。
|
|
67
|
+
static void trayAttachMenu(GtkStatusIcon *icon, GtkWidget *menu) {
|
|
68
|
+
g_object_ref_sink(menu);
|
|
69
|
+
g_object_set_data_full(G_OBJECT(icon), "freedom-menu", menu, (GDestroyNotify) g_object_unref);
|
|
70
|
+
gtk_widget_show_all(menu);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static GtkWidget* menuNew(void) { return gtk_menu_new(); }
|
|
74
|
+
|
|
75
|
+
static GtkWidget* menuSubmenu(GtkWidget *parent, const char *label) {
|
|
76
|
+
GtkWidget *item = gtk_menu_item_new_with_label(label);
|
|
77
|
+
GtkWidget *sub = gtk_menu_new();
|
|
78
|
+
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
|
|
79
|
+
gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
|
|
80
|
+
return sub;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static void menuAppendItem(GtkWidget *menu, const char *label, int idx, gboolean sensitive) {
|
|
84
|
+
GtkWidget *item = gtk_menu_item_new_with_label(label);
|
|
85
|
+
gtk_widget_set_sensitive(item, sensitive);
|
|
86
|
+
g_signal_connect(item, "activate", G_CALLBACK(onMenuItemClick), GINT_TO_POINTER(idx));
|
|
87
|
+
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static void menuAppendCheck(GtkWidget *menu, const char *label, int idx, gboolean checked, gboolean sensitive) {
|
|
91
|
+
GtkWidget *item = gtk_check_menu_item_new_with_label(label);
|
|
92
|
+
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), checked);
|
|
93
|
+
gtk_widget_set_sensitive(item, sensitive);
|
|
94
|
+
g_signal_connect(item, "activate", G_CALLBACK(onMenuItemClick), GINT_TO_POINTER(idx));
|
|
95
|
+
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static void menuAppendSeparator(GtkWidget *menu) {
|
|
99
|
+
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
|
|
100
|
+
}
|
|
101
|
+
*/
|
|
102
|
+
import "C"
|
|
103
|
+
|
|
104
|
+
import (
|
|
105
|
+
"encoding/json"
|
|
106
|
+
"fmt"
|
|
107
|
+
"sync"
|
|
108
|
+
"unsafe"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
// M4 Linux 托盘(GtkStatusIcon,cgo):与 Windows 侧 trayCall 同一前端契约
|
|
112
|
+
// (tray.create/destroy/tooltip/menu;事件 tray:click / tray:menu({id}))。
|
|
113
|
+
// 限制:GtkStatusIcon 无双击信号(tray:double-click 不触发);menu.set(主窗口
|
|
114
|
+
// 原生菜单栏)与 GDBus StatusNotifierItem 适配未实装,托盘图标走 legacy
|
|
115
|
+
// system tray 协议(KDE/xfce/wmctrl 系支持;GNOME 需 AppIndicator 扩展)。
|
|
116
|
+
// GTK 调用须发生在 main线程:__freedom_tray 桥回调经 WebKit 消息处理器在
|
|
117
|
+
// GTK main loop 线程执行,天然满足;单测须先 gtk_init_check 且有 DISPLAY。
|
|
118
|
+
|
|
119
|
+
type linuxTrayState struct {
|
|
120
|
+
mu sync.Mutex
|
|
121
|
+
icon *C.GtkStatusIcon
|
|
122
|
+
items map[int32]string // 菜单条目序号 → 前端 id
|
|
123
|
+
emit func(event string, data interface{})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
var linuxTray = &linuxTrayState{items: map[int32]string{}}
|
|
127
|
+
|
|
128
|
+
//export goTrayClick
|
|
129
|
+
func goTrayClick() {
|
|
130
|
+
linuxTray.mu.Lock()
|
|
131
|
+
emit := linuxTray.emit
|
|
132
|
+
linuxTray.mu.Unlock()
|
|
133
|
+
if emit != nil {
|
|
134
|
+
emit("tray:click", map[string]interface{}{"button": "left"})
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//export goTrayMenuItemActivate
|
|
139
|
+
func goTrayMenuItemActivate(idx C.int) {
|
|
140
|
+
linuxTray.mu.Lock()
|
|
141
|
+
id := linuxTray.items[int32(idx)]
|
|
142
|
+
emit := linuxTray.emit
|
|
143
|
+
linuxTray.mu.Unlock()
|
|
144
|
+
if emit != nil {
|
|
145
|
+
emit("tray:menu", map[string]interface{}{"id": id})
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// trayCall 处理前端 __freedom_tray 请求(Linux 实现,方法面与 Windows 对齐)。
|
|
150
|
+
func (a *App) trayCall(method string, paramsJSON string) (result interface{}, err error) {
|
|
151
|
+
defer func() {
|
|
152
|
+
if r := recover(); r != nil {
|
|
153
|
+
result = nil
|
|
154
|
+
err = fmt.Errorf("freedom: tray method %q panicked: %v", method, r)
|
|
155
|
+
}
|
|
156
|
+
}()
|
|
157
|
+
|
|
158
|
+
var args map[string]json.RawMessage
|
|
159
|
+
if len(paramsJSON) > 0 && paramsJSON != "null" {
|
|
160
|
+
if err := json.Unmarshal([]byte(paramsJSON), &args); err != nil {
|
|
161
|
+
return nil, fmt.Errorf("freedom: tray method %q: invalid args: %w", method, err)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
argStr := func(k string) string {
|
|
165
|
+
if v, ok := args[k]; ok {
|
|
166
|
+
var s string
|
|
167
|
+
if json.Unmarshal(v, &s) == nil {
|
|
168
|
+
return s
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return ""
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
switch method {
|
|
175
|
+
case "tray.create":
|
|
176
|
+
return nil, linuxTrayCreate(a, argStr("icon"), argStr("tooltip"))
|
|
177
|
+
case "tray.destroy":
|
|
178
|
+
linuxTrayDestroy()
|
|
179
|
+
return nil, nil
|
|
180
|
+
case "tray.tooltip":
|
|
181
|
+
linuxTray.mu.Lock()
|
|
182
|
+
icon := linuxTray.icon
|
|
183
|
+
linuxTray.mu.Unlock()
|
|
184
|
+
if icon == nil {
|
|
185
|
+
return nil, fmt.Errorf("tray: 托盘未创建")
|
|
186
|
+
}
|
|
187
|
+
tip := C.CString(argStr("tooltip"))
|
|
188
|
+
C.traySetTooltip(icon, tip)
|
|
189
|
+
C.free(unsafe.Pointer(tip))
|
|
190
|
+
return nil, nil
|
|
191
|
+
case "tray.menu":
|
|
192
|
+
linuxTray.mu.Lock()
|
|
193
|
+
icon := linuxTray.icon
|
|
194
|
+
linuxTray.mu.Unlock()
|
|
195
|
+
if icon == nil {
|
|
196
|
+
return nil, fmt.Errorf("tray: 托盘未创建")
|
|
197
|
+
}
|
|
198
|
+
var items []menuItem
|
|
199
|
+
if v, ok := args["items"]; ok {
|
|
200
|
+
if err := json.Unmarshal(v, &items); err != nil {
|
|
201
|
+
return nil, fmt.Errorf("tray: 菜单格式错误: %w", err)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
linuxTraySetMenu(icon, items)
|
|
205
|
+
return nil, nil
|
|
206
|
+
case "menu.set":
|
|
207
|
+
return nil, fmt.Errorf("freedom: menu.set 在 linux 暂不支持(GTK 菜单栏待补)")
|
|
208
|
+
default:
|
|
209
|
+
return nil, fmt.Errorf("freedom: unknown tray method %q", method)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
func linuxTrayCreate(a *App, iconDataURL, tooltip string) error {
|
|
214
|
+
if C.ensureGtk() == 0 {
|
|
215
|
+
return fmt.Errorf("freedom: 无可用显示服务(DISPLAY/Wayland),无法创建托盘")
|
|
216
|
+
}
|
|
217
|
+
png := dataURLToBytes(iconDataURL)
|
|
218
|
+
var icon *C.GtkStatusIcon
|
|
219
|
+
if len(png) > 0 {
|
|
220
|
+
icon = C.trayNewFromPng((*C.guint8)(unsafe.Pointer(&png[0])), C.gsize(len(png)))
|
|
221
|
+
} else {
|
|
222
|
+
name := C.CString("application-x-executable")
|
|
223
|
+
icon = C.trayNewNamed(name)
|
|
224
|
+
C.free(unsafe.Pointer(name))
|
|
225
|
+
}
|
|
226
|
+
if icon == nil {
|
|
227
|
+
return fmt.Errorf("freedom: 托盘图标创建失败(PNG 无法解析或无托盘协议支持)")
|
|
228
|
+
}
|
|
229
|
+
if tooltip != "" {
|
|
230
|
+
tip := C.CString(tooltip)
|
|
231
|
+
C.traySetTooltip(icon, tip)
|
|
232
|
+
C.free(unsafe.Pointer(tip))
|
|
233
|
+
}
|
|
234
|
+
linuxTray.mu.Lock()
|
|
235
|
+
old := linuxTray.icon
|
|
236
|
+
linuxTray.icon = icon
|
|
237
|
+
linuxTray.emit = a.Emit
|
|
238
|
+
linuxTray.mu.Unlock()
|
|
239
|
+
if old != nil {
|
|
240
|
+
C.trayDestroy(old)
|
|
241
|
+
}
|
|
242
|
+
return nil
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
func linuxTrayDestroy() {
|
|
246
|
+
linuxTray.mu.Lock()
|
|
247
|
+
icon := linuxTray.icon
|
|
248
|
+
linuxTray.icon = nil
|
|
249
|
+
linuxTray.items = map[int32]string{}
|
|
250
|
+
linuxTray.mu.Unlock()
|
|
251
|
+
if icon != nil {
|
|
252
|
+
C.trayDestroy(icon)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// linuxTraySetMenu 重建右键菜单并接管 icon 上的旧菜单释放(set_data_full)。
|
|
257
|
+
func linuxTraySetMenu(icon *C.GtkStatusIcon, items []menuItem) {
|
|
258
|
+
linuxTray.mu.Lock()
|
|
259
|
+
linuxTray.items = map[int32]string{}
|
|
260
|
+
var next int32
|
|
261
|
+
assign := func(id string) int32 {
|
|
262
|
+
h := next
|
|
263
|
+
next++
|
|
264
|
+
linuxTray.items[h] = id
|
|
265
|
+
return h
|
|
266
|
+
}
|
|
267
|
+
var build func(menu *C.GtkWidget, list []menuItem)
|
|
268
|
+
build = func(menu *C.GtkWidget, list []menuItem) {
|
|
269
|
+
for _, it := range list {
|
|
270
|
+
label := C.CString(it.Label)
|
|
271
|
+
switch {
|
|
272
|
+
case it.Type == "separator":
|
|
273
|
+
C.menuAppendSeparator(menu)
|
|
274
|
+
case it.Type == "submenu" || len(it.Submenu) > 0:
|
|
275
|
+
sub := C.menuSubmenu(menu, label)
|
|
276
|
+
// 父条目无动作,仅展开;子条目递归编号。
|
|
277
|
+
assign(it.ID)
|
|
278
|
+
build(sub, it.Submenu)
|
|
279
|
+
default:
|
|
280
|
+
idx := assign(it.ID)
|
|
281
|
+
sensitive := C.gboolean(1)
|
|
282
|
+
if it.Enabled != nil && !*it.Enabled {
|
|
283
|
+
sensitive = 0
|
|
284
|
+
}
|
|
285
|
+
if it.Checked != nil {
|
|
286
|
+
checked := C.gboolean(0)
|
|
287
|
+
if *it.Checked {
|
|
288
|
+
checked = 1
|
|
289
|
+
}
|
|
290
|
+
C.menuAppendCheck(menu, label, C.int(idx), checked, sensitive)
|
|
291
|
+
} else {
|
|
292
|
+
C.menuAppendItem(menu, label, C.int(idx), sensitive)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
C.free(unsafe.Pointer(label))
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
menu := C.menuNew()
|
|
299
|
+
build(menu, items)
|
|
300
|
+
C.trayAttachMenu(icon, menu)
|
|
301
|
+
linuxTray.mu.Unlock()
|
|
302
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//go:build !windows && !linux
|
|
2
|
+
|
|
3
|
+
package freedom
|
|
4
|
+
|
|
5
|
+
import "fmt"
|
|
6
|
+
|
|
7
|
+
// trayCall 非 Windows/Linux 平台暂不提供系统托盘与原生菜单栏。Linux 实装见 tray_linux.go(M4)。
|
|
8
|
+
func (a *App) trayCall(method string, paramsJSON string) (interface{}, error) {
|
|
9
|
+
return nil, fmt.Errorf("freedom: tray method %q is not supported on this platform", method)
|
|
10
|
+
}
|