├── .github └── workflows │ └── package-worker.yml ├── 2worker.zip ├── LICENSE ├── ProxyIP or ADD or ADDAPI ├── README.md ├── _worker.js ├── _worker.src.js ├── worker.old.zip └── worker.zip /.github/workflows/package-worker.yml: -------------------------------------------------------------------------------- 1 | name: Package Worker # 工作流程的名称 2 | 3 | on: # 触发事件 4 | workflow_dispatch: # 手动触发 5 | push: # 当代码被推送到仓库时触发 6 | paths: # 指定触发条件的文件路径 7 | - '_worker.js' # 当_worker.js文件发生变动时触发 8 | 9 | jobs: # 工作流程中的任务 10 | package-and-commit: # 任务名称 11 | runs-on: ubuntu-latest # 运行环境,这里使用最新版本的Ubuntu 12 | steps: # 任务步骤 13 | - name: Checkout Repository # 步骤名称,检出代码 14 | uses: actions/checkout@v2 # 使用actions/checkout动作 15 | 16 | - name: Zip the worker file # 将_worker.js文件打包成worker.zip 并备份上个版本zip文件 17 | run: | 18 | mv worker.zip worker.old.zip 19 | zip worker.zip _worker.js # 使用zip命令直接打包 20 | 21 | - name: Commit and push the packaged file # 提交并推送打包后的文件 22 | run: | 23 | git config --local user.email "action@github.com" 24 | git config --local user.name "GitHub Action" 25 | git add worker.zip worker.old.zip 26 | git commit -m "Automatically package and commit worker.zip" 27 | git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{github.repository}}.git 28 | git push 29 | -------------------------------------------------------------------------------- /2worker.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzhhh1/epeius/e8f59aae6c9d897d0d3ffb911b41df908150e974/2worker.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /ProxyIP or ADD or ADDAPI: -------------------------------------------------------------------------------- 1 | ProxyIP: 2 | workers.cloudflare.cyou 3 | my-telegram-is-herocore.onecf.eu.org 4 | 5 | ADD: 6 | acjp2.cloudflarest.link#加入我的频道https://t.me/kjgxZY获取更多免费VPN 7 | acsg.cloudflarest.link#加入我的频道https://t.me/kjgxZY获取更多免费VPN 8 | acsg3.cloudflarest.link#加入我的频道https://t.me/kjgxZY获取更多免费VPN 9 | bestcf.onecf.eu.org#官方优选域名-Mingyu大佬提供维护 10 | bestproxy.onecf.eu.org#反代优选域名-Mingyu大佬提供维护 11 | cfip.xxxxxxxx.tk#官方优选域名-OTC大佬提供维护 12 | proxy.xxxxxxxx.tk#反代优选域名-OTC大佬提供维护 13 | acjp2.cloudflarest.link:2053#反代优选域名-KJKKK大佬提供维护 14 | acsg.cloudflarest.link:2053#反代优选域名-KJKKK大佬提供维护 15 | acsg3.cloudflarest.link:2053#反代优选域名-KJKKK大佬提供维护 16 | xn--b6gac.eu.org#↗↘↗.eu.org官方优选域名 17 | cdn-all.xn--b6gac.eu.org#cdn-all.↗↘↗.eu.org官方优选域名 18 | cdn-b100.xn--b6gac.eu.org#cdn-b100.↗↘↗.eu.org反代优选域名 19 | time.cloudflare.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 20 | shopify.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 21 | time.is#加入我的频道https://t.me/kjgxZY获取更多免费VPN 22 | icook.hk#加入我的频道https://t.me/kjgxZY获取更多免费VPN 23 | icook.tw#加入我的频道https://t.me/kjgxZY获取更多免费VPN 24 | ip.sb#加入我的频道https://t.me/kjgxZY获取更多免费VPN 25 | japan.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 26 | malaysia.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 27 | russia.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 28 | singapore.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 29 | skk.moe#加入我的频道https://t.me/kjgxZY获取更多免费VPN 30 | www.visa.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 31 | www.visa.com.sg#加入我的频道https://t.me/kjgxZY获取更多免费VPN 32 | www.visa.com.hk#加入我的频道https://t.me/kjgxZY获取更多免费VPN 33 | www.visa.com.tw#加入我的频道https://t.me/kjgxZY获取更多免费VPN 34 | www.visa.co.jp#加入我的频道https://t.me/kjgxZY获取更多免费VPN 35 | www.visakorea.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 36 | www.gco.gov.qa#加入我的频道https://t.me/kjgxZY获取更多免费VPN 37 | www.gov.se#加入我的频道https://t.me/kjgxZY获取更多免费VPN 38 | www.gov.ua#加入我的频道https://t.me/kjgxZY获取更多免费VPN 39 | www.digitalocean.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 40 | www.csgo.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 41 | www.shopify.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 42 | www.whoer.net#加入我的频道https://t.me/kjgxZY获取更多免费VPN 43 | www.whatismyip.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 44 | www.ipget.net#加入我的频道https://t.me/kjgxZY获取更多免费VPN 45 | www.hugedomains.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 46 | www.udacity.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 47 | www.4chan.org#加入我的频道https://t.me/kjgxZY获取更多免费VPN 48 | www.okcupid.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 49 | www.glassdoor.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 50 | www.udemy.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 51 | alejandracaiccedo.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 52 | nc.gocada.co#加入我的频道https://t.me/kjgxZY获取更多免费VPN 53 | log.bpminecraft.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 54 | www.boba88slot.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 55 | gur.gov.ua#加入我的频道https://t.me/kjgxZY获取更多免费VPN 56 | www.zsu.gov.ua#加入我的频道https://t.me/kjgxZY获取更多免费VPN 57 | www.iakeys.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 58 | www.d-555.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 59 | fbi.gov#加入我的频道https://t.me/kjgxZY获取更多免费VPN 60 | wz.weishao2023.dk.eu.org#加入我的频道https://t.me/kjgxZY获取更多免费VPN 61 | cloudflare.cfgo.cc#加入我的频道https://t.me/kjgxZY获取更多免费VPN 62 | 086181.xyz#加入我的频道https://t.me/kjgxZY获取更多免费VPN 63 | stock.hostmonit.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 64 | www.lyzdzy.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 65 | xs.wxtv.cc#加入我的频道https://t.me/kjgxZY获取更多免费VPN 66 | cf.zmdhc.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 67 | www.90dushu.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 68 | www.tushencn.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 69 | 7sc.cc#加入我的频道https://t.me/kjgxZY获取更多免费VPN 70 | 0550cq.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 71 | www.xinpian8.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 72 | www.c333.net#加入我的频道https://t.me/kjgxZY获取更多免费VPN 73 | www.7749tv.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 74 | www.888dyy.cc#加入我的频道https://t.me/kjgxZY获取更多免费VPN 75 | manmankan.cc#加入我的频道https://t.me/kjgxZY获取更多免费VPN 76 | www.ddwhm.com#加入我的频道https://t.me/kjgxZY获取更多免费VPN 77 | 78 | ADDPAI: 79 | https://ipdb.api.030101.xyz/?type=bestproxy&country=true 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Worker 2 Trojan & Sub 2 | 这是一个基于 Cloudflare Worker 平台的脚本,在原版的基础上修改了显示 Trojan 配置信息转换为订阅内容。使用该脚本,你可以方便地将 Trojan 配置信息使用在线配置转换到 Clash 或 Singbox 等工具中。 3 | 4 | Telegram交流群:[@CMLiussss](https://t.me/kjgxZY) 5 | 6 | # 免责声明 7 | 8 | 本免责声明适用于 GitHub 上的 “epeius” 项目(以下简称“该项目”),项目链接为:https://github.com/cmliu/epeius 9 | 10 | ### 用途 11 | 该项目被设计和开发仅供学习、研究和安全测试目的。它旨在为安全研究者、学术界人士和技术爱好者提供一个了解和实践网络通信技术的工具。 12 | 13 | ### 合法性 14 | 使用者在下载和使用该项目时,必须遵守当地法律和规定。使用者有责任确保他们的行为符合其所在地区的法律、规章以及其他适用的规定。 15 | 16 | ### 免责 17 | 1. 作为该项目的作者,我(以下简称“作者”)强调该项目应仅用于合法、道德和教育目的。 18 | 2. 作者不鼓励、不支持也不促进任何形式的非法使用该项目。如果发现该项目被用于非法或不道德的活动,作者将强烈谴责这种行为。 19 | 3. 作者对任何人或团体使用该项目进行的任何非法活动不承担责任。使用者使用该项目时产生的任何后果由使用者本人承担。 20 | 4. 作者不对使用该项目可能引起的任何直接或间接损害负责。 21 | 5. 通过使用该项目,使用者表示理解并同意本免责声明的所有条款。如果使用者不同意这些条款,应立即停止使用该项目。 22 | 23 | 作者保留随时更新本免责声明的权利,且不另行通知。最新的免责声明版本将会在该项目的 GitHub 页面上发布。 24 | 25 | ## 风险提示 26 | - 通过提交虚假的节点配置给订阅服务,避免节点配置信息泄露。 27 | - 另外,您也可以选择自行部署 [WorkerVless2sub 订阅生成服务](https://github.com/cmliu/WorkerVless2sub),这样既可以利用订阅生成器的便利。 28 | 29 | ## Workers 部署方法 [视频教程](https://youtu.be/MBlAqYajVSY) 30 | 1. 部署 Cloudflare Worker: 31 | - 在 Cloudflare Worker 控制台中创建一个新的 Worker。 32 | - 将 [worker.js](https://github.com/cmliu/epeius/blob/main/_worker.js) 的内容粘贴到 Worker 编辑器中。 33 | - 将第 3 行 `password` 修改成你自己的 **密码** 34 | 35 | 2. 添加优选线路: 36 | - 给 `addresses` 按格式添加优选域名/优选IP,若不带端口号 TLS默认端口为443,#号后为备注别名,例如: 37 | ```js 38 | let addresses = [ 39 | //当sub为空时启用本地优选域名/优选IP 40 | 'www.visa.com.sg#官方优选域名', 41 | 'www.wto.org:8443#官方优选域名', 42 | 'www.csgo.com:2087', 43 | 'icook.hk', 44 | ]; 45 | ``` 46 | - 或 给 `sub` 添加 **Trojan优选订阅生成器** 地址,例如: 47 | ```js 48 | let sub = 'trojan.fxxk.dedyn.io'; 49 | ``` 50 | 51 | 3. 访问订阅内容: 52 | - 访问 `https://[YOUR-WORKERS-URL]/[PASSWORD]` 即可获取订阅内容。 53 | - 例如 `https://vless.google.workers.dev/auto` 就是你的通用自适应订阅地址。 54 | - 例如 `https://vless.google.workers.dev/auto?sub` Base64订阅格式,适用PassWall,SSR+等。 55 | - 例如 `https://vless.google.workers.dev/auto?clash` Clash订阅格式,适用OpenClash等。 56 | - 例如 `https://vless.google.workers.dev/auto?sb` singbox订阅格式,适用singbox等。 57 | 58 | 4. 给 workers绑定 自定义域: 59 | - 在 workers控制台的 `触发器`选项卡,下方点击 `添加自定义域`。 60 | - 填入你已转入 CloudFlare 域名解析服务的次级域名,例如:`vless.google.com`后 点击`添加自定义域`,等待证书生效即可。 61 | 62 | ## Pages 上传 部署方法 63 | 1. 部署 Cloudflare Pages: 64 | - 下载 [worker.zip](https://raw.githubusercontent.com/cmliu/epeius/main/worker.zip) 文件,并点上 Star !!! 65 | - 在 Cloudflare Pages 控制台中选择 `上传资产`后,为你的项目取名后点击 `创建项目`,然后上传你下载好的 [worker.zip](https://raw.githubusercontent.com/cmliu/epeius/main/worker.zip) 文件后点击 `部署站点`。 66 | - 部署完成后点击 `继续处理站点` 后,选择 `设置` > `环境变量` > **制作**为生产环境定义变量 > `添加变量`。 67 | 变量名称填写**PASSWORD**,值则为你的密码,后点击 `保存`即可。 68 | - 返回 `部署` 选项卡,在右下角点击 `创建新部署` 后,重新上传 [worker.zip](https://raw.githubusercontent.com/cmliu/epeius/main/worker.zip) 文件后点击 `保存并部署` 即可。 69 | 70 | 2. 添加优选线路: 71 | - 添加变量 `ADD` 本地静态的优选线路,若不带端口号 TLS默认端口为443,#号后为备注别名,例如: 72 | ``` 73 | cf.090227.xyz:443#加入我的频道t.me/CMLiussss解锁更多优选节点 74 | time.is#你可以只放域名 如下 75 | www.visa.com.sg 76 | skk.moe#也可以放域名带端口 如下 77 | www.wto.org:8443 78 | www.csgo.com:2087#节点名放在井号之后即可 79 | icook.hk#若不带端口号默认端口为443 80 | 104.17.152.41#IP也可以 81 | [2606:4700:e7:25:4b9:f8f8:9bfb:774a]#IPv6也OK 82 | ``` 83 | 84 | 3. 访问订阅内容: 85 | - 访问 `https://[YOUR-PAGES-URL]/[PASSWORD]` 即可获取订阅内容。 86 | - 例如 `https://epeius.pages.dev/auto` 就是你的通用自适应订阅地址。 87 | - 例如 `https://epeius.pages.dev/auto?sub` Base64订阅格式,适用PassWall,SSR+等。 88 | - 例如 `https://epeius.pages.dev/auto?clash` Clash订阅格式,适用OpenClash等。 89 | - 例如 `https://epeius.pages.dev/auto?sb` singbox订阅格式,适用singbox等。 90 | - 例如 `https://epeius.pages.dev/auto?surge` surge订阅格式,适用surge 4/5。 91 | 92 | 4. 给 Pages绑定 CNAME自定义域: 93 | - 在 Pages控制台的 `自定义域`选项卡,下方点击 `设置自定义域`。 94 | - 填入你的自定义次级域名,注意不要使用你的根域名,例如: 95 | 您分配到的域名是 `fuck.cloudns.biz`,则添加自定义域填入 `lizi.fuck.cloudns.biz`即可; 96 | - 按照 Cloudflare 的要求将返回你的域名DNS服务商,添加 该自定义域 `lizi`的 CNAME记录 `epeius.pages.dev` 后,点击 `激活域`即可。 97 | 98 | ## Pages GitHub 部署方法 99 | 1. 部署 Cloudflare Pages: 100 | - 在 Github 上先 Fork 本项目,并点上 Star !!! 101 | - 在 Cloudflare Pages 控制台中选择 `连接到 Git`后,选中 `epeius`项目后点击 `开始设置`。 102 | - 在 `设置构建和部署`页面下方,选择 `环境变量(高级)`后并 `添加变量`, 103 | 变量名称填写**PASSWORD**,值则为你的密码,后点击 `保存并部署`即可。 104 | 105 | 2. 添加优选线路: 106 | - 添加变量 `ADD` 本地静态的优选线路,若不带端口号 TLS默认端口为443,#号后为备注别名,例如: 107 | ``` 108 | cf.090227.xyz:443#加入我的频道t.me/CMLiussss解锁更多优选节点 109 | time.is#你可以只放域名 如下 110 | www.visa.com.sg 111 | skk.moe#也可以放域名带端口 如下 112 | www.wto.org:8443 113 | www.csgo.com:2087#节点名放在井号之后即可 114 | icook.hk#若不带端口号默认端口为443 115 | 104.17.152.41#IP也可以 116 | [2606:4700:e7:25:4b9:f8f8:9bfb:774a]#IPv6也OK 117 | ``` 118 | 119 | 3. 访问订阅内容: 120 | - 访问 `https://[YOUR-PAGES-URL]/[PASSWORD]` 即可获取订阅内容。 121 | - 例如 `https://epeius.pages.dev/auto` 就是你的通用自适应订阅地址。 122 | - 例如 `https://epeius.pages.dev/auto?sub` Base64订阅格式,适用PassWall,SSR+等。 123 | - 例如 `https://epeius.pages.dev/auto?clash` Clash订阅格式,适用OpenClash等。 124 | - 例如 `https://epeius.pages.dev/auto?sb` singbox订阅格式,适用singbox等。 125 | - 例如 `https://epeius.pages.dev/auto?surge` surge订阅格式,适用surge 4/5。 126 | 127 | 4. 给 Pages绑定 CNAME自定义域: 128 | - 在 Pages控制台的 `自定义域`选项卡,下方点击 `设置自定义域`。 129 | - 填入你的自定义次级域名,注意不要使用你的根域名,例如: 130 | 您分配到的域名是 `fuck.cloudns.biz`,则添加自定义域填入 `lizi.fuck.cloudns.biz`即可; 131 | - 按照 Cloudflare 的要求将返回你的域名DNS服务商,添加 该自定义域 `lizi`的 CNAME记录 `epeius.pages.dev` 后,点击 `激活域`即可。 132 | 133 | ## 变量说明 134 | | 变量名 | 示例 | 备注 | 135 | |--------|---------|-----| 136 | | PASSWORD | auto | 可以取任意值 | 137 | | PROXYIP | proxyip.fxxk.dedyn.io | 备选作为访问CloudFlareCDN站点的代理节点(支持多ProxyIP, ProxyIP之间使用`,`或 换行 作间隔) | 138 | | SOCKS5 | user:password@127.0.0.1:1080 | 优先作为访问CloudFlareCDN站点的SOCKS5代理 | 139 | | ADD | www.csgo.com:2087,icook.hk | 本地优选域名/优选IP(支持多元素之间`,`或 换行 作间隔) | 140 | | ADDAPI | [https://raw.github.../addressesapi.txt](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt) | 不解释, 懂得都懂 | 141 | | ADDCSV | [https://raw.github.../addressescsv.csv](https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressescsv.csv) | 不解释, 懂得都懂 | 142 | | DLS | 8 | `ADDCSV`测速结果满足速度下限 | 143 | | TGTOKEN | 6894123456:XXXXXXXXXX0qExVsBPUhHDAbXXXXXqWXgBA | 发送TG通知的机器人token | 144 | | TGID | 6946912345 | 接收TG通知的账户数字ID | 145 | | SUB | trojan.fxxk.dedyn.io | 优选订阅生成器地址(使用订阅器将放弃`ADD`内的本地优选订阅内容) | 146 | | SUBAPI | url.v1.mk | clash、singbox等 订阅转换后端 | 147 | | SUBCONFIG | [https://raw.github.../ACL4SSR_Online_Mini.ini](https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini.ini) | clash、singbox等 订阅转换配置文件 | 148 | | SUBNAME | epeius | 订阅名称 | 149 | | RPROXYIP | false | 设为 true 即可强制获取订阅器分配的ProxyIP(需订阅器支持)| 150 | | URL302 | https://t.me/CMLiussss | 主页302跳转(支持多url, url之间使用`,`或 换行 作间隔, 小白别用) | 151 | | URL | https://t.me/CMLiussss | 主页伪装(支持多url, url之间使用`,`或 换行 作间隔, 乱设容易触发反诈) | 152 | | CFEMAIL | admin@gmail.com | CF账户邮箱(与`CFKEY`都填上后, 订阅信息将显示请求使用量, 小白别用) | 153 | | CFKEY | c6a944b5c956b6c18c2352880952bced8b85e | CF账户Global API Key(与`CFEMAIL`都填上后, 订阅信息将显示请求使用量, 小白别用) | 154 | 155 | **注意: 填入`SOCKS5`后将不再启用`PROXYIP`!请二选一使用!!!** 156 | 157 | **注意: 填入`SUB`后将不再启用`ADD*`类变量生成的订阅内容!请二选一使用!!!** 158 | 159 | **注意: 同时填入`CFEMAIL`和`CFKEY`才会启用显示请求使用量,但是不推荐使用!没必要给一个Worker项目这么高的权限!后果自负!!!** 160 | 161 | ## 实用小技巧 162 | 163 | **该项目部署的节点可通过节点PATH(路径)的方式,使用指定的`PROXYIP`或`SOCKS5`!!!** 164 | 165 | - 指定 `PROXYIP` 案例 166 | ```url 167 | /proxyip=proxyip.fxxk.dedyn.io 168 | /?proxyip=proxyip.fxxk.dedyn.io 169 | /proxyip.fxxk.dedyn.io (仅限于域名开头为'proxyip.'的域名) 170 | ``` 171 | 172 | - 指定 `SOCKS5` 案例 173 | ```url 174 | /socks5=user:password@127.0.0.1:1080 175 | /?socks5=user:password@127.0.0.1:1080 176 | /socks://dXNlcjpwYXNzd29yZA==@127.0.0.1:1080 177 | /socks5://user:password@127.0.0.1:1080 178 | ``` 179 | 180 | ## Star 星星走起 181 | [![Stargazers over time](https://starchart.cc/cmliu/epeius.svg?variant=adaptive)](https://starchart.cc/cmliu/epeius) 182 | 183 | # 感谢 184 | [ca110us](https://github.com/ca110us/epeius)、[xream](https://github.com/xream)、[3Kmfi6HP](https://github.com/3Kmfi6HP/EDtunnel/tree/trojan)、[zizifn](https://github.com/zizifn/edgetunnel)、[emn178](https://github.com/emn178/js-sha256)、[ACL4SSR](https://github.com/ACL4SSR/ACL4SSR/tree/master/Clash/config)、[SHIJS1999](https://github.com/SHIJS1999/cloudflare-worker-vless-ip)、 185 | -------------------------------------------------------------------------------- /_worker.src.js: -------------------------------------------------------------------------------- 1 | // worker.src.js 2 | import { connect } from "cloudflare:sockets"; 3 | let password = 'auto'; 4 | let proxyIP = ''; 5 | // The user name and password do not contain special characters 6 | // Setting the address will ignore proxyIP 7 | // Example: user:pass@host:port or host:port 8 | let socks5Address = ''; 9 | 10 | let addresses = [ 11 | //当sub为空时启用本地优选域名/优选IP,若不带端口号 TLS默认端口为443,#号后为备注别名 12 | 'cf.090227.xyz:443#加入我的频道t.me/CMLiussss解锁更多优选节点', 13 | 'time.is#你可以只放域名 如下', 14 | 'www.visa.com.sg', 15 | 'skk.moe#也可以放域名带端口 如下', 16 | 'www.wto.org:8443', 17 | 'www.csgo.com:2087#节点名放在井号之后即可', 18 | 'icook.hk#若不带端口号默认端口为443', 19 | '104.17.152.41#IP也可以', 20 | '[2606:4700:e7:25:4b9:f8f8:9bfb:774a]#IPv6也OK', 21 | ]; 22 | 23 | let sub = ''; 24 | let subconverter = 'url.v1.mk';// clash订阅转换后端,目前使用肥羊的订阅转换功能。自带虚假节点信息防泄露 25 | let subconfig = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini.ini"; //订阅配置文件 26 | let RproxyIP = 'false'; 27 | 28 | let addressesapi = []; 29 | let addressescsv = []; 30 | let DLS = 8; 31 | 32 | let FileName = 'epeius'; 33 | let BotToken =''; 34 | let ChatID =''; 35 | let proxyhosts = [];//本地代理域名池 36 | let proxyhostsURL = 'https://raw.githubusercontent.com/cmliu/CFcdnVmess2sub/main/proxyhosts';//在线代理域名池URL 37 | 38 | let fakeUserID ; 39 | let fakeHostName ; 40 | let proxyIPs ; 41 | let sha224Password ; 42 | const expire = 4102329600;//2099-12-31 43 | const regex = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[.*\]):?(\d+)?#?(.*)?$/; 44 | 45 | /* 46 | if (!isValidSHA224(sha224Password)) { 47 | throw new Error('sha224Password is not valid'); 48 | } 49 | */ 50 | 51 | let parsedSocks5Address = {}; 52 | let enableSocks = false; 53 | 54 | export default { 55 | async fetch(request, env, ctx) { 56 | try { 57 | const UA = request.headers.get('User-Agent') || 'null'; 58 | const userAgent = UA.toLowerCase(); 59 | proxyIP = env.PROXYIP || proxyIP; 60 | proxyIPs = await ADD(proxyIP); 61 | proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; 62 | socks5Address = env.SOCKS5 || socks5Address; 63 | if (socks5Address) { 64 | try { 65 | parsedSocks5Address = socks5AddressParser(socks5Address); 66 | RproxyIP = env.RPROXYIP || 'false'; 67 | enableSocks = true; 68 | } catch (err) { 69 | /** @type {Error} */ 70 | let e = err; 71 | console.log(e.toString()); 72 | RproxyIP = env.RPROXYIP || !proxyIP ? 'true' : 'false'; 73 | enableSocks = false; 74 | } 75 | } else { 76 | RproxyIP = env.RPROXYIP || !proxyIP ? 'true' : 'false'; 77 | } 78 | password = env.PASSWORD || password; 79 | sha224Password = env.SHA224 || env.SHA224PASS || sha256.sha224(password); 80 | //console.log(sha224Password); 81 | 82 | const url = new URL(request.url); 83 | const upgradeHeader = request.headers.get("Upgrade"); 84 | if (env.ADD) addresses = await ADD(env.ADD); 85 | if (env.ADDAPI) addressesapi = await ADD(env.ADDAPI); 86 | if (env.ADDCSV) addressescsv = await ADD(env.ADDCSV); 87 | DLS = env.DLS || DLS; 88 | BotToken = env.TGTOKEN || BotToken; 89 | ChatID = env.TGID || ChatID; 90 | sub = env.SUB || sub; 91 | subconverter = env.SUBAPI || subconverter; 92 | subconfig = env.SUBCONFIG || subconfig; 93 | FileName = env.SUBNAME || FileName; 94 | RproxyIP = env.RPROXYIP || !proxyIP ? 'true' : 'false'; 95 | 96 | const currentDate = new Date(); 97 | currentDate.setHours(0, 0, 0, 0); // 设置时间为当天 98 | const timestamp = Math.ceil(currentDate.getTime() / 1000); 99 | const fakeUserIDMD5 = await MD5MD5(`${password}${timestamp}`); 100 | fakeUserID = fakeUserIDMD5.slice(0, 8) + "-" + fakeUserIDMD5.slice(8, 12) + "-" + fakeUserIDMD5.slice(12, 16) + "-" + fakeUserIDMD5.slice(16, 20) + "-" + fakeUserIDMD5.slice(20); 101 | fakeHostName = fakeUserIDMD5.slice(6, 9) + "." + fakeUserIDMD5.slice(13, 19); 102 | //console.log(fakeUserID); // 打印fakeID 103 | 104 | if (!upgradeHeader || upgradeHeader !== "websocket") { 105 | //const url = new URL(request.url); 106 | switch (url.pathname) { 107 | case '/': 108 | const envKey = env.URL302 ? 'URL302' : (env.URL ? 'URL' : null); 109 | if (envKey) { 110 | const URLs = await ADD(env[envKey]); 111 | const URL = URLs[Math.floor(Math.random() * URLs.length)]; 112 | return envKey === 'URL302' ? Response.redirect(URL, 302) : fetch(new Request(URL, request)); 113 | } 114 | return new Response(JSON.stringify(request.cf, null, 4), { status: 200 }); 115 | case `/${fakeUserID}`: 116 | const fakeConfig = await getTrojanConfig(password, request.headers.get('Host'), sub, 'CF-Workers-SUB', RproxyIP, url); 117 | return new Response(`${fakeConfig}`, { status: 200 }); 118 | case `/${password}`: 119 | await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${UA}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); 120 | const trojanConfig = await getTrojanConfig(password, request.headers.get('Host'), sub, UA, RproxyIP, url); 121 | const now = Date.now(); 122 | //const timestamp = Math.floor(now / 1000); 123 | const today = new Date(now); 124 | today.setHours(0, 0, 0, 0); 125 | const UD = Math.floor(((now - today.getTime())/86400000) * 24 * 1099511627776 / 2); 126 | let pagesSum = UD; 127 | let workersSum = UD; 128 | let total = 24 * 1099511627776 ; 129 | if (env.CFEMAIL && env.CFKEY){ 130 | const email = env.CFEMAIL; 131 | const key = env.CFKEY; 132 | const accountIndex = env.CFID || 0; 133 | const accountId = await getAccountId(email, key); 134 | if (accountId){ 135 | const now = new Date() 136 | now.setUTCHours(0, 0, 0, 0) 137 | const startDate = now.toISOString() 138 | const endDate = new Date().toISOString(); 139 | const Sum = await getSum(accountId, accountIndex, email, key, startDate, endDate); 140 | pagesSum = Sum[0]; 141 | workersSum = Sum[1]; 142 | total = 102400 ; 143 | } 144 | } 145 | //console.log(`pagesSum: ${pagesSum}\nworkersSum: ${workersSum}\ntotal: ${total}`); 146 | if (userAgent && (userAgent.includes('mozilla') || userAgent.includes('subconverter'))){ 147 | return new Response(`${trojanConfig}`, { 148 | status: 200, 149 | headers: { 150 | "Content-Type": "text/plain;charset=utf-8", 151 | "Profile-Update-Interval": "6", 152 | "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, 153 | } 154 | }); 155 | } else { 156 | return new Response(`${trojanConfig}`, { 157 | status: 200, 158 | headers: { 159 | "Content-Disposition": `attachment; filename=${FileName}; filename*=utf-8''${encodeURIComponent(FileName)}`, 160 | "Content-Type": "text/plain;charset=utf-8", 161 | "Profile-Update-Interval": "6", 162 | "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, 163 | } 164 | }); 165 | } 166 | default: 167 | return new Response("Incorrect password!!!", { status: 404 }); 168 | } 169 | } else { 170 | proxyIP = url.searchParams.get('proxyip') || proxyIP; 171 | if (new RegExp('/proxyip=', 'i').test(url.pathname)) proxyIP = url.pathname.toLowerCase().split('/proxyip=')[1]; 172 | else if (new RegExp('/proxyip.', 'i').test(url.pathname)) proxyIP = `proxyip.${url.pathname.toLowerCase().split("/proxyip.")[1]}`; 173 | else if (!proxyIP || proxyIP == '') proxyIP = 'proxyip.fxxk.dedyn.io'; 174 | 175 | socks5Address = url.searchParams.get('socks5') || socks5Address; 176 | if (new RegExp('/socks5=', 'i').test(url.pathname)) socks5Address = url.pathname.split('5=')[1]; 177 | else if (new RegExp('/socks://', 'i').test(url.pathname) || new RegExp('/socks5://', 'i').test(url.pathname)) { 178 | socks5Address = url.pathname.split('://')[1].split('#')[0]; 179 | if (socks5Address.includes('@')){ 180 | let userPassword = socks5Address.split('@')[0]; 181 | const base64Regex = /^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$/i; 182 | if (base64Regex.test(userPassword) && !userPassword.includes(':')) userPassword = atob(userPassword); 183 | socks5Address = `${userPassword}@${socks5Address.split('@')[1]}`; 184 | } 185 | } 186 | if (socks5Address) { 187 | try { 188 | parsedSocks5Address = socks5AddressParser(socks5Address); 189 | enableSocks = true; 190 | } catch (err) { 191 | /** @type {Error} */ 192 | let e = err; 193 | console.log(e.toString()); 194 | enableSocks = false; 195 | } 196 | } else { 197 | enableSocks = false; 198 | } 199 | return await trojanOverWSHandler(request); 200 | } 201 | } catch (err) { 202 | let e = err; 203 | return new Response(e.toString()); 204 | } 205 | } 206 | }; 207 | 208 | async function trojanOverWSHandler(request) { 209 | const webSocketPair = new WebSocketPair(); 210 | const [client, webSocket] = Object.values(webSocketPair); 211 | webSocket.accept(); 212 | let address = ""; 213 | let portWithRandomLog = ""; 214 | const log = (info, event) => { 215 | console.log(`[${address}:${portWithRandomLog}] ${info}`, event || ""); 216 | }; 217 | const earlyDataHeader = request.headers.get("sec-websocket-protocol") || ""; 218 | const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log); 219 | let remoteSocketWapper = { 220 | value: null 221 | }; 222 | let udpStreamWrite = null; 223 | readableWebSocketStream.pipeTo(new WritableStream({ 224 | async write(chunk, controller) { 225 | if (udpStreamWrite) { 226 | return udpStreamWrite(chunk); 227 | } 228 | if (remoteSocketWapper.value) { 229 | const writer = remoteSocketWapper.value.writable.getWriter(); 230 | await writer.write(chunk); 231 | writer.releaseLock(); 232 | return; 233 | } 234 | const { 235 | hasError, 236 | message, 237 | portRemote = 443, 238 | addressRemote = "", 239 | rawClientData, 240 | addressType 241 | } = await parseTrojanHeader(chunk); 242 | address = addressRemote; 243 | portWithRandomLog = `${portRemote}--${Math.random()} tcp`; 244 | if (hasError) { 245 | throw new Error(message); 246 | return; 247 | } 248 | handleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, log, addressType); 249 | }, 250 | close() { 251 | log(`readableWebSocketStream is closed`); 252 | }, 253 | abort(reason) { 254 | log(`readableWebSocketStream is aborted`, JSON.stringify(reason)); 255 | } 256 | })).catch((err) => { 257 | log("readableWebSocketStream pipeTo error", err); 258 | }); 259 | return new Response(null, { 260 | status: 101, 261 | // @ts-ignore 262 | webSocket: client 263 | }); 264 | } 265 | 266 | async function parseTrojanHeader(buffer) { 267 | if (buffer.byteLength < 56) { 268 | return { 269 | hasError: true, 270 | message: "invalid data" 271 | }; 272 | } 273 | let crLfIndex = 56; 274 | if (new Uint8Array(buffer.slice(56, 57))[0] !== 0x0d || new Uint8Array(buffer.slice(57, 58))[0] !== 0x0a) { 275 | return { 276 | hasError: true, 277 | message: "invalid header format (missing CR LF)" 278 | }; 279 | } 280 | const password = new TextDecoder().decode(buffer.slice(0, crLfIndex)); 281 | if (password !== sha224Password) { 282 | return { 283 | hasError: true, 284 | message: "invalid password" 285 | }; 286 | } 287 | 288 | const socks5DataBuffer = buffer.slice(crLfIndex + 2); 289 | if (socks5DataBuffer.byteLength < 6) { 290 | return { 291 | hasError: true, 292 | message: "invalid SOCKS5 request data" 293 | }; 294 | } 295 | 296 | const view = new DataView(socks5DataBuffer); 297 | const cmd = view.getUint8(0); 298 | if (cmd !== 1) { 299 | return { 300 | hasError: true, 301 | message: "unsupported command, only TCP (CONNECT) is allowed" 302 | }; 303 | } 304 | 305 | const atype = view.getUint8(1); 306 | // 0x01: IPv4 address 307 | // 0x03: Domain name 308 | // 0x04: IPv6 address 309 | let addressLength = 0; 310 | let addressIndex = 2; 311 | let address = ""; 312 | switch (atype) { 313 | case 1: 314 | addressLength = 4; 315 | address = new Uint8Array( 316 | socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) 317 | ).join("."); 318 | break; 319 | case 3: 320 | addressLength = new Uint8Array( 321 | socks5DataBuffer.slice(addressIndex, addressIndex + 1) 322 | )[0]; 323 | addressIndex += 1; 324 | address = new TextDecoder().decode( 325 | socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) 326 | ); 327 | break; 328 | case 4: 329 | addressLength = 16; 330 | const dataView = new DataView(socks5DataBuffer.slice(addressIndex, addressIndex + addressLength)); 331 | const ipv6 = []; 332 | for (let i = 0; i < 8; i++) { 333 | ipv6.push(dataView.getUint16(i * 2).toString(16)); 334 | } 335 | address = ipv6.join(":"); 336 | break; 337 | default: 338 | return { 339 | hasError: true, 340 | message: `invalid addressType is ${atype}` 341 | }; 342 | } 343 | 344 | if (!address) { 345 | return { 346 | hasError: true, 347 | message: `address is empty, addressType is ${atype}` 348 | }; 349 | } 350 | 351 | const portIndex = addressIndex + addressLength; 352 | const portBuffer = socks5DataBuffer.slice(portIndex, portIndex + 2); 353 | const portRemote = new DataView(portBuffer).getUint16(0); 354 | return { 355 | hasError: false, 356 | addressRemote: address, 357 | portRemote, 358 | rawClientData: socks5DataBuffer.slice(portIndex + 4), 359 | addressType: atype 360 | }; 361 | } 362 | 363 | async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, log, addressType) { 364 | async function connectAndWrite(address, port, socks = false) { 365 | const tcpSocket2 = socks ? await socks5Connect(addressType, address, port, log) 366 | : connect({ 367 | hostname: address, 368 | port 369 | }); 370 | remoteSocket.value = tcpSocket2; 371 | log(`connected to ${address}:${port}`); 372 | const writer = tcpSocket2.writable.getWriter(); 373 | await writer.write(rawClientData); 374 | writer.releaseLock(); 375 | return tcpSocket2; 376 | } 377 | async function retry() { 378 | let tcpSocket2 379 | if (enableSocks) { 380 | tcpSocket2 = await connectAndWrite(addressRemote, portRemote, true); 381 | } else { 382 | tcpSocket2 = await connectAndWrite(proxyIP || addressRemote, portRemote); 383 | } 384 | tcpSocket2.closed.catch((error) => { 385 | console.log("retry tcpSocket closed error", error); 386 | }).finally(() => { 387 | safeCloseWebSocket(webSocket); 388 | }); 389 | remoteSocketToWS(tcpSocket2, webSocket, null, log); 390 | } 391 | const tcpSocket = await connectAndWrite(addressRemote, portRemote); 392 | remoteSocketToWS(tcpSocket, webSocket, retry, log); 393 | } 394 | 395 | function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) { 396 | let readableStreamCancel = false; 397 | const stream = new ReadableStream({ 398 | start(controller) { 399 | webSocketServer.addEventListener("message", (event) => { 400 | if (readableStreamCancel) { 401 | return; 402 | } 403 | const message = event.data; 404 | controller.enqueue(message); 405 | }); 406 | webSocketServer.addEventListener("close", () => { 407 | safeCloseWebSocket(webSocketServer); 408 | if (readableStreamCancel) { 409 | return; 410 | } 411 | controller.close(); 412 | }); 413 | webSocketServer.addEventListener("error", (err) => { 414 | log("webSocketServer error"); 415 | controller.error(err); 416 | }); 417 | const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader); 418 | if (error) { 419 | controller.error(error); 420 | } else if (earlyData) { 421 | controller.enqueue(earlyData); 422 | } 423 | }, 424 | pull(controller) {}, 425 | cancel(reason) { 426 | if (readableStreamCancel) { 427 | return; 428 | } 429 | log(`readableStream was canceled, due to ${reason}`); 430 | readableStreamCancel = true; 431 | safeCloseWebSocket(webSocketServer); 432 | } 433 | }); 434 | return stream; 435 | } 436 | 437 | async function remoteSocketToWS(remoteSocket, webSocket, retry, log) { 438 | let hasIncomingData = false; 439 | await remoteSocket.readable.pipeTo( 440 | new WritableStream({ 441 | start() {}, 442 | /** 443 | * 444 | * @param {Uint8Array} chunk 445 | * @param {*} controller 446 | */ 447 | async write(chunk, controller) { 448 | hasIncomingData = true; 449 | if (webSocket.readyState !== WS_READY_STATE_OPEN) { 450 | controller.error( 451 | "webSocket connection is not open" 452 | ); 453 | } 454 | webSocket.send(chunk); 455 | }, 456 | close() { 457 | log(`remoteSocket.readable is closed, hasIncomingData: ${hasIncomingData}`); 458 | }, 459 | abort(reason) { 460 | console.error("remoteSocket.readable abort", reason); 461 | } 462 | }) 463 | ).catch((error) => { 464 | console.error( 465 | `remoteSocketToWS error:`, 466 | error.stack || error 467 | ); 468 | safeCloseWebSocket(webSocket); 469 | }); 470 | if (hasIncomingData === false && retry) { 471 | log(`retry`); 472 | retry(); 473 | } 474 | } 475 | /* 476 | function isValidSHA224(hash) { 477 | const sha224Regex = /^[0-9a-f]{56}$/i; 478 | return sha224Regex.test(hash); 479 | } 480 | */ 481 | function base64ToArrayBuffer(base64Str) { 482 | if (!base64Str) { 483 | return { error: null }; 484 | } 485 | try { 486 | base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/"); 487 | const decode = atob(base64Str); 488 | const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0)); 489 | return { earlyData: arryBuffer.buffer, error: null }; 490 | } catch (error) { 491 | return { error }; 492 | } 493 | } 494 | 495 | let WS_READY_STATE_OPEN = 1; 496 | let WS_READY_STATE_CLOSING = 2; 497 | 498 | function safeCloseWebSocket(socket) { 499 | try { 500 | if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) { 501 | socket.close(); 502 | } 503 | } catch (error) { 504 | console.error("safeCloseWebSocket error", error); 505 | } 506 | } 507 | 508 | /* 509 | export { 510 | worker_default as 511 | default 512 | }; 513 | //# sourceMappingURL=worker.js.map 514 | */ 515 | 516 | function revertFakeInfo(content, userID, hostName, isBase64) { 517 | if (isBase64) content = atob(content);//Base64解码 518 | content = content.replace(new RegExp(fakeUserID, 'g'), userID).replace(new RegExp(fakeHostName, 'g'), hostName); 519 | //console.log(content); 520 | if (isBase64) content = btoa(content);//Base64编码 521 | 522 | return content; 523 | } 524 | 525 | async function MD5MD5(text) { 526 | const encoder = new TextEncoder(); 527 | 528 | const firstPass = await crypto.subtle.digest('MD5', encoder.encode(text)); 529 | const firstPassArray = Array.from(new Uint8Array(firstPass)); 530 | const firstHex = firstPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); 531 | 532 | const secondPass = await crypto.subtle.digest('MD5', encoder.encode(firstHex.slice(7, 27))); 533 | const secondPassArray = Array.from(new Uint8Array(secondPass)); 534 | const secondHex = secondPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); 535 | 536 | return secondHex.toLowerCase(); 537 | } 538 | 539 | async function ADD(envadd) { 540 | var addtext = envadd.replace(/[ |"'\r\n]+/g, ',').replace(/,+/g, ','); // 双引号、单引号和换行符替换为逗号 541 | //console.log(addtext); 542 | if (addtext.charAt(0) == ',') addtext = addtext.slice(1); 543 | if (addtext.charAt(addtext.length -1) == ',') addtext = addtext.slice(0, addtext.length - 1); 544 | const add = addtext.split(','); 545 | //console.log(add); 546 | return add ; 547 | } 548 | 549 | function 配置信息(密码, 域名地址) { 550 | const 啥啥啥_写的这是啥啊 = 'dHJvamFu'; 551 | const 协议类型 = atob(啥啥啥_写的这是啥啊); 552 | 553 | const 别名 = 域名地址; 554 | let 地址 = 域名地址; 555 | let 端口 = 443; 556 | 557 | const 传输层协议 = 'ws'; 558 | const 伪装域名 = 域名地址; 559 | const 路径 = '/?ed=2560'; 560 | 561 | let 传输层安全 = ['tls',true]; 562 | const SNI = 域名地址; 563 | const 指纹 = 'randomized'; 564 | 565 | const v2ray = `${协议类型}://${encodeURIComponent(密码)}@${地址}:${端口}?security=${传输层安全[0]}&sni=${SNI}&fp=${指纹}&type=${传输层协议}&host=${伪装域名}&path=${encodeURIComponent(路径)}#${encodeURIComponent(别名)}` 566 | const clash = `- {name: ${别名}, server: ${地址}, port: ${端口}, udp: false, client-fingerprint: ${指纹}, type: ${协议类型}, password: ${密码}, sni: ${SNI}, skip-cert-verify: true, network: ${传输层协议}, ws-opts: {path: ${路径}, headers: {Host: ${伪装域名}}}}`; 567 | 568 | return [v2ray,clash]; 569 | } 570 | 571 | let subParams = ['sub','base64','b64','clash','singbox','sb','surge']; 572 | async function getTrojanConfig(password, hostName, sub, UA, RproxyIP, _url) { 573 | const userAgent = UA.toLowerCase(); 574 | const Config = 配置信息(password , hostName); 575 | const v2ray = Config[0]; 576 | const clash = Config[1]; 577 | 578 | if ( userAgent.includes('mozilla') && !subParams.some(_searchParams => _url.searchParams.has(_searchParams))) { 579 | let surge = `Surge订阅地址:\nhttps://${hostName}/${password}?surge`; 580 | if (hostName.includes(".workers.dev") || hostName.includes(".pages.dev")) surge = "Surge订阅必须绑定自定义域"; 581 | 582 | let 订阅器 = `您的订阅内容由 ${sub} 提供维护支持, 自动获取ProxyIP: ${RproxyIP}`; 583 | if (!sub || sub == '') { 584 | if (!proxyIP || proxyIP =='') { 585 | 订阅器 = '您的订阅内容由 内置 addresses/ADD 参数提供, 当前使用的ProxyIP为空, 推荐您设置 proxyIP/PROXYIP !!!'; 586 | } else { 587 | 订阅器 = `您的订阅内容由 内置 addresses/ADD 参数提供, 当前使用的ProxyIP: ${proxyIPs.join(',')}`; 588 | } 589 | } else if (RproxyIP != 'true'){ 590 | 订阅器 += `, 当前使用的ProxyIP: ${proxyIPs.join(',')}`; 591 | } 592 | return ` 593 | ################################################################ 594 | Subscribe / sub 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式, ${订阅器} 595 | --------------------------------------------------------------- 596 | 快速自适应订阅地址: 597 | https://${hostName}/${password} 598 | 599 | Base64订阅地址: 600 | https://${hostName}/${password}?sub 601 | https://${hostName}/${password}?b64 602 | https://${hostName}/${password}?base64 603 | 604 | clash订阅地址: 605 | https://${hostName}/${password}?clash 606 | 607 | singbox订阅地址: 608 | https://${hostName}/${password}?sb 609 | https://${hostName}/${password}?singbox 610 | 611 | ${surge} 612 | --------------------------------------------------------------- 613 | ################################################################ 614 | v2ray 615 | --------------------------------------------------------------- 616 | ${v2ray} 617 | --------------------------------------------------------------- 618 | ################################################################ 619 | clash-meta 620 | --------------------------------------------------------------- 621 | ${clash} 622 | --------------------------------------------------------------- 623 | ################################################################ 624 | telegram 交流群 技术大佬~在线发牌! 625 | https://t.me/CMLiussss 626 | --------------------------------------------------------------- 627 | github 项目地址 Star!Star!Star!!! 628 | https://github.com/cmliu/epeius 629 | --------------------------------------------------------------- 630 | ################################################################ 631 | `; 632 | } else { 633 | if (typeof fetch != 'function') { 634 | return 'Error: fetch is not available in this environment.'; 635 | } 636 | // 如果是使用默认域名,则改成一个workers的域名,订阅器会加上代理 637 | if (hostName.includes(".workers.dev") || hostName.includes(".pages.dev")){ 638 | fakeHostName = `${fakeHostName}.workers.dev`; 639 | } else { 640 | fakeHostName = `${fakeHostName}.xyz` 641 | } 642 | 643 | let url = `https://${sub}/sub?host=${fakeHostName}&pw=${fakeUserID}&password=${fakeUserID}&epeius=cmliu&proxyip=${RproxyIP}`; 644 | let isBase64 = true; 645 | let newAddressesapi; 646 | let newAddressescsv; 647 | 648 | if (!sub || sub == "") { 649 | if(hostName.includes('workers.dev') || hostName.includes('pages.dev')) { 650 | if (proxyhostsURL && (!proxyhosts || proxyhosts.length == 0)) { 651 | try { 652 | const response = await fetch(proxyhostsURL); 653 | 654 | if (!response.ok) { 655 | console.error('获取地址时出错:', response.status, response.statusText); 656 | return; // 如果有错误,直接返回 657 | } 658 | 659 | const text = await response.text(); 660 | const lines = text.split('\n'); 661 | // 过滤掉空行或只包含空白字符的行 662 | const nonEmptyLines = lines.filter(line => line.trim() !== ''); 663 | 664 | proxyhosts = proxyhosts.concat(nonEmptyLines); 665 | } catch (error) { 666 | console.error('获取地址时出错:', error); 667 | } 668 | } 669 | // 使用Set对象去重 670 | proxyhosts = [...new Set(proxyhosts)]; 671 | } 672 | 673 | newAddressesapi = await getAddressesapi(addressesapi); 674 | newAddressescsv = await getAddressescsv('TRUE'); 675 | url = `https://${hostName}/${fakeUserID}`; 676 | } 677 | 678 | if (!userAgent.includes(('CF-Workers-SUB').toLowerCase())){ 679 | if ((userAgent.includes('clash') && !userAgent.includes('nekobox')) || ( _url.searchParams.has('clash'))) { 680 | url = `https://${subconverter}/sub?target=clash&url=${encodeURIComponent(url)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; 681 | isBase64 = false; 682 | } else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || _url.searchParams.has('singbox') || _url.searchParams.has('sb')) { 683 | url = `https://${subconverter}/sub?target=singbox&url=${encodeURIComponent(url)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; 684 | isBase64 = false; 685 | } else if (userAgent.includes('surge') || _url.searchParams.has('surge')) { 686 | url = `https://${subconverter}/sub?target=surge&ver=4&url=${encodeURIComponent(url)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&xudp=false&udp=false&tfo=false&expand=true&scv=true&fdn=false`; 687 | isBase64 = false; 688 | } 689 | } 690 | 691 | try { 692 | let content; 693 | if ((!sub || sub == "") && isBase64 == true) { 694 | content = await subAddresses(fakeHostName,fakeUserID,userAgent,newAddressesapi,newAddressescsv); 695 | } else { 696 | const response = await fetch(url ,{ 697 | headers: { 698 | 'User-Agent': `CF-Workers-epeius/cmliu` 699 | }}); 700 | content = await response.text(); 701 | } 702 | 703 | if (!_url.pathname.includes(`/${fakeUserID}`)) { 704 | content = revertFakeInfo(content, password, hostName, isBase64); 705 | if (userAgent.includes('surge') || _url.searchParams.has('surge')) content = surge(content, `https://${hostName}/${password}?surge`); 706 | } 707 | return content; 708 | } catch (error) { 709 | console.error('Error fetching content:', error); 710 | return `Error fetching content: ${error.message}`; 711 | } 712 | } 713 | } 714 | 715 | async function sendMessage(type, ip, add_data = "") { 716 | if ( BotToken !== '' && ChatID !== ''){ 717 | let msg = ""; 718 | const response = await fetch(`http://ip-api.com/json/${ip}?lang=zh-CN`); 719 | if (response.status == 200) { 720 | const ipInfo = await response.json(); 721 | msg = `${type}\nIP: ${ip}\n国家: ${ipInfo.country}\n城市: ${ipInfo.city}\n组织: ${ipInfo.org}\nASN: ${ipInfo.as}\n${add_data}`; 722 | } else { 723 | msg = `${type}\nIP: ${ip}\n${add_data}`; 724 | } 725 | 726 | let url = "https://api.telegram.org/bot"+ BotToken +"/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg); 727 | return fetch(url, { 728 | method: 'get', 729 | headers: { 730 | 'Accept': 'text/html,application/xhtml+xml,application/xml;', 731 | 'Accept-Encoding': 'gzip, deflate, br', 732 | 'User-Agent': 'Mozilla/5.0 Chrome/90.0.4430.72' 733 | } 734 | }); 735 | } 736 | } 737 | 738 | function subAddresses(host,pw,userAgent,newAddressesapi,newAddressescsv) { 739 | addresses = addresses.concat(newAddressesapi); 740 | addresses = addresses.concat(newAddressescsv); 741 | // 使用Set对象去重 742 | const uniqueAddresses = [...new Set(addresses)]; 743 | 744 | const responseBody = uniqueAddresses.map(address => { 745 | let port = "443"; 746 | let addressid = address; 747 | 748 | const match = addressid.match(regex); 749 | if (!match) { 750 | if (address.includes(':') && address.includes('#')) { 751 | const parts = address.split(':'); 752 | address = parts[0]; 753 | const subParts = parts[1].split('#'); 754 | port = subParts[0]; 755 | addressid = subParts[1]; 756 | } else if (address.includes(':')) { 757 | const parts = address.split(':'); 758 | address = parts[0]; 759 | port = parts[1]; 760 | } else if (address.includes('#')) { 761 | const parts = address.split('#'); 762 | address = parts[0]; 763 | addressid = parts[1]; 764 | } 765 | 766 | if (addressid.includes(':')) { 767 | addressid = addressid.split(':')[0]; 768 | } 769 | } else { 770 | address = match[1]; 771 | port = match[2] || port; 772 | addressid = match[3] || address; 773 | } 774 | 775 | let 伪装域名 = host ; 776 | let 最终路径 = '/?ed=2560' ; 777 | let 节点备注 = ''; 778 | 779 | if(proxyhosts.length > 0 && (伪装域名.includes('.workers.dev') || 伪装域名.includes('pages.dev'))) { 780 | 最终路径 = `/${伪装域名}${最终路径}`; 781 | 伪装域名 = proxyhosts[Math.floor(Math.random() * proxyhosts.length)]; 782 | 节点备注 = ` 已启用临时域名中转服务,请尽快绑定自定义域!`; 783 | } 784 | 785 | let 密码 = pw; 786 | if (!userAgent.includes('subconverter')) 密码 = encodeURIComponent(pw); 787 | 788 | const 啥啥啥_写的这是啥啊 = 'dHJvamFu'; 789 | const 协议类型 = atob(啥啥啥_写的这是啥啊); 790 | const trojanLink = `${协议类型}://${密码}@${address}:${port}?security=tls&sni=${伪装域名}&fp=randomized&type=ws&host=${伪装域名}&path=${encodeURIComponent(最终路径)}#${encodeURIComponent(addressid + 节点备注)}`; 791 | 792 | return trojanLink; 793 | }).join('\n'); 794 | 795 | const base64Response = btoa(responseBody); // 重新进行 Base64 编码 796 | 797 | return base64Response; 798 | } 799 | 800 | async function getAddressesapi(api) { 801 | if (!api || api.length === 0) { 802 | return []; 803 | } 804 | 805 | let newapi = ""; 806 | 807 | // 创建一个AbortController对象,用于控制fetch请求的取消 808 | const controller = new AbortController(); 809 | 810 | const timeout = setTimeout(() => { 811 | controller.abort(); // 取消所有请求 812 | }, 2000); // 2秒后触发 813 | 814 | try { 815 | // 使用Promise.allSettled等待所有API请求完成,无论成功或失败 816 | // 对api数组进行遍历,对每个API地址发起fetch请求 817 | const responses = await Promise.allSettled(api.map(apiUrl => fetch(apiUrl, { 818 | method: 'get', 819 | headers: { 820 | 'Accept': 'text/html,application/xhtml+xml,application/xml;', 821 | 'User-Agent': 'CF-Workers-epeius/cmliu' 822 | }, 823 | signal: controller.signal // 将AbortController的信号量添加到fetch请求中,以便于需要时可以取消请求 824 | }).then(response => response.ok ? response.text() : Promise.reject()))); 825 | 826 | // 遍历所有响应 827 | for (const response of responses) { 828 | // 检查响应状态是否为'fulfilled',即请求成功完成 829 | if (response.status === 'fulfilled') { 830 | // 获取响应的内容 831 | const content = await response.value; 832 | newapi += content + '\n'; 833 | } 834 | } 835 | } catch (error) { 836 | console.error(error); 837 | } finally { 838 | // 无论成功或失败,最后都清除设置的超时定时器 839 | clearTimeout(timeout); 840 | } 841 | 842 | const newAddressesapi = await ADD(newapi); 843 | 844 | // 返回处理后的结果 845 | return newAddressesapi; 846 | } 847 | 848 | async function getAddressescsv(tls) { 849 | if (!addressescsv || addressescsv.length === 0) { 850 | return []; 851 | } 852 | 853 | let newAddressescsv = []; 854 | 855 | for (const csvUrl of addressescsv) { 856 | try { 857 | const response = await fetch(csvUrl); 858 | 859 | if (!response.ok) { 860 | console.error('获取CSV地址时出错:', response.status, response.statusText); 861 | continue; 862 | } 863 | 864 | const text = await response.text();// 使用正确的字符编码解析文本内容 865 | let lines; 866 | if (text.includes('\r\n')){ 867 | lines = text.split('\r\n'); 868 | } else { 869 | lines = text.split('\n'); 870 | } 871 | 872 | // 检查CSV头部是否包含必需字段 873 | const header = lines[0].split(','); 874 | const tlsIndex = header.indexOf('TLS'); 875 | const speedIndex = header.length - 1; // 最后一个字段 876 | 877 | const ipAddressIndex = 0;// IP地址在 CSV 头部的位置 878 | const portIndex = 1;// 端口在 CSV 头部的位置 879 | const dataCenterIndex = tlsIndex + 1; // 数据中心是 TLS 的后一个字段 880 | 881 | if (tlsIndex === -1) { 882 | console.error('CSV文件缺少必需的字段'); 883 | continue; 884 | } 885 | 886 | // 从第二行开始遍历CSV行 887 | for (let i = 1; i < lines.length; i++) { 888 | const columns = lines[i].split(','); 889 | 890 | // 检查TLS是否为"TRUE"且速度大于DLS 891 | if (columns[tlsIndex].toUpperCase() === tls && parseFloat(columns[speedIndex]) > DLS) { 892 | const ipAddress = columns[ipAddressIndex]; 893 | const port = columns[portIndex]; 894 | const dataCenter = columns[dataCenterIndex]; 895 | 896 | const formattedAddress = `${ipAddress}:${port}#${dataCenter}`; 897 | newAddressescsv.push(formattedAddress); 898 | } 899 | } 900 | } catch (error) { 901 | console.error('获取CSV地址时出错:', error); 902 | continue; 903 | } 904 | } 905 | 906 | return newAddressescsv; 907 | } 908 | 909 | function surge(content, url) { 910 | let 每行内容; 911 | if (content.includes('\r\n')){ 912 | 每行内容 = content.split('\r\n'); 913 | } else { 914 | 每行内容 = content.split('\n'); 915 | } 916 | 917 | let 输出内容 = ""; 918 | for (let x of 每行内容) { 919 | if (x.includes('= trojan,')) { 920 | const host = x.split("sni=")[1].split(",")[0]; 921 | const 备改内容 = `skip-cert-verify=true, tfo=false, udp-relay=false`; 922 | const 正确内容 = `skip-cert-verify=true, ws=true, ws-path=/?ed=2560, ws-headers=Host:"${host}", tfo=false, udp-relay=false`; 923 | 输出内容 += x.replace(new RegExp(备改内容, 'g'), 正确内容).replace("[", "").replace("]", "") + '\n'; 924 | } else { 925 | 输出内容 += x + '\n'; 926 | } 927 | } 928 | 929 | 输出内容 = `#!MANAGED-CONFIG ${url} interval=86400 strict=false` + 输出内容.substring(输出内容.indexOf('\n')); 930 | return 输出内容; 931 | } 932 | 933 | /** 934 | * [js-sha256]{@link https://github.com/emn178/js-sha256} 935 | * 936 | * @version 0.11.0 937 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 938 | * @copyright Chen, Yi-Cyuan 2014-2024 939 | * @license MIT 940 | */ 941 | /*jslint bitwise: true */ 942 | (function () { 943 | 'use strict'; 944 | 945 | var ERROR = 'input is invalid type'; 946 | var WINDOW = typeof window === 'object'; 947 | var root = WINDOW ? window : {}; 948 | if (root.JS_SHA256_NO_WINDOW) { 949 | WINDOW = false; 950 | } 951 | var WEB_WORKER = !WINDOW && typeof self === 'object'; 952 | var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; 953 | if (NODE_JS) { 954 | root = global; 955 | } else if (WEB_WORKER) { 956 | root = self; 957 | } 958 | var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports; 959 | var AMD = typeof define === 'function' && define.amd; 960 | var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; 961 | var HEX_CHARS = '0123456789abcdef'.split(''); 962 | var EXTRA = [-2147483648, 8388608, 32768, 128]; 963 | var SHIFT = [24, 16, 8, 0]; 964 | var K = [ 965 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 966 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 967 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 968 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 969 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 970 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 971 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 972 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 973 | ]; 974 | var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer']; 975 | 976 | var blocks = []; 977 | 978 | if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) { 979 | Array.isArray = function (obj) { 980 | return Object.prototype.toString.call(obj) === '[object Array]'; 981 | }; 982 | } 983 | 984 | if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { 985 | ArrayBuffer.isView = function (obj) { 986 | return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; 987 | }; 988 | } 989 | 990 | var createOutputMethod = function (outputType, is224) { 991 | return function (message) { 992 | return new Sha256(is224, true).update(message)[outputType](); 993 | }; 994 | }; 995 | 996 | var createMethod = function (is224) { 997 | var method = createOutputMethod('hex', is224); 998 | if (NODE_JS) { 999 | method = nodeWrap(method, is224); 1000 | } 1001 | method.create = function () { 1002 | return new Sha256(is224); 1003 | }; 1004 | method.update = function (message) { 1005 | return method.create().update(message); 1006 | }; 1007 | for (var i = 0; i < OUTPUT_TYPES.length; ++i) { 1008 | var type = OUTPUT_TYPES[i]; 1009 | method[type] = createOutputMethod(type, is224); 1010 | } 1011 | return method; 1012 | }; 1013 | 1014 | var nodeWrap = function (method, is224) { 1015 | var crypto = require('crypto') 1016 | var Buffer = require('buffer').Buffer; 1017 | var algorithm = is224 ? 'sha224' : 'sha256'; 1018 | var bufferFrom; 1019 | if (Buffer.from && !root.JS_SHA256_NO_BUFFER_FROM) { 1020 | bufferFrom = Buffer.from; 1021 | } else { 1022 | bufferFrom = function (message) { 1023 | return new Buffer(message); 1024 | }; 1025 | } 1026 | var nodeMethod = function (message) { 1027 | if (typeof message === 'string') { 1028 | return crypto.createHash(algorithm).update(message, 'utf8').digest('hex'); 1029 | } else { 1030 | if (message === null || message === undefined) { 1031 | throw new Error(ERROR); 1032 | } else if (message.constructor === ArrayBuffer) { 1033 | message = new Uint8Array(message); 1034 | } 1035 | } 1036 | if (Array.isArray(message) || ArrayBuffer.isView(message) || 1037 | message.constructor === Buffer) { 1038 | return crypto.createHash(algorithm).update(bufferFrom(message)).digest('hex'); 1039 | } else { 1040 | return method(message); 1041 | } 1042 | }; 1043 | return nodeMethod; 1044 | }; 1045 | 1046 | var createHmacOutputMethod = function (outputType, is224) { 1047 | return function (key, message) { 1048 | return new HmacSha256(key, is224, true).update(message)[outputType](); 1049 | }; 1050 | }; 1051 | 1052 | var createHmacMethod = function (is224) { 1053 | var method = createHmacOutputMethod('hex', is224); 1054 | method.create = function (key) { 1055 | return new HmacSha256(key, is224); 1056 | }; 1057 | method.update = function (key, message) { 1058 | return method.create(key).update(message); 1059 | }; 1060 | for (var i = 0; i < OUTPUT_TYPES.length; ++i) { 1061 | var type = OUTPUT_TYPES[i]; 1062 | method[type] = createHmacOutputMethod(type, is224); 1063 | } 1064 | return method; 1065 | }; 1066 | 1067 | function Sha256(is224, sharedMemory) { 1068 | if (sharedMemory) { 1069 | blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = 1070 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 1071 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 1072 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 1073 | this.blocks = blocks; 1074 | } else { 1075 | this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 1076 | } 1077 | 1078 | if (is224) { 1079 | this.h0 = 0xc1059ed8; 1080 | this.h1 = 0x367cd507; 1081 | this.h2 = 0x3070dd17; 1082 | this.h3 = 0xf70e5939; 1083 | this.h4 = 0xffc00b31; 1084 | this.h5 = 0x68581511; 1085 | this.h6 = 0x64f98fa7; 1086 | this.h7 = 0xbefa4fa4; 1087 | } else { // 256 1088 | this.h0 = 0x6a09e667; 1089 | this.h1 = 0xbb67ae85; 1090 | this.h2 = 0x3c6ef372; 1091 | this.h3 = 0xa54ff53a; 1092 | this.h4 = 0x510e527f; 1093 | this.h5 = 0x9b05688c; 1094 | this.h6 = 0x1f83d9ab; 1095 | this.h7 = 0x5be0cd19; 1096 | } 1097 | 1098 | this.block = this.start = this.bytes = this.hBytes = 0; 1099 | this.finalized = this.hashed = false; 1100 | this.first = true; 1101 | this.is224 = is224; 1102 | } 1103 | 1104 | Sha256.prototype.update = function (message) { 1105 | if (this.finalized) { 1106 | return; 1107 | } 1108 | var notString, type = typeof message; 1109 | if (type !== 'string') { 1110 | if (type === 'object') { 1111 | if (message === null) { 1112 | throw new Error(ERROR); 1113 | } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) { 1114 | message = new Uint8Array(message); 1115 | } else if (!Array.isArray(message)) { 1116 | if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { 1117 | throw new Error(ERROR); 1118 | } 1119 | } 1120 | } else { 1121 | throw new Error(ERROR); 1122 | } 1123 | notString = true; 1124 | } 1125 | var code, index = 0, i, length = message.length, blocks = this.blocks; 1126 | while (index < length) { 1127 | if (this.hashed) { 1128 | this.hashed = false; 1129 | blocks[0] = this.block; 1130 | this.block = blocks[16] = blocks[1] = blocks[2] = blocks[3] = 1131 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 1132 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 1133 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 1134 | } 1135 | 1136 | if (notString) { 1137 | for (i = this.start; index < length && i < 64; ++index) { 1138 | blocks[i >>> 2] |= message[index] << SHIFT[i++ & 3]; 1139 | } 1140 | } else { 1141 | for (i = this.start; index < length && i < 64; ++index) { 1142 | code = message.charCodeAt(index); 1143 | if (code < 0x80) { 1144 | blocks[i >>> 2] |= code << SHIFT[i++ & 3]; 1145 | } else if (code < 0x800) { 1146 | blocks[i >>> 2] |= (0xc0 | (code >>> 6)) << SHIFT[i++ & 3]; 1147 | blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 1148 | } else if (code < 0xd800 || code >= 0xe000) { 1149 | blocks[i >>> 2] |= (0xe0 | (code >>> 12)) << SHIFT[i++ & 3]; 1150 | blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3]; 1151 | blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 1152 | } else { 1153 | code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); 1154 | blocks[i >>> 2] |= (0xf0 | (code >>> 18)) << SHIFT[i++ & 3]; 1155 | blocks[i >>> 2] |= (0x80 | ((code >>> 12) & 0x3f)) << SHIFT[i++ & 3]; 1156 | blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3]; 1157 | blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; 1158 | } 1159 | } 1160 | } 1161 | 1162 | this.lastByteIndex = i; 1163 | this.bytes += i - this.start; 1164 | if (i >= 64) { 1165 | this.block = blocks[16]; 1166 | this.start = i - 64; 1167 | this.hash(); 1168 | this.hashed = true; 1169 | } else { 1170 | this.start = i; 1171 | } 1172 | } 1173 | if (this.bytes > 4294967295) { 1174 | this.hBytes += this.bytes / 4294967296 << 0; 1175 | this.bytes = this.bytes % 4294967296; 1176 | } 1177 | return this; 1178 | }; 1179 | 1180 | Sha256.prototype.finalize = function () { 1181 | if (this.finalized) { 1182 | return; 1183 | } 1184 | this.finalized = true; 1185 | var blocks = this.blocks, i = this.lastByteIndex; 1186 | blocks[16] = this.block; 1187 | blocks[i >>> 2] |= EXTRA[i & 3]; 1188 | this.block = blocks[16]; 1189 | if (i >= 56) { 1190 | if (!this.hashed) { 1191 | this.hash(); 1192 | } 1193 | blocks[0] = this.block; 1194 | blocks[16] = blocks[1] = blocks[2] = blocks[3] = 1195 | blocks[4] = blocks[5] = blocks[6] = blocks[7] = 1196 | blocks[8] = blocks[9] = blocks[10] = blocks[11] = 1197 | blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; 1198 | } 1199 | blocks[14] = this.hBytes << 3 | this.bytes >>> 29; 1200 | blocks[15] = this.bytes << 3; 1201 | this.hash(); 1202 | }; 1203 | 1204 | Sha256.prototype.hash = function () { 1205 | var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, 1206 | h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc; 1207 | 1208 | for (j = 16; j < 64; ++j) { 1209 | // rightrotate 1210 | t1 = blocks[j - 15]; 1211 | s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3); 1212 | t1 = blocks[j - 2]; 1213 | s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10); 1214 | blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0; 1215 | } 1216 | 1217 | bc = b & c; 1218 | for (j = 0; j < 64; j += 4) { 1219 | if (this.first) { 1220 | if (this.is224) { 1221 | ab = 300032; 1222 | t1 = blocks[0] - 1413257819; 1223 | h = t1 - 150054599 << 0; 1224 | d = t1 + 24177077 << 0; 1225 | } else { 1226 | ab = 704751109; 1227 | t1 = blocks[0] - 210244248; 1228 | h = t1 - 1521486534 << 0; 1229 | d = t1 + 143694565 << 0; 1230 | } 1231 | this.first = false; 1232 | } else { 1233 | s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10)); 1234 | s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7)); 1235 | ab = a & b; 1236 | maj = ab ^ (a & c) ^ bc; 1237 | ch = (e & f) ^ (~e & g); 1238 | t1 = h + s1 + ch + K[j] + blocks[j]; 1239 | t2 = s0 + maj; 1240 | h = d + t1 << 0; 1241 | d = t1 + t2 << 0; 1242 | } 1243 | s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10)); 1244 | s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7)); 1245 | da = d & a; 1246 | maj = da ^ (d & b) ^ ab; 1247 | ch = (h & e) ^ (~h & f); 1248 | t1 = g + s1 + ch + K[j + 1] + blocks[j + 1]; 1249 | t2 = s0 + maj; 1250 | g = c + t1 << 0; 1251 | c = t1 + t2 << 0; 1252 | s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10)); 1253 | s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7)); 1254 | cd = c & d; 1255 | maj = cd ^ (c & a) ^ da; 1256 | ch = (g & h) ^ (~g & e); 1257 | t1 = f + s1 + ch + K[j + 2] + blocks[j + 2]; 1258 | t2 = s0 + maj; 1259 | f = b + t1 << 0; 1260 | b = t1 + t2 << 0; 1261 | s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10)); 1262 | s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7)); 1263 | bc = b & c; 1264 | maj = bc ^ (b & d) ^ cd; 1265 | ch = (f & g) ^ (~f & h); 1266 | t1 = e + s1 + ch + K[j + 3] + blocks[j + 3]; 1267 | t2 = s0 + maj; 1268 | e = a + t1 << 0; 1269 | a = t1 + t2 << 0; 1270 | this.chromeBugWorkAround = true; 1271 | } 1272 | 1273 | this.h0 = this.h0 + a << 0; 1274 | this.h1 = this.h1 + b << 0; 1275 | this.h2 = this.h2 + c << 0; 1276 | this.h3 = this.h3 + d << 0; 1277 | this.h4 = this.h4 + e << 0; 1278 | this.h5 = this.h5 + f << 0; 1279 | this.h6 = this.h6 + g << 0; 1280 | this.h7 = this.h7 + h << 0; 1281 | }; 1282 | 1283 | Sha256.prototype.hex = function () { 1284 | this.finalize(); 1285 | 1286 | var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, 1287 | h6 = this.h6, h7 = this.h7; 1288 | 1289 | var hex = HEX_CHARS[(h0 >>> 28) & 0x0F] + HEX_CHARS[(h0 >>> 24) & 0x0F] + 1290 | HEX_CHARS[(h0 >>> 20) & 0x0F] + HEX_CHARS[(h0 >>> 16) & 0x0F] + 1291 | HEX_CHARS[(h0 >>> 12) & 0x0F] + HEX_CHARS[(h0 >>> 8) & 0x0F] + 1292 | HEX_CHARS[(h0 >>> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + 1293 | HEX_CHARS[(h1 >>> 28) & 0x0F] + HEX_CHARS[(h1 >>> 24) & 0x0F] + 1294 | HEX_CHARS[(h1 >>> 20) & 0x0F] + HEX_CHARS[(h1 >>> 16) & 0x0F] + 1295 | HEX_CHARS[(h1 >>> 12) & 0x0F] + HEX_CHARS[(h1 >>> 8) & 0x0F] + 1296 | HEX_CHARS[(h1 >>> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + 1297 | HEX_CHARS[(h2 >>> 28) & 0x0F] + HEX_CHARS[(h2 >>> 24) & 0x0F] + 1298 | HEX_CHARS[(h2 >>> 20) & 0x0F] + HEX_CHARS[(h2 >>> 16) & 0x0F] + 1299 | HEX_CHARS[(h2 >>> 12) & 0x0F] + HEX_CHARS[(h2 >>> 8) & 0x0F] + 1300 | HEX_CHARS[(h2 >>> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + 1301 | HEX_CHARS[(h3 >>> 28) & 0x0F] + HEX_CHARS[(h3 >>> 24) & 0x0F] + 1302 | HEX_CHARS[(h3 >>> 20) & 0x0F] + HEX_CHARS[(h3 >>> 16) & 0x0F] + 1303 | HEX_CHARS[(h3 >>> 12) & 0x0F] + HEX_CHARS[(h3 >>> 8) & 0x0F] + 1304 | HEX_CHARS[(h3 >>> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + 1305 | HEX_CHARS[(h4 >>> 28) & 0x0F] + HEX_CHARS[(h4 >>> 24) & 0x0F] + 1306 | HEX_CHARS[(h4 >>> 20) & 0x0F] + HEX_CHARS[(h4 >>> 16) & 0x0F] + 1307 | HEX_CHARS[(h4 >>> 12) & 0x0F] + HEX_CHARS[(h4 >>> 8) & 0x0F] + 1308 | HEX_CHARS[(h4 >>> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] + 1309 | HEX_CHARS[(h5 >>> 28) & 0x0F] + HEX_CHARS[(h5 >>> 24) & 0x0F] + 1310 | HEX_CHARS[(h5 >>> 20) & 0x0F] + HEX_CHARS[(h5 >>> 16) & 0x0F] + 1311 | HEX_CHARS[(h5 >>> 12) & 0x0F] + HEX_CHARS[(h5 >>> 8) & 0x0F] + 1312 | HEX_CHARS[(h5 >>> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] + 1313 | HEX_CHARS[(h6 >>> 28) & 0x0F] + HEX_CHARS[(h6 >>> 24) & 0x0F] + 1314 | HEX_CHARS[(h6 >>> 20) & 0x0F] + HEX_CHARS[(h6 >>> 16) & 0x0F] + 1315 | HEX_CHARS[(h6 >>> 12) & 0x0F] + HEX_CHARS[(h6 >>> 8) & 0x0F] + 1316 | HEX_CHARS[(h6 >>> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F]; 1317 | if (!this.is224) { 1318 | hex += HEX_CHARS[(h7 >>> 28) & 0x0F] + HEX_CHARS[(h7 >>> 24) & 0x0F] + 1319 | HEX_CHARS[(h7 >>> 20) & 0x0F] + HEX_CHARS[(h7 >>> 16) & 0x0F] + 1320 | HEX_CHARS[(h7 >>> 12) & 0x0F] + HEX_CHARS[(h7 >>> 8) & 0x0F] + 1321 | HEX_CHARS[(h7 >>> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F]; 1322 | } 1323 | return hex; 1324 | }; 1325 | 1326 | Sha256.prototype.toString = Sha256.prototype.hex; 1327 | 1328 | Sha256.prototype.digest = function () { 1329 | this.finalize(); 1330 | 1331 | var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, 1332 | h6 = this.h6, h7 = this.h7; 1333 | 1334 | var arr = [ 1335 | (h0 >>> 24) & 0xFF, (h0 >>> 16) & 0xFF, (h0 >>> 8) & 0xFF, h0 & 0xFF, 1336 | (h1 >>> 24) & 0xFF, (h1 >>> 16) & 0xFF, (h1 >>> 8) & 0xFF, h1 & 0xFF, 1337 | (h2 >>> 24) & 0xFF, (h2 >>> 16) & 0xFF, (h2 >>> 8) & 0xFF, h2 & 0xFF, 1338 | (h3 >>> 24) & 0xFF, (h3 >>> 16) & 0xFF, (h3 >>> 8) & 0xFF, h3 & 0xFF, 1339 | (h4 >>> 24) & 0xFF, (h4 >>> 16) & 0xFF, (h4 >>> 8) & 0xFF, h4 & 0xFF, 1340 | (h5 >>> 24) & 0xFF, (h5 >>> 16) & 0xFF, (h5 >>> 8) & 0xFF, h5 & 0xFF, 1341 | (h6 >>> 24) & 0xFF, (h6 >>> 16) & 0xFF, (h6 >>> 8) & 0xFF, h6 & 0xFF 1342 | ]; 1343 | if (!this.is224) { 1344 | arr.push((h7 >>> 24) & 0xFF, (h7 >>> 16) & 0xFF, (h7 >>> 8) & 0xFF, h7 & 0xFF); 1345 | } 1346 | return arr; 1347 | }; 1348 | 1349 | Sha256.prototype.array = Sha256.prototype.digest; 1350 | 1351 | Sha256.prototype.arrayBuffer = function () { 1352 | this.finalize(); 1353 | 1354 | var buffer = new ArrayBuffer(this.is224 ? 28 : 32); 1355 | var dataView = new DataView(buffer); 1356 | dataView.setUint32(0, this.h0); 1357 | dataView.setUint32(4, this.h1); 1358 | dataView.setUint32(8, this.h2); 1359 | dataView.setUint32(12, this.h3); 1360 | dataView.setUint32(16, this.h4); 1361 | dataView.setUint32(20, this.h5); 1362 | dataView.setUint32(24, this.h6); 1363 | if (!this.is224) { 1364 | dataView.setUint32(28, this.h7); 1365 | } 1366 | return buffer; 1367 | }; 1368 | 1369 | function HmacSha256(key, is224, sharedMemory) { 1370 | var i, type = typeof key; 1371 | if (type === 'string') { 1372 | var bytes = [], length = key.length, index = 0, code; 1373 | for (i = 0; i < length; ++i) { 1374 | code = key.charCodeAt(i); 1375 | if (code < 0x80) { 1376 | bytes[index++] = code; 1377 | } else if (code < 0x800) { 1378 | bytes[index++] = (0xc0 | (code >>> 6)); 1379 | bytes[index++] = (0x80 | (code & 0x3f)); 1380 | } else if (code < 0xd800 || code >= 0xe000) { 1381 | bytes[index++] = (0xe0 | (code >>> 12)); 1382 | bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); 1383 | bytes[index++] = (0x80 | (code & 0x3f)); 1384 | } else { 1385 | code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff)); 1386 | bytes[index++] = (0xf0 | (code >>> 18)); 1387 | bytes[index++] = (0x80 | ((code >>> 12) & 0x3f)); 1388 | bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); 1389 | bytes[index++] = (0x80 | (code & 0x3f)); 1390 | } 1391 | } 1392 | key = bytes; 1393 | } else { 1394 | if (type === 'object') { 1395 | if (key === null) { 1396 | throw new Error(ERROR); 1397 | } else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) { 1398 | key = new Uint8Array(key); 1399 | } else if (!Array.isArray(key)) { 1400 | if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) { 1401 | throw new Error(ERROR); 1402 | } 1403 | } 1404 | } else { 1405 | throw new Error(ERROR); 1406 | } 1407 | } 1408 | 1409 | if (key.length > 64) { 1410 | key = (new Sha256(is224, true)).update(key).array(); 1411 | } 1412 | 1413 | var oKeyPad = [], iKeyPad = []; 1414 | for (i = 0; i < 64; ++i) { 1415 | var b = key[i] || 0; 1416 | oKeyPad[i] = 0x5c ^ b; 1417 | iKeyPad[i] = 0x36 ^ b; 1418 | } 1419 | 1420 | Sha256.call(this, is224, sharedMemory); 1421 | 1422 | this.update(iKeyPad); 1423 | this.oKeyPad = oKeyPad; 1424 | this.inner = true; 1425 | this.sharedMemory = sharedMemory; 1426 | } 1427 | HmacSha256.prototype = new Sha256(); 1428 | 1429 | HmacSha256.prototype.finalize = function () { 1430 | Sha256.prototype.finalize.call(this); 1431 | if (this.inner) { 1432 | this.inner = false; 1433 | var innerHash = this.array(); 1434 | Sha256.call(this, this.is224, this.sharedMemory); 1435 | this.update(this.oKeyPad); 1436 | this.update(innerHash); 1437 | Sha256.prototype.finalize.call(this); 1438 | } 1439 | }; 1440 | 1441 | var exports = createMethod(); 1442 | exports.sha256 = exports; 1443 | exports.sha224 = createMethod(true); 1444 | exports.sha256.hmac = createHmacMethod(); 1445 | exports.sha224.hmac = createHmacMethod(true); 1446 | 1447 | if (COMMON_JS) { 1448 | module.exports = exports; 1449 | } else { 1450 | root.sha256 = exports.sha256; 1451 | root.sha224 = exports.sha224; 1452 | if (AMD) { 1453 | define(function () { 1454 | return exports; 1455 | }); 1456 | } 1457 | } 1458 | })(); 1459 | 1460 | async function getAccountId(email, key) { 1461 | try { 1462 | const url = 'https://api.cloudflare.com/client/v4/accounts'; 1463 | const headers = new Headers({ 1464 | 'X-AUTH-EMAIL': email, 1465 | 'X-AUTH-KEY': key 1466 | }); 1467 | const response = await fetch(url, { headers }); 1468 | const data = await response.json(); 1469 | return data.result[0].id; // 假设我们需要第一个账号ID 1470 | } catch (error) { 1471 | return false ; 1472 | } 1473 | } 1474 | 1475 | async function getSum(accountId, accountIndex, email, key, startDate, endDate) { 1476 | try { 1477 | const startDateISO = new Date(startDate).toISOString(); 1478 | const endDateISO = new Date(endDate).toISOString(); 1479 | 1480 | const query = JSON.stringify({ 1481 | query: `query getBillingMetrics($accountId: String!, $filter: AccountWorkersInvocationsAdaptiveFilter_InputObject) { 1482 | viewer { 1483 | accounts(filter: {accountTag: $accountId}) { 1484 | pagesFunctionsInvocationsAdaptiveGroups(limit: 1000, filter: $filter) { 1485 | sum { 1486 | requests 1487 | } 1488 | } 1489 | workersInvocationsAdaptive(limit: 10000, filter: $filter) { 1490 | sum { 1491 | requests 1492 | } 1493 | } 1494 | } 1495 | } 1496 | }`, 1497 | variables: { 1498 | accountId, 1499 | filter: { datetime_geq: startDateISO, datetime_leq: endDateISO } 1500 | }, 1501 | }); 1502 | 1503 | const headers = new Headers({ 1504 | 'Content-Type': 'application/json', 1505 | 'X-AUTH-EMAIL': email, 1506 | 'X-AUTH-KEY': key, 1507 | }); 1508 | 1509 | const response = await fetch(`https://api.cloudflare.com/client/v4/graphql`, { 1510 | method: 'POST', 1511 | headers: headers, 1512 | body: query 1513 | }); 1514 | 1515 | if (!response.ok) { 1516 | throw new Error(`HTTP error! status: ${response.status}`); 1517 | } 1518 | 1519 | const res = await response.json(); 1520 | 1521 | const pagesFunctionsInvocationsAdaptiveGroups = res?.data?.viewer?.accounts?.[accountIndex]?.pagesFunctionsInvocationsAdaptiveGroups; 1522 | const workersInvocationsAdaptive = res?.data?.viewer?.accounts?.[accountIndex]?.workersInvocationsAdaptive; 1523 | 1524 | if (!pagesFunctionsInvocationsAdaptiveGroups && !workersInvocationsAdaptive) { 1525 | throw new Error('找不到数据'); 1526 | } 1527 | 1528 | const pagesSum = pagesFunctionsInvocationsAdaptiveGroups.reduce((a, b) => a + b?.sum.requests, 0); 1529 | const workersSum = workersInvocationsAdaptive.reduce((a, b) => a + b?.sum.requests, 0); 1530 | 1531 | //console.log(`范围: ${startDateISO} ~ ${endDateISO}\n默认取第 ${accountIndex} 项`); 1532 | 1533 | return [pagesSum, workersSum ]; 1534 | } catch (error) { 1535 | return [ 0, 0 ]; 1536 | } 1537 | } 1538 | 1539 | /** 1540 | * 1541 | * @param {number} addressType 1542 | * @param {string} addressRemote 1543 | * @param {number} portRemote 1544 | * @param {function} log The logging function. 1545 | */ 1546 | async function socks5Connect(addressType, addressRemote, portRemote, log) { 1547 | const { username, password, hostname, port } = parsedSocks5Address; 1548 | // Connect to the SOCKS server 1549 | const socket = connect({ 1550 | hostname, 1551 | port, 1552 | }); 1553 | 1554 | // Request head format (Worker -> Socks Server): 1555 | // +----+----------+----------+ 1556 | // |VER | NMETHODS | METHODS | 1557 | // +----+----------+----------+ 1558 | // | 1 | 1 | 1 to 255 | 1559 | // +----+----------+----------+ 1560 | 1561 | // https://en.wikipedia.org/wiki/SOCKS#SOCKS5 1562 | // For METHODS: 1563 | // 0x00 NO AUTHENTICATION REQUIRED 1564 | // 0x02 USERNAME/PASSWORD https://datatracker.ietf.org/doc/html/rfc1929 1565 | const socksGreeting = new Uint8Array([5, 2, 0, 2]); 1566 | 1567 | const writer = socket.writable.getWriter(); 1568 | 1569 | await writer.write(socksGreeting); 1570 | log('sent socks greeting'); 1571 | 1572 | const reader = socket.readable.getReader(); 1573 | const encoder = new TextEncoder(); 1574 | let res = (await reader.read()).value; 1575 | // Response format (Socks Server -> Worker): 1576 | // +----+--------+ 1577 | // |VER | METHOD | 1578 | // +----+--------+ 1579 | // | 1 | 1 | 1580 | // +----+--------+ 1581 | if (res[0] !== 0x05) { 1582 | log(`socks server version error: ${res[0]} expected: 5`); 1583 | return; 1584 | } 1585 | if (res[1] === 0xff) { 1586 | log("no acceptable methods"); 1587 | return; 1588 | } 1589 | 1590 | // if return 0x0502 1591 | if (res[1] === 0x02) { 1592 | log("socks server needs auth"); 1593 | if (!username || !password) { 1594 | log("please provide username/password"); 1595 | return; 1596 | } 1597 | // +----+------+----------+------+----------+ 1598 | // |VER | ULEN | UNAME | PLEN | PASSWD | 1599 | // +----+------+----------+------+----------+ 1600 | // | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 1601 | // +----+------+----------+------+----------+ 1602 | const authRequest = new Uint8Array([ 1603 | 1, 1604 | username.length, 1605 | ...encoder.encode(username), 1606 | password.length, 1607 | ...encoder.encode(password) 1608 | ]); 1609 | await writer.write(authRequest); 1610 | res = (await reader.read()).value; 1611 | // expected 0x0100 1612 | if (res[0] !== 0x01 || res[1] !== 0x00) { 1613 | log("fail to auth socks server"); 1614 | return; 1615 | } 1616 | } 1617 | 1618 | // Request data format (Worker -> Socks Server): 1619 | // +----+-----+-------+------+----------+----------+ 1620 | // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 1621 | // +----+-----+-------+------+----------+----------+ 1622 | // | 1 | 1 | X'00' | 1 | Variable | 2 | 1623 | // +----+-----+-------+------+----------+----------+ 1624 | // ATYP: address type of following address 1625 | // 0x01: IPv4 address 1626 | // 0x03: Domain name 1627 | // 0x04: IPv6 address 1628 | // DST.ADDR: desired destination address 1629 | // DST.PORT: desired destination port in network octet order 1630 | 1631 | // addressType 1632 | // 0x01: IPv4 address 1633 | // 0x03: Domain name 1634 | // 0x04: IPv6 address 1635 | // 1--> ipv4 addressLength =4 1636 | // 2--> domain name 1637 | // 3--> ipv6 addressLength =16 1638 | let DSTADDR; // DSTADDR = ATYP + DST.ADDR 1639 | switch (addressType) { 1640 | case 1: 1641 | DSTADDR = new Uint8Array( 1642 | [1, ...addressRemote.split('.').map(Number)] 1643 | ); 1644 | break; 1645 | case 3: 1646 | DSTADDR = new Uint8Array( 1647 | [3, addressRemote.length, ...encoder.encode(addressRemote)] 1648 | ); 1649 | break; 1650 | case 4: 1651 | DSTADDR = new Uint8Array( 1652 | [4, ...addressRemote.split(':').flatMap(x => [parseInt(x.slice(0, 2), 16), parseInt(x.slice(2), 16)])] 1653 | ); 1654 | break; 1655 | default: 1656 | log(`invild addressType is ${addressType}`); 1657 | return; 1658 | } 1659 | const socksRequest = new Uint8Array([5, 1, 0, ...DSTADDR, portRemote >> 8, portRemote & 0xff]); 1660 | await writer.write(socksRequest); 1661 | log('sent socks request'); 1662 | 1663 | res = (await reader.read()).value; 1664 | // Response format (Socks Server -> Worker): 1665 | // +----+-----+-------+------+----------+----------+ 1666 | // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 1667 | // +----+-----+-------+------+----------+----------+ 1668 | // | 1 | 1 | X'00' | 1 | Variable | 2 | 1669 | // +----+-----+-------+------+----------+----------+ 1670 | if (res[1] === 0x00) { 1671 | log("socks connection opened"); 1672 | } else { 1673 | log("fail to open socks connection"); 1674 | return; 1675 | } 1676 | writer.releaseLock(); 1677 | reader.releaseLock(); 1678 | return socket; 1679 | } 1680 | 1681 | 1682 | /** 1683 | * 1684 | * @param {string} address 1685 | */ 1686 | function socks5AddressParser(address) { 1687 | let [latter, former] = address.split("@").reverse(); 1688 | let username, password, hostname, port; 1689 | if (former) { 1690 | const formers = former.split(":"); 1691 | if (formers.length !== 2) { 1692 | throw new Error('Invalid SOCKS address format'); 1693 | } 1694 | [username, password] = formers; 1695 | } 1696 | const latters = latter.split(":"); 1697 | port = Number(latters.pop()); 1698 | if (isNaN(port)) { 1699 | throw new Error('Invalid SOCKS address format'); 1700 | } 1701 | hostname = latters.join(":"); 1702 | const regex = /^\[.*\]$/; 1703 | if (hostname.includes(":") && !regex.test(hostname)) { 1704 | throw new Error('Invalid SOCKS address format'); 1705 | } 1706 | return { 1707 | username, 1708 | password, 1709 | hostname, 1710 | port, 1711 | } 1712 | } 1713 | -------------------------------------------------------------------------------- /worker.old.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzhhh1/epeius/e8f59aae6c9d897d0d3ffb911b41df908150e974/worker.old.zip -------------------------------------------------------------------------------- /worker.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzzhhh1/epeius/e8f59aae6c9d897d0d3ffb911b41df908150e974/worker.zip --------------------------------------------------------------------------------