From cc26734d5d1d7198c2d68b0cc29399f3cf2f010a Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Tue, 23 Oct 2018 23:22:14 +0530 Subject: [PATCH] Prepare for rewrite: Remove UI and model code Signed-off-by: Roopesh Chander --- WireGuard/AppDelegate.swift | 57 - .../AppIcon.appiconset/Contents.json | 116 -- .../AppIcon.appiconset/Icon.png | Bin 68333 -> 0 bytes .../AppIcon.appiconset/icon_20pt.png | Bin 740 -> 0 bytes .../AppIcon.appiconset/icon_20pt@2x-1.png | Bin 1551 -> 0 bytes .../AppIcon.appiconset/icon_20pt@2x.png | Bin 1551 -> 0 bytes .../AppIcon.appiconset/icon_20pt@3x.png | Bin 2328 -> 0 bytes .../AppIcon.appiconset/icon_29pt.png | Bin 1088 -> 0 bytes .../AppIcon.appiconset/icon_29pt@2x-1.png | Bin 2236 -> 0 bytes .../AppIcon.appiconset/icon_29pt@2x.png | Bin 2223 -> 0 bytes .../AppIcon.appiconset/icon_29pt@3x.png | Bin 3472 -> 0 bytes .../AppIcon.appiconset/icon_40pt.png | Bin 1551 -> 0 bytes .../AppIcon.appiconset/icon_40pt@2x-1.png | Bin 3156 -> 0 bytes .../AppIcon.appiconset/icon_40pt@2x.png | Bin 3135 -> 0 bytes .../AppIcon.appiconset/icon_40pt@3x.png | Bin 4839 -> 0 bytes .../AppIcon.appiconset/icon_60pt@2x.png | Bin 4839 -> 0 bytes .../AppIcon.appiconset/icon_60pt@3x.png | Bin 7744 -> 0 bytes .../AppIcon.appiconset/icon_76pt.png | Bin 2996 -> 0 bytes .../AppIcon.appiconset/icon_76pt@2x.png | Bin 6398 -> 0 bytes .../AppIcon.appiconset/icon_83.5@2x.png | Bin 7101 -> 0 bytes .../Assets.xcassets/Arrow.imageset/Arrow.pdf | Bin 8558 -> 0 bytes .../Arrow.imageset/Contents.json | 15 - WireGuard/Assets.xcassets/Contents.json | 6 - .../settings.imageset/Contents.json | 15 - .../settings.imageset/Dots.pdf | Bin 4016 -> 0 bytes .../trash.imageset/Contents.json | 23 - .../trash.imageset/ic_action_delete.png | Bin 178 -> 0 bytes .../trash.imageset/ic_action_delete@2x.png | Bin 289 -> 0 bytes .../trash.imageset/ic_action_delete@3x.png | Bin 407 -> 0 bytes .../wireguard.imageset/Contents.json | 15 - .../wireguard.imageset/wireguard.pdf | Bin 15345 -> 0 bytes WireGuard/Base.lproj/LaunchScreen.storyboard | 47 - WireGuard/Base.lproj/Main.storyboard | 1010 ----------------- ...dinator+QRScanViewControllerDelegate.swift | 17 - ...+SettingsTableViewControllerDelegate.swift | 18 - ...igurationTableViewControllerDelegate.swift | 11 - ...unnelInfoTableViewControllerDelegate.swift | 32 - ...r+TunnelsTableViewControllerDelegate.swift | 114 -- WireGuard/Coordinators/AppCoordinator.swift | 468 -------- WireGuard/Coordinators/Coordinator.swift | 30 - WireGuard/Coordinators/RootCoordinator.swift | 15 - WireGuard/Crypto/x25519.c | 177 --- WireGuard/Crypto/x25519.h | 7 - WireGuard/CustomViews/CopyableLabel.swift | 40 - WireGuard/Extensions/String+Arrays.swift | 20 - WireGuard/Extensions/String+Base64.swift | 14 - WireGuard/Info.plist | 173 --- WireGuard/Log.swift | 9 - WireGuard/Models/Attribute.swift | 40 - .../Models/Interface+CoreDataClass.swift | 11 - .../Models/Interface+CoreDataProperties.swift | 25 - WireGuard/Models/Interface+Extension.swift | 100 -- WireGuard/Models/Peer+CoreDataClass.swift | 11 - .../Models/Peer+CoreDataProperties.swift | 21 - WireGuard/Models/Peer+Extension.swift | 94 -- WireGuard/Models/Tunnel+CoreDataClass.swift | 11 - .../Models/Tunnel+CoreDataProperties.swift | 54 - WireGuard/Models/Tunnel+Extension.swift | 212 ---- .../WireGuard.xcdatamodel/contents | 30 - WireGuard/ViewControllers/Identifyable.swift | 23 - .../QRScanViewController.swift | 152 --- .../SetttingsTableViewController.swift | 77 -- ...nnelConfigurationTableViewController.swift | 300 ----- .../TunnelInfoTableViewController.swift | 194 ---- .../TunnelsTableViewController.swift | 308 ----- .../UITableView+WireGuard.swift | 32 - WireGuard/WireGuard-Bridging-Header.h | 6 - WireGuard/WireGuard.entitlements | 18 - WireGuardTests/Info.plist | 22 - WireGuardTests/ValidatorsTests.swift | 189 --- 70 files changed, 4379 deletions(-) delete mode 100644 WireGuard/AppDelegate.swift delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/Icon.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x-1.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x-1.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_76pt.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png delete mode 100644 WireGuard/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png delete mode 100644 WireGuard/Assets.xcassets/Arrow.imageset/Arrow.pdf delete mode 100644 WireGuard/Assets.xcassets/Arrow.imageset/Contents.json delete mode 100644 WireGuard/Assets.xcassets/Contents.json delete mode 100644 WireGuard/Assets.xcassets/settings.imageset/Contents.json delete mode 100644 WireGuard/Assets.xcassets/settings.imageset/Dots.pdf delete mode 100644 WireGuard/Assets.xcassets/trash.imageset/Contents.json delete mode 100644 WireGuard/Assets.xcassets/trash.imageset/ic_action_delete.png delete mode 100644 WireGuard/Assets.xcassets/trash.imageset/ic_action_delete@2x.png delete mode 100644 WireGuard/Assets.xcassets/trash.imageset/ic_action_delete@3x.png delete mode 100644 WireGuard/Assets.xcassets/wireguard.imageset/Contents.json delete mode 100644 WireGuard/Assets.xcassets/wireguard.imageset/wireguard.pdf delete mode 100644 WireGuard/Base.lproj/LaunchScreen.storyboard delete mode 100644 WireGuard/Base.lproj/Main.storyboard delete mode 100644 WireGuard/Coordinators/AppCoordinator+QRScanViewControllerDelegate.swift delete mode 100644 WireGuard/Coordinators/AppCoordinator+SettingsTableViewControllerDelegate.swift delete mode 100644 WireGuard/Coordinators/AppCoordinator+TunnelConfigurationTableViewControllerDelegate.swift delete mode 100644 WireGuard/Coordinators/AppCoordinator+TunnelInfoTableViewControllerDelegate.swift delete mode 100644 WireGuard/Coordinators/AppCoordinator+TunnelsTableViewControllerDelegate.swift delete mode 100644 WireGuard/Coordinators/AppCoordinator.swift delete mode 100644 WireGuard/Coordinators/Coordinator.swift delete mode 100644 WireGuard/Coordinators/RootCoordinator.swift delete mode 100644 WireGuard/Crypto/x25519.c delete mode 100644 WireGuard/Crypto/x25519.h delete mode 100644 WireGuard/CustomViews/CopyableLabel.swift delete mode 100644 WireGuard/Extensions/String+Arrays.swift delete mode 100644 WireGuard/Extensions/String+Base64.swift delete mode 100644 WireGuard/Info.plist delete mode 100644 WireGuard/Log.swift delete mode 100644 WireGuard/Models/Attribute.swift delete mode 100644 WireGuard/Models/Interface+CoreDataClass.swift delete mode 100644 WireGuard/Models/Interface+CoreDataProperties.swift delete mode 100644 WireGuard/Models/Interface+Extension.swift delete mode 100644 WireGuard/Models/Peer+CoreDataClass.swift delete mode 100644 WireGuard/Models/Peer+CoreDataProperties.swift delete mode 100644 WireGuard/Models/Peer+Extension.swift delete mode 100644 WireGuard/Models/Tunnel+CoreDataClass.swift delete mode 100644 WireGuard/Models/Tunnel+CoreDataProperties.swift delete mode 100644 WireGuard/Models/Tunnel+Extension.swift delete mode 100644 WireGuard/Models/WireGuard.xcdatamodeld/WireGuard.xcdatamodel/contents delete mode 100644 WireGuard/ViewControllers/Identifyable.swift delete mode 100644 WireGuard/ViewControllers/QRScanViewController.swift delete mode 100644 WireGuard/ViewControllers/SetttingsTableViewController.swift delete mode 100644 WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift delete mode 100644 WireGuard/ViewControllers/TunnelInfoTableViewController.swift delete mode 100644 WireGuard/ViewControllers/TunnelsTableViewController.swift delete mode 100644 WireGuard/ViewControllers/UITableView+WireGuard.swift delete mode 100644 WireGuard/WireGuard-Bridging-Header.h delete mode 100644 WireGuard/WireGuard.entitlements delete mode 100644 WireGuardTests/Info.plist delete mode 100644 WireGuardTests/ValidatorsTests.swift diff --git a/WireGuard/AppDelegate.swift b/WireGuard/AppDelegate.swift deleted file mode 100644 index 6380636..0000000 --- a/WireGuard/AppDelegate.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import os.log - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - var appCoordinator: AppCoordinator! - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - - self.window = UIWindow(frame: UIScreen.main.bounds) - appCoordinator = AppCoordinator(window: self.window!) - appCoordinator.start() - - appCoordinator.checkAndCleanConfigs() - - return true - } - - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { - defer { - do { - try FileManager.default.removeItem(at: url) - } catch { - os_log("Failed to remove item from Inbox: %{public}@", log: Log.general, type: .error, url.absoluteString) - } - } - if url.pathExtension == "conf" { - do { - try appCoordinator.importConfig(config: url) - } catch { - os_log("Unable to import config: %{public}@", log: Log.general, type: .error, url.absoluteString) - return false - } - return true - } else if url.pathExtension == "zip" { - do { - try appCoordinator.importConfigs(configZip: url) - } catch { - os_log("Unable to import config: %{public}@", log: Log.general, type: .error, url.absoluteString) - return false - } - return true - } - return false - - } - - func applicationWillEnterForeground(_ application: UIApplication) { - appCoordinator.checkAndCleanConfigs() - } -} diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/Contents.json b/WireGuard/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 29d9125..0000000 --- a/WireGuard/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "icon_20pt@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "icon_20pt@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "icon_29pt@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "icon_29pt@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "icon_40pt@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "icon_40pt@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "icon_60pt@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "icon_60pt@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "icon_20pt.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "icon_20pt@2x-1.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "icon_29pt.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "icon_29pt@2x-1.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "icon_40pt.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "icon_40pt@2x-1.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "icon_76pt.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "icon_76pt@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "icon_83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/Icon.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/Icon.png deleted file mode 100644 index 7b0779f14f7edd137b25e7bd099acf6874419a4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68333 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�v8*2yvU02M9O zj$Pu-90xe{Rr&}{Nw4;jt5W2yTIlv0aLu2!DKOHx{&xp13yI;CKfh}1&rCtle+){N z&h;(?Xe36NGTnar8Q$MGzTImYp?k;mCJIu!LlgrEi z_);zL(ecV-ad)Y@TW(CJ7sIhPE+|ofG%*@jis>CqFl@n_EDJTnXqKbdECWwqdl<2q zC5hnsGWO33bHn-s61{RD27w|F(qpA*{wVG5G_4PVG zkP3|DYb~umwP;qqYaCu^5}~TD7CmX^p+;4|aqAd9Y}r%r{%&j&iekn9&nY_f&LrE< zA2fZp0lEZ(Q$YpF>o*|4i`-8&3Uzp>*yt+yBTY?aXlms%YNhv8vnb|L@Ow~Ki4b;Pbpf&X6rE@qm~Hfm zD9(Tq^Htof^#|Yh?AV&5yMeL!K7T{oj<1`t7Eg+?k#|-B0l$b~Gv%b!z8aVgW}%SQ zew+vE@eh{=3uglhAGSy(puiI+jItY%xwW-Wq1{pty8Ab0Kp^}0`DZD+F3YPJW^TQ< z*_)F7>Vd0wOl_l>KK<5%6}2@c7SCC0yPRVnc}(Ey+-t&ckUB*{x6w`{^t4PbV_#oN zEhMm5e@c$qs@yTQb=;9!inF}=>YG7I7!wV{jiP|pWuH|;f}X0A*pU$a0*THy@I}|5 zQ9_k!jG+4Ca$A`yFMXb{zL@`Lu37w&vaQVL=PpiOQ`A>(M%nlrDgF5whl!wTe({XzdWfnl0b$=OS%wY-G9$*bj?C@ogQ?oDD^U4F3~rzO9aTgi z+6Q59<``OB{c<)-b#+{yyh~w}+5B^d-qeq`Bmz%2BqQRZqMjQPfsA{cQMdgk5scTU zKH74UVsb1CeA^x+xE%FQ6=p%v$0(@pr(-+R<@|!ICmO!F(B1^dxzaA6&zjo^8=wpQ6^~{DeIB;zTE&bOkwYBn|C`OwAcoqdg1pw(yMSGDvrLq zxU5K+@gSw5x|(iR7z)XEQ_6mvF|dOlQ@1_ep5j=)s!yvUB+s}RQ64PhGT&~e%2;|7 z3M_^K=MC~9a1ONK_naCzBAMZAgi($oy=lpRoAfc#6YeVgGc%QmyhVEnj+V_GhFuSP z-;UTw+Av#5g=pXN{P;BFE}nVmomKEjWzZ)Lx|5Q?%c(dfbNusX+&njyNT#d9za%EJ z9iFP2uSKf2#?gy!6osJ&3DNIP4tcKC-IaZO6=oH}Z3tr1f9*c?KBIbegjVX42PF46 zY%|cF%vlqp&Q%IX$=@%UrkLoiT7P0v|L|*%0O@Xe6YsX?!AIC_BWOe#Xz2jkelGX! z5~wkYPA01_#DY|!icH6mplXcOX|aVY?sV#QtD?G_{vWDNy=@}2cOLAvGsj&40hT?M zgika!s-xiGCBebx3A4%hp?UG!%KjXpa<7ar6xJ~<1vAEq<6k-3%sfe7A;eO;V_1R{ zVDePlGzY2lboWoHTq2Sq{!Cp~fH$r_EuP!DMbENVix-6hhEV$ORyvND@=) zTK(+AW`^>P z@582p3PLkrA>xpcHH$>D!ru~JE9^#~A6H5V);i3(IUn|OGT3VURD=9M``cen$D*9E zE|O)ILHlz)T;jYuVd|k08w2QQjzQX8moQ&zUL9%#aY6R~ zuggUN;SXD}{0v2BiwDXW-4xU}lJRI3?^u5%@V+H`qv3{8Q@nMEhYk}wOBX*(nEL1F z?v``Rd0!K$@CpsRmkmu-0c;#Xm{%ynFJ@8=%pccf#jp~cXzmU85_?qw`$HmdtmfR9 zvdIroe#F%FlwaxJNS1h~XA}huWaoo&zl=EXDL(p@Aaw1Sp-ua7I|2d6ka09!L}M@w z4+|66)%1j1gKE0OYyE)RXpQA>H*5O>Gj1ZHGc1)Ir-Qh=)f9ML*`Z;Q$5v0BcCQ*mSyNy5E(=en%nH1Q;PR7=)(m{W=flP^xdq znPxI|@Y^*aKJ2gSPw%-lB{>Y-G&VE!73QzcF$=S#iPrXMF2h6sOOu{8o1x7VdE8ijh2GfP4 z4l}NSv={S^TOoXKdsr4Rb1>L5HOS*EV#$O+%d^D{GlPRmUbMxHqT+4*Z@>G72Tx#E ze}SYLRG#ihQDM=X;Uu<95dNx1e&xeFj{;20Ne7Zz)Iy=}5oa4feJO!!HvUEy<|rT_ zU@^2}2JaP45>q$FeSgsQ3~iMZYXH0Z`;P1=!bB&K9Jv0UF!_~`0zG|(xu$fqJb^k5dU76+rvI3w<2_J`LeuF_Y^GD_alEmy;Rqi>B5ORui_GjX_m zZ}&$gF22&6D={^%r4od10B=KFAd&mvf}RUtNMRUIkt0&|t4}JhA%@bp<45)KSVs(R zWaiQMMUoSJWZj`YJ6@^roWWV4e|u&L`=H}S_RVMrHSV0MT!7wR`3t03oOo zRA6?|Y759trWjPjqq1X|6aS;+M12TPWFXfrF!zbs=EAh)3_Y<(9a|aDzmf`bg4yfHCq6+pofP`a_ z(flnELzDR*;={5d`?-bNQ+g? zl_Spt{Oz)HpPmTN#((rJw~ZOiZV15y=|qFBgyb2q-dJ3Od=lb>V(JbIOmGRk`K8Kv z?qL#y55K}o#tk{hL$t_$Z?dsJ(T#~q^cH+h7Kd#ele6@Qm!u-47TH(wD+>dEsKi}6?z&#duF4uYqj{@OL$z?6W|1vxdJ533SmS>I2 zM+85TM47GJ)_ODVP?wchZe3FfRPTv;@k^{MU1NX?0-bA+y>soKrINp$r>!PngDP-{ zFlo3Hf!s9<;IM>DazGO!s9K4Z8ZJ*vXVfGGGx{*l>@4)*)KrC1eZ;8F%cejUe-+Ly z>~KxKdL925>lQE)KIAsEi|_%Zp-8`;HFKX=K2SFSiuXbp)HN6IDJ_dT|iF+Rl9 zZ2$u)^uCj@{#r&R%`^1oNYtO_l8BIk-ts$NZu;~>VkYwkP#z@0^}`SCkMF#>h(anX zjPb=-UU~^L?ms-N^D>Fb$7L5Vr2A|)5am0DkNJ;i|3saxJQC@6AF~q90YK;i$gfd0 zszwm}WyfxzPI-K67FYQ6Uc7tdak{W_e{O&$c^M^!LI)HL!{3c z?#IPBG8i8y*!W$SZyt-QsK*54kl#}C*q?Y-n+2GS5Kn)cZVpWmQwJ=d)Lp#>Qs* zUR=V_)aLfA1F)!-8f^F+w|Akc8dM8opv!!&ietuq-T3{3eRBC%aAb_cbQ1z{jHVtd ze#=MjrHg?eYS*777}k0=`pB|ML~k zaib2;7OKXtK-KuU2Jbp2X$KLE+2gCd_}XQ5m<8dFglgh6HWp=1+nlx4-*w;S7<@h- z8XtlXpjd~wu##Mz|7Wt{!0pjbl_DrHx&ij*<0n-H0ueVcqBHS z#=>H}pld3FHNe}$tL$|fIc89l_dJT`f3|Is%@&*vYW;I_#3zp;;R($*{bCha3ONfA z8Q?4wE;B1JnkOR_4YE9ve)Unp7dd%;*2DcARmsd5&^Rlp(wEsQXS)?R)VH8Q$hc3v z*4;HDZh3-X0hNl|a>2=`=W{O1bs_5(6Zqi|m|Ze5jXX4Q+l|WVYA<{vEUZN_v%~E% zL7b#`+2UvX?rRS^O@x609rU#dK%el0Vp!ZQ8AYOTJ{~d)Eb#o11uO?yEQOt7tLaW15@nmML{ueF@`rkCn`zYvh#0lNT2J}&7|2I~Z6UTQ{ zkfC290yhAApOqEy;Tl2LH)fdp(X)Y9G~BR~Khu(L5Z|2_gt9D;1-&*m$Uv`_I{t#g z=}|7-ai(D>j%eu%%@QFM)G36)hrsVRg#ch7yyOjxUI+B;4Y*EA(pQON86&(2i%_vRFOc6Wb_C;dqvJs=urB!_!3t7 zn)l<+NNYZ~LYPKq#Au;CN9LRsyPBBKNq7ub)PNGBB(K^YuR*G|ogl;y7EuR>wh+vD zgULJ#rts@VTY}{b)8lEw`tAgR>r7MglrYXs!en(^S@pzcp3`paoHUSU4&6Ub8%cfc z2gF!I)IFyR@Xh}aKW^jgQa>rc68Jr+K8_s5X4TXVr7{wBQcfHBMW^_3-DwW7YilqL zn%8o~CjHaolysS28oJI4HLd<_8d$KqOV7q%xm)NA;=5DhCE&qpo`Le5O+ z^Xwad2W1CJz|C*J$mk4sPz-0(rkl7e$C%@ONA`D_=a(Qe-v@kjBB`7m@1Ktfx<`h)SuHIIgnLJ4KsYLV1P+@%(phZ~cD%hCd?{%f{b8c={|A*5=0od4QQ2NPE)B7dzTOb)axOCkW05q>XeP0>&rBb_n7MIGN}ynn|}|X15-p8Fmn1#nwRy#vnzG# zAU5RLs18`-qQy#wK)bq$AaSxry`PfqAEz(@g_k6Xbf6zX!3lp+%bljjao+|Ef+!Nz z=A9)m%;z#YQK<$0?gkD8{es@8OwXCg9nR$AA-`wl)4bXlG{a(Q&_{Jaar=Bs?R7q^ z6zna9)$jYJdw4DVZ-oH?!>3Q}NXWW)a4?vL7sSopYthx5fAX2@!x$}5hypAKKdh~T z*`N>Y%kmB?o}y?f5o8hlEbs71bNq)>X|kq&D^4PWUxG$z(j}RUl)6!H_T| zx%)cqjoz5xr_FJomON(zQG=z=Ur;7+Tx>N5Fo>b35g zzBD2R5l@~7ZkBnUiDnOHlmX6zklxhJV7~K{#*0tSnVnGjaYD8DkGH3K2a>%nfp?#q znfMx4dhV)DE|4I0NI6{kf;|PFW(xt1jHLLPnTWfFwlQFUM9?z$Ku(F4zX+p_3s%Sg z(7sa|u>KG_y$BFkF_m`#vZp7qJg73!!?6sn4MI!9+no2c)M$?TUe7IMWM+8AoH7{J z%V^t!x;6G;ig#M}75`vrMSxMg>PWQlK4-=L+YOXre>N(7SbM$qm6T&{s&k}7F`+`0 zoWm$LBa3!IbWST}7q>gDV7Xp<7_Y@;{N?SK(4IIUA<2MF==UaK`-HPMAn%}=B$GU^ z_y3!r@H+W+n|`TDJ>@|ti#vI|qFUUFX@$=@+E_Y=Ho3-zhcme(yDPuyIx^H|_fU=r zn}}o=dBrTJcAbi+cJp|X>cjhU9#dP2IRal4xNUPB!de_RpXR2rc;Zk_a!?%jNy7n|ILtr?pXg8tV42|}_tI9f(G z*E&bx@it-*CEQfo^%vsx{L6V=#=Cjpwyfy3RL;b2)@@;rOLz?Uw!3SqPu1*nA8mDc zl{n0Dbl!J8{NplBM%!thp(~Op;al!_2Jbui0=<$3+SDL(eWBAz2+FXo^>M57G7Nom z9hQLiETeI`o&d4X!ZhHxJguUuGGKW2tGVPz+RQp68)QR@yKCcuLtkEdzya^+v8mP0 zc`(xf!7Shkj}4P~DJ&Froj1|vc%b^l*N8fDRxmxYr@CyG%K$t2Cx$z7ZLeX&pW5=L zLW*@r{w{5y(&;xhn*s&=ZN!rhhFJQ$B1hd4FFZkyEfaEH{o$wlX3}1BH ziG>22XkLc8B&V>{Q4xR;Z|gHMi5Us0$6GjL?wrTF|E|9h?OZRUaOXxr;`2+v47Jju z0@sj?;uz027vEQ3s2?wYSO{7bqqCrG6ff(zwISQPvX}{N=plSLDha1e@zF`hEE&+2 z|8+=_h_2O%r&{VSBjb?a@%Pd}eiB#LxlCZe4N+>W?%8v{*sZr_Jq=@fxI9us+Zs+C)XXTG2uum4zB z>vHGPd*2dL(8)-@R-nflL|*HU-Nl!2dBBl!Chc@8%zLynnB8Zg+$|+Fey!YRS*_|Y zu$edh#$yxSu$YKjb`3W?cH6!GnPn3I+>-B4f?>Q{vQFEPWBmpe9QKs* zr!{L40FU^6>zQjN&Z99UTr^ag)2406s33L99Hb|i5ZloxM^gw3U$RgKeNMcP*J}_b z+zJY3d7CV>2vtgrPz$j#kDzRy-jQAW9M@&8bjRw=BgZW+_z+o3_}xrF-Dq0(ix?mwVvV;D3rV53*)G0f&9 zc)Nzie0Bt-KF4aB(u)8~q{Vn%xTLuD-M@~Lrbpls&iK~TQP(i-1R=W+W*z}8Pjwo8 z-I|w!#<4^gN`pfC6E{QAxpQJI5^09#tKB~oIY{c11Um+EhFgOAvzV6D=&9i&gnkR1 z+~9^PzWND2@_p;v|F=zDI&$%JE$Rm`wO}*Ez`e1tY(E$EfhvAki>U|{g~cUDL1Y+` z*Avi={OeYbixekE!a7R!G8kL~wi6GxJhY<(_^7ORw}RR-asE8qVeX3&CxX^RJYG0i zGRs@YW!*eelN*Bj!j>)_IS{QF4h(QNSUpmTiXe#;s!iIVrpX}_c!VI27a~X*i+OhZ zzF*BDwksm+N{%MRbRd)`dK8x?Mx?)1TsS-Wl&)fFzg%8|n!c6tB)hjNawp|5lJ}0gtmTfJa>Jkpf_IlyCh%iP_eLct+n^57S7hTep zwKcuqdunLAySS?D!)2&oeyG5p0$Lre@PEY3|3xXj;&-i&a4(6D8xN9mOaeNz#{rWa z{sTcg3Txb1O^gu@%6`>o&Jg#i4HK-UA5kaD#hs-1x89Sa@fOkNkV#taVG9_oBLh=JO`~J8wQuxGBKx zw!qxF_B4lzR{uAbe1eobI?@+6*wcr8Y$ke6C#25Vo}Mk)NhKYaSIH4T)qhbXu>Etc zJ(drCi3;~PR>OqS3NS0jq+XR~S$%e?(oQuP7wbJL)4!1H{nj~ga?qyFvR|$9tfsx@ zYV&cnlH4^O#yWPjuxE`ae>`yL&>Shel{j(rD`!=5DNWYrb9ot6Kmk=UI}H$>4ZW$2 zElU8gtUQ0w7RNzqSemsHCuZn8-|hIM@TDa_1`Kjpl-hbkNJvap{$@^Be+gJyT)JXz0BH@*PvaD?Dm+}WyOGVaKPl!K-}GCbieD!` zXY3v-BF01u%qBjeJN$etYWp;YkE zg3QJc(X3uf%l`FyS~q5T>?Q^OQtmdPKq^^s(il3o5<>60ua&CxU~#9lSu1Cg#JA$X zg~4lpN0Yr0cXufM8yV&QIvXS-qF)zAvUZd1UBROE8)Uvz9jnzut-x~qB^F*zC0Vui zMuv<$ZVr|KCz~0`M@4S+o-?>W5Suz3<5R;(Z3I@BY>xUVBA6w{*7vNzYduTM050(! z`JX@Jgm)9q=>Qga6aI{NMK{FdPe}m!NCY`)qb)bincRK`;;>8TuP0T}>ai2*d=nMOBzeu;LlRKh^0%FmpjH{E)A*h6ARQs&)DukV{`;5~rx#~w zU>=BgJ;SHkf$OY@$_JSd6m5g7#V*q4eYLr zk@(jk`V(qFk@koUi zUdx*9X#e?9f}n*D-mYQ`NDypJk%7>VT_=dRdF7_DmMmi!d@0ith#?3p2!I?68`G+7 zF-^?>LLxTQ_nBTU2tO|w4ucU3J#OlgPwmbkT-#iJFY&EM1tG}4cA7M^F%--kBg;lO_ zhh3xPCXO=u?beZKImtpt<1z54MzO-NzISdOH=EH3y!*@UPLxckZ~KX^r>nNcZi|v@ z=xYg96|t9sirnIOyOUvNH|b(b?o2?PB&M#+x4;nA8` ziSLd<_~nP8_tbH1$x!-c(s0z93I5b@nPfw!rqn7<^Gcz?<6)7Q=M%;rT_{l0f!t{7 zuqzr)493|cp!7o|z=J?&U3>#P^MPZpp<`#P!CBJxz+GC4HSNZ^ zv4U|_!;eWeLY?J_)dpc46O-xw$CyN(fY?G(SM?A87Ak`N^$?h=mp5FHKX!8PR14Ji z`MR9z8kq4mzrH-CeKA4tUdT&>c@_vXsP?kRih_}afin+I5pnIJ=ak{Sgm93V@w0NW zHHiiqibPglSc}?QZ&)6%h!$bNzSdTt~ zzp(0V{rKp&BB0a=1tmJ2XS-0SUfE<72b2{^O4DoAmWFP=4?7}e;aK=yc=p6^%K&>_ zN&8jUf&k!QAqy9^4O5Z|q`)-dGx*3|w|Y90GUZ-v?O?)rRQ|<)x5~kzo{EtH0ZN~^ zqDfYRnpWAvK1s0c$l~yvH$tUXsU^rDsOJiVcT8VU^#l)-OqtFJqTy}XFypRk??hk7 z=y~rH13rlfa2iQ*7O)a6x1RNl=}TJsUA{v*1rz2;BlRW#2>yGRX14zHxL|Pu#ScaE z-SujfrK>kt!XLc1(EBiC!nZLrG}*#X*s$n~-wWNz|2CPNqL7WB_7z7f4lH{#-*_fj zfJ%2^gu@At&xbr>V@nAjb-;MTsXSMiKV8YufX^NqJku0+WK-6S_bBa2Hf@69N?@e(VoNw$PUrLe3)!v; z4B5ZF)c7s5QiNUq+n)??kk~0&_(A9;uig*goBw6p0M3*_Rm5eJa+awVq(IjM`Eh_U zTC7$uvwBYYZeK`kw#UB}L>UR1tIGNHK56FZ$|EtEFt|RkeUgyLyu{v*0sigtLF(wA z5YufKO?m}9Km1qR=Y13yNzlp}@rVk()Z_}dU6Ie*g1;wMxv<`2x)an}Ygvk&R5=+) zINRcV^sai55frEd5G7!;VwnRV#PvFv5ZMroh5(I^@6_}ODos+gj`w<9P7EsUhBe$u zmEx}T+T$;AJ-X^_ze}U4dhNg~5CtF%77)_e_EhyBUenk=ygpf#3kC4N#c)7VX9Q2j zf;>$)jRk7mzJ5K6xtGfVxb#$4B6>QgD%}s>ZN0;W0#_MofAblsFKA9nvJ>g7Pnh&K zzo;bbQ87Qe+YP}vJGLSJJWO*LQdOEm!zeJ^_%vg84Sv^c??v-((Zg{R8lj}4!YIs& z?pfk^@dauIh`qHqQe`G7U-YD=oIG7(rrRGqaZUn0Y)tu8WB41IZbEt+0@yFSumRH5 z0!jix;>hEnyr`@{KMQ>#^+^w6k${Po449YO3+>_2xgz=}W90sye@?yUFhE4(>M zO+)sg?n&)iG#|WquppYVVn1dl>YB;#FJ$K(V;68rx0~Zk0oH2<-;JJujdC}`otdWc zk$@CMcW`=jq`|rv(1o-_+1C9kbm>hBtXGZNde8Qf=T4UdaExXf>6s zvn*+*{FB!0K@4xxnFpm%H%=GOZJN+*pVnxdUJh_|x1pKaCIJlyU-0HvG5yeG?t!%8 zsON(^T;P4S);U+X02@U9_;6|Mbxz+3tP7I(r*eT9y|UDXqzQKW3iIZ#;~RbL#q;3(A7FB>g%LUyoP%r2qeanyIw z6>^mS(q-urXXV1y9@WWgMR82qUWyO~lCWnR9fQxEZI|^#0bY=(cNQ{HVFo-{@S;Y5 z-Wyrjbb}tFSC5H#ds?gW40EFaergR5iK#k7 zpOvHHWy>sAji6W-HZFYksqg`3u8A^d%2ICkMlOm-KbP(Pw{LIvlx7J2GNrCnZEpMQ zyKEO;Vtao6&EOt0VlN=~ftZPrSJY4sx1eH!n-F(+#^^?Y=pS#>_uZ?qr;+|u`m~)$ zCnw8(aA*aUvN6dBkXJz_?P`EtVEq1CAAZ8Yl-|{+IyRO<*co_F7G%T(1ma0RBRdIC zu7m0E#Y&`CiXM&nHSAJAkn-S%17(1O8ucr{KGgQl9b3jv@KBDH#t=RKtyo`T`C%ob zoDA?@DTyeKd4*H+u;=W=8W6ke_y(zl75whcv<8Xa-`0eaD8bGz33$stKbg zpJ~-1?qSs-&IkbRrNUE|B(D0tyU)z(7WEy^WSMW(<|*9)*;H78#Ip1;CZO`LV(&H? zH03MR5LjTR1w<#T!+&)u@rY(ja@eImZsK`gat)&YZkup$3S+JmF7!u=xTE5hM|)KG zl4P|C6gQ`r1}-nYktZW4#eQEfi}Kl~Mu=TLI!~y2pkGb8Zv%2`ZwiB*KkWkU(-J}t zwu8HO%lg&1D;_5CaZ8=afp&e*I5V*4?7{q89esx*6~U}RuVcY?=xD@Qjad_d+h307 z{GN#cm@Acnr4twm3Jwv=)hO7NPVZkhwR`uwfV`!pB@CdOZ0!@r$j|%hL-+Op)}sV+ zLU*Y}exJTz)rX5YDo^z&he1)e(7>MCr0|a&pAi-jrvAe^pvS*OG#h)YmmiksvAs0R zr6#I71-fJS+q^&B$PR;g`-1w0-GrzneK56PTI> zn#Y1`=J;stfTT3CBEVSg=-;|39Z~LBXVVD_Y$JzfRyagUPkKMP!fTT8NCJ!x()#MA zo-ORe*uA?9M(?~L7XjATLF3FXjC(~R_yl_Y#hVoT;8kmgjWvUKEh96VJV~weDM$Ci zvR}+|PJjU4F+7?$E}6-^QT@{l$mQoUQ0S6uv#W%iKd+osf9nm)M|7=?aYj0>^9EA$ z4RblXK7UoF2Vx5S!zum-hgu)vz8`I!_yrxQF|(B--34a=yX0Id4)-;?e_tzITLG#D zIe!&lCOdzDiA+=w%hP##QXAsHi;_G!Kk^MNAe^i9`wY6dAK9JUM+88+mAt^#S!=r3 zY76Kis8Q63QcUe`h_RH<@AVCt@88q()=hg4K3z&f{(SEX=JpZ{n@pY5`v|04IXaxJ zN`;+2ab^veD98&`4*-xXfqB4R%VL=@!87f#^>K(((olX1B>SIlk^u3QXTwvil=VVs z_b|a)w=77U@#GReZs1?7@IY)}vcR3bUEL-^_>ptX5VrsWT?5|7e$>!Syfh?J; z{p3k6>5^IZjw_H1sH4D`2nu zT`c2QYLT?WomAf?hA%t{dkZ-OnH7Rwo|Ut_CT%ItvVzcG@Fi%^cB>lKaT9dGa?VgB zR6)2Su&fu<;=zSLo?7VpTw}b2@~z4Ivvd&o+pCw84%tB)Y+&M{CEJfc#y%Ri24YvS&fTordV$b}8EM5jZI;lSF z*3Algd9?HNhRA|GxOT^1kh5%rbjNo2s`dHQ!Z%5}V2C0|MXr%T%WqU8)b0JqTD64e!T2<4?@c3%-iXiGP_A)1 zRr1^!KDYi>8Q~Js6c?Ur$xemB&B&d89sN1Al5+<+LJU}Jd-74hj}sHJnAUQ9U8_?E z{Zig*l%I@wA<_o7^s%v_?^xeL0`49BFnw9yOc{VRehIi-|HGR=vu=Oln|K0VZyh@^ zO9{}2l87N%c<+m9 z-pUINIHm@vtt^(r&^^xGmd_8;PcN-2&t0JhNH!~Cj3c$6((t4$7a+QK98^>O8F?=V zx}B+bL7zc*DPIfw8dAWx0ZPK|$Ywwu zdWRlGMDUr#nB8<&+yk$NmG_^|SwLbhouf`0&wVnkCTT*rYR{uoWcqvOp_3}85Smcy zOO6HlI)?C(s}dZ5dbw576#a86ifd8yccJn2yng*R@M=d`Iu?i>W-~EvtzgVR2~Tsv z`3Vu6@M77}D3uLi&{ol61Qkcz@el3t595UQ8BFVCnp{^_wmVT}YvZ$PKZ*SlQ0ymy zVQ=E#fNC7JnN;nx?Z_tPbKU}k=#=L)@k$eOz@fGn&-&$Hbz2fg^0Xn=#^+e+k3Vtz z@s-Z#_U&vG$Pr>dK(j4S$489uq~6>XKHM{fFtdakEzq-sV99uUFfjTLNC3g;T| zfD%${HNf=$kh3fd28oGqOxz%J`I?DAY@P}Dh#+%{MNSB$TTVGPK)t5%=t{zoyf-YOd=s{xM#PdOT^3sX_{P1f5BYx;eHtrsx+#n+KOy7h=72k-7$9`-}m0{_uW7FgLCHWz4qE`J?mM|3dUe3=A`0A5W^i6 zgV=?(Z?SOi{^ESJMnuPTX?w+`{Ud6X6knZb?iMOK`nuuel7V2Y0b}I7z%l8_Bp}`Z z4%S;ZvomYHnNZC&I_M^aGr9d~yB}!~VqZSeY6=VRRZLqWf}jCz9@$epPdPyB9p3$R zT)3K~sqCiwYWYkL+13Y#`W83NZzacctI)r@@cp}L21B{{Lse^xN5)h2!l9N21wlQj?=;{S!R+!% zJy0cMG_>_#^`sv?^~d#JR(4JRcJ@EBMcUL*#^{TZvR}9_rZ&k1MJj!3$gepNP`I>~MI;Oxo@j{+lhk`s9@`O+c z@_*XgNp~KEsf6|JLNU(Ivm@P{dopkQ->x_3yBv+5?rRpdJ4=`E^9z8!x~Cwr2y#@4 zO)T7Q-Ts+~fv4QQ&EqnYQq{eGb!7%>Kzgy73|zpuUpPmd{X5Cj5a>0JE$;_%go?06 zX8i&DSx=5j^y5)YCeGP0-T8s+^YPNj&1h zjI=}k6}`{Tg*eqDOA?h=dwxk~1_xJ{f}62dAO`3G~YTD%eMXV{<$2*2fRGHjh_~UDW_q`81ip z*+{L)cP16IVAz$ftH12&Mq|q!&@+K_;kZcL23k6V6BpPcqH8hnAf61x8enTX`BXl0 zL+g@Kr{xqKw3f^Y5k^v@7jsL#)hX6;K zKJQw6<*1kxT3?b~ZjFz@+K^%jXu84Lu8$It6%BwS(63V{t3OQ6#hvE6mc}bmM#3Xj zCbKSEYwOx4hFQBC>U(h~#_Fm}>ht%f+*pUYp@)9xyC01lTR#vJ;3v@E`fMJ~Z~mma z4^2P=Bo=}>G?N{sn+&@XEdG7T0U5{){-gRL3ZN5`w44QW+8*Dur@RF~O$1l#rbJ}d zOZjD6oe#LQ4K&?=5gfsRf=dEeOkO~V=xN<~#I7ppz_uytXAm_~>^^#LIjGb{NBp?! zPnGwYu%~1JGfJ(=+XU~L3N1G}e z11zt84s-({p97aSNB=$y&PF;cD!5h)J5;ZS+#@?eaCq2ye4v`$;L9@|(0-@(-CCX$ zG~TCj*B>Un?ykldmA`2T?1I>J@i!%E^zwP(<)9y5J;fU+FBl$QPoV$<0{YSVvobkU zDutQC#3y}dx@Ji%?N6r0k#Vu9fUscSA3^ZX>c=4W9$+OW5Au0Dtfi##%h%L_KFj>$ z?;6-cPREj%@1NqBNv~}`t6E2=mR^}YFIebcRCT*!+-~QdUv`cdxs-qUTja6Nh42Fq ze2HLDmKZ4naK()aH~PK;bj3lv@xNblRKn_<*|<6MGe#yXynJi^5kxGY8V)Y@PcU|V zLJi{mdW3A74J^RE5TAZGp57VstQi+|Rtgje`Fr2~e2hLe^ZKW8O|~H;kTT5#cUSLe zc2ynAkb1vU?@3{0c`qEgWw^SRJ8=EpFHJQm!<3J1YCPH)K8dUGUu99dxBhv^A2^Q( z?02zPz!=~==1?FZ)wD2sb$KI_ORMby=Cz?c-MO9?acis@-!MNgqMNUxxxk7|_+?l% z0x&FDp!B^CbCOhy$+m9+$g{xajK3O)gg(?dv~|}9tSZ67$99UBrsbdt6ab@(PS%M(>q>?kpa4@)5hU1aif?#i zFHPzm=CG^@VT=S0!_mO!Lvdk^e(l3k+1UW&v7plwn|bE{%*NXWeq?7RDiI(^a;R6& zaHKLlQk*6ReI_x7ef4`Cj;?l5O;0OwhL>Is7#>xq#C&xjeFZoe00APL6c2e;z|L;3 zVHjNS7c^a@0HTyl!^(vSXTBa(ld4kr^smW=v@#9s)DfM)JD~Ig!z*5ynLS$ym6s+M z;2+mm(tAF6EL+TNB7%0A4dMI3%=~6e`vw*#A)Co(CP3wisY-lWW1FO9?!i~Mu?ANA zxWKKpq*brpn&I$Mgn5KC%e|-lRn|cWh3Z5SL4 z`x%ZbT#ig1Wcz%GL-sbWm`&DOpnmGGGD3dq6GWx+u~Pw%TQn(`{{vRQ5TK8|ZT9=s z@}e3&Pi%;WLtRIb|e zGMUq4WWpG(Uv)Jo~biplIJ!+R0d=oAcey{Z7bD$(Tm-kkZxayL7~(gUQpka1Z> zPvBu`XHWH2#2Gi!xKsX}r)bDki5nXM;hQwPMSYq3+vOWM=4VCp*onKK>(Qp&^w@9O zx3X%;9He;#y?tW-rV-CT(<9T-2=}D8Pgd2ZSp>i@=X_PymP0^5qQUZ-`ml-by|7!* zv}DF`b)2RWyX22BDaa}FK&+>wA!bn!Km$R=8_0dz+*A${5~0Hz(%uc5C$Xk%+@fQS zJl;R#05a%jn)3_-bH1Mub-%xy?b0VxTx1E^KK z`N=zI9Q9mFSmXDrtQ)WrY4#SVPz;xxe6y#>tfT3L{h472AbC+ma zPjpQITX2Au#(DA2ii#S)D+!zYfv;yZtMBwjI{1oa-QV9dYyGWYm~s8b(%^yM0q7Yf0{``PiZcR49x04x)7)!Ap))24Kcc$kUhaQJ?c%-`tRvUL&`;b8 zMcHOxhEhtsVoaw;s{1l4)P{^|y`0CLV?K0Xhs?I-10kH{|7OUQ5W70{CiOE=B7Bce zsTVu7ezD5=4}j5Wa{C(}y*_A|$Zxt=k{w@pXI0iQJlRfbwsenD4$Rn5xqG+De~;2o zHXwRSEENKhjm?4$OMF(Ht`Qi2_jBmc&zPva$B8}hqy`U+qsf9G%AZQ<7hvB6;cF^b zFMc+HuG!VN0jlB2G5196osxQ+b5DU zRzNcj6Ffi&sse7Yzja1R<1pu$35d7Zzo7X`itsCxbN!E20J7~Vkjr_^Ge9ZJ15wPG zmT0Y9`MrgzKeU`XG@e$7+2whi%t^bxd4CJ5s43OfcDFlQQnj+m z0Qod6U|;As@;%$~#BOht$$mhWVobqoFXQCFHXW^5Kx(O zaY=ZDs{u_T+m#K5Zlb|*P!8)>p8goLGmk@VSn#SS09?WZ@HK}tNLEaSJBJA*2-oqs z%^N&&RxV1pl3Y!e2_S(RP{w4!U&-&=OrQA|!bt&tyYu|t>mTL~)Nt#x+7L$AC`bZ; zuED;#j9#K!=uhD-M%(XHAg~paek-*i>-DOb-r5645otOq{4uUdOhr-A;-3UK5}=|I zCRz8u%paf&NMQ#sQb0 zD}CWW_{|_zDOd{%6MU(-{@ts2nV_2Dm0!RNd;(Ad1eBZXFWd0DQl1P;_|^h6KOHAYzf0R6t}MAd-&JiIaazObOG0yj+r zq<~W^lO#+c%tLRm$p109kPyM@UtoQlB9vQhN+hwweHkqdMXkx{}4gKNaJ+z;*inR0i%2R`X@AlJFgnqXC|$1 z`RygBvW&3LfM%{uu!Jq%nSb7ADr?SsetkAfzMoupA`z9iJ%lR`9b z6s34`&`aRu0P1_4gcXzzM_ThMgd4Zbj+*b7O#LRl{d-u|;b@B;^jHmn5&)#!;+6p# z06sglseqQ@Eav$4Ufi^ME8Fk3u0S1o5;|v9o?`=h<6^83F)!Sg5rFf;H$CEj@F&t^ zxyRNo)Qj{6*5Pi#_M3XBc^{hs)&fO7{7^lI5I2JoTysb)8*UE}7_dWH54WgR8<=+Qr6L8E8XX`tM&j`;!n&ezsTkQT!qBqi+7oByYJZKc|v*2Ik{KfIW~ZPLuN6I zQ5#q3Ye@VGlFplya(~AyW)ESZAcfQfa#{S$Z{Id9B3Z|%Aic+5t%pUuA#=>@xGEq* z0Zsu*y-#7}GH|>b0zjZOjd-)z*QP3Sk}oyZ{NfS|lz}GI|{bm3Sy^V#GXMh(~?nLykPg!fHn2d93A#U z`-vX?qds${sUpmrjePDC+-rV8lS#|nR5 zaTyTA-2C&WRro$b1b#6ElFvNgKD7+y-8Vs22FTa!fKNq)T!%Wo9#X#Iil40xY6X5E zhaMxv-q-R6<6E*;joA;E-QP~Dx@a^ycG3CdoXOj>!vW|b*4EaYZ`swPdoGRvCiE`I zb&;w}YQTJRjDOhTue45;W==7^Y@qq-tJn(*! z1oGUu9FJCiYnOPfu@$;F%^wS$2fQo_X`})TLk4{xI&!D?)_TlR3Q6HJ1Z+RryX)*_ zJJ0S~Eqz5{&*<+rm;gL3CHvxvNolZQSfFfF&ZKYlHM_6`rGo3 zJ=%1|Hi-D&&F6<0(d;Vq+A6#FI$_)`>U?|6WnRB|M5r7MgaaW3A}TW=6JXPsILrQm zp0lEv%M0)-@w$Tvsk?#v&eG1_(zrmuLg`v)DBu_G{XR(p(OO5UeYg5QfLU8i#OeW3 zj7YKpK;3VFj=-JdG-&d{byQ*uoys)UWue2kF+1Sb3N;>-#+?qxtQ_{Ce`#md&&(~) z3b^|k#2RqCseAZ_7qIJ-(ib?dcXVb5%UDx{wBqv@2W;nszJ-NvbN?D(#}!>rlu zI{Qt?Xm{${y3{j)?TqF&)D#q;%|#Dfy_G=QK?oqEPOP9+9^AJxp+PAg6Q%S~a7G5m z;Xo>hP_11GK9|c_3qH&m1?ZDN?tDA7@p3!<6&&Z`)--x+#B)?h#F-!Tzy^%QOLpD$ zTFp(YaH6f~*2P2BELu+<_EhB9TmgI$?}oC=lI~O$&|sxq(!P1<8WN5zN*TNA2l&m9 zdRlB(ggl5HP)PhrIFr`i!D|@&4T3_m-EVDupo%99+4H8kF8~kw|m*ZqKQEPkRq8w5_^8C$%8i;KOcFgDWlyc!I)f zTuJ$}`V8b!EQ6HngQpwjmO^x2p=z8kcrTKI<|X)2CoFH3-IzF;`N@Y5rK!8i4In(N z#E?)${o%oFoWsvGfTUFQBL~-vU7q;?BDTzA$#5BMyCv17C3;%jQ+VZT+MuiS;rFL} z0KJd$TTYH0n4XU-{E~~$VhmWQCn!Nygr0nXeik9=Rig(?xtL@L!M{$!!lK^rD!a z5#jI@PgFMfm`-i2QDct0P0t%|`$SRQQ{GmfEZ}ZoJ4ltoV{W;!&1uBrSZqnlXz;WR z**{%OT5QP(>_43;>&X)Hw0*`Kyzi_6RF8V#$Cov#y%jG9q<9XeYVOiuJy;aaXC7?U zbRCyzd7x$&$L=gMJZeJ2?%#er?vbJdWGkM~Xx=Q51mNfJu=aH@sP@Rv_xl5cPh6#a zCJ(>qobJ5)bDz_=;*naz(iBeF1!GORtdFq3ra92_EW0VK@A31ev|)|^l3IjkKd}kz z;L|~5WNgf#bv7kcEAm&Px8PZC^*6>aRw((+B^-q9oHD|eSm&s*_HX^s#awW%`b^?Q zMn`$58IAVmH#eKK6H6HA7VTXTEF;mU17ym&o`BRrFT*AZ{CmQhWtr!)eH%>R9em}-T;pF zc@*~2clz?A*a!VXKA`dDs<7mP17_LU|F}k|ptxI%+})zb?Ss9PR?-kEyav54!Eo9iAoCfB{besfpy_}q! z;qEO`Wr?18(W`(RIO|beBi>M}Iqwnc{G zMSOC^fg7*%(d?K0#98TSi?~I(ufpPVMfx|eV^bJ*ad%V?5PhhjVKpz)uY(&EO;bEt zoRD>Tl0UpTtQLYPQZm20eaSdlT0wbB>W0_LwBQ3&&At6-=tHD&1Vx=w0gdHkpJ2IN zF4Sp^Kwe%EH;2t*E%z4bzWW=e8JZKPMUg6-ev@q))tAt@Qh+B=$9#k4mbGmoBu)KL zzpLy}6&hFSFH*K+@K+bnUArBgdzdElE!UR#2AkJGo*kyBlpe8%>0DpC(0mk5A#pVP6 zt!2BsuCmTQ{7?73Wx9szd7x!ysD`gL%HohJ_ffnT$DZwxn2f3|9xIfR#sx!0bJhG4 zLrdZLnKfV4xkv&j{(dqa_WMS;l1TDEF9Y(-Jm`C3;lePlED;Yykk~E1pBx`Z=a8;w z?fzl-EA5viV+hyjxzKas_`$l5UZUm67W+A2{^n;*?{nE_0Z5$AS>V)9m`>C%i8+21 zJ0$>kk?tnc*JZA}PgxM;vLu-8uD^>@}I z)rs(xINiGUquDj1?;d>FW`)8Ptt->wQDE&nwVeG`xZHYRZ%Od!j>O({4v#oihk(#QB3j*|H2Ui<^Lr^JJ9bNYT9C}v4`B~O5*TzotFSX2mS+vB8$z;7l z?Lf(~PeX#X_V7xbaf>P2C{*#M#vg=L;w4&=?v#d|Uf;@G?%%s)@mYQ!rDhh)S0MXb zrha;UJsb#z@y|9e@u;(xDIcM+F9fd3XALN}= zrKx$Dl!-;XB>>;jrU>?5bY4&xZbtp8O#4B<-v(L3#sW#9&qBKyzeutB!ys1Jf3*O9 zCEE5UKELOKTU*hPbV@RMi}kWWLvB#{&BkZPRUO*kvB^X!t8fn5q^JJ&ABHLeO(8$r z%PCyBDnP1RU+zUK`Vb>m3~pS~O2aVRu)enIabYw#^K_!|rL7ka&t^h0<>lr5K7EgO zJX^gak&`T1|3P!Ug^$mSWnbyp@aY|99@EOfNQBm_^4%U{veJ<$ z4U4md`?}LLqMDg5zscQlHZ(QLx3q3nDCbSRQe%@${Q;xerJx334=K27zOW^*z*TXg z126i1T!qVE%H$Q5c+`Kye9?W{N3c2+x_pM8EzsN+Qy8yH1z*m;Y&UmL0lw|=kDTU@ z)yStFsureUi?l-C{NL&uI>t&lvjrLl>koAy;6W<|tWL=bKSnG@!jWPs&a`NMvC4_u zINDglGtKQ#zux1xkm{9DR{w+9AuhU$t8c|(*7KXbQK!8AqT7U&wDnj)_P>cMw@NEo z%*(Fv2v<|ebT&M>k@PB)#;yb}!Dm~LXXIm+suxw>3$ zAEo3p3EbQ^U!fW&NPqpcFW>}Y{i7-0G?O)QlGTEL>!dH+_u3noWufKC12Vgz`nVD2 zNx3Q@-NtDz2wlcE$>#`Q5qbE}!!+PAO+G2>Me56o=qMHA!vy#3P`uLcdRo7d5uq#X z?xMK1=!mQKF0{-~o8Y2$OzZpKf#{1H^Hwq+HD8cDp!zGg@lK1xG8D2)8sMga?)Fhe zB6r~G(W9#sXY;xrtW2=l^c%uXyLQ$z<%};Xz)tZn#`~IZ-dP#ySn6=!ZsHdp_b{_K zGryI%wB5WCWWf^7H)wNGSsAy4gr3?1p4u$cG!l+{1z+yMqyRX@9UPontLW+D%M)E? zo-axrKf2vla#v)z)OpNydaJ7r`s#)Ia%wh7@3`U^?wxVn3xE2M9?`4xQPggBCOm-_ znhQQ?3@mVFU+D<%F-QEw^vNP-e>dym8h4|8cQVuQg@64*IC09GTE_^l>-S2@9s`=z z-enI)nkRUys_zPef1NgLzVNH4v$y3oY=7IBQsrZG9D3(uPBlY z#Lt%CQN+(Fh_UMN5gJ#rmoJhqq#PW;Cv-hj!9ROt6ho&v^%EDTMfP3^*@U=%RPPm9 zX%xX(q7N6s9Fa`cxxLkwIKMj?4kpmyE zu;(Z=gAB}Age->$CE zbWeY`6@C@d7LLF9>-F}m>O`)hz68lB$(`f%zd5e?Zg|-~vtDvQl{rr>mS(!74$nU^ zSXo_Jr1O^4SgUjTV+(hH(C}E`6xs=~=8CzqUDh9(ri!J;POcIrn9T>&0y-a3%zS^W(5iQoO$` zq*f+dp_35{Y~}Z{O?7-sbC%`Y-#Q7yeCMeMGs2q_`{37Bm+l#AXhx zoz1vPF6XM7wQxlsrfDi3xC&n++$VKIhc)0$vv0Ss68)<84Xxtu8*E zeE-eyDg$)iW+BIp7@m|b_J@Z(0#JN_(ePM#t%G>`C#}50FkLoD(Xp>&w2+$}Gyq24 z>Z!Dh_k!)tVne7J&jRCpr$2-nXO- zCcpbKtRd%nLDN>k@H-asky71+<*v|m-D`i71pzt$gV#a#cT6gZ%qXeWMNkFKNmm*W}C9dH~Z*@O{ zHA(;{wOLfvN5FWw=hw7}S5x)lYi)h|4_rV2A`67%D`k-{!WQ7_no{@sLziqKU%hgZ zsvCz>udMX6=7tb7^6q>51jqXt`1D@_7BVHy!;ITY_ z6;)v?MKBmdKn%rVbH3nQhF}QuLIwyx++@PfAg1W>{fB>@A}8Tgb>>ka2$!@aVEv>Lm5$amwtMoXy0iE#~1wY>N z)Ju({#|p_%JLU_1a3sBiVv%i!@CW8WW^}%*8)s79s%|UubK4lPiq_)sl0uCof0^+H z!2T(G`7);>2|mq!XMLMQ&CvcsQ{tYx=*P3;WB0>k(4UNV!HdKWLn9DU9B%W6<0@&E zH2!6`YnRfGW48@krT(%R5zV>l-nWvd%%5zYJn3V*#zF>1vEm%LYNS454E0!ieNptV z&8c_He(a%P5FBzqF5nQ(g&Q(mL-3N@4S&qcI{j`%9n*dX4J7<(RaN&0LoRE(w?AIX z(pi$(n2Qc;V45n6V07oWp-ozhv>5UfsARIh;V&_p7ll3A`wp(MdT?~ydLG7KgO5_) z**<5y>dz!+pwR705WlcPN%uU%9L!49jdBaaVny{1&r9Mus&{g42hHOmJalwzR*hZX z{vpSrhI@6%#{*qZE(#DgMCY{OJ?8m$TI8nc#)!M^uu#!4^v_el+NGpB!YV(|aDj9c z2NR$e%wjzkh+?m3<@Y}q3f`W>4NJZBBM+lrM%@JIM>eoR?<0A|HbImIjTw`vK*L1U z?v207sA!_h*q}c*(6#e>7^}bH=VNhJ9V%vu;nnve!;v^}1x2B?rZlsXIR-NiqddzF zV)D%RIj_g_kg=4Lf%SXyfr$+9mEsQLq1fUqhG5$wmOz!sN_U3{wuK>y8ac{Vji$n+ zwSKV~uX{kjWCw!t*|f6FDJaw3q)=W9X%2oaBnTO^2QX&-T&Cd%dACt-2V{BNiRkod z>9-@e<6CUw(sO5Unrfw9c09y!v{?x$m8BJESY7oAw{Swpk#h;tfck!G zdX)1%E|dkafCom+;lB=}f=^d8%Sm3B=!klIBcB{B;Fr)dMiA0?`+wJCPwa1TlJO1h za?H;nRAxgwqkJrD$rAH{>Ep(4zEAgvVE2M)f&SueJ|uSA^!@`MJiXgmO)3-;>s=i@ z!MS2(WD|^EmoO^Q0gow?wM*D5zle89ezsDoZJ)D1Y>?imfS;^BC)vF5=I#Sh<#~cI z(wYe{uB@2@Jk3!^Rl1ezj^>rs+Q_bYO9=td5NqhzW4)U|iohh2eh)YNRiPS3wBmMzZpm6d~si zhk^MGFvp+eQ_BMJ2SoHvblH|<#jR~`TLNwNYgR`YUy*&Ke)Z~AygW7h`cxb?AXU18 zH47MEoIKZJy3L{3AF^!Es9#>RsFeeYpGY!>jr0!xDK3?{THF!1coC+CqaS^1VYv4q ziFzG&Vq5+JjHQmH1Q%PuH8k^F07`eONr^nVhh}nvrc*_o=nNmW8yQLNTGrE6q>%@* zC{fMqBIqkf3)*5`X}YfZy6$iFx%l8!5{EIAL<0yw5}c<&%hXOXlsRIp)`2^CyBV7# z0^xB~h|3VEiFsaB<=o+I9?Vy$pimbx08R>b<&)kUJP}r9q&RfmTa@!;8<6MldjKvT zvE_u@K`d^+W-%N??R+q&e!Rt^LL7!ynn};VW0d$Y_2Bw&CVeb)CB)6mRcUD*eqE92 zt#gxwkJUf+jwguxq{Ip-7ayUDIJ3D-!%6lX{L9ODIQgXiHYfU(dkyOQY@~x=rJ&r% zxnnRoGK>$dAR$o|{HMMyx-ah$;YgXO+I&)C$xMPYbZN%{PrEbmLMPT2r$6X`Y@2#z zxZC6Bb2L29^8JE|(M#E3qr+XlP)gO59P$aN;PCfrLm$&|8Gfy&3Z6nY-Y9^uw4CK| zk!>NU1u&l7DC_t56;fVYj%mUe#*&|3Xx5XebhAgGpTH^oB&HfGGCT|i&MjoC;_u&p z!+KX<98UDhogOLfaufLK008z423~c}aKf<}0|q%$8cTbBGr3|F&oqRiM#78S_%gaYx3 zCT1=I9_;zo0&$RV%&Ri_!HhJJ^7wF&YLiypXYy}?j~5O0uen&2@P!c!w9*|6NJ(u}J4i=fGtpa#m7C7cxSD8vuz9u4E=UMedp5##o! zT8J$2IZ@dAg1Bg_oQrY$v4c*UQwX})`3!T`jMKccw8{g4tSXC>dvzKX{)QRQy*oVa z3Ql8t+UfL(pgG}EL1K@xb9RvxasMTz1E|ZWBYgPHSU9Kso^wnF@bpQlsCc+_Xt+`- zh(P$%T@dTt#Ez&Z)#4sJPtAN3er&Swp#Apla#wIWM&n?-2b>}u9WAYoM)?a*3N>_P z?w3$M5h0%W^tZ|3X5U*dkBZ5A)WMf+{u}R_u;cQ#5^f+Y1YNCd1J# zL8*@Wo}N#ZrT?tbi>kIOF7%w_T=g73E8{gDF8^7R0q}zfLDA>8jN6)BCB>vKC+_X? z!|CwS4H&4F7nL6dHRFPxu0Z#B=8a~_eHf|)_$WQ+@3-*8`3KiY#5{BiUj|tE9APxJ zLS-grDL+Tc3b5u!v3?A0@=0nRBkr`jPq<-vYBhLX#R}MO%Em2i9QR7>| z;}PpR{GH1G@aL+p*gU2Ik?o|Crs;3g9%n1EIS_5?e&18&CTa+l*%;I*jl;&TUY>%5{L!)&=~ix=rQpjF_~$x+?USH zMN|4scfr%rt34KmLeE2t3R#5jl2s}&jedrQ_4%VDBZXmE2AnK#ykg*D^K^12@NTke zp}igLhw2BkE7mZMDwc1dxCP9B=5I>lCk*np*%bx9Z2#C^=F8j8$HFm0SQU8bp+5oE zsFSasWuQ9zE_UJtf^Uya1v35H!1e2^2ol4o@ot8m;t?up%gSpwtPOCUp|f@}IWaar zeymYcGe1B1E)SjA5=1YL(gf*FA`+POZt?KpaM`$u+3go$}w$< zOmU*@bMPZ?N2+NdHYht)^06%5yV_WF&>6rgq1Y${ijC4TiZsRvy>5EMmU>9lxaK-# z-`ifPI3+CDnY(YWv=VL&{4{&_XWwM7zq~G3Znv^u)e-vHxa&>5vpG@s7~O6{_!ZVZd}hedEsa(t;1DxL)dH%6_0h2`!L#l&-zc*+HAk- zsOSab%hE5g zVPzxNL&}~xjpgH+y_WVS@9gU&tyZBYqy3=!>(>e$1AS>Q5hYlEJOmFCo9Qw4(StS) z)YJB^(3&AcWq^=C!c3jT+p^p{L*lEs{VXB+*z^nTgkeO*_pci!C((a5+jtfh0$*xB zqdvV>RiOV3_l&*5y5$ygpB!^{a7;>A#e-=EWo zhd>w|$u<~~FUy5ArST;ZwR2w5a|E$UDV7*zF*Ee?!I<3*>x774JzTV%FX3clWc&L8r%US^Q}V;@Nj=WZ5Ok2 zC662bqARz6)Xz9=_U<5_4^ssW;PzqUW*{mYOx@;6OL*@(apQCI>_rWxZR}&~u`ZE? zS@4(TX0WH?t{UiBST|?Q==1w`cM8BSXa)p?)U(Se?S9v)rTA~oX7SQeEZn;8Yt}HG)-hd?x0zMjDd2F8g}hdD6xXjxVr}&RQct=PaxREk3lB6nDWSX z{;v8VzKT&44U*O#7IP|gV>Htfu;6d(Ty93v#?Y(`MgC2Ptzcrc8HvA-nnduO01B#< z05~`Mx(`t<)ONoQ-LRP)&yU(zLe^s_Fd+H;oh90E$iBRW}1PjYu?k=$DfRW!84H0kpr-jB;pTs*f;76 zAf+$^ea)prksJ+SklU9#G`30(kMJvTk&on#ni&~@Lp$meETKm{Mhp^FBf(VjurOa7 zmKI~W6lm{`pdwdGYf8+mM@hCm24J$q8^Rm8SL4xfcNoILv$qKMX7i9A8IAH`nPb8VNN-ZD!N$?^@GE%)OD_ATxIDtkY@05ct+V1BA zFAD2}FWE@p4nCbHh=_~*Ll8z_>8Blt0JMoCq*@tJvFXTZa z`%4`dRmjq;(i}n9Y~~KZ|NjcPa#*F|=lMVDZ0wINa4T5y8juVwSXzS5g<;8+6d?bg z1WsHFq4^lVP3CPT5{=?a$!j5h}{$8{p` zWv$+!kcAgS2I@?o&Ufo#`r10E!D3mR@9=~FQ3L-|zntU%{^viSErvWciCtt%zE+dz zQ=soTuI-`~!J>@^PTO6SA0YKev4i8H`%~pENWg25M>*0O5o|fk0BDiLuE1wI1peuX z24M^itS9RAqZb@d-(Q|Qcm=u7Gq7L=2;kO_RJn~thbpae$F1dKqzWr{9IuQG?&*+dNR|joyVJ>tm^L zJzdOaEdsPX5gbW6;Dh{uCH7}x=e$xV%{blOt@1%e5cDTmfM#OPJ`vk;I*xyLF2Lun~=9uE(dZHx2x`!wx zSWri{Bz1Od;rL2nxGv%jQ068HWp4gQP^Ym8b9}9HCePlE6}htpJ=-!X)+7*u&%2zo zU47Gd#jTJ1mlwd+K*rqkauoyUY?*+a(LpO*i z1IouXhnXzlLbpsZd{jbIh`mrU!jl)Wo|+d1cJF0oQc61~RN=~#14cmL{REiY3PSKR0dg{H%ynATC|eQ+ zNO`^F8tH`tH{zumuc2#+ML8Vgk{?01V<%$D28d2BRLZlJLmxk!vQ*@-R_rNcQ?4?g z^xtQ(d;(R1_e?}QlexWAFggu-ZdQof0MZqT_-~L&>4x#ZMy?oc`pz_vgWBpZwpX!8 zJh*fPE$!Et4TlKiQ$a`A#GmeTaDH5XeQxD2R)LUB9q|}XYg1mKqg{1ejbA?#F+_%^ zlc%4r_(b&M#0dUkL7|GJPhBJ874V06T;yQG@p3A`Blu9)fj5(REB%=Wd3rM*)Y_#h zZgFdiI3VhU0w-DG>z;n(TMz{04yHLD@HUrR<~{H>J_G@nN4p^%SkpOLs={&jmtQ?r zcBXVmJIw&W!m{|nv0_(Mh<)Gf13Ma)FtX;PH>N7yl@^pH~$9B!&P%*&B83UETC*tGO@SON{I zh{M*nW1?eILwsioC5h%)-CiI!In);m=v}4eMMAV$D_uu#i=ZN*EABHA7#|@AiW2;Q zd+?@I@W1p=t3kG@9Hf&-ufu!|0f%D)7O=xe)Prw0aFBU<-lr~rLW*LL0_3%47lX~x zMose~{zhfQ#6~9QV)kqe7UjtCK-yvyU?NS9mxi}t^fiEwKZ9WSe>*Xr%D_nvZUKQ~ z7Zly2v4s*Iwhy)>F@hYADhRFz{S_d8lpk);^RuKJd#VnCZ1p9QpfhGs2=09z5n4c* z4-(Ky&*r107d@N#LIhiW;%F;-sVP<;%n<`i%-Qn-x z%+2EMkUaENKU^ijm^!p~H1Tj(?Y>0522yXAlh1>-OZgSHp1##LEsBx?uiyYyDEdVZ z{OA({i}SCphS%B@ewu@V1MSYrHIrnr4=4ATSZ=H0V)j*JlS|ZN8dhnmLOrWQPZOad zU=abn^PV0pxW!kM z497(^!UV$K*nt`UCuC^mj~DbT8dn=BY3=-L*RWG-z%D7OU)rpquZdF3j!nV}Z8RTP zl+HRF^WT>?VJL*+wl7ew*dN&f1u^jmou_@o_Mtv?<`6*c(auUT#rO)ZmHJMujQb2| zW7F$<)9T}9wL7)!i4#V@@-hpUk|Fr?{s0O976q|X`Yy#KX69@qIUI8D7i795*V$&3 zYksvZ$wtoJb4@Ga%*ivIG1C+ez6`kQI`9Ol&R>AqO51iQ)(GG_*5SKRg*n%Z(w#J? znI})Yc;OK9OPDCmupMBGbl}zH83g42Mcdp~qT4w+ zx(8Qsy=^_L3oDTFFWgr#ugiq~4AT~1%?(E~^MM^U0Xw{~hyX3uXgnt&>a5#*{6}gH zMx&F!Z5O2NTEj#UW#o5gE*)o@>K}c(8~YN_l|;wmLkw1o;E_Rz@zVjQ+V_7MXV8Y-M*RT- z6Ua6KR5ERK*^ThKPNc7*qY^D$TbKcf@{^@k_`z%Bw*|>=oQg{WmS|(x#Bc6O`))m7 z4n=+FNBlRK1rWj&nR1Q_c3WRHgE6|*MA9XCBs$L5^UdP24it+lCEnduxgILZpUsRP zwC8Gu)%H(+Y^NGn+!Z-wKJ++Mb$M3W&B6rDLyd&oQWbto= z3eeDniV^*)-PaxcHQE?Foa#d!3pvB*p`Qu;c9Vhn5;cbNDn|AJs(Ki$DA`BM#kSyfltx!k?*6?PXCgo z2yjo{tegASjU$TXf?XLiwuc%Bn!mexckgyjhYj))=U0}faya_DPJXobZRlN@V(3fH z@>Er!)_pmU{*u0-352Q`miSI@Bp*e2cz%;ieV#>ihjB&p;MDd7p5m-Sh3&Q|I ziRQ4iLnh>eqB|5~Q|R2?>wZ{RIN~JQ_9nl}y6Je$Mi^QWY+ztgcOsL)&k4YTIGobt z>^)&fYp4<=WH7_tC@SAzzj-XMJ?EAkL)#Psq~Z z_&3xK&&l}Y<6=S4leYZ14I zq@-;*b^;z0_5S4q=n7hb)e2-WkMf#L#)3~%$|uhyw|`#k`a+ebVCT8|`Kes#$K_{x zgpnT&23!jr&9@r`Vw5UUlkLo};Xpa94~RW0AEev`VGK$Yp&y5-N%Zxb+=MSLU#35Li~ursIJH1_OKrfrRO#4xNN-Lu4@I$dss5a9=>E@8(O{gA zn;q{lXZ^P_{`b1>&|~fI>KRV?UMy3EjHu^-jbimb6vqm>HpJ12YBC!iPhmww|9}}p-}3yfcJVGZ?DXLY;ng{##7f3{ z_9{i9O9G~aFl4Fjwa&wz@0I6wJ6PW}w9zeSmx4O=8-x3hfJayh*zS!(8!uoyd2*;n zjKREsB23lV@j3uM%kSHv;NH4GfyU3G0QRkYr@o@TRm?F-!(R0+d2ae&Pom2n0WrE# zldB4hln#iGCLr7*#EJ#lI5Y)UZ+~iSZtzjlxc_}k6o|mPVmzNlH7GM>p5xGY*$IrR zpDJp!u4_Oj%VS1>ao3$2TsG6mr9x_`)wnU04bcz z@t`u%*#boOymlV-h1{-#Sen6C3WgF-%K$s)7a$wQ_5RHc*;Fl783o#hZ@Pm$rLl4y6L_eo~_0ilMSN8D5Z(&!_feaF( zj{*0_T!!T#Hb=wLJ$a3*Ql-_i{JvT}@l)SR;RGhIbjsjKCc?A@K)Ozb>W)4$+W(JK zIee$nfnsjAV1Of4_WU**X3?T`F z4tXvBDj-&`_Va~xsUoX+2u8v4Q^}h{rg}Bb1qr0c^QGXi)!6ebs~!Nrh0S?7fO~$i zko?1(dF-pGL>E?mqOztz?~^-`<%U8h&nI<_Q9mkLIRFKFTr`v%Iv9F*0EhaQV!_}_ zgf|SZE-bH1?7d7n@@N0}k`N}-9rIOOUJx4Yt*s|!d==__kiGVI;xX{^s;hw=3_2Ay zueC^QLt}7yH7}J8*LVPHozCF?8uY98p`HZ*_Ca2V0EdA1=G^Tt0-NUZCk4A*-cODf zmI~-A(iF4rsg2b+CuXKDPe0=;;Vp78T@5^UMrmH$GxtM%A1ien>b#!+x{ahFE|CvR z*-Pa2hrpC_GQb=hfB1jeyYhdkx36zFG8SbDU9-%jOqDoP*OVb-$XKR|l$0pbxlLrq ztPmHf;NIp;kO6Y0MG>3nMC)s3RDM8@5hG&VC+$cBv4Yq;VJ-K(8_}#2q%YLe~ z-Ohw|*1WalW47T;vrSQp^;)%*npLZgOyi5^&$sA|4)W@k8!EaUtuu&NrOq_htsk_k zR;!<6Lw+UGb-+9bd+ytUC?4mm2wJw#AM1HtOB0b_6XGvHjGE*%Y-+v-SmeYV{m&0p zB|~*Pvn7K-c=oA&VR5HX$rHl$`5hvcLcxjrEj>leg`xB(+4iJ zsBu;wWjm%W8Vz=1+^*VszF_s}e7>~^Xq+mqt=c|w)Wo%A{S*Kh8ZQg@j#EN6Ygda* z^)z@`FOdbz^|>KQU<#T_CqM_;u6Nri&UbjU&wUwu*L!1ufqb4@U2@t%up}-_-1}R&uiC-ts|2J#i7fy+o(6|o#lR%pOM%a z6GMHSbQ5fPY(Qb>&L(q%|v3|{08!t}D3 zsguUUxj`Sr#T+LYl(h7OG?dexU9S;8JGV-yC^V+6EOK`8{pF0(B4-(RYNlej;46`5 zsp1G@QGv3ReQwtS5S5Q`s>aE3`)gOIkFA!lRCF1BBvHQTOU;J?h1fA91ITw&XERm@ zVuW`PY}mC#T{Twr?bsIuQHc@5h~|9eb1B!b?4CH(T}d$p)=#AJ79mojIP@ILjf1YN zUlVf}LhmOLpV0O3D8vIi8f70)bk>CGT#qD?qs@^_gfB;K(Rd+W@~9hqN43o`LtV?! zjXEcEMZ%~IX{eoG#+C0$wIeaVec^&jZ@Lf;wO3A+5dR8Zv)yfOreQDk7R{T7>W;CJ zkZ6T;2JutntP5bnuX~H%LRNc%x4Y6WOz!H+9}AKOH_^n|XyW_o?Ep_$X911xy%%bL z!L*N|XGTNXG(JTV0FEY^)%|gEN4d~0H^DBw?lN2e_TY3lkPq-Z*k9_p7|J~Y8k1Np znU2~5DzuL7MzkuUL?PD11mUx=>xi7q$`UV?A>#s&9v@OUw%(-VeBc=8TSS}}%39ak zh#+5GmQI9OvF^0MD(R3*}#&MS%gSdwW#!=K%VJPhS z$4Wo|Rb3SfTj@rKFiNqR zBe!rKLMYDDa5iaa4!0rru46uOmC_np8dybc%7({p+71x|hRIfHRBeb~R2uIpqYH8l z;aENen8C}Yi+04-ccqnrcxaDlm5>sGP3<&wa8QVwc%ciz)t|_}gpQ~dRg6<|vrU05 z;l$c>%f^1mv|omm9T2T1GX*SsF~qt)dSX!)o?-;_45V7+0sqrk<$^~K^eDULwQ^&# zi$Xpl5umNCUi!B*&}Ab-$z|$i2Wl7avv+E$SqQJ}=0Us6FcbD6@hpwJuR4~E_XODh z4;^HDDhKFc@&mQWP6_vTmITqs9ZNkMSk{-;=ed^82d&vU-HjM<4DRvcbo$*$W<5D~ zr87-^HBu{<$~gOq4V;vB+nDUaO1wWl_Z>WdW~XID*FMxp3jTt>K`eM{=+f&bXtp&O zc(;6VBq+gOlMZNaD^Mqk|1R9LX=R&}pht5Np&@X4Xg=CEc?gq4y zDRQ8o0bAiRGk7vpBiB69h(6rN`t0c*TK$fur0YwZYZ|iUdzRxhfJKFYmPZLtPOqASzCjB$ z<*Zrz5C{H|$!EGQR(NSb14%?yeu;AG>%EW^43IPRl9Su_m8zvb6TzoxnSml6ydp^8 zl@{I}8tx*c(95?zXcR5N%n zQkbKNm^_`{G`@aSe0WG5HoGca_zgbyxU_$Ax!5lcbS5acQ2rf`qe_vplJFcRj1R}n z7g$TXN@TS!chK@gHtYhaISf%mRHDBL^<#L}QS6%xs7{oYev$?0$iH}Z@oviB$}1_q zJkLxOo`;{2nevqsmeQ%CjDhBgHxTs>pam$Ud|869NJcUk6S??r*2y%TF2m<>8j^(< z#?|j3jr3dFt%`$2GATBCx}oj*B6s3#yu(Ta{mw+|7Q&_Sv!Sf4SBv@x2KJLA%rITT z3KZ4eb-Rry(&6ncbqV8gan{#DIOF{$I|i(sZM(;(qaleyYRC zpg(dH8ae@6^p6@Bumuk8g$~>zS+*glhOjaqw9_3X``PdA3e8dR*uYnyM>wMR-yxl% zxy^d5(NDUmC4tp3_}IfU9aBfY#@`MJW-wr30X=$I56+W%7+DNF@fux>V18IEHisNf zHz25&W^Sfrs%w$I#PEU8g3^NgRlt?b&eYYavnLxE5n(7f&JfCmLd8XGC(`)d8Su$a zj}`k@Gcmeat_D)KqLAZm9p9k3?xZ<$Q0XH1dPmG~FrX1HU6PD(@I zp1pEH{F3X8WuDVkgUC)XEgk{lT6d;iK>An~x8>(&0d*UIQoi7Rt%UH^T;0>37iI^xPfj$uvpOcf4u@hO=Ub_=-+z2sdU8Gwt;N9v zSs@BLN)o`MPw+Oo_bfAQO15#a=aEf1;9s)F3nVQCucxm!xr;p;G`K(JvzrbXil;Ol zG^h4o+VJ(vGfE0gRiXR!M$fIxxmAuM`WIayj(_s;au&Uh413!BCO zV8kNxl?O(1Cy%vTzJizL@o~y~`%b}dTJT3S2y2avGt|mal3PI&Gkf$S#KZsKW3kwN zC!t2xvgzB)QN5X8d|n3Ob{tbThyV(rFCQK!r;dkTkw#rq_>42OUbK&ULot9YE>Fa1 zU|S*e2eVmf3U7skuxRXnkBa(UE`kgu{sZPFr14uqkYav_peZmM+%zVXQ;4`#x9nbv z(99gBGHv-*ihT2*q;mVJE88`gqC%_~P;j!7?DK3Yx6aD_?h6=*{BorubF1p`l@-_! z4#56N0_8Zin8>)Dx6X4_K?CbCx~#YGsjGYLU)NX_z6{sN$PFMBA0P*3ubCEr89WP? zi-Nu}scXNqvH*G{^HErpu9r3Qsl6<8m8WMuv&{*V=Yn$wWAF@k+Wmuso(O_QDyF-4 zSOOMGKDt8Sm@xj51aI@m5sKQ)mL|TgH*|}Pdd~#QNe!U;#<7?VBUkVIC4|YT1@lEd z&E^VzigcI8i-bMXWwc}mA(80J;g#pxD63+#z|fWOzup@+u$it*D0;^_=@Ye z!+ab(w3o3qlx*nXLuJJMoZ_AfMuSwoq z*SPuF!*nAo>sr;*+0~avoM275FDlrY87Rs=CF6@!Eywxe8UB+47v}5IV&6=BzQ4st z0~N`4dz2w(9D3Kh4{M4e)g_!!4*qV<=pF3o{z=wDhZ>l>9K^0s=Q+w5{DRAJr+8_7 zV(RwZ(U5_h$vez%prIv!r)2$SBOW^gUzRug9&~KWKduqn@Q1`N7xtWP=^n$O{3H1M z+Llp#l3(kcsT;bTqtFagQ$lhC_Ewft6&~^+u7%SLM4rIqZozOGCUps9r)A&ODv~u9 zs=-+7CCuX{{K= zEFdg7u(|!0P!|J?u_QF`t3=q+6(mv@KFdxUC3o|Ozua1QoM_j54*X=jre+&U_7*>E zF(wP}>@#$D958OS=?m{uu)Om5;-l1nuKU}%G6=@GaZlJ8nhjTZYZi<0{mzx#O``r@ zloAh%=46H;uSytp*s|#N-Dl+~>baK4HvXe;Xe$lD6bHrsrgk+lOX?!;*Wv3Iq*joA zhyNc2gAKRyZ8&H~bR(Sf%bx>tQZEigBIIg{nHaAS%W!rMiTzpK3Aq_HOK`vfrSOdy z(O$@pPP`|~jtLWq;f$J>T;N27k#WVynXp{ju9;~*4uUiDj@~M(#OnDMtG{0A0$}=l zzP&#?Vi2mSfRFm>$i{Q033MtRUC>T;CtkCBK=hKWveiA7=YhiK0g`RAI_6O{He`|s z*+WKdb3o>Tm!|;UKP`uvnHni`*WEyrIPeO@m zS#q!=wBWLga3IhBKJdL^RT;Q0Lhp3TxR*H{^RH0!uGp&XTpV5?j-$ylMhX}rBq3!h5!GWTGx&>mqmjviCBXudP|8*0qOEh%V9XG~kwJ3Ie?ddT za#{b7wuRfz-u3}&*^JlGK458c41U%}%JfEdaWQeZxs%EmSY3bg`xjjr&}bZ}(beX; zj)@%}{}c|hlzIqL*HeWU&}fcm9_dD;ISo&BgoWK%IA1y;(_;7L+~gfC2IKjbIO+kC zRp=5wa#w+*AQYmH_T>0tNAeCQ`tTu0uO!+}L^ghpvxv4AZ(-s(CF(vQVWs?iiqK+7 z9fe5iLBETCV}fJ^OA4UVhhP_E%Y^W)yBp7$(Gw=Ack+&4dx^VAF7*DTy_IU{t%$EBFh_UY+V`L<`Awax8&SP2h?ypZiV&08PoZ2qG|iT(1gQ$p%L9z~<~G}BX+QF0q@|+! zf3Xe8+5-rhP7>@AC51e@d$(QE9_9^QO_4y(ak9~w4Y{K5(iUqwsnQ{NE)`ITS05Vf zt%rnRX#}}t0a`uvEsjJS;#>LiZAbj$WEF`Q+0!eETDp8%x&m4$R{Zf?Tn73l2-C;5 zFDg?<$-zNSI|5qOE7i!P)}~mES)A6CYwEawq7dd6NU)*9H<4Q*?GAhzYvor*=}FrZB3!mbAx&^O{rAsv zkVcm<+VNli9mfTE5z|l;l+pb^OZ>Zm-wgTp1pXr!|BBG>OY-j}{(U$8)k6Q#ng6QM i-*@Bxfgz);)BZT+@S$?S(4Pi==^r*eRG{PZ*Z%+zPF!99 diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt.png deleted file mode 100644 index d12a29728974662e984a5a251c2442f48ec77c0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 740 zcmVPx%o=HSOR5%f>luJw#Q51&%sVD*4no06;n&cRTnZ?;TV~5M9jZiP zP7Z$4G$v>-R#lY4KR%ASox9-a@0Wy1mOM8)8l{c(&}U@uNkOK}PY)kq>5lElKYa?# zhmY`kLPhdYOb06otk3#{^zGUC3rs61EJ#Q|U}_2~-6A0)M3)5W)|g1p%PUtgVzZ(B z#!b+6JLthdC?X;-)YTmV5gL*}dcaO%jN7(?QYa7=qhWx9NXX7YV0s!|cj|bwar?9w|ke$g^{G ze8AZ7FbtcEVQXrJe{4+1;dN2T^OQ=IH$8y)_%UW=vf*>PajS46?(f?VufqYgUXQFQ z3lEs7h=7aDW_)ga3|n&x>0b|1zNfDrf0z?l&zvRs`pmU6IlL|EVV~7XHkTBxCsJ!P z^1-pjRHCy(F1JKLF3|q`1w70jg&pM5hI;&9E@DO59Px)$w@>(R9FekSbI>ERTTd%yDZ341zF|givoGr_&`ubK{IsG012WYXNzUYPka56#`J%*9v$5T)d$xorSpa5sqJO^V_v)w>djvSJh%^MM# zmjF3@COKAzU;n! zEM_zMy1QwA$DO-4HaDK}_Z=kZaOjX&`ub3ln1LftJcj^!4-z`>zY8wszL9gs>YRacpR46qd|{(GP{d z+}#83pg`)|NuxpJ(<$f?4n|$U?@I6t(RJvM47L`#bu;F@{u)$H16!NSaK?sB=78E&u9kVZgDYArL2Upv5Coe3A+GJ zS}-3A-r6bKccR0_vNGt?(h;+1BfY#udD%}Fac1p0k>&mltOe(g=$F9RdVz@1#Wj75gp`~n(PR%d+2oT~+3=H5P_A0Ld(%994}CH4&qWsV6^ zaP$}hCwA26^FgAB*hrYuy1R)inky<9%}a0tbn)_%+3XYozqQuc&_Kl`1@nstXDSvU zEvvY4mGQg;H^8=9d72auJ#&Z;5(^;q z746PW-HIv8o)lU74PUVwWfw2O)Y^)uRV!H^33)mD_A_1y!5xcx3`UyP`-S%}8=0-p z#3yKy+EP`8$dnX3viey}eslr60s~|iNM=)Y?H8Ghmr)c+Tt|+?x~xm^^7p6q$!zr) z3 zyn}<_?&l}uhsjJQVaFS|`SodJWO=#0liXTA!)EK4t=XJ{BkCB1nx)c? zXrd^Rh|b8D)Fja_z91DnkUqbD1Fe-GsAQ$nt{EhDuI}1Ri*_qEhlup)N9+Pe3@M5v zQqLr|mXO0^G1Jm>@T(Tl?P_U3=GIgce0)?oR1t0W5=*_f`T8ImL>oI002ovPDHLkV1k95 B?MDCr diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png deleted file mode 100644 index 7f1668dd5b3b7b9548442b1a9ffdef09e26c5fbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1551 zcmV+q2JrcbP)Px)$w@>(R9FekSbI>ERTTd%yDZ341zF|givoGr_&`ubK{IsG012WYXNzUYPka56#`J%*9v$5T)d$xorSpa5sqJO^V_v)w>djvSJh%^MM# zmjF3@COKAzU;n! zEM_zMy1QwA$DO-4HaDK}_Z=kZaOjX&`ub3ln1LftJcj^!4-z`>zY8wszL9gs>YRacpR46qd|{(GP{d z+}#83pg`)|NuxpJ(<$f?4n|$U?@I6t(RJvM47L`#bu;F@{u)$H16!NSaK?sB=78E&u9kVZgDYArL2Upv5Coe3A+GJ zS}-3A-r6bKccR0_vNGt?(h;+1BfY#udD%}Fac1p0k>&mltOe(g=$F9RdVz@1#Wj75gp`~n(PR%d+2oT~+3=H5P_A0Ld(%994}CH4&qWsV6^ zaP$}hCwA26^FgAB*hrYuy1R)inky<9%}a0tbn)_%+3XYozqQuc&_Kl`1@nstXDSvU zEvvY4mGQg;H^8=9d72auJ#&Z;5(^;q z746PW-HIv8o)lU74PUVwWfw2O)Y^)uRV!H^33)mD_A_1y!5xcx3`UyP`-S%}8=0-p z#3yKy+EP`8$dnX3viey}eslr60s~|iNM=)Y?H8Ghmr)c+Tt|+?x~xm^^7p6q$!zr) z3 zyn}<_?&l}uhsjJQVaFS|`SodJWO=#0liXTA!)EK4t=XJ{BkCB1nx)c? zXrd^Rh|b8D)Fja_z91DnkUqbD1Fe-GsAQ$nt{EhDuI}1Ri*_qEhlup)N9+Pe3@M5v zQqLr|mXO0^G1Jm>@T(Tl?P_U3=GIgce0)?oR1t0W5=*_f`T8ImL>oI002ovPDHLkV1k95 B?MDCr diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png deleted file mode 100644 index 28c67d4af524cf87832cced99a5fcbc813b6073d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2328 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 diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png deleted file mode 100644 index ed8332ff558c0914538c2da81f08678b2093cd2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2223 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 diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png deleted file mode 100644 index e436f81bb294d29d740428275442054f62fcc6fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 B?MDCr diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png deleted file mode 100644 index d0e7d2c2a410b8ccac64157a89f609fa955a8cb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3156 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 Z{{#6!COf-&2OIzZ002ovPDHLkV1hjU=Li4* diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png deleted file mode 100644 index 410f08228228d2ffdc73a1349b9234beeb8dc270..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4839 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 M07*qoM6N<$g4=s(;{X5v diff --git a/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png b/WireGuard/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png deleted file mode 100644 index f575275a8d00674fee6ce17ec73135cd943fba79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7101 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 diff --git a/WireGuard/Assets.xcassets/Arrow.imageset/Arrow.pdf b/WireGuard/Assets.xcassets/Arrow.imageset/Arrow.pdf deleted file mode 100644 index 781e3095b509097d311a25b04028b11c52b9d6be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8558 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 PVjw6Oz|F0wp#=CpqgZtL diff --git a/WireGuard/Assets.xcassets/Arrow.imageset/Contents.json b/WireGuard/Assets.xcassets/Arrow.imageset/Contents.json deleted file mode 100644 index 77459c6..0000000 --- a/WireGuard/Assets.xcassets/Arrow.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Arrow.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/WireGuard/Assets.xcassets/Contents.json b/WireGuard/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/WireGuard/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/WireGuard/Assets.xcassets/settings.imageset/Contents.json b/WireGuard/Assets.xcassets/settings.imageset/Contents.json deleted file mode 100644 index ab3fbb2..0000000 --- a/WireGuard/Assets.xcassets/settings.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Dots.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/WireGuard/Assets.xcassets/settings.imageset/Dots.pdf b/WireGuard/Assets.xcassets/settings.imageset/Dots.pdf deleted file mode 100644 index c5a2168b6210d9f67c951b914af7fee3a1447390..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4016 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 Bw1@xz diff --git a/WireGuard/Assets.xcassets/wireguard.imageset/Contents.json b/WireGuard/Assets.xcassets/wireguard.imageset/Contents.json deleted file mode 100644 index 6c935c1..0000000 --- a/WireGuard/Assets.xcassets/wireguard.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "wireguard.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/WireGuard/Assets.xcassets/wireguard.imageset/wireguard.pdf b/WireGuard/Assets.xcassets/wireguard.imageset/wireguard.pdf deleted file mode 100644 index f404859f1125f9f466a941af1c528ca04b8afe39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15345 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WireGuard/Base.lproj/Main.storyboard b/WireGuard/Base.lproj/Main.storyboard deleted file mode 100644 index c9ae86c..0000000 --- a/WireGuard/Base.lproj/Main.storyboard +++ /dev/null @@ -1,1010 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WireGuard/Coordinators/AppCoordinator+QRScanViewControllerDelegate.swift b/WireGuard/Coordinators/AppCoordinator+QRScanViewControllerDelegate.swift deleted file mode 100644 index d76470b..0000000 --- a/WireGuard/Coordinators/AppCoordinator+QRScanViewControllerDelegate.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension AppCoordinator: QRScanViewControllerDelegate { - func didSave(tunnel: Tunnel, qrScanViewController: QRScanViewController) { - qrScanViewController.navigationController?.popViewController(animated: true) - showTunnelInfoViewController(tunnel: tunnel, context: tunnel.managedObjectContext!) - saveTunnel(tunnel) - } - - func didCancel(qrScanViewController: QRScanViewController) { - qrScanViewController.navigationController?.popViewController(animated: true) - } -} diff --git a/WireGuard/Coordinators/AppCoordinator+SettingsTableViewControllerDelegate.swift b/WireGuard/Coordinators/AppCoordinator+SettingsTableViewControllerDelegate.swift deleted file mode 100644 index 9961043..0000000 --- a/WireGuard/Coordinators/AppCoordinator+SettingsTableViewControllerDelegate.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import PromiseKit -import NetworkExtension - -enum GoVersionCoordinatorError: Error { - case noEnabledSession - case noResponse -} - -extension AppCoordinator: SettingsTableViewControllerDelegate { - func exportTunnels(settingsTableViewController: SettingsTableViewController, sourceView: UIView) { - self.exportConfigs(sourceView: sourceView) - } -} diff --git a/WireGuard/Coordinators/AppCoordinator+TunnelConfigurationTableViewControllerDelegate.swift b/WireGuard/Coordinators/AppCoordinator+TunnelConfigurationTableViewControllerDelegate.swift deleted file mode 100644 index 0b96762..0000000 --- a/WireGuard/Coordinators/AppCoordinator+TunnelConfigurationTableViewControllerDelegate.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension AppCoordinator: TunnelConfigurationTableViewControllerDelegate { - func didSave(tunnel: Tunnel, tunnelConfigurationTableViewController: TunnelConfigurationTableViewController) { - saveTunnel(tunnel) - } -} diff --git a/WireGuard/Coordinators/AppCoordinator+TunnelInfoTableViewControllerDelegate.swift b/WireGuard/Coordinators/AppCoordinator+TunnelInfoTableViewControllerDelegate.swift deleted file mode 100644 index aa6f3f2..0000000 --- a/WireGuard/Coordinators/AppCoordinator+TunnelInfoTableViewControllerDelegate.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import NetworkExtension - -extension AppCoordinator: TunnelInfoTableViewControllerDelegate { - func connect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) { - connect(tunnel: tunnel) - } - - func disconnect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) { - disconnect(tunnel: tunnel) - } - - func status(for tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) -> NEVPNStatus { - let session = self.providerManager(for: tunnel)?.connection as? NETunnelProviderSession - return session?.status ?? .invalid - } - - func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) { - let editContext = persistentContainer.newBackgroundContext() - var backgroundTunnel: Tunnel? - editContext.performAndWait { - backgroundTunnel = editContext.object(with: tunnel.objectID) as? Tunnel - } - - showTunnelConfigurationViewController(tunnel: backgroundTunnel, context: editContext) - } - -} diff --git a/WireGuard/Coordinators/AppCoordinator+TunnelsTableViewControllerDelegate.swift b/WireGuard/Coordinators/AppCoordinator+TunnelsTableViewControllerDelegate.swift deleted file mode 100644 index 0357c40..0000000 --- a/WireGuard/Coordinators/AppCoordinator+TunnelsTableViewControllerDelegate.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import NetworkExtension -import os.log - -import MobileCoreServices - -import ZIPFoundation -import PromiseKit - -extension AppCoordinator: TunnelsTableViewControllerDelegate { - func status(for tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) -> NEVPNStatus { - let session = self.providerManager(for: tunnel)?.connection as? NETunnelProviderSession - return session?.status ?? .invalid - } - - func addProvider(tunnelsTableViewController: TunnelsTableViewController) { - let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("Create from file or archive", comment: ""), style: .default) { [unowned self] _ in - self.addProviderFromFile() - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("Create from QR code", comment: ""), style: .default) { [unowned self] _ in - self.addProviderWithQRScan() - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("Create from scratch", comment: ""), style: .default) { [unowned self] _ in - self.addProviderManually() - }) - actionSheet.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel)) - - tunnelsTableViewController.present(actionSheet, animated: true, completion: nil) - } - - func addProviderFromFile() { - let documentPickerController = UIDocumentPickerViewController(documentTypes: [String(kUTTypeZipArchive), "com.wireguard.config.quick"], in: .import) - documentPickerController.delegate = documentPickerDelegateObject - tunnelsTableViewController.present(documentPickerController, animated: true, completion: nil) - } - - func addProviderManually() { - let addContext = persistentContainer.newBackgroundContext() - showTunnelConfigurationViewController(tunnel: nil, context: addContext) - } - - func addProviderWithQRScan() { - let addContext = persistentContainer.newBackgroundContext() - - let qrScanViewController = storyboard.instantiateViewController(type: QRScanViewController.self) - - qrScanViewController.configure(context: addContext, delegate: self) - - self.navigationController.pushViewController(qrScanViewController, animated: true) - } - - func connect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) { - connect(tunnel: tunnel) - } - - func disconnect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) { - disconnect(tunnel: tunnel) - } - - func info(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) { - showTunnelInfoViewController(tunnel: tunnel, context: self.persistentContainer.viewContext) - } - - func delete(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) { - if let moc = tunnel.managedObjectContext { - moc.perform { - moc.delete(tunnel) - moc.saveContextToStore() - } - let manager = providerManager(for: tunnel) - manager?.removeFromPreferences { (error) in - if let error = error { - os_log("error removing preferences: %{public}@", log: Log.general, type: .error, error.localizedDescription) - return - } - self.providerManagers?.removeAll { $0 == manager } - os_log("removed preferences", log: Log.general, type: .info) - } - } - } - - func saveTunnel(_ tunnel: Tunnel) { - let manager = providerManager(for: tunnel) ?? NETunnelProviderManager() - manager.localizedDescription = tunnel.title - - let protocolConfiguration = NETunnelProviderProtocol() - protocolConfiguration.providerBundleIdentifier = VPNBUNDLE - protocolConfiguration.serverAddress = (tunnel.peers?.array as? [Peer])?.compactMap { $0.endpoint}.joined(separator: ", ") - protocolConfiguration.providerConfiguration = tunnel.generateProviderConfiguration() - - manager.protocolConfiguration = protocolConfiguration - let connectRule = NEOnDemandRuleConnect() - connectRule.interfaceTypeMatch = .any - manager.onDemandRules = [connectRule] - - manager.saveToPreferences { (error) in - if let error = error { - os_log("error saving preferences: %{public}@", log: Log.general, type: .error, error.localizedDescription) - return - } - os_log("saved preferences", log: Log.general, type: .info) - } - - _ = refreshProviderManagers().then { () -> Promise in - self.navigationController.popViewController(animated: true) - return Promise.value(()) - } - } -} diff --git a/WireGuard/Coordinators/AppCoordinator.swift b/WireGuard/Coordinators/AppCoordinator.swift deleted file mode 100644 index aa20c16..0000000 --- a/WireGuard/Coordinators/AppCoordinator.swift +++ /dev/null @@ -1,468 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import NetworkExtension -import os.log -import ZIPFoundation -import PromiseKit - -import CoreData -import BNRCoreDataStack - -import MobileCoreServices - -enum AppCoordinatorError: Error { - case configImportError(msg: String) -} - -extension UINavigationController: Identifyable {} - -let APPGROUP = "group.com.wireguard.ios" -let VPNBUNDLE = "com.wireguard.ios.network-extension" - -class AppCoordinator: RootViewCoordinator { // swiftlint:disable:this type_body_length - - let persistentContainer = NSPersistentContainer(name: "WireGuard") - let storyboard = UIStoryboard(name: "Main", bundle: nil) - var providerManagers: [NETunnelProviderManager]? - let documentPickerDelegateObject: AppDocumentPickerDelegate - - // MARK: - Properties - - var childCoordinators: [Coordinator] = [] - - var rootViewController: UIViewController { - return self.tunnelsTableViewController - } - - var tunnelsTableViewController: TunnelsTableViewController! - - /// Window to manage - let window: UIWindow - - let navigationController: UINavigationController = { - let navController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(type: UINavigationController.self) - return navController - }() - - // MARK: - Init - public init(window: UIWindow) { - self.window = window - - self.window.rootViewController = self.navigationController - self.window.makeKeyAndVisible() - - documentPickerDelegateObject = AppDocumentPickerDelegate() - documentPickerDelegateObject.appCoordinator = self - - NotificationCenter.default.addObserver(self, - selector: #selector(VPNStatusDidChange(notification:)), - name: .NEVPNStatusDidChange, - object: nil) - } - - // MARK: - Functions - - /// Starts the coordinator - public func start() { - _ = refreshProviderManagers().then { () -> Promise in - self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true - self.persistentContainer.loadPersistentStores { [weak self] (_, error) in - if let error = error { - os_log("Unable to load Persistent Store: %{public}@", log: Log.general, type: .error, error.localizedDescription) - } else { - DispatchQueue.main.async { - //start - if let tunnelsTableViewController = self?.storyboard.instantiateViewController(type: TunnelsTableViewController.self) { - self?.tunnelsTableViewController = tunnelsTableViewController - self?.tunnelsTableViewController.viewContext = self?.persistentContainer.viewContext - self?.tunnelsTableViewController.delegate = self - self?.navigationController.viewControllers = [tunnelsTableViewController] - } - } - } - } - return Promise.value(()) - } - } - - func refreshProviderManagers() -> Promise { - return Promise { (resolver) in - NETunnelProviderManager.loadAllFromPreferences { [weak self] (managers, error) in - if let error = error { - os_log("Unable to load provider managers: %{public}@", log: Log.general, type: .error, error.localizedDescription) - } - self?.providerManagers = managers - resolver.fulfill(()) - } - } - } - - func importConfig(config: URL) throws { - do { - try importConfig(configString: try String(contentsOf: config), title: config.deletingPathExtension().lastPathComponent) - } catch { - throw AppCoordinatorError.configImportError(msg: "Failed") - } - } - - func importConfig(configString: String, title: String) throws { - do { - let addContext = persistentContainer.newBackgroundContext() - let tunnel = try Tunnel.fromConfig(configString, context: addContext) - tunnel.title = title - addContext.saveContext() - self.saveTunnel(tunnel) - } catch { - throw AppCoordinatorError.configImportError(msg: "Failed") - } - } - - func importConfigs(configZip: URL) throws { - if let archive = Archive(url: configZip, accessMode: .read) { - for entry in archive { - var entryData = Data(capacity: 0) - _ = try archive.extract(entry) { (data) in - entryData.append(data) - } - if let config = String(data: entryData, encoding: .utf8) { - try importConfig(configString: config, title: entry.path) - } - } - } - } - - func checkAndCleanConfigs() { - _ = refreshProviderManagers().then { () -> Promise in - guard let providerManagers = self.providerManagers else { - return Promise.value(()) - } - let tunnels = try Tunnel.allInContext(self.persistentContainer.viewContext) - let tunnelIdentifiers = tunnels.compactMap {$0.tunnelIdentifier} - - let unknownManagers = providerManagers.filter { - guard let prot = $0.protocolConfiguration as? NETunnelProviderProtocol else { - return false - } - guard let candidateTunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else { - return false - } - - return !tunnelIdentifiers.contains(candidateTunnelIdentifier) - } - - let deletionPromises = unknownManagers.map({ (manager) -> Promise in - return Promise(resolver: { resolver in - return manager.removeFromPreferences(completionHandler: { (error) in - if let error = error { - resolver.reject(error) - } else { - resolver.fulfill(manager) - } - }) - }) - }) - - return when(resolved: deletionPromises).asVoid() - - } - } - - // swiftlint:disable next function_body_length - func exportConfigs(sourceView: UIView) { - guard let path = FileManager.default - .urls(for: .documentDirectory, in: .userDomainMask).first else { - return - } - let saveFileURL = path.appendingPathComponent("wireguard-export.zip") - do { - try FileManager.default.removeItem(at: saveFileURL) - } catch { - os_log("Failed to delete file: %{public}@ : %{public}@", log: Log.general, type: .error, saveFileURL.absoluteString, error.localizedDescription) - } - - guard let archive = Archive(url: saveFileURL, accessMode: .create) else { - return - } - - do { - var tunnelsByTitle = [String: [Tunnel]]() - let tunnels = try Tunnel.allInContext(persistentContainer.viewContext) - tunnels.forEach { - guard let title = $0.title ?? $0.tunnelIdentifier else { - // there is always a tunnelidentifier. - return - } - if let tunnels = tunnelsByTitle[title] { - tunnelsByTitle[title] = tunnels + [$0] - } else { - tunnelsByTitle[title] = [$0] - } - } - - func addEntry(title: String, tunnel: Tunnel) throws { - let data = tunnel.export().data(using: .utf8)! - let byteCount: UInt32 = UInt32(data.count) - try archive.addEntry(with: "\(title).conf", type: .file, uncompressedSize: byteCount, provider: { (position, size) -> Data in - return data.subdata(in: position ..< size) - }) - } - - try tunnelsByTitle.keys.forEach { - if let tunnels = tunnelsByTitle[$0] { - if tunnels.count == 1 { - try addEntry(title: $0, tunnel: tunnels[0]) - } else { - for (index, tunnel) in tunnels.enumerated() { - try addEntry(title: $0 + "-\(index + 1)", tunnel: tunnel) - } - } - } - } - } catch { - os_log("Failed to create archive file: %{public}@ : %{public}@", log: Log.general, type: .error, saveFileURL.absoluteString, error.localizedDescription) - return - } - - let activityViewController = UIActivityViewController( - activityItems: [saveFileURL], - applicationActivities: nil) - if let popoverPresentationController = activityViewController.popoverPresentationController { - popoverPresentationController.sourceView = sourceView - } - navigationController.present(activityViewController, animated: true) { - } - } - - func exportConfig(tunnel: Tunnel, barButtonItem: UIBarButtonItem) { - let exportString = tunnel.export() - - guard let path = FileManager.default - .urls(for: .documentDirectory, in: .userDomainMask).first else { - return - } - let saveFileURL = path.appendingPathComponent("/\(tunnel.title ?? "wireguard").conf") - do { - try exportString.write(to: saveFileURL, atomically: true, encoding: .utf8) - } catch { - os_log("Failed to export tunnel to: %{public}@", log: Log.general, type: .error, saveFileURL.absoluteString) - return - } - - let activityViewController = UIActivityViewController( - activityItems: [saveFileURL], - applicationActivities: nil) - if let popoverPresentationController = activityViewController.popoverPresentationController { - popoverPresentationController.barButtonItem = barButtonItem - } - self.navigationController.present(activityViewController, animated: true) { - } - } - - // MARK: - NEVPNManager handling - - @objc private func VPNStatusDidChange(notification: NSNotification) { - guard let session = notification.object as? NETunnelProviderSession else { - return - } - - guard let prot = session.manager.protocolConfiguration as? NETunnelProviderProtocol else { - return - } - - guard let changedTunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else { - return - } - - providerManagers?.first(where: { (manager) -> Bool in - guard let prot = manager.protocolConfiguration as? NETunnelProviderProtocol else { - return false - } - guard let candidateTunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else { - return false - } - - return changedTunnelIdentifier == candidateTunnelIdentifier - - })?.loadFromPreferences(completionHandler: { [weak self] (_) in - self?.tunnelsTableViewController.updateStatus(for: changedTunnelIdentifier) - }) - } - - func showTunnelInfoViewController(tunnel: Tunnel, context: NSManagedObjectContext) { - let tunnelInfoViewController = storyboard.instantiateViewController(type: TunnelInfoTableViewController.self) - - tunnelInfoViewController.configure(context: context, delegate: self, tunnel: tunnel) - - self.navigationController.pushViewController(tunnelInfoViewController, animated: true) - } - - func showTunnelConfigurationViewController(tunnel: Tunnel?, context: NSManagedObjectContext) { - let tunnelConfigurationViewController = storyboard.instantiateViewController(type: TunnelConfigurationTableViewController.self) - - tunnelConfigurationViewController.configure(context: context, delegate: self, tunnel: tunnel) - - self.navigationController.pushViewController(tunnelConfigurationViewController, animated: true) - } - - func showSettings() { - let settingsTableViewController = storyboard.instantiateViewController(type: SettingsTableViewController.self) - - settingsTableViewController.delegate = self - - self.navigationController.pushViewController(settingsTableViewController, animated: true) - } - - public func showError(_ error: Error) { - showAlert(title: NSLocalizedString("Error", comment: "Error alert title"), message: error.localizedDescription) - } - - func connect(tunnel: Tunnel) { - _ = refreshProviderManagers().then { () -> Promise in - guard let manager = self.providerManager(for: tunnel) else { - return Promise.value(()) - } - let block = { - switch manager.connection.status { - case .invalid, .disconnected: - os_log("connect tunnel: %{public}@", log: Log.general, type: .info, tunnel.description) - // Should the manager be enabled? - - let manager = self.providerManager(for: tunnel) - manager?.isEnabled = true - manager?.saveToPreferences { (error) in - if let error = error { - os_log("error saving preferences: %{public}@", log: Log.general, type: .error, error.localizedDescription) - return - } - os_log("saved preferences", log: Log.general, type: .info) - - let session = manager?.connection as! NETunnelProviderSession //swiftlint:disable:this force_cast - do { - try session.startTunnel() - } catch let error { - os_log("error starting tunnel: %{public}@", log: Log.general, type: .error, error.localizedDescription) - } - } - - default: - break - } - } - - if manager.connection.status == .invalid { - manager.loadFromPreferences { (_) in - block() - } - } else { - block() - } - - return Promise.value(()) - } - } - - func disconnect(tunnel: Tunnel) { - _ = refreshProviderManagers().then { () -> Promise in - let manager = self.providerManager(for: tunnel)! - let block = { - switch manager.connection.status { - case .connected, .connecting: - let manager = self.providerManager(for: tunnel) - manager?.connection.stopVPNTunnel() - default: - break - } - } - - if manager.connection.status == .invalid { - manager.loadFromPreferences { (_) in - block() - } - } else { - block() - } - return Promise.value(()) - } - } - - private func showAlert(title: String, message: String) { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "OK button"), style: .default)) - self.navigationController.present(alert, animated: true) - } - - func providerManager(for tunnel: Tunnel) -> NETunnelProviderManager? { - return self.providerManagers?.first { - guard let prot = $0.protocolConfiguration as? NETunnelProviderProtocol else { - return false - } - guard let tunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else { - return false - } - return tunnelIdentifier == tunnel.tunnelIdentifier - } - } - - func extensionGoVersionInformation() -> Promise { - return Promise(resolver: { (resolver) in - guard let session = self.providerManagers?.first(where: { $0.isEnabled })?.connection as? NETunnelProviderSession else { - resolver.reject(GoVersionCoordinatorError.noEnabledSession) - return - } - do { - try session.sendProviderMessage(ExtensionMessage.requestVersion.data, responseHandler: { (data) in - guard let data = data, let responseString = String(data: data, encoding: .utf8) else { - resolver.reject(GoVersionCoordinatorError.noResponse) - return - } - resolver.fulfill(responseString) - }) - } catch { - resolver.reject(error) - } - }) - } -} - -class AppDocumentPickerDelegate: NSObject, UIDocumentPickerDelegate { - weak var appCoordinator: AppCoordinator? - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) { - if url.pathExtension == "conf" { - do { - try appCoordinator?.importConfig(config: url) - } catch { - os_log("Unable to import config: %{public}@", log: Log.general, type: .error, url.absoluteString) - } - } else if url.pathExtension == "zip" { - do { - try appCoordinator?.importConfigs(configZip: url) - } catch { - os_log("Unable to import config: %{public}@", log: Log.general, type: .error, url.absoluteString) - } - } - - } -} - -extension NEVPNStatus { - var statusDescription: String { - switch self { - case .connected: - return "Connected" - case .connecting: - return "Connecting" - case .disconnected: - return "Disconnected" - case .disconnecting: - return "Disconnecting" - case .invalid: - return "Invalid" - case .reasserting: - return "Reasserting" - } - } -} diff --git a/WireGuard/Coordinators/Coordinator.swift b/WireGuard/Coordinators/Coordinator.swift deleted file mode 100644 index d4263fc..0000000 --- a/WireGuard/Coordinators/Coordinator.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -/// The Coordinator protocol -public protocol Coordinator: class { - - /// Starts the coordinator - func start() - - /// The array containing any child Coordinators - var childCoordinators: [Coordinator] { get set } - -} - -public extension Coordinator { - - /// Add a child coordinator to the parent - public func addChildCoordinator(_ childCoordinator: Coordinator) { - self.childCoordinators.append(childCoordinator) - } - - /// Remove a child coordinator from the parent - public func removeChildCoordinator(_ childCoordinator: Coordinator) { - self.childCoordinators = self.childCoordinators.filter { $0 !== childCoordinator } - } - -} diff --git a/WireGuard/Coordinators/RootCoordinator.swift b/WireGuard/Coordinators/RootCoordinator.swift deleted file mode 100644 index 79ca0ad..0000000 --- a/WireGuard/Coordinators/RootCoordinator.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import UIKit - -public protocol RootViewControllerProvider: class { - // The coordinators 'rootViewController'. It helps to think of this as the view - // controller that can be used to dismiss the coordinator from the view hierarchy. - var rootViewController: UIViewController { get } -} - -/// A Coordinator type that provides a root UIViewController -public typealias RootViewCoordinator = Coordinator & RootViewControllerProvider diff --git a/WireGuard/Crypto/x25519.c b/WireGuard/Crypto/x25519.c deleted file mode 100644 index 6569e11..0000000 --- a/WireGuard/Crypto/x25519.c +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ - * - * Copyright (C) 2015-2018 WireGuard LLC. All Rights Reserved. - * - * Curve25519 ECDH functions, based on TweetNaCl but cleaned up. - */ - -#include -#include -#include - -#include "x25519.h" - -typedef int64_t fe[16]; - -static inline void carry(fe o) -{ - int i; - - for (i = 0; i < 16; ++i) { - o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16); - o[i] &= 0xffff; - } -} - -static inline void cswap(fe p, fe q, int b) -{ - int i; - int64_t t, c = ~(b - 1); - - for (i = 0; i < 16; ++i) { - t = c & (p[i] ^ q[i]); - p[i] ^= t; - q[i] ^= t; - } -} - -static inline void pack(uint8_t *o, const fe n) -{ - int i, j, b; - fe m, t; - - memcpy(t, n, sizeof(t)); - carry(t); - carry(t); - carry(t); - for (j = 0; j < 2; ++j) { - m[0] = t[0] - 0xffed; - for (i = 1; i < 15; ++i) { - m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); - m[i - 1] &= 0xffff; - } - m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); - b = (m[15] >> 16) & 1; - m[14] &= 0xffff; - cswap(t, m, 1 - b); - } - for (i = 0; i < 16; ++i) { - o[2 * i] = t[i] & 0xff; - o[2 * i + 1] = t[i] >> 8; - } -} - -static inline void unpack(fe o, const uint8_t *n) -{ - int i; - - for (i = 0; i < 16; ++i) - o[i] = n[2 * i] + ((int64_t)n[2 * i + 1] << 8); - o[15] &= 0x7fff; -} - -static inline void add(fe o, const fe a, const fe b) -{ - int i; - - for (i = 0; i < 16; ++i) - o[i] = a[i] + b[i]; -} - -static inline void subtract(fe o, const fe a, const fe b) -{ - int i; - - for (i = 0; i < 16; ++i) - o[i] = a[i] - b[i]; -} - -static inline void multmod(fe o, const fe a, const fe b) -{ - int i, j; - int64_t t[31] = { 0 }; - - for (i = 0; i < 16; ++i) { - for (j = 0; j < 16; ++j) - t[i + j] += a[i] * b[j]; - } - for (i = 0; i < 15; ++i) - t[i] += 38 * t[i + 16]; - memcpy(o, t, sizeof(fe)); - carry(o); - carry(o); -} - -static inline void invert(fe o, const fe i) -{ - fe c; - int a; - - memcpy(c, i, sizeof(c)); - for (a = 253; a >= 0; --a) { - multmod(c, c, c); - if (a != 2 && a != 4) - multmod(c, c, i); - } - memcpy(o, c, sizeof(fe)); -} - -static void curve25519_shared_secret(uint8_t shared_secret[32], const uint8_t private_key[32], const uint8_t public_key[32]) -{ - static const fe a24 = { 0xdb41, 1 }; - uint8_t z[32]; - int64_t r; - int i; - fe a = { 1 }, b, c = { 0 }, d = { 1 }, e, f, x; - - memcpy(z, private_key, sizeof(z)); - - z[31] = (z[31] & 127) | 64; - z[0] &= 248; - - unpack(x, public_key); - memcpy(b, x, sizeof(b)); - - for (i = 254; i >= 0; --i) { - r = (z[i >> 3] >> (i & 7)) & 1; - cswap(a, b, (int)r); - cswap(c, d, (int)r); - add(e, a, c); - subtract(a, a, c); - add(c, b, d); - subtract(b, b, d); - multmod(d, e, e); - multmod(f, a, a); - multmod(a, c, a); - multmod(c, b, e); - add(e, a, c); - subtract(a, a, c); - multmod(b, a, a); - subtract(c, d, f); - multmod(a, c, a24); - add(a, a, d); - multmod(c, c, a); - multmod(a, d, f); - multmod(d, b, x); - multmod(b, e, e); - cswap(a, b, (int)r); - cswap(c, d, (int)r); - } - invert(c, c); - multmod(a, a, c); - pack(shared_secret, a); -} - -void curve25519_derive_public_key(uint8_t public_key[32], const uint8_t private_key[32]) -{ - static const uint8_t basepoint[32] = { 9 }; - - curve25519_shared_secret(public_key, private_key, basepoint); -} - -void curve25519_generate_private_key(uint8_t private_key[32]) -{ - CCRandomGenerateBytes(private_key, 32); - private_key[31] = (private_key[31] & 127) | 64; - private_key[0] &= 248; -} diff --git a/WireGuard/Crypto/x25519.h b/WireGuard/Crypto/x25519.h deleted file mode 100644 index 7d8440d..0000000 --- a/WireGuard/Crypto/x25519.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef X25519_H -#define X25519_H - -void curve25519_derive_public_key(unsigned char public_key[32], const unsigned char private_key[32]); -void curve25519_generate_private_key(unsigned char private_key[32]); - -#endif diff --git a/WireGuard/CustomViews/CopyableLabel.swift b/WireGuard/CustomViews/CopyableLabel.swift deleted file mode 100644 index 1bca7e3..0000000 --- a/WireGuard/CustomViews/CopyableLabel.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit - -@IBDesignable -class CopyableLabel: UILabel { - override func awakeFromNib() { - super.awakeFromNib() - let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:))) - self.addGestureRecognizer(gestureRecognizer) - self.isUserInteractionEnabled = true - } - - // MARK: - UIGestureRecognizer - @objc func handleTapGesture(_ recognizer: UIGestureRecognizer) { - guard recognizer.state == .recognized else { return } - - if let recognizerView = recognizer.view, - let recognizerSuperView = recognizerView.superview, recognizerView.becomeFirstResponder() { - let menuController = UIMenuController.shared - menuController.setTargetRect(recognizerView.frame, in: recognizerSuperView) - menuController.setMenuVisible(true, animated: true) - } - } - - override var canBecomeFirstResponder: Bool { - return true - } - - override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - return (action == #selector(UIResponderStandardEditActions.copy(_:))) - - } - - override func copy(_ sender: Any?) { - UIPasteboard.general.string = text - } -} diff --git a/WireGuard/Extensions/String+Arrays.swift b/WireGuard/Extensions/String+Arrays.swift deleted file mode 100644 index b142202..0000000 --- a/WireGuard/Extensions/String+Arrays.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension String { - - static func commaSeparatedStringFrom(elements: [String]) -> String { - return elements.joined(separator: ",") - } - - func commaSeparatedToArray() -> [String] { - return components(separatedBy: .whitespaces) - .joined() - .split(separator: ",") - .map(String.init) - } - -} diff --git a/WireGuard/Extensions/String+Base64.swift b/WireGuard/Extensions/String+Base64.swift deleted file mode 100644 index ae70010..0000000 --- a/WireGuard/Extensions/String+Base64.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension String { - - func isBase64() -> Bool { - let base64Predicate = NSPredicate(format: "SELF MATCHES %@", "^[a-zA-Z0-9+/]{43}=$") - return base64Predicate.evaluate(with: self) - } - -} diff --git a/WireGuard/Info.plist b/WireGuard/Info.plist deleted file mode 100644 index 842a2a2..0000000 --- a/WireGuard/Info.plist +++ /dev/null @@ -1,173 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleDocumentTypes - - - CFBundleTypeExtensions - - conf - - CFBundleTypeIconFiles - - icon_20pt - icon_20pt@3x - icon_60pt@3x - - CFBundleTypeName - WireGuard configuration - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes - - com.wireguard.config.quick - - - - CFBundleTypeExtensions - - zip - - CFBundleTypeIconFile - zip - CFBundleTypeIconFiles - - CFBundleTypeMIMETypes - - application/zip - application/x-zip - application/x-zip-compressed - - CFBundleTypeName - WireGuard Config Zip - CFBundleTypeOSTypes - - ZIP - - CFBundleTypeRole - Viewer - LSItemContentTypes - - com.pkware.zip-archive - - - - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - WireGuardGoVersion - unknown - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - auto-generated - LSRequiresIPhoneOS - - LSSupportsOpeningDocumentsInPlace - - NSCameraUsageDescription - Camera is used to scan QR codes - UIFileSharingEnabled - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - UTExportedTypeDeclarations - - - UTTypeConformsTo - - public.data - - UTTypeDescription - WireGuard configuration - UTTypeIconFiles - - icon_20pt@3x - icon_60pt@3x - - UTTypeIdentifier - com.wireguard.config.quick - UTTypeTagSpecification - - public.filename-extension - conf - - - - UTImportedTypeDeclarations - - - UTTypeConformsTo - - com.pkware.zip-archive - - UTTypeDescription - WireGuard configuration - UTTypeIconFiles - - icon_20pt@3x - icon_60pt@3x - - UTTypeIdentifier - com.wireguard.config.quick - UTTypeTagSpecification - - public.filename-extension - conf - - - - UTTypeConformsTo - - public.data - - UTTypeDescription - WireGuard configurations - UTTypeIconFiles - - icon_20pt.png - icon_60pt@3x.png - - UTTypeIdentifier - com.wireguard.config.quick.confs - public.filename-extension - zip - - - - diff --git a/WireGuard/Log.swift b/WireGuard/Log.swift deleted file mode 100644 index 7472934..0000000 --- a/WireGuard/Log.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import os.log - -struct Log { - static var general = OSLog(subsystem: "com.wireguard.ios", category: "general") -} diff --git a/WireGuard/Models/Attribute.swift b/WireGuard/Models/Attribute.swift deleted file mode 100644 index 61e7246..0000000 --- a/WireGuard/Models/Attribute.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -struct Attribute { - - enum Key: String, CaseIterable { - case address = "Address" - case allowedIPs = "AllowedIPs" - case dns = "DNS" - case endpoint = "Endpoint" - case listenPort = "ListenPort" - case mtu = "MTU" - case persistentKeepalive = "PersistentKeepalive" - case presharedKey = "PresharedKey" - case privateKey = "PrivateKey" - case publicKey = "PublicKey" - } - - private static let separatorPattern = (try? NSRegularExpression(pattern: "\\s|=", options: []))! - - let line: String - let key: Key - let stringValue: String - var arrayValue: [String] { - return stringValue.commaSeparatedToArray() - } - - static func match(line: String) -> Attribute? { - guard let equalsIndex = line.firstIndex(of: "=") else { return nil } - let keyString = line[.. NSFetchRequest { - return NSFetchRequest(entityName: "Interface") - } - - @NSManaged public var addresses: String? - @NSManaged public var listenPort: Int16 - @NSManaged public var privateKey: String? - @NSManaged public var mtu: Int32 - @NSManaged public var dns: String? - @NSManaged public var tunnel: Tunnel? - -} - -// MARK: Generated accessors for adresses -extension Interface { -} diff --git a/WireGuard/Models/Interface+Extension.swift b/WireGuard/Models/Interface+Extension.swift deleted file mode 100644 index 848f29e..0000000 --- a/WireGuard/Models/Interface+Extension.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension Interface { - - var publicKey: String? { - if let privateKeyString = privateKey, let privateKey = Data(base64Encoded: privateKeyString) { - var publicKey = Data(count: 32) - privateKey.withUnsafeBytes({ (privateKeyBytes) -> Void in - publicKey.withUnsafeMutableBytes({ (mutableBytes) -> Void in - curve25519_derive_public_key(mutableBytes, privateKeyBytes) - }) - }) - return publicKey.base64EncodedString() - } else { - return nil - } - } - - func validate() throws { - guard let privateKey = privateKey, !privateKey.isEmpty else { - throw InterfaceValidationError.emptyPrivateKey - } - - guard privateKey.isBase64() else { - throw InterfaceValidationError.invalidPrivateKey - } - - try addresses?.commaSeparatedToArray().forEach { address in - do { - try _ = CIDRAddress(stringRepresentation: address) - } catch { - throw InterfaceValidationError.invalidAddress(cause: error) - } - } - - try dns?.commaSeparatedToArray().forEach { address in - do { - try _ = Endpoint(endpointString: address, needsPort: false) - } catch { - throw InterfaceValidationError.invalidDNSServer(cause: error) - } - } - } - - func parse(attribute: Attribute) throws { - switch attribute.key { - case .address: - addresses = attribute.stringValue - case .dns: - dns = attribute.stringValue - case .listenPort: - if let port = Int16(attribute.stringValue) { - listenPort = port - } - case .mtu: - if let mtu = Int32(attribute.stringValue) { - self.mtu = mtu - } - case .privateKey: - privateKey = attribute.stringValue - default: - throw TunnelParseError.invalidLine(attribute.line) - } - } - - func export() -> String { - var exportString = "[Interface]\n" - if let privateKey = privateKey { - exportString.append("PrivateKey=\(privateKey)\n") - } - if let addresses = addresses { - exportString.append("Address=\(addresses)\n") - } - if let dns = dns { - exportString.append("DNS=\(dns)\n") - } - if mtu > 0 { - exportString.append("MTU=\(mtu)\n") - } - if listenPort > 0 { - exportString.append("ListenPort=\(listenPort)\n") - } - - exportString.append("\n") - - return exportString - } - -} - -enum InterfaceValidationError: Error { - case emptyPrivateKey - case invalidPrivateKey - case invalidAddress(cause: Error) - case invalidDNSServer(cause: Error) -} diff --git a/WireGuard/Models/Peer+CoreDataClass.swift b/WireGuard/Models/Peer+CoreDataClass.swift deleted file mode 100644 index d8c4664..0000000 --- a/WireGuard/Models/Peer+CoreDataClass.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import CoreData - -@objc(Peer) -public class Peer: NSManagedObject { - -} diff --git a/WireGuard/Models/Peer+CoreDataProperties.swift b/WireGuard/Models/Peer+CoreDataProperties.swift deleted file mode 100644 index 50132e7..0000000 --- a/WireGuard/Models/Peer+CoreDataProperties.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import CoreData - -extension Peer { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "Peer") - } - - @NSManaged public var publicKey: String? - @NSManaged public var presharedKey: String? - @NSManaged public var allowedIPs: String? - @NSManaged public var endpoint: String? - @NSManaged public var persistentKeepalive: Int32 - @NSManaged public var tunnel: Tunnel? - -} diff --git a/WireGuard/Models/Peer+Extension.swift b/WireGuard/Models/Peer+Extension.swift deleted file mode 100644 index 4472b0c..0000000 --- a/WireGuard/Models/Peer+Extension.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -extension Peer { - - func validate() throws { - guard let publicKey = publicKey, !publicKey.isEmpty else { - throw PeerValidationError.emptyPublicKey - } - - guard publicKey.isBase64() else { - throw PeerValidationError.invalidPublicKey - } - - guard let allowedIPs = allowedIPs, !allowedIPs.isEmpty else { - throw PeerValidationError.nilAllowedIps - } - - try allowedIPs.commaSeparatedToArray().forEach { address in - do { - try _ = CIDRAddress(stringRepresentation: address) - } catch { - throw PeerValidationError.invalidAllowedIPs(cause: error) - } - } - - if let endpoint = endpoint { - do { - try _ = Endpoint(endpointString: endpoint) - } catch { - throw PeerValidationError.invalidEndpoint(cause: error) - } - } - - guard persistentKeepalive >= 0, persistentKeepalive <= 65535 else { - throw PeerValidationError.invalidPersistedKeepAlive - } - } - - func parse(attribute: Attribute) throws { - switch attribute.key { - case .allowedIPs: - allowedIPs = attribute.stringValue - case .endpoint: - endpoint = attribute.stringValue - case .persistentKeepalive: - if let keepAlive = Int32(attribute.stringValue) { - persistentKeepalive = keepAlive - } - case .presharedKey: - presharedKey = attribute.stringValue - case .publicKey: - publicKey = attribute.stringValue - default: - throw TunnelParseError.invalidLine(attribute.line) - } - } - - func export() -> String { - var exportString = "[Peer]\n" - if let publicKey = publicKey { - exportString.append("PublicKey=\(publicKey)\n") - } - if let presharedKey = presharedKey { - exportString.append("PresharedKey=\(presharedKey)\n") - } - if let allowedIPs = allowedIPs { - exportString.append("AllowedIPs=\(allowedIPs)\n") - } - if let endpoint = endpoint { - exportString.append("Endpoint=\(endpoint)\n") - } - if persistentKeepalive > 0 { - exportString.append("PersistentKeepalive=\(persistentKeepalive)\n") - } - - exportString.append("\n") - - return exportString - } - -} - -enum PeerValidationError: Error { - case emptyPublicKey - case invalidPublicKey - case nilAllowedIps - case invalidAllowedIPs(cause: Error) - case invalidEndpoint(cause: Error) - case invalidPersistedKeepAlive -} diff --git a/WireGuard/Models/Tunnel+CoreDataClass.swift b/WireGuard/Models/Tunnel+CoreDataClass.swift deleted file mode 100644 index f26d33c..0000000 --- a/WireGuard/Models/Tunnel+CoreDataClass.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import CoreData - -@objc(Tunnel) -public class Tunnel: NSManagedObject { - -} diff --git a/WireGuard/Models/Tunnel+CoreDataProperties.swift b/WireGuard/Models/Tunnel+CoreDataProperties.swift deleted file mode 100644 index 2bfad02..0000000 --- a/WireGuard/Models/Tunnel+CoreDataProperties.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import CoreData - -extension Tunnel { - - @nonobjc public class func fetchRequest() -> NSFetchRequest { - return NSFetchRequest(entityName: "Tunnel") - } - - @NSManaged public var tunnelIdentifier: String? - @NSManaged public var title: String? - @NSManaged public var interface: Interface? - @NSManaged public var peers: NSOrderedSet? - -} - -// MARK: Generated accessors for peers -extension Tunnel { - - @objc(insertObject:inPeersAtIndex:) - @NSManaged public func insertIntoPeers(_ value: Peer, at idx: Int) - - @objc(removeObjectFromPeersAtIndex:) - @NSManaged public func removeFromPeers(at idx: Int) - - @objc(insertPeers:atIndexes:) - @NSManaged public func insertIntoPeers(_ values: [Peer], at indexes: NSIndexSet) - - @objc(removePeersAtIndexes:) - @NSManaged public func removeFromPeers(at indexes: NSIndexSet) - - @objc(replaceObjectInPeersAtIndex:withObject:) - @NSManaged public func replacePeers(at idx: Int, with value: Peer) - - @objc(replacePeersAtIndexes:withPeers:) - @NSManaged public func replacePeers(at indexes: NSIndexSet, with values: [Peer]) - - @objc(addPeersObject:) - @NSManaged public func addToPeers(_ value: Peer) - - @objc(removePeersObject:) - @NSManaged public func removeFromPeers(_ value: Peer) - - @objc(addPeers:) - @NSManaged public func addToPeers(_ values: NSOrderedSet) - - @objc(removePeers:) - @NSManaged public func removeFromPeers(_ values: NSOrderedSet) - -} diff --git a/WireGuard/Models/Tunnel+Extension.swift b/WireGuard/Models/Tunnel+Extension.swift deleted file mode 100644 index 99271a1..0000000 --- a/WireGuard/Models/Tunnel+Extension.swift +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import CoreData - -extension Tunnel { - public func generateProviderConfiguration() -> [String: Any] { - var providerConfiguration = [String: Any]() - - providerConfiguration[PCKeys.title.rawValue] = self.title - providerConfiguration[PCKeys.tunnelIdentifier.rawValue] = self.tunnelIdentifier - providerConfiguration[PCKeys.endpoints.rawValue] = peers?.array.compactMap {($0 as? Peer)?.endpoint}.joined(separator: ", ") - providerConfiguration[PCKeys.dns.rawValue] = interface?.dns - providerConfiguration[PCKeys.addresses.rawValue] = interface?.addresses - if let mtu = interface?.mtu, mtu > 0 { - providerConfiguration[PCKeys.mtu.rawValue] = NSNumber(value: mtu) - } - - var settingsString = "replace_peers=true\n" - if let interface = interface { - settingsString += generateInterfaceProviderConfiguration(interface) - } - - if let peers = peers?.array as? [Peer] { - peers.forEach { - settingsString += generatePeerProviderConfiguration($0) - } - - } - - providerConfiguration["settings"] = settingsString - - return providerConfiguration - } - - private func generateInterfaceProviderConfiguration(_ interface: Interface) -> String { - var settingsString = "" - - if let hexPrivateKey = base64KeyToHex(interface.privateKey) { - settingsString += "private_key=\(hexPrivateKey)\n" - } - if interface.listenPort > 0 { - settingsString += "listen_port=\(interface.listenPort)\n" - } - if interface.mtu > 0 { - settingsString += "mtu=\(interface.mtu)\n" - } - - return settingsString - } - - private func generatePeerProviderConfiguration(_ peer: Peer) -> String { - var settingsString = "" - - if let hexPublicKey = base64KeyToHex(peer.publicKey) { - settingsString += "public_key=\(hexPublicKey)\n" - } - if let presharedKey = peer.presharedKey { - settingsString += "preshared_key=\(presharedKey)\n" - } - if let endpoint = peer.endpoint { - settingsString += "endpoint=\(endpoint)\n" - } - if peer.persistentKeepalive > 0 { - settingsString += "persistent_keepalive_interval=\(peer.persistentKeepalive)\n" - } - if let allowedIPs = peer.allowedIPs?.commaSeparatedToArray() { - allowedIPs.forEach { - settingsString += "allowed_ip=\($0.trimmingCharacters(in: .whitespaces))\n" - } - } - - return settingsString - } - - func validate() throws { - let nameRegex = "[a-zA-Z0-9_=+.-]{1,15}" - let nameTest = NSPredicate(format: "SELF MATCHES %@", nameRegex) - guard let title = title, nameTest.evaluate(with: title) else { - throw TunnelValidationError.invalidTitle - } - - let fetchRequest: NSFetchRequest = Tunnel.fetchRequest() - fetchRequest.predicate = NSPredicate(format: "title == %@", title) - guard (try? managedObjectContext?.count(for: fetchRequest)) == 1 else { - throw TunnelValidationError.titleExists - } - - guard let interface = interface else { - throw TunnelValidationError.nilInterface - } - - try interface.validate() - - guard let peers = peers else { - throw TunnelValidationError.nilPeers - } - - try peers.forEach { - guard let peer = $0 as? Peer else { - throw TunnelValidationError.invalidPeer - } - - try peer.validate() - } - } - - static func fromConfig(_ text: String, context: NSManagedObjectContext) throws -> Tunnel { - let lines = text.split(separator: "\n") - - var currentPeer: Peer? - var isInInterfaceSection = false - - var tunnel: Tunnel! - context.performAndWait { - tunnel = Tunnel(context: context) - tunnel.interface = Interface(context: context) - } - tunnel.tunnelIdentifier = UUID().uuidString - - for line in lines { - var trimmedLine: String - if let commentRange = line.range(of: "#") { - trimmedLine = String(line[.. 0 else { continue } - - if "[interface]" == line.lowercased() { - currentPeer = nil - isInInterfaceSection = true - } else if "[peer]" == line.lowercased() { - context.performAndWait { currentPeer = Peer(context: context) } - tunnel.insertIntoPeers(currentPeer!, at: tunnel.peers?.count ?? 0) - isInInterfaceSection = false - } else if isInInterfaceSection, let attribute = Attribute.match(line: String(line)) { - try tunnel.interface!.parse(attribute: attribute) - } else if let currentPeer = currentPeer, let attribute = Attribute.match(line: String(line)) { - try currentPeer.parse(attribute: attribute) - } else { - throw TunnelParseError.invalidLine(String(line)) - } - } - - if !isInInterfaceSection && currentPeer == nil { - throw TunnelParseError.noConfigInfo - } - - return tunnel - } - - func export() -> String { - var exportString = "" - if let interfaceExport = self.interface?.export() { - exportString.append(interfaceExport) - } - - if let peers = peers?.array as? [Peer] { - peers.forEach { - exportString.append($0.export()) - } - } - - return exportString - } - -} - -private func base64KeyToHex(_ base64: String?) -> String? { - guard let base64 = base64 else { - return nil - } - - guard base64.count == 44 else { - return nil - } - - guard base64.last == "=" else { - return nil - } - - guard let keyData = Data(base64Encoded: base64) else { - return nil - } - - guard keyData.count == 32 else { - return nil - } - - let hexKey = keyData.reduce("") {$0 + String(format: "%02x", $1)} - - return hexKey -} - -enum TunnelValidationError: Error { - case invalidTitle - case titleExists - case nilInterface - case nilPeers - case invalidPeer -} - -enum TunnelParseError: Error { - case invalidLine(_ line: String) - case noConfigInfo -} diff --git a/WireGuard/Models/WireGuard.xcdatamodeld/WireGuard.xcdatamodel/contents b/WireGuard/Models/WireGuard.xcdatamodeld/WireGuard.xcdatamodel/contents deleted file mode 100644 index eeb1155..0000000 --- a/WireGuard/Models/WireGuard.xcdatamodeld/WireGuard.xcdatamodel/contents +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WireGuard/ViewControllers/Identifyable.swift b/WireGuard/ViewControllers/Identifyable.swift deleted file mode 100644 index c94a399..0000000 --- a/WireGuard/ViewControllers/Identifyable.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation -import UIKit - -public protocol Identifyable: class { - static var identifier: String { get } -} - -public extension Identifyable { - static var identifier: String { - return String(describing: Self.self) - } -} - -extension UIStoryboard { - - public func instantiateViewController(type: T.Type) -> T where T: UIViewController { - return self.instantiateViewController(withIdentifier: type.identifier) as! T // swiftlint:disable:this force_cast - } -} diff --git a/WireGuard/ViewControllers/QRScanViewController.swift b/WireGuard/ViewControllers/QRScanViewController.swift deleted file mode 100644 index 30fd79d..0000000 --- a/WireGuard/ViewControllers/QRScanViewController.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import AVFoundation -import CoreData -import UIKit - -protocol QRScanViewControllerDelegate: class { - func didSave(tunnel: Tunnel, qrScanViewController: QRScanViewController) - func didCancel(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.insertSublayer(previewLayer, at: 0) - } - - 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() - } - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - if let connection = previewLayer.connection { - - let currentDevice: UIDevice = UIDevice.current - - let orientation: UIDeviceOrientation = currentDevice.orientation - - let previewLayerConnection: AVCaptureConnection = connection - - if previewLayerConnection.isVideoOrientationSupported { - - switch orientation { - case .portrait: - previewLayerConnection.videoOrientation = .portrait - case .landscapeRight: - previewLayerConnection.videoOrientation = .landscapeLeft - case .landscapeLeft: - previewLayerConnection.videoOrientation = .landscapeRight - case .portraitUpsideDown: - previewLayerConnection.videoOrientation = .portraitUpsideDown - default: - previewLayerConnection.videoOrientation = .portrait - - } - } - } - - previewLayer.frame = self.view.bounds - } - - func scanDidComplete(withCode code: String) { - do { - let tunnel = try Tunnel.fromConfig(code, context: viewContext) - let alert = UIAlertController(title: NSLocalizedString("Enter a title for new tunnel", comment: ""), message: nil, preferredStyle: .alert) - alert.addTextField(configurationHandler: nil) - alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: { [weak self] _ in - self?.delegate?.didCancel(qrScanViewController: self!) - })) - alert.addAction(UIAlertAction(title: NSLocalizedString("Save", comment: ""), style: .default, handler: { [weak self] _ in - do { - tunnel.title = alert.textFields?[0].text - try self?.viewContext.save() - self?.delegate?.didSave(tunnel: tunnel, qrScanViewController: self!) - } catch { - self?.scanDidEncounterError(title: "Invalid Code", message: "The scanned code is not a valid WireGuard config file.") - } - })) - - self.present(alert, animated: true) - - } 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 {} diff --git a/WireGuard/ViewControllers/SetttingsTableViewController.swift b/WireGuard/ViewControllers/SetttingsTableViewController.swift deleted file mode 100644 index 50832eb..0000000 --- a/WireGuard/ViewControllers/SetttingsTableViewController.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import PromiseKit - -enum GoVersionError: Error { - case noDelegate -} - -protocol SettingsTableViewControllerDelegate: class { - func exportTunnels(settingsTableViewController: SettingsTableViewController, sourceView: UIView) -} - -class SettingsTableViewController: UITableViewController { - - weak var delegate: SettingsTableViewControllerDelegate? - @IBOutlet weak var versionInfoCell: UITableViewCell! - @IBOutlet weak var goVersionInfoCell: UITableViewCell! - @IBOutlet weak var exportCell: UITableViewCell! - - @IBOutlet weak var versionInfoLabel: UILabel! - @IBOutlet weak var goVersionInfoLabel: UILabel! - - override func viewDidLoad() { - super.viewDidLoad() - versionInfoLabel.text = versionInformation - goVersionInfoLabel.text = goVersionInformation - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if let cell = tableView.cellForRow(at: indexPath) { - switch cell { - case versionInfoCell, goVersionInfoCell: - UIPasteboard.general.string = ["WireGuard for iOS:", versionInformation, "Go userspace backend:", goVersionInfoLabel.text ?? ""].joined(separator: "\n") - showCopyConfirmation() - case exportCell: - delegate?.exportTunnels(settingsTableViewController: self, sourceView: exportCell) - default: - () - } - tableView.deselectRow(at: indexPath, animated: true) - } - } - - var versionInformation: String { - var versionElements: [String] = [] - if let appBuildNumber = Bundle.main.infoDictionary!["CFBundleVersion"] as? String, let appVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as? String { - versionElements.append(appVersion) - versionElements.append("(\(appBuildNumber))") - } - - return versionElements.joined(separator: " ") - } - - var goVersionInformation: String { - return Bundle.main.infoDictionary!["WireGuardGoVersion"] as? String ?? "Unknown!!!" - } - - private func showNotEnabledAlert() { - let notEnabledAlertController = UIAlertController(title: NSLocalizedString("Go version", comment: ""), message: NSLocalizedString("Enable a WireGuard config by connecting or by selecting one in the VPN section of the device Settings app.", comment: ""), preferredStyle: .alert) - notEnabledAlertController.addAction(UIAlertAction(title: NSLocalizedString("Ok", comment: "Generic OK button"), style: .default, handler: nil)) - - present(notEnabledAlertController, animated: true, completion: nil) - } - - private func showCopyConfirmation() { - let confirmationAlertController = UIAlertController(title: NSLocalizedString("Copied version information", comment: ""), message: UIPasteboard.general.string, preferredStyle: .alert) - confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Ok", comment: "Generic OK button"), style: .default, handler: nil)) - - present(confirmationAlertController, animated: true, completion: nil) - - } -} - -extension SettingsTableViewController: Identifyable {} diff --git a/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift b/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift deleted file mode 100644 index 65679c7..0000000 --- a/WireGuard/ViewControllers/TunnelConfigurationTableViewController.swift +++ /dev/null @@ -1,300 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import CoreData -import BNRCoreDataStack -import PromiseKit - -protocol TunnelConfigurationTableViewControllerDelegate: class { - func didSave(tunnel: Tunnel, tunnelConfigurationTableViewController: TunnelConfigurationTableViewController) - func showSettings() -} - -class TunnelConfigurationTableViewController: UITableViewController { - - @IBOutlet weak var saveButton: UIBarButtonItem! - - private var viewContext: NSManagedObjectContext! - private weak var delegate: TunnelConfigurationTableViewControllerDelegate? - private var tunnel: Tunnel! - - override func viewDidLoad() { - super.viewDidLoad() - - // Get rid of seperator lines in table. - tableView.tableFooterView = UIView(frame: CGRect.zero) - } - - func configure(context: NSManagedObjectContext, delegate: TunnelConfigurationTableViewControllerDelegate? = nil, tunnel: Tunnel? = nil) { - viewContext = context - self.delegate = delegate - self.tunnel = tunnel ?? generateNewTunnelConfig() - } - - private func generateNewTunnelConfig() -> Tunnel { - var tunnel: Tunnel! = nil - - viewContext.performAndWait { - tunnel = Tunnel(context: viewContext) - tunnel.tunnelIdentifier = UUID().uuidString - - let interface = Interface(context: viewContext) - - tunnel.interface = interface - } - return tunnel - } - - @IBAction func showSettings(_ sender: Any) { - delegate?.showSettings() - } - - @IBAction func addPeer(_ sender: Any) { - if let moc = tunnel.managedObjectContext { - tableView.beginUpdates() - let insertedAt = IndexPath(row: tunnel.peers?.count ?? 0, section: 1) - tableView.insertRows(at: [insertedAt], with: .automatic) - - let peer = Peer(context: moc) - tunnel.addToPeers(peer) - - tableView.endUpdates() - tableView.scrollToRow(at: insertedAt, at: .middle, animated: true) - } - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 3 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 1: - return tunnel?.peers?.count ?? 1 - default: - return 1 - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: - let cell = tableView.dequeueReusableCell(type: InterfaceTableViewCell.self, for: indexPath) - cell.model = tunnel.interface - cell.delegate = self - return cell - case 1: - let cell = tableView.dequeueReusableCell(type: PeerTableViewCell.self, for: indexPath) - if let peer = tunnel.peers?.object(at: indexPath.row) as? Peer { - cell.peer = peer - } else { - let peer = Peer(context: tunnel.managedObjectContext!) - tunnel.addToPeers(peer) - cell.peer = peer - } - cell.delegate = self - return cell - default: - let cell = tableView.dequeueReusableCell(type: AddPeerTableViewCell.self, for: indexPath) - cell.tunnel = tunnel - return cell - } - } - - @IBAction func saveTunnelConfiguration(_ sender: Any) { - Promise(resolver: { (seal) in - do { - try tunnel.validate() - } catch { - seal.reject(error) - return - } - - viewContext.perform({ - self.viewContext.saveContext({ (result) in - switch result { - case .success: - seal.fulfill(()) - case .failure(let error): - seal.reject(error) - } - }) - }) - }).then { () -> Promise in - self.delegate?.didSave(tunnel: self.tunnel, tunnelConfigurationTableViewController: self) - return Promise.value(()) - }.catch { error in - let alert = UIAlertController(title: "Error", message: "\(error)", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) - self.present(alert, animated: true, completion: nil) - } - } -} - -extension TunnelConfigurationTableViewController: PeerTableViewCellDelegate { - func delete(peer: Peer) { - if let moc = tunnel.managedObjectContext { - tableView.beginUpdates() - let deletedAt = IndexPath(row: tunnel.peers?.index(of: peer) ?? 0, section: 1) - tableView.deleteRows(at: [deletedAt], with: .automatic) - tunnel.removeFromPeers(peer) - moc.delete(peer) - tableView.endUpdates() - } - } -} - -extension TunnelConfigurationTableViewController: InterfaceTableViewCellDelegate { - func generateKeys() { - if let moc = tunnel.managedObjectContext { - moc.perform { - var privateKey = Data(count: 32) - privateKey.withUnsafeMutableBytes { (mutableBytes) -> Void in - curve25519_generate_private_key(mutableBytes) - } - - self.tunnel.interface?.privateKey = privateKey.base64EncodedString() - } - } - self.tableView.reloadData() - } -} - -protocol InterfaceTableViewCellDelegate: class { - func generateKeys() -} - -class InterfaceTableViewCell: UITableViewCell { - var model: Interface! { - didSet { - nameField.text = model.tunnel?.title - addressesField.text = model.addresses - privateKeyField.text = model.privateKey - publicKeyField.text = model.publicKey - - listenPortField.text = model.listenPort > 0 ? String(model.listenPort) : nil - dnsField.text = model.dns - mtuField.text = model.mtu > 0 ? String(model.mtu) : nil - } - } - - weak var delegate: InterfaceTableViewCellDelegate? - - @IBOutlet weak var nameField: UITextField! - @IBOutlet weak var addressesField: UITextField! - @IBOutlet weak var privateKeyField: UITextField! - @IBOutlet weak var publicKeyField: CopyableLabel! - @IBOutlet weak var listenPortField: UITextField! - @IBOutlet weak var dnsField: UITextField! - @IBOutlet weak var mtuField: UITextField! - - @IBAction func generateTapped(_ sender: Any) { - delegate?.generateKeys() - } -} - -extension InterfaceTableViewCell: UITextFieldDelegate { - - @IBAction - func textfieldDidChange(_ sender: UITextField) { - let string = sender.text - - if sender == nameField { - model.tunnel?.title = string - } else if sender == privateKeyField { - model.privateKey = string - publicKeyField.text = model.publicKey - } else if sender == addressesField { - model.addresses = string - } else if sender == listenPortField { - if let string = string, let port = Int16(string) { - model.listenPort = port - } else { - model.listenPort = 0 - } - } else if sender == dnsField { - model.dns = string - } else if sender == mtuField { - if let string = string, let mtu = Int32(string) { - model.mtu = mtu - } else { - model.mtu = 0 - } - } - } - - func textFieldDidEndEditing(_ textField: UITextField) { - if textField == addressesField { - if let addresses = model.addresses?.commaSeparatedToArray() { - textField.text = addresses.compactMap { try? CIDRAddress(stringRepresentation: $0 ) }.compactMap { $0?.stringRepresentation }.joined(separator: ", ") - } - } - } -} - -protocol PeerTableViewCellDelegate: class { - func delete(peer: Peer) -} - -class PeerTableViewCell: UITableViewCell { - var peer: Peer! { - didSet { - publicKeyField.text = peer.publicKey - preSharedKeyField.text = peer.presharedKey - allowedIpsField.text = peer.allowedIPs - endpointField.text = peer.endpoint - persistentKeepaliveField.text = peer.persistentKeepalive > 0 ? String(peer.persistentKeepalive) : nil - } - } - weak var delegate: PeerTableViewCellDelegate? - - @IBOutlet weak var publicKeyField: UITextField! - @IBOutlet weak var preSharedKeyField: UITextField! - @IBOutlet weak var allowedIpsField: UITextField! - @IBOutlet weak var endpointField: UITextField! - @IBOutlet weak var persistentKeepaliveField: UITextField! - - @IBAction func deletePeer(_ sender: Any) { - delegate?.delete(peer: peer) - } -} - -extension PeerTableViewCell: UITextFieldDelegate { - @IBAction - func textfieldDidChange(_ sender: UITextField) { - let string = sender.text - - if sender == publicKeyField { - peer.publicKey = string - } else if sender == preSharedKeyField { - peer.presharedKey = string - } else if sender == allowedIpsField { - peer.allowedIPs = string - } else if sender == endpointField { - peer.endpoint = string - } else if sender == persistentKeepaliveField { - if let string = string, let persistentKeepalive = Int32(string) { - peer.persistentKeepalive = persistentKeepalive - } else { - peer.persistentKeepalive = 0 - } - } - } -} - -class AddPeerTableViewCell: UITableViewCell { - var tunnel: Tunnel! - - @IBAction func addPeer(_ sender: Any) { - if let moc = tunnel.managedObjectContext { - tunnel.addToPeers(Peer(context: moc)) - } - } -} - -extension TunnelConfigurationTableViewController: Identifyable {} -extension InterfaceTableViewCell: Identifyable {} -extension PeerTableViewCell: Identifyable {} -extension AddPeerTableViewCell: Identifyable {} diff --git a/WireGuard/ViewControllers/TunnelInfoTableViewController.swift b/WireGuard/ViewControllers/TunnelInfoTableViewController.swift deleted file mode 100644 index 1eb898a..0000000 --- a/WireGuard/ViewControllers/TunnelInfoTableViewController.swift +++ /dev/null @@ -1,194 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import CoreData -import NetworkExtension - -import BNRCoreDataStack -import PromiseKit - -protocol TunnelInfoTableViewControllerDelegate: class { - func connect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) - func disconnect(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) - func configure(tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) - func showSettings() - func status(for tunnel: Tunnel, tunnelInfoTableViewController: TunnelInfoTableViewController) -> NEVPNStatus -} - -class TunnelInfoTableViewController: UITableViewController { - - @IBOutlet weak var editButton: UIBarButtonItem! - - private var viewContext: NSManagedObjectContext! - private weak var delegate: TunnelInfoTableViewControllerDelegate? - private var tunnel: Tunnel! - - func configure(context: NSManagedObjectContext, delegate: TunnelInfoTableViewControllerDelegate? = nil, tunnel: Tunnel) { - viewContext = context - self.delegate = delegate - self.tunnel = tunnel - } - - override func viewDidLoad() { - super.viewDidLoad() - - // Get rid of seperator lines in table. - tableView.tableFooterView = UIView(frame: CGRect.zero) - - NotificationCenter.default.addObserver(self, - selector: #selector(VPNStatusDidChange(notification:)), - name: .NEVPNStatusDidChange, - object: nil) - } - - override func viewWillAppear(_ animated: Bool) { - super .viewWillAppear(animated) - - self.tableView.reloadData() - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 2 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 1: - return tunnel?.peers?.count ?? 0 - default: - return 1 - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: - let cell = tableView.dequeueReusableCell(type: InterfaceInfoTableViewCell.self, for: indexPath) - cell.delegate = self - cell.configure(model: tunnel.interface, status: delegate?.status(for: tunnel, tunnelInfoTableViewController: self) ?? .invalid) - return cell - default: - let cell = tableView.dequeueReusableCell(type: PeerInfoTableViewCell.self, for: indexPath) - if let peer = tunnel.peers?.object(at: indexPath.row) as? Peer { - cell.peer = peer - } else { - let peer = Peer(context: tunnel.managedObjectContext!) - tunnel.addToPeers(peer) - cell.peer = peer - } - return cell - } - } - - @IBAction func showSettings(_ sender: Any) { - delegate?.showSettings() - } - - @IBAction func editTunnelConfiguration(_ sender: Any) { - delegate?.configure(tunnel: self.tunnel, tunnelInfoTableViewController: self) - } - - @objc private func VPNStatusDidChange(notification: NSNotification) { - guard let session = notification.object as? NETunnelProviderSession else { - return - } - - guard let prot = session.manager.protocolConfiguration as? NETunnelProviderProtocol else { - return - } - - guard let changedTunnelIdentifier = prot.providerConfiguration?[PCKeys.tunnelIdentifier.rawValue] as? String else { - return - } - - guard tunnel.tunnelIdentifier == changedTunnelIdentifier else { - return - } - - self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none) - } -} - -extension TunnelInfoTableViewController: InterfaceInfoTableViewCellDelegate { - func connect(tunnelIdentifier: String) { - delegate?.connect(tunnel: tunnel, tunnelInfoTableViewController: self) - } - - func disconnect(tunnelIdentifier: String) { - delegate?.disconnect(tunnel: tunnel, tunnelInfoTableViewController: self) - } -} - -protocol InterfaceInfoTableViewCellDelegate: class { - func connect(tunnelIdentifier: String) - func disconnect(tunnelIdentifier: String) -} - -class InterfaceInfoTableViewCell: UITableViewCell { - weak var delegate: InterfaceInfoTableViewCellDelegate? - private var model: Interface! { - didSet { - nameField.text = model.tunnel?.title - addressesField.text = model.addresses - publicKeyField.text = model.publicKey - } - } - - func configure(model: Interface!, status: NEVPNStatus) { - self.model = model - - if status == .connecting || status == .disconnecting || status == .reasserting { - activityIndicator.startAnimating() - tunnelSwitch.isHidden = true - } else { - activityIndicator.stopAnimating() - tunnelSwitch.isHidden = false - } - - tunnelSwitch.isOn = status == .connected - tunnelSwitch.onTintColor = status == .invalid || status == .reasserting ? .gray : .green - tunnelSwitch.isEnabled = true - } - - @IBAction func tunnelSwitchChanged(_ sender: Any) { - tunnelSwitch.isEnabled = false - - guard let tunnelIdentifier = model.tunnel?.tunnelIdentifier else { - return - } - - if tunnelSwitch.isOn { - delegate?.connect(tunnelIdentifier: tunnelIdentifier) - } else { - delegate?.disconnect(tunnelIdentifier: tunnelIdentifier) - } - } - - @IBOutlet weak var nameField: UILabel! - @IBOutlet weak var addressesField: UILabel! - @IBOutlet weak var publicKeyField: CopyableLabel! - @IBOutlet weak var tunnelSwitch: UISwitch! - @IBOutlet weak var activityIndicator: UIActivityIndicatorView! -} - -class PeerInfoTableViewCell: UITableViewCell { - var peer: Peer! { - didSet { - publicKeyField.text = peer.publicKey - allowedIpsField.text = peer.allowedIPs - endpointField.text = peer.endpoint - } - } - - @IBOutlet weak var publicKeyField: CopyableLabel! - @IBOutlet weak var allowedIpsField: UILabel! - @IBOutlet weak var endpointField: UILabel! - @IBOutlet weak var copiedStatusLabel: UILabel! - -} - -extension TunnelInfoTableViewController: Identifyable {} -extension InterfaceInfoTableViewCell: Identifyable {} -extension PeerInfoTableViewCell: Identifyable {} diff --git a/WireGuard/ViewControllers/TunnelsTableViewController.swift b/WireGuard/ViewControllers/TunnelsTableViewController.swift deleted file mode 100644 index 26932d9..0000000 --- a/WireGuard/ViewControllers/TunnelsTableViewController.swift +++ /dev/null @@ -1,308 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import UIKit -import os.log -import CoreData - -import BNRCoreDataStack -import NetworkExtension - -protocol TunnelsTableViewControllerDelegate: class { - func addProvider(tunnelsTableViewController: TunnelsTableViewController) - func connect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) - func disconnect(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) - func info(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) - func delete(tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) - func status(for tunnel: Tunnel, tunnelsTableViewController: TunnelsTableViewController) -> NEVPNStatus - func showSettings() -} - -class TunnelsTableViewController: UITableViewController { - weak var delegate: TunnelsTableViewControllerDelegate? - - var viewContext: NSManagedObjectContext! - - @IBOutlet var settingsButton: UIBarButtonItem! - @IBOutlet var editButton: UIBarButtonItem! - @IBOutlet var doneButton: UIBarButtonItem! - - private lazy var fetchedResultsController: FetchedResultsController = { - let fetchRequest = NSFetchRequest() - fetchRequest.entity = Tunnel.entity() - fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)] - let frc = FetchedResultsController(fetchRequest: fetchRequest, - managedObjectContext: viewContext) - frc.setDelegate(self.frcDelegate) - return frc - }() - - public func updateStatus(for tunnelIdentifier: String) { - viewContext.perform { - do { - let tunnel = try Tunnel.findFirstInContext(self.viewContext, predicate: NSPredicate(format: "tunnelIdentifier == %@", tunnelIdentifier)) - if let tunnel = tunnel { - if let indexPath = self.fetchedResultsController.indexPathForObject(tunnel) { - self.tableView.reloadRows(at: [indexPath], with: .none) - } - } - } catch { - os_log("Unable to load tunnel for tunnel identifier: %{public}@", log: Log.general, type: .error, error.localizedDescription) - - } - } - } - - private lazy var frcDelegate: TunnelFetchedResultsControllerDelegate = { // swiftlint:disable:this weak_delegate - return TunnelFetchedResultsControllerDelegate(tableView: self.tableView) - }() - - override func viewDidLoad() { - super.viewDidLoad() - do { - try fetchedResultsController.performFetch() - } catch { - print("Failed to fetch objects: \(error)") - } - - // Get rid of seperator lines in table. - tableView.tableFooterView = UIView(frame: CGRect.zero) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - updateBarButtons() - } - - @IBAction func editTunnels(_ sender: Any) { - tableView.setEditing(!tableView.isEditing, animated: true) - updateBarButtons() - - } - - private func updateBarButtons() { - navigationController?.setToolbarHidden(tableView.isEditing, animated: true) - if tableView.isEditing { - self.navigationItem.setRightBarButtonItems([doneButton], animated: true) - } else { - self.navigationItem.setRightBarButtonItems([settingsButton, editButton], animated: true) - } - } - - @IBAction func showSettings(_ sender: Any) { - delegate?.showSettings() - } - - @IBAction func addProvider(_ sender: UIBarButtonItem) { - delegate?.addProvider(tunnelsTableViewController: self) - } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return fetchedResultsController.sections?[0].objects.count ?? 0 - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(type: TunnelTableViewCell.self, for: indexPath) - cell.delegate = self - - guard let sections = fetchedResultsController.sections else { - fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil") - } - - let section = sections[indexPath.section] - let tunnel = section.objects[indexPath.row] - - cell.configure(tunnel: tunnel, status: delegate?.status(for: tunnel, tunnelsTableViewController: self) ?? .invalid) - - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let sections = fetchedResultsController.sections else { - fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil") - } - - let section = sections[indexPath.section] - let tunnel = section.objects[indexPath.row] - - delegate?.info(tunnel: tunnel, tunnelsTableViewController: self) - - tableView.deselectRow(at: indexPath, animated: true) - } - - override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) { - guard let sections = fetchedResultsController.sections else { - fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil") - } - - let section = sections[indexPath.section] - let tunnel = section.objects[indexPath.row] - - delegate?.info(tunnel: tunnel, tunnelsTableViewController: self) - - } - - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return true - } - - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - - guard let sections = fetchedResultsController.sections else { - fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil") - } - - let section = sections[indexPath.section] - let tunnel = section.objects[indexPath.row] - - delegate?.delete(tunnel: tunnel, tunnelsTableViewController: self) - } - } -} - -extension TunnelsTableViewController: TunnelTableViewCellDelegate { - func connect(tunnelIdentifier: String) { - let tunnel = try? Tunnel.findFirstInContext(self.viewContext, predicate: NSPredicate(format: "tunnelIdentifier == %@", tunnelIdentifier)) - if let tunnel = tunnel { - self.delegate?.connect(tunnel: tunnel!, tunnelsTableViewController: self) - } - } - - func disconnect(tunnelIdentifier: String) { - let tunnel = try? Tunnel.findFirstInContext(self.viewContext, predicate: NSPredicate(format: "tunnelIdentifier == %@", tunnelIdentifier)) - if let tunnel = tunnel { - self.delegate?.disconnect(tunnel: tunnel!, tunnelsTableViewController: self) - } - } - -} - -extension TunnelsTableViewController: Identifyable {} - -class TunnelFetchedResultsControllerDelegate: NSObject, FetchedResultsControllerDelegate { - - private weak var tableView: UITableView? - private var arrowImage: UIImageView? - - // MARK: - Lifecycle - init(tableView: UITableView) { - self.tableView = tableView - } - - func fetchedResultsControllerDidPerformFetch(_ controller: FetchedResultsController) { - tableView?.reloadData() - updateEmptyIndicator(controller) - } - - func fetchedResultsControllerWillChangeContent(_ controller: FetchedResultsController) { - tableView?.beginUpdates() - } - - func fetchedResultsControllerDidChangeContent(_ controller: FetchedResultsController) { - tableView?.endUpdates() - updateEmptyIndicator(controller) - } - - func fetchedResultsController(_ controller: FetchedResultsController, didChangeObject change: FetchedResultsObjectChange) { - guard let tableView = tableView else { return } - switch change { - case let .insert(_, indexPath): - tableView.insertRows(at: [indexPath], with: .automatic) - - case let .delete(_, indexPath): - tableView.deleteRows(at: [indexPath], with: .automatic) - - case let .move(_, fromIndexPath, toIndexPath): - tableView.moveRow(at: fromIndexPath, to: toIndexPath) - - case let .update(_, indexPath): - tableView.reloadRows(at: [indexPath], with: .automatic) - } - } - - func fetchedResultsController(_ controller: FetchedResultsController, didChangeSection change: FetchedResultsSectionChange) { - guard let tableView = tableView else { return } - switch change { - case let .insert(_, index): - tableView.insertSections(IndexSet(integer: index), with: .automatic) - - case let .delete(_, index): - tableView.deleteSections(IndexSet(integer: index), with: .automatic) - } - } - - private func updateEmptyIndicator(_ controller: FetchedResultsController) { - guard let tableView = tableView else { return } - if controller.count > 0 { - tableView.backgroundView = nil - arrowImage = nil - } else { - if arrowImage == nil { - let imageView = UIImageView(image: UIImage(named: "Arrow")) - imageView.autoresizingMask = [.flexibleHeight, .flexibleWidth] - imageView.frame = tableView.bounds - imageView.contentMode = .bottomRight - tableView.backgroundView = imageView - arrowImage = imageView - } - } - } -} - -protocol TunnelTableViewCellDelegate: class { - func connect(tunnelIdentifier: String) - func disconnect(tunnelIdentifier: String) -} - -class TunnelTableViewCell: UITableViewCell { - - @IBOutlet weak var tunnelTitleLabel: UILabel! - @IBOutlet weak var activityIndicator: UIActivityIndicatorView! - @IBOutlet weak var tunnelSwitch: UISwitch! - - weak var delegate: TunnelTableViewCellDelegate? - private var tunnelIdentifier: String? - - @IBAction func tunnelSwitchChanged(_ sender: Any) { - tunnelSwitch.isEnabled = false - guard let tunnelIdentifier = tunnelIdentifier else { - return - } - - if tunnelSwitch.isOn { - delegate?.connect(tunnelIdentifier: tunnelIdentifier) - } else { - delegate?.disconnect(tunnelIdentifier: tunnelIdentifier) - } - } - - func configure(tunnel: Tunnel, status: NEVPNStatus) { - self.tunnelTitleLabel?.text = tunnel.title - tunnelIdentifier = tunnel.tunnelIdentifier - - if status == .connecting || status == .disconnecting || status == .reasserting { - activityIndicator.startAnimating() - tunnelSwitch.isHidden = true - } else { - activityIndicator.stopAnimating() - tunnelSwitch.isHidden = false - } - - tunnelSwitch.isOn = status == .connected - tunnelSwitch.onTintColor = status == .invalid || status == .reasserting ? .gray : .green - tunnelSwitch.isEnabled = true - } - - override func setEditing(_ editing: Bool, animated: Bool) { - super.setEditing(editing, animated: animated) - tunnelSwitch.isHidden = editing - } -} - -extension TunnelTableViewCell: Identifyable {} diff --git a/WireGuard/ViewControllers/UITableView+WireGuard.swift b/WireGuard/ViewControllers/UITableView+WireGuard.swift deleted file mode 100644 index a8b913b..0000000 --- a/WireGuard/ViewControllers/UITableView+WireGuard.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import Foundation - -import UIKit - -extension UITableView { - - func register(type: T.Type, prefix: String = "") where T: UITableViewCell { - register(type, forCellReuseIdentifier: prefix + type.identifier) - } - - func dequeueReusableCell(type: T.Type, for indexPath: IndexPath, prefix: String = "") -> T where T: UITableViewCell { - return dequeueReusableCell(withIdentifier: prefix + type.identifier, for: indexPath) as! T // swiftlint:disable:this force_cast - } - - func registerNib(type: T.Type, prefix: String = "") where T: UITableViewCell { - let nib = UINib(nibName: prefix + type.identifier, bundle: nil) - register(nib, forCellReuseIdentifier: prefix + type.identifier) - } - - func registerNib(type: T.Type, prefix: String = "") where T: UITableViewHeaderFooterView { - let nib = UINib(nibName: prefix + type.identifier, bundle: nil) - register(nib, forHeaderFooterViewReuseIdentifier: prefix + type.identifier) - } - - func dequeueReusableHeaderFooterView(type: T.Type, prefix: String = "") -> T where T: UITableViewHeaderFooterView { - return dequeueReusableHeaderFooterView(withIdentifier: prefix + type.identifier) as! T // swiftlint:disable:this force_cast - } -} diff --git a/WireGuard/WireGuard-Bridging-Header.h b/WireGuard/WireGuard-Bridging-Header.h deleted file mode 100644 index 95922cc..0000000 --- a/WireGuard/WireGuard-Bridging-Header.h +++ /dev/null @@ -1,6 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "Crypto/x25519.h" -#import "../wireguard-go-bridge/wireguard.h" diff --git a/WireGuard/WireGuard.entitlements b/WireGuard/WireGuard.entitlements deleted file mode 100644 index a4774c6..0000000 --- a/WireGuard/WireGuard.entitlements +++ /dev/null @@ -1,18 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - com.apple.security.application-groups - - group.com.wireguard.ios - - keychain-access-groups - - $(AppIdentifierPrefix)com.wireguard.ios - - - diff --git a/WireGuardTests/Info.plist b/WireGuardTests/Info.plist deleted file mode 100644 index 6c40a6c..0000000 --- a/WireGuardTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/WireGuardTests/ValidatorsTests.swift b/WireGuardTests/ValidatorsTests.swift deleted file mode 100644 index 39acd06..0000000 --- a/WireGuardTests/ValidatorsTests.swift +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright © 2018 WireGuard LLC. All rights reserved. -// - -import XCTest -@testable import WireGuard - -class ValidatorsTests: XCTestCase { - func testEndpoint() throws { - _ = try Endpoint(endpointString: "[2607:f938:3001:4000::aac]:12345") - _ = try Endpoint(endpointString: "192.168.0.1:12345") - } - - func testEndpoint_invalidIP() throws { - func executeTest(endpointString: String, ipString: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try Endpoint(endpointString: endpointString)) { (error) in - guard case EndpointValidationError.invalidIP(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, ipString, file: file, line: line) - } - } - - executeTest(endpointString: "12345:12345", ipString: "12345") - executeTest(endpointString: ":12345", ipString: "") - } - - func testEndpoint_invalidPort() throws { - func executeTest(endpointString: String, portString: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try Endpoint(endpointString: endpointString)) { (error) in - guard case EndpointValidationError.invalidPort(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, portString, file: file, line: line) - } - } - - executeTest(endpointString: ":", portString: "") - executeTest(endpointString: "[2607:f938:3001:4000::aac]:-12345", portString: "-12345") - executeTest(endpointString: "[2607:f938:3001:4000::aac]", portString: "aac]") - executeTest(endpointString: "[2607:f938:3001:4000::aac]:", portString: "") - executeTest(endpointString: "192.168.0.1:-12345", portString: "-12345") - executeTest(endpointString: "192.168.0.1:", portString: "") - - } - - func testEndpoint_noIpAndPort() throws { - - func executeTest(endpointString: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try Endpoint(endpointString: endpointString)) { (error) in - guard case EndpointValidationError.noIpAndPort(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, endpointString, file: file, line: line) - } - } - - executeTest(endpointString: "192.168.0.1") - executeTest(endpointString: "12345") - } - - func testCIDRAddress() throws { - _ = try CIDRAddress(stringRepresentation: "2607:f938:3001:4000::aac/24") - _ = try CIDRAddress(stringRepresentation: "192.168.0.1/24") - } - - func testIPv4CIDRAddress() throws { - _ = try CIDRAddress(stringRepresentation: "192.168.0.1/24") - } - - func testCIDRAddress_invalidIP() throws { - func executeTest(stringRepresentation: String, ipString: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try CIDRAddress(stringRepresentation: stringRepresentation)) { (error) in - guard case CIDRAddressValidationError.invalidIP(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, ipString, file: file, line: line) - } - } - - executeTest(stringRepresentation: "12345/12345", ipString: "12345") - executeTest(stringRepresentation: "/12345", ipString: "") - } - - func testCIDRAddress_invalidSubnet() throws { - func executeTest(stringRepresentation: String, subnetString: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try CIDRAddress(stringRepresentation: stringRepresentation)) { (error) in - guard case CIDRAddressValidationError.invalidSubnet(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, subnetString, file: file, line: line) - } - } - - executeTest(stringRepresentation: "/", subnetString: "") - executeTest(stringRepresentation: "2607:f938:3001:4000::aac/a", subnetString: "a") - executeTest(stringRepresentation: "2607:f938:3001:4000:/aac", subnetString: "aac") - executeTest(stringRepresentation: "2607:f938:3001:4000::aac/", subnetString: "") - executeTest(stringRepresentation: "192.168.0.1/a", subnetString: "a") - executeTest(stringRepresentation: "192.168.0.1/", subnetString: "") - - } - - func testCIDRAddress_noIpAndSubnet() throws { - - func executeTest(stringRepresentation: String, file: StaticString = #file, line: UInt = #line) { - XCTAssertThrowsError(try CIDRAddress(stringRepresentation: stringRepresentation)) { (error) in - guard case CIDRAddressValidationError.noIpAndSubnet(let value) = error else { - return XCTFail("Unexpected error: \(error)", file: file, line: line) - } - XCTAssertEqual(value, stringRepresentation, file: file, line: line) - } - } - - executeTest(stringRepresentation: "192.168.0.1") - executeTest(stringRepresentation: "12345") - } - - // swiftlint:disable next function_body_length - func testIPv4CIDRAddressSubnetConversion() throws { - // swiftlint:disable force_try - let cidrAddress1 = try! CIDRAddress(stringRepresentation: "128.0.0.0/1")! - XCTAssertEqual(cidrAddress1.ipAddress, cidrAddress1.subnetString) - let cidrAddress2 = try! CIDRAddress(stringRepresentation: "192.0.0.0/2")! - XCTAssertEqual(cidrAddress2.ipAddress, cidrAddress2.subnetString) - let cidrAddress3 = try! CIDRAddress(stringRepresentation: "224.0.0.0/3")! - XCTAssertEqual(cidrAddress3.ipAddress, cidrAddress3.subnetString) - let cidrAddress4 = try! CIDRAddress(stringRepresentation: "240.0.0.0/4")! - XCTAssertEqual(cidrAddress4.ipAddress, cidrAddress4.subnetString) - let cidrAddress5 = try! CIDRAddress(stringRepresentation: "248.0.0.0/5")! - XCTAssertEqual(cidrAddress5.ipAddress, cidrAddress5.subnetString) - let cidrAddress6 = try! CIDRAddress(stringRepresentation: "252.0.0.0/6")! - XCTAssertEqual(cidrAddress6.ipAddress, cidrAddress6.subnetString) - let cidrAddress7 = try! CIDRAddress(stringRepresentation: "254.0.0.0/7")! - XCTAssertEqual(cidrAddress7.ipAddress, cidrAddress7.subnetString) - let cidrAddress8 = try! CIDRAddress(stringRepresentation: "255.0.0.0/8")! - XCTAssertEqual(cidrAddress8.ipAddress, cidrAddress8.subnetString) - let cidrAddress9 = try! CIDRAddress(stringRepresentation: "255.128.0.0/9")! - XCTAssertEqual(cidrAddress9.ipAddress, cidrAddress9.subnetString) - let cidrAddress10 = try! CIDRAddress(stringRepresentation: "255.192.0.0/10")! - XCTAssertEqual(cidrAddress10.ipAddress, cidrAddress10.subnetString) - let cidrAddress11 = try! CIDRAddress(stringRepresentation: "255.224.0.0/11")! - XCTAssertEqual(cidrAddress11.ipAddress, cidrAddress11.subnetString) - let cidrAddress12 = try! CIDRAddress(stringRepresentation: "255.240.0.0/12")! - XCTAssertEqual(cidrAddress12.ipAddress, cidrAddress12.subnetString) - let cidrAddress13 = try! CIDRAddress(stringRepresentation: "255.248.0.0/13")! - XCTAssertEqual(cidrAddress13.ipAddress, cidrAddress13.subnetString) - let cidrAddress14 = try! CIDRAddress(stringRepresentation: "255.252.0.0/14")! - XCTAssertEqual(cidrAddress14.ipAddress, cidrAddress14.subnetString) - let cidrAddress15 = try! CIDRAddress(stringRepresentation: "255.254.0.0/15")! - XCTAssertEqual(cidrAddress15.ipAddress, cidrAddress15.subnetString) - let cidrAddress16 = try! CIDRAddress(stringRepresentation: "255.255.0.0/16")! - XCTAssertEqual(cidrAddress16.ipAddress, cidrAddress16.subnetString) - let cidrAddress17 = try! CIDRAddress(stringRepresentation: "255.255.128.0/17")! - XCTAssertEqual(cidrAddress17.ipAddress, cidrAddress17.subnetString) - let cidrAddress18 = try! CIDRAddress(stringRepresentation: "255.255.192.0/18")! - XCTAssertEqual(cidrAddress18.ipAddress, cidrAddress18.subnetString) - let cidrAddress19 = try! CIDRAddress(stringRepresentation: "255.255.224.0/19")! - XCTAssertEqual(cidrAddress19.ipAddress, cidrAddress19.subnetString) - let cidrAddress20 = try! CIDRAddress(stringRepresentation: "255.255.240.0/20")! - XCTAssertEqual(cidrAddress20.ipAddress, cidrAddress20.subnetString) - let cidrAddress21 = try! CIDRAddress(stringRepresentation: "255.255.248.0/21")! - XCTAssertEqual(cidrAddress21.ipAddress, cidrAddress21.subnetString) - let cidrAddress22 = try! CIDRAddress(stringRepresentation: "255.255.252.0/22")! - XCTAssertEqual(cidrAddress22.ipAddress, cidrAddress22.subnetString) - let cidrAddress23 = try! CIDRAddress(stringRepresentation: "255.255.254.0/23")! - XCTAssertEqual(cidrAddress23.ipAddress, cidrAddress23.subnetString) - let cidrAddress24 = try! CIDRAddress(stringRepresentation: "255.255.255.0/24")! - XCTAssertEqual(cidrAddress24.ipAddress, cidrAddress24.subnetString) - let cidrAddress25 = try! CIDRAddress(stringRepresentation: "255.255.255.128/25")! - XCTAssertEqual(cidrAddress25.ipAddress, cidrAddress25.subnetString) - let cidrAddress26 = try! CIDRAddress(stringRepresentation: "255.255.255.192/26")! - XCTAssertEqual(cidrAddress26.ipAddress, cidrAddress26.subnetString) - let cidrAddress27 = try! CIDRAddress(stringRepresentation: "255.255.255.224/27")! - XCTAssertEqual(cidrAddress27.ipAddress, cidrAddress27.subnetString) - let cidrAddress28 = try! CIDRAddress(stringRepresentation: "255.255.255.240/28")! - XCTAssertEqual(cidrAddress28.ipAddress, cidrAddress28.subnetString) - let cidrAddress29 = try! CIDRAddress(stringRepresentation: "255.255.255.248/29")! - XCTAssertEqual(cidrAddress29.ipAddress, cidrAddress29.subnetString) - let cidrAddress30 = try! CIDRAddress(stringRepresentation: "255.255.255.252/30")! - XCTAssertEqual(cidrAddress30.ipAddress, cidrAddress30.subnetString) - let cidrAddress31 = try! CIDRAddress(stringRepresentation: "255.255.255.254/31")! - XCTAssertEqual(cidrAddress31.ipAddress, cidrAddress31.subnetString) - let cidrAddress32 = try! CIDRAddress(stringRepresentation: "255.255.255.255/32")! - XCTAssertEqual(cidrAddress32.ipAddress, cidrAddress32.subnetString) - // swiftlint:enable force_try - } - -}