aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift
diff options
context:
space:
mode:
authorEric Kuck <eric@bluelinelabs.com>2018-08-21 11:00:41 -0500
committerRoopesh Chander <roop@roopc.net>2018-10-28 18:26:41 +0530
commit3082863fd193f82127da9379462e6b972141621f (patch)
treed6c60627f39b4be172abcacf1dfbb12ea8cdbccb /WireGuard/WireGuard/UI/iOS/QRScanViewController.swift
parentModel: Ensure name is not empty (diff)
downloadwireguard-apple-3082863fd193f82127da9379462e6b972141621f.tar.xz
wireguard-apple-3082863fd193f82127da9379462e6b972141621f.zip
QR code: Ability to add tunnels with a QR code scan
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
Diffstat (limited to 'WireGuard/WireGuard/UI/iOS/QRScanViewController.swift')
-rw-r--r--WireGuard/WireGuard/UI/iOS/QRScanViewController.swift107
1 files changed, 107 insertions, 0 deletions
diff --git a/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift
new file mode 100644
index 0000000..f15d30b
--- /dev/null
+++ b/WireGuard/WireGuard/UI/iOS/QRScanViewController.swift
@@ -0,0 +1,107 @@
+//
+// QRScanViewController.swift
+// WireGuard
+//
+// Created by Eric Kuck on 8/20/18.
+// Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All rights reserved.
+//
+
+import AVFoundation
+import CoreData
+import UIKit
+
+protocol QRScanViewControllerDelegate: class {
+ func didSave(tunnel: Tunnel, qrScanViewController: QRScanViewController)
+}
+
+class QRScanViewController: UIViewController {
+
+ private var viewContext: NSManagedObjectContext!
+ private weak var delegate: QRScanViewControllerDelegate?
+ var captureSession: AVCaptureSession? = AVCaptureSession()
+ let metadataOutput = AVCaptureMetadataOutput()
+ var previewLayer: AVCaptureVideoPreviewLayer!
+
+ func configure(context: NSManagedObjectContext, delegate: QRScanViewControllerDelegate? = nil) {
+ viewContext = context
+ self.delegate = delegate
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ guard let videoCaptureDevice = AVCaptureDevice.default(for: .video),
+ let videoInput = try? AVCaptureDeviceInput(device: videoCaptureDevice),
+ let captureSession = captureSession,
+ captureSession.canAddInput(videoInput),
+ captureSession.canAddOutput(metadataOutput) else {
+ scanDidEncounterError(title: "Scanning Not Supported", message: "This device does not have the ability to scan QR codes.")
+ return
+ }
+
+ captureSession.addInput(videoInput)
+ captureSession.addOutput(metadataOutput)
+
+ metadataOutput.setMetadataObjectsDelegate(self, queue: .main)
+ metadataOutput.metadataObjectTypes = [.qr]
+
+ previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
+ previewLayer.frame = view.layer.bounds
+ previewLayer.videoGravity = .resizeAspectFill
+ view.layer.addSublayer(previewLayer)
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+
+ if captureSession?.isRunning == false {
+ captureSession?.startRunning()
+ }
+ }
+
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+
+ if captureSession?.isRunning == true {
+ captureSession?.stopRunning()
+ }
+ }
+
+ func scanDidComplete(withCode code: String) {
+ do {
+ let tunnel = try Tunnel.fromConfig(code, context: viewContext)
+ delegate?.didSave(tunnel: tunnel, qrScanViewController: self)
+ } catch {
+ scanDidEncounterError(title: "Invalid Code", message: "The scanned code is not a valid WireGuard config file.")
+ }
+ }
+
+ func scanDidEncounterError(title: String, message: String) {
+ let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
+ alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self] _ in
+ self?.navigationController?.popViewController(animated: true)
+ }))
+ present(alertController, animated: true)
+ captureSession = nil
+ }
+
+}
+
+extension QRScanViewController: AVCaptureMetadataOutputObjectsDelegate {
+ func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
+ captureSession?.stopRunning()
+
+ guard let metadataObject = metadataObjects.first,
+ let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject,
+ let stringValue = readableObject.stringValue else {
+ scanDidEncounterError(title: "Invalid Code", message: "The scanned code could not be read.")
+ return
+ }
+
+ AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
+ scanDidComplete(withCode: stringValue)
+ }
+
+}
+
+extension QRScanViewController: Identifyable {}