├── .gitignore ├── Cartfile ├── CryptoSwift.framework ├── CryptoSwift ├── Headers ├── Modules ├── Resources └── Versions │ ├── A │ ├── CryptoSwift │ ├── Headers │ │ └── CryptoSwift.h │ ├── Modules │ │ ├── CryptoSwift.swiftmodule │ │ │ ├── x86_64.swiftdoc │ │ │ └── x86_64.swiftmodule │ │ └── module.modulemap │ └── Resources │ │ └── Info.plist │ └── Current ├── LICENSE ├── LightSwordPlayground.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ └── contents.xcworkspacedata └── timeline.xctimeline ├── LightSwordX.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── LightSwordX ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── happy_128.png │ │ ├── happy_16.png │ │ ├── happy_256.png │ │ ├── happy_32.png │ │ ├── happy_512.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32@2x.png │ │ └── icon_512x512@2x.png │ ├── Contents.json │ ├── TrayIcon.imageset │ │ ├── Contents.json │ │ ├── icon_16x16@2x.png │ │ └── sword_16.png │ └── TrayIconHighlight.imageset │ │ ├── Contents.json │ │ ├── alter_sword_16.png │ │ └── icon_16x16@2x.png ├── Base.lproj │ ├── Localizable.strings │ └── Main.storyboard ├── Common │ └── AppKeys.swift ├── Info.plist ├── Lib │ ├── Constants.swift │ ├── Crypto.swift │ ├── Json.swift │ ├── Regex.swift │ ├── SettingsHelper.swift │ ├── StatisticsHelper.swift │ └── String.swift ├── LightSwordX-Bridging-Header.h ├── LightSwordX.entitlements ├── Models │ └── UserServer.swift ├── Socket │ ├── ysocket.swift │ ├── ytcpsocket.c │ ├── ytcpsocket.swift │ ├── yudpsocket.c │ └── yudpsocket.swift ├── Socket6 │ ├── Socket.swift │ └── TCPSocket.c ├── Socks5 │ ├── Socks5Constants.swift │ ├── Socks5Helper.swift │ └── Socks5Server.swift ├── TCPSocket.swift ├── ViewController.Servers.swift ├── ViewController.Settings.swift ├── ViewController.Websites.swift ├── ViewController.swift ├── black.txt ├── white.txt └── zh-Hans.lproj │ ├── Localizable.strings │ └── Main.strings ├── LightSwordXHelper ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── 1451660318_game-fighting-sword-shooter.png │ │ ├── 1451660323_game-fighting-sword-shooter.png │ │ ├── 1451660327_game-fighting-sword-shooter.png │ │ ├── 1451660336_game-fighting-sword-shooter.png │ │ ├── Contents.json │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512@2x.png │ │ └── sword_16.png ├── Base.lproj │ └── Main.storyboard ├── Info.plist ├── LightSwordXHelper.entitlements └── zh-Hans.lproj │ └── Main.strings ├── LightSwordXTests ├── Info.plist └── LightSwordXTests.swift ├── README.md ├── README_zh.md └── SINQ.framework ├── Headers ├── Modules ├── Resources ├── SINQ └── Versions ├── A ├── Headers │ ├── SINQ-Swift.h │ └── SINQ.h ├── Modules │ ├── SINQ.swiftmodule │ │ ├── x86_64.swiftdoc │ │ └── x86_64.swiftmodule │ └── module.modulemap ├── Resources │ └── Info.plist └── SINQ └── Current /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata/ 3 | Cartfile.resolved 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # CocoaPods 25 | # 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Pods/ 31 | 32 | # Carthage 33 | # 34 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 35 | Carthage/Checkouts 36 | 37 | Carthage/Build 38 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "slazyk/SINQ" 2 | github "krzyzanowskim/CryptoSwift" 3 | -------------------------------------------------------------------------------- /CryptoSwift.framework/CryptoSwift: -------------------------------------------------------------------------------- 1 | Versions/Current/CryptoSwift -------------------------------------------------------------------------------- /CryptoSwift.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /CryptoSwift.framework/Modules: -------------------------------------------------------------------------------- 1 | Versions/Current/Modules -------------------------------------------------------------------------------- /CryptoSwift.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/CryptoSwift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/CryptoSwift.framework/Versions/A/CryptoSwift -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/Headers/CryptoSwift.h: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoSwift.h 3 | // CryptoSwift 4 | // 5 | // Created by Sam Soffes on 11/29/15. 6 | // Copyright © 2015 Marcin Krzyzanowski. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | //! Project version number for CryptoSwift. 12 | FOUNDATION_EXPORT double CryptoSwiftVersionNumber; 13 | 14 | //! Project version string for CryptoSwift. 15 | FOUNDATION_EXPORT const unsigned char CryptoSwiftVersionString[]; 16 | -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/Modules/CryptoSwift.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/CryptoSwift.framework/Versions/A/Modules/CryptoSwift.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/Modules/CryptoSwift.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/CryptoSwift.framework/Versions/A/Modules/CryptoSwift.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module CryptoSwift { 2 | umbrella header "CryptoSwift.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 15D21 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | CryptoSwift 11 | CFBundleIdentifier 12 | com.hakore.CryptoSwift 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | CryptoSwift 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 0.2.3 21 | CFBundleSignature 22 | ???? 23 | CFBundleSupportedPlatforms 24 | 25 | MacOSX 26 | 27 | CFBundleVersion 28 | 1 29 | DTCompiler 30 | com.apple.compilers.llvm.clang.1_0 31 | DTPlatformBuild 32 | 7C1002 33 | DTPlatformVersion 34 | GM 35 | DTSDKBuild 36 | 15C43 37 | DTSDKName 38 | macosx10.11 39 | DTXcode 40 | 0721 41 | DTXcodeBuild 42 | 7C1002 43 | UIDeviceFamily 44 | 45 | 1 46 | 2 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /CryptoSwift.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /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 | {description} 294 | Copyright (C) {year} {fullname} 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 | {signature of Ty Coon}, 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 | 341 | -------------------------------------------------------------------------------- /LightSwordPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //: Playground - noun: a place where people can play 2 | 3 | import Cocoa 4 | 5 | var status: Int32 = 0 6 | 7 | // Protocol configuration 8 | 9 | var hints = addrinfo( 10 | ai_flags: AI_PASSIVE, // Assign the address of my local host to the socket structures 11 | ai_family: AF_UNSPEC, // Either IPv4 or IPv6 12 | ai_socktype: SOCK_STREAM, // TCP 13 | ai_protocol: 0, 14 | ai_addrlen: 0, 15 | ai_canonname: nil, 16 | ai_addr: nil, 17 | ai_next: nil) 18 | 19 | 20 | // For the result from the getaddrinfo 21 | 22 | var servinfo = UnsafeMutablePointer.init() 23 | 24 | 25 | // Get the info we need to create our socket descriptor 26 | 27 | status = getaddrinfo("ip.cn", "", &hints, &servinfo) 28 | 29 | print(status) 30 | 31 | print(servinfo.memory.ai_addr) -------------------------------------------------------------------------------- /LightSwordPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /LightSwordPlayground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LightSwordPlayground.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /LightSwordX.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LightSwordX/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate { 13 | 14 | func applicationDidFinishLaunching(aNotification: NSNotification) { 15 | 16 | if SettingsHelper.loadValue(defaultValue: "", forKey: "Servers").length > 0 { 17 | NSApplication.sharedApplication().windows.last!.close() 18 | } 19 | 20 | if let button = statusItem.button { 21 | button.image = NSImage(named: "TrayIcon") 22 | button.image?.template = true 23 | button.alternateImage = NSImage(named: "TrayIconHighlight") 24 | } 25 | 26 | let menu = NSMenu() 27 | menu.addItem(NSMenuItem(title: NSLocalizedString("Preferences", comment: ""), action: Selector("openPreferences:"), keyEquivalent: "")) 28 | menu.addItem(NSMenuItem(title: NSLocalizedString("Quit", comment: ""), action: Selector("quit:"), keyEquivalent: "")) 29 | 30 | statusItem.menu = menu 31 | 32 | NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self 33 | } 34 | 35 | func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool { 36 | return true 37 | } 38 | 39 | func applicationWillTerminate(aNotification: NSNotification) { 40 | // Insert code here to tear down your application 41 | } 42 | 43 | let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSSquareStatusItemLength) 44 | 45 | func openPreferences(sender: NSMenuItem) { 46 | NSApplication.sharedApplication().windows.last!.makeKeyAndOrderFront(nil) 47 | NSApplication.sharedApplication().activateIgnoringOtherApps(true) 48 | } 49 | 50 | func quit(sender: NSMenuItem) { 51 | NSApplication.sharedApplication().terminate(self) 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "happy_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "happy_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "happy_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "happy_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "happy_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_128.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_16.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_256.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_32.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/happy_512.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "sword_16.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "icon_16x16@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIcon.imageset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/TrayIcon.imageset/icon_16x16@2x.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIcon.imageset/sword_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/TrayIcon.imageset/sword_16.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIconHighlight.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "alter_sword_16.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "icon_16x16@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIconHighlight.imageset/alter_sword_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/TrayIconHighlight.imageset/alter_sword_16.png -------------------------------------------------------------------------------- /LightSwordX/Assets.xcassets/TrayIconHighlight.imageset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordX/Assets.xcassets/TrayIconHighlight.imageset/icon_16x16@2x.png -------------------------------------------------------------------------------- /LightSwordX/Base.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | // Connection Test 2 | 3 | "Test Connection Speed" = "Test Connection Speed"; 4 | "Elapsed Time" = "Elapsed Time"; 5 | "Connection Timeout" = "Connection Timeout"; 6 | 7 | // Menu Bar 8 | 9 | "Preferences" = "Preferences"; 10 | "Quit" = "Quit"; 11 | 12 | // Status 13 | 14 | "Stopped" = "Stopped"; 15 | "Running" = "Running"; 16 | 17 | // Local Server 18 | 19 | "Start Failed" = "Start Failed"; 20 | "Port is used" = "Port number: %d is used by other process or access denied"; -------------------------------------------------------------------------------- /LightSwordX/Common/AppKeys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppKeys.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/29/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class AppKeys { 12 | static let Servers = "Servers" 13 | static let WhiteList = "WhiteList" 14 | static let BlackList = "BlackList" 15 | static let LoginItem = "LoginItem" 16 | } -------------------------------------------------------------------------------- /LightSwordX/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 3 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | LSUIElement 30 | 31 | NSHumanReadableCopyright 32 | Copyright © 2015 Project LightSword. All rights reserved. 33 | NSMainStoryboardFile 34 | Main 35 | NSPrincipalClass 36 | NSApplication 37 | 38 | 39 | -------------------------------------------------------------------------------- /LightSwordX/Lib/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/20/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum VPN_TYPE: UInt8 { 12 | case OSXCL5 = 0xa5 13 | } -------------------------------------------------------------------------------- /LightSwordX/Lib/Crypto.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Crypto.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/19/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import SINQ 10 | import Foundation 11 | import CryptoSwift 12 | 13 | class Crypto { 14 | 15 | static let SupportedCiphers = [ 16 | "aes-256-cfb": (info: [32, 16], blockMode: CipherBlockMode.CFB), 17 | "aes-192-cfb": (info: [24, 16], blockMode: CipherBlockMode.CFB), 18 | "aes-128-cfb": (info: [16, 16], blockMode: CipherBlockMode.CFB) 19 | ] 20 | 21 | static func createCipher(algorithm: String, password: String, iv: [UInt8]? = nil) -> (cipher: AES, iv: [UInt8]) { 22 | var tuple: (info: [Int], blockMode: CipherBlockMode)! = SupportedCiphers[algorithm.lowercaseString] 23 | if tuple == nil { 24 | tuple = (info: [32, 16], blockMode: CipherBlockMode.CFB) 25 | } 26 | 27 | var key = [UInt8](password.utf8) 28 | if key.count > tuple.info[0] { 29 | key = sinq(key).take(tuple.info[0]).toArray() 30 | } else { 31 | let longPw = String(count: (tuple.info[0] / password.length) + 1, byRepeatingString: password)! 32 | key = [UInt8](longPw.utf8) 33 | key = sinq(key).take(tuple.info[0]).toArray() 34 | } 35 | 36 | var civ: [UInt8]! = iv 37 | if civ == nil { 38 | civ = AES.randomIV(tuple.info[1]) 39 | } 40 | 41 | let cipher = try! AES(key: key, iv: civ, blockMode: tuple.blockMode) 42 | return (cipher: cipher, iv: civ) 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /LightSwordX/Lib/Json.swift: -------------------------------------------------------------------------------- 1 | // 2 | // json.swift 3 | // json 4 | // 5 | // Created by Dan Kogai on 7/15/14. 6 | // Copyright (c) 2014 Dan Kogai. All rights reserved. 7 | // 8 | import Foundation 9 | /// init 10 | public class JSON { 11 | private let _value:AnyObject 12 | /// unwraps the JSON object 13 | public class func unwrap(obj:AnyObject) -> AnyObject { 14 | switch obj { 15 | case let json as JSON: 16 | return json._value 17 | case let ary as NSArray: 18 | var ret = [AnyObject]() 19 | for v in ary { 20 | ret.append(unwrap(v)) 21 | } 22 | return ret 23 | case let dict as NSDictionary: 24 | var ret = [String:AnyObject]() 25 | for (ko, v) in dict { 26 | if let k = ko as? String { 27 | ret[k] = unwrap(v) 28 | } 29 | } 30 | return ret 31 | default: 32 | return obj 33 | } 34 | } 35 | /// pass the object that was returned from 36 | /// NSJSONSerialization 37 | public init(_ obj:AnyObject) { self._value = JSON.unwrap(obj) } 38 | /// pass the JSON object for another instance 39 | public init(_ json:JSON){ self._value = json._value } 40 | } 41 | /// class properties 42 | extension JSON { 43 | public typealias NSNull = Foundation.NSNull 44 | public typealias NSError = Foundation.NSError 45 | public class var null:NSNull { return NSNull() } 46 | /// constructs JSON object from data 47 | public convenience init(data:NSData) { 48 | var err:NSError? 49 | var obj:AnyObject? 50 | do { 51 | obj = try NSJSONSerialization.JSONObjectWithData( 52 | data, options:[]) 53 | } catch let error as NSError { 54 | err = error 55 | obj = nil 56 | } 57 | self.init(err != nil ? err! : obj!) 58 | } 59 | /// constructs JSON object from string 60 | public convenience init(string:String) { 61 | let enc:NSStringEncoding = NSUTF8StringEncoding 62 | self.init(data: string.dataUsingEncoding(enc)!) 63 | } 64 | /// parses string to the JSON object 65 | /// same as JSON(string:String) 66 | public class func parse(string:String)->JSON { 67 | return JSON(string:string) 68 | } 69 | /// constructs JSON object from the content of NSURL 70 | public convenience init(nsurl:NSURL) { 71 | var enc:NSStringEncoding = NSUTF8StringEncoding 72 | do { 73 | let str = try NSString(contentsOfURL:nsurl, usedEncoding:&enc) 74 | self.init(string:str as String) 75 | } catch let err as NSError { 76 | self.init(err) 77 | } 78 | } 79 | /// fetch the JSON string from NSURL and parse it 80 | /// same as JSON(nsurl:NSURL) 81 | public class func fromNSURL(nsurl:NSURL) -> JSON { 82 | return JSON(nsurl:nsurl) 83 | } 84 | /// constructs JSON object from the content of URL 85 | public convenience init(url:String) { 86 | if let nsurl = NSURL(string:url) as NSURL? { 87 | self.init(nsurl:nsurl) 88 | } else { 89 | self.init(NSError( 90 | domain:"JSONErrorDomain", 91 | code:400, 92 | userInfo:[NSLocalizedDescriptionKey: "malformed URL"] 93 | ) 94 | ) 95 | } 96 | } 97 | /// fetch the JSON string from URL in the string 98 | public class func fromURL(url:String) -> JSON { 99 | return JSON(url:url) 100 | } 101 | /// does what JSON.stringify in ES5 does. 102 | /// when the 2nd argument is set to true it pretty prints 103 | public class func stringify(obj:AnyObject, pretty:Bool=false) -> String! { 104 | if !NSJSONSerialization.isValidJSONObject(obj) { 105 | let error = JSON(NSError( 106 | domain:"JSONErrorDomain", 107 | code:422, 108 | userInfo:[NSLocalizedDescriptionKey: "not an JSON object"] 109 | )) 110 | return JSON(error).toString(pretty) 111 | } 112 | return JSON(obj).toString(pretty) 113 | } 114 | } 115 | /// instance properties 116 | extension JSON { 117 | /// access the element like array 118 | public subscript(idx:Int) -> JSON { 119 | switch _value { 120 | case _ as NSError: 121 | return self 122 | case let ary as NSArray: 123 | if 0 <= idx && idx < ary.count { 124 | return JSON(ary[idx]) 125 | } 126 | return JSON(NSError( 127 | domain:"JSONErrorDomain", code:404, userInfo:[ 128 | NSLocalizedDescriptionKey: 129 | "[\(idx)] is out of range" 130 | ])) 131 | default: 132 | return JSON(NSError( 133 | domain:"JSONErrorDomain", code:500, userInfo:[ 134 | NSLocalizedDescriptionKey: "not an array" 135 | ])) 136 | } 137 | } 138 | /// access the element like dictionary 139 | public subscript(key:String)->JSON { 140 | switch _value { 141 | case _ as NSError: 142 | return self 143 | case let dic as NSDictionary: 144 | if let val:AnyObject = dic[key] { return JSON(val) } 145 | return JSON(NSError( 146 | domain:"JSONErrorDomain", code:404, userInfo:[ 147 | NSLocalizedDescriptionKey: 148 | "[\"\(key)\"] not found" 149 | ])) 150 | default: 151 | return JSON(NSError( 152 | domain:"JSONErrorDomain", code:500, userInfo:[ 153 | NSLocalizedDescriptionKey: "not an object" 154 | ])) 155 | } 156 | } 157 | /// access json data object 158 | public var data:AnyObject? { 159 | return self.isError ? nil : self._value 160 | } 161 | /// Gives the type name as string. 162 | /// e.g. if it returns "Double" 163 | /// .asDouble returns Double 164 | public var type:String { 165 | switch _value { 166 | case is NSError: return "NSError" 167 | case is NSNull: return "NSNull" 168 | case let o as NSNumber: 169 | switch String.fromCString(o.objCType)! { 170 | case "c", "C": return "Bool" 171 | case "q", "l", "i", "s": return "Int" 172 | case "Q", "L", "I", "S": return "UInt" 173 | default: return "Double" 174 | } 175 | case is NSString: return "String" 176 | case is NSArray: return "Array" 177 | case is NSDictionary: return "Dictionary" 178 | default: return "NSError" 179 | } 180 | } 181 | /// check if self is NSError 182 | public var isError: Bool { return _value is NSError } 183 | /// check if self is NSNull 184 | public var isNull: Bool { return _value is NSNull } 185 | /// check if self is Bool 186 | public var isBool: Bool { return type == "Bool" } 187 | /// check if self is Int 188 | public var isInt: Bool { return type == "Int" } 189 | /// check if self is UInt 190 | public var isUInt: Bool { return type == "UInt" } 191 | /// check if self is Double 192 | public var isDouble: Bool { return type == "Double" } 193 | /// check if self is any type of number 194 | public var isNumber: Bool { 195 | if let o = _value as? NSNumber { 196 | let t = String.fromCString(o.objCType)! 197 | return t != "c" && t != "C" 198 | } 199 | return false 200 | } 201 | /// check if self is String 202 | public var isString: Bool { return _value is NSString } 203 | /// check if self is Array 204 | public var isArray: Bool { return _value is NSArray } 205 | /// check if self is Dictionary 206 | public var isDictionary: Bool { return _value is NSDictionary } 207 | /// check if self is a valid leaf node. 208 | public var isLeaf: Bool { 209 | return !(isArray || isDictionary || isError) 210 | } 211 | /// gives NSError if it holds the error. nil otherwise 212 | public var asError:NSError? { 213 | return _value as? NSError 214 | } 215 | /// gives NSNull if self holds it. nil otherwise 216 | public var asNull:NSNull? { 217 | return _value is NSNull ? JSON.null : nil 218 | } 219 | /// gives Bool if self holds it. nil otherwise 220 | public var asBool:Bool? { 221 | switch _value { 222 | case let o as NSNumber: 223 | switch String.fromCString(o.objCType)! { 224 | case "c", "C": return Bool(o.boolValue) 225 | default: 226 | return nil 227 | } 228 | default: return nil 229 | } 230 | } 231 | /// gives Int if self holds it. nil otherwise 232 | public var asInt:Int? { 233 | switch _value { 234 | case let o as NSNumber: 235 | switch String.fromCString(o.objCType)! { 236 | case "c", "C": 237 | return nil 238 | default: 239 | return Int(o.longLongValue) 240 | } 241 | default: return nil 242 | } 243 | } 244 | /// gives Int32 if self holds it. nil otherwise 245 | public var asInt32:Int32? { 246 | switch _value { 247 | case let o as NSNumber: 248 | switch String.fromCString(o.objCType)! { 249 | case "c", "C": 250 | return nil 251 | default: 252 | return Int32(o.longLongValue) 253 | } 254 | default: return nil 255 | } 256 | } 257 | /// gives Int64 if self holds it. nil otherwise 258 | public var asInt64:Int64? { 259 | switch _value { 260 | case let o as NSNumber: 261 | switch String.fromCString(o.objCType)! { 262 | case "c", "C": 263 | return nil 264 | default: 265 | return Int64(o.longLongValue) 266 | } 267 | default: return nil 268 | } 269 | } 270 | /// gives Float if self holds it. nil otherwise 271 | public var asFloat:Float? { 272 | switch _value { 273 | case let o as NSNumber: 274 | switch String.fromCString(o.objCType)! { 275 | case "c", "C": 276 | return nil 277 | default: 278 | return Float(o.floatValue) 279 | } 280 | default: return nil 281 | } 282 | } 283 | /// gives Double if self holds it. nil otherwise 284 | public var asDouble:Double? { 285 | switch _value { 286 | case let o as NSNumber: 287 | switch String.fromCString(o.objCType)! { 288 | case "c", "C": 289 | return nil 290 | default: 291 | return Double(o.doubleValue) 292 | } 293 | default: return nil 294 | } 295 | } 296 | // an alias to asDouble 297 | public var asNumber:Double? { return asDouble } 298 | /// gives String if self holds it. nil otherwise 299 | public var asString:String? { 300 | switch _value { 301 | case let o as NSString: 302 | return o as String 303 | default: return nil 304 | } 305 | } 306 | /// if self holds NSArray, gives a [JSON] 307 | /// with elements therein. nil otherwise 308 | public var asArray:[JSON]? { 309 | switch _value { 310 | case let o as NSArray: 311 | var result = [JSON]() 312 | for v:AnyObject in o { result.append(JSON(v)) } 313 | return result 314 | default: 315 | return nil 316 | } 317 | } 318 | /// if self holds NSDictionary, gives a [String:JSON] 319 | /// with elements therein. nil otherwise 320 | public var asDictionary:[String:JSON]? { 321 | switch _value { 322 | case let o as NSDictionary: 323 | var result = [String:JSON]() 324 | for (ko, v): (AnyObject, AnyObject) in o { 325 | if let k = ko as? String { 326 | result[k] = JSON(v) 327 | } 328 | } 329 | return result 330 | default: return nil 331 | } 332 | } 333 | /// Yields date from string 334 | public var asDate:NSDate? { 335 | if let dateString = _value as? String { 336 | let dateFormatter = NSDateFormatter() 337 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZ" 338 | return dateFormatter.dateFromString(dateString) 339 | } 340 | return nil 341 | } 342 | /// gives the number of elements if an array or a dictionary. 343 | /// you can use this to check if you can iterate. 344 | public var length:Int { 345 | switch _value { 346 | case let o as NSArray: return o.count 347 | case let o as NSDictionary: return o.count 348 | default: return 0 349 | } 350 | } 351 | // gives all values content in JSON object. 352 | public var allValues:JSON{ 353 | if(self._value.allValues == nil) { 354 | return JSON([]) 355 | } 356 | return JSON(self._value.allValues) 357 | } 358 | // gives all keys content in JSON object. 359 | public var allKeys:JSON{ 360 | if(self._value.allObjects == nil) { 361 | return JSON([]) 362 | } 363 | return JSON(self._value.allObjects) 364 | } 365 | } 366 | extension JSON : SequenceType { 367 | public func generate()->AnyGenerator<(AnyObject,JSON)> { 368 | switch _value { 369 | case let o as NSArray: 370 | var i = -1 371 | return anyGenerator { 372 | if ++i == o.count { return nil } 373 | return (i, JSON(o[i])) 374 | } 375 | case let o as NSDictionary: 376 | var ks = Array(o.allKeys.reverse()) 377 | return anyGenerator { 378 | if ks.isEmpty { return nil } 379 | if let k = ks.removeLast() as? String { 380 | return (k, JSON(o.valueForKey(k)!)) 381 | } else { 382 | return nil 383 | } 384 | } 385 | default: 386 | return anyGenerator{ nil } 387 | } 388 | } 389 | public func mutableCopyOfTheObject() -> AnyObject { 390 | return _value.mutableCopy() 391 | } 392 | } 393 | extension JSON : CustomStringConvertible { 394 | /// stringifies self. 395 | /// if pretty:true it pretty prints 396 | public func toString(pretty:Bool=false)->String { 397 | switch _value { 398 | case is NSError: return "\(_value)" 399 | case is NSNull: return "null" 400 | case let o as NSNumber: 401 | switch String.fromCString(o.objCType)! { 402 | case "c", "C": 403 | return o.boolValue.description 404 | case "q", "l", "i", "s": 405 | return o.longLongValue.description 406 | case "Q", "L", "I", "S": 407 | return o.unsignedLongLongValue.description 408 | default: 409 | switch o.doubleValue { 410 | case 0.0/0.0: return "0.0/0.0" // NaN 411 | case -1.0/0.0: return "-1.0/0.0" // -infinity 412 | case +1.0/0.0: return "+1.0/0.0" // infinity 413 | default: 414 | return o.doubleValue.description 415 | } 416 | } 417 | case let o as NSString: 418 | return o.debugDescription 419 | default: 420 | let opts = pretty ? NSJSONWritingOptions.PrettyPrinted : NSJSONWritingOptions() 421 | if let data = (try? NSJSONSerialization.dataWithJSONObject( 422 | _value, options:opts)) as NSData? { 423 | if let result = NSString( 424 | data:data, encoding:NSUTF8StringEncoding 425 | ) as? String { 426 | return result 427 | } 428 | } 429 | return "YOU ARE NOT SUPPOSED TO SEE THIS!" 430 | } 431 | } 432 | public var description:String { return toString() } 433 | } -------------------------------------------------------------------------------- /LightSwordX/Lib/Regex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Regex.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 1/3/16. 6 | // Copyright © 2016 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Regex { 12 | let internalExpression: NSRegularExpression 13 | let pattern: String 14 | 15 | init(_ pattern: String) { 16 | self.pattern = pattern 17 | self.internalExpression = try! NSRegularExpression(pattern: pattern, options: .CaseInsensitive) 18 | } 19 | 20 | func test(input: String) -> Bool { 21 | let matches = self.internalExpression.matchesInString(input, options: .ReportCompletion, range:NSMakeRange(0, input.length)) 22 | return matches.count > 0 23 | } 24 | } -------------------------------------------------------------------------------- /LightSwordX/Lib/SettingsHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDefaultsHelper.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/23/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class SettingsHelper { 12 | 13 | private static let defaults = NSUserDefaults.standardUserDefaults() 14 | 15 | public class func saveValue(value: AnyObject, forKey key: String) { 16 | defaults.setValue(value, forKey: key) 17 | } 18 | 19 | public class func loadValue(defaultValue defaultValue: T, forKey key: String) -> T { 20 | let value: AnyObject? = defaults.objectForKey(key) 21 | if let v: AnyObject = value { 22 | return v as! T 23 | } 24 | 25 | return defaultValue 26 | } 27 | 28 | public class func loadValueForKey(key: String) -> T! { 29 | return loadValue(defaultValue: nil, forKey: key) 30 | } 31 | 32 | public class func removeValueForKey(key: String) { 33 | defaults.removeObjectForKey(key) 34 | } 35 | 36 | public class func reset() { 37 | defaults.removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!) 38 | } 39 | 40 | public class func synchronize() { 41 | defaults.synchronize() 42 | } 43 | } -------------------------------------------------------------------------------- /LightSwordX/Lib/StatisticsHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Number.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/27/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class StatisticsHelper { 12 | 13 | private static let KB: Double = 1024 14 | private static let MB = 1024 * KB 15 | private static let GB = 1024 * MB 16 | private static let TB = 1024 * GB 17 | private static var formatter: NSNumberFormatter! 18 | 19 | static func toStatisticsString(number: UInt64) -> (value: Double, formattedValue: String, unit: String) { 20 | if formatter == nil { 21 | formatter = NSNumberFormatter() 22 | formatter.numberStyle = .DecimalStyle 23 | } 24 | 25 | var value = Double(number) 26 | var unit = "Bytes" 27 | formatter.format = "0.0#" 28 | 29 | switch value { 30 | case let v where v > TB: 31 | value = value / TB 32 | unit = "TB" 33 | break 34 | 35 | case let v where v > GB && v <= TB: 36 | value = value / GB 37 | unit = "GB" 38 | break 39 | 40 | case let v where v > MB && v <= GB: 41 | value = value / MB 42 | unit = "MB" 43 | break 44 | 45 | case let v where v > KB && v <= MB: 46 | value = value / KB 47 | unit = "KB" 48 | break 49 | 50 | default: 51 | formatter.format = "0" 52 | break 53 | } 54 | 55 | return (value: value, formattedValue: formatter.stringFromNumber(value)!, unit: unit) 56 | } 57 | 58 | static func getUptimeInMilliseconds() -> UInt64 { 59 | let kOneMillion: UInt64 = 1000 * 1000; 60 | var s_timebase_info = mach_timebase_info_data_t(); 61 | 62 | if (s_timebase_info.denom == 0) { 63 | mach_timebase_info(&s_timebase_info); 64 | } 65 | 66 | // mach_absolute_time() returns billionth of seconds, 67 | // so divide by one million to get milliseconds 68 | return mach_absolute_time() * UInt64(s_timebase_info.numer) / (kOneMillion * UInt64(s_timebase_info.denom)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /LightSwordX/Lib/String.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/19/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | 13 | public init?(count: Int, byRepeatingString str: String) { 14 | var newString = "" 15 | 16 | for _ in 0 ..< count { 17 | newString += str 18 | } 19 | 20 | self.init(newString) 21 | } 22 | 23 | var length: Int { 24 | get { 25 | return self.characters.count 26 | } 27 | } 28 | 29 | func beginsWith (str: String) -> Bool { 30 | if let range = self.rangeOfString(str) { 31 | return range.startIndex == self.startIndex 32 | } 33 | return false 34 | } 35 | 36 | func endsWith (str: String) -> Bool { 37 | if let range = self.rangeOfString(str, options: .BackwardsSearch) { 38 | return range.endIndex == self.endIndex 39 | } 40 | return false 41 | } 42 | 43 | func indexOf(target: String) -> Int? { 44 | guard let range = self.rangeOfString(target) else { 45 | return nil 46 | } 47 | 48 | return startIndex.distanceTo(range.startIndex) 49 | } 50 | 51 | func lastIndexOf(target: String) -> Int { 52 | guard let range = self.rangeOfString(target, options: .BackwardsSearch) else { 53 | return -1 54 | } 55 | 56 | return startIndex.distanceTo(range.startIndex) 57 | } 58 | } -------------------------------------------------------------------------------- /LightSwordX/LightSwordX-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /LightSwordX/LightSwordX.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LightSwordX/Models/UserServer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Server.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/23/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class UserServer: Equatable { 12 | var address = "127.0.0.1" 13 | var port = 8900 14 | var listenAddr = "127.0.0.1" 15 | var listenPort = 1080 16 | var cipherAlgorithm = "aes-256-cfb" 17 | var password = "lightsword.neko" 18 | var keepConnection = false 19 | var proxyMode = ProxyMode.WHITE 20 | var id = 0 21 | } 22 | 23 | func ==(lhs: UserServer, rhs: UserServer) -> Bool { 24 | return lhs.address == rhs.address && lhs.port == rhs.port && lhs.listenPort == rhs.listenPort && lhs.listenAddr == rhs.listenAddr && lhs.cipherAlgorithm == rhs.cipherAlgorithm && lhs.password == rhs.password && lhs.keepConnection == rhs.keepConnection 25 | } -------------------------------------------------------------------------------- /LightSwordX/Socket/ysocket.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) <2014>, skysent 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. All advertising materials mentioning features or use of this software 13 | must display the following acknowledgement: 14 | This product includes software developed by skysent. 15 | 4. Neither the name of the skysent nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | import Foundation 32 | public class YSocket{ 33 | var addr:String 34 | var port:Int 35 | var fd:Int32? 36 | init(){ 37 | self.addr="" 38 | self.port=0 39 | } 40 | public init(addr a:String,port p:Int){ 41 | self.addr=a 42 | self.port=p 43 | } 44 | } -------------------------------------------------------------------------------- /LightSwordX/Socket/ytcpsocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) <2014>, skysent 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. All advertising materials mentioning features or use of this software 13 | must display the following acknowledgement: 14 | This product includes software developed by skysent. 15 | 4. Neither the name of the skysent nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | void ytcpsocket_set_block(int socket,int on) { 46 | int flags; 47 | flags = fcntl(socket,F_GETFL,0); 48 | if (on==0) { 49 | fcntl(socket, F_SETFL, flags | O_NONBLOCK); 50 | }else{ 51 | flags &= ~ O_NONBLOCK; 52 | fcntl(socket, F_SETFL, flags); 53 | } 54 | } 55 | int ytcpsocket_connect(const char *host,int port,int timeout){ 56 | struct sockaddr_in sa; 57 | struct hostent *hp; 58 | int sockfd = -1; 59 | hp = gethostbyname(host); 60 | if(hp==NULL){ 61 | return -1; 62 | } 63 | bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length); 64 | sa.sin_family = hp->h_addrtype; 65 | sa.sin_port = htons(port); 66 | sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0); 67 | ytcpsocket_set_block(sockfd,0); 68 | connect(sockfd, (struct sockaddr *)&sa, sizeof(sa)); 69 | fd_set fdwrite; 70 | struct timeval tvSelect; 71 | FD_ZERO(&fdwrite); 72 | FD_SET(sockfd, &fdwrite); 73 | tvSelect.tv_sec = timeout; 74 | tvSelect.tv_usec = 0; 75 | int retval = select(sockfd + 1,NULL, &fdwrite, NULL, &tvSelect); 76 | if (retval<0) { 77 | close(sockfd); 78 | return -2; 79 | }else if(retval==0){//timeout 80 | close(sockfd); 81 | return -3; 82 | }else{ 83 | int error=0; 84 | int errlen=sizeof(error); 85 | getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&errlen); 86 | if(error!=0){ 87 | close(sockfd); 88 | return -4;//connect fail 89 | } 90 | ytcpsocket_set_block(sockfd, 1); 91 | int set = 1; 92 | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); 93 | return sockfd; 94 | } 95 | } 96 | int ytcpsocket_close(int socketfd){ 97 | return close(socketfd); 98 | } 99 | int ytcpsocket_pull(int socketfd,char *data,int len,int timeout_sec){ 100 | if (timeout_sec>0) { 101 | fd_set fdset; 102 | struct timeval timeout; 103 | timeout.tv_usec = 0; 104 | timeout.tv_sec = timeout_sec; 105 | FD_ZERO(&fdset); 106 | FD_SET(socketfd, &fdset); 107 | int ret = select(socketfd+1, &fdset, NULL, NULL, &timeout); 108 | if (ret<=0) { 109 | return ret; // select-call failed or timeout occurred (before anything was sent) 110 | } 111 | } 112 | int readlen=(int)read(socketfd,data,len); 113 | return readlen; 114 | } 115 | int ytcpsocket_send(int socketfd,const char *data,int len){ 116 | int byteswrite=0; 117 | while (len-byteswrite>0) { 118 | int writelen=(int)write(socketfd, data+byteswrite, len-byteswrite); 119 | if (writelen<0) { 120 | return -1; 121 | } 122 | byteswrite+=writelen; 123 | } 124 | return byteswrite; 125 | } 126 | //return socket fd 127 | int ytcpsocket_listen(const char *addr,int port){ 128 | //create socket 129 | int socketfd=socket(AF_INET, SOCK_STREAM, 0); 130 | int reuseon = 1; 131 | setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon) ); 132 | //bind 133 | struct sockaddr_in serv_addr; 134 | memset( &serv_addr, '\0', sizeof(serv_addr)); 135 | serv_addr.sin_family = AF_INET; 136 | serv_addr.sin_addr.s_addr = inet_addr(addr); 137 | serv_addr.sin_port = htons(port); 138 | int r=bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 139 | if(r==0){ 140 | if (listen(socketfd, 128)==0) { 141 | return socketfd; 142 | }else{ 143 | return -2;//listen error 144 | } 145 | }else{ 146 | return -1;//bind error 147 | } 148 | } 149 | //return client socket fd 150 | int ytcpsocket_accept(int onsocketfd,char *remoteip,int* remoteport){ 151 | socklen_t clilen; 152 | struct sockaddr_in cli_addr; 153 | clilen = sizeof(cli_addr); 154 | int newsockfd = accept(onsocketfd, (struct sockaddr *) &cli_addr, &clilen); 155 | char *clientip=inet_ntoa(cli_addr.sin_addr); 156 | memcpy(remoteip, clientip, strlen(clientip)); 157 | *remoteport=cli_addr.sin_port; 158 | if(newsockfd>0){ 159 | return newsockfd; 160 | }else{ 161 | return -1; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /LightSwordX/Socket/ytcpsocket.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) <2014>, skysent 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. All advertising materials mentioning features or use of this software 13 | must display the following acknowledgement: 14 | This product includes software developed by skysent. 15 | 4. Neither the name of the skysent nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | import Foundation 31 | 32 | @asmname("ytcpsocket_connect") func c_ytcpsocket_connect(host:UnsafePointer,port:Int32,timeout:Int32) -> Int32 33 | @asmname("ytcpsocket_close") func c_ytcpsocket_close(fd:Int32) -> Int32 34 | @asmname("ytcpsocket_send") func c_ytcpsocket_send(fd:Int32,buff:UnsafePointer,len:Int32) -> Int32 35 | @asmname("ytcpsocket_pull") func c_ytcpsocket_pull(fd:Int32,buff:UnsafePointer,len:Int32,timeout:Int32) -> Int32 36 | @asmname("ytcpsocket_listen") func c_ytcpsocket_listen(addr:UnsafePointer,port:Int32)->Int32 37 | @asmname("ytcpsocket_accept") func c_ytcpsocket_accept(onsocketfd:Int32,ip:UnsafePointer,port:UnsafePointer) -> Int32 38 | 39 | public class TCPClient:YSocket{ 40 | /* 41 | * connect to server 42 | * return success or fail with message 43 | */ 44 | public func connect(timeout t:Int)->(Bool,String){ 45 | let rs:Int32=c_ytcpsocket_connect(self.addr, port: Int32(self.port), timeout: Int32(t)) 46 | if rs>0{ 47 | self.fd=rs 48 | return (true,"connect success") 49 | }else{ 50 | switch rs{ 51 | case -1: 52 | return (false,"query server fail") 53 | case -2: 54 | return (false,"connection closed") 55 | case -3: 56 | return (false,"connect timeout") 57 | default: 58 | return (false,"unknow err.") 59 | } 60 | } 61 | } 62 | /* 63 | * close socket 64 | * return success or fail with message 65 | */ 66 | public func close()->(Bool,String){ 67 | if let fd:Int32=self.fd{ 68 | c_ytcpsocket_close(fd) 69 | self.fd=nil 70 | return (true,"close success") 71 | }else{ 72 | return (false,"socket not open") 73 | } 74 | } 75 | /* 76 | * send data 77 | * return success or fail with message 78 | */ 79 | public func send(data d:[UInt8])->(Bool,String){ 80 | if let fd:Int32=self.fd{ 81 | let sendsize:Int32=c_ytcpsocket_send(fd, buff: d, len: Int32(d.count)) 82 | if Int(sendsize)==d.count{ 83 | return (true,"send success") 84 | }else{ 85 | return (false,"send error") 86 | } 87 | }else{ 88 | return (false,"socket not open") 89 | } 90 | } 91 | /* 92 | * send string 93 | * return success or fail with message 94 | */ 95 | public func send(str s:String)->(Bool,String){ 96 | if let fd:Int32=self.fd{ 97 | let sendsize:Int32=c_ytcpsocket_send(fd, buff: s, len: Int32(strlen(s))) 98 | if sendsize==Int32(strlen(s)){ 99 | return (true,"send success") 100 | }else{ 101 | return (false,"send error") 102 | } 103 | }else{ 104 | return (false,"socket not open") 105 | } 106 | } 107 | /* 108 | * 109 | * send nsdata 110 | */ 111 | public func send(data d:NSData)->(Bool,String){ 112 | if let fd:Int32=self.fd{ 113 | var buff:[UInt8] = [UInt8](count:d.length,repeatedValue:0x0) 114 | d.getBytes(&buff, length: d.length) 115 | let sendsize:Int32=c_ytcpsocket_send(fd, buff: buff, len: Int32(d.length)) 116 | if sendsize==Int32(d.length){ 117 | return (true,"send success") 118 | }else{ 119 | return (false,"send error") 120 | } 121 | }else{ 122 | return (false,"socket not open") 123 | } 124 | } 125 | /* 126 | * read data with expect length 127 | * return success or fail with message 128 | */ 129 | public func read(expectlen:Int, timeout:Int = -1)->[UInt8]?{ 130 | if let fd:Int32 = self.fd{ 131 | var buff:[UInt8] = [UInt8](count:expectlen,repeatedValue:0x0) 132 | let readLen:Int32=c_ytcpsocket_pull(fd, buff: &buff, len: Int32(expectlen), timeout: Int32(timeout)) 133 | if readLen<=0{ 134 | return nil 135 | } 136 | let rs=buff[0...Int(readLen-1)] 137 | let data:[UInt8] = Array(rs) 138 | return data 139 | } 140 | return nil 141 | } 142 | } 143 | 144 | public class TCPServer:YSocket{ 145 | 146 | public func listen()->(Bool,String){ 147 | 148 | let fd:Int32=c_ytcpsocket_listen(self.addr, port: Int32(self.port)) 149 | if fd>0{ 150 | self.fd=fd 151 | return (true,"listen success") 152 | }else{ 153 | return (false,"listen fail") 154 | } 155 | } 156 | public func accept()->TCPClient?{ 157 | if let serferfd=self.fd{ 158 | var buff:[Int8] = [Int8](count:16,repeatedValue:0x0) 159 | var port:Int32=0 160 | let clientfd:Int32=c_ytcpsocket_accept(serferfd, ip: &buff,port: &port) 161 | if clientfd<0{ 162 | return nil 163 | } 164 | let tcpClient:TCPClient=TCPClient() 165 | tcpClient.fd=clientfd 166 | tcpClient.port=Int(port) 167 | if let addr=String(CString: buff, encoding: NSUTF8StringEncoding){ 168 | tcpClient.addr=addr 169 | } 170 | return tcpClient 171 | } 172 | return nil 173 | } 174 | public func close()->(Bool,String){ 175 | if let fd:Int32=self.fd{ 176 | c_ytcpsocket_close(fd) 177 | self.fd=nil 178 | return (true,"close success") 179 | }else{ 180 | return (false,"socket not open") 181 | } 182 | } 183 | } 184 | 185 | 186 | -------------------------------------------------------------------------------- /LightSwordX/Socket/yudpsocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) <2014>, skysent 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. All advertising materials mentioning features or use of this software 13 | must display the following acknowledgement: 14 | This product includes software developed by skysent. 15 | 4. Neither the name of the skysent nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #define yudpsocket_buff_len 8192 40 | 41 | //return socket fd 42 | int yudpsocket_server(const char *addr,int port){ 43 | //create socket 44 | int socketfd=socket(AF_INET, SOCK_DGRAM, 0); 45 | int reuseon = 1; 46 | setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon) ); 47 | //bind 48 | struct sockaddr_in serv_addr; 49 | memset( &serv_addr, '\0', sizeof(serv_addr)); 50 | serv_addr.sin_family = AF_INET; 51 | serv_addr.sin_addr.s_addr = inet_addr(addr); 52 | serv_addr.sin_port = htons(port); 53 | int r=bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 54 | if(r==0){ 55 | return socketfd; 56 | }else{ 57 | return -1; 58 | } 59 | } 60 | int yudpsocket_recive(int socket_fd,char *outdata,int expted_len,char *remoteip,int* remoteport){ 61 | struct sockaddr_in cli_addr; 62 | socklen_t clilen=sizeof(cli_addr); 63 | memset(&cli_addr, 0x0, sizeof(struct sockaddr_in)); 64 | int len=(int)recvfrom(socket_fd, outdata, expted_len, 0, (struct sockaddr *)&cli_addr, &clilen); 65 | char *clientip=inet_ntoa(cli_addr.sin_addr); 66 | memcpy(remoteip, clientip, strlen(clientip)); 67 | *remoteport=cli_addr.sin_port; 68 | return len; 69 | } 70 | int yudpsocket_close(int socket_fd){ 71 | return close(socket_fd); 72 | } 73 | //return socket fd 74 | int yudpsocket_client(){ 75 | //create socket 76 | int socketfd=socket(AF_INET, SOCK_DGRAM, 0); 77 | int reuseon = 1; 78 | setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon) ); 79 | return socketfd; 80 | } 81 | int yudpsocket_get_server_ip(char *host,char *ip){ 82 | struct hostent *hp; 83 | struct sockaddr_in addr; 84 | hp = gethostbyname(host); 85 | if(hp==NULL){ 86 | return -1; 87 | } 88 | bcopy((char *)hp->h_addr, (char *)&addr.sin_addr, hp->h_length); 89 | char *clientip=inet_ntoa(addr.sin_addr); 90 | memcpy(ip, clientip, strlen(clientip)); 91 | return 0; 92 | } 93 | //send message to addr and port 94 | int yudpsocket_sentto(int socket_fd,char *msg,int len, char *toaddr, int topotr){ 95 | struct sockaddr_in addr; 96 | socklen_t addrlen=sizeof(addr); 97 | memset(&addr, 0x0, sizeof(struct sockaddr_in)); 98 | addr.sin_family=AF_INET; 99 | addr.sin_port=htons(topotr); 100 | addr.sin_addr.s_addr=inet_addr(toaddr); 101 | int sendlen=(int)sendto(socket_fd, msg, len, 0, (struct sockaddr *)&addr, addrlen); 102 | return sendlen; 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /LightSwordX/Socket/yudpsocket.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) <2014>, skysent 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. All advertising materials mentioning features or use of this software 13 | must display the following acknowledgement: 14 | This product includes software developed by skysent. 15 | 4. Neither the name of the skysent nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | import Foundation 32 | 33 | @asmname("yudpsocket_server") func c_yudpsocket_server(host:UnsafePointer,port:Int32) -> Int32 34 | @asmname("yudpsocket_recive") func c_yudpsocket_recive(fd:Int32,buff:UnsafePointer,len:Int32,ip:UnsafePointer,port:UnsafePointer) -> Int32 35 | @asmname("yudpsocket_close") func c_yudpsocket_close(fd:Int32) -> Int32 36 | @asmname("yudpsocket_client") func c_yudpsocket_client() -> Int32 37 | @asmname("yudpsocket_get_server_ip") func c_yudpsocket_get_server_ip(host:UnsafePointer,ip:UnsafePointer) -> Int32 38 | @asmname("yudpsocket_sentto") func c_yudpsocket_sentto(fd:Int32,buff:UnsafePointer,len:Int32,ip:UnsafePointer,port:Int32) -> Int32 39 | 40 | public class UDPClient: YSocket { 41 | public override init(addr a:String,port p:Int){ 42 | super.init() 43 | let remoteipbuff:[Int8] = [Int8](count:16,repeatedValue:0x0) 44 | let ret=c_yudpsocket_get_server_ip(a, ip: remoteipbuff) 45 | if ret==0{ 46 | if let ip=String(CString: remoteipbuff, encoding: NSUTF8StringEncoding){ 47 | self.addr=ip 48 | self.port=p 49 | let fd:Int32=c_yudpsocket_client() 50 | if fd>0{ 51 | self.fd=fd 52 | } 53 | } 54 | } 55 | } 56 | /* 57 | * send data 58 | * return success or fail with message 59 | */ 60 | public func send(data d:[UInt8])->(Bool,String){ 61 | if let fd:Int32=self.fd{ 62 | let sendsize:Int32=c_yudpsocket_sentto(fd, buff: d, len: Int32(d.count), ip: self.addr,port: Int32(self.port)) 63 | if Int(sendsize)==d.count{ 64 | return (true,"send success") 65 | }else{ 66 | return (false,"send error") 67 | } 68 | }else{ 69 | return (false,"socket not open") 70 | } 71 | } 72 | /* 73 | * send string 74 | * return success or fail with message 75 | */ 76 | public func send(str s:String)->(Bool,String){ 77 | if let fd:Int32=self.fd{ 78 | let sendsize:Int32=c_yudpsocket_sentto(fd, buff: s, len: Int32(strlen(s)), ip: self.addr,port: Int32(self.port)) 79 | if sendsize==Int32(strlen(s)){ 80 | return (true,"send success") 81 | }else{ 82 | return (false,"send error") 83 | } 84 | }else{ 85 | return (false,"socket not open") 86 | } 87 | } 88 | /* 89 | * 90 | * send nsdata 91 | */ 92 | public func send(data d:NSData)->(Bool,String){ 93 | if let fd:Int32=self.fd{ 94 | var buff:[UInt8] = [UInt8](count:d.length,repeatedValue:0x0) 95 | d.getBytes(&buff, length: d.length) 96 | let sendsize:Int32=c_yudpsocket_sentto(fd, buff: buff, len: Int32(d.length), ip: self.addr,port: Int32(self.port)) 97 | if sendsize==Int32(d.length){ 98 | return (true,"send success") 99 | }else{ 100 | return (false,"send error") 101 | } 102 | }else{ 103 | return (false,"socket not open") 104 | } 105 | } 106 | public func close()->(Bool,String){ 107 | if let fd:Int32=self.fd{ 108 | c_yudpsocket_close(fd) 109 | self.fd=nil 110 | return (true,"close success") 111 | }else{ 112 | return (false,"socket not open") 113 | } 114 | } 115 | //TODO add multycast and boardcast 116 | } 117 | 118 | public class UDPServer:YSocket{ 119 | public override init(addr a:String,port p:Int){ 120 | super.init(addr: a, port: p) 121 | let fd:Int32 = c_yudpsocket_server(self.addr, port: Int32(self.port)) 122 | if fd>0{ 123 | self.fd=fd 124 | } 125 | } 126 | //TODO add multycast and boardcast 127 | public func recv(expectlen:Int)->([UInt8]?,String,Int){ 128 | if let fd:Int32 = self.fd{ 129 | var buff:[UInt8] = [UInt8](count:expectlen,repeatedValue:0x0) 130 | var remoteipbuff:[Int8] = [Int8](count:16,repeatedValue:0x0) 131 | var remoteport:Int32=0 132 | let readLen:Int32=c_yudpsocket_recive(fd, buff: buff, len: Int32(expectlen), ip: &remoteipbuff, port: &remoteport) 133 | let port:Int=Int(remoteport) 134 | var addr:String="" 135 | if let ip=String(CString: remoteipbuff, encoding: NSUTF8StringEncoding){ 136 | addr=ip 137 | } 138 | if readLen<=0{ 139 | return (nil,addr,port) 140 | } 141 | let rs=buff[0...Int(readLen-1)] 142 | let data:[UInt8] = Array(rs) 143 | return (data,addr,port) 144 | } 145 | return (nil,"no ip",0) 146 | } 147 | public func close()->(Bool,String){ 148 | if let fd:Int32=self.fd{ 149 | c_yudpsocket_close(fd) 150 | self.fd=nil 151 | return (true,"close success") 152 | }else{ 153 | return (false,"socket not open") 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /LightSwordX/Socket6/Socket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Socket.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 1/9/16. 6 | // Copyright © 2016 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Socket { 12 | var addr: String 13 | var port: Int 14 | var fd: Int32? 15 | internal var _timeout = -1 16 | 17 | init() { 18 | self.addr = "" 19 | self.port = 0 20 | } 21 | 22 | init(addr a: String, port p: Int) { 23 | self.addr = a 24 | self.port = p 25 | } 26 | } -------------------------------------------------------------------------------- /LightSwordX/Socket6/TCPSocket.c: -------------------------------------------------------------------------------- 1 | // 2 | // TCPSocket.c 3 | // LightSwordX 4 | // 5 | // Created by Neko on 1/9/16. 6 | // Copyright © 2016 Neko. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | char* get_ip_str(const struct sockaddr *sa, char *s, unsigned int maxlen) 26 | { 27 | switch(sa->sa_family) { 28 | case AF_INET: 29 | inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen); 30 | break; 31 | 32 | case AF_INET6: 33 | inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen); 34 | break; 35 | 36 | default: 37 | strncpy(s, "Unknown AF", maxlen); 38 | return NULL; 39 | } 40 | 41 | return s; 42 | } 43 | 44 | void fill_addrinfo_port(const struct addrinfo* addr, int port) { 45 | if (addr->ai_family == AF_INET) { 46 | struct sockaddr_in* ipv4 = (struct sockaddr_in*)(addr->ai_addr); 47 | ipv4->sin_port = htons(port); 48 | } else if (addr->ai_family == AF_INET6) { 49 | struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)(addr->ai_addr); 50 | ipv6->sin6_port = htons(port); 51 | } 52 | } 53 | 54 | void tcpsocket_set_block(int socket, int on) { 55 | int flags = fcntl(socket, F_GETFL, 0); 56 | 57 | if (on == 0) { 58 | fcntl(socket, F_SETFL, flags | O_NONBLOCK); 59 | } else { 60 | flags &= ~ O_NONBLOCK; 61 | fcntl(socket, F_SETFL, flags); 62 | } 63 | } 64 | 65 | int tcpsocket_connect(const char* host, int port, int timeout) { 66 | 67 | struct addrinfo hints, *addrs, *p; 68 | memset(&hints, 0, sizeof(hints)); 69 | hints.ai_family = AF_UNSPEC; 70 | hints.ai_socktype = SOCK_STREAM; 71 | 72 | int s = getaddrinfo(host, NULL, &hints, &addrs); 73 | if (s != 0) { 74 | return -1; 75 | } 76 | 77 | int socketfd = -1; 78 | int error = -1; 79 | int errorlen = sizeof(error); 80 | 81 | for (p = addrs; p != NULL; p = p->ai_next) { 82 | 83 | socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 84 | if (socketfd == -1) { 85 | error = socketfd; 86 | continue; 87 | } 88 | 89 | fill_addrinfo_port(p, port); 90 | 91 | tcpsocket_set_block(socketfd, 0); // Set non-block socket 92 | connect(socketfd, p->ai_addr, p->ai_addrlen); 93 | 94 | fd_set fdset; 95 | FD_ZERO(&fdset); 96 | FD_SET(socketfd, &fdset); 97 | 98 | struct timeval tv; 99 | tv.tv_sec = timeout; 100 | tv.tv_usec = 0; 101 | 102 | int retval = select(socketfd + 1, NULL, &fdset, NULL, &tv); 103 | if (retval <= 0) { 104 | close(socketfd); // Error or Timeout 105 | socketfd = -1; 106 | error = retval < 0 ? -2 : -3; 107 | continue; 108 | } 109 | 110 | getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&errorlen); 111 | if (error != 0) { 112 | fprintf(stderr, "failed to connect: %s\n", gai_strerror(error)); 113 | close(socketfd); // Failed to connect 114 | socketfd = -1; 115 | continue; 116 | } 117 | 118 | tcpsocket_set_block(socketfd, 1); 119 | int set = 1; 120 | setsockopt(socketfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); 121 | 122 | break; 123 | } 124 | 125 | freeaddrinfo(addrs); 126 | 127 | return socketfd > 0 ? socketfd : error; 128 | } 129 | 130 | int tcpsocket_close(int socketfd) { 131 | return close(socketfd); 132 | } 133 | 134 | int tcpsocket_read(int socketfd, char* data, int len) { 135 | return (int)read(socketfd, data, len); 136 | } 137 | 138 | int tcpsocket_send(int socketfd, const char* data, int len) { 139 | int byteswrote = 0; 140 | while (len - byteswrote > 0) { 141 | int wrotelen = (int)write(socketfd, data + byteswrote, len - byteswrote); 142 | if (wrotelen < 0) { 143 | return -1; 144 | } 145 | 146 | byteswrote += wrotelen; 147 | } 148 | 149 | return byteswrote; 150 | } 151 | 152 | int tcpsocket_accept(int socketfd, char* remoteip, int* remoteport) { 153 | char clienthost[NI_MAXHOST]; 154 | char clientservice[NI_MAXSERV]; 155 | 156 | struct sockaddr_storage clientaddr; 157 | socklen_t addrlen = sizeof(clientaddr); 158 | 159 | int connfd = accept(socketfd, (struct sockaddr *)&clientaddr, &addrlen); 160 | if (getnameinfo((struct sockaddr *)&clientaddr, addrlen, clienthost, NI_MAXHOST, clientservice, NI_MAXSERV, NI_NUMERICHOST)) { 161 | fprintf(stderr, "can not resolve name"); 162 | } else { 163 | if (clientaddr.ss_family == AF_INET) { 164 | struct sockaddr_in* ipv4 = (struct sockaddr_in *)&clientaddr; 165 | char* clientip = inet_ntoa(ipv4->sin_addr); 166 | memcpy(remoteip, clientip, strlen(clientip)); 167 | *remoteport = ipv4->sin_port; 168 | } else if (clientaddr.ss_family == AF_INET6) { 169 | struct sockaddr_in6* ipv6 = (struct sockaddr_in6 *)&clientaddr; 170 | char clientip[INET6_ADDRSTRLEN]; 171 | inet_ntop(AF_INET6, &(ipv6->sin6_addr), clientip, INET6_ADDRSTRLEN); 172 | memcpy(remoteip, clientip, strlen(clientip)); 173 | *remoteport = ipv6->sin6_port; 174 | } 175 | } 176 | 177 | return connfd > 0 ? connfd : -1; 178 | } 179 | 180 | int tcpsocket_listen(const char *addr,int port){ 181 | 182 | int socketfd=socket(AF_INET, SOCK_STREAM, 0); 183 | int reuseon = 1; 184 | 185 | setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon) ); 186 | 187 | //bind 188 | struct sockaddr_in serv_addr; 189 | memset( &serv_addr, '\0', sizeof(serv_addr)); 190 | serv_addr.sin_family = AF_INET; 191 | serv_addr.sin_addr.s_addr = inet_addr(addr); 192 | serv_addr.sin_port = htons(port); 193 | 194 | int r = bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 195 | if(r == 0){ 196 | if (listen(socketfd, 128) == 0) { 197 | return socketfd; 198 | }else{ 199 | return -2;//listen error 200 | } 201 | }else{ 202 | return -1;//bind error 203 | } 204 | } 205 | 206 | int tcpsocket6_listen(const char* addr, int port) { 207 | 208 | int socketfd = socket(AF_INET6, SOCK_STREAM, 0); 209 | 210 | int reuse = 1; 211 | setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 212 | 213 | if (socketfd < 0) { 214 | return socketfd; 215 | } 216 | 217 | struct sockaddr_in6 sa; 218 | memset(&sa, 0, sizeof(sa)); 219 | sa.sin6_port = htons(port); 220 | sa.sin6_family = AF_INET6; 221 | sa.sin6_len = sizeof(sa); 222 | inet_pton(AF_INET6, addr, &(sa.sin6_addr)); 223 | 224 | int b = bind(socketfd, (struct sockaddr *) &sa, sizeof(sa)); 225 | if (b != 0) { 226 | fprintf(stderr, "%s\n", gai_strerror(b)); 227 | return -1; 228 | } 229 | 230 | int l = listen(socketfd, 128); 231 | if (l !=0 ) { 232 | fprintf(stderr, "%s\n", gai_strerror(b)); 233 | return -2; 234 | } 235 | 236 | return socketfd; 237 | } 238 | 239 | void set_socket_timeout(int socketfd, int timeout) { 240 | 241 | if (timeout < 0) return; 242 | 243 | struct timeval tv; 244 | 245 | tv.tv_sec = timeout > 0 ? timeout : 0; 246 | tv.tv_usec = 0; 247 | 248 | setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); 249 | } -------------------------------------------------------------------------------- /LightSwordX/Socks5/Socks5Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Socks5Constants.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Authentication: UInt8 { 12 | case NOAUTH = 0x00 13 | case GSSAPI = 0x01 14 | case USERPASS = 0x02 15 | case NONE = 0xFF 16 | } 17 | 18 | enum REQUEST_CMD: UInt8 { 19 | case CONNECT = 0x01 20 | case BIND = 0x02 21 | case UDP_ASSOCIATE = 0x03 22 | } 23 | 24 | enum ATYP: UInt8 { 25 | case IPV4 = 0x01 26 | case DN = 0x03 27 | case IPV6 = 0x04 28 | } 29 | 30 | enum REPLY_CODE: UInt8 { 31 | case SUCCESS = 0x00 32 | case SOCKS_SERVER_FAILURE = 0x01 33 | case CONNECTION_NOT_ALLOWED = 0x02 34 | case NETWORK_UNREACHABLE = 0x03 35 | case HOST_UNREACHABLE = 0x04 36 | case CONNECTION_REFUSED = 0x05 37 | case TTL_EXPIRED = 0x06 38 | case CMD_NOT_SUPPORTED = 0x07 39 | case ADDR_TYPE_NOT_SUPPORTED = 0x08 40 | } 41 | 42 | enum SOCKS_VER: UInt8 { 43 | case V5 = 0x05 44 | } 45 | -------------------------------------------------------------------------------- /LightSwordX/Socks5/Socks5Helper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Socks5Helper.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SINQ 11 | 12 | class Socks5Helper { 13 | static func refineDestination(rawData: [UInt8]) -> (cmd: REQUEST_CMD, addr: String, port: Int, headerSize: Int)? { 14 | if rawData.count < 4 { 15 | return nil 16 | } 17 | 18 | if let cmd = REQUEST_CMD(rawValue: rawData[1]) { 19 | 20 | let atyp = rawData[3] 21 | var addr = "" 22 | var dnLength: UInt8 = 0 23 | 24 | switch (atyp) { 25 | case ATYP.DN.rawValue: 26 | dnLength = rawData[4] 27 | let data = sinq(rawData).skip(5).take(Int(dnLength)).toArray() 28 | addr = NSString(bytes: data, length: data.count, encoding: NSUTF8StringEncoding) as! String 29 | break 30 | 31 | case ATYP.IPV4.rawValue: 32 | dnLength = 4 33 | addr = sinq(rawData).skip(4).take(4).aggregate("", combine: { (c: String, n: UInt8) in c.characters.count > 1 ? c + String(format: ".%d", n) : String(format: "%d.%d", c, n)}) 34 | break 35 | 36 | case ATYP.IPV6.rawValue: 37 | dnLength = 16 38 | let bytes = sinq(rawData).skip(4).take(16).toArray() 39 | addr = bytes.reduce("", combine: { (s: String, n: UInt8) -> String in 40 | let length = s.length 41 | let lastSemicolon = s.lastIndexOf(":") 42 | 43 | if length == 4 { 44 | return "\(s):\(String(format: "%02x", n))" 45 | } 46 | 47 | return length - lastSemicolon == 5 ? "\(s):\(String(format: "%02x", n))" : "\(s)\(String(format: "%02x", n))" 48 | }) 49 | break 50 | 51 | default: 52 | return nil 53 | } 54 | 55 | let headerSize = Int(4 + (atyp == ATYP.DN.rawValue ? 1 : 0) + dnLength + 2) 56 | if rawData.count < headerSize { 57 | return nil 58 | } 59 | 60 | let littleEndian = [rawData[headerSize - 2], rawData[headerSize - 1]] 61 | let port = UnsafePointer(littleEndian).memory.bigEndian 62 | return ( cmd, addr, Int(port), headerSize ) 63 | } 64 | 65 | return nil 66 | } 67 | } -------------------------------------------------------------------------------- /LightSwordX/Socks5/Socks5Server.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Socks5Server.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import SINQ 10 | import Foundation 11 | import CryptoSwift 12 | 13 | enum ProxyMode: Int { 14 | case GLOBAL = 0 15 | case BLACK = 1 16 | case WHITE = 2 17 | } 18 | 19 | class Socks5Server { 20 | var serverAddr: String! 21 | var serverPort: Int! 22 | var listenAddr: String! 23 | var listenPort: Int! 24 | var cipherAlgorithm: String! 25 | var password: String! 26 | var timeout: Int! 27 | var bypassLocal: Bool! 28 | var tag: AnyObject? 29 | var blackList: [String]! 30 | var whiteList: [String]! 31 | var proxyMode = ProxyMode.GLOBAL 32 | 33 | private(set) var sentBytes: UInt64 = 0 34 | private(set) var receivedBytes: UInt64 = 0 35 | 36 | private var server: TCPServer6! 37 | private var running = true 38 | private var queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 39 | private let localAreas = ["10.", "192.168.", "localhost", "127.0.0.1", "172.16.", "::1", "169.254.0.0"] 40 | private let localServers = ["127.0.0.1", "localhost", "::1"] 41 | private let bufferSize = 4096 42 | 43 | func startAsync(callback: (success: Bool) -> Void) { 44 | dispatch_async(queue) { 45 | self.startSync(callback) 46 | } 47 | } 48 | 49 | func startSync(callback: (success: Bool) -> Void) { 50 | running = true 51 | 52 | server = TCPServer6(addr: listenAddr, port: listenPort) 53 | let (success, msg) = server.listen() 54 | if !success { 55 | running = false 56 | callback(success: false) 57 | print(msg) 58 | return 59 | } 60 | 61 | callback(success: true) 62 | while running { 63 | if let client = server.accept() { 64 | dispatch_async(queue, { () -> Void in 65 | client.timeout = self.timeout 66 | 67 | let (data: hello, _) = client.read(768) 68 | guard hello != nil else { 69 | client.close() 70 | return 71 | } 72 | 73 | let (success, reply) = self.handleHandshake(hello!) 74 | client.send(data: reply) 75 | 76 | if !success { 77 | client.close() 78 | return 79 | } 80 | 81 | let (data, _) = client.read(self.bufferSize) 82 | guard data != nil else { 83 | client.close() 84 | return 85 | } 86 | 87 | let request: (cmd: REQUEST_CMD, addr: String, port: Int, headerSize: Int)! = Socks5Helper.refineDestination(data!) 88 | if request == nil { 89 | client.close() 90 | return 91 | } 92 | 93 | let connectLocal = sinq(self.localServers).any({ s in self.serverAddr.containsString(s)}) || self.bypassLocal.boolValue && sinq(self.localAreas).any({ s in request.addr.containsString(s)}) 94 | 95 | switch(request.cmd) { 96 | case .BIND: 97 | break 98 | case .CONNECT: 99 | if (connectLocal) { 100 | self.connectToTarget(request.addr, destPort: request.port, requestBuf: data!, client: client) 101 | } else { 102 | self.connectToServer(request.addr, destPort: request.port, requestBuf: data!, client: client) 103 | } 104 | 105 | break 106 | case .UDP_ASSOCIATE: 107 | break 108 | } 109 | }) 110 | } 111 | } 112 | 113 | } 114 | 115 | func stop() { 116 | running = false 117 | 118 | if server == nil { 119 | return 120 | } 121 | 122 | server.close() 123 | server = nil 124 | } 125 | 126 | private func handleHandshake(data: [UInt8]) -> (success: Bool, reply: [UInt8]) { 127 | if data.count < 2 { 128 | return (success: false, reply: [0x5, Authentication.NONE.rawValue]) 129 | } 130 | 131 | let methodCount = data[1] 132 | let code = sinq(data).skip(2).take(Int(methodCount)).contains(Authentication.NOAUTH.rawValue) ? Authentication.NOAUTH : Authentication.NONE 133 | 134 | return (success: true, reply: [0x5, code.rawValue]) 135 | } 136 | 137 | private func connectToTarget(destAddr: String, destPort: Int, requestBuf: [UInt8], client: TCPClient6) { 138 | let transitSocket = TCPClient6(addr: destAddr, port: destPort) 139 | let (success, msg) = transitSocket.connect(timeout: timeout) 140 | if !success { 141 | client.close() 142 | print(msg, destAddr) 143 | return 144 | } 145 | 146 | print("connected:", destAddr) 147 | 148 | var reply = requestBuf.map { n in return n } 149 | reply[0] = 0x05 150 | reply[1] = 0x00 151 | 152 | client.send(data: reply) 153 | 154 | dispatch_async(queue, { () -> Void in 155 | self.sentBytes += self.exchangeSocket(client, writeSocket: transitSocket) 156 | }) 157 | 158 | dispatch_async(queue, { () -> Void in 159 | self.receivedBytes += self.exchangeSocket(transitSocket, writeSocket: client) 160 | }) 161 | } 162 | 163 | private func exchangeSocket(readSocket: TCPClient6, writeSocket: TCPClient6, secret: UInt8? = nil) -> UInt64 { 164 | var bytes: UInt64 = 0 165 | var retry = 0 166 | var readSize = self.bufferSize 167 | var accidentalFailure = 0 168 | 169 | while true { 170 | let (data, errno) = readSocket.read(readSize) 171 | 172 | guard data != nil else { 173 | if errno == 0 { 174 | 175 | if accidentalFailure < 12 { 176 | accidentalFailure++ 177 | continue 178 | } 179 | 180 | print("closed successful") 181 | readSocket.close() 182 | writeSocket.close() 183 | break 184 | } 185 | 186 | switch errno { 187 | case -1: 188 | print("closed failure:", accidentalFailure) 189 | readSocket.close() 190 | writeSocket.close() 191 | return bytes 192 | 193 | case EAGAIN: 194 | print("try again") 195 | continue 196 | 197 | case EINVAL: 198 | print("EINVAL") 199 | fallthrough 200 | case EFAULT: 201 | print("EFAULT") 202 | readSize += readSize 203 | break 204 | 205 | case EBADF: 206 | print("EBADF") 207 | break 208 | case EIO: 209 | print("EIO") 210 | break 211 | case EINTR: 212 | print("EINTR") 213 | break 214 | default: 215 | break 216 | } 217 | 218 | print("error:", errno) 219 | 220 | if retry < 7 { 221 | retry++ 222 | print("retry", retry) 223 | continue 224 | } 225 | 226 | readSocket.close() 227 | writeSocket.close() 228 | break 229 | } 230 | 231 | if accidentalFailure > 0 { 232 | print("recovered from failure -", accidentalFailure) 233 | accidentalFailure-- 234 | } 235 | 236 | writeSocket.send(data: secret != nil ? data!.map{ n in n ^ secret! } : data!) 237 | bytes += UInt64(data!.count) 238 | retry = 0 239 | } 240 | 241 | return bytes 242 | } 243 | 244 | private func connectToServer(destAddr: String, destPort: Int, requestBuf: [UInt8], client: TCPClient6) { 245 | switch proxyMode { 246 | case .BLACK: 247 | if blackList != nil && sinq(blackList).any({ l in destAddr.endsWith(l) }) { 248 | break 249 | } 250 | connectToTarget(destAddr, destPort: destPort, requestBuf: requestBuf, client: client) 251 | return 252 | 253 | case .WHITE: 254 | if whiteList != nil && sinq(whiteList).any({ l in destAddr.endsWith(l) }) { 255 | connectToTarget(destAddr, destPort: destPort, requestBuf: requestBuf, client: client) 256 | return 257 | } 258 | break 259 | 260 | case .GLOBAL: 261 | break 262 | } 263 | 264 | let proxySocket = TCPClient6(addr: serverAddr, port: serverPort) 265 | let (success, msg) = proxySocket.connect(timeout: timeout) 266 | if !success { 267 | client.close() 268 | print(msg) 269 | return 270 | } 271 | 272 | let (cipher, iv) = Crypto.createCipher(cipherAlgorithm, password: password) 273 | let pl = UInt8(arc4random() % 256) 274 | let pa = AES.randomIV(Int(pl)) 275 | let et = try! cipher.encrypt(sinq([VPN_TYPE.OSXCL5.rawValue, pl]).concat(pa).concat(requestBuf).toArray(), padding: nil) 276 | 277 | proxySocket.send(data: sinq(iv).concat(et).toArray()) 278 | 279 | let (data, _) = proxySocket.read(1024) 280 | if data == nil || data?.count < iv.count { 281 | client.close() 282 | proxySocket.close() 283 | return 284 | } 285 | 286 | let riv = sinq(data!).take(iv.count).toArray() 287 | let (cipher: decipher, _) = Crypto.createCipher(cipherAlgorithm, password: password, iv: riv) 288 | let rlBuf = sinq(data!).skip(iv.count).toArray() 289 | var reBuf = try! decipher.decrypt(rlBuf, padding: nil) 290 | let paddingSize = reBuf[0] 291 | 292 | reBuf = sinq(reBuf).skip(1 + Int(paddingSize)).toArray() 293 | client.send(data: reBuf) 294 | 295 | print("connected:", destAddr) 296 | 297 | dispatch_async(queue, { () -> Void in 298 | self.sentBytes += self.exchangeSocket(client, writeSocket: proxySocket, secret: pl) 299 | }) 300 | 301 | dispatch_async(queue, { () -> Void in 302 | self.receivedBytes += self.exchangeSocket(proxySocket, writeSocket: client, secret: paddingSize) 303 | }) 304 | } 305 | 306 | } 307 | 308 | extension Socks5Server: Equatable { 309 | 310 | } 311 | 312 | func ==(lhs: Socks5Server, rhs: Socks5Server) -> Bool { 313 | return lhs.serverAddr == rhs.serverAddr && lhs.serverPort == rhs.serverPort && lhs.listenAddr == rhs.listenAddr && lhs.listenPort == rhs.listenPort && lhs.cipherAlgorithm == rhs.cipherAlgorithm && lhs.password == rhs.password 314 | } -------------------------------------------------------------------------------- /LightSwordX/TCPSocket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TCPSocket.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 1/9/16. 6 | // Copyright © 2016 Neko. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @asmname("tcpsocket_connect") func c_tcpsocket_connect(host:UnsafePointer, port:Int32, timeout:Int32) -> Int32 12 | @asmname("tcpsocket_close") func c_tcpsocket_close(fd:Int32) -> Int32 13 | @asmname("tcpsocket_send") func c_tcpsocket_send(fd:Int32, buff:UnsafePointer, len:Int32) -> Int32 14 | @asmname("tcpsocket_read") func c_tcpsocket_read(fd:Int32, buff:UnsafePointer, len:Int32) -> Int32 15 | @asmname("tcpsocket_listen") func c_tcpsocket_listen(addr:UnsafePointer, port:Int32) -> Int32 16 | @asmname("tcpsocket_accept") func c_tcpsocket_accept(socketfd:Int32, ip:UnsafePointer, port:UnsafePointer) -> Int32 17 | @asmname("tcpsocket6_listen") func c_tcpsocket6_listen(addr: UnsafePointer, port: Int32) -> Int32 18 | @asmname("set_socket_timeout") func c_set_socket_timeout(socketfd: Int32, timeout: Int) -> Void 19 | 20 | class TCPClient6: Socket { 21 | func connect(timeout t: Int) -> (Bool, String) { 22 | let r = c_tcpsocket_connect(self.addr, port: Int32(self.port), timeout: Int32(t)) 23 | 24 | if r > 0 { 25 | self.fd = r 26 | return (true, "connceted") 27 | } else { 28 | switch r { 29 | case -1: 30 | return (false, "failed to query server") 31 | case -2: 32 | return (false,"connection closed") 33 | case -3: 34 | return (false,"connect timeout") 35 | default: 36 | return (false, "unknow err") 37 | } 38 | } 39 | } 40 | 41 | func close() -> (Bool, String) { 42 | guard let fd = self.fd else { 43 | return (false, "socket not open") 44 | } 45 | 46 | c_tcpsocket_close(fd) 47 | self.fd = nil 48 | return (true, "closed") 49 | } 50 | 51 | func send(data d: [UInt8]) -> (Bool, String) { 52 | guard let fd = self.fd else { 53 | return (false, "socket not open") 54 | } 55 | 56 | let sent = c_tcpsocket_send(fd, buff: d, len: Int32(d.count)) 57 | if Int(sent) == d.count { 58 | return (true, "succcess") 59 | } else { 60 | return (false, "error") 61 | } 62 | } 63 | 64 | func send(str s: String) -> (Bool, String) { 65 | guard let fd = self.fd else { 66 | return (false, "socket not open") 67 | } 68 | 69 | let sent = c_tcpsocket_send(fd, buff: s, len: Int32(strlen(s))) 70 | if sent == Int32(strlen(s)) { 71 | return (true, "success") 72 | } 73 | 74 | return (false, "error") 75 | } 76 | 77 | func send(data d: NSData) -> (Bool, String) { 78 | guard let fd = self.fd else { 79 | return (false, "socket not open") 80 | } 81 | 82 | var buf = [UInt8](count: d.length, repeatedValue: 0) 83 | d.getBytes(&buf, length: d.length) 84 | 85 | let sent = c_tcpsocket_send(fd, buff: buf, len: Int32(d.length)) 86 | if sent == Int32(d.length) { 87 | return (true, "success") 88 | } 89 | 90 | return (false, "error") 91 | } 92 | 93 | func read(exceptLength: Int) -> (data: [UInt8]?, errno: Int32) { 94 | guard let fd = self.fd else { 95 | return (data: nil, errno: -1) 96 | } 97 | 98 | var buf = [UInt8](count: exceptLength, repeatedValue: 0) 99 | let read = c_tcpsocket_read(fd, buff: buf, len: Int32(exceptLength)) 100 | if read <= 0 { 101 | return (data: nil, errno: 0) 102 | } 103 | 104 | return (data: Array(buf[0...Int(read - 1)]), errno: read) 105 | } 106 | 107 | var timeout: Int { 108 | get { 109 | return _timeout 110 | } 111 | set { 112 | guard let fd = self.fd else { 113 | return 114 | } 115 | 116 | c_set_socket_timeout(fd, timeout: newValue) 117 | _timeout = newValue 118 | } 119 | } 120 | } 121 | 122 | class TCPServer6: Socket { 123 | 124 | func listen() -> (Bool, String) { 125 | 126 | if self.fd != nil { 127 | return (false, "listening ready") 128 | } 129 | 130 | let fd = c_tcpsocket6_listen(self.addr, port: Int32(self.port)) 131 | if fd > 0 { 132 | self.fd = fd; 133 | return (true, "listening") 134 | } 135 | 136 | return (false, "Failed to listen") 137 | } 138 | 139 | func accept() -> TCPClient6? { 140 | guard let fd = self.fd else { 141 | return nil 142 | } 143 | 144 | var buf = [Int8](count: 16, repeatedValue: 0) 145 | var port: Int32 = 0 146 | let clientfd = c_tcpsocket_accept(fd, ip: &buf, port: &port) 147 | if clientfd < 0 { 148 | return nil 149 | } 150 | 151 | let client = TCPClient6() 152 | client.fd = clientfd 153 | client.port = Int(port) 154 | if let addr = String(CString: buf, encoding: NSUTF8StringEncoding) { 155 | client.addr = addr 156 | } 157 | 158 | return client 159 | } 160 | 161 | func close() -> (Bool, String) { 162 | 163 | guard let fd = self.fd else { 164 | return (false, "socket not open") 165 | } 166 | 167 | c_tcpsocket_close(fd) 168 | self.fd = nil 169 | return (true, "closed") 170 | } 171 | 172 | } -------------------------------------------------------------------------------- /LightSwordX/ViewController.Servers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserServersDataSource.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/23/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SINQ 11 | 12 | extension ViewController: NSTableViewDataSource { 13 | 14 | @objc func numberOfRowsInTableView(tableView: NSTableView) -> Int { 15 | return servers.count 16 | } 17 | 18 | @objc func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? { 19 | return servers[row].address 20 | } 21 | 22 | @IBAction func addServer(sender: NSButton) { 23 | let server = UserServer() 24 | server.id = servers.count 25 | 26 | if servers.count == 0 { 27 | server.address = "public1.lightsword.org" 28 | server.port = 443 29 | } 30 | 31 | servers.append(server) 32 | serversTableView.reloadData() 33 | 34 | selectedRow = servers.count - 1 35 | let indexSet = NSIndexSet(index: selectedRow) 36 | serversTableView.selectRowIndexes(indexSet, byExtendingSelection: false) 37 | 38 | serverDetailsView.hidden = false 39 | keepConnectionCheckBox.state = server.keepConnection ? NSOnState : NSOffState 40 | serverAddressTextField.stringValue = server.address 41 | serverPortTextField.stringValue = String(server.port) 42 | cipherAlgorithmComboBox.stringValue = server.cipherAlgorithm 43 | proxyModeComboBox.selectItemAtIndex(server.proxyMode.rawValue) 44 | passwordTextField.stringValue = server.password 45 | listenAddressTextField.stringValue = server.listenAddr 46 | listenPortTextField.stringValue = String(server.listenPort) 47 | 48 | saveServers(true) 49 | 50 | if (server.keepConnection) { 51 | startServer(server) 52 | } 53 | } 54 | 55 | @IBAction func removeServer(sender: NSButton) { 56 | let selectedRow = serversTableView.selectedRow 57 | if (selectedRow == -1) { 58 | return 59 | } 60 | 61 | let removed = servers.removeAtIndex(selectedRow) 62 | serversTableView.reloadData() 63 | 64 | if (servers.count == 0) { 65 | serverDetailsView.hidden = true 66 | } 67 | 68 | saveServers(true) 69 | stopServer(removed) 70 | } 71 | 72 | @IBAction func setAsDefaultServer(sender: NSButton) { 73 | let selectedServer = servers[selectedRow] 74 | 75 | selectedServer.keepConnection = !selectedServer.keepConnection 76 | saveServers(true) 77 | 78 | if selectedServer.keepConnection { 79 | startServer(selectedServer) 80 | return 81 | } 82 | 83 | stopServer(selectedServer) 84 | } 85 | 86 | @IBAction func testConnectionSpeed(sender: NSButton) { 87 | let ip = servers[selectedRow].address 88 | let port = servers[selectedRow].port 89 | 90 | sender.enabled = false 91 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 92 | let start = StatisticsHelper.getUptimeInMilliseconds() 93 | 94 | let con = TCPClient(addr: ip, port: port) 95 | let (success, _) = con.connect(timeout: 10) 96 | con.close() 97 | 98 | let message = success ? "\(NSLocalizedString("Elapsed Time", comment: "")): \(StatisticsHelper.getUptimeInMilliseconds() - start)ms\n\(ip) ✓" : NSLocalizedString("Connection Timeout", comment: "") 99 | 100 | let notification = NSUserNotification() 101 | notification.title = NSLocalizedString("Test Connection Speed", comment: "") 102 | notification.informativeText = message 103 | 104 | NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification) 105 | 106 | dispatch_async(dispatch_get_main_queue()) { 107 | sender.enabled = true 108 | } 109 | } 110 | } 111 | } 112 | 113 | extension ViewController: NSTableViewDelegate { 114 | func tableView(tableView: NSTableView, shouldSelectRow row: Int) -> Bool { 115 | 116 | let info = servers[row] 117 | selectedRow = row 118 | 119 | serverAddressTextField.stringValue = info.address 120 | serverPortTextField.stringValue = String(info.port) 121 | cipherAlgorithmComboBox.stringValue = info.cipherAlgorithm 122 | proxyModeComboBox.selectItemAtIndex(info.proxyMode.rawValue) 123 | passwordTextField.stringValue = info.password 124 | keepConnectionCheckBox.state = info.keepConnection ? NSOnState : NSOffState 125 | listenAddressTextField.stringValue = info.listenAddr 126 | listenPortTextField.stringValue = String(info.listenPort) 127 | 128 | saveServers() 129 | return true 130 | } 131 | } 132 | 133 | extension ViewController: NSComboBoxDelegate { 134 | 135 | override func controlTextDidChange(obj: NSNotification) { 136 | let textField: NSTextField! = obj.object as? NSTextField 137 | if textField == nil { 138 | return 139 | } 140 | 141 | var newValue = textField.stringValue 142 | let selectedServer = servers[selectedRow] 143 | 144 | switch textField.identifier! { 145 | 146 | case "serverAddress": 147 | if (newValue.length == 0) { 148 | newValue = "127.0.0.1" 149 | } 150 | 151 | selectedServer.address = newValue 152 | serversTableView.reloadData() 153 | break 154 | 155 | case "serverPort": 156 | let port = Int(newValue) ?? 8900 157 | selectedServer.port = port 158 | serverPortTextField.stringValue = String(port) 159 | break 160 | 161 | case "password": 162 | if (newValue.length == 0) { 163 | newValue = "lightsword.neko" 164 | } 165 | 166 | selectedServer.password = newValue 167 | break 168 | 169 | case "listenAddr": 170 | if (newValue.length == 0) { 171 | newValue = "127.0.0.1" 172 | } else if (newValue == "localhost") { 173 | newValue = "127.0.0.1" 174 | } 175 | 176 | if ipv4Regex.test(newValue) && !["127.0.0.1", "0.0.0.0"].contains(newValue) { 177 | newValue = "127.0.0.1" 178 | } 179 | 180 | selectedServer.listenAddr = newValue 181 | listenAddressTextField.stringValue = newValue 182 | break 183 | 184 | case "listenPort": 185 | let port = Int(newValue) ?? 1080 186 | selectedServer.listenPort = port 187 | listenPortTextField.stringValue = String(port) 188 | break 189 | 190 | default: 191 | return 192 | } 193 | 194 | isDirty = true 195 | } 196 | 197 | override func controlTextDidEndEditing(obj: NSNotification) { 198 | saveServers() 199 | } 200 | 201 | func comboBoxSelectionDidChange(notification: NSNotification) { 202 | let comboBox = notification.object as! NSComboBox 203 | let handlers = [ 204 | "cipherAlgorithm": cipherAlgorithmComboBoxChanged, 205 | "proxyMode": proxyModeComboBoxChanged 206 | ] 207 | 208 | handlers[comboBox.identifier!]?(comboBox) 209 | } 210 | 211 | private func cipherAlgorithmComboBoxChanged(comboBox: NSComboBox) { 212 | let methods = ["aes-256-cfb", "aes-192-cfb", "aes-128-cfb"] 213 | let selectedIndex = comboBox.indexOfSelectedItem 214 | if (servers[selectedRow].cipherAlgorithm == methods[selectedIndex]) { 215 | return 216 | } 217 | 218 | servers[selectedRow].cipherAlgorithm = methods[selectedIndex] 219 | isDirty = true 220 | } 221 | 222 | private func proxyModeComboBoxChanged(comboBox: NSComboBox) { 223 | let modes = [ 224 | ProxyMode.GLOBAL.rawValue: ProxyMode.GLOBAL, 225 | ProxyMode.BLACK.rawValue: ProxyMode.BLACK, 226 | ProxyMode.WHITE.rawValue: ProxyMode.WHITE 227 | ] 228 | 229 | let selectedIndex = comboBox.indexOfSelectedItem 230 | if let selectedMode = modes[selectedIndex] { 231 | if (servers[selectedRow].proxyMode == selectedMode) { 232 | return 233 | } 234 | 235 | servers[selectedRow].proxyMode = selectedMode 236 | if let running = sinq(self.runningServers).firstOrNil({ s in s.tag as? Int == self.servers[self.selectedRow].id }) { 237 | running.proxyMode = selectedMode 238 | } 239 | isDirty = true 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /LightSwordX/ViewController.Settings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.Settings.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/29/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import ServiceManagement 11 | 12 | extension ViewController { 13 | @IBAction func toggleLoginItem(sender: NSButton) { 14 | let on = sender.state == NSOnState 15 | let launcherIdentifier = "org.lightsword.LightSwordXHelper" 16 | 17 | SMLoginItemSetEnabled(launcherIdentifier, on) 18 | SettingsHelper.saveValue(on, forKey: AppKeys.LoginItem) 19 | } 20 | } -------------------------------------------------------------------------------- /LightSwordX/ViewController.Websites.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.Websites.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/25/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension ViewController: NSTextDelegate { 12 | func textDidChange(notification: NSNotification) { 13 | isWebsitesDirty = true 14 | } 15 | } -------------------------------------------------------------------------------- /LightSwordX/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // LightSwordX 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SINQ 11 | 12 | class ViewController: NSViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | serverDetailsView.hidden = servers.count == 0 ? true : false 18 | 19 | let login = SettingsHelper.loadValue(defaultValue: false, forKey: AppKeys.LoginItem) 20 | loginItemCheckBox.state = login ? NSOnState : NSOffState 21 | } 22 | 23 | override func awakeFromNib() { 24 | 25 | if self.blackList == nil { 26 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 27 | self.initBlackWhiteList() 28 | } 29 | } 30 | 31 | if (servers != nil && servers.count > 0) { 32 | return 33 | } 34 | 35 | let jsonStr = SettingsHelper.loadValue(defaultValue: "", forKey: AppKeys.Servers) 36 | 37 | if (jsonStr.length == 0) { 38 | self.servers = [UserServer]() 39 | return 40 | } 41 | 42 | let jObjs = JSON(string: jsonStr) 43 | var index = 0 44 | self.servers = jObjs.map{ obj, jObj in 45 | let server = UserServer() 46 | 47 | server.address = jObj["address"].asString! 48 | server.port = jObj["port"].asInt! 49 | server.cipherAlgorithm = jObj["cipherAlgorithm"].asString! 50 | server.password = jObj["password"].asString! 51 | server.keepConnection = jObj["keepConnection"].asBool! 52 | server.listenAddr = jObj["listenAddr"].asString! 53 | server.listenPort = jObj["listenPort"].asInt! 54 | server.proxyMode = ProxyMode(rawValue: jObj["proxyMode"].asInt ?? 0)! 55 | server.id = index++ 56 | 57 | return server 58 | } 59 | 60 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 61 | self.servers.filter({ s in return s.keepConnection }).forEach { s in 62 | self.startServer(s) 63 | } 64 | } 65 | } 66 | 67 | func initBlackWhiteList() { 68 | let mainBundle = NSBundle.mainBundle() 69 | let whiteList = SettingsHelper.loadValue(defaultValue: try! NSString(contentsOfFile: mainBundle.pathForResource("white", ofType: "txt")!, encoding: NSUTF8StringEncoding), forKey: AppKeys.WhiteList) 70 | let blackList = SettingsHelper.loadValue(defaultValue: try! NSString(contentsOfFile: mainBundle.pathForResource("black", ofType: "txt")!, encoding: NSUTF8StringEncoding), forKey: AppKeys.BlackList) 71 | 72 | self.whiteList = whiteList.componentsSeparatedByString("\n") 73 | self.blackList = blackList.componentsSeparatedByString("\n") 74 | } 75 | 76 | @IBAction func onCloseClick(sender: NSButton) { 77 | view.window?.close() 78 | saveServers() 79 | saveWebsites() 80 | stopTimer() 81 | } 82 | 83 | var blackList: [String]! 84 | var whiteList: [String]! 85 | 86 | var servers: [UserServer]! 87 | var runningServers = [Socks5Server]() 88 | var selectedRow: Int! 89 | var isDirty = false 90 | var isWebsitesDirty = false 91 | var statisticsTimer: NSTimer! 92 | var totalSentBytes: UInt64 = 0 93 | var totalReceivedBytes: UInt64 = 0 94 | 95 | let ipv4Regex = Regex("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$") 96 | 97 | @IBOutlet weak var serversTableView: NSTableView! 98 | @IBOutlet weak var serverDetailsView: NSView! 99 | @IBOutlet weak var serverAddressTextField: NSTextField! 100 | @IBOutlet weak var serverPortTextField: NSTextField! 101 | @IBOutlet weak var listenAddressTextField: NSTextField! 102 | @IBOutlet weak var listenPortTextField: NSTextField! 103 | @IBOutlet weak var cipherAlgorithmComboBox: NSComboBox! 104 | @IBOutlet weak var passwordTextField: NSSecureTextField! 105 | @IBOutlet weak var keepConnectionCheckBox: NSButton! 106 | @IBOutlet weak var proxyModeComboBox: NSComboBox! 107 | @IBOutlet weak var connectionStatus: NSTextField! 108 | var blackListTextView: NSTextView! 109 | var whiteListTextView: NSTextView! 110 | @IBOutlet weak var sentBytesTextField: NSTextField! 111 | @IBOutlet weak var receivedBytesTextField: NSTextField! 112 | @IBOutlet weak var uploadSpeedTextField: NSTextField! 113 | @IBOutlet weak var downloadSpeedTextField: NSTextField! 114 | @IBOutlet weak var loginItemCheckBox: NSButton! 115 | 116 | func startServer(userServer: UserServer) { 117 | let server = Socks5Server() 118 | server.listenAddr = userServer.listenAddr 119 | server.listenPort = userServer.listenPort 120 | server.serverAddr = userServer.address 121 | server.serverPort = userServer.port 122 | server.bypassLocal = true 123 | server.cipherAlgorithm = userServer.cipherAlgorithm 124 | server.password = userServer.password 125 | server.timeout = 30 126 | server.tag = userServer.id 127 | server.proxyMode = userServer.proxyMode 128 | server.blackList = self.blackList 129 | server.whiteList = self.whiteList 130 | 131 | server.startAsync({ s in 132 | if (!s) { 133 | let notification = NSUserNotification() 134 | notification.title = NSLocalizedString("Start Failed", comment: "") 135 | notification.informativeText = NSString(format: NSLocalizedString("Port is used", comment: "Port: %d is used"), server.listenPort) as String 136 | 137 | NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification) 138 | return 139 | } 140 | 141 | dispatch_async(dispatch_get_main_queue()) { 142 | self.runningServers.append(server) 143 | self.updateStatusText(self.runningServers.count) 144 | } 145 | }) 146 | } 147 | 148 | func stopServer(userServer: UserServer) { 149 | if let s = sinq(runningServers).firstOrNil({ s in s.tag as! Int == userServer.id }) { 150 | s.stop() 151 | runningServers.removeAtIndex(runningServers.indexOf({ ss in ss == s })!) 152 | updateStatusText(runningServers.count) 153 | } 154 | } 155 | 156 | func refreshStatistics() { 157 | if self.runningServers.count == 0 { 158 | return 159 | } 160 | 161 | var curSent = self.runningServers.reduce(0, combine: { n, s in n + s.sentBytes }) 162 | var curReceived = self.runningServers.reduce(0, combine: { n, s in n + s.receivedBytes }) 163 | 164 | if curSent < totalSentBytes { 165 | curSent = totalSentBytes 166 | } 167 | 168 | if curReceived < totalReceivedBytes { 169 | curReceived = totalReceivedBytes 170 | } 171 | 172 | let deltaSent = curSent - totalSentBytes 173 | let deltaReceived = curReceived - totalReceivedBytes 174 | 175 | totalSentBytes = curSent 176 | totalReceivedBytes = curReceived 177 | 178 | let (value: _, formattedValue: sent, unit: sentUnit) = StatisticsHelper.toStatisticsString(curSent) 179 | sentBytesTextField.stringValue = "\(sent) \(sentUnit)" 180 | 181 | let (value: _, formattedValue: received, unit: receivedUnit) = StatisticsHelper.toStatisticsString(curReceived) 182 | receivedBytesTextField.stringValue = "\(received) \(receivedUnit)" 183 | 184 | let (value: _, formattedValue: sentSpeed, unit: sentSpeedUnit) = StatisticsHelper.toStatisticsString(deltaSent) 185 | uploadSpeedTextField.stringValue = "\(sentSpeed) \(sentSpeedUnit)/s ↑" 186 | 187 | let (value: _, formattedValue: receivedSpeed, unit: receivedSpeedUnit) = StatisticsHelper.toStatisticsString(deltaReceived) 188 | downloadSpeedTextField.stringValue = "\(receivedSpeed) \(receivedSpeedUnit)/s ↓" 189 | } 190 | 191 | func saveServers(force: Bool = false) { 192 | if !force && !isDirty { 193 | return 194 | } 195 | 196 | isDirty = false 197 | let list = servers.map{ s in return [ 198 | "address": s.address, 199 | "port": s.port, 200 | "cipherAlgorithm": s.cipherAlgorithm, 201 | "password": s.password, 202 | "keepConnection": s.keepConnection, 203 | "listenAddr": s.listenAddr, 204 | "listenPort": s.listenPort, 205 | "proxyMode": s.proxyMode.rawValue 206 | ]} 207 | 208 | SettingsHelper.saveValue(JSON(list).toString(), forKey: AppKeys.Servers) 209 | } 210 | 211 | func saveWebsites() { 212 | if !isWebsitesDirty { 213 | return 214 | } 215 | 216 | SettingsHelper.saveValue(blackListTextView.string!, forKey: AppKeys.BlackList) 217 | SettingsHelper.saveValue(whiteListTextView.string!, forKey: AppKeys.WhiteList) 218 | self.blackList = blackListTextView.string!.componentsSeparatedByString("\n") 219 | self.whiteList = whiteListTextView.string!.componentsSeparatedByString("\n") 220 | 221 | for s in self.runningServers { 222 | s.blackList = self.blackList 223 | s.whiteList = self.whiteList 224 | } 225 | 226 | isWebsitesDirty = false 227 | } 228 | 229 | func updateStatusText(runningCount: Int) { 230 | dispatch_async(dispatch_get_main_queue()) { 231 | let color = runningCount == 0 ? NSColor.grayColor() : NSColor(red: 51.0 / 255, green: 204.0 / 255, blue: 51 / 255, alpha: 1) 232 | let text = runningCount == 0 ? NSLocalizedString("Stopped", comment: "") : "\(NSLocalizedString("Running", comment: "")): \(runningCount)" 233 | 234 | self.connectionStatus.textColor = color 235 | self.connectionStatus.stringValue = "◉ \(text)" 236 | } 237 | } 238 | 239 | func stopTimer() { 240 | if statisticsTimer == nil { 241 | return 242 | } 243 | 244 | statisticsTimer.invalidate() 245 | statisticsTimer = nil 246 | } 247 | } 248 | 249 | extension ViewController: NSTabViewDelegate { 250 | func tabView(tabView: NSTabView, didSelectTabViewItem tabViewItem: NSTabViewItem?) { 251 | let identifier = tabViewItem?.identifier as? String 252 | if identifier == nil { 253 | return 254 | } 255 | 256 | stopTimer() 257 | saveWebsites() 258 | 259 | if identifier! == "Websites" { 260 | if blackListTextView == nil { 261 | blackListTextView = sinq(tabViewItem!.view!.subviews).first{ v in v.identifier == "BlackListScrollView" }.subviews.first!.subviews.first as! NSTextView 262 | whiteListTextView = sinq(tabViewItem!.view!.subviews).first{ v in v.identifier == "WhiteListScrollView" }.subviews.first!.subviews.first as! NSTextView 263 | } 264 | 265 | let blackList = SettingsHelper.loadValue(defaultValue: try! NSString(contentsOfFile: NSBundle.mainBundle().pathForResource("black", ofType: "txt")!, encoding: NSUTF8StringEncoding) as String, forKey: AppKeys.BlackList) 266 | let whiteList = SettingsHelper.loadValue(defaultValue: try! NSString(contentsOfFile: NSBundle.mainBundle().pathForResource("white", ofType: "txt")!, encoding: NSUTF8StringEncoding) as String, forKey: AppKeys.WhiteList) 267 | blackListTextView.string = blackList 268 | whiteListTextView.string = whiteList 269 | 270 | return 271 | } 272 | 273 | if identifier! == "Statistics" { 274 | if self.statisticsTimer == nil { 275 | self.statisticsTimer = NSTimer(timeInterval: 1, target: self, selector: Selector("refreshStatistics"), userInfo: nil, repeats: true) 276 | NSRunLoop.mainRunLoop().addTimer(self.statisticsTimer, forMode: NSRunLoopCommonModes) 277 | refreshStatistics() 278 | } 279 | 280 | return 281 | } 282 | 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /LightSwordX/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | // Connection Test 2 | 3 | "Test Connection Speed" = "测试连接速度"; 4 | "Elapsed Time" = "总耗时"; 5 | "Connection Timeout" = "连接超时"; 6 | 7 | // Menu Bar 8 | 9 | "Preferences" = "偏好设置"; 10 | "Quit" = "退出"; 11 | 12 | // Status 13 | 14 | "Stopped" = "已停止"; 15 | "Running" = "运行中"; 16 | 17 | // Local Server 18 | 19 | "Start Failed" = "本地服务器启动失败"; 20 | "Port is used" = "端口号: %d 已被使用或拒绝访问,请更换其它端口号"; -------------------------------------------------------------------------------- /LightSwordX/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSMenuItem"; title = "LightSwordX"; ObjectID = "1Xt-HY-uBw"; */ 3 | "1Xt-HY-uBw.title" = "LightSwordX"; 4 | 5 | /* Class = "NSTextFieldCell"; placeholderString = "IPv4/Domain"; ObjectID = "1dW-tW-y1K"; */ 6 | "1dW-tW-y1K.placeholderString" = "IPv4/Domain"; 7 | 8 | /* Class = "NSTextFieldCell"; title = "Cipher Algorithm:"; ObjectID = "2EF-Gk-wm0"; */ 9 | "2EF-Gk-wm0.title" = "加密方式 (OS X客户端仅在握手时使用): "; 10 | 11 | /* Class = "NSTextFieldCell"; title = "0 KB"; ObjectID = "40K-aO-fio"; */ 12 | "40K-aO-fio.title" = "0 KB"; 13 | 14 | /* Class = "NSTextFieldCell"; title = "Blocked Sites List:"; ObjectID = "4ox-Ns-yq2"; */ 15 | "4ox-Ns-yq2.title" = "被屏蔽网址:"; 16 | 17 | /* Class = "NSMenuItem"; title = "Quit LightSwordX"; ObjectID = "4sb-4s-VLi"; */ 18 | "4sb-4s-VLi.title" = "退出 LightSwordX"; 19 | 20 | /* Class = "NSTabViewItem"; label = "Statistics"; ObjectID = "50s-kU-6kF"; */ 21 | "50s-kU-6kF.label" = "统计"; 22 | 23 | /* Class = "NSMenuItem"; title = "Edit"; ObjectID = "5QF-Oa-p0T"; */ 24 | "5QF-Oa-p0T.title" = "编辑"; 25 | 26 | /* Class = "NSMenuItem"; title = "About LightSwordX"; ObjectID = "5kV-Vb-QxS"; */ 27 | "5kV-Vb-QxS.title" = "关于 LightSwordX"; 28 | 29 | /* Class = "NSTextFieldCell"; title = "Proxy Mode:"; ObjectID = "8WL-FF-sEa"; */ 30 | "8WL-FF-sEa.title" = "代理模式:"; 31 | 32 | /* Class = "NSButtonCell"; title = "Start LigthSwordX on system startup"; ObjectID = "8d1-XH-mmP"; */ 33 | "8d1-XH-mmP.title" = "开机启动 LightSwordX"; 34 | 35 | /* Class = "NSWindow"; title = "LightSwordX"; ObjectID = "8fW-kc-wPs"; */ 36 | "8fW-kc-wPs.title" = "LightSwordX"; 37 | 38 | /* Class = "NSTextFieldCell"; title = "0 KB/s ↑"; ObjectID = "9mK-b0-W6S"; */ 39 | "9mK-b0-W6S.title" = "0 KB/s ↑"; 40 | 41 | /* Class = "NSTextFieldCell"; title = "Remote Server:"; ObjectID = "9zW-eR-W7U"; */ 42 | "9zW-eR-W7U.title" = "服务器地址:"; 43 | 44 | /* Class = "NSTabViewItem"; label = "Servers"; ObjectID = "A5f-Uf-vFi"; */ 45 | "A5f-Uf-vFi.label" = "服务器"; 46 | 47 | /* Class = "NSMenu"; title = "Main Menu"; ObjectID = "AYu-sK-qS6"; */ 48 | "AYu-sK-qS6.title" = "主菜单"; 49 | 50 | /* Class = "NSViewController"; title = "LightSwordX"; ObjectID = "B3C-Ed-y2d"; */ 51 | "B3C-Ed-y2d.title" = "LightSwordX"; 52 | 53 | /* Class = "NSMenuItem"; title = "Preferences…"; ObjectID = "BOF-NM-1cW"; */ 54 | "BOF-NM-1cW.title" = "偏好…"; 55 | 56 | /* Class = "NSComboBoxCell"; title = "Global"; ObjectID = "C4f-hN-IR5"; */ 57 | "C4f-hN-IR5.title" = "全局"; 58 | 59 | /* Class = "NSComboBoxCell"; C4f-hN-IR5.ibShadowedObjectValues[0] = "Global"; ObjectID = "C4f-hN-IR5"; */ 60 | "C4f-hN-IR5.ibShadowedObjectValues[0]" = "全局代理"; 61 | 62 | /* Class = "NSComboBoxCell"; C4f-hN-IR5.ibShadowedObjectValues[1] = "Blacklist only"; ObjectID = "C4f-hN-IR5"; */ 63 | "C4f-hN-IR5.ibShadowedObjectValues[1]" = "仅黑名单(仅被封网址)"; 64 | 65 | /* Class = "NSComboBoxCell"; C4f-hN-IR5.ibShadowedObjectValues[2] = "Global except whitelist"; ObjectID = "C4f-hN-IR5"; */ 66 | "C4f-hN-IR5.ibShadowedObjectValues[2]" = "全局代理(白名单除外)"; 67 | 68 | /* Class = "NSTextFieldCell"; placeholderString = "8900"; ObjectID = "DgL-yC-gyI"; */ 69 | "DgL-yC-gyI.placeholderString" = "8900"; 70 | 71 | /* Class = "NSTextFieldCell"; title = "◉ Stopped"; ObjectID = "Dlh-tC-hWx"; */ 72 | "Dlh-tC-hWx.title" = "◉ 未启动"; 73 | 74 | /* Class = "NSTabViewItem"; label = "Websites"; ObjectID = "EcX-pW-W6U"; */ 75 | "EcX-pW-W6U.label" = "网址列表"; 76 | 77 | /* Class = "NSTextFieldCell"; title = ":"; ObjectID = "FLy-ws-6rO"; */ 78 | "FLy-ws-6rO.title" = ":"; 79 | 80 | /* Class = "NSMenuItem"; title = "View"; ObjectID = "H8h-7b-M4v"; */ 81 | "H8h-7b-M4v.title" = "查看"; 82 | 83 | /* Class = "NSMenuItem"; title = "Show All"; ObjectID = "Kd2-mp-pUS"; */ 84 | "Kd2-mp-pUS.title" = "显示全部"; 85 | 86 | /* Class = "NSMenuItem"; title = "Services"; ObjectID = "NMo-om-nkz"; */ 87 | "NMo-om-nkz.title" = "服务"; 88 | 89 | /* Class = "NSMenuItem"; title = "Hide LightSwordX"; ObjectID = "Olw-nP-bQN"; */ 90 | "Olw-nP-bQN.title" = "隐藏 LightSwordX"; 91 | 92 | /* Class = "NSTextFieldCell"; title = "Listening:"; ObjectID = "OwG-wI-lyB"; */ 93 | "OwG-wI-lyB.title" = "本地监听地址:"; 94 | 95 | /* Class = "NSTextFieldCell"; title = ":"; ObjectID = "RLb-g5-Plg"; */ 96 | "RLb-g5-Plg.title" = ":"; 97 | 98 | /* Class = "NSTableColumn"; headerCell.title = "Address"; ObjectID = "Se1-fH-6G4"; */ 99 | "Se1-fH-6G4.headerCell.title" = "地址"; 100 | 101 | /* Class = "NSTextFieldCell"; title = "Tips: 102 | 1. Open System Preferences 103 | 2. Select Network 104 | 3. Click Advanced -> Proxies 105 | 4. Select SOCKS Proxy 106 | 5. Fill in Proxy Server Address (eg. 127.0.0.1 1080, NOTE: No Password Required.) 107 | 108 | "; ObjectID = "Te6-Td-saK"; */ 109 | "Te6-Td-saK.title" = "提示: 110 | 1. 打开系统偏好 111 | 2. 选择 “网络” 112 | 3. 点击 “高级...” -> “代理” 113 | 4. 勾选 “SOCKS 代理” 114 | 5. 填写代理服务器地址 (例如: 127.0.0.1 1080, 注意: 无需填写密码) 115 | 116 | "; 117 | 118 | /* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "Vdr-fp-XzO"; */ 119 | "Vdr-fp-XzO.title" = "隐藏其它"; 120 | 121 | /* Class = "NSComboBoxCell"; placeholderString = "Required"; ObjectID = "YEI-dA-kwa"; */ 122 | "YEI-dA-kwa.placeholderString" = "必填"; 123 | 124 | /* Class = "NSComboBoxCell"; YEI-dA-kwa.ibShadowedObjectValues[0] = "aes-256-cfb"; ObjectID = "YEI-dA-kwa"; */ 125 | "YEI-dA-kwa.ibShadowedObjectValues[0]" = "aes-256-cfb"; 126 | 127 | /* Class = "NSComboBoxCell"; YEI-dA-kwa.ibShadowedObjectValues[1] = "aes-192-cfb"; ObjectID = "YEI-dA-kwa"; */ 128 | "YEI-dA-kwa.ibShadowedObjectValues[1]" = "aes-192-cfb"; 129 | 130 | /* Class = "NSComboBoxCell"; YEI-dA-kwa.ibShadowedObjectValues[2] = "aes-128-cfb"; ObjectID = "YEI-dA-kwa"; */ 131 | "YEI-dA-kwa.ibShadowedObjectValues[2]" = "aes-128-cfb"; 132 | 133 | /* Class = "NSSecureTextFieldCell"; placeholderString = "Required"; ObjectID = "Z5R-gf-Vfe"; */ 134 | "Z5R-gf-Vfe.placeholderString" = "必填"; 135 | 136 | /* Class = "NSMenuItem"; title = "Window"; ObjectID = "aUF-d1-5bR"; */ 137 | "aUF-d1-5bR.title" = "窗口"; 138 | 139 | /* Class = "NSTextFieldCell"; title = "Sent:"; ObjectID = "bYm-WL-eY4"; */ 140 | "bYm-WL-eY4.title" = "已发送:"; 141 | 142 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "ciz-Oo-91w"; */ 143 | "ciz-Oo-91w.title" = "Text Cell"; 144 | 145 | /* Class = "NSTextFieldCell"; title = "Received:"; ObjectID = "d6A-Ze-fIH"; */ 146 | "d6A-Ze-fIH.title" = "已接收:"; 147 | 148 | /* Class = "NSMenuItem"; title = "File"; ObjectID = "dMs-cI-mzQ"; */ 149 | "dMs-cI-mzQ.title" = "文件"; 150 | 151 | /* Class = "NSButtonCell"; title = "Test Connection Speed"; ObjectID = "fWM-7s-Kmi"; */ 152 | "fWM-7s-Kmi.title" = "测试连接速度"; 153 | 154 | /* Class = "NSTabViewItem"; label = "Settings"; ObjectID = "gyd-cc-HxZ"; */ 155 | "gyd-cc-HxZ.label" = "设置"; 156 | 157 | /* Class = "NSTextFieldCell"; title = "White List:"; ObjectID = "h6R-RQ-s0t"; */ 158 | "h6R-RQ-s0t.title" = "白名单:"; 159 | 160 | /* Class = "NSTextFieldCell"; placeholderString = "1080"; ObjectID = "hpa-EM-orp"; */ 161 | "hpa-EM-orp.placeholderString" = "1080"; 162 | 163 | /* Class = "NSMenu"; title = "Services"; ObjectID = "hz9-B4-Xy5"; */ 164 | "hz9-B4-Xy5.title" = "服务"; 165 | 166 | /* Class = "NSMenuItem"; title = "Format"; ObjectID = "jxT-CU-nIS"; */ 167 | "jxT-CU-nIS.title" = "格式"; 168 | 169 | /* Class = "NSTextFieldCell"; placeholderString = "Listening Address: 0.0.0.0, 127.0.0.1"; ObjectID = "kKq-2t-fwt"; */ 170 | "kKq-2t-fwt.placeholderString" = "监听地址: 0.0.0.0, 127.0.0.1"; 171 | 172 | /* Class = "NSTextFieldCell"; title = "0 KB/s ↓"; ObjectID = "kcC-Z5-c4O"; */ 173 | "kcC-Z5-c4O.title" = "0 KB/s ↓"; 174 | 175 | /* Class = "NSTextFieldCell"; title = "0 KB"; ObjectID = "q8v-Xs-Nzp"; */ 176 | "q8v-Xs-Nzp.title" = "0 KB"; 177 | 178 | /* Class = "NSButtonCell"; title = "Close"; ObjectID = "qah-Sp-kt3"; */ 179 | "qah-Sp-kt3.title" = "关闭"; 180 | 181 | /* Class = "NSTextFieldCell"; title = "Servers List:"; ObjectID = "rP6-Tk-LZ4"; */ 182 | "rP6-Tk-LZ4.title" = "服务器列表:"; 183 | 184 | /* Class = "NSButtonCell"; title = "Keep Connection"; ObjectID = "tZb-9v-MfO"; */ 185 | "tZb-9v-MfO.title" = "启用服务器"; 186 | 187 | /* Class = "NSMenu"; title = "LightSwordX"; ObjectID = "uQy-DD-JDr"; */ 188 | "uQy-DD-JDr.title" = "LightSwordX"; 189 | 190 | /* Class = "NSMenuItem"; title = "Help"; ObjectID = "wpr-3q-Mcd"; */ 191 | "wpr-3q-Mcd.title" = "帮助"; 192 | 193 | /* Class = "NSTextFieldCell"; title = "Source Code: https://github.com/SunshinyNeko/LightSwordX"; ObjectID = "xjN-cc-33o"; */ 194 | "xjN-cc-33o.title" = "源码地址: https://github.com/SunshinyNeko/LightSwordX"; 195 | 196 | /* Class = "NSTextFieldCell"; title = "Password:"; ObjectID = "xmv-oa-oyN"; */ 197 | "xmv-oa-oyN.title" = "密码:"; 198 | -------------------------------------------------------------------------------- /LightSwordXHelper/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LightSwordXHelper 4 | // 5 | // Created by Neko on 12/28/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | func applicationDidFinishLaunching(aNotification: NSNotification) { 15 | let isRunning = NSWorkspace.sharedWorkspace().runningApplications.filter({ a in a.bundleIdentifier != nil ? a.bundleIdentifier! == "org.lightsword.LightSwordX" : false ?? false }).count > 0 16 | 17 | if isRunning { 18 | NSApp.terminate(nil) 19 | return 20 | } 21 | 22 | let path = NSBundle.mainBundle().bundlePath as NSString 23 | var components = path.pathComponents 24 | components.removeLast() 25 | components.removeLast() 26 | components.removeLast() 27 | components.append("MacOS") 28 | components.append("LightSwordX") 29 | 30 | NSWorkspace.sharedWorkspace().launchApplication(NSString.pathWithComponents(components)) 31 | NSApp.terminate(nil) 32 | } 33 | 34 | func applicationWillTerminate(aNotification: NSNotification) { 35 | // Insert code here to tear down your application 36 | } 37 | 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660318_game-fighting-sword-shooter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660318_game-fighting-sword-shooter.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660323_game-fighting-sword-shooter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660323_game-fighting-sword-shooter.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660327_game-fighting-sword-shooter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660327_game-fighting-sword-shooter.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660336_game-fighting-sword-shooter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/1451660336_game-fighting-sword-shooter.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "sword_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "1451660336_game-fighting-sword-shooter.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "1451660318_game-fighting-sword-shooter.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "1451660323_game-fighting-sword-shooter.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "1451660327_game-fighting-sword-shooter.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/sword_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/LightSwordXHelper/Assets.xcassets/AppIcon.appiconset/sword_16.png -------------------------------------------------------------------------------- /LightSwordXHelper/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /LightSwordXHelper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSBackgroundOnly 28 | 29 | LSMinimumSystemVersion 30 | $(MACOSX_DEPLOYMENT_TARGET) 31 | NSHumanReadableCopyright 32 | Copyright © 2015 Neko. All rights reserved. 33 | NSMainStoryboardFile 34 | Main 35 | NSPrincipalClass 36 | NSApplication 37 | 38 | 39 | -------------------------------------------------------------------------------- /LightSwordXHelper/LightSwordXHelper.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LightSwordXHelper/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSMenuItem"; title = "Customize Toolbar…"; ObjectID = "1UK-8n-QPP"; */ 3 | "1UK-8n-QPP.title" = "Customize Toolbar…"; 4 | 5 | /* Class = "NSMenuItem"; title = "LightSwordXHelper"; ObjectID = "1Xt-HY-uBw"; */ 6 | "1Xt-HY-uBw.title" = "LightSwordXHelper"; 7 | 8 | /* Class = "NSMenu"; title = "Find"; ObjectID = "1b7-l0-nxx"; */ 9 | "1b7-l0-nxx.title" = "Find"; 10 | 11 | /* Class = "NSMenuItem"; title = "Lower"; ObjectID = "1tx-W0-xDw"; */ 12 | "1tx-W0-xDw.title" = "Lower"; 13 | 14 | /* Class = "NSMenuItem"; title = "Raise"; ObjectID = "2h7-ER-AoG"; */ 15 | "2h7-ER-AoG.title" = "Raise"; 16 | 17 | /* Class = "NSMenuItem"; title = "Transformations"; ObjectID = "2oI-Rn-ZJC"; */ 18 | "2oI-Rn-ZJC.title" = "Transformations"; 19 | 20 | /* Class = "NSMenu"; title = "Spelling"; ObjectID = "3IN-sU-3Bg"; */ 21 | "3IN-sU-3Bg.title" = "Spelling"; 22 | 23 | /* Class = "NSMenuItem"; title = "Use Default"; ObjectID = "3Om-Ey-2VK"; */ 24 | "3Om-Ey-2VK.title" = "Use Default"; 25 | 26 | /* Class = "NSMenu"; title = "Speech"; ObjectID = "3rS-ZA-NoH"; */ 27 | "3rS-ZA-NoH.title" = "Speech"; 28 | 29 | /* Class = "NSMenuItem"; title = "Tighten"; ObjectID = "46P-cB-AYj"; */ 30 | "46P-cB-AYj.title" = "Tighten"; 31 | 32 | /* Class = "NSMenuItem"; title = "Find"; ObjectID = "4EN-yA-p0u"; */ 33 | "4EN-yA-p0u.title" = "Find"; 34 | 35 | /* Class = "NSMenuItem"; title = "Quit LightSwordXHelper"; ObjectID = "4sb-4s-VLi"; */ 36 | "4sb-4s-VLi.title" = "Quit LightSwordXHelper"; 37 | 38 | /* Class = "NSMenuItem"; title = "Edit"; ObjectID = "5QF-Oa-p0T"; */ 39 | "5QF-Oa-p0T.title" = "Edit"; 40 | 41 | /* Class = "NSMenuItem"; title = "Copy Style"; ObjectID = "5Vv-lz-BsD"; */ 42 | "5Vv-lz-BsD.title" = "Copy Style"; 43 | 44 | /* Class = "NSMenuItem"; title = "About LightSwordXHelper"; ObjectID = "5kV-Vb-QxS"; */ 45 | "5kV-Vb-QxS.title" = "About LightSwordXHelper"; 46 | 47 | /* Class = "NSMenuItem"; title = "Redo"; ObjectID = "6dh-zS-Vam"; */ 48 | "6dh-zS-Vam.title" = "Redo"; 49 | 50 | /* Class = "NSMenuItem"; title = "Correct Spelling Automatically"; ObjectID = "78Y-hA-62v"; */ 51 | "78Y-hA-62v.title" = "Correct Spelling Automatically"; 52 | 53 | /* Class = "NSMenu"; title = "Writing Direction"; ObjectID = "8mr-sm-Yjd"; */ 54 | "8mr-sm-Yjd.title" = "Writing Direction"; 55 | 56 | /* Class = "NSMenuItem"; title = "Substitutions"; ObjectID = "9ic-FL-obx"; */ 57 | "9ic-FL-obx.title" = "Substitutions"; 58 | 59 | /* Class = "NSMenuItem"; title = "Smart Copy/Paste"; ObjectID = "9yt-4B-nSM"; */ 60 | "9yt-4B-nSM.title" = "Smart Copy/Paste"; 61 | 62 | /* Class = "NSMenu"; title = "Main Menu"; ObjectID = "AYu-sK-qS6"; */ 63 | "AYu-sK-qS6.title" = "Main Menu"; 64 | 65 | /* Class = "NSMenuItem"; title = "Preferences…"; ObjectID = "BOF-NM-1cW"; */ 66 | "BOF-NM-1cW.title" = "Preferences…"; 67 | 68 | /* Class = "NSMenuItem"; title = "\tLeft to Right"; ObjectID = "BgM-ve-c93"; */ 69 | "BgM-ve-c93.title" = "\tLeft to Right"; 70 | 71 | /* Class = "NSMenuItem"; title = "Save As…"; ObjectID = "Bw7-FT-i3A"; */ 72 | "Bw7-FT-i3A.title" = "Save As…"; 73 | 74 | /* Class = "NSMenuItem"; title = "Close"; ObjectID = "DVo-aG-piG"; */ 75 | "DVo-aG-piG.title" = "Close"; 76 | 77 | /* Class = "NSMenuItem"; title = "Spelling and Grammar"; ObjectID = "Dv1-io-Yv7"; */ 78 | "Dv1-io-Yv7.title" = "Spelling and Grammar"; 79 | 80 | /* Class = "NSMenu"; title = "Help"; ObjectID = "F2S-fz-NVQ"; */ 81 | "F2S-fz-NVQ.title" = "Help"; 82 | 83 | /* Class = "NSMenuItem"; title = "LightSwordXHelper Help"; ObjectID = "FKE-Sm-Kum"; */ 84 | "FKE-Sm-Kum.title" = "LightSwordXHelper Help"; 85 | 86 | /* Class = "NSMenuItem"; title = "Text"; ObjectID = "Fal-I4-PZk"; */ 87 | "Fal-I4-PZk.title" = "Text"; 88 | 89 | /* Class = "NSMenu"; title = "Substitutions"; ObjectID = "FeM-D8-WVr"; */ 90 | "FeM-D8-WVr.title" = "Substitutions"; 91 | 92 | /* Class = "NSMenuItem"; title = "Bold"; ObjectID = "GB9-OM-e27"; */ 93 | "GB9-OM-e27.title" = "Bold"; 94 | 95 | /* Class = "NSMenu"; title = "Format"; ObjectID = "GEO-Iw-cKr"; */ 96 | "GEO-Iw-cKr.title" = "Format"; 97 | 98 | /* Class = "NSMenuItem"; title = "Use Default"; ObjectID = "GUa-eO-cwY"; */ 99 | "GUa-eO-cwY.title" = "Use Default"; 100 | 101 | /* Class = "NSMenuItem"; title = "Font"; ObjectID = "Gi5-1S-RQB"; */ 102 | "Gi5-1S-RQB.title" = "Font"; 103 | 104 | /* Class = "NSMenuItem"; title = "Writing Direction"; ObjectID = "H1b-Si-o9J"; */ 105 | "H1b-Si-o9J.title" = "Writing Direction"; 106 | 107 | /* Class = "NSMenuItem"; title = "View"; ObjectID = "H8h-7b-M4v"; */ 108 | "H8h-7b-M4v.title" = "View"; 109 | 110 | /* Class = "NSMenuItem"; title = "Text Replacement"; ObjectID = "HFQ-gK-NFA"; */ 111 | "HFQ-gK-NFA.title" = "Text Replacement"; 112 | 113 | /* Class = "NSMenuItem"; title = "Show Spelling and Grammar"; ObjectID = "HFo-cy-zxI"; */ 114 | "HFo-cy-zxI.title" = "Show Spelling and Grammar"; 115 | 116 | /* Class = "NSMenu"; title = "View"; ObjectID = "HyV-fh-RgO"; */ 117 | "HyV-fh-RgO.title" = "View"; 118 | 119 | /* Class = "NSMenuItem"; title = "Subscript"; ObjectID = "I0S-gh-46l"; */ 120 | "I0S-gh-46l.title" = "Subscript"; 121 | 122 | /* Class = "NSMenuItem"; title = "Open…"; ObjectID = "IAo-SY-fd9"; */ 123 | "IAo-SY-fd9.title" = "Open…"; 124 | 125 | /* Class = "NSMenuItem"; title = "Justify"; ObjectID = "J5U-5w-g23"; */ 126 | "J5U-5w-g23.title" = "Justify"; 127 | 128 | /* Class = "NSMenuItem"; title = "Use None"; ObjectID = "J7y-lM-qPV"; */ 129 | "J7y-lM-qPV.title" = "Use None"; 130 | 131 | /* Class = "NSMenuItem"; title = "Revert to Saved"; ObjectID = "KaW-ft-85H"; */ 132 | "KaW-ft-85H.title" = "Revert to Saved"; 133 | 134 | /* Class = "NSMenuItem"; title = "Show All"; ObjectID = "Kd2-mp-pUS"; */ 135 | "Kd2-mp-pUS.title" = "Show All"; 136 | 137 | /* Class = "NSMenuItem"; title = "Bring All to Front"; ObjectID = "LE2-aR-0XJ"; */ 138 | "LE2-aR-0XJ.title" = "Bring All to Front"; 139 | 140 | /* Class = "NSMenuItem"; title = "Paste Ruler"; ObjectID = "LVM-kO-fVI"; */ 141 | "LVM-kO-fVI.title" = "Paste Ruler"; 142 | 143 | /* Class = "NSMenuItem"; title = "\tLeft to Right"; ObjectID = "Lbh-J2-qVU"; */ 144 | "Lbh-J2-qVU.title" = "\tLeft to Right"; 145 | 146 | /* Class = "NSMenuItem"; title = "Copy Ruler"; ObjectID = "MkV-Pr-PK5"; */ 147 | "MkV-Pr-PK5.title" = "Copy Ruler"; 148 | 149 | /* Class = "NSMenuItem"; title = "Services"; ObjectID = "NMo-om-nkz"; */ 150 | "NMo-om-nkz.title" = "Services"; 151 | 152 | /* Class = "NSMenuItem"; title = "\tDefault"; ObjectID = "Nop-cj-93Q"; */ 153 | "Nop-cj-93Q.title" = "\tDefault"; 154 | 155 | /* Class = "NSMenuItem"; title = "Minimize"; ObjectID = "OY7-WF-poV"; */ 156 | "OY7-WF-poV.title" = "Minimize"; 157 | 158 | /* Class = "NSMenuItem"; title = "Baseline"; ObjectID = "OaQ-X3-Vso"; */ 159 | "OaQ-X3-Vso.title" = "Baseline"; 160 | 161 | /* Class = "NSMenuItem"; title = "Hide LightSwordXHelper"; ObjectID = "Olw-nP-bQN"; */ 162 | "Olw-nP-bQN.title" = "Hide LightSwordXHelper"; 163 | 164 | /* Class = "NSMenuItem"; title = "Find Previous"; ObjectID = "OwM-mh-QMV"; */ 165 | "OwM-mh-QMV.title" = "Find Previous"; 166 | 167 | /* Class = "NSMenuItem"; title = "Stop Speaking"; ObjectID = "Oyz-dy-DGm"; */ 168 | "Oyz-dy-DGm.title" = "Stop Speaking"; 169 | 170 | /* Class = "NSMenuItem"; title = "Bigger"; ObjectID = "Ptp-SP-VEL"; */ 171 | "Ptp-SP-VEL.title" = "Bigger"; 172 | 173 | /* Class = "NSMenuItem"; title = "Show Fonts"; ObjectID = "Q5e-8K-NDq"; */ 174 | "Q5e-8K-NDq.title" = "Show Fonts"; 175 | 176 | /* Class = "NSMenuItem"; title = "Zoom"; ObjectID = "R4o-n2-Eq4"; */ 177 | "R4o-n2-Eq4.title" = "Zoom"; 178 | 179 | /* Class = "NSMenuItem"; title = "\tRight to Left"; ObjectID = "RB4-Sm-HuC"; */ 180 | "RB4-Sm-HuC.title" = "\tRight to Left"; 181 | 182 | /* Class = "NSMenuItem"; title = "Superscript"; ObjectID = "Rqc-34-cIF"; */ 183 | "Rqc-34-cIF.title" = "Superscript"; 184 | 185 | /* Class = "NSMenuItem"; title = "Select All"; ObjectID = "Ruw-6m-B2m"; */ 186 | "Ruw-6m-B2m.title" = "Select All"; 187 | 188 | /* Class = "NSMenuItem"; title = "Jump to Selection"; ObjectID = "S0p-oC-mLd"; */ 189 | "S0p-oC-mLd.title" = "Jump to Selection"; 190 | 191 | /* Class = "NSMenu"; title = "Window"; ObjectID = "Td7-aD-5lo"; */ 192 | "Td7-aD-5lo.title" = "Window"; 193 | 194 | /* Class = "NSMenuItem"; title = "Capitalize"; ObjectID = "UEZ-Bs-lqG"; */ 195 | "UEZ-Bs-lqG.title" = "Capitalize"; 196 | 197 | /* Class = "NSMenuItem"; title = "Center"; ObjectID = "VIY-Ag-zcb"; */ 198 | "VIY-Ag-zcb.title" = "Center"; 199 | 200 | /* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "Vdr-fp-XzO"; */ 201 | "Vdr-fp-XzO.title" = "Hide Others"; 202 | 203 | /* Class = "NSMenuItem"; title = "Italic"; ObjectID = "Vjx-xi-njq"; */ 204 | "Vjx-xi-njq.title" = "Italic"; 205 | 206 | /* Class = "NSMenu"; title = "Edit"; ObjectID = "W48-6f-4Dl"; */ 207 | "W48-6f-4Dl.title" = "Edit"; 208 | 209 | /* Class = "NSMenuItem"; title = "Underline"; ObjectID = "WRG-CD-K1S"; */ 210 | "WRG-CD-K1S.title" = "Underline"; 211 | 212 | /* Class = "NSMenuItem"; title = "New"; ObjectID = "Was-JA-tGl"; */ 213 | "Was-JA-tGl.title" = "New"; 214 | 215 | /* Class = "NSMenuItem"; title = "Paste and Match Style"; ObjectID = "WeT-3V-zwk"; */ 216 | "WeT-3V-zwk.title" = "Paste and Match Style"; 217 | 218 | /* Class = "NSMenuItem"; title = "Find…"; ObjectID = "Xz5-n4-O0W"; */ 219 | "Xz5-n4-O0W.title" = "Find…"; 220 | 221 | /* Class = "NSMenuItem"; title = "Find and Replace…"; ObjectID = "YEy-JH-Tfz"; */ 222 | "YEy-JH-Tfz.title" = "Find and Replace…"; 223 | 224 | /* Class = "NSMenuItem"; title = "\tDefault"; ObjectID = "YGs-j5-SAR"; */ 225 | "YGs-j5-SAR.title" = "\tDefault"; 226 | 227 | /* Class = "NSMenuItem"; title = "Start Speaking"; ObjectID = "Ynk-f8-cLZ"; */ 228 | "Ynk-f8-cLZ.title" = "Start Speaking"; 229 | 230 | /* Class = "NSMenuItem"; title = "Align Left"; ObjectID = "ZM1-6Q-yy1"; */ 231 | "ZM1-6Q-yy1.title" = "Align Left"; 232 | 233 | /* Class = "NSMenuItem"; title = "Paragraph"; ObjectID = "ZvO-Gk-QUH"; */ 234 | "ZvO-Gk-QUH.title" = "Paragraph"; 235 | 236 | /* Class = "NSMenuItem"; title = "Print…"; ObjectID = "aTl-1u-JFS"; */ 237 | "aTl-1u-JFS.title" = "Print…"; 238 | 239 | /* Class = "NSMenuItem"; title = "Window"; ObjectID = "aUF-d1-5bR"; */ 240 | "aUF-d1-5bR.title" = "Window"; 241 | 242 | /* Class = "NSMenu"; title = "Font"; ObjectID = "aXa-aM-Jaq"; */ 243 | "aXa-aM-Jaq.title" = "Font"; 244 | 245 | /* Class = "NSMenuItem"; title = "Use Default"; ObjectID = "agt-UL-0e3"; */ 246 | "agt-UL-0e3.title" = "Use Default"; 247 | 248 | /* Class = "NSMenuItem"; title = "Show Colors"; ObjectID = "bgn-CT-cEk"; */ 249 | "bgn-CT-cEk.title" = "Show Colors"; 250 | 251 | /* Class = "NSMenu"; title = "File"; ObjectID = "bib-Uj-vzu"; */ 252 | "bib-Uj-vzu.title" = "File"; 253 | 254 | /* Class = "NSMenuItem"; title = "Use Selection for Find"; ObjectID = "buJ-ug-pKt"; */ 255 | "buJ-ug-pKt.title" = "Use Selection for Find"; 256 | 257 | /* Class = "NSMenu"; title = "Transformations"; ObjectID = "c8a-y6-VQd"; */ 258 | "c8a-y6-VQd.title" = "Transformations"; 259 | 260 | /* Class = "NSMenuItem"; title = "Use None"; ObjectID = "cDB-IK-hbR"; */ 261 | "cDB-IK-hbR.title" = "Use None"; 262 | 263 | /* Class = "NSMenuItem"; title = "Selection"; ObjectID = "cqv-fj-IhA"; */ 264 | "cqv-fj-IhA.title" = "Selection"; 265 | 266 | /* Class = "NSMenuItem"; title = "Smart Links"; ObjectID = "cwL-P1-jid"; */ 267 | "cwL-P1-jid.title" = "Smart Links"; 268 | 269 | /* Class = "NSMenuItem"; title = "Make Lower Case"; ObjectID = "d9M-CD-aMd"; */ 270 | "d9M-CD-aMd.title" = "Make Lower Case"; 271 | 272 | /* Class = "NSMenu"; title = "Text"; ObjectID = "d9c-me-L2H"; */ 273 | "d9c-me-L2H.title" = "Text"; 274 | 275 | /* Class = "NSMenuItem"; title = "File"; ObjectID = "dMs-cI-mzQ"; */ 276 | "dMs-cI-mzQ.title" = "File"; 277 | 278 | /* Class = "NSMenuItem"; title = "Undo"; ObjectID = "dRJ-4n-Yzg"; */ 279 | "dRJ-4n-Yzg.title" = "Undo"; 280 | 281 | /* Class = "NSMenuItem"; title = "Paste"; ObjectID = "gVA-U4-sdL"; */ 282 | "gVA-U4-sdL.title" = "Paste"; 283 | 284 | /* Class = "NSMenuItem"; title = "Smart Quotes"; ObjectID = "hQb-2v-fYv"; */ 285 | "hQb-2v-fYv.title" = "Smart Quotes"; 286 | 287 | /* Class = "NSMenuItem"; title = "Check Document Now"; ObjectID = "hz2-CU-CR7"; */ 288 | "hz2-CU-CR7.title" = "Check Document Now"; 289 | 290 | /* Class = "NSMenu"; title = "Services"; ObjectID = "hz9-B4-Xy5"; */ 291 | "hz9-B4-Xy5.title" = "Services"; 292 | 293 | /* Class = "NSMenuItem"; title = "Smaller"; ObjectID = "i1d-Er-qST"; */ 294 | "i1d-Er-qST.title" = "Smaller"; 295 | 296 | /* Class = "NSMenu"; title = "Baseline"; ObjectID = "ijk-EB-dga"; */ 297 | "ijk-EB-dga.title" = "Baseline"; 298 | 299 | /* Class = "NSMenuItem"; title = "Kern"; ObjectID = "jBQ-r6-VK2"; */ 300 | "jBQ-r6-VK2.title" = "Kern"; 301 | 302 | /* Class = "NSMenuItem"; title = "\tRight to Left"; ObjectID = "jFq-tB-4Kx"; */ 303 | "jFq-tB-4Kx.title" = "\tRight to Left"; 304 | 305 | /* Class = "NSMenuItem"; title = "Format"; ObjectID = "jxT-CU-nIS"; */ 306 | "jxT-CU-nIS.title" = "Format"; 307 | 308 | /* Class = "NSMenuItem"; title = "Check Grammar With Spelling"; ObjectID = "mK6-2p-4JG"; */ 309 | "mK6-2p-4JG.title" = "Check Grammar With Spelling"; 310 | 311 | /* Class = "NSMenuItem"; title = "Ligatures"; ObjectID = "o6e-r0-MWq"; */ 312 | "o6e-r0-MWq.title" = "Ligatures"; 313 | 314 | /* Class = "NSMenu"; title = "Open Recent"; ObjectID = "oas-Oc-fiZ"; */ 315 | "oas-Oc-fiZ.title" = "Open Recent"; 316 | 317 | /* Class = "NSMenuItem"; title = "Loosen"; ObjectID = "ogc-rX-tC1"; */ 318 | "ogc-rX-tC1.title" = "Loosen"; 319 | 320 | /* Class = "NSMenuItem"; title = "Delete"; ObjectID = "pa3-QI-u2k"; */ 321 | "pa3-QI-u2k.title" = "Delete"; 322 | 323 | /* Class = "NSMenuItem"; title = "Save…"; ObjectID = "pxx-59-PXV"; */ 324 | "pxx-59-PXV.title" = "Save…"; 325 | 326 | /* Class = "NSMenuItem"; title = "Find Next"; ObjectID = "q09-fT-Sye"; */ 327 | "q09-fT-Sye.title" = "Find Next"; 328 | 329 | /* Class = "NSMenuItem"; title = "Page Setup…"; ObjectID = "qIS-W8-SiK"; */ 330 | "qIS-W8-SiK.title" = "Page Setup…"; 331 | 332 | /* Class = "NSMenuItem"; title = "Check Spelling While Typing"; ObjectID = "rbD-Rh-wIN"; */ 333 | "rbD-Rh-wIN.title" = "Check Spelling While Typing"; 334 | 335 | /* Class = "NSMenuItem"; title = "Smart Dashes"; ObjectID = "rgM-f4-ycn"; */ 336 | "rgM-f4-ycn.title" = "Smart Dashes"; 337 | 338 | /* Class = "NSMenuItem"; title = "Show Toolbar"; ObjectID = "snW-S8-Cw5"; */ 339 | "snW-S8-Cw5.title" = "Show Toolbar"; 340 | 341 | /* Class = "NSMenuItem"; title = "Data Detectors"; ObjectID = "tRr-pd-1PS"; */ 342 | "tRr-pd-1PS.title" = "Data Detectors"; 343 | 344 | /* Class = "NSMenuItem"; title = "Open Recent"; ObjectID = "tXI-mr-wws"; */ 345 | "tXI-mr-wws.title" = "Open Recent"; 346 | 347 | /* Class = "NSMenu"; title = "Kern"; ObjectID = "tlD-Oa-oAM"; */ 348 | "tlD-Oa-oAM.title" = "Kern"; 349 | 350 | /* Class = "NSMenu"; title = "LightSwordXHelper"; ObjectID = "uQy-DD-JDr"; */ 351 | "uQy-DD-JDr.title" = "LightSwordXHelper"; 352 | 353 | /* Class = "NSMenuItem"; title = "Cut"; ObjectID = "uRl-iY-unG"; */ 354 | "uRl-iY-unG.title" = "Cut"; 355 | 356 | /* Class = "NSMenuItem"; title = "Paste Style"; ObjectID = "vKC-jM-MkH"; */ 357 | "vKC-jM-MkH.title" = "Paste Style"; 358 | 359 | /* Class = "NSMenuItem"; title = "Show Ruler"; ObjectID = "vLm-3I-IUL"; */ 360 | "vLm-3I-IUL.title" = "Show Ruler"; 361 | 362 | /* Class = "NSMenuItem"; title = "Clear Menu"; ObjectID = "vNY-rz-j42"; */ 363 | "vNY-rz-j42.title" = "Clear Menu"; 364 | 365 | /* Class = "NSMenuItem"; title = "Make Upper Case"; ObjectID = "vmV-6d-7jI"; */ 366 | "vmV-6d-7jI.title" = "Make Upper Case"; 367 | 368 | /* Class = "NSMenu"; title = "Ligatures"; ObjectID = "w0m-vy-SC9"; */ 369 | "w0m-vy-SC9.title" = "Ligatures"; 370 | 371 | /* Class = "NSMenuItem"; title = "Align Right"; ObjectID = "wb2-vD-lq4"; */ 372 | "wb2-vD-lq4.title" = "Align Right"; 373 | 374 | /* Class = "NSMenuItem"; title = "Help"; ObjectID = "wpr-3q-Mcd"; */ 375 | "wpr-3q-Mcd.title" = "Help"; 376 | 377 | /* Class = "NSMenuItem"; title = "Copy"; ObjectID = "x3v-GG-iWU"; */ 378 | "x3v-GG-iWU.title" = "Copy"; 379 | 380 | /* Class = "NSMenuItem"; title = "Use All"; ObjectID = "xQD-1f-W4t"; */ 381 | "xQD-1f-W4t.title" = "Use All"; 382 | 383 | /* Class = "NSMenuItem"; title = "Speech"; ObjectID = "xrE-MZ-jX0"; */ 384 | "xrE-MZ-jX0.title" = "Speech"; 385 | 386 | /* Class = "NSMenuItem"; title = "Show Substitutions"; ObjectID = "z6F-FW-3nz"; */ 387 | "z6F-FW-3nz.title" = "Show Substitutions"; 388 | -------------------------------------------------------------------------------- /LightSwordXTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LightSwordXTests/LightSwordXTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LightSwordXTests.swift 3 | // LightSwordXTests 4 | // 5 | // Created by Neko on 12/17/15. 6 | // Copyright © 2015 Neko. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LightSwordX 11 | 12 | class LightSwordXTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | func testIpv4() { 37 | let rawData = [0x87, 0x58, 0x24, 0xef]; 38 | let addr = rawData.reduce("", combine: { (c: String, n: Int) in c.characters.count > 1 ? c + String(format: ".%d", n) : String(format: "%d.%d", c, n)}) 39 | 40 | assert(addr == "135.88.36.239"); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LightSwordX 2 | 3 | [简体中文](./README_zh.md) 4 | 5 | LightSwordX is a SOCKS5 proxy client for OS X 10.10+. 6 | 7 | It's an open-source project. To get it, you may download the source code and compile it on your Mac, or buy it from Mac App Store. 8 | 9 | LightSwordX has a built-in remote proxy server that is free for everyone. Of course, everyone can set up LightSword Server for self, and enjoy it by using LightSwordX or LightSword Command Line Interface. 10 | 11 | **HOW TO USE** 12 | 13 | 1. Run LightSword from Launchpad 14 | 15 | 2. Open System Preferences - Network - Advanced - Proxies 16 | 17 | 3. Select 'SOCKS Proxy', fill in server address and port number 18 | 19 | 4. Click OK - Apply Settings 20 | 21 | 5. Open Safari or Chrome, surf the Internet! 22 | 23 | You can buy it from Mac App Store: 24 | 25 | [](https://itunes.apple.com/us/app/lightswordx/id1071607364?ls=1&mt=12) 26 | 27 | Price: $0.99 28 | 29 | **Why it's not Free on Mac App Store?** 30 | 31 | LightSwordX is an open-source software, everyone can download the source code and compile it on Mac without any cost. But you may know **maintenance is the most expensive part** of software. No one can live without money! So, as a developer, I hope people would use and buy it. Thanks. 32 | 33 | Features 34 | --- 35 | 36 | ✓ Enable mutli proxy servers simultaneously 37 | 38 | ✓ IPv6 39 | 40 | ✓ Whitelist & Blacklist 41 | 42 | ✓ Start self on system startup 43 | 44 | ✓ Traffic statistics 45 | 46 | Privacy Policy 47 | --- 48 | 49 | LightSwordX doesn't collect any data about the user. 50 | 51 | License 52 | --- 53 | 54 | GPLv2 -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # LightSwordX 2 | 3 | [English](./README.md) 4 | 5 | LightSwordX 是一款基于 OS X 10.10+ 的 SOCKS5 代理客户端应用 6 | 7 | LightSwordX 是完全开源的,你可以下载源码并且在 Mac 上编译,或者从 Mac App Store 上购买。 8 | 9 | LightSwordX 内置一台由网友免费提供的公用代理服务器,当然,你也可以搭建自己的服务器,并通过 LightSwordX 或者命令行工具使用代理。 10 | 11 | **如何使用** 12 | 13 | 1. 从 Mac App Store 购买或者下载源码编译并运行,输入服务器IP地址、端口号,密码,勾选“启用该服务器” 14 | 15 | 2. 打开系统偏好 - 网络 - 高级 - 代理 16 | 17 | 3. 勾选 “SOCKS 代理” 18 | 19 | 4. 输入 127.0.0.1 和端口号(默认: 1080),无需密码 20 | 21 | 5. 保存并应用设置 22 | 23 | 6. 使用 Safari 或 Chrome 访问 Internet 24 | 25 | 如果你有多台服务器,LightSwordX 也支持同时启用多服务器。只需要点击 + 按钮,按照上述配置新服务器即可。 在 Chrome 中,安装 SwitchyOmega 插件,新建 Profile,选择 SOCKS5 代理类型,并且填写本地 IP 和端口号,最后再启用 SwitchyOmega 即可。 26 | 27 | 从 Mac App Store 购买: 28 | 29 | [](https://itunes.apple.com/us/app/lightswordx/id1071607364?ls=1&mt=12) 30 | 31 | 价格: $0.99 32 | 33 | **为什么不是免费的?** 34 | 35 | LightSwordX 是完全开源的软件,每个人都可以下载源码并且编译运行。但是创建和维护任何一个项目都是需要成本与开销的。即便是开源项目,通常来说,也要有资金来源才能更好的发展。虽然不论你是否购买,我都会维护下去,但还是希望有用户能够购买该 App,支持这个该项目发展。 36 | 37 | 特性 38 | --- 39 | 40 | ✓ 同时使用多台服务器 41 | 42 | ✓ IPv6 43 | 44 | ✓ 黑白名单 45 | 46 | ✓ 开机启动 47 | 48 | ✓ 流量统计 49 | 50 | 隐私政策 51 | --- 52 | 53 | LightSwordX 不收集有关用户的任何信息 54 | 55 | License 56 | --- 57 | GPLv2 -------------------------------------------------------------------------------- /SINQ.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /SINQ.framework/Modules: -------------------------------------------------------------------------------- 1 | Versions/Current/Modules -------------------------------------------------------------------------------- /SINQ.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /SINQ.framework/SINQ: -------------------------------------------------------------------------------- 1 | Versions/Current/SINQ -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Headers/SINQ-Swift.h: -------------------------------------------------------------------------------- 1 | // Generated by Apple Swift version 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81) 2 | #pragma clang diagnostic push 3 | 4 | #if defined(__has_include) && __has_include() 5 | # include 6 | #endif 7 | 8 | #pragma clang diagnostic ignored "-Wauto-import" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(__has_include) && __has_include() 15 | # include 16 | #elif !defined(__cplusplus) || __cplusplus < 201103L 17 | typedef uint_least16_t char16_t; 18 | typedef uint_least32_t char32_t; 19 | #endif 20 | 21 | typedef struct _NSZone NSZone; 22 | 23 | #if !defined(SWIFT_PASTE) 24 | # define SWIFT_PASTE_HELPER(x, y) x##y 25 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) 26 | #endif 27 | #if !defined(SWIFT_METATYPE) 28 | # define SWIFT_METATYPE(X) Class 29 | #endif 30 | 31 | #if defined(__has_attribute) && __has_attribute(objc_runtime_name) 32 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) 33 | #else 34 | # define SWIFT_RUNTIME_NAME(X) 35 | #endif 36 | #if defined(__has_attribute) && __has_attribute(swift_name) 37 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) 38 | #else 39 | # define SWIFT_COMPILE_NAME(X) 40 | #endif 41 | #if !defined(SWIFT_CLASS_EXTRA) 42 | # define SWIFT_CLASS_EXTRA 43 | #endif 44 | #if !defined(SWIFT_PROTOCOL_EXTRA) 45 | # define SWIFT_PROTOCOL_EXTRA 46 | #endif 47 | #if !defined(SWIFT_ENUM_EXTRA) 48 | # define SWIFT_ENUM_EXTRA 49 | #endif 50 | #if !defined(SWIFT_CLASS) 51 | # if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 52 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA 53 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 54 | # else 55 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 56 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 57 | # endif 58 | #endif 59 | 60 | #if !defined(SWIFT_PROTOCOL) 61 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 62 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 63 | #endif 64 | 65 | #if !defined(SWIFT_EXTENSION) 66 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) 67 | #endif 68 | 69 | #if !defined(OBJC_DESIGNATED_INITIALIZER) 70 | # if defined(__has_attribute) && __has_attribute(objc_designated_initializer) 71 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 72 | # else 73 | # define OBJC_DESIGNATED_INITIALIZER 74 | # endif 75 | #endif 76 | #if !defined(SWIFT_ENUM) 77 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type 78 | #endif 79 | typedef float swift_float2 __attribute__((__ext_vector_type__(2))); 80 | typedef float swift_float3 __attribute__((__ext_vector_type__(3))); 81 | typedef float swift_float4 __attribute__((__ext_vector_type__(4))); 82 | typedef double swift_double2 __attribute__((__ext_vector_type__(2))); 83 | typedef double swift_double3 __attribute__((__ext_vector_type__(3))); 84 | typedef double swift_double4 __attribute__((__ext_vector_type__(4))); 85 | typedef int swift_int2 __attribute__((__ext_vector_type__(2))); 86 | typedef int swift_int3 __attribute__((__ext_vector_type__(3))); 87 | typedef int swift_int4 __attribute__((__ext_vector_type__(4))); 88 | #if defined(__has_feature) && __has_feature(modules) 89 | #endif 90 | 91 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" 92 | #pragma clang diagnostic ignored "-Wduplicate-method-arg" 93 | #pragma clang diagnostic pop 94 | -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Headers/SINQ.h: -------------------------------------------------------------------------------- 1 | // 2 | // SINQ.h 3 | // SINQ 4 | // 5 | // Created by Leszek Ślażyński on 25/06/14. 6 | // Copyright (c) 2014 Leszek Ślażyński. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SINQ. 12 | FOUNDATION_EXPORT double SINQVersionNumber; 13 | 14 | //! Project version string for SINQ. 15 | FOUNDATION_EXPORT const unsigned char SINQVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Modules/SINQ.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/SINQ.framework/Versions/A/Modules/SINQ.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Modules/SINQ.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/SINQ.framework/Versions/A/Modules/SINQ.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module SINQ { 2 | umbrella header "SINQ.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module SINQ.Swift { 9 | header "SINQ-Swift.h" 10 | } 11 | -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 15D21 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | SINQ 11 | CFBundleIdentifier 12 | com.utdloc.SINQ 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | SINQ 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleSupportedPlatforms 24 | 25 | MacOSX 26 | 27 | CFBundleVersion 28 | 0.5.0 29 | DTCompiler 30 | com.apple.compilers.llvm.clang.1_0 31 | DTPlatformBuild 32 | 7C1002 33 | DTPlatformVersion 34 | GM 35 | DTSDKBuild 36 | 15C43 37 | DTSDKName 38 | macosx10.11 39 | DTXcode 40 | 0721 41 | DTXcodeBuild 42 | 7C1002 43 | NSHumanReadableCopyright 44 | Copyright © 2014 Leszek Ślażyński. All rights reserved. 45 | 46 | 47 | -------------------------------------------------------------------------------- /SINQ.framework/Versions/A/SINQ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UnsignedInt8/LightSwordX/98eea71721ae22a65446b9d56f45aa2a689f5266/SINQ.framework/Versions/A/SINQ -------------------------------------------------------------------------------- /SINQ.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A --------------------------------------------------------------------------------