最近运维同窗为了提升安全性,用Google Authenticator对服务器加了双重认证,此后登陆服务器须要先输入动态密码,在输入服务器密码。Google Authenticator至关于软token,对他不了解的同窗能够看下这篇文章:谷歌验证 (Google Authenticator) 的实现原理是什么?。git
运维同窗的出发点是好的,可是我原来写的各类自动登陆服务器的脚本通通失效了。蛋疼的是我如今登陆服务器的流程变成了:github
本来我只执行本身搞的一个命令就完事了,因为我常常须要登陆各类不一样的服务器,这种方式对工做效率的影响是可想而知的。算法
目前Google官方的客户端只有Android和iOS的,因而开始找找看有没有针对PC,发现有个针对Windows系统的WinAuth支持Google Authenticator,我不管工做、在家基本都用Mac,因此这个WinAuth我是无法用了,后来在GitHub上找到一个MacAuthenticator的工具,下载下来试用了一下基本能用,至少Mac端能够获得Verification Code不须要依赖手机了,可是依然解决不了效率问题,并且那个工具竟然无法退出...shell
没个顺手的工具,看来还得我亲手开发个了,因而简单了设计了下我须要的功能:swift
GitHub上已经有个MacAuthenticator开源项目了(基于OC的),因此技术实现上应该没什么障碍。安全
语言方面,由于14年的时候参与过《The Swift Programming Language》翻译(如今已经成为苹果官方指定的中文版本了),可是还历来没用过Swift,因此决定采用Swift开发,就当学习了。服务器
otp协议方面,Google开源了其算法:google-authenticator,恰好也有个iOS版本的,是基于OC的,不过给Swift调用没啥问题,因此核心协议的处理直接拿来用就能够了。框架
如何将生成的Verification Code给其余应用调用?想来想去仍是基于HTTP的调用起来比较简单,因此还须要实现一个内嵌的HTTP服务器,到cocoapods上找了下,发现Swifter比较适合。运维
macOS上的Application我确实是第一次接触,不过在Windows平台上开发过很多桌面类的应用,这块边学边作感受问题不大(实际作的时候发现各类踩坑),在网上找了些快速入门的资料,发现一个很是棒的资料推荐一下:WeatherBarcurl
GoldenPassport已经放到GitHub上了,项目主页有一个简单的使用说明,我这里就不介绍具体功能了,基本照着个人需求实现的。
几乎全部功能都在这个菜单里搞定了:
从二维码中识别OTP地址,没有二维码,本身手动输入也能够:
和Shell脚本集成,全靠这个HTTP接口啦:
# you can get the url from `http://localhost:17304/` code=$(curl 'http://localhost:17304/code/test@stanzhai.site') # ues the verification code echo $code
开发过程当中,踩了不少坑,遇到很多难点(主要是可参考的资料少),我这里简单的梳理下,对源码感兴趣的同窗,直接去GitHub上Fork吧。
let data = OTPAuthURL.base32Decode(otpData.secret) let gen = TOTPGenerator(secret: data, algorithm: TOTPGenerator.defaultAlgorithm(), digits: TOTPGenerator.defaultDigits(), period: TOTPGenerator.defaultPeriod()) let code = gen?.generateOTP(for: Date()) // 这个code就是最终的结果啦
若是你的statusIcon是个18*18的png,参照网上的例子去弄的话,你会发现状态栏图标至关模糊,远不如系统自带的清晰,若是你用的png是个比较大的图片,你会发现状态栏中根本显示不下,解决这个问题的关键点是须要指定图片的大小。
statusIcon = NSImage(named: "statusIcon") // 48 * 48的大小就能够了 statusIcon.size = NSMakeSize(20, 20) // 这是保证高清又能正常显示的关键
获取到系统状态栏按钮对象后,我须要绑定下点击事件,来显示菜单,折腾了许久才搞定,主要卡在action这个地方,网上关于这方面的资料是至关少,在Swift3中,咱们建立一个Selector的正确姿式是#selector(方法名)
同时必须指定statusItem.target = self
才行。
statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength) statusItem.target = self statusItem.action = #selector(openMenu)
这方面的资料真的好少~
let opts = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionary guard AXIsProcessTrustedWithOptions(opts) == true else { return } monitor = NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: self.handleKeydownEvent)
httpPortConfigWindow.showWindow(nil) httpPortConfigWindow.window?.makeKeyAndOrderFront(nil) httpPortConfigWindow.window?.center() NSApp.activate(ignoringOtherApps: true)
Foundation库为咱们提供了一个基于观察者模式的NotificationCenter
,用起来至关方便。
// 组件A监听消息 let notificationCenter = NotificationCenter.default notificationCenter.addObserver(self, selector: #selector(verifyCodeAdded), name: NSNotification.Name(rawValue: "VerifyKeyAdded"), object: nil) // 组件B发送消息 let notificationCenter = NotificationCenter.default notificationCenter.post(name: NSNotification.Name(rawValue: "VerifyKeyAdded"), object: nil)
let pasteboard = NSPasteboard.general() pasteboard.clearContents() pasteboard.setString(codeInfo.value, forType: NSStringPboardType)
let openPanel = NSOpenPanel() openPanel.allowedFileTypes = NSImage.imageTypes()
网上大部分都是iOS扫二维码的示例,OSX下从文件中识别的方法,摸索了好一阵子才实现。
let ciImage = CIImage(contentsOf: openPanel.url!) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow]) let results = detector?.features(in: ciImage!) if (results?.count)! > 0 { let qrFeature = results?.last as! CIQRCodeFeature let data = qrFeature.messageString // 识别后的数据 ... }
GoldenPassport是我开发的第一个macOS Application,对桌面应用的开发流程算是清楚了,搞个窗口类的应用已无大碍。和Windows的桌面应用开发体验相比,感受OSX的仍是差了很多,这也跟本身不熟悉OSX有关吧。
踩了很多Swift语法的坑,如今用的是Swift3,网上找的一些资料不必定是针对Swift3的代码,拿过来不必定用,Swift的这种兼容性问题仍是挺让人讨厌的。Swift4也快要出来了,依然有兼容性问题。
因为对Cocoa框架不熟悉,很多NSXXX的API不知道咋用,另外NS的很多API在Swift下用法变掉了,多亏了GitHub,经过GitHub的代码搜索功能,能够找到不少别人项目里的示例代码,在结合Swift的语法,开发过程当中碰到的一些功能性问题基本都能解决。
熟悉了Xcode的项目依赖管理工具:cocoapods和Swift Package Manager,对于子子孙孙无穷尽也的项目依赖,熟悉下项目依赖管理工具仍是很是有必要的。在GoldenPassport项目由于Swift Package Manager不支持混合语言的项目依赖管理,因此就用了cocoapods来管理项目依赖了。
GoldenPassport的核心功能是我利用周末整整2天多时间折腾出来的,有种参加黑马的感受,逼着本身作本身不熟悉的东西,现学现作,看看短期内到底能作成什么样,搞完那一刻成就感满满。
源码地址:GoldenPassport,欢迎Star。
编译好的工具能够到GitHub的releases中下载,若是这个工具能帮助到其余人,那就再好不过了。
引入Google Authenticator,致使效率变差的问题得以完美解决,我原来的自动化脚本也能正常使用了,这个项目算是告一段了。回过神,该继续研究大数据的东西去了 )逃...