├── .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 | image-20250308152911121 13 | 14 | + 参考其他师傅搜索引擎语法,目前适配获取fofa、hunter、quake平台数据。 15 | 16 | image-20250306224207882 17 | 18 | + 配置保存 19 | 20 | image-20250308152932210 21 | 22 | ## 代理配置 23 | 24 | 以火狐浏览器为例,下载FoxyProxy,点击添加,选择socks5协议 25 | 26 | ![image-20250308153601293](images/image-20250308153601293.png) 27 | 28 | 插件选择刚刚配置的代理即可 29 | ![image-20250308153811761](images/image-20250308153811761.png) 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 | 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 | 310 | 311 | -------------------------------------------------------------------------------- /frontend/src/components/Fetch.vue: -------------------------------------------------------------------------------- 1 | 118 | 119 | 142 | 143 | -------------------------------------------------------------------------------- /frontend/src/components/Panel.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 45 | 90 | 91 | -------------------------------------------------------------------------------- /frontend/src/components/Run.vue: -------------------------------------------------------------------------------- 1 | 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 | --------------------------------------------------------------------------------