├── .gitignore
├── LICENSE
├── README.md
├── backend
├── client
│ ├── app.go
│ ├── check.go
│ ├── log.go
│ ├── response.go
│ └── start.go
├── config
│ └── config.go
├── info
│ └── info.go
└── request
│ ├── fofa.go
│ ├── hunter.go
│ ├── pr_89.go
│ ├── pr_happy.go
│ ├── pr_qi_yun.go
│ ├── quake.go
│ ├── request.go
│ ├── rs_proxy5.go
│ └── rs_proxy_hub.go
├── build
├── README.md
├── appicon.png
├── darwin
│ ├── Info.dev.plist
│ └── Info.plist
└── windows
│ ├── icon.ico
│ ├── info.json
│ ├── installer
│ ├── project.nsi
│ └── wails_tools.nsh
│ └── wails.exe.manifest
├── frontend
├── index.html
├── package-lock.json
├── package.json
├── package.json.md5
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── fonts
│ │ │ ├── OFL.txt
│ │ │ └── nunito-v16-latin-regular.woff2
│ │ └── images
│ │ │ └── logo-universal.png
│ ├── components
│ │ ├── Config.vue
│ │ ├── Fetch.vue
│ │ ├── Panel.vue
│ │ └── Run.vue
│ ├── main.ts
│ ├── store
│ │ └── types.ts
│ ├── style.css
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
│ ├── go
│ ├── client
│ │ ├── App.d.ts
│ │ └── App.js
│ └── models.ts
│ └── runtime
│ ├── package.json
│ ├── runtime.d.ts
│ └── runtime.js
├── go.mod
├── go.sum
├── images
├── image-20250306224207882.png
├── image-20250308152911121.png
├── image-20250308152932210.png
├── image-20250308153601293.png
└── image-20250308153811761.png
├── main.go
└── wails.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | build/bin
3 | node_modules
4 | frontend/dist
5 | frontend/node_modules
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FreeProxy
2 |
3 | > 一个用于动态切换ip的代理池工具,本工具参考自https://github.com/BKLockly/Proxyz
4 | >
5 | > 参考原作者前端界面(主要是鄙人不会前端o(╥﹏╥)o),新增搜索引擎获取、修复存在的bug
6 | >
7 | > 感谢原作者写出这么好看的前端
8 |
9 | ## 程序使用
10 | 1. 自行导入文件,经检测后若存在可用代理则会持续监听本地的`127.0.0.1:1080`
11 |
12 |
13 |
14 | + 参考其他师傅搜索引擎语法,目前适配获取fofa、hunter、quake平台数据。
15 |
16 |
17 |
18 | + 配置保存
19 |
20 |
21 |
22 | ## 代理配置
23 |
24 | 以火狐浏览器为例,下载FoxyProxy,点击添加,选择socks5协议
25 |
26 | 
27 |
28 | 插件选择刚刚配置的代理即可
29 | 
30 |
31 | ## 注意事项
32 |
33 | + mac下采集保存的代理文件在包结构中,需要手动访问,后续将完善
34 | + 系统全局配置暂未实现,后续将添加
35 | + 如果配置采集页面较多,请耐心等待
36 |
--------------------------------------------------------------------------------
/backend/client/app.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "bufio"
5 | "context"
6 | "doki-byte/FreeProxy/backend/config"
7 | "doki-byte/FreeProxy/backend/info"
8 | "doki-byte/FreeProxy/backend/request"
9 | "fmt"
10 | "github.com/wailsapp/wails/v2/pkg/runtime"
11 | "os"
12 | "strings"
13 | "time"
14 | )
15 |
16 | type App struct {
17 | ctx context.Context
18 | stopChan chan struct{}
19 |
20 | rpm *request.ProxyManager
21 | metrics *info.ProxyMetrics
22 | config *config.Config
23 | }
24 |
25 | func NewApp() *App {
26 | stopChan := make(chan struct{})
27 | return &App{
28 | stopChan: stopChan,
29 | config: config.GetConfig(),
30 | rpm: request.NewProxyManager([]request.ProxyFetcher{
31 | //&request.Free89,
32 | //&request.FreeHappy,
33 | //&request.FreeQiYun,
34 | &request.HunterConfig{},
35 | &request.QuakeConfig{},
36 | &request.FofaConfig{},
37 | }),
38 | metrics: info.NewProxyMetrics(stopChan),
39 | }
40 | }
41 |
42 | func (a *App) Startup(ctx context.Context) {
43 | a.ctx = ctx
44 | go a.metrics.StartMonitoring(1 * time.Second)
45 | go a.metricsPusher()
46 | }
47 |
48 | func (a *App) Shutdown(ctx context.Context) {
49 | a.metrics.StopMonitoring()
50 | close(a.stopChan)
51 | }
52 |
53 | func (a *App) GetProfile() config.Config {
54 | return a.config.GetProfile()
55 | }
56 |
57 | func (a *App) FetchProxies() Response {
58 | proxies, err := a.rpm.FetchAll()
59 | if err != nil {
60 | return a.errorResponse(err)
61 | }
62 |
63 | table, err := a.rpm.RenderTable()
64 | if err != nil {
65 | return a.errorResponse(err)
66 | }
67 |
68 | a.config.SetAllProxies(proxies)
69 | return Response{
70 | Code: 200,
71 | Message: "抓取成功",
72 | Data: string(table),
73 | }
74 | }
75 |
76 | func (a *App) ChooseFile() config.Config {
77 | a.config.Code = 200
78 |
79 | //// 获取配置文件路径
80 | //optSys := runtime2.GOOS
81 | //proxy_success_path := ""
82 | //if optSys == "windows" {
83 | // proxy_success_path = config.GetCurrentAbPathByExecutable() + "\\proxy_success.txt"
84 | //} else {
85 | // proxy_success_path = config.GetCurrentAbPathByExecutable() + "/proxy_success.txt"
86 | //}
87 | //if _, err := os.Stat(proxy_success_path); err == nil {
88 | // a.config.FilePath = proxy_success_path
89 | //} else {
90 | //}
91 |
92 | a.config.FilePath, _ = runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
93 | Title: "请选择配置文件",
94 | ShowHiddenFiles: true,
95 | Filters: []runtime.FileFilter{
96 | {DisplayName: "配置文件", Pattern: "*.txt"},
97 | },
98 | })
99 | if a.config.FilePath == "" {
100 | a.config.Code = 400
101 | a.config.Error = "未选择配置文件"
102 | return a.config.GetProfile()
103 | }
104 |
105 | f, errOpen := os.Open(a.config.FilePath)
106 | if errOpen != nil {
107 | a.config.Code = 400
108 | a.config.Error = errOpen.Error()
109 | return a.config.GetProfile()
110 | }
111 | defer f.Close()
112 |
113 | stat, _ := f.Stat()
114 | if stat.Size() == 0 {
115 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[WARN] 配置文件 %s 是空的", a.config.FilePath))
116 | a.config.Code = 400
117 | a.config.Error = "配置文件为空"
118 | return a.config.GetProfile()
119 | }
120 |
121 | // 按行读取代理数据
122 | var lists []string
123 | scanner := bufio.NewScanner(f)
124 | for scanner.Scan() {
125 | line := strings.TrimSpace(scanner.Text())
126 | // 忽略空行和注释行
127 | if line == "" || strings.HasPrefix(line, "#") {
128 | continue
129 | }
130 | lists = append(lists, line)
131 | }
132 |
133 | if err := scanner.Err(); err != nil {
134 | a.config.Code = 400
135 | a.config.Error = err.Error()
136 | return a.config.GetProfile()
137 | }
138 |
139 | a.config.SetAllProxies(lists)
140 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[INF] 配置文件 %s 读取成功,共 %d 条数据", a.config.FilePath, len(lists)))
141 |
142 | rsp := a.CheckDatasets()
143 | if rsp.Code != 200 {
144 | a.Error("测试有误: %s\n", rsp.Message)
145 | a.config.Code = 400
146 | a.config.Error = rsp.Message
147 | return a.config.GetProfile()
148 | }
149 |
150 | return a.config.GetProfile()
151 | }
152 |
153 | func (a *App) UseFetchedDatasets() Response {
154 | a.StopListening()
155 | a.stopTask()
156 | runtime.EventsEmit(a.ctx, "log_update", "[INF] 使用抓取的代理")
157 | return a.CheckDatasets()
158 | }
159 |
160 | func (a *App) metricsPusher() {
161 | ticker := time.NewTicker(2 * time.Second)
162 | defer ticker.Stop()
163 |
164 | for range ticker.C {
165 | runtime.EventsEmit(a.ctx, "metrics_update", a.metrics.GetMetrics())
166 | }
167 | }
168 |
169 | func (a *App) SaveConfig(data config.Config) string {
170 | a.config = &data
171 | a.StopListening()
172 | a.stopTask()
173 | err := a.config.SaveConfig()
174 | if err != nil {
175 | return "保存失败: " + err.Error()
176 | }
177 | return "保存成功"
178 | }
179 |
--------------------------------------------------------------------------------
/backend/client/check.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "doki-byte/FreeProxy/backend/config"
5 | "fmt"
6 | "github.com/imroc/req/v3"
7 | "github.com/wailsapp/wails/v2/pkg/runtime"
8 | "os"
9 | runtime2 "runtime"
10 | "strconv"
11 | "strings"
12 | "sync"
13 | "time"
14 | )
15 |
16 | func (a *App) CheckDatasets() Response {
17 | a.Debug("workers: ", a.config.CoroutineCount)
18 | availableProxies := make(chan string, a.config.CoroutineCount)
19 | var wg sync.WaitGroup
20 |
21 | checkedProxies := 0
22 | var mu sync.Mutex
23 |
24 | runtime.EventsEmit(a.ctx, "start_task", a.config.GetProfile())
25 | for _, ip := range a.config.LiveProxyLists {
26 | wg.Add(1)
27 | go func(ip string) {
28 | defer wg.Done()
29 | if a.checkProxy(ip) {
30 | availableProxies <- ip
31 | }
32 |
33 | mu.Lock()
34 | checkedProxies++
35 | mu.Unlock()
36 |
37 | progress := float64(checkedProxies) / float64(a.config.AllProxies)
38 | progressStr := fmt.Sprintf("%.2f", progress)
39 | runtime.EventsEmit(a.ctx, "task_progress", progressStr)
40 | }(ip)
41 | }
42 |
43 | go func() {
44 | wg.Wait()
45 | close(availableProxies)
46 | }()
47 |
48 | var availableProxiesList []string
49 | for proxy := range availableProxies {
50 | availableProxiesList = append(availableProxiesList, proxy)
51 | }
52 |
53 | a.config.SetLiveProxies(availableProxiesList)
54 |
55 | // 获取配置文件路径
56 | optSys := runtime2.GOOS
57 | path := ""
58 | if optSys == "windows" {
59 | path = config.GetCurrentAbPathByExecutable() + "\\proxy_success.txt"
60 | } else {
61 | path = config.GetCurrentAbPathByExecutable() + "/proxy_success.txt"
62 | }
63 |
64 | // 使用 map 去重代理列表
65 | proxySet := make(map[string]struct{})
66 | for _, proxy := range availableProxiesList {
67 | proxySet[proxy] = struct{}{}
68 | }
69 |
70 | if len(proxySet) != 0 {
71 | // 检查文件是否已存在,如果不存在则创建
72 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
73 | if err != nil {
74 | a.Error("无法打开文件: %v", err)
75 | }
76 | defer file.Close()
77 |
78 | // 写入去重后的代理地址,并保证每行一个代理
79 | for proxy := range proxySet {
80 | _, err := file.WriteString(proxy + "\n")
81 | if err != nil {
82 | a.Error("写入失败: %v", err)
83 | }
84 | }
85 | }
86 |
87 | msg := fmt.Sprintf("共有 %d 条有效数据", a.config.LiveProxies)
88 | a.Debug("msg: ", msg)
89 | runtime.EventsEmit(a.ctx, "is_ready", a.config.LiveProxies)
90 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[INF] %s ", msg))
91 |
92 | return a.startListening()
93 | }
94 |
95 | func (a *App) checkProxy(proxyIP string) bool {
96 | client := req.C()
97 | client.SetProxyURL(fmt.Sprintf("socks5://%s", proxyIP))
98 | timeout, err := strconv.Atoi(a.config.Timeout)
99 | if err != nil {
100 | a.Debug("Invalid timeout value: %v", err)
101 | }
102 | client.SetTimeout(time.Duration(timeout) * time.Second)
103 | resp, err := client.R().Get("http://myip.ipip.net")
104 | if err != nil {
105 | a.Error("不可用: %s, 错误: %v\n", proxyIP, err)
106 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[ERR] %s <-- : --> %v", proxyIP, err))
107 | return false
108 | }
109 |
110 | if strings.Contains(resp.String(), "当前 IP") {
111 | a.Error("可用: %s\n", proxyIP, "resp: ", resp.String())
112 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[INF] 有效值 %s ", resp.String()))
113 | return true
114 | }
115 |
116 | a.Error("不可用: %s\n", proxyIP)
117 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[WAR] 不稳定 %s -- %v", proxyIP, err))
118 | return false
119 | }
120 |
--------------------------------------------------------------------------------
/backend/client/log.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/wailsapp/wails/v2/pkg/runtime"
7 | )
8 |
9 | func (a *App) Debug(msg ...interface{}) {
10 | runtime.LogDebug(a.ctx, fmt.Sprint(msg...))
11 | }
12 |
13 | func (a *App) Info(msg ...interface{}) {
14 | runtime.LogInfo(a.ctx, fmt.Sprint(msg...))
15 | }
16 |
17 | func (a *App) Warn(msg ...interface{}) {
18 | runtime.LogWarning(a.ctx, fmt.Sprint(msg...))
19 | }
20 |
21 | func (a *App) Error(msg ...interface{}) {
22 | runtime.LogError(a.ctx, fmt.Sprint(msg...))
23 | }
24 |
25 | func (a *App) Fatal(msg ...interface{}) {
26 | runtime.LogFatal(a.ctx, fmt.Sprint(msg...))
27 | }
28 |
--------------------------------------------------------------------------------
/backend/client/response.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import "fmt"
4 |
5 | type Response struct {
6 | Code int
7 | Message string
8 | Data interface{}
9 | }
10 |
11 | func (a *App) errorResponse(message ...interface{}) Response {
12 | return Response{
13 | Code: 400,
14 | Message: fmt.Sprint(message...),
15 | Data: nil,
16 | }
17 | }
18 |
19 | func (a *App) successResponse(msg string, data interface{}) Response {
20 | return Response{
21 | Code: 200,
22 | Message: msg,
23 | Data: data,
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backend/client/start.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "io"
7 | "math/rand"
8 | "net"
9 | "strconv"
10 | "strings"
11 | "sync"
12 | "time"
13 |
14 | "github.com/wailsapp/wails/v2/pkg/runtime"
15 | )
16 |
17 | var listener net.Listener // 全局监听器
18 | var cancel context.CancelFunc // 用于取消监听的上下文
19 |
20 | // 启动监听
21 | func (a *App) startListening() Response {
22 | // 检查缓存代理数
23 | if len(a.config.LiveProxyLists) == 0 {
24 | a.Error("缓存代理数为0,任务取消。")
25 | runtime.EventsEmit(a.ctx, "log_update", "[ERR] 缓存代理数为0。")
26 | runtime.EventsEmit(a.ctx, "log_update", "========================= 任务取消 ==========================")
27 | return a.errorResponse("缓存代理数为0,任务取消。")
28 | }
29 |
30 | // 检查监听器是否已存在
31 | if a.config.GetStatus() == 2 {
32 | // 取消监听
33 | cancel()
34 | listener.Close() // 关闭监听器
35 | }
36 |
37 | // 创建监听器
38 | var err error
39 | var ctx context.Context
40 | ctx, cancel = context.WithCancel(context.Background()) // 创建带取消功能的上下文
41 |
42 | // 继续按原有逻辑使用个别代理
43 | socksAddress := strings.Replace(a.config.SocksAddress, "socks5://", "", -1)
44 | listener, err = net.Listen("tcp", socksAddress)
45 | if err != nil {
46 | a.Error("Error: %s\n", err.Error())
47 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[ERR] 监听失败 %s ", err.Error()))
48 | runtime.EventsEmit(a.ctx, "log_update", "========================= 任务取消 ==========================")
49 | return a.errorResponse(err.Error())
50 | }
51 | defer listener.Close()
52 |
53 | runtime.EventsEmit(a.ctx, "log_update", "======================== 开始监听 =========================")
54 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[INF] 开始监听 %s -- 挂上代理以使用", a.config.SocksAddress))
55 |
56 | var wg sync.WaitGroup
57 | semaphore := make(chan struct{}, a.config.CoroutineCount)
58 |
59 | // 监听连接
60 | for {
61 | select {
62 | case <-ctx.Done(): // 如果上下文被取消,退出监听
63 | runtime.EventsEmit(a.ctx, "log_update", "[INF] 监听已停止")
64 | wg.Wait() // 等待所有连接处理完成
65 | return a.successResponse("监听已成功停止", nil)
66 | default:
67 | conn, err := listener.Accept()
68 | if err != nil {
69 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[ERR] 接受连接失败 %s ", err.Error()))
70 | continue
71 | }
72 |
73 | semaphore <- struct{}{}
74 | wg.Add(1)
75 | go func(conn net.Conn) {
76 | defer wg.Done()
77 | defer func() { <-semaphore }()
78 | a.handleConnection(conn)
79 | }(conn)
80 | }
81 | }
82 | }
83 |
84 | // 停止监听
85 | func (a *App) StopListening() Response {
86 | if listener == nil {
87 | a.Error("监听服务未启动")
88 | runtime.EventsEmit(a.ctx, "log_update", "[ERR] 监听服务未启动")
89 | return a.errorResponse("监听服务未启动")
90 | }
91 |
92 | // 取消监听
93 | cancel()
94 | listener.Close() // 关闭监听器
95 |
96 | runtime.EventsEmit(a.ctx, "log_update", "[INF] 监听已停止")
97 | return a.successResponse("监听已成功停止", nil)
98 | }
99 |
100 | // 处理连接
101 | func (a *App) handleConnection(conn net.Conn) {
102 | defer conn.Close()
103 |
104 | if len(a.config.LiveProxyLists) == 0 {
105 | runtime.EventsEmit(a.ctx, "log_update", "[ERR] 没有可用代理")
106 | return
107 | }
108 |
109 | current := a.config.LiveProxyLists[rand.Intn(len(a.config.LiveProxyLists))]
110 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[INF] 当前使用代理 %s ", current))
111 | runtime.EventsEmit(a.ctx, "status_update", current)
112 |
113 | timeout, err := strconv.Atoi(a.config.Timeout)
114 | if err != nil {
115 | a.Debug("Invalid timeout value: %v", err)
116 | }
117 | socks, err := net.DialTimeout("tcp", current, time.Duration(timeout)*time.Second)
118 | if err != nil {
119 | a.Debug("DialTimeout error: %v", err)
120 | }
121 |
122 | if err != nil {
123 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[ERR] 连接代理失败 %s ", err.Error()))
124 | a.handleConnection(conn)
125 | return
126 | }
127 | defer socks.Close()
128 |
129 | var wg sync.WaitGroup
130 | ioCopy := func(dst io.Writer, src io.Reader) {
131 | defer wg.Done()
132 | _, err := io.Copy(dst, src)
133 | if err != nil {
134 | runtime.EventsEmit(a.ctx, "log_update", fmt.Sprintf("[ERR] 数据传输失败 %s ", err.Error()))
135 | }
136 | }
137 |
138 | wg.Add(2)
139 | go ioCopy(socks, conn)
140 | go ioCopy(conn, socks)
141 | wg.Wait()
142 | }
143 |
144 | // 停止任务,释放端口
145 | func (a *App) stopTask() Response {
146 | if a.config.GetStatus() == 2 {
147 | // 取消上下文,以停止监听
148 | cancel() // 取消监听操作
149 | listener.Close() // 关闭监听器
150 | listener = nil // 清空监听器
151 | runtime.EventsEmit(a.ctx, "log_update", "[INF] 停止监听服务")
152 | runtime.EventsEmit(a.ctx, "log_update", "======================== 任务停止 =========================")
153 | }
154 | a.config.SetStatus(0) // 更新任务状态为停止
155 | // 返回成功响应
156 | return a.successResponse("监听已成功停止", nil)
157 | }
158 |
--------------------------------------------------------------------------------
/backend/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "log"
7 | "os"
8 | "path/filepath"
9 | "reflect"
10 | "runtime"
11 | "strconv"
12 | "strings"
13 | )
14 |
15 | type Config struct {
16 | Email string
17 | FofaKey string
18 | HunterKey string
19 | QuakeKey string
20 | Country string
21 | Maxpage string
22 |
23 | CoroutineCount int
24 | LiveProxies int
25 | AllProxies int
26 | LiveProxyLists []string
27 | Timeout string
28 | SocksAddress string
29 | FilePath string
30 |
31 | Status int
32 |
33 | Code int
34 | Error string
35 | GlobalProxy string
36 | }
37 |
38 | // 获取当前执行程序所在的绝对路径
39 | func GetCurrentAbPathByExecutable() string {
40 | exePath, err := os.Executable()
41 | if err != nil {
42 | log.Fatal(err)
43 | }
44 | res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
45 | return res
46 | }
47 |
48 | func CreateConfigFile() error {
49 | // 获取配置文件路径
50 | optSys := runtime.GOOS
51 | path := ""
52 | if optSys == "windows" {
53 | path = GetCurrentAbPathByExecutable() + "\\config.ini"
54 | } else {
55 | path = GetCurrentAbPathByExecutable() + "/config.ini"
56 | }
57 |
58 | // 检查文件是否已存在
59 | if _, err := os.Stat(path); err == nil {
60 | // 如果文件存在,则返回
61 | return nil
62 | }
63 |
64 | // 文件不存在,创建并写入默认配置
65 | defaultConfig := map[string]string{
66 | "Timeout": "10",
67 | "GlobalProxy": "0",
68 | "Country": "0",
69 | "Email": "",
70 | "FofaKey": "",
71 | "HunterKey": "",
72 | "QuakeKey": "",
73 | "Maxpage": "10",
74 | "CoroutineCount": "200",
75 | "SocksAddress": "socks5://127.0.0.1:1080",
76 | }
77 |
78 | // 创建文件
79 | file, err := os.Create(path)
80 | if err != nil {
81 | return fmt.Errorf("failed to create config file: %v", err)
82 | }
83 | defer file.Close()
84 |
85 | writer := bufio.NewWriter(file)
86 |
87 | // 写入默认配置
88 | for key, value := range defaultConfig {
89 | _, err := writer.WriteString(fmt.Sprintf("%s=%s\n", key, value))
90 | if err != nil {
91 | return fmt.Errorf("failed to write to config file: %v", err)
92 | }
93 | }
94 | writer.Flush()
95 |
96 | return nil
97 | }
98 |
99 | func GetConfig() *Config {
100 | // 创建一个空的结构体
101 | c := &Config{}
102 | cr := reflect.ValueOf(c).Elem()
103 |
104 | // 读取 config.ini 文件路径
105 | optSys := runtime.GOOS
106 | path := ""
107 | if optSys == "windows" {
108 | path = GetCurrentAbPathByExecutable() + "\\config.ini"
109 | } else {
110 | path = GetCurrentAbPathByExecutable() + "/config.ini"
111 | }
112 |
113 | // 打印路径,检查是否正确
114 | log.Printf("Config file path: %s", path)
115 |
116 | // 打开配置文件
117 | f, err := os.Open(path)
118 | if err != nil {
119 | // 如果文件不存在,创建文件
120 | log.Printf("Config file not found, attempting to create it... Error: %v", err)
121 | err := CreateConfigFile()
122 | if err != nil {
123 | log.Fatalf("Failed to create config file: %v", err)
124 | return nil
125 | }
126 | // 尝试重新打开文件
127 | f, err = os.Open(path)
128 | if err != nil {
129 | log.Fatalf("Failed to open config file after creation: %v", err)
130 | return nil
131 | }
132 | }
133 | defer f.Close()
134 |
135 | // 逐行读取文件内容
136 | s := bufio.NewScanner(f)
137 | for s.Scan() {
138 | line := s.Text()
139 | index := strings.Index(line, "=")
140 | if index == -1 {
141 | continue // 跳过不符合格式的行
142 | }
143 |
144 | key := strings.TrimSpace(line[:index])
145 | value := strings.TrimSpace(line[index+1:])
146 |
147 | // 获取结构体字段
148 | field := cr.FieldByName(key)
149 | if !field.IsValid() { // 检查字段是否存在
150 | log.Printf("Warning: Unknown config key: %s", key)
151 | continue
152 | }
153 |
154 | // 设置字段值
155 | if field.Kind() == reflect.String {
156 | field.SetString(value)
157 | } else if field.Kind() == reflect.Int {
158 | intValue, err := strconv.Atoi(value)
159 | if err != nil {
160 | log.Printf("Warning: Invalid integer value for key %s: %s", key, value)
161 | continue
162 | }
163 | field.SetInt(int64(intValue))
164 | } else if field.Kind() == reflect.Slice && field.Type().Elem().Kind() == reflect.String {
165 | field.Set(reflect.ValueOf(strings.Split(value, ",")))
166 | }
167 | }
168 |
169 | if err = s.Err(); err != nil {
170 | log.Fatalf("Failed to read config file: %v", err)
171 | }
172 |
173 | return c
174 | }
175 |
176 | func (p *Config) SaveConfig() error {
177 | optSys := runtime.GOOS
178 | path := ""
179 | if optSys == "windows" {
180 | path = GetCurrentAbPathByExecutable() + "\\config.ini"
181 | } else {
182 | path = GetCurrentAbPathByExecutable() + "/config.ini"
183 | }
184 |
185 | file, err := os.Create(path)
186 | if err != nil {
187 | return err
188 | }
189 | defer file.Close()
190 |
191 | writer := bufio.NewWriter(file)
192 |
193 | configMap := map[string]string{
194 | "Email": p.Email,
195 | "FofaKey": p.FofaKey,
196 | "HunterKey": p.HunterKey,
197 | "QuakeKey": p.QuakeKey,
198 | "Maxpage": p.Maxpage,
199 | "CoroutineCount": strconv.Itoa(p.CoroutineCount),
200 | "Timeout": p.Timeout,
201 | "SocksAddress": p.SocksAddress,
202 | "Status": strconv.Itoa(p.Status),
203 | "Code": strconv.Itoa(p.Code),
204 | "Error": p.Error,
205 | "Country": p.Country,
206 | "GlobalProxy": p.GlobalProxy,
207 | }
208 |
209 | for key, value := range configMap {
210 | //if key == "SocksAddress" {
211 | // value = strings.Replace(value, "socks5://", "", -1)
212 | //}
213 |
214 | _, err := writer.WriteString(fmt.Sprintf("%s=%s\n", key, value))
215 | if err != nil {
216 | return err
217 | }
218 | }
219 | writer.Flush()
220 | return nil
221 | }
222 |
223 | func (p *Config) GetProfile() Config {
224 | //optSys := runtime.GOOS
225 | //proxy_success_path := ""
226 | //if optSys == "windows" {
227 | // proxy_success_path = GetCurrentAbPathByExecutable() + "\\proxy_success.txt"
228 | //} else {
229 | // proxy_success_path = GetCurrentAbPathByExecutable() + "/proxy_success.txt"
230 | //}
231 | //if _, err := os.Stat(proxy_success_path); err == nil {
232 | // // 如果文件存在,则返回
233 | // p.FilePath = proxy_success_path
234 | //} else {
235 | // p.FilePath = ""
236 | //}
237 | return *p
238 | }
239 |
240 | func (p *Config) GetCoroutineCount() int {
241 | return p.CoroutineCount
242 | }
243 |
244 | func (p *Config) GetLiveProxies() int {
245 | return p.LiveProxies
246 | }
247 |
248 | func (p *Config) SetAllProxies(datasets []string) {
249 | p.AllProxies = len(datasets)
250 | p.LiveProxyLists = datasets
251 | }
252 |
253 | func (p *Config) SetLiveProxies(datasets []string) {
254 | p.LiveProxyLists = datasets
255 | p.LiveProxies = len(datasets)
256 | }
257 |
258 | func (p *Config) GetTimeout() string { return p.Timeout }
259 |
260 | func (p *Config) GetSocksAddress() string {
261 | return p.SocksAddress
262 | }
263 |
264 | func (p *Config) GetStatus() int {
265 | return p.Status
266 | }
267 |
268 | func (p *Config) SetStatus(i int) {
269 | p.Status = i
270 | }
271 |
--------------------------------------------------------------------------------
/backend/info/info.go:
--------------------------------------------------------------------------------
1 | package info
2 |
3 | import (
4 | "fmt"
5 | "runtime"
6 | "sync"
7 | "time"
8 |
9 | "github.com/shirou/gopsutil/v3/cpu"
10 | "github.com/shirou/gopsutil/v3/mem"
11 | )
12 |
13 | type ProxyMetrics struct {
14 | mu sync.RWMutex
15 | stop chan struct{}
16 |
17 | cpuUsage float64
18 | memUsageMB float64
19 | }
20 |
21 | func NewProxyMetrics(stopChan chan struct{}) *ProxyMetrics {
22 | return &ProxyMetrics{
23 | stop: stopChan,
24 | }
25 | }
26 |
27 | func (pm *ProxyMetrics) StopMonitoring() {
28 | close(pm.stop)
29 | }
30 |
31 | func (pm *ProxyMetrics) StartMonitoring(interval time.Duration) {
32 | ticker := time.NewTicker(interval)
33 | defer ticker.Stop()
34 |
35 | for {
36 | select {
37 | case <-ticker.C:
38 | percent, _ := cpu.Percent(time.Second, false)
39 | if len(percent) > 0 {
40 | pm.mu.Lock()
41 | pm.cpuUsage = percent[0]
42 | pm.mu.Unlock()
43 | }
44 |
45 | var m runtime.MemStats
46 | runtime.ReadMemStats(&m)
47 |
48 | pm.mu.Lock()
49 | pm.memUsageMB = float64(m.Alloc) / 1024 / 1024
50 | pm.mu.Unlock()
51 | case <-pm.stop:
52 | return
53 | }
54 | }
55 | }
56 |
57 | func (pm *ProxyMetrics) GetMetrics() map[string]string {
58 | pm.mu.RLock()
59 | defer pm.mu.RUnlock()
60 |
61 | v, _ := mem.VirtualMemory()
62 |
63 | return map[string]string{
64 | "cpu_usage": fmt.Sprintf("%.2f%%", pm.cpuUsage),
65 | "mem_usage_self": fmt.Sprintf("%.2f MB", pm.memUsageMB),
66 | "mem_usage_total": fmt.Sprintf("%.2f%%", v.UsedPercent),
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/backend/request/fofa.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "crypto/tls"
5 | "doki-byte/FreeProxy/backend/config"
6 | "encoding/base64"
7 | "encoding/json"
8 | "fmt"
9 | "io"
10 | "log"
11 | "net/http"
12 | "strconv"
13 | "strings"
14 | "time"
15 | )
16 |
17 | type FofaAutoGenerated struct {
18 | Mode string `json:"mode"`
19 | Error bool `json:"error"`
20 | Query string `json:"query"`
21 | Page int `json:"page"`
22 | Size int `json:"size"`
23 | Results [][]string `json:"results"`
24 | }
25 |
26 | func fofa_api(keyword string, email string, key string, page int, size int) string {
27 | input := []byte(keyword)
28 | encodeString := base64.StdEncoding.EncodeToString(input)
29 | api_request := fmt.Sprintf("https://fofa.info/api/v1/search/all?email=%s&page=%d&size=%d&key=%s&qbase64=%s&fields=ip,host,title,port,protocol", strings.Trim(email, " "), page, size, strings.Trim(key, " "), encodeString)
30 | return api_request
31 | }
32 |
33 | func fofahttp(url string, timeout string) *FofaAutoGenerated {
34 | var itime, err = strconv.Atoi(timeout)
35 | if err != nil {
36 | log.Println("fofa超时参数错误: ", err)
37 | }
38 | transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
39 | client := &http.Client{
40 | Timeout: time.Duration(itime) * time.Second,
41 | Transport: transport,
42 | }
43 | req, err := http.NewRequest("GET", url, nil)
44 | if err != nil {
45 | log.Fatal(err)
46 | }
47 | req.Header.Set("Accept", "*/*;q=0.8")
48 | req.Header.Set("Connection", "close")
49 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36")
50 | resp, err := client.Do(req)
51 | if err != nil {
52 | log.Fatal(err)
53 | }
54 | defer resp.Body.Close()
55 | result, _ := io.ReadAll(resp.Body)
56 | res := &FofaAutoGenerated{}
57 | json.Unmarshal(result, &res)
58 | return res
59 | }
60 |
61 | func Fafaall(keyword string) (urls []string) {
62 | fofa := config.GetConfig()
63 | url := fofa_api(keyword, fofa.Email, fofa.FofaKey, 1, 100)
64 | res := fofahttp(url, fofa.Timeout)
65 | pagelength := res.Size/1000 + 1
66 | for _, value := range res.Results {
67 | urls = append(urls, value[1])
68 | }
69 | Maxpage, _ := strconv.Atoi(fofa.Maxpage)
70 | if pagelength > 1 {
71 | for i := 2; i <= pagelength && i <= Maxpage; i++ {
72 | fmt.Println("正在请求第" + strconv.Itoa(i) + "页数据")
73 | url = fofa_api(keyword, fofa.Email, fofa.FofaKey, i, 100)
74 | res = fofahttp(url, fofa.Timeout)
75 | if len(res.Results) > 0 {
76 | for _, value := range res.Results {
77 | urls = append(urls, value[1])
78 | }
79 | }
80 | }
81 | }
82 |
83 | return urls
84 | }
85 |
86 | type FofaConfig struct {
87 | }
88 |
89 | func (fp *FofaConfig) Name() string {
90 | return "Hunter"
91 | }
92 |
93 | func (fp *FofaConfig) Fetch() ([]string, error) {
94 | fofa := config.GetConfig()
95 |
96 | var fofakeys string
97 |
98 | if fofa.FofaKey != "" && fofa.Email != "" {
99 | switch fofa.Country {
100 | case "0":
101 | fofakeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\""
102 | case "1":
103 | fofakeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\" && ip.country=\"CN\""
104 | case "2":
105 | fofakeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\" && ip.country!=\"CN\""
106 | }
107 | urls := Fafaall(fofakeys)
108 | return urls, nil
109 | } else {
110 | return nil, nil
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/backend/request/hunter.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "crypto/tls"
5 | "doki-byte/FreeProxy/backend/config"
6 | "encoding/base64"
7 | "encoding/json"
8 | "fmt"
9 | "io"
10 | "log"
11 | "net/http"
12 | "strconv"
13 | "strings"
14 | "time"
15 | )
16 |
17 | type HunterAutoGenerated struct {
18 | Code int `json:"code"`
19 | Data struct {
20 | AccountType string `json:"account_type"`
21 | Total int `json:"total"`
22 | Time int `json:"time"`
23 | Arr []struct {
24 | IsRisk string `json:"is_risk"`
25 | Url string `json:"url"`
26 | Ip string `json:"ip"`
27 | Port int `json:"port"`
28 | WebTitle string `json:"web_title"`
29 | Domain string `json:"domain"`
30 | IsRiskProtocol string `json:"is_risk_protocol"`
31 | Protocol string `json:"protocol"`
32 | BaseProtocol string `json:"base_protocol"`
33 | StatusCode int `json:"status_code"`
34 | Component interface{} `json:"component"`
35 | Os string `json:"os"`
36 | Company string `json:"company"`
37 | Number string `json:"number"`
38 | Country string `json:"country"`
39 | Province string `json:"province"`
40 | City string `json:"city"`
41 | UpdatedAt string `json:"updated_at"`
42 | IsWeb string `json:"is_web"`
43 | AsOrg string `json:"as_org"`
44 | Isp string `json:"isp"`
45 | Banner string `json:"banner"`
46 | } `json:"arr"`
47 | ConsumeQuota string `json:"consume_quota"`
48 | RestQuota string `json:"rest_quota"`
49 | SyntaxPrompt string `json:"syntax_prompt"`
50 | } `json:"data"`
51 | Message string `json:"message"`
52 | }
53 |
54 | func hunter_api(keyword string, key string, page int, size int) string {
55 | input := []byte(keyword)
56 | encodeString := base64.StdEncoding.EncodeToString(input)
57 | nowTime := time.Now()
58 | endtime := nowTime.Format("2006-01-02")
59 | starttime := nowTime.AddDate(0, -1, 0).Format("2006-01-02")
60 | api_request := fmt.Sprintf("https://hunter.qianxin.com/openApi/search?api-key=%s&search=%s&page=%s&page_size=%s&is_web=3&port_filter=false&start_time=%s&end_time=%s", strings.Trim(key, " "), encodeString, strconv.Itoa(page), strconv.Itoa(size), starttime, endtime)
61 | return api_request
62 | }
63 |
64 | func hunterhttp(url string, timeout string) *HunterAutoGenerated {
65 | var itime, err = strconv.Atoi(timeout)
66 | if err != nil {
67 | log.Println("hunter超时参数错误: ", err)
68 | }
69 | transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
70 | client := &http.Client{
71 | Timeout: time.Duration(itime) * time.Second,
72 | Transport: transport,
73 | }
74 | req, err := http.NewRequest("GET", url, nil)
75 | if err != nil {
76 | log.Fatal(err)
77 | }
78 | req.Header.Set("Accept", "*/*;q=0.8")
79 | req.Header.Set("Connection", "close")
80 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36")
81 | resp, err := client.Do(req)
82 | if err != nil {
83 | log.Fatal(err)
84 | }
85 | defer resp.Body.Close()
86 | result, _ := io.ReadAll(resp.Body)
87 | res := &HunterAutoGenerated{}
88 | json.Unmarshal(result, &res)
89 | return res
90 | }
91 |
92 | func Hunterall(keyword string) (urls []string) {
93 | hunter := config.GetConfig()
94 | url := hunter_api(keyword, hunter.HunterKey, 1, 10)
95 | res := hunterhttp(url, hunter.Timeout)
96 | pagelength := res.Data.Total/10 + 1
97 | for _, value := range res.Data.Arr {
98 | urls = append(urls, value.Ip+":"+strconv.Itoa(value.Port))
99 | }
100 | Maxpage, _ := strconv.Atoi(hunter.Maxpage)
101 | if pagelength > 1 {
102 | for i := 2; i <= pagelength && i <= Maxpage; i++ {
103 | fmt.Println("正在请求第" + strconv.Itoa(i) + "页数据")
104 | url = hunter_api(keyword, hunter.HunterKey, i, 10)
105 | res = hunterhttp(url, hunter.Timeout)
106 | if len(res.Data.Arr) > 0 {
107 | for _, value := range res.Data.Arr {
108 | urls = append(urls, value.Ip+":"+strconv.Itoa(value.Port))
109 | }
110 | }
111 | }
112 | }
113 |
114 | return urls
115 | }
116 |
117 | type HunterConfig struct {
118 | }
119 |
120 | func (fp *HunterConfig) Name() string {
121 | return "Hunter"
122 | }
123 |
124 | func (fp *HunterConfig) Fetch() ([]string, error) {
125 | hunter := config.GetConfig()
126 |
127 | var hunterkeys string
128 |
129 | if hunter.HunterKey != "" {
130 | switch hunter.Country {
131 | case "0":
132 | hunterkeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\""
133 | case "1":
134 | hunterkeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\" && ip.country=\"CN\""
135 | case "2":
136 | hunterkeys = "protocol==\"socks5\"&&protocol.banner=\"Method: 0x00 (No authentication)\" && ip.country!=\"CN\""
137 | }
138 | urls := Hunterall(hunterkeys)
139 | return urls, nil
140 | } else {
141 | return nil, nil
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/backend/request/pr_89.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/imroc/req/v3"
7 | )
8 |
9 | type Free89Proxy struct {
10 | url string
11 | reg string
12 | }
13 |
14 | var Free89 = Free89Proxy{
15 | url: "https://www.89ip.cn/tqdl.html?num=60&address=&kill_address=&port=&kill_port=&isp=",
16 | reg: `(\d+\.\d+\.\d+\.\d+):\d+`,
17 | }
18 |
19 | func (fp *Free89Proxy) Name() string {
20 | return "89代理"
21 | }
22 |
23 | func (fp *Free89Proxy) Fetch() ([]string, error) {
24 | client := req.C()
25 | resp, err := client.R().Get(fp.url)
26 | if err != nil {
27 | return nil, err
28 | }
29 |
30 | body := resp.String()
31 |
32 | ipPortRegex := regexp.MustCompile(fp.reg)
33 | matches := ipPortRegex.FindAllString(body, -1)
34 |
35 | return matches, nil
36 | }
37 |
--------------------------------------------------------------------------------
/backend/request/pr_happy.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "sync"
7 |
8 | "github.com/imroc/req/v3"
9 | )
10 |
11 | type FreeHappyProxy struct {
12 | page int
13 | url string
14 | reg string
15 | }
16 |
17 | func (fp *FreeHappyProxy) Name() string {
18 | return "开心代理"
19 | }
20 |
21 | var FreeHappy = FreeHappyProxy{
22 | page: 20,
23 | url: "http://www.kxdaili.com/dailiip/1/",
24 | reg: "
(.*?)\\s*?(.*?) | ",
25 | }
26 |
27 | func (fp *FreeHappyProxy) Fetch() ([]string, error) {
28 | var wg sync.WaitGroup
29 | ch := make(chan []string, fp.page)
30 | errCh := make(chan error, fp.page)
31 |
32 | for i := 1; i <= fp.page; i++ {
33 | wg.Add(1)
34 | go func(page int) {
35 | defer wg.Done()
36 | proxies, err := fp.fetchPage(page)
37 | if err != nil {
38 | errCh <- err
39 | return
40 | }
41 | ch <- proxies
42 | }(i)
43 | }
44 |
45 | go func() {
46 | wg.Wait()
47 | close(ch)
48 | close(errCh)
49 | }()
50 |
51 | var allProxies []string
52 | for {
53 | select {
54 | case proxies, ok := <-ch:
55 | if !ok {
56 | return allProxies, nil
57 | }
58 | allProxies = append(allProxies, proxies...)
59 | case err, ok := <-errCh:
60 | if !ok {
61 | continue
62 | }
63 | return nil, err
64 | }
65 | }
66 | }
67 |
68 | func (fp *FreeHappyProxy) fetchPage(page int) ([]string, error) {
69 | client := req.C()
70 | resp, err := client.R().Get(fmt.Sprintf("%s%d.html", fp.url, page))
71 | if err != nil {
72 | return nil, err
73 | }
74 |
75 | body := resp.String()
76 |
77 | ipPortRegex := regexp.MustCompile(fp.reg)
78 | matches := ipPortRegex.FindAllStringSubmatch(body, -1)
79 |
80 | var proxies []string
81 | for _, match := range matches {
82 | if len(match) == 3 {
83 | ip := match[1]
84 | port := match[2]
85 | proxies = append(proxies, fmt.Sprintf("%s:%s", ip, port))
86 | }
87 | }
88 |
89 | return proxies, nil
90 | }
91 |
--------------------------------------------------------------------------------
/backend/request/pr_qi_yun.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "sync"
7 |
8 | "github.com/imroc/req/v3"
9 | )
10 |
11 | type FreeQiYunProxy struct {
12 | page int
13 | url string
14 | reg string
15 | }
16 |
17 | func (fp *FreeQiYunProxy) Name() string {
18 | return "齐云代理"
19 | }
20 |
21 | var FreeQiYun = FreeQiYunProxy{
22 | page: 20,
23 | url: "https://proxy.ip3366.net/free/?action=china&page=",
24 | reg: `([\d.]+) | \s*(\d+) | `,
25 | }
26 |
27 | func (fp *FreeQiYunProxy) Fetch() ([]string, error) {
28 | var wg sync.WaitGroup
29 | ch := make(chan []string, fp.page)
30 | errCh := make(chan error, fp.page)
31 |
32 | for i := 1; i <= fp.page; i++ {
33 | wg.Add(1)
34 | go func(page int) {
35 | defer wg.Done()
36 | proxies, err := fp.fetchPage(page)
37 | if err != nil {
38 | errCh <- err
39 | return
40 | }
41 | ch <- proxies
42 | }(i)
43 | }
44 |
45 | go func() {
46 | wg.Wait()
47 | close(ch)
48 | close(errCh)
49 | }()
50 |
51 | var allProxies []string
52 | for {
53 | select {
54 | case proxies, ok := <-ch:
55 | if !ok {
56 | return allProxies, nil
57 | }
58 | allProxies = append(allProxies, proxies...)
59 | case err, ok := <-errCh:
60 | if !ok {
61 | continue
62 | }
63 | return nil, err
64 | }
65 | }
66 | }
67 |
68 | func (fp *FreeQiYunProxy) fetchPage(page int) ([]string, error) {
69 | client := req.C()
70 | resp, err := client.R().Get(fmt.Sprintf("%s%d", fp.url, page))
71 | if err != nil {
72 | return nil, err
73 | }
74 |
75 | body := resp.String()
76 |
77 | ipPortRegex := regexp.MustCompile(fp.reg)
78 | matches := ipPortRegex.FindAllStringSubmatch(body, -1)
79 |
80 | var proxies []string
81 | for _, match := range matches {
82 | if len(match) == 3 {
83 | ip := match[1]
84 | port := match[2]
85 | proxies = append(proxies, fmt.Sprintf("%s:%s", ip, port))
86 | }
87 | }
88 |
89 | return proxies, nil
90 | }
91 |
--------------------------------------------------------------------------------
/backend/request/quake.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "bytes"
5 | "crypto/tls"
6 | "doki-byte/FreeProxy/backend/config"
7 | "encoding/json"
8 | "fmt"
9 | "io"
10 | "log"
11 | "net/http"
12 | "strconv"
13 | "time"
14 | )
15 |
16 | type QuakeData struct {
17 | Query string `json:"query"`
18 | Start int `json:"start"`
19 | Size int `json:"size"`
20 | }
21 |
22 | type QuakeAutoGenerated struct {
23 | Code int `json:"code"`
24 | Message string `json:"message"`
25 | Data []struct {
26 | Hostname string `json:"hostname"`
27 | Org string `json:"org"`
28 | Port int `json:"port"`
29 | Service struct {
30 | Response string `json:"response"`
31 | ResponseHash string `json:"response_hash"`
32 | Name string `json:"name"`
33 | Version string `json:"version"`
34 | Socks5 struct {
35 | AuthAcceptedMethod string `json:"auth_accepted_method"`
36 | Version int `json:"version"`
37 | } `json:"socks5"`
38 | } `json:"service"`
39 | Ip string `json:"ip"`
40 | OsVersion string `json:"os_version"`
41 | OsName string `json:"os_name"`
42 | Location struct {
43 | Owner string `json:"owner"`
44 | ProvinceCn string `json:"province_cn"`
45 | ProvinceEn string `json:"province_en"`
46 | Isp string `json:"isp"`
47 | CountryEn string `json:"country_en"`
48 | DistrictCn string `json:"district_cn"`
49 | Gps []float64 `json:"gps"`
50 | StreetCn string `json:"street_cn"`
51 | CityEn string `json:"city_en"`
52 | DistrictEn string `json:"district_en"`
53 | CountryCn string `json:"country_cn"`
54 | StreetEn string `json:"street_en"`
55 | CityCn string `json:"city_cn"`
56 | CountryCode string `json:"country_code"`
57 | Asname string `json:"asname"`
58 | SceneCn string `json:"scene_cn"`
59 | SceneEn string `json:"scene_en"`
60 | Radius int `json:"radius"`
61 | } `json:"location"`
62 | IsIpv6 bool `json:"is_ipv6"`
63 | Transport string `json:"transport"`
64 | Time time.Time `json:"time"`
65 | Asn int `json:"asn"`
66 | } `json:"data"`
67 | Meta struct {
68 | Pagination struct {
69 | Count int `json:"count"`
70 | PageIndex int `json:"page_index"`
71 | PageSize int `json:"page_size"`
72 | Total int `json:"total"`
73 | } `json:"pagination"`
74 | } `json:"meta"`
75 | }
76 |
77 | func quake_api(keyword string, start int, size int) QuakeData {
78 | reqData := QuakeData{}
79 | reqData.Query = keyword
80 | reqData.Start = start
81 | reqData.Size = size
82 |
83 | return reqData
84 | }
85 |
86 | func quakehttp(postdata QuakeData, key string, timeout string) *QuakeAutoGenerated {
87 | var itime, err = strconv.Atoi(timeout)
88 | if err != nil {
89 | log.Println("quake超时参数错误: ", err)
90 | }
91 | transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
92 | client := &http.Client{
93 | Timeout: time.Duration(itime) * time.Second,
94 | Transport: transport,
95 | }
96 | url := "https://quake.360.net/api/v3/search/quake_service"
97 | payload, _ := json.Marshal(postdata)
98 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
99 | if err != nil {
100 | log.Fatal(err)
101 | }
102 | req.Header.Set("content-type", "application/json")
103 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36")
104 | req.Header.Set("X-QuakeToken", key)
105 | resp, err := client.Do(req)
106 | if err != nil {
107 | log.Fatal(err)
108 | }
109 | defer resp.Body.Close()
110 | result, _ := io.ReadAll(resp.Body)
111 | res := &QuakeAutoGenerated{}
112 | json.Unmarshal(result, &res)
113 | return res
114 | }
115 |
116 | func Quakeall(keyword string) (urls []string) {
117 | quake := config.GetConfig()
118 | postdata := quake_api(keyword, 0, 50)
119 | res := quakehttp(postdata, quake.QuakeKey, quake.Timeout)
120 | pagelength := res.Meta.Pagination.Total/50 + 1
121 | for _, value := range res.Data {
122 | urls = append(urls, value.Ip+":"+strconv.Itoa(value.Port))
123 | }
124 | Maxpage, _ := strconv.Atoi(quake.Maxpage)
125 | if pagelength > 1 {
126 | for i := 1; i <= pagelength && i <= Maxpage*2; i++ {
127 | fmt.Println("正在请求第" + strconv.Itoa(i) + "页数据")
128 | postdata = quake_api(keyword, i*50, 50)
129 | res = quakehttp(postdata, quake.QuakeKey, quake.Timeout)
130 | if len(res.Data) > 0 {
131 | for _, value := range res.Data {
132 | urls = append(urls, value.Ip+":"+strconv.Itoa(value.Port))
133 | }
134 | } else {
135 | break
136 | }
137 | }
138 | }
139 |
140 | return urls
141 | }
142 |
143 | type QuakeConfig struct{}
144 |
145 | func (fp *QuakeConfig) Name() string {
146 | return "Quake"
147 | }
148 |
149 | func (fp *QuakeConfig) Fetch() ([]string, error) {
150 | quake := config.GetConfig()
151 |
152 | var quakekeys string
153 |
154 | if quake.QuakeKey != "" {
155 | switch quake.Country {
156 | case "0":
157 | quakekeys = fmt.Sprintf("service:\"socks5\" and response:\"Accepted Auth Method: 0x0\"")
158 | case "1":
159 | quakekeys = fmt.Sprintf("service:\"socks5\" and response:\"Accepted Auth Method: 0x0\" and country: \"China\"")
160 | case "2":
161 | quakekeys = fmt.Sprintf("service:\"socks5\" and response:\"Accepted Auth Method: 0x0\" and not country: \"China\"")
162 | }
163 | urls := Quakeall(quakekeys)
164 | return urls, nil
165 | } else {
166 | return nil, nil
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/backend/request/request.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "doki-byte/FreeProxy/backend/config"
5 | "encoding/json"
6 | "github.com/labstack/gommon/log"
7 | "os"
8 | "runtime"
9 | "strconv"
10 | )
11 |
12 | type ProxyInfo struct {
13 | Key string `json:"key"`
14 | Address string `json:"address"`
15 | Source string `json:"source"`
16 | Kind string `json:"kind"`
17 | }
18 |
19 | type ProxyFetcher interface {
20 | Fetch() ([]string, error)
21 | Name() string
22 | }
23 |
24 | type ProxyManager struct {
25 | fetchers []ProxyFetcher
26 | allProxies []string
27 | proxies []ProxyInfo
28 | }
29 |
30 | func NewProxyManager(fetchers []ProxyFetcher) *ProxyManager {
31 | return &ProxyManager{
32 | fetchers: fetchers,
33 | }
34 | }
35 |
36 | func (pm *ProxyManager) RenderTable() ([]byte, error) {
37 | marshal, err := json.Marshal(pm.proxies)
38 | if err != nil {
39 | return nil, err
40 | }
41 | return marshal, nil
42 | }
43 |
44 | func (pm *ProxyManager) FetchAll() ([]string, error) {
45 | i := 1
46 | for _, fetcher := range pm.fetchers {
47 | proxies, err := fetcher.Fetch()
48 | if err != nil {
49 | continue
50 | }
51 |
52 | for _, proxy := range proxies {
53 | pi := &ProxyInfo{
54 | Key: strconv.Itoa(i),
55 | Address: proxy,
56 | Source: fetcher.Name(),
57 | Kind: "socks5",
58 | }
59 | pm.proxies = append(pm.proxies, *pi)
60 | i++
61 | }
62 |
63 | pm.allProxies = append(pm.allProxies, proxies...)
64 | }
65 |
66 | // 获取配置文件路径
67 | optSys := runtime.GOOS
68 | path := ""
69 | if optSys == "windows" {
70 | path = config.GetCurrentAbPathByExecutable() + "\\proxy.txt"
71 | } else {
72 | path = config.GetCurrentAbPathByExecutable() + "/proxy.txt"
73 | }
74 |
75 | // 检查文件是否已存在,如果不存在则创建
76 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
77 | if err != nil {
78 | log.Error("无法打开文件: %v", err)
79 | }
80 | defer file.Close()
81 |
82 | // 使用 map 去重代理列表
83 | proxySet := make(map[string]struct{})
84 | for _, proxy := range pm.allProxies {
85 | proxySet[proxy] = struct{}{}
86 | }
87 |
88 | // 写入去重后的代理地址,并保证每行一个代理
89 | for proxy := range proxySet {
90 | _, err := file.WriteString(proxy + "\n")
91 | if err != nil {
92 | log.Error("写入失败: %v", err)
93 | }
94 | }
95 |
96 | return pm.allProxies, nil
97 | }
98 |
--------------------------------------------------------------------------------
/backend/request/rs_proxy5.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "sync"
7 |
8 | "github.com/imroc/req/v3"
9 | )
10 |
11 | type FreeProxy5Proxy struct {
12 | page int
13 | url string
14 | reg string
15 | }
16 |
17 | func (fp *FreeProxy5Proxy) Name() string {
18 | return "齐云代理"
19 | }
20 |
21 | var FreeProxy5 = FreeProxy5Proxy{
22 | page: 20,
23 | url: "https://proxy.ip3366.net/free/?action=china&page=",
24 | reg: `([\d.]+) | \s*(\d+) | `,
25 | }
26 |
27 | func (fp *FreeProxy5Proxy) Fetch() ([]string, error) {
28 | var wg sync.WaitGroup
29 | ch := make(chan []string, fp.page)
30 | errCh := make(chan error, fp.page)
31 |
32 | for i := 1; i <= fp.page; i++ {
33 | wg.Add(1)
34 | go func(page int) {
35 | defer wg.Done()
36 | proxies, err := fp.fetchPage(page)
37 | if err != nil {
38 | errCh <- err
39 | return
40 | }
41 | ch <- proxies
42 | }(i)
43 | }
44 |
45 | go func() {
46 | wg.Wait()
47 | close(ch)
48 | close(errCh)
49 | }()
50 |
51 | var allProxies []string
52 | for {
53 | select {
54 | case proxies, ok := <-ch:
55 | if !ok {
56 | return allProxies, nil
57 | }
58 | allProxies = append(allProxies, proxies...)
59 | case err, ok := <-errCh:
60 | if !ok {
61 | continue
62 | }
63 | return nil, err
64 | }
65 | }
66 | }
67 |
68 | func (fp *FreeProxy5Proxy) fetchPage(page int) ([]string, error) {
69 | client := req.C()
70 | resp, err := client.R().Get(fmt.Sprintf("%s%d", fp.url, page))
71 | if err != nil {
72 | return nil, err
73 | }
74 |
75 | body := resp.String()
76 |
77 | ipPortRegex := regexp.MustCompile(fp.reg)
78 | matches := ipPortRegex.FindAllStringSubmatch(body, -1)
79 |
80 | var proxies []string
81 | for _, match := range matches {
82 | if len(match) == 3 {
83 | ip := match[1]
84 | port := match[2]
85 | proxies = append(proxies, fmt.Sprintf("%s:%s", ip, port))
86 | }
87 | }
88 |
89 | return proxies, nil
90 | }
91 |
--------------------------------------------------------------------------------
/backend/request/rs_proxy_hub.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "sync"
7 |
8 | "github.com/imroc/req/v3"
9 | )
10 |
11 | type FreeProxyHubProxy struct {
12 | page int
13 | url string
14 | reg string
15 | }
16 |
17 | func (fp *FreeProxyHubProxy) Name() string {
18 | return "ProxyHub"
19 | }
20 |
21 | var FreeProxyHub = FreeProxyHubProxy{
22 | page: 20,
23 | url: "https://proxyhub.me/zh/cn-socks5-proxy-list.html",
24 | reg: `([\d.]+) | \s*(\d+) | `,
25 | }
26 |
27 | func (fp *FreeProxyHubProxy) Fetch() ([]string, error) {
28 | var wg sync.WaitGroup
29 | ch := make(chan []string, fp.page)
30 | errCh := make(chan error, fp.page)
31 |
32 | for i := 1; i <= fp.page; i++ {
33 | wg.Add(1)
34 | go func(page int) {
35 | defer wg.Done()
36 | proxies, err := fp.fetchPage(page)
37 | if err != nil {
38 | errCh <- err
39 | return
40 | }
41 | ch <- proxies
42 | }(i)
43 | }
44 |
45 | go func() {
46 | wg.Wait()
47 | close(ch)
48 | close(errCh)
49 | }()
50 |
51 | var allProxies []string
52 | for {
53 | select {
54 | case proxies, ok := <-ch:
55 | if !ok {
56 | return allProxies, nil
57 | }
58 | allProxies = append(allProxies, proxies...)
59 | case err, ok := <-errCh:
60 | if !ok {
61 | continue
62 | }
63 | return nil, err
64 | }
65 | }
66 | }
67 |
68 | func (fp *FreeProxyHubProxy) fetchPage(page int) ([]string, error) {
69 | client := req.C()
70 | resp, err := client.R().Get(fmt.Sprintf("%s%d", fp.url, page))
71 | if err != nil {
72 | return nil, err
73 | }
74 |
75 | body := resp.String()
76 |
77 | ipPortRegex := regexp.MustCompile(fp.reg)
78 | matches := ipPortRegex.FindAllStringSubmatch(body, -1)
79 |
80 | var proxies []string
81 | for _, match := range matches {
82 | if len(match) == 3 {
83 | ip := match[1]
84 | port := match[2]
85 | proxies = append(proxies, fmt.Sprintf("%s:%s", ip, port))
86 | }
87 | }
88 |
89 | return proxies, nil
90 | }
91 |
--------------------------------------------------------------------------------
/build/README.md:
--------------------------------------------------------------------------------
1 | # Build Directory
2 |
3 | The build directory is used to house all the build files and assets for your application.
4 |
5 | The structure is:
6 |
7 | * bin - Output directory
8 | * darwin - macOS specific files
9 | * windows - Windows specific files
10 |
11 | ## Mac
12 |
13 | The `darwin` directory holds files specific to Mac builds.
14 | These may be customised and used as part of the build. To return these files to the default state, simply delete them
15 | and
16 | build with `wails build`.
17 |
18 | The directory contains the following files:
19 |
20 | - `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`.
21 | - `Info.dev.plist` - same as the main plist file but used when building using `wails dev`.
22 |
23 | ## Windows
24 |
25 | The `windows` directory contains the manifest and rc files used when building with `wails build`.
26 | These may be customised for your application. To return these files to the default state, simply delete them and
27 | build with `wails build`.
28 |
29 | - `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to
30 | use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file
31 | will be created using the `appicon.png` file in the build directory.
32 | - `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`.
33 | - `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer,
34 | as well as the application itself (right click the exe -> properties -> details)
35 | - `wails.exe.manifest` - The main application manifest file.
--------------------------------------------------------------------------------
/build/appicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/build/appicon.png
--------------------------------------------------------------------------------
/build/darwin/Info.dev.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundlePackageType
5 | APPL
6 | CFBundleName
7 | {{.Info.ProductName}}
8 | CFBundleExecutable
9 | {{.Name}}
10 | CFBundleIdentifier
11 | com.wails.{{.Name}}
12 | CFBundleVersion
13 | {{.Info.ProductVersion}}
14 | CFBundleGetInfoString
15 | {{.Info.Comments}}
16 | CFBundleShortVersionString
17 | {{.Info.ProductVersion}}
18 | CFBundleIconFile
19 | iconfile
20 | LSMinimumSystemVersion
21 | 10.13.0
22 | NSHighResolutionCapable
23 | true
24 | NSHumanReadableCopyright
25 | {{.Info.Copyright}}
26 | {{if .Info.FileAssociations}}
27 | CFBundleDocumentTypes
28 |
29 | {{range .Info.FileAssociations}}
30 |
31 | CFBundleTypeExtensions
32 |
33 | {{.Ext}}
34 |
35 | CFBundleTypeName
36 | {{.Name}}
37 | CFBundleTypeRole
38 | {{.Role}}
39 | CFBundleTypeIconFile
40 | {{.IconName}}
41 |
42 | {{end}}
43 |
44 | {{end}}
45 | {{if .Info.Protocols}}
46 | CFBundleURLTypes
47 |
48 | {{range .Info.Protocols}}
49 |
50 | CFBundleURLName
51 | com.wails.{{.Scheme}}
52 | CFBundleURLSchemes
53 |
54 | {{.Scheme}}
55 |
56 | CFBundleTypeRole
57 | {{.Role}}
58 |
59 | {{end}}
60 |
61 | {{end}}
62 | NSAppTransportSecurity
63 |
64 | NSAllowsLocalNetworking
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/build/darwin/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundlePackageType
5 | APPL
6 | CFBundleName
7 | {{.Info.ProductName}}
8 | CFBundleExecutable
9 | {{.Name}}
10 | CFBundleIdentifier
11 | com.wails.{{.Name}}
12 | CFBundleVersion
13 | {{.Info.ProductVersion}}
14 | CFBundleGetInfoString
15 | {{.Info.Comments}}
16 | CFBundleShortVersionString
17 | {{.Info.ProductVersion}}
18 | CFBundleIconFile
19 | iconfile
20 | LSMinimumSystemVersion
21 | 10.13.0
22 | NSHighResolutionCapable
23 | true
24 | NSHumanReadableCopyright
25 | {{.Info.Copyright}}
26 | {{if .Info.FileAssociations}}
27 | CFBundleDocumentTypes
28 |
29 | {{range .Info.FileAssociations}}
30 |
31 | CFBundleTypeExtensions
32 |
33 | {{.Ext}}
34 |
35 | CFBundleTypeName
36 | {{.Name}}
37 | CFBundleTypeRole
38 | {{.Role}}
39 | CFBundleTypeIconFile
40 | {{.IconName}}
41 |
42 | {{end}}
43 |
44 | {{end}}
45 | {{if .Info.Protocols}}
46 | CFBundleURLTypes
47 |
48 | {{range .Info.Protocols}}
49 |
50 | CFBundleURLName
51 | com.wails.{{.Scheme}}
52 | CFBundleURLSchemes
53 |
54 | {{.Scheme}}
55 |
56 | CFBundleTypeRole
57 | {{.Role}}
58 |
59 | {{end}}
60 |
61 | {{end}}
62 |
63 |
64 |
--------------------------------------------------------------------------------
/build/windows/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/build/windows/icon.ico
--------------------------------------------------------------------------------
/build/windows/info.json:
--------------------------------------------------------------------------------
1 | {
2 | "fixed": {
3 | "file_version": "{{.Info.ProductVersion}}"
4 | },
5 | "info": {
6 | "0000": {
7 | "ProductVersion": "{{.Info.ProductVersion}}",
8 | "CompanyName": "{{.Info.CompanyName}}",
9 | "FileDescription": "{{.Info.ProductName}}",
10 | "LegalCopyright": "{{.Info.Copyright}}",
11 | "ProductName": "{{.Info.ProductName}}",
12 | "Comments": "{{.Info.Comments}}"
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/build/windows/installer/project.nsi:
--------------------------------------------------------------------------------
1 | Unicode true
2 |
3 | ####
4 | ## Please note: Template replacements don't work in this file. They are provided with default defines like
5 | ## mentioned underneath.
6 | ## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo.
7 | ## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually
8 | ## from outside of Wails for debugging and development of the installer.
9 | ##
10 | ## For development first make a wails nsis build to populate the "wails_tools.nsh":
11 | ## > wails build --target windows/amd64 --nsis
12 | ## Then you can call makensis on this file with specifying the path to your binary:
13 | ## For a AMD64 only installer:
14 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe
15 | ## For a ARM64 only installer:
16 | ## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe
17 | ## For a installer with both architectures:
18 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe
19 | ####
20 | ## The following information is taken from the ProjectInfo file, but they can be overwritten here.
21 | ####
22 | ## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
23 | ## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
24 | ## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
25 | ## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
26 | ## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
27 | ###
28 | ## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
29 | ## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
30 | ####
31 | ## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
32 | ####
33 | ## Include the wails tools
34 | ####
35 | !include "wails_tools.nsh"
36 |
37 | # The version information for this two must consist of 4 parts
38 | VIProductVersion "${INFO_PRODUCTVERSION}.0"
39 | VIFileVersion "${INFO_PRODUCTVERSION}.0"
40 |
41 | VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
42 | VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
43 | VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
44 | VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
45 | VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
46 | VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
47 |
48 | # Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware
49 | ManifestDPIAware true
50 |
51 | !include "MUI.nsh"
52 |
53 | !define MUI_ICON "..\icon.ico"
54 | !define MUI_UNICON "..\icon.ico"
55 | # !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
56 | !define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
57 | !define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
58 |
59 | !insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
60 | # !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer
61 | !insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
62 | !insertmacro MUI_PAGE_INSTFILES # Installing page.
63 | !insertmacro MUI_PAGE_FINISH # Finished installation page.
64 |
65 | !insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page
66 |
67 | !insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
68 |
69 | ## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
70 | #!uninstfinalize 'signtool --file "%1"'
71 | #!finalize 'signtool --file "%1"'
72 |
73 | Name "${INFO_PRODUCTNAME}"
74 | OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
75 | InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
76 | ShowInstDetails show # This will always show the installation details.
77 |
78 | Function .onInit
79 | !insertmacro wails.checkArchitecture
80 | FunctionEnd
81 |
82 | Section
83 | !insertmacro wails.setShellContext
84 |
85 | !insertmacro wails.webview2runtime
86 |
87 | SetOutPath $INSTDIR
88 |
89 | !insertmacro wails.files
90 |
91 | CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
92 | CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
93 |
94 | !insertmacro wails.associateFiles
95 | !insertmacro wails.associateCustomProtocols
96 |
97 | !insertmacro wails.writeUninstaller
98 | SectionEnd
99 |
100 | Section "uninstall"
101 | !insertmacro wails.setShellContext
102 |
103 | RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
104 |
105 | RMDir /r $INSTDIR
106 |
107 | Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
108 | Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
109 |
110 | !insertmacro wails.unassociateFiles
111 | !insertmacro wails.unassociateCustomProtocols
112 |
113 | !insertmacro wails.deleteUninstaller
114 | SectionEnd
115 |
--------------------------------------------------------------------------------
/build/windows/installer/wails_tools.nsh:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - Generated automatically by `wails build`
2 |
3 | !include "x64.nsh"
4 | !include "WinVer.nsh"
5 | !include "FileFunc.nsh"
6 |
7 | !ifndef INFO_PROJECTNAME
8 | !define INFO_PROJECTNAME "{{.Name}}"
9 | !endif
10 | !ifndef INFO_COMPANYNAME
11 | !define INFO_COMPANYNAME "{{.Info.CompanyName}}"
12 | !endif
13 | !ifndef INFO_PRODUCTNAME
14 | !define INFO_PRODUCTNAME "{{.Info.ProductName}}"
15 | !endif
16 | !ifndef INFO_PRODUCTVERSION
17 | !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
18 | !endif
19 | !ifndef INFO_COPYRIGHT
20 | !define INFO_COPYRIGHT "{{.Info.Copyright}}"
21 | !endif
22 | !ifndef PRODUCT_EXECUTABLE
23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
24 | !endif
25 | !ifndef UNINST_KEY_NAME
26 | !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
27 | !endif
28 | !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
29 |
30 | !ifndef REQUEST_EXECUTION_LEVEL
31 | !define REQUEST_EXECUTION_LEVEL "admin"
32 | !endif
33 |
34 | RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
35 |
36 | !ifdef ARG_WAILS_AMD64_BINARY
37 | !define SUPPORTS_AMD64
38 | !endif
39 |
40 | !ifdef ARG_WAILS_ARM64_BINARY
41 | !define SUPPORTS_ARM64
42 | !endif
43 |
44 | !ifdef SUPPORTS_AMD64
45 | !ifdef SUPPORTS_ARM64
46 | !define ARCH "amd64_arm64"
47 | !else
48 | !define ARCH "amd64"
49 | !endif
50 | !else
51 | !ifdef SUPPORTS_ARM64
52 | !define ARCH "arm64"
53 | !else
54 | !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
55 | !endif
56 | !endif
57 |
58 | !macro wails.checkArchitecture
59 | !ifndef WAILS_WIN10_REQUIRED
60 | !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
61 | !endif
62 |
63 | !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
64 | !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
65 | !endif
66 |
67 | ${If} ${AtLeastWin10}
68 | !ifdef SUPPORTS_AMD64
69 | ${if} ${IsNativeAMD64}
70 | Goto ok
71 | ${EndIf}
72 | !endif
73 |
74 | !ifdef SUPPORTS_ARM64
75 | ${if} ${IsNativeARM64}
76 | Goto ok
77 | ${EndIf}
78 | !endif
79 |
80 | IfSilent silentArch notSilentArch
81 | silentArch:
82 | SetErrorLevel 65
83 | Abort
84 | notSilentArch:
85 | MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
86 | Quit
87 | ${else}
88 | IfSilent silentWin notSilentWin
89 | silentWin:
90 | SetErrorLevel 64
91 | Abort
92 | notSilentWin:
93 | MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
94 | Quit
95 | ${EndIf}
96 |
97 | ok:
98 | !macroend
99 |
100 | !macro wails.files
101 | !ifdef SUPPORTS_AMD64
102 | ${if} ${IsNativeAMD64}
103 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
104 | ${EndIf}
105 | !endif
106 |
107 | !ifdef SUPPORTS_ARM64
108 | ${if} ${IsNativeARM64}
109 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
110 | ${EndIf}
111 | !endif
112 | !macroend
113 |
114 | !macro wails.writeUninstaller
115 | WriteUninstaller "$INSTDIR\uninstall.exe"
116 |
117 | SetRegView 64
118 | WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
119 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
120 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
121 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
122 | WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
123 | WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
124 |
125 | ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
126 | IntFmt $0 "0x%08X" $0
127 | WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
128 | !macroend
129 |
130 | !macro wails.deleteUninstaller
131 | Delete "$INSTDIR\uninstall.exe"
132 |
133 | SetRegView 64
134 | DeleteRegKey HKLM "${UNINST_KEY}"
135 | !macroend
136 |
137 | !macro wails.setShellContext
138 | ${If} ${REQUEST_EXECUTION_LEVEL} == "admin"
139 | SetShellVarContext all
140 | ${else}
141 | SetShellVarContext current
142 | ${EndIf}
143 | !macroend
144 |
145 | # Install webview2 by launching the bootstrapper
146 | # See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
147 | !macro wails.webview2runtime
148 | !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
149 | !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
150 | !endif
151 |
152 | SetRegView 64
153 | # If the admin key exists and is not empty then webview2 is already installed
154 | ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
155 | ${If} $0 != ""
156 | Goto ok
157 | ${EndIf}
158 |
159 | ${If} ${REQUEST_EXECUTION_LEVEL} == "user"
160 | # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
161 | ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
162 | ${If} $0 != ""
163 | Goto ok
164 | ${EndIf}
165 | ${EndIf}
166 |
167 | SetDetailsPrint both
168 | DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
169 | SetDetailsPrint listonly
170 |
171 | InitPluginsDir
172 | CreateDirectory "$pluginsdir\webview2bootstrapper"
173 | SetOutPath "$pluginsdir\webview2bootstrapper"
174 | File "tmp\MicrosoftEdgeWebview2Setup.exe"
175 | ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
176 |
177 | SetDetailsPrint both
178 | ok:
179 | !macroend
180 |
181 | # Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b
182 | !macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
183 | ; Backup the previously associated file class
184 | ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
185 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
186 |
187 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
188 |
189 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
190 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
191 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
192 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
193 | WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}`
194 | !macroend
195 |
196 | !macro APP_UNASSOCIATE EXT FILECLASS
197 | ; Backup the previously associated file class
198 | ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
199 | WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"
200 |
201 | DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
202 | !macroend
203 |
204 | !macro wails.associateFiles
205 | ; Create file associations
206 | {{range .Info.FileAssociations}}
207 | !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
208 |
209 | File "..\{{.IconName}}.ico"
210 | {{end}}
211 | !macroend
212 |
213 | !macro wails.unassociateFiles
214 | ; Delete app associations
215 | {{range .Info.FileAssociations}}
216 | !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
217 |
218 | Delete "$INSTDIR\{{.IconName}}.ico"
219 | {{end}}
220 | !macroend
221 |
222 | !macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
223 | DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
224 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
225 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
226 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
227 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
228 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
229 | WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
230 | !macroend
231 |
232 | !macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
233 | DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
234 | !macroend
235 |
236 | !macro wails.associateCustomProtocols
237 | ; Create custom protocols associations
238 | {{range .Info.Protocols}}
239 | !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
240 |
241 | {{end}}
242 | !macroend
243 |
244 | !macro wails.unassociateCustomProtocols
245 | ; Delete app custom protocol associations
246 | {{range .Info.Protocols}}
247 | !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
248 | {{end}}
249 | !macroend
250 |
--------------------------------------------------------------------------------
/build/windows/wails.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | true/pm
12 | permonitorv2,permonitor
13 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | FreeProxy
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/frontend/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "frontend",
9 | "version": "0.0.0",
10 | "dependencies": {
11 | "pinia": "^3.0.1",
12 | "vue": "^3.2.37",
13 | "vue-router": "^4.5.0"
14 | },
15 | "devDependencies": {
16 | "@arco-design/web-vue": "^2.56.3",
17 | "@babel/types": "^7.18.10",
18 | "@types/node": "^22.13.1",
19 | "@vitejs/plugin-vue": "^3.0.3",
20 | "typescript": "^4.6.4",
21 | "vite": "^3.0.7",
22 | "vue-tsc": "^1.8.27"
23 | }
24 | },
25 | "node_modules/@arco-design/color": {
26 | "version": "0.4.0",
27 | "resolved": "https://registry.npmmirror.com/@arco-design/color/-/color-0.4.0.tgz",
28 | "integrity": "sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==",
29 | "dev": true,
30 | "dependencies": {
31 | "color": "^3.1.3"
32 | }
33 | },
34 | "node_modules/@arco-design/web-vue": {
35 | "version": "2.56.3",
36 | "resolved": "https://registry.npmmirror.com/@arco-design/web-vue/-/web-vue-2.56.3.tgz",
37 | "integrity": "sha512-D2CPIXRBUPcg37TFsfWROZddCWFZnIwqGpsOhOn2BhmH89UFqtBGpTxyuMdYJEwKNXunp3dVL6V69ZMmJBRPOg==",
38 | "dev": true,
39 | "dependencies": {
40 | "@arco-design/color": "^0.4.0",
41 | "b-tween": "^0.3.3",
42 | "b-validate": "^1.4.4",
43 | "compute-scroll-into-view": "^1.0.17",
44 | "dayjs": "^1.10.3",
45 | "number-precision": "^1.5.0",
46 | "resize-observer-polyfill": "^1.5.1",
47 | "scroll-into-view-if-needed": "^2.2.28"
48 | },
49 | "peerDependencies": {
50 | "vue": "^3.1.0"
51 | }
52 | },
53 | "node_modules/@babel/helper-string-parser": {
54 | "version": "7.25.9",
55 | "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
56 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
57 | "engines": {
58 | "node": ">=6.9.0"
59 | }
60 | },
61 | "node_modules/@babel/helper-validator-identifier": {
62 | "version": "7.25.9",
63 | "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
64 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
65 | "engines": {
66 | "node": ">=6.9.0"
67 | }
68 | },
69 | "node_modules/@babel/parser": {
70 | "version": "7.26.8",
71 | "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.8.tgz",
72 | "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
73 | "dependencies": {
74 | "@babel/types": "^7.26.8"
75 | },
76 | "bin": {
77 | "parser": "bin/babel-parser.js"
78 | },
79 | "engines": {
80 | "node": ">=6.0.0"
81 | }
82 | },
83 | "node_modules/@babel/types": {
84 | "version": "7.26.8",
85 | "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.8.tgz",
86 | "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
87 | "dependencies": {
88 | "@babel/helper-string-parser": "^7.25.9",
89 | "@babel/helper-validator-identifier": "^7.25.9"
90 | },
91 | "engines": {
92 | "node": ">=6.9.0"
93 | }
94 | },
95 | "node_modules/@esbuild/android-arm": {
96 | "version": "0.15.18",
97 | "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
98 | "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
99 | "cpu": [
100 | "arm"
101 | ],
102 | "dev": true,
103 | "optional": true,
104 | "os": [
105 | "android"
106 | ],
107 | "engines": {
108 | "node": ">=12"
109 | }
110 | },
111 | "node_modules/@esbuild/linux-loong64": {
112 | "version": "0.15.18",
113 | "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
114 | "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
115 | "cpu": [
116 | "loong64"
117 | ],
118 | "dev": true,
119 | "optional": true,
120 | "os": [
121 | "linux"
122 | ],
123 | "engines": {
124 | "node": ">=12"
125 | }
126 | },
127 | "node_modules/@jridgewell/sourcemap-codec": {
128 | "version": "1.5.0",
129 | "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
130 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
131 | },
132 | "node_modules/@types/node": {
133 | "version": "22.13.1",
134 | "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.1.tgz",
135 | "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
136 | "dev": true,
137 | "dependencies": {
138 | "undici-types": "~6.20.0"
139 | }
140 | },
141 | "node_modules/@vitejs/plugin-vue": {
142 | "version": "3.2.0",
143 | "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz",
144 | "integrity": "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==",
145 | "dev": true,
146 | "engines": {
147 | "node": "^14.18.0 || >=16.0.0"
148 | },
149 | "peerDependencies": {
150 | "vite": "^3.0.0",
151 | "vue": "^3.2.25"
152 | }
153 | },
154 | "node_modules/@volar/language-core": {
155 | "version": "1.11.1",
156 | "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-1.11.1.tgz",
157 | "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==",
158 | "dev": true,
159 | "dependencies": {
160 | "@volar/source-map": "1.11.1"
161 | }
162 | },
163 | "node_modules/@volar/source-map": {
164 | "version": "1.11.1",
165 | "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-1.11.1.tgz",
166 | "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==",
167 | "dev": true,
168 | "dependencies": {
169 | "muggle-string": "^0.3.1"
170 | }
171 | },
172 | "node_modules/@volar/typescript": {
173 | "version": "1.11.1",
174 | "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-1.11.1.tgz",
175 | "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==",
176 | "dev": true,
177 | "dependencies": {
178 | "@volar/language-core": "1.11.1",
179 | "path-browserify": "^1.0.1"
180 | }
181 | },
182 | "node_modules/@vue/compiler-core": {
183 | "version": "3.5.13",
184 | "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz",
185 | "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
186 | "dependencies": {
187 | "@babel/parser": "^7.25.3",
188 | "@vue/shared": "3.5.13",
189 | "entities": "^4.5.0",
190 | "estree-walker": "^2.0.2",
191 | "source-map-js": "^1.2.0"
192 | }
193 | },
194 | "node_modules/@vue/compiler-dom": {
195 | "version": "3.5.13",
196 | "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz",
197 | "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
198 | "dependencies": {
199 | "@vue/compiler-core": "3.5.13",
200 | "@vue/shared": "3.5.13"
201 | }
202 | },
203 | "node_modules/@vue/compiler-sfc": {
204 | "version": "3.5.13",
205 | "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz",
206 | "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
207 | "dependencies": {
208 | "@babel/parser": "^7.25.3",
209 | "@vue/compiler-core": "3.5.13",
210 | "@vue/compiler-dom": "3.5.13",
211 | "@vue/compiler-ssr": "3.5.13",
212 | "@vue/shared": "3.5.13",
213 | "estree-walker": "^2.0.2",
214 | "magic-string": "^0.30.11",
215 | "postcss": "^8.4.48",
216 | "source-map-js": "^1.2.0"
217 | }
218 | },
219 | "node_modules/@vue/compiler-ssr": {
220 | "version": "3.5.13",
221 | "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz",
222 | "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
223 | "dependencies": {
224 | "@vue/compiler-dom": "3.5.13",
225 | "@vue/shared": "3.5.13"
226 | }
227 | },
228 | "node_modules/@vue/devtools-api": {
229 | "version": "7.7.2",
230 | "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-7.7.2.tgz",
231 | "integrity": "sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==",
232 | "dependencies": {
233 | "@vue/devtools-kit": "^7.7.2"
234 | }
235 | },
236 | "node_modules/@vue/devtools-kit": {
237 | "version": "7.7.2",
238 | "resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz",
239 | "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==",
240 | "dependencies": {
241 | "@vue/devtools-shared": "^7.7.2",
242 | "birpc": "^0.2.19",
243 | "hookable": "^5.5.3",
244 | "mitt": "^3.0.1",
245 | "perfect-debounce": "^1.0.0",
246 | "speakingurl": "^14.0.1",
247 | "superjson": "^2.2.1"
248 | }
249 | },
250 | "node_modules/@vue/devtools-shared": {
251 | "version": "7.7.2",
252 | "resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz",
253 | "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==",
254 | "dependencies": {
255 | "rfdc": "^1.4.1"
256 | }
257 | },
258 | "node_modules/@vue/language-core": {
259 | "version": "1.8.27",
260 | "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-1.8.27.tgz",
261 | "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==",
262 | "dev": true,
263 | "dependencies": {
264 | "@volar/language-core": "~1.11.1",
265 | "@volar/source-map": "~1.11.1",
266 | "@vue/compiler-dom": "^3.3.0",
267 | "@vue/shared": "^3.3.0",
268 | "computeds": "^0.0.1",
269 | "minimatch": "^9.0.3",
270 | "muggle-string": "^0.3.1",
271 | "path-browserify": "^1.0.1",
272 | "vue-template-compiler": "^2.7.14"
273 | },
274 | "peerDependencies": {
275 | "typescript": "*"
276 | },
277 | "peerDependenciesMeta": {
278 | "typescript": {
279 | "optional": true
280 | }
281 | }
282 | },
283 | "node_modules/@vue/reactivity": {
284 | "version": "3.5.13",
285 | "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz",
286 | "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
287 | "dependencies": {
288 | "@vue/shared": "3.5.13"
289 | }
290 | },
291 | "node_modules/@vue/runtime-core": {
292 | "version": "3.5.13",
293 | "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz",
294 | "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
295 | "dependencies": {
296 | "@vue/reactivity": "3.5.13",
297 | "@vue/shared": "3.5.13"
298 | }
299 | },
300 | "node_modules/@vue/runtime-dom": {
301 | "version": "3.5.13",
302 | "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz",
303 | "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
304 | "dependencies": {
305 | "@vue/reactivity": "3.5.13",
306 | "@vue/runtime-core": "3.5.13",
307 | "@vue/shared": "3.5.13",
308 | "csstype": "^3.1.3"
309 | }
310 | },
311 | "node_modules/@vue/server-renderer": {
312 | "version": "3.5.13",
313 | "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz",
314 | "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
315 | "dependencies": {
316 | "@vue/compiler-ssr": "3.5.13",
317 | "@vue/shared": "3.5.13"
318 | },
319 | "peerDependencies": {
320 | "vue": "3.5.13"
321 | }
322 | },
323 | "node_modules/@vue/shared": {
324 | "version": "3.5.13",
325 | "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz",
326 | "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="
327 | },
328 | "node_modules/b-tween": {
329 | "version": "0.3.3",
330 | "resolved": "https://registry.npmmirror.com/b-tween/-/b-tween-0.3.3.tgz",
331 | "integrity": "sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==",
332 | "dev": true
333 | },
334 | "node_modules/b-validate": {
335 | "version": "1.5.3",
336 | "resolved": "https://registry.npmmirror.com/b-validate/-/b-validate-1.5.3.tgz",
337 | "integrity": "sha512-iCvCkGFskbaYtfQ0a3GmcQCHl/Sv1GufXFGuUQ+FE+WJa7A/espLOuFIn09B944V8/ImPj71T4+rTASxO2PAuA==",
338 | "dev": true
339 | },
340 | "node_modules/balanced-match": {
341 | "version": "1.0.2",
342 | "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
343 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
344 | "dev": true
345 | },
346 | "node_modules/birpc": {
347 | "version": "0.2.19",
348 | "resolved": "https://registry.npmmirror.com/birpc/-/birpc-0.2.19.tgz",
349 | "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==",
350 | "funding": {
351 | "url": "https://github.com/sponsors/antfu"
352 | }
353 | },
354 | "node_modules/brace-expansion": {
355 | "version": "2.0.1",
356 | "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
357 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
358 | "dev": true,
359 | "dependencies": {
360 | "balanced-match": "^1.0.0"
361 | }
362 | },
363 | "node_modules/color": {
364 | "version": "3.2.1",
365 | "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
366 | "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
367 | "dev": true,
368 | "dependencies": {
369 | "color-convert": "^1.9.3",
370 | "color-string": "^1.6.0"
371 | }
372 | },
373 | "node_modules/color-convert": {
374 | "version": "1.9.3",
375 | "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
376 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
377 | "dev": true,
378 | "dependencies": {
379 | "color-name": "1.1.3"
380 | }
381 | },
382 | "node_modules/color-name": {
383 | "version": "1.1.3",
384 | "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
385 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
386 | "dev": true
387 | },
388 | "node_modules/color-string": {
389 | "version": "1.9.1",
390 | "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz",
391 | "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
392 | "dev": true,
393 | "dependencies": {
394 | "color-name": "^1.0.0",
395 | "simple-swizzle": "^0.2.2"
396 | }
397 | },
398 | "node_modules/compute-scroll-into-view": {
399 | "version": "1.0.20",
400 | "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
401 | "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
402 | "dev": true
403 | },
404 | "node_modules/computeds": {
405 | "version": "0.0.1",
406 | "resolved": "https://registry.npmmirror.com/computeds/-/computeds-0.0.1.tgz",
407 | "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
408 | "dev": true
409 | },
410 | "node_modules/copy-anything": {
411 | "version": "3.0.5",
412 | "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-3.0.5.tgz",
413 | "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
414 | "dependencies": {
415 | "is-what": "^4.1.8"
416 | },
417 | "engines": {
418 | "node": ">=12.13"
419 | },
420 | "funding": {
421 | "url": "https://github.com/sponsors/mesqueeb"
422 | }
423 | },
424 | "node_modules/csstype": {
425 | "version": "3.1.3",
426 | "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
427 | "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
428 | },
429 | "node_modules/dayjs": {
430 | "version": "1.11.13",
431 | "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
432 | "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
433 | "dev": true
434 | },
435 | "node_modules/de-indent": {
436 | "version": "1.0.2",
437 | "resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
438 | "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
439 | "dev": true
440 | },
441 | "node_modules/entities": {
442 | "version": "4.5.0",
443 | "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
444 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
445 | "engines": {
446 | "node": ">=0.12"
447 | },
448 | "funding": {
449 | "url": "https://github.com/fb55/entities?sponsor=1"
450 | }
451 | },
452 | "node_modules/esbuild": {
453 | "version": "0.15.18",
454 | "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz",
455 | "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
456 | "dev": true,
457 | "hasInstallScript": true,
458 | "bin": {
459 | "esbuild": "bin/esbuild"
460 | },
461 | "engines": {
462 | "node": ">=12"
463 | },
464 | "optionalDependencies": {
465 | "@esbuild/android-arm": "0.15.18",
466 | "@esbuild/linux-loong64": "0.15.18",
467 | "esbuild-android-64": "0.15.18",
468 | "esbuild-android-arm64": "0.15.18",
469 | "esbuild-darwin-64": "0.15.18",
470 | "esbuild-darwin-arm64": "0.15.18",
471 | "esbuild-freebsd-64": "0.15.18",
472 | "esbuild-freebsd-arm64": "0.15.18",
473 | "esbuild-linux-32": "0.15.18",
474 | "esbuild-linux-64": "0.15.18",
475 | "esbuild-linux-arm": "0.15.18",
476 | "esbuild-linux-arm64": "0.15.18",
477 | "esbuild-linux-mips64le": "0.15.18",
478 | "esbuild-linux-ppc64le": "0.15.18",
479 | "esbuild-linux-riscv64": "0.15.18",
480 | "esbuild-linux-s390x": "0.15.18",
481 | "esbuild-netbsd-64": "0.15.18",
482 | "esbuild-openbsd-64": "0.15.18",
483 | "esbuild-sunos-64": "0.15.18",
484 | "esbuild-windows-32": "0.15.18",
485 | "esbuild-windows-64": "0.15.18",
486 | "esbuild-windows-arm64": "0.15.18"
487 | }
488 | },
489 | "node_modules/esbuild-android-64": {
490 | "version": "0.15.18",
491 | "resolved": "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
492 | "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
493 | "cpu": [
494 | "x64"
495 | ],
496 | "dev": true,
497 | "optional": true,
498 | "os": [
499 | "android"
500 | ],
501 | "engines": {
502 | "node": ">=12"
503 | }
504 | },
505 | "node_modules/esbuild-android-arm64": {
506 | "version": "0.15.18",
507 | "resolved": "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
508 | "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
509 | "cpu": [
510 | "arm64"
511 | ],
512 | "dev": true,
513 | "optional": true,
514 | "os": [
515 | "android"
516 | ],
517 | "engines": {
518 | "node": ">=12"
519 | }
520 | },
521 | "node_modules/esbuild-darwin-64": {
522 | "version": "0.15.18",
523 | "resolved": "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
524 | "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
525 | "cpu": [
526 | "x64"
527 | ],
528 | "dev": true,
529 | "optional": true,
530 | "os": [
531 | "darwin"
532 | ],
533 | "engines": {
534 | "node": ">=12"
535 | }
536 | },
537 | "node_modules/esbuild-darwin-arm64": {
538 | "version": "0.15.18",
539 | "resolved": "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
540 | "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
541 | "cpu": [
542 | "arm64"
543 | ],
544 | "dev": true,
545 | "optional": true,
546 | "os": [
547 | "darwin"
548 | ],
549 | "engines": {
550 | "node": ">=12"
551 | }
552 | },
553 | "node_modules/esbuild-freebsd-64": {
554 | "version": "0.15.18",
555 | "resolved": "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
556 | "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
557 | "cpu": [
558 | "x64"
559 | ],
560 | "dev": true,
561 | "optional": true,
562 | "os": [
563 | "freebsd"
564 | ],
565 | "engines": {
566 | "node": ">=12"
567 | }
568 | },
569 | "node_modules/esbuild-freebsd-arm64": {
570 | "version": "0.15.18",
571 | "resolved": "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
572 | "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
573 | "cpu": [
574 | "arm64"
575 | ],
576 | "dev": true,
577 | "optional": true,
578 | "os": [
579 | "freebsd"
580 | ],
581 | "engines": {
582 | "node": ">=12"
583 | }
584 | },
585 | "node_modules/esbuild-linux-32": {
586 | "version": "0.15.18",
587 | "resolved": "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
588 | "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
589 | "cpu": [
590 | "ia32"
591 | ],
592 | "dev": true,
593 | "optional": true,
594 | "os": [
595 | "linux"
596 | ],
597 | "engines": {
598 | "node": ">=12"
599 | }
600 | },
601 | "node_modules/esbuild-linux-64": {
602 | "version": "0.15.18",
603 | "resolved": "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
604 | "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
605 | "cpu": [
606 | "x64"
607 | ],
608 | "dev": true,
609 | "optional": true,
610 | "os": [
611 | "linux"
612 | ],
613 | "engines": {
614 | "node": ">=12"
615 | }
616 | },
617 | "node_modules/esbuild-linux-arm": {
618 | "version": "0.15.18",
619 | "resolved": "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
620 | "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
621 | "cpu": [
622 | "arm"
623 | ],
624 | "dev": true,
625 | "optional": true,
626 | "os": [
627 | "linux"
628 | ],
629 | "engines": {
630 | "node": ">=12"
631 | }
632 | },
633 | "node_modules/esbuild-linux-arm64": {
634 | "version": "0.15.18",
635 | "resolved": "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
636 | "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
637 | "cpu": [
638 | "arm64"
639 | ],
640 | "dev": true,
641 | "optional": true,
642 | "os": [
643 | "linux"
644 | ],
645 | "engines": {
646 | "node": ">=12"
647 | }
648 | },
649 | "node_modules/esbuild-linux-mips64le": {
650 | "version": "0.15.18",
651 | "resolved": "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
652 | "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
653 | "cpu": [
654 | "mips64el"
655 | ],
656 | "dev": true,
657 | "optional": true,
658 | "os": [
659 | "linux"
660 | ],
661 | "engines": {
662 | "node": ">=12"
663 | }
664 | },
665 | "node_modules/esbuild-linux-ppc64le": {
666 | "version": "0.15.18",
667 | "resolved": "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
668 | "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
669 | "cpu": [
670 | "ppc64"
671 | ],
672 | "dev": true,
673 | "optional": true,
674 | "os": [
675 | "linux"
676 | ],
677 | "engines": {
678 | "node": ">=12"
679 | }
680 | },
681 | "node_modules/esbuild-linux-riscv64": {
682 | "version": "0.15.18",
683 | "resolved": "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
684 | "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
685 | "cpu": [
686 | "riscv64"
687 | ],
688 | "dev": true,
689 | "optional": true,
690 | "os": [
691 | "linux"
692 | ],
693 | "engines": {
694 | "node": ">=12"
695 | }
696 | },
697 | "node_modules/esbuild-linux-s390x": {
698 | "version": "0.15.18",
699 | "resolved": "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
700 | "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
701 | "cpu": [
702 | "s390x"
703 | ],
704 | "dev": true,
705 | "optional": true,
706 | "os": [
707 | "linux"
708 | ],
709 | "engines": {
710 | "node": ">=12"
711 | }
712 | },
713 | "node_modules/esbuild-netbsd-64": {
714 | "version": "0.15.18",
715 | "resolved": "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
716 | "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
717 | "cpu": [
718 | "x64"
719 | ],
720 | "dev": true,
721 | "optional": true,
722 | "os": [
723 | "netbsd"
724 | ],
725 | "engines": {
726 | "node": ">=12"
727 | }
728 | },
729 | "node_modules/esbuild-openbsd-64": {
730 | "version": "0.15.18",
731 | "resolved": "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
732 | "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
733 | "cpu": [
734 | "x64"
735 | ],
736 | "dev": true,
737 | "optional": true,
738 | "os": [
739 | "openbsd"
740 | ],
741 | "engines": {
742 | "node": ">=12"
743 | }
744 | },
745 | "node_modules/esbuild-sunos-64": {
746 | "version": "0.15.18",
747 | "resolved": "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
748 | "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
749 | "cpu": [
750 | "x64"
751 | ],
752 | "dev": true,
753 | "optional": true,
754 | "os": [
755 | "sunos"
756 | ],
757 | "engines": {
758 | "node": ">=12"
759 | }
760 | },
761 | "node_modules/esbuild-windows-32": {
762 | "version": "0.15.18",
763 | "resolved": "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
764 | "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
765 | "cpu": [
766 | "ia32"
767 | ],
768 | "dev": true,
769 | "optional": true,
770 | "os": [
771 | "win32"
772 | ],
773 | "engines": {
774 | "node": ">=12"
775 | }
776 | },
777 | "node_modules/esbuild-windows-64": {
778 | "version": "0.15.18",
779 | "resolved": "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
780 | "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
781 | "cpu": [
782 | "x64"
783 | ],
784 | "dev": true,
785 | "optional": true,
786 | "os": [
787 | "win32"
788 | ],
789 | "engines": {
790 | "node": ">=12"
791 | }
792 | },
793 | "node_modules/esbuild-windows-arm64": {
794 | "version": "0.15.18",
795 | "resolved": "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
796 | "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
797 | "cpu": [
798 | "arm64"
799 | ],
800 | "dev": true,
801 | "optional": true,
802 | "os": [
803 | "win32"
804 | ],
805 | "engines": {
806 | "node": ">=12"
807 | }
808 | },
809 | "node_modules/estree-walker": {
810 | "version": "2.0.2",
811 | "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
812 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
813 | },
814 | "node_modules/fsevents": {
815 | "version": "2.3.3",
816 | "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
817 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
818 | "dev": true,
819 | "hasInstallScript": true,
820 | "optional": true,
821 | "os": [
822 | "darwin"
823 | ],
824 | "engines": {
825 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
826 | }
827 | },
828 | "node_modules/function-bind": {
829 | "version": "1.1.2",
830 | "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
831 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
832 | "dev": true,
833 | "funding": {
834 | "url": "https://github.com/sponsors/ljharb"
835 | }
836 | },
837 | "node_modules/hasown": {
838 | "version": "2.0.2",
839 | "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
840 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
841 | "dev": true,
842 | "dependencies": {
843 | "function-bind": "^1.1.2"
844 | },
845 | "engines": {
846 | "node": ">= 0.4"
847 | }
848 | },
849 | "node_modules/he": {
850 | "version": "1.2.0",
851 | "resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
852 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
853 | "dev": true,
854 | "bin": {
855 | "he": "bin/he"
856 | }
857 | },
858 | "node_modules/hookable": {
859 | "version": "5.5.3",
860 | "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz",
861 | "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
862 | },
863 | "node_modules/is-arrayish": {
864 | "version": "0.3.2",
865 | "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz",
866 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
867 | "dev": true
868 | },
869 | "node_modules/is-core-module": {
870 | "version": "2.16.1",
871 | "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
872 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
873 | "dev": true,
874 | "dependencies": {
875 | "hasown": "^2.0.2"
876 | },
877 | "engines": {
878 | "node": ">= 0.4"
879 | },
880 | "funding": {
881 | "url": "https://github.com/sponsors/ljharb"
882 | }
883 | },
884 | "node_modules/is-what": {
885 | "version": "4.1.16",
886 | "resolved": "https://registry.npmmirror.com/is-what/-/is-what-4.1.16.tgz",
887 | "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
888 | "engines": {
889 | "node": ">=12.13"
890 | },
891 | "funding": {
892 | "url": "https://github.com/sponsors/mesqueeb"
893 | }
894 | },
895 | "node_modules/magic-string": {
896 | "version": "0.30.17",
897 | "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz",
898 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
899 | "dependencies": {
900 | "@jridgewell/sourcemap-codec": "^1.5.0"
901 | }
902 | },
903 | "node_modules/minimatch": {
904 | "version": "9.0.5",
905 | "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz",
906 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
907 | "dev": true,
908 | "dependencies": {
909 | "brace-expansion": "^2.0.1"
910 | },
911 | "engines": {
912 | "node": ">=16 || 14 >=14.17"
913 | },
914 | "funding": {
915 | "url": "https://github.com/sponsors/isaacs"
916 | }
917 | },
918 | "node_modules/mitt": {
919 | "version": "3.0.1",
920 | "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
921 | "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
922 | },
923 | "node_modules/muggle-string": {
924 | "version": "0.3.1",
925 | "resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.3.1.tgz",
926 | "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
927 | "dev": true
928 | },
929 | "node_modules/nanoid": {
930 | "version": "3.3.8",
931 | "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz",
932 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
933 | "funding": [
934 | {
935 | "type": "github",
936 | "url": "https://github.com/sponsors/ai"
937 | }
938 | ],
939 | "bin": {
940 | "nanoid": "bin/nanoid.cjs"
941 | },
942 | "engines": {
943 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
944 | }
945 | },
946 | "node_modules/number-precision": {
947 | "version": "1.6.0",
948 | "resolved": "https://registry.npmmirror.com/number-precision/-/number-precision-1.6.0.tgz",
949 | "integrity": "sha512-05OLPgbgmnixJw+VvEh18yNPUo3iyp4BEWJcrLu4X9W05KmMifN7Mu5exYvQXqxxeNWhvIF+j3Rij+HmddM/hQ==",
950 | "dev": true
951 | },
952 | "node_modules/path-browserify": {
953 | "version": "1.0.1",
954 | "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz",
955 | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
956 | "dev": true
957 | },
958 | "node_modules/path-parse": {
959 | "version": "1.0.7",
960 | "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
961 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
962 | "dev": true
963 | },
964 | "node_modules/perfect-debounce": {
965 | "version": "1.0.0",
966 | "resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
967 | "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="
968 | },
969 | "node_modules/picocolors": {
970 | "version": "1.1.1",
971 | "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
972 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
973 | },
974 | "node_modules/pinia": {
975 | "version": "3.0.1",
976 | "resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.1.tgz",
977 | "integrity": "sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg==",
978 | "dependencies": {
979 | "@vue/devtools-api": "^7.7.2"
980 | },
981 | "funding": {
982 | "url": "https://github.com/sponsors/posva"
983 | },
984 | "peerDependencies": {
985 | "typescript": ">=4.4.4",
986 | "vue": "^2.7.0 || ^3.5.11"
987 | },
988 | "peerDependenciesMeta": {
989 | "typescript": {
990 | "optional": true
991 | }
992 | }
993 | },
994 | "node_modules/postcss": {
995 | "version": "8.5.2",
996 | "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.2.tgz",
997 | "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==",
998 | "funding": [
999 | {
1000 | "type": "opencollective",
1001 | "url": "https://opencollective.com/postcss/"
1002 | },
1003 | {
1004 | "type": "tidelift",
1005 | "url": "https://tidelift.com/funding/github/npm/postcss"
1006 | },
1007 | {
1008 | "type": "github",
1009 | "url": "https://github.com/sponsors/ai"
1010 | }
1011 | ],
1012 | "dependencies": {
1013 | "nanoid": "^3.3.8",
1014 | "picocolors": "^1.1.1",
1015 | "source-map-js": "^1.2.1"
1016 | },
1017 | "engines": {
1018 | "node": "^10 || ^12 || >=14"
1019 | }
1020 | },
1021 | "node_modules/resize-observer-polyfill": {
1022 | "version": "1.5.1",
1023 | "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
1024 | "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
1025 | "dev": true
1026 | },
1027 | "node_modules/resolve": {
1028 | "version": "1.22.10",
1029 | "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz",
1030 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
1031 | "dev": true,
1032 | "dependencies": {
1033 | "is-core-module": "^2.16.0",
1034 | "path-parse": "^1.0.7",
1035 | "supports-preserve-symlinks-flag": "^1.0.0"
1036 | },
1037 | "bin": {
1038 | "resolve": "bin/resolve"
1039 | },
1040 | "engines": {
1041 | "node": ">= 0.4"
1042 | },
1043 | "funding": {
1044 | "url": "https://github.com/sponsors/ljharb"
1045 | }
1046 | },
1047 | "node_modules/rfdc": {
1048 | "version": "1.4.1",
1049 | "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz",
1050 | "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
1051 | },
1052 | "node_modules/rollup": {
1053 | "version": "2.79.2",
1054 | "resolved": "https://registry.npmmirror.com/rollup/-/rollup-2.79.2.tgz",
1055 | "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
1056 | "dev": true,
1057 | "bin": {
1058 | "rollup": "dist/bin/rollup"
1059 | },
1060 | "engines": {
1061 | "node": ">=10.0.0"
1062 | },
1063 | "optionalDependencies": {
1064 | "fsevents": "~2.3.2"
1065 | }
1066 | },
1067 | "node_modules/scroll-into-view-if-needed": {
1068 | "version": "2.2.31",
1069 | "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
1070 | "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
1071 | "dev": true,
1072 | "dependencies": {
1073 | "compute-scroll-into-view": "^1.0.20"
1074 | }
1075 | },
1076 | "node_modules/semver": {
1077 | "version": "7.7.1",
1078 | "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.1.tgz",
1079 | "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
1080 | "dev": true,
1081 | "bin": {
1082 | "semver": "bin/semver.js"
1083 | },
1084 | "engines": {
1085 | "node": ">=10"
1086 | }
1087 | },
1088 | "node_modules/simple-swizzle": {
1089 | "version": "0.2.2",
1090 | "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
1091 | "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
1092 | "dev": true,
1093 | "dependencies": {
1094 | "is-arrayish": "^0.3.1"
1095 | }
1096 | },
1097 | "node_modules/source-map-js": {
1098 | "version": "1.2.1",
1099 | "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
1100 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1101 | "engines": {
1102 | "node": ">=0.10.0"
1103 | }
1104 | },
1105 | "node_modules/speakingurl": {
1106 | "version": "14.0.1",
1107 | "resolved": "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz",
1108 | "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
1109 | "engines": {
1110 | "node": ">=0.10.0"
1111 | }
1112 | },
1113 | "node_modules/superjson": {
1114 | "version": "2.2.2",
1115 | "resolved": "https://registry.npmmirror.com/superjson/-/superjson-2.2.2.tgz",
1116 | "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
1117 | "dependencies": {
1118 | "copy-anything": "^3.0.2"
1119 | },
1120 | "engines": {
1121 | "node": ">=16"
1122 | }
1123 | },
1124 | "node_modules/supports-preserve-symlinks-flag": {
1125 | "version": "1.0.0",
1126 | "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1127 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1128 | "dev": true,
1129 | "engines": {
1130 | "node": ">= 0.4"
1131 | },
1132 | "funding": {
1133 | "url": "https://github.com/sponsors/ljharb"
1134 | }
1135 | },
1136 | "node_modules/typescript": {
1137 | "version": "4.9.5",
1138 | "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz",
1139 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
1140 | "devOptional": true,
1141 | "bin": {
1142 | "tsc": "bin/tsc",
1143 | "tsserver": "bin/tsserver"
1144 | },
1145 | "engines": {
1146 | "node": ">=4.2.0"
1147 | }
1148 | },
1149 | "node_modules/undici-types": {
1150 | "version": "6.20.0",
1151 | "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz",
1152 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
1153 | "dev": true
1154 | },
1155 | "node_modules/vite": {
1156 | "version": "3.2.11",
1157 | "resolved": "https://registry.npmmirror.com/vite/-/vite-3.2.11.tgz",
1158 | "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==",
1159 | "dev": true,
1160 | "dependencies": {
1161 | "esbuild": "^0.15.9",
1162 | "postcss": "^8.4.18",
1163 | "resolve": "^1.22.1",
1164 | "rollup": "^2.79.1"
1165 | },
1166 | "bin": {
1167 | "vite": "bin/vite.js"
1168 | },
1169 | "engines": {
1170 | "node": "^14.18.0 || >=16.0.0"
1171 | },
1172 | "optionalDependencies": {
1173 | "fsevents": "~2.3.2"
1174 | },
1175 | "peerDependencies": {
1176 | "@types/node": ">= 14",
1177 | "less": "*",
1178 | "sass": "*",
1179 | "stylus": "*",
1180 | "sugarss": "*",
1181 | "terser": "^5.4.0"
1182 | },
1183 | "peerDependenciesMeta": {
1184 | "@types/node": {
1185 | "optional": true
1186 | },
1187 | "less": {
1188 | "optional": true
1189 | },
1190 | "sass": {
1191 | "optional": true
1192 | },
1193 | "stylus": {
1194 | "optional": true
1195 | },
1196 | "sugarss": {
1197 | "optional": true
1198 | },
1199 | "terser": {
1200 | "optional": true
1201 | }
1202 | }
1203 | },
1204 | "node_modules/vue": {
1205 | "version": "3.5.13",
1206 | "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz",
1207 | "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
1208 | "dependencies": {
1209 | "@vue/compiler-dom": "3.5.13",
1210 | "@vue/compiler-sfc": "3.5.13",
1211 | "@vue/runtime-dom": "3.5.13",
1212 | "@vue/server-renderer": "3.5.13",
1213 | "@vue/shared": "3.5.13"
1214 | },
1215 | "peerDependencies": {
1216 | "typescript": "*"
1217 | },
1218 | "peerDependenciesMeta": {
1219 | "typescript": {
1220 | "optional": true
1221 | }
1222 | }
1223 | },
1224 | "node_modules/vue-router": {
1225 | "version": "4.5.0",
1226 | "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz",
1227 | "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
1228 | "dependencies": {
1229 | "@vue/devtools-api": "^6.6.4"
1230 | },
1231 | "funding": {
1232 | "url": "https://github.com/sponsors/posva"
1233 | },
1234 | "peerDependencies": {
1235 | "vue": "^3.2.0"
1236 | }
1237 | },
1238 | "node_modules/vue-router/node_modules/@vue/devtools-api": {
1239 | "version": "6.6.4",
1240 | "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
1241 | "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
1242 | },
1243 | "node_modules/vue-template-compiler": {
1244 | "version": "2.7.16",
1245 | "resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
1246 | "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
1247 | "dev": true,
1248 | "dependencies": {
1249 | "de-indent": "^1.0.2",
1250 | "he": "^1.2.0"
1251 | }
1252 | },
1253 | "node_modules/vue-tsc": {
1254 | "version": "1.8.27",
1255 | "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-1.8.27.tgz",
1256 | "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==",
1257 | "dev": true,
1258 | "dependencies": {
1259 | "@volar/typescript": "~1.11.1",
1260 | "@vue/language-core": "1.8.27",
1261 | "semver": "^7.5.4"
1262 | },
1263 | "bin": {
1264 | "vue-tsc": "bin/vue-tsc.js"
1265 | },
1266 | "peerDependencies": {
1267 | "typescript": "*"
1268 | }
1269 | }
1270 | }
1271 | }
1272 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vue-tsc --noEmit && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "pinia": "^3.0.1",
13 | "vue": "^3.2.37",
14 | "vue-router": "^4.5.0"
15 | },
16 | "devDependencies": {
17 | "@arco-design/web-vue": "^2.56.3",
18 | "@babel/types": "^7.18.10",
19 | "@types/node": "^22.13.1",
20 | "@vitejs/plugin-vue": "^3.0.3",
21 | "typescript": "^4.6.4",
22 | "vite": "^3.0.7",
23 | "vue-tsc": "^1.8.27"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/package.json.md5:
--------------------------------------------------------------------------------
1 | 44ac666a86a54bb1225e566e5b8e8d26
--------------------------------------------------------------------------------
/frontend/src/App.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
11 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/frontend/src/assets/fonts/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2
--------------------------------------------------------------------------------
/frontend/src/assets/images/logo-universal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/frontend/src/assets/images/logo-universal.png
--------------------------------------------------------------------------------
/frontend/src/components/Config.vue:
--------------------------------------------------------------------------------
1 |
142 |
143 |
144 |
145 |
146 |
150 |
151 |
152 | 保存配置
157 |
158 |
159 |
160 |
161 |
162 | 秘钥配置:
163 |
164 |
165 |
166 |
167 |
172 |
173 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
191 |
192 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
213 |
214 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
232 |
233 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
253 |
254 |
255 |
256 |
257 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
271 |
272 |
273 |
274 |
275 |
281 | 所有
282 | 国内
283 | 国外
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
297 | 是
298 | 否
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/frontend/src/components/Fetch.vue:
--------------------------------------------------------------------------------
1 |
118 |
119 |
120 |
121 |
122 | 如欲使用Hunter等进行搜索,请先配置好Key哦
123 |
124 |
125 |
126 |
127 |
128 | 获取
129 | 使用
130 |
131 |
132 |
133 |
134 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/frontend/src/components/Panel.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
47 |
55 |
56 |
57 |
58 |
59 |
60 | 运行
61 |
62 |
63 |
64 |
65 |
66 | 获取
67 |
68 |
69 |
70 |
71 |
72 | 配置
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/frontend/src/components/Run.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
13 |
14 |
15 |
16 |
17 | 导入
24 |
25 | 停止
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
47 |
48 | 尚未测试
49 | 正在测试
50 | 测试完成
51 | 任务取消
52 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
运行日志
72 |
73 | {{ log }}
74 |
75 |
76 |
77 |
78 |
248 |
249 |
306 |
--------------------------------------------------------------------------------
/frontend/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { createPinia } from 'pinia';
3 | import ArcoVue from '@arco-design/web-vue';
4 | import ArcoVueIcon from '@arco-design/web-vue/es/icon';
5 | import { Notification } from '@arco-design/web-vue';
6 | import App from '@/App.vue';
7 | import '@arco-design/web-vue/dist/arco.css';
8 |
9 | const app = createApp(App);
10 | const pinia = createPinia();
11 |
12 | app.use(pinia)
13 | app.use(ArcoVue);
14 | app.use(ArcoVueIcon);
15 | Notification._context = app._context;
16 |
17 | app.mount('#app');
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src/store/types.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { GetProfile, SaveConfig, StopListening } from "../../wailsjs/go/client/App";
3 |
4 | export interface Config {
5 | Email: string;
6 | FofaKey: string;
7 | HunterKey: string;
8 | QuakeKey: string;
9 | Country: string;
10 | Maxpage: string; // 保持与 Go 中一致,字符串类型
11 |
12 | CoroutineCount: number;
13 | LiveProxies: number;
14 | AllProxies: number;
15 | LiveProxyLists: string[]; // 字符串数组类型
16 | Timeout: string; // 保持与 Go 中一致,字符串类型
17 | SocksAddress: string;
18 | FilePath: string;
19 |
20 | Status: number;
21 |
22 | Code: number;
23 | Error: string;
24 | GlobalProxy: string;
25 | }
26 |
27 |
28 |
29 | // 定义 Pinia store
30 | export const useConfigStore = defineStore('config', {
31 | state: () => ({
32 | Code: 0,
33 | Error: '',
34 | Status: 0,
35 | FilePath: '路径为空',
36 | CoroutineCount: 0,
37 | LiveProxies: 0,
38 | AllProxies: 0,
39 | Timeout: 0,
40 | SocksAddress: 'NULL',
41 | Email: "",
42 | FofaKey: "",
43 | HunterKey: "",
44 | QuakeKey: "",
45 | CheckTimeout: 0,
46 | Maxpage: 0,
47 | LiveProxyLists: [] as any[], // 可以根据实际数据改成具体类型
48 | Country: "0",
49 | GlobalProxy:"0"
50 | }),
51 |
52 | actions: {
53 | // 获取配置文件
54 | async getProfile() {
55 | try {
56 | const profile = await GetProfile();
57 | this.FilePath = profile.FilePath;
58 | this.CoroutineCount = profile.CoroutineCount;
59 | this.LiveProxies = profile.LiveProxies;
60 | this.AllProxies = profile.AllProxies;
61 | this.Timeout = Number(profile.Timeout);
62 | this.SocksAddress = profile.SocksAddress;
63 | this.Email = profile.Email;
64 | this.FofaKey = profile.FofaKey;
65 | this.HunterKey = profile.HunterKey;
66 | this.QuakeKey = profile.QuakeKey;
67 | this.Maxpage = Number(profile.Maxpage);
68 | this.Country = profile.Country;
69 | this.GlobalProxy=profile.GlobalProxy;
70 | } catch (err) {
71 | console.error("获取配置失败:", err);
72 | }
73 | },
74 |
75 | // 保存配置,传入参数类型明确
76 | async saveConfig(configData: Config): Promise {
77 | try {
78 | await SaveConfig(configData); // SaveConfig 应该接受 Config 类型
79 | console.log("配置已保存!");
80 | } catch (err) {
81 | console.error("保存失败:", err);
82 | }
83 | },
84 |
85 | // 新增的停止任务方法
86 | async stopTask() {
87 | try {
88 | this.setStatus(0); // 更新状态为停止中
89 | await StopListening(); // 调用后端的 stopListening 方法
90 | this.setStatus(3); // 更新任务状态为已取消
91 | } catch (err) {
92 | console.error("停止任务失败:", err);
93 | this.setStatus(1); // 设置为失败状态
94 | }
95 | },
96 |
97 | // 获取和设置方法
98 | getSocksAddress() {
99 | return this.SocksAddress;
100 | },
101 | setSocksAddress(socksAddress: string) {
102 | this.SocksAddress = socksAddress;
103 | },
104 | getTimeout() {
105 | return this.Timeout;
106 | },
107 | setTimeout(timeout: number) {
108 | this.Timeout = timeout;
109 | },
110 | getLiveProxies() {
111 | return this.LiveProxies;
112 | },
113 | getAllProxies() {
114 | return this.AllProxies;
115 | },
116 | getCoroutineCount() {
117 | return this.CoroutineCount;
118 | },
119 | setCoroutineCount(count: number) {
120 | this.CoroutineCount = count;
121 | },
122 | getFilePath() {
123 | return this.FilePath;
124 | },
125 | setFilePath(path: string) {
126 | this.FilePath = path;
127 | },
128 | getStatus() {
129 | return this.Status;
130 | },
131 | setStatus(status: number) {
132 | this.Status = status;
133 | },
134 | getEmail() {
135 | return this.Email;
136 | },
137 | setEmail(email: string) {
138 | this.Email = email;
139 | },
140 | getFofaKey() {
141 | return this.FofaKey;
142 | },
143 | setFofaKey(FofaKey: string) {
144 | this.FofaKey = FofaKey;
145 | },
146 | getHunterKey() {
147 | return this.HunterKey;
148 | },
149 | setHunterKey(HunterKey: string) {
150 | this.HunterKey = HunterKey;
151 | },
152 | getQuakeKey() {
153 | return this.QuakeKey;
154 | },
155 | setQuakeKey(QuakeKey: string) {
156 | this.QuakeKey = QuakeKey;
157 | },
158 | getCheckTimeout() {
159 | return this.CheckTimeout;
160 | },
161 | setCheckTimeout(timeout: number) {
162 | this.CheckTimeout = timeout;
163 | },
164 | getMaxpage() {
165 | return this.Maxpage;
166 | },
167 | setMaxpage(maxpage: number) {
168 | this.Maxpage = maxpage;
169 | },
170 | getCountry(){
171 | return this.Country;
172 | },
173 | setCountry(country: string) {
174 | this.Country = country;
175 | },
176 | getGlobalProxy(){
177 | return this.GlobalProxy;
178 | },
179 | setGlobalProxy(proxy: string) {
180 | this.GlobalProxy = proxy;
181 | }
182 | }
183 | });
184 |
--------------------------------------------------------------------------------
/frontend/src/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
4 | "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | }
7 |
8 | @font-face {
9 | font-family: "Nunito";
10 | font-style: normal;
11 | font-weight: 400;
12 | src: local(""),
13 | url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
14 | }
15 |
16 | #app {
17 | text-align: center;
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type {DefineComponent} from 'vue'
5 | const component: DefineComponent<{}, {}, any>
6 | export default component
7 | }
8 |
--------------------------------------------------------------------------------
/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["src/*"]
6 | },
7 | "target": "ESNext",
8 | "useDefineForClassFields": true,
9 | "module": "ESNext",
10 | "moduleResolution": "Node",
11 | "strict": true,
12 | "jsx": "preserve",
13 | "sourceMap": true,
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "esModuleInterop": true,
17 | "lib": [
18 | "ESNext",
19 | "DOM"
20 | ],
21 | "skipLibCheck": true
22 | },
23 | "include": [
24 | "src/**/*.ts",
25 | "src/**/*.d.ts",
26 | "src/**/*.tsx",
27 | "src/**/*.vue"
28 | ],
29 | "references": [
30 | {
31 | "path": "./tsconfig.node.json"
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/frontend/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": [
9 | "vite.config.ts"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/vite.config.ts:
--------------------------------------------------------------------------------
1 | import {defineConfig} from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import { resolve } from 'path';
4 |
5 |
6 | // https://vitejs.dev/config/
7 | export default defineConfig({
8 | plugins: [vue()],
9 | resolve: {
10 | alias: [
11 | {
12 | find: '@',
13 | replacement: resolve(__dirname, './src')
14 | }
15 | ]
16 | }
17 |
18 | })
19 |
--------------------------------------------------------------------------------
/frontend/wailsjs/go/client/App.d.ts:
--------------------------------------------------------------------------------
1 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
2 | // This file is automatically generated. DO NOT EDIT
3 | import {client} from '../models';
4 | import {config} from '../models';
5 |
6 | export function CheckDatasets():Promise;
7 |
8 | export function ChooseFile():Promise;
9 |
10 | export function Debug(arg1:Array):Promise;
11 |
12 | export function Error(arg1:Array):Promise;
13 |
14 | export function Fatal(arg1:Array):Promise;
15 |
16 | export function FetchProxies():Promise;
17 |
18 | export function GetProfile():Promise;
19 |
20 | export function Info(arg1:Array):Promise;
21 |
22 | export function SaveConfig(arg1:config.Config):Promise;
23 |
24 | export function StopListening():Promise;
25 |
26 | export function UseFetchedDatasets():Promise;
27 |
28 | export function Warn(arg1:Array):Promise;
29 |
--------------------------------------------------------------------------------
/frontend/wailsjs/go/client/App.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
3 | // This file is automatically generated. DO NOT EDIT
4 |
5 | export function CheckDatasets() {
6 | return window['go']['client']['App']['CheckDatasets']();
7 | }
8 |
9 | export function ChooseFile() {
10 | return window['go']['client']['App']['ChooseFile']();
11 | }
12 |
13 | export function Debug(arg1) {
14 | return window['go']['client']['App']['Debug'](arg1);
15 | }
16 |
17 | export function Error(arg1) {
18 | return window['go']['client']['App']['Error'](arg1);
19 | }
20 |
21 | export function Fatal(arg1) {
22 | return window['go']['client']['App']['Fatal'](arg1);
23 | }
24 |
25 | export function FetchProxies() {
26 | return window['go']['client']['App']['FetchProxies']();
27 | }
28 |
29 | export function GetProfile() {
30 | return window['go']['client']['App']['GetProfile']();
31 | }
32 |
33 | export function Info(arg1) {
34 | return window['go']['client']['App']['Info'](arg1);
35 | }
36 |
37 | export function SaveConfig(arg1) {
38 | return window['go']['client']['App']['SaveConfig'](arg1);
39 | }
40 |
41 | export function StopListening() {
42 | return window['go']['client']['App']['StopListening']();
43 | }
44 |
45 | export function UseFetchedDatasets() {
46 | return window['go']['client']['App']['UseFetchedDatasets']();
47 | }
48 |
49 | export function Warn(arg1) {
50 | return window['go']['client']['App']['Warn'](arg1);
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/wailsjs/go/models.ts:
--------------------------------------------------------------------------------
1 | export namespace client {
2 |
3 | export class Response {
4 | Code: number;
5 | Message: string;
6 | Data: any;
7 |
8 | static createFrom(source: any = {}) {
9 | return new Response(source);
10 | }
11 |
12 | constructor(source: any = {}) {
13 | if ('string' === typeof source) source = JSON.parse(source);
14 | this.Code = source["Code"];
15 | this.Message = source["Message"];
16 | this.Data = source["Data"];
17 | }
18 | }
19 |
20 | }
21 |
22 | export namespace config {
23 |
24 | export class Config {
25 | Email: string;
26 | FofaKey: string;
27 | HunterKey: string;
28 | QuakeKey: string;
29 | Country: string;
30 | Maxpage: string;
31 | CoroutineCount: number;
32 | LiveProxies: number;
33 | AllProxies: number;
34 | LiveProxyLists: string[];
35 | Timeout: string;
36 | SocksAddress: string;
37 | FilePath: string;
38 | Status: number;
39 | Code: number;
40 | Error: string;
41 | GlobalProxy: string;
42 |
43 | static createFrom(source: any = {}) {
44 | return new Config(source);
45 | }
46 |
47 | constructor(source: any = {}) {
48 | if ('string' === typeof source) source = JSON.parse(source);
49 | this.Email = source["Email"];
50 | this.FofaKey = source["FofaKey"];
51 | this.HunterKey = source["HunterKey"];
52 | this.QuakeKey = source["QuakeKey"];
53 | this.Country = source["Country"];
54 | this.Maxpage = source["Maxpage"];
55 | this.CoroutineCount = source["CoroutineCount"];
56 | this.LiveProxies = source["LiveProxies"];
57 | this.AllProxies = source["AllProxies"];
58 | this.LiveProxyLists = source["LiveProxyLists"];
59 | this.Timeout = source["Timeout"];
60 | this.SocksAddress = source["SocksAddress"];
61 | this.FilePath = source["FilePath"];
62 | this.Status = source["Status"];
63 | this.Code = source["Code"];
64 | this.Error = source["Error"];
65 | this.GlobalProxy = source["GlobalProxy"];
66 | }
67 | }
68 |
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/frontend/wailsjs/runtime/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@wailsapp/runtime",
3 | "version": "2.0.0",
4 | "description": "Wails Javascript runtime library",
5 | "main": "runtime.js",
6 | "types": "runtime.d.ts",
7 | "scripts": {
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/wailsapp/wails.git"
12 | },
13 | "keywords": [
14 | "Wails",
15 | "Javascript",
16 | "Go"
17 | ],
18 | "author": "Lea Anthony ",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/wailsapp/wails/issues"
22 | },
23 | "homepage": "https://github.com/wailsapp/wails#readme"
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/wailsjs/runtime/runtime.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | _ __ _ __
3 | | | / /___ _(_) /____
4 | | | /| / / __ `/ / / ___/
5 | | |/ |/ / /_/ / / (__ )
6 | |__/|__/\__,_/_/_/____/
7 | The electron alternative for Go
8 | (c) Lea Anthony 2019-present
9 | */
10 |
11 | export interface Position {
12 | x: number;
13 | y: number;
14 | }
15 |
16 | export interface Size {
17 | w: number;
18 | h: number;
19 | }
20 |
21 | export interface Screen {
22 | isCurrent: boolean;
23 | isPrimary: boolean;
24 | width : number
25 | height : number
26 | }
27 |
28 | // Environment information such as platform, buildtype, ...
29 | export interface EnvironmentInfo {
30 | buildType: string;
31 | platform: string;
32 | arch: string;
33 | }
34 |
35 | // [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
36 | // emits the given event. Optional data may be passed with the event.
37 | // This will trigger any event listeners.
38 | export function EventsEmit(eventName: string, ...data: any): void;
39 |
40 | // [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
41 | export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
42 |
43 | // [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
44 | // sets up a listener for the given event name, but will only trigger a given number times.
45 | export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
46 |
47 | // [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
48 | // sets up a listener for the given event name, but will only trigger once.
49 | export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
50 |
51 | // [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
52 | // unregisters the listener for the given event name.
53 | export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
54 |
55 | // [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
56 | // unregisters all listeners.
57 | export function EventsOffAll(): void;
58 |
59 | // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
60 | // logs the given message as a raw message
61 | export function LogPrint(message: string): void;
62 |
63 | // [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
64 | // logs the given message at the `trace` log level.
65 | export function LogTrace(message: string): void;
66 |
67 | // [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
68 | // logs the given message at the `debug` log level.
69 | export function LogDebug(message: string): void;
70 |
71 | // [LogError](https://wails.io/docs/reference/runtime/log#logerror)
72 | // logs the given message at the `error` log level.
73 | export function LogError(message: string): void;
74 |
75 | // [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
76 | // logs the given message at the `fatal` log level.
77 | // The application will quit after calling this method.
78 | export function LogFatal(message: string): void;
79 |
80 | // [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
81 | // logs the given message at the `info` log level.
82 | export function LogInfo(message: string): void;
83 |
84 | // [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
85 | // logs the given message at the `warning` log level.
86 | export function LogWarning(message: string): void;
87 |
88 | // [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
89 | // Forces a reload by the main application as well as connected browsers.
90 | export function WindowReload(): void;
91 |
92 | // [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
93 | // Reloads the application frontend.
94 | export function WindowReloadApp(): void;
95 |
96 | // [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
97 | // Sets the window AlwaysOnTop or not on top.
98 | export function WindowSetAlwaysOnTop(b: boolean): void;
99 |
100 | // [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
101 | // *Windows only*
102 | // Sets window theme to system default (dark/light).
103 | export function WindowSetSystemDefaultTheme(): void;
104 |
105 | // [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
106 | // *Windows only*
107 | // Sets window to light theme.
108 | export function WindowSetLightTheme(): void;
109 |
110 | // [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
111 | // *Windows only*
112 | // Sets window to dark theme.
113 | export function WindowSetDarkTheme(): void;
114 |
115 | // [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
116 | // Centers the window on the monitor the window is currently on.
117 | export function WindowCenter(): void;
118 |
119 | // [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
120 | // Sets the text in the window title bar.
121 | export function WindowSetTitle(title: string): void;
122 |
123 | // [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
124 | // Makes the window full screen.
125 | export function WindowFullscreen(): void;
126 |
127 | // [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
128 | // Restores the previous window dimensions and position prior to full screen.
129 | export function WindowUnfullscreen(): void;
130 |
131 | // [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
132 | // Returns the state of the window, i.e. whether the window is in full screen mode or not.
133 | export function WindowIsFullscreen(): Promise;
134 |
135 | // [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
136 | // Sets the width and height of the window.
137 | export function WindowSetSize(width: number, height: number): Promise;
138 |
139 | // [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
140 | // Gets the width and height of the window.
141 | export function WindowGetSize(): Promise;
142 |
143 | // [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
144 | // Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
145 | // Setting a size of 0,0 will disable this constraint.
146 | export function WindowSetMaxSize(width: number, height: number): void;
147 |
148 | // [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
149 | // Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
150 | // Setting a size of 0,0 will disable this constraint.
151 | export function WindowSetMinSize(width: number, height: number): void;
152 |
153 | // [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
154 | // Sets the window position relative to the monitor the window is currently on.
155 | export function WindowSetPosition(x: number, y: number): void;
156 |
157 | // [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
158 | // Gets the window position relative to the monitor the window is currently on.
159 | export function WindowGetPosition(): Promise;
160 |
161 | // [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
162 | // Hides the window.
163 | export function WindowHide(): void;
164 |
165 | // [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
166 | // Shows the window, if it is currently hidden.
167 | export function WindowShow(): void;
168 |
169 | // [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
170 | // Maximises the window to fill the screen.
171 | export function WindowMaximise(): void;
172 |
173 | // [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
174 | // Toggles between Maximised and UnMaximised.
175 | export function WindowToggleMaximise(): void;
176 |
177 | // [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
178 | // Restores the window to the dimensions and position prior to maximising.
179 | export function WindowUnmaximise(): void;
180 |
181 | // [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
182 | // Returns the state of the window, i.e. whether the window is maximised or not.
183 | export function WindowIsMaximised(): Promise;
184 |
185 | // [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
186 | // Minimises the window.
187 | export function WindowMinimise(): void;
188 |
189 | // [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
190 | // Restores the window to the dimensions and position prior to minimising.
191 | export function WindowUnminimise(): void;
192 |
193 | // [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
194 | // Returns the state of the window, i.e. whether the window is minimised or not.
195 | export function WindowIsMinimised(): Promise;
196 |
197 | // [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
198 | // Returns the state of the window, i.e. whether the window is normal or not.
199 | export function WindowIsNormal(): Promise;
200 |
201 | // [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
202 | // Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
203 | export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
204 |
205 | // [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
206 | // Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
207 | export function ScreenGetAll(): Promise;
208 |
209 | // [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
210 | // Opens the given URL in the system browser.
211 | export function BrowserOpenURL(url: string): void;
212 |
213 | // [Environment](https://wails.io/docs/reference/runtime/intro#environment)
214 | // Returns information about the environment
215 | export function Environment(): Promise;
216 |
217 | // [Quit](https://wails.io/docs/reference/runtime/intro#quit)
218 | // Quits the application.
219 | export function Quit(): void;
220 |
221 | // [Hide](https://wails.io/docs/reference/runtime/intro#hide)
222 | // Hides the application.
223 | export function Hide(): void;
224 |
225 | // [Show](https://wails.io/docs/reference/runtime/intro#show)
226 | // Shows the application.
227 | export function Show(): void;
228 |
229 | // [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
230 | // Returns the current text stored on clipboard
231 | export function ClipboardGetText(): Promise;
232 |
233 | // [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
234 | // Sets a text on the clipboard
235 | export function ClipboardSetText(text: string): Promise;
236 |
237 | // [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
238 | // OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
239 | export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
240 |
241 | // [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
242 | // OnFileDropOff removes the drag and drop listeners and handlers.
243 | export function OnFileDropOff() :void
244 |
245 | // Check if the file path resolver is available
246 | export function CanResolveFilePaths(): boolean;
247 |
248 | // Resolves file paths for an array of files
249 | export function ResolveFilePaths(files: File[]): void
--------------------------------------------------------------------------------
/frontend/wailsjs/runtime/runtime.js:
--------------------------------------------------------------------------------
1 | /*
2 | _ __ _ __
3 | | | / /___ _(_) /____
4 | | | /| / / __ `/ / / ___/
5 | | |/ |/ / /_/ / / (__ )
6 | |__/|__/\__,_/_/_/____/
7 | The electron alternative for Go
8 | (c) Lea Anthony 2019-present
9 | */
10 |
11 | export function LogPrint(message) {
12 | window.runtime.LogPrint(message);
13 | }
14 |
15 | export function LogTrace(message) {
16 | window.runtime.LogTrace(message);
17 | }
18 |
19 | export function LogDebug(message) {
20 | window.runtime.LogDebug(message);
21 | }
22 |
23 | export function LogInfo(message) {
24 | window.runtime.LogInfo(message);
25 | }
26 |
27 | export function LogWarning(message) {
28 | window.runtime.LogWarning(message);
29 | }
30 |
31 | export function LogError(message) {
32 | window.runtime.LogError(message);
33 | }
34 |
35 | export function LogFatal(message) {
36 | window.runtime.LogFatal(message);
37 | }
38 |
39 | export function EventsOnMultiple(eventName, callback, maxCallbacks) {
40 | return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
41 | }
42 |
43 | export function EventsOn(eventName, callback) {
44 | return EventsOnMultiple(eventName, callback, -1);
45 | }
46 |
47 | export function EventsOff(eventName, ...additionalEventNames) {
48 | return window.runtime.EventsOff(eventName, ...additionalEventNames);
49 | }
50 |
51 | export function EventsOnce(eventName, callback) {
52 | return EventsOnMultiple(eventName, callback, 1);
53 | }
54 |
55 | export function EventsEmit(eventName) {
56 | let args = [eventName].slice.call(arguments);
57 | return window.runtime.EventsEmit.apply(null, args);
58 | }
59 |
60 | export function WindowReload() {
61 | window.runtime.WindowReload();
62 | }
63 |
64 | export function WindowReloadApp() {
65 | window.runtime.WindowReloadApp();
66 | }
67 |
68 | export function WindowSetAlwaysOnTop(b) {
69 | window.runtime.WindowSetAlwaysOnTop(b);
70 | }
71 |
72 | export function WindowSetSystemDefaultTheme() {
73 | window.runtime.WindowSetSystemDefaultTheme();
74 | }
75 |
76 | export function WindowSetLightTheme() {
77 | window.runtime.WindowSetLightTheme();
78 | }
79 |
80 | export function WindowSetDarkTheme() {
81 | window.runtime.WindowSetDarkTheme();
82 | }
83 |
84 | export function WindowCenter() {
85 | window.runtime.WindowCenter();
86 | }
87 |
88 | export function WindowSetTitle(title) {
89 | window.runtime.WindowSetTitle(title);
90 | }
91 |
92 | export function WindowFullscreen() {
93 | window.runtime.WindowFullscreen();
94 | }
95 |
96 | export function WindowUnfullscreen() {
97 | window.runtime.WindowUnfullscreen();
98 | }
99 |
100 | export function WindowIsFullscreen() {
101 | return window.runtime.WindowIsFullscreen();
102 | }
103 |
104 | export function WindowGetSize() {
105 | return window.runtime.WindowGetSize();
106 | }
107 |
108 | export function WindowSetSize(width, height) {
109 | window.runtime.WindowSetSize(width, height);
110 | }
111 |
112 | export function WindowSetMaxSize(width, height) {
113 | window.runtime.WindowSetMaxSize(width, height);
114 | }
115 |
116 | export function WindowSetMinSize(width, height) {
117 | window.runtime.WindowSetMinSize(width, height);
118 | }
119 |
120 | export function WindowSetPosition(x, y) {
121 | window.runtime.WindowSetPosition(x, y);
122 | }
123 |
124 | export function WindowGetPosition() {
125 | return window.runtime.WindowGetPosition();
126 | }
127 |
128 | export function WindowHide() {
129 | window.runtime.WindowHide();
130 | }
131 |
132 | export function WindowShow() {
133 | window.runtime.WindowShow();
134 | }
135 |
136 | export function WindowMaximise() {
137 | window.runtime.WindowMaximise();
138 | }
139 |
140 | export function WindowToggleMaximise() {
141 | window.runtime.WindowToggleMaximise();
142 | }
143 |
144 | export function WindowUnmaximise() {
145 | window.runtime.WindowUnmaximise();
146 | }
147 |
148 | export function WindowIsMaximised() {
149 | return window.runtime.WindowIsMaximised();
150 | }
151 |
152 | export function WindowMinimise() {
153 | window.runtime.WindowMinimise();
154 | }
155 |
156 | export function WindowUnminimise() {
157 | window.runtime.WindowUnminimise();
158 | }
159 |
160 | export function WindowSetBackgroundColour(R, G, B, A) {
161 | window.runtime.WindowSetBackgroundColour(R, G, B, A);
162 | }
163 |
164 | export function ScreenGetAll() {
165 | return window.runtime.ScreenGetAll();
166 | }
167 |
168 | export function WindowIsMinimised() {
169 | return window.runtime.WindowIsMinimised();
170 | }
171 |
172 | export function WindowIsNormal() {
173 | return window.runtime.WindowIsNormal();
174 | }
175 |
176 | export function BrowserOpenURL(url) {
177 | window.runtime.BrowserOpenURL(url);
178 | }
179 |
180 | export function Environment() {
181 | return window.runtime.Environment();
182 | }
183 |
184 | export function Quit() {
185 | window.runtime.Quit();
186 | }
187 |
188 | export function Hide() {
189 | window.runtime.Hide();
190 | }
191 |
192 | export function Show() {
193 | window.runtime.Show();
194 | }
195 |
196 | export function ClipboardGetText() {
197 | return window.runtime.ClipboardGetText();
198 | }
199 |
200 | export function ClipboardSetText(text) {
201 | return window.runtime.ClipboardSetText(text);
202 | }
203 |
204 | /**
205 | * Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
206 | *
207 | * @export
208 | * @callback OnFileDropCallback
209 | * @param {number} x - x coordinate of the drop
210 | * @param {number} y - y coordinate of the drop
211 | * @param {string[]} paths - A list of file paths.
212 | */
213 |
214 | /**
215 | * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
216 | *
217 | * @export
218 | * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
219 | * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
220 | */
221 | export function OnFileDrop(callback, useDropTarget) {
222 | return window.runtime.OnFileDrop(callback, useDropTarget);
223 | }
224 |
225 | /**
226 | * OnFileDropOff removes the drag and drop listeners and handlers.
227 | */
228 | export function OnFileDropOff() {
229 | return window.runtime.OnFileDropOff();
230 | }
231 |
232 | export function CanResolveFilePaths() {
233 | return window.runtime.CanResolveFilePaths();
234 | }
235 |
236 | export function ResolveFilePaths(files) {
237 | return window.runtime.ResolveFilePaths(files);
238 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module doki-byte/FreeProxy
2 |
3 | go 1.22.3
4 |
5 | require (
6 | github.com/imroc/req/v3 v3.49.1
7 | github.com/labstack/gommon v0.4.2
8 | github.com/shirou/gopsutil/v3 v3.24.5
9 | github.com/wailsapp/wails/v2 v2.9.2
10 | )
11 |
12 | require (
13 | github.com/andybalholm/brotli v1.1.1 // indirect
14 | github.com/bep/debounce v1.2.1 // indirect
15 | github.com/cloudflare/circl v1.5.0 // indirect
16 | github.com/go-ole/go-ole v1.3.0 // indirect
17 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
18 | github.com/godbus/dbus/v5 v5.1.0 // indirect
19 | github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
20 | github.com/google/uuid v1.6.0 // indirect
21 | github.com/hashicorp/errwrap v1.1.0 // indirect
22 | github.com/hashicorp/go-multierror v1.1.1 // indirect
23 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
24 | github.com/klauspost/compress v1.17.11 // indirect
25 | github.com/labstack/echo/v4 v4.13.3 // indirect
26 | github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
27 | github.com/leaanthony/gosod v1.0.4 // indirect
28 | github.com/leaanthony/slicer v1.6.0 // indirect
29 | github.com/leaanthony/u v1.1.1 // indirect
30 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
31 | github.com/mattn/go-colorable v0.1.13 // indirect
32 | github.com/mattn/go-isatty v0.0.20 // indirect
33 | github.com/onsi/ginkgo/v2 v2.22.0 // indirect
34 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
35 | github.com/pkg/errors v0.9.1 // indirect
36 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
37 | github.com/quic-go/qpack v0.5.1 // indirect
38 | github.com/quic-go/quic-go v0.48.2 // indirect
39 | github.com/refraction-networking/utls v1.6.7 // indirect
40 | github.com/rivo/uniseg v0.4.7 // indirect
41 | github.com/samber/lo v1.49.1 // indirect
42 | github.com/shoenig/go-m1cpu v0.1.6 // indirect
43 | github.com/tklauser/go-sysconf v0.3.12 // indirect
44 | github.com/tklauser/numcpus v0.6.1 // indirect
45 | github.com/tkrajina/go-reflector v0.5.8 // indirect
46 | github.com/valyala/bytebufferpool v1.0.0 // indirect
47 | github.com/valyala/fasttemplate v1.2.2 // indirect
48 | github.com/wailsapp/go-webview2 v1.0.19 // indirect
49 | github.com/wailsapp/mimetype v1.4.1 // indirect
50 | github.com/yusufpapurcu/wmi v1.2.4 // indirect
51 | go.uber.org/mock v0.5.0 // indirect
52 | golang.org/x/crypto v0.33.0 // indirect
53 | golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
54 | golang.org/x/mod v0.23.0 // indirect
55 | golang.org/x/net v0.35.0 // indirect
56 | golang.org/x/sync v0.11.0 // indirect
57 | golang.org/x/sys v0.30.0 // indirect
58 | golang.org/x/text v0.22.0 // indirect
59 | golang.org/x/tools v0.30.0 // indirect
60 | )
61 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
2 | github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
3 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
4 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
5 | github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
6 | github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
10 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
11 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
12 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
13 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
14 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
15 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
16 | github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
17 | github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
18 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
19 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
20 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
21 | github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
22 | github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
23 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
24 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
25 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
26 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
27 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
28 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
29 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
30 | github.com/imroc/req/v3 v3.49.1 h1:Nvwo02riiPEzh74ozFHeEJrtjakFxnoWNR3YZYuQm9U=
31 | github.com/imroc/req/v3 v3.49.1/go.mod h1:tsOk8K7zI6cU4xu/VWCZVtq9Djw9IWm4MslKzme5woU=
32 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
33 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
34 | github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
35 | github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
36 | github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
37 | github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
38 | github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
39 | github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
40 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
41 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
42 | github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
43 | github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
44 | github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
45 | github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
46 | github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
47 | github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
48 | github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
49 | github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
50 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
51 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
52 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
53 | github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
54 | github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
55 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
56 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
57 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
58 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
59 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
60 | github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
61 | github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
62 | github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
63 | github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
64 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
65 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
66 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
67 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
68 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
69 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
70 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
71 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
72 | github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
73 | github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
74 | github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
75 | github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
76 | github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
77 | github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
78 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
79 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
80 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
81 | github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
82 | github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
83 | github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
84 | github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
85 | github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
86 | github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
87 | github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
88 | github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
89 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
90 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
91 | github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
92 | github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
93 | github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
94 | github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
95 | github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
96 | github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
97 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
98 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
99 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
100 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
101 | github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU=
102 | github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
103 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
104 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
105 | github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
106 | github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
107 | github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
108 | github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
109 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
110 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
111 | go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
112 | go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
113 | golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
114 | golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
115 | golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
116 | golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
117 | golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
118 | golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
119 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
120 | golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
121 | golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
122 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
123 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
124 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
125 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
126 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
127 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
128 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
129 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
130 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
131 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
132 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
133 | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
134 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
135 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
136 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
137 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
138 | golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
139 | golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
140 | golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
141 | golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
142 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
143 | golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
144 | golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
145 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
146 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
147 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
148 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
149 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
150 |
--------------------------------------------------------------------------------
/images/image-20250306224207882.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/images/image-20250306224207882.png
--------------------------------------------------------------------------------
/images/image-20250308152911121.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/images/image-20250308152911121.png
--------------------------------------------------------------------------------
/images/image-20250308152932210.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/images/image-20250308152932210.png
--------------------------------------------------------------------------------
/images/image-20250308153601293.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/images/image-20250308153601293.png
--------------------------------------------------------------------------------
/images/image-20250308153811761.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/doki-byte/FreeProxy/0782a1b5f06f0e5c80e87f23204c047113b991b8/images/image-20250308153811761.png
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "doki-byte/FreeProxy/backend/client"
5 | "embed"
6 | "github.com/wailsapp/wails/v2/pkg/options/linux"
7 | "github.com/wailsapp/wails/v2/pkg/options/mac"
8 |
9 | "github.com/wailsapp/wails/v2"
10 | "github.com/wailsapp/wails/v2/pkg/options"
11 | "github.com/wailsapp/wails/v2/pkg/options/assetserver"
12 | "github.com/wailsapp/wails/v2/pkg/options/windows"
13 | )
14 |
15 | //go:embed all:frontend/dist
16 | var assets embed.FS
17 |
18 | //go:embed build/appicon.png
19 | var icon []byte
20 |
21 | func main() {
22 | app := client.NewApp()
23 |
24 | err := wails.Run(&options.App{
25 | Title: "FreeProxy 一款简洁的代理池工具",
26 | Width: 750,
27 | Height: 768,
28 | //DisableResize: true,
29 | AssetServer: &assetserver.Options{
30 | Assets: assets,
31 | },
32 | OnStartup: app.Startup,
33 | OnShutdown: app.Shutdown,
34 | Bind: []interface{}{
35 | app,
36 | },
37 | Windows: &windows.Options{
38 | WebviewIsTransparent: false,
39 | WindowIsTranslucent: false,
40 | DisableFramelessWindowDecorations: true,
41 | },
42 | Mac: &mac.Options{
43 | TitleBar: mac.TitleBarDefault(),
44 | About: &mac.AboutInfo{
45 | Title: "FreeProxy",
46 | Message: "一款简洁的代理池工具",
47 | Icon: icon,
48 | },
49 | WebviewIsTransparent: false,
50 | WindowIsTranslucent: false,
51 | },
52 | Linux: &linux.Options{
53 | ProgramName: "FreeProxy",
54 | Icon: icon,
55 | WebviewGpuPolicy: linux.WebviewGpuPolicyOnDemand,
56 | WindowIsTranslucent: false,
57 | },
58 | })
59 |
60 | if err != nil {
61 | println("Error:", err.Error())
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/wails.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://wails.io/schemas/config.v2.json",
3 | "name": "FreeProxy",
4 | "outputfilename": "FreeProxy",
5 | "frontend:install": "npm install",
6 | "frontend:build": "npm run build",
7 | "frontend:dev:watcher": "npm run dev",
8 | "frontend:dev:serverUrl": "auto",
9 | "author": {
10 | "name": "MuHan",
11 | "email": ""
12 | }
13 | }
14 |
--------------------------------------------------------------------------------