├── thunderPassby
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ ├── icon_16x16.png
│ │ ├── icon_32x32.png
│ │ ├── icon_128x128.png
│ │ ├── icon_256x256.png
│ │ ├── icon_512x512.png
│ │ ├── icon_16x16@2x.png
│ │ ├── icon_256x256-1.png
│ │ ├── icon_256x256@2x.png
│ │ ├── icon_32x32@2x.png
│ │ ├── icon_512x512@2x.png
│ │ └── Contents.json
├── thunderPassby.entitlements
├── AppDelegate.swift
├── WindowController.swift
├── Info.plist
├── ViewController.swift
├── Base64FS.swift
└── Base.lproj
│ └── Main.storyboard
├── thunderPassby.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── Chih-Hao.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── README.md
/thunderPassby/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256-1.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhihaozhang/thunder-Bypass/HEAD/thunderPassby/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/thunderPassby.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/thunderPassby.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/thunderPassby/thunderPassby.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/thunderPassby.xcodeproj/xcuserdata/Chih-Hao.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | thunderPassby.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # thunder-Bypass for macOS
2 |
3 | 破解并获得以thunder:// 开头的迅雷下载地址背后的真实下载地址,自动复制到您的剪切板,您可以用非迅雷的第三方下载软件另行下载。
4 |
5 | *Get the real dwnload url from encrypted thunder url which starts with thunder://*
6 |
7 | ### icon -> 软件用途
8 |
9 | 
10 |
11 | icon很有趣,是围绕着迅雷的图标展开的。迅雷的图标是一只鸟,thunder-Bypass旨在绕开(Bypass)迅雷(thunder),因此,我用迅雷icon那只鸟飞出鸟笼的瞬间作为图标,寓意着突破迅雷的禁锢。
12 |
13 | ### 主界面:
14 |
15 | 
16 |
17 | ### 通知中心视图:
18 |
19 | 成功破解、迅雷下载链接无效,均有相应提示。
20 |
21 | 
22 |
23 |
24 |
25 | # License
26 |
27 | **MIT**
28 |
--------------------------------------------------------------------------------
/thunderPassby/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // thunderPassby
4 | //
5 | // Created by Chih-Hao on 2018/5/29.
6 | // Copyright © 2018年 Chih-Hao. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
15 | return true
16 | }
17 |
18 | func applicationDidFinishLaunching(_ aNotification: Notification) {
19 | // Insert code here to initialize your application
20 | }
21 |
22 | func applicationWillTerminate(_ aNotification: Notification) {
23 | // Insert code here to tear down your application
24 | }
25 |
26 |
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/thunderPassby/WindowController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowController.swift
3 | // thunderPassby
4 | //
5 | // Created by Chih-Hao on 2018/5/29.
6 | // Copyright © 2018年 Chih-Hao. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class WindowController: NSWindowController {
12 |
13 | override func windowDidLoad() {
14 | super.windowDidLoad()
15 |
16 | if #available(OSX 10.13, *) {
17 | let customToolbar = NSToolbar()
18 | customToolbar.showsBaselineSeparator = false
19 | window?.toolbar = customToolbar
20 | } else {
21 | // Fallback on earlier versions
22 | }
23 |
24 | window?.titlebarAppearsTransparent = true
25 | window?.titleVisibility = .hidden
26 | window?.backgroundColor = .gray
27 |
28 |
29 |
30 |
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/thunderPassby/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
22 | 1
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | Copyright © 2018年 Chih-Hao. All rights reserved.
27 | NSMainStoryboardFile
28 | Main
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/thunderPassby/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon_16x16.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" : "icon_32x32.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" : "icon_128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon_256x256-1.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon_256x256.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" : "icon_512x512.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 | }
--------------------------------------------------------------------------------
/thunderPassby/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // thunderPassby
4 | //
5 | // Created by Chih-Hao on 2018/5/29.
6 | // Copyright © 2018年 Chih-Hao. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ViewController: NSViewController,NSUserNotificationCenterDelegate {
12 |
13 | @IBOutlet weak var thunderURLFiled: NSTextField!
14 |
15 | @IBOutlet weak var decryptedURL: NSTextField!
16 |
17 | @IBAction func decryptButtonClicked(_ sender: Any) {
18 | let thunderURL = thunderURLFiled.stringValue
19 | if thunderURL.hasPrefix("thunder://") {
20 | let encryptedURL = thunderURL.substring(from: thunderURL.index(thunderURL.startIndex,offsetBy :10))
21 |
22 |
23 | let decryptedURL0 = Base64FS.decodeString(str: encryptedURL)
24 |
25 | if decryptedURL0.count > 0{
26 |
27 | let decryptedURL1 = decryptedURL0.substring(from: decryptedURL0.index(decryptedURL0.startIndex,offsetBy :2))
28 |
29 | let decryptedURL2 = decryptedURL1.substring(to: decryptedURL1.index(decryptedURL1.endIndex,offsetBy :-2))
30 |
31 | decryptedURL.stringValue = decryptedURL2
32 |
33 | // copy decrypted URL automaticly for users
34 | let pasteboard = NSPasteboard.general
35 | pasteboard.declareTypes([NSPasteboard.PasteboardType.string], owner: nil)
36 | pasteboard.setString(decryptedURL2, forType: NSPasteboard.PasteboardType.string)
37 |
38 | let userNotification = NSUserNotification()
39 | userNotification.title = "Message"
40 | userNotification.subtitle = "恭喜成功破解迅雷下载地址"
41 | userNotification.informativeText = "提示:地址已帮您复制到剪切板"
42 | // 使用NSUserNotificationCenter发送NSUserNotification
43 | let userNotificationCenter = NSUserNotificationCenter.default
44 |
45 |
46 | userNotificationCenter.delegate = self
47 |
48 | userNotificationCenter.scheduleNotification(userNotification)
49 | }else{
50 | let userNotification = NSUserNotification()
51 | userNotification.title = "Message"
52 | userNotification.subtitle = "解码失败"
53 | userNotification.informativeText = "请输入正确的迅雷下载地址"
54 | // 使用NSUserNotificationCenter发送NSUserNotification
55 | let userNotificationCenter = NSUserNotificationCenter.default
56 |
57 |
58 | userNotificationCenter.delegate = self
59 |
60 | userNotificationCenter.scheduleNotification(userNotification)
61 |
62 | thunderURLFiled.stringValue = ""
63 | }
64 |
65 | } else{
66 |
67 | let alert = NSAlert()
68 | alert.addButton(withTitle: "OK")
69 |
70 | alert.messageText = "Alert"
71 |
72 | alert.informativeText = "please input correct thunder download url which hasPrefix thunder://"
73 |
74 | alert.alertStyle = .informational
75 |
76 | alert.beginSheetModal(for: self.view.window!, completionHandler: nil)
77 |
78 | thunderURLFiled.stringValue = ""
79 | }
80 |
81 | }
82 |
83 |
84 | override func viewDidLoad() {
85 | super.viewDidLoad()
86 |
87 | }
88 |
89 | override var representedObject: Any? {
90 | didSet {
91 | // Update the view, if already loaded.
92 | }
93 | }
94 |
95 | func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool {
96 | return true
97 | }
98 |
99 |
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/thunderPassby/Base64FS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Base64FS.swift
3 | //
4 | // Created by Jack Chorley on 27/06/2017.
5 | //
6 |
7 | import Foundation
8 |
9 | public class Base64FS {
10 |
11 | private static let padding: UInt8 = 61 // Padding = "="
12 |
13 | private static let filenameSafeAlphabet: [UInt8] = [
14 | 65, // 0 = "A"
15 | 66, // 1 = "B"
16 | 67, // 2 = "C"
17 | 68, // 3 = "D"
18 | 69, // 4 = "E"
19 | 70, // 5 = "F"
20 | 71, // 6 = "G"
21 | 72, // 7 = "H"
22 | 73, // 8 = "I"
23 | 74, // 9 = "J"
24 | 75, // 10 = "K"
25 | 76, // 11 = "L"
26 | 77, // 12 = "M"
27 | 78, // 13 = "N"
28 | 79, // 14 = "O"
29 | 80, // 15 = "P"
30 | 81, // 16 = "Q"
31 | 82, // 17 = "R"
32 | 83, // 18 = "S"
33 | 84, // 19 = "T"
34 | 85, // 20 = "U"
35 | 86, // 21 = "V"
36 | 87, // 22 = "W"
37 | 88, // 23 = "X"
38 | 89, // 24 = "Y"
39 | 90, // 25 = "Z"
40 | 97, // 26 = "a"
41 | 98, // 27 = "b"
42 | 99, // 28 = "c"
43 | 100, // 29 = "d"
44 | 101, // 30 = "e"
45 | 102, // 31 = "f"
46 | 103, // 32 = "g"
47 | 104, // 33 = "h"
48 | 105, // 34 = "i"
49 | 106, // 35 = "j"
50 | 107, // 36 = "k"
51 | 108, // 37 = "l"
52 | 109, // 38 = "m"
53 | 110, // 39 = "n"
54 | 111, // 40 = "o"
55 | 112, // 41 = "p"
56 | 113, // 42 = "q"
57 | 114, // 43 = "r"
58 | 115, // 44 = "s"
59 | 116, // 45 = "t"
60 | 117, // 46 = "u"
61 | 118, // 47 = "v"
62 | 119, // 48 = "w"
63 | 120, // 49 = "x"
64 | 121, // 50 = "y"
65 | 122, // 51 = "z"
66 | 48, // 52 = "0"
67 | 49, // 53 = "1"
68 | 50, // 54 = "2"
69 | 51, // 55 = "3"
70 | 52, // 56 = "4"
71 | 53, // 57 = "5"
72 | 54, // 58 = "6"
73 | 55, // 59 = "7"
74 | 56, // 60 = "8"
75 | 57, // 61 = "9"
76 | 45, // 62 = "-"
77 | 95, // 63 = "_"
78 | ]
79 |
80 | private static let safeAlphabetToIndex: [UInt8 : UInt8] = [
81 | 61 : 0, // Padding = 0
82 | 65 : 0, // 0 = "A"
83 | 66 : 1, // 1 = "B"
84 | 67 : 2, // 2 = "C"
85 | 68 : 3, // 3 = "D"
86 | 69 : 4, // 4 = "E"
87 | 70 : 5, // 5 = "F"
88 | 71 : 6, // 6 = "G"
89 | 72 : 7, // 7 = "H"
90 | 73 : 8, // 8 = "I"
91 | 74 : 9, // 9 = "J"
92 | 75 : 10, // 10 = "K"
93 | 76 : 11, // 11 = "L"
94 | 77 : 12, // 12 = "M"
95 | 78 : 13, // 13 = "N"
96 | 79 : 14, // 14 = "O"
97 | 80 : 15, // 15 = "P"
98 | 81 : 16, // 16 = "Q"
99 | 82 : 17, // 17 = "R"
100 | 83 : 18, // 18 = "S"
101 | 84 : 19, // 19 = "T"
102 | 85 : 20, // 20 = "U"
103 | 86 : 21, // 21 = "V"
104 | 87 : 22, // 22 = "W"
105 | 88 : 23, // 23 = "X"
106 | 89 : 24, // 24 = "Y"
107 | 90 : 25, // 25 = "Z"
108 | 97 : 26, // 26 = "a"
109 | 98 : 27, // 27 = "b"
110 | 99 : 28, // 28 = "c"
111 | 100 : 29, // 29 = "d"
112 | 101 : 30, // 30 = "e"
113 | 102 : 31, // 31 = "f"
114 | 103 : 32, // 32 = "g"
115 | 104 : 33, // 33 = "h"
116 | 105 : 34, // 34 = "i"
117 | 106 : 35, // 35 = "j"
118 | 107 : 36, // 36 = "k"
119 | 108 : 37, // 37 = "l"
120 | 109 : 38, // 38 = "m"
121 | 110 : 39, // 39 = "n"
122 | 111 : 40, // 40 = "o"
123 | 112 : 41, // 41 = "p"
124 | 113 : 42, // 42 = "q"
125 | 114 : 43, // 43 = "r"
126 | 115 : 44, // 44 = "s"
127 | 116 : 45, // 45 = "t"
128 | 117 : 46, // 46 = "u"
129 | 118 : 47, // 47 = "v"
130 | 119 : 48, // 48 = "w"
131 | 120 : 49, // 49 = "x"
132 | 121 : 50, // 50 = "y"
133 | 122 : 51, // 51 = "z"
134 | 48 : 52, // 52 = "0"
135 | 49 : 53, // 53 = "1"
136 | 50 : 54, // 54 = "2"
137 | 51 : 55, // 55 = "3"
138 | 52 : 56, // 56 = "4"
139 | 53 : 57, // 57 = "5"
140 | 54 : 58, // 58 = "6"
141 | 55 : 59, // 59 = "7"
142 | 56 : 60, // 60 = "8"
143 | 57 : 61, // 61 = "9"
144 | 45 : 62, // 62 = "-"
145 | 95 : 63, // 63 = "_"
146 | ]
147 |
148 |
149 | public static func encodeString(str: String) -> String {
150 |
151 | // Get the ascii representation and return
152 | let data = str.data(using: .ascii)!
153 |
154 | let encData = encode(data: [UInt8](data))
155 |
156 | let retStr = String(data: Data(encData), encoding: .ascii)!
157 |
158 | return retStr
159 | }
160 |
161 | public static func encode(data: [UInt8]) -> [UInt8] {
162 |
163 | var result: [UInt8] = []
164 |
165 | let size = data.count
166 |
167 | // Step through 3 bytes at a time
168 | for i in stride(from: 0, to: size, by: 3) {
169 |
170 |
171 | // Get the first 6 bits, and add the Base64 letter
172 | let first = data[i] >> 2
173 | result.append(filenameSafeAlphabet[Int(first)])
174 |
175 | // Get the remaining 2 bits from the previous byte
176 | var second = (data[i] & 0b11) << 4
177 |
178 |
179 | // If there is more of the array, add the next 4 bits from byte 2, or return with padding for the 3rd and 4th characters
180 | if i + 1 < size {
181 | second |= (data[i + 1] & 0b11110000) >> 4
182 | result.append(filenameSafeAlphabet[Int(second)])
183 | } else {
184 | result.append(filenameSafeAlphabet[Int(second)])
185 | result.append(padding)
186 | result.append(padding)
187 | return result
188 | }
189 |
190 |
191 | // Get the remaining 4 bits from the previous byte
192 | var third = (data[i + 1] & 0b1111) << 2
193 |
194 | // If there is more of the array, add the next 2 bits from byte 3, or return with padding for the 4th character
195 | if i + 2 < size {
196 | third |= (data[i + 2] & 0b11000000) >> 6
197 | result.append(filenameSafeAlphabet[Int(third)])
198 | } else {
199 | result.append(filenameSafeAlphabet[Int(third)])
200 | result.append(padding)
201 | return result
202 | }
203 |
204 |
205 | // Get the remaining 6 bits from the previous byte, add to the result
206 | let forth = data[i + 2] & 0b00111111
207 | result.append(filenameSafeAlphabet[Int(forth)])
208 | }
209 |
210 | return result
211 | }
212 |
213 | public static func decode(data: [UInt8]) -> [UInt8] {
214 |
215 | var result: [UInt8] = []
216 |
217 | let size = data.count
218 | // We loop over the 4 letters at a time
219 | // We know it is padded, so we dont need to check for size
220 | for i in stride(from: 0, to: size, by: 4) {
221 |
222 | // Get the 4 letters, then get back to their non-index values
223 |
224 | if safeAlphabetToIndex[data[i]] == nil || safeAlphabetToIndex[data[i+1]] == nil || safeAlphabetToIndex[data[i+2]] == nil || safeAlphabetToIndex[data[i+3]] == nil{
225 | let resultError: [UInt8] = []
226 | return resultError
227 | }
228 |
229 | let first = safeAlphabetToIndex[data[i]]!
230 | let second = safeAlphabetToIndex[data[i + 1]]!
231 | let third = safeAlphabetToIndex[data[i + 2]]!
232 | let forth = safeAlphabetToIndex[data[i + 3]]!
233 |
234 |
235 |
236 | // Get the 3 binary letters from the four 6-bit ones
237 | let l1 = first << 2 | ((second & 0b110000) >> 4)
238 | let l2 = ((second & 0b1111) << 4) | ((third & 0b111100) >> 2)
239 | let l3 = ((third & 0b11) << 6) | forth
240 |
241 |
242 |
243 | // Return the letters if they arent empty
244 | result.append(l1)
245 |
246 | if l2 != 0 {
247 | result.append(l2)
248 | }
249 |
250 | if l3 != 0 {
251 | result.append(l3)
252 | }
253 |
254 | }
255 |
256 | return result
257 | }
258 |
259 | public static func decodeString(str: String) -> String {
260 |
261 | // Get the ascii representation and return
262 | let data = str.data(using: .ascii)!
263 |
264 | let decData = decode(data: [UInt8](data))
265 |
266 | let retStr = String(data: Data(decData), encoding: .ascii)!
267 |
268 | return retStr
269 | }
270 | }
271 |
272 |
273 |
274 |
275 |
--------------------------------------------------------------------------------
/thunderPassby.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | CE3F8A0020BD6CC7007011F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3F89FF20BD6CC7007011F2 /* AppDelegate.swift */; };
11 | CE3F8A0220BD6CC7007011F2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3F8A0120BD6CC7007011F2 /* ViewController.swift */; };
12 | CE3F8A0420BD6CCA007011F2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE3F8A0320BD6CCA007011F2 /* Assets.xcassets */; };
13 | CE3F8A0720BD6CCA007011F2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE3F8A0520BD6CCA007011F2 /* Main.storyboard */; };
14 | CE3F8A1020BD6FAE007011F2 /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3F8A0F20BD6FAE007011F2 /* WindowController.swift */; };
15 | CE3F8A1420BE8922007011F2 /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3F8A1320BE8922007011F2 /* Base64FS.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | CE3F89FC20BD6CC7007011F2 /* thunderPassby.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = thunderPassby.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | CE3F89FF20BD6CC7007011F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | CE3F8A0120BD6CC7007011F2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
22 | CE3F8A0320BD6CCA007011F2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | CE3F8A0620BD6CCA007011F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
24 | CE3F8A0820BD6CCA007011F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
25 | CE3F8A0920BD6CCA007011F2 /* thunderPassby.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = thunderPassby.entitlements; sourceTree = ""; };
26 | CE3F8A0F20BD6FAE007011F2 /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = ""; };
27 | CE3F8A1320BE8922007011F2 /* Base64FS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64FS.swift; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | CE3F89F920BD6CC7007011F2 /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | CE3F89F320BD6CC6007011F2 = {
42 | isa = PBXGroup;
43 | children = (
44 | CE3F89FE20BD6CC7007011F2 /* thunderPassby */,
45 | CE3F89FD20BD6CC7007011F2 /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | CE3F89FD20BD6CC7007011F2 /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | CE3F89FC20BD6CC7007011F2 /* thunderPassby.app */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | CE3F89FE20BD6CC7007011F2 /* thunderPassby */ = {
58 | isa = PBXGroup;
59 | children = (
60 | CE3F8A1320BE8922007011F2 /* Base64FS.swift */,
61 | CE3F89FF20BD6CC7007011F2 /* AppDelegate.swift */,
62 | CE3F8A0120BD6CC7007011F2 /* ViewController.swift */,
63 | CE3F8A0320BD6CCA007011F2 /* Assets.xcassets */,
64 | CE3F8A0520BD6CCA007011F2 /* Main.storyboard */,
65 | CE3F8A0820BD6CCA007011F2 /* Info.plist */,
66 | CE3F8A0920BD6CCA007011F2 /* thunderPassby.entitlements */,
67 | CE3F8A0F20BD6FAE007011F2 /* WindowController.swift */,
68 | );
69 | path = thunderPassby;
70 | sourceTree = "";
71 | };
72 | /* End PBXGroup section */
73 |
74 | /* Begin PBXNativeTarget section */
75 | CE3F89FB20BD6CC7007011F2 /* thunderPassby */ = {
76 | isa = PBXNativeTarget;
77 | buildConfigurationList = CE3F8A0C20BD6CCA007011F2 /* Build configuration list for PBXNativeTarget "thunderPassby" */;
78 | buildPhases = (
79 | CE3F89F820BD6CC7007011F2 /* Sources */,
80 | CE3F89F920BD6CC7007011F2 /* Frameworks */,
81 | CE3F89FA20BD6CC7007011F2 /* Resources */,
82 | );
83 | buildRules = (
84 | );
85 | dependencies = (
86 | );
87 | name = thunderPassby;
88 | productName = thunderPassby;
89 | productReference = CE3F89FC20BD6CC7007011F2 /* thunderPassby.app */;
90 | productType = "com.apple.product-type.application";
91 | };
92 | /* End PBXNativeTarget section */
93 |
94 | /* Begin PBXProject section */
95 | CE3F89F420BD6CC6007011F2 /* Project object */ = {
96 | isa = PBXProject;
97 | attributes = {
98 | LastSwiftUpdateCheck = 0930;
99 | LastUpgradeCheck = 0930;
100 | ORGANIZATIONNAME = "Chih-Hao";
101 | TargetAttributes = {
102 | CE3F89FB20BD6CC7007011F2 = {
103 | CreatedOnToolsVersion = 9.3;
104 | };
105 | };
106 | };
107 | buildConfigurationList = CE3F89F720BD6CC7007011F2 /* Build configuration list for PBXProject "thunderPassby" */;
108 | compatibilityVersion = "Xcode 9.3";
109 | developmentRegion = en;
110 | hasScannedForEncodings = 0;
111 | knownRegions = (
112 | en,
113 | Base,
114 | );
115 | mainGroup = CE3F89F320BD6CC6007011F2;
116 | productRefGroup = CE3F89FD20BD6CC7007011F2 /* Products */;
117 | projectDirPath = "";
118 | projectRoot = "";
119 | targets = (
120 | CE3F89FB20BD6CC7007011F2 /* thunderPassby */,
121 | );
122 | };
123 | /* End PBXProject section */
124 |
125 | /* Begin PBXResourcesBuildPhase section */
126 | CE3F89FA20BD6CC7007011F2 /* Resources */ = {
127 | isa = PBXResourcesBuildPhase;
128 | buildActionMask = 2147483647;
129 | files = (
130 | CE3F8A0420BD6CCA007011F2 /* Assets.xcassets in Resources */,
131 | CE3F8A0720BD6CCA007011F2 /* Main.storyboard in Resources */,
132 | );
133 | runOnlyForDeploymentPostprocessing = 0;
134 | };
135 | /* End PBXResourcesBuildPhase section */
136 |
137 | /* Begin PBXSourcesBuildPhase section */
138 | CE3F89F820BD6CC7007011F2 /* Sources */ = {
139 | isa = PBXSourcesBuildPhase;
140 | buildActionMask = 2147483647;
141 | files = (
142 | CE3F8A0220BD6CC7007011F2 /* ViewController.swift in Sources */,
143 | CE3F8A1020BD6FAE007011F2 /* WindowController.swift in Sources */,
144 | CE3F8A0020BD6CC7007011F2 /* AppDelegate.swift in Sources */,
145 | CE3F8A1420BE8922007011F2 /* Base64FS.swift in Sources */,
146 | );
147 | runOnlyForDeploymentPostprocessing = 0;
148 | };
149 | /* End PBXSourcesBuildPhase section */
150 |
151 | /* Begin PBXVariantGroup section */
152 | CE3F8A0520BD6CCA007011F2 /* Main.storyboard */ = {
153 | isa = PBXVariantGroup;
154 | children = (
155 | CE3F8A0620BD6CCA007011F2 /* Base */,
156 | );
157 | name = Main.storyboard;
158 | sourceTree = "";
159 | };
160 | /* End PBXVariantGroup section */
161 |
162 | /* Begin XCBuildConfiguration section */
163 | CE3F8A0A20BD6CCA007011F2 /* Debug */ = {
164 | isa = XCBuildConfiguration;
165 | buildSettings = {
166 | ALWAYS_SEARCH_USER_PATHS = NO;
167 | CLANG_ANALYZER_NONNULL = YES;
168 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
169 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
170 | CLANG_CXX_LIBRARY = "libc++";
171 | CLANG_ENABLE_MODULES = YES;
172 | CLANG_ENABLE_OBJC_ARC = YES;
173 | CLANG_ENABLE_OBJC_WEAK = YES;
174 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
175 | CLANG_WARN_BOOL_CONVERSION = YES;
176 | CLANG_WARN_COMMA = YES;
177 | CLANG_WARN_CONSTANT_CONVERSION = YES;
178 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
179 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181 | CLANG_WARN_EMPTY_BODY = YES;
182 | CLANG_WARN_ENUM_CONVERSION = YES;
183 | CLANG_WARN_INFINITE_RECURSION = YES;
184 | CLANG_WARN_INT_CONVERSION = YES;
185 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
186 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
187 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
189 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
190 | CLANG_WARN_STRICT_PROTOTYPES = YES;
191 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
192 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
193 | CLANG_WARN_UNREACHABLE_CODE = YES;
194 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
195 | CODE_SIGN_IDENTITY = "Mac Developer";
196 | COPY_PHASE_STRIP = NO;
197 | DEBUG_INFORMATION_FORMAT = dwarf;
198 | ENABLE_STRICT_OBJC_MSGSEND = YES;
199 | ENABLE_TESTABILITY = YES;
200 | GCC_C_LANGUAGE_STANDARD = gnu11;
201 | GCC_DYNAMIC_NO_PIC = NO;
202 | GCC_NO_COMMON_BLOCKS = YES;
203 | GCC_OPTIMIZATION_LEVEL = 0;
204 | GCC_PREPROCESSOR_DEFINITIONS = (
205 | "DEBUG=1",
206 | "$(inherited)",
207 | );
208 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
209 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
210 | GCC_WARN_UNDECLARED_SELECTOR = YES;
211 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
212 | GCC_WARN_UNUSED_FUNCTION = YES;
213 | GCC_WARN_UNUSED_VARIABLE = YES;
214 | MACOSX_DEPLOYMENT_TARGET = 10.13;
215 | MTL_ENABLE_DEBUG_INFO = YES;
216 | ONLY_ACTIVE_ARCH = YES;
217 | SDKROOT = macosx;
218 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
219 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
220 | };
221 | name = Debug;
222 | };
223 | CE3F8A0B20BD6CCA007011F2 /* Release */ = {
224 | isa = XCBuildConfiguration;
225 | buildSettings = {
226 | ALWAYS_SEARCH_USER_PATHS = NO;
227 | CLANG_ANALYZER_NONNULL = YES;
228 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
230 | CLANG_CXX_LIBRARY = "libc++";
231 | CLANG_ENABLE_MODULES = YES;
232 | CLANG_ENABLE_OBJC_ARC = YES;
233 | CLANG_ENABLE_OBJC_WEAK = YES;
234 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
235 | CLANG_WARN_BOOL_CONVERSION = YES;
236 | CLANG_WARN_COMMA = YES;
237 | CLANG_WARN_CONSTANT_CONVERSION = YES;
238 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
239 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
240 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
241 | CLANG_WARN_EMPTY_BODY = YES;
242 | CLANG_WARN_ENUM_CONVERSION = YES;
243 | CLANG_WARN_INFINITE_RECURSION = YES;
244 | CLANG_WARN_INT_CONVERSION = YES;
245 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
246 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
247 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
248 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
249 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
250 | CLANG_WARN_STRICT_PROTOTYPES = YES;
251 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
252 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
253 | CLANG_WARN_UNREACHABLE_CODE = YES;
254 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
255 | CODE_SIGN_IDENTITY = "Mac Developer";
256 | COPY_PHASE_STRIP = NO;
257 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
258 | ENABLE_NS_ASSERTIONS = NO;
259 | ENABLE_STRICT_OBJC_MSGSEND = YES;
260 | GCC_C_LANGUAGE_STANDARD = gnu11;
261 | GCC_NO_COMMON_BLOCKS = YES;
262 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
263 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
264 | GCC_WARN_UNDECLARED_SELECTOR = YES;
265 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
266 | GCC_WARN_UNUSED_FUNCTION = YES;
267 | GCC_WARN_UNUSED_VARIABLE = YES;
268 | MACOSX_DEPLOYMENT_TARGET = 10.13;
269 | MTL_ENABLE_DEBUG_INFO = NO;
270 | SDKROOT = macosx;
271 | SWIFT_COMPILATION_MODE = wholemodule;
272 | SWIFT_OPTIMIZATION_LEVEL = "-O";
273 | };
274 | name = Release;
275 | };
276 | CE3F8A0D20BD6CCA007011F2 /* Debug */ = {
277 | isa = XCBuildConfiguration;
278 | buildSettings = {
279 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
280 | CODE_SIGN_ENTITLEMENTS = thunderPassby/thunderPassby.entitlements;
281 | CODE_SIGN_STYLE = Automatic;
282 | COMBINE_HIDPI_IMAGES = YES;
283 | DEVELOPMENT_TEAM = 2JY6F4ZP47;
284 | INFOPLIST_FILE = thunderPassby/Info.plist;
285 | LD_RUNPATH_SEARCH_PATHS = (
286 | "$(inherited)",
287 | "@executable_path/../Frameworks",
288 | );
289 | MACOSX_DEPLOYMENT_TARGET = 10.10;
290 | PRODUCT_BUNDLE_IDENTIFIER = zhihao.fudan.thunderPassby;
291 | PRODUCT_NAME = "$(TARGET_NAME)";
292 | SWIFT_VERSION = 4.0;
293 | };
294 | name = Debug;
295 | };
296 | CE3F8A0E20BD6CCA007011F2 /* Release */ = {
297 | isa = XCBuildConfiguration;
298 | buildSettings = {
299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
300 | CODE_SIGN_ENTITLEMENTS = thunderPassby/thunderPassby.entitlements;
301 | CODE_SIGN_STYLE = Automatic;
302 | COMBINE_HIDPI_IMAGES = YES;
303 | DEVELOPMENT_TEAM = 2JY6F4ZP47;
304 | INFOPLIST_FILE = thunderPassby/Info.plist;
305 | LD_RUNPATH_SEARCH_PATHS = (
306 | "$(inherited)",
307 | "@executable_path/../Frameworks",
308 | );
309 | MACOSX_DEPLOYMENT_TARGET = 10.10;
310 | PRODUCT_BUNDLE_IDENTIFIER = zhihao.fudan.thunderPassby;
311 | PRODUCT_NAME = "$(TARGET_NAME)";
312 | SWIFT_VERSION = 4.0;
313 | };
314 | name = Release;
315 | };
316 | /* End XCBuildConfiguration section */
317 |
318 | /* Begin XCConfigurationList section */
319 | CE3F89F720BD6CC7007011F2 /* Build configuration list for PBXProject "thunderPassby" */ = {
320 | isa = XCConfigurationList;
321 | buildConfigurations = (
322 | CE3F8A0A20BD6CCA007011F2 /* Debug */,
323 | CE3F8A0B20BD6CCA007011F2 /* Release */,
324 | );
325 | defaultConfigurationIsVisible = 0;
326 | defaultConfigurationName = Release;
327 | };
328 | CE3F8A0C20BD6CCA007011F2 /* Build configuration list for PBXNativeTarget "thunderPassby" */ = {
329 | isa = XCConfigurationList;
330 | buildConfigurations = (
331 | CE3F8A0D20BD6CCA007011F2 /* Debug */,
332 | CE3F8A0E20BD6CCA007011F2 /* Release */,
333 | );
334 | defaultConfigurationIsVisible = 0;
335 | defaultConfigurationName = Release;
336 | };
337 | /* End XCConfigurationList section */
338 | };
339 | rootObject = CE3F89F420BD6CC6007011F2 /* Project object */;
340 | }
341 |
--------------------------------------------------------------------------------
/thunderPassby/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
--------------------------------------------------------------------------------