ThirdTabViewController.swift 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. //
  2. // ThirdTabViewController.swift
  3. // AppBuilder
  4. //
  5. // Created by Kevin Maulana on 30/03/22.
  6. //
  7. import UIKit
  8. import WebKit
  9. import NexilisLite
  10. import Speech
  11. import CommonCrypto
  12. class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler, ImageVideoPickerDelegate {
  13. var webView: WKWebView!
  14. var address = ""
  15. private var lastContentOffset: CGFloat = 0
  16. var isAllowSpeech = false
  17. var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))
  18. var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
  19. var recognitionTask : SFSpeechRecognitionTask?
  20. let audioEngine = AVAudioEngine()
  21. var alertController = LibAlertController()
  22. public static var forceRefresh = true
  23. public static var inView = false
  24. public static var atFirstPage = true
  25. public static var showModal = false
  26. var indexImageVideoWv = 0
  27. var imageVideoPicker: ImageVideoPicker!
  28. var blockedCertificate = ""
  29. var allowedURLs = Set<String>()
  30. override func viewDidLoad() {
  31. super.viewDidLoad()
  32. self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
  33. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
  34. tapGesture.cancelsTouchesInView = false
  35. tapGesture.delegate = self
  36. let configuration = WKWebViewConfiguration()
  37. configuration.allowsInlineMediaPlayback = true
  38. let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
  39. let finalUserAgent = "\(customUserAgent)"
  40. configuration.applicationNameForUserAgent = finalUserAgent
  41. webView = WKWebView(frame: .zero, configuration: configuration)
  42. view.addSubview(webView)
  43. webView.translatesAutoresizingMaskIntoConstraints = false
  44. NSLayoutConstraint.activate([
  45. webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
  46. webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
  47. webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
  48. webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
  49. ])
  50. webView.scrollView.addGestureRecognizer(tapGesture)
  51. let refreshControl = UIRefreshControl()
  52. refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
  53. webView.scrollView.addSubview(refreshControl)
  54. webView.scrollView.delegate = self
  55. webView.navigationDelegate = self
  56. webView.allowsBackForwardNavigationGestures = true
  57. let contentController = self.webView.configuration.userContentController
  58. contentController.add(self, name: "checkProfile")
  59. contentController.add(self, name: "setIsProductModalOpen")
  60. contentController.add(self, name: "toggleVoiceSearch")
  61. contentController.add(self, name: "blockUser")
  62. contentController.add(self, name: "showAlert")
  63. contentController.add(self, name: "closeProfile")
  64. contentController.add(self, name: "tabShowHide")
  65. contentController.add(self, name: "shareText")
  66. contentController.add(self, name: "openGalleryiOS")
  67. let source: String = "var meta = document.createElement('meta');" +
  68. "meta.name = 'viewport';" +
  69. "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
  70. "var head = document.getElementsByTagName('head')[0];" +
  71. "head.appendChild(meta);" +
  72. "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
  73. "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
  74. let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
  75. contentController.addUserScript(script)
  76. let cookieScript1 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[0])';"
  77. let cookieScriptInjection1 = WKUserScript(source: cookieScript1, injectionTime: .atDocumentStart, forMainFrameOnly: false)
  78. configuration.userContentController.addUserScript(cookieScriptInjection1)
  79. let cookieScript2 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[1])';"
  80. let cookieScriptInjection2 = WKUserScript(source: cookieScript2, injectionTime: .atDocumentStart, forMainFrameOnly: false)
  81. configuration.userContentController.addUserScript(cookieScriptInjection2)
  82. NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
  83. NotificationCenter.default.addObserver(self, selector: #selector(onRefreshWebView(notification:)), name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil)
  84. imageVideoPicker = ImageVideoPicker(presentationController: self, delegate: self)
  85. }
  86. func loadURLWithCookie(url: URL) {
  87. var urlRequest = URLRequest(url: url)
  88. let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
  89. urlRequest.setValue(customUserAgent, forHTTPHeaderField: "User-Agent")
  90. if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
  91. for cookie in cookies {
  92. webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
  93. }
  94. webView.load(urlRequest)
  95. }
  96. }
  97. override func viewWillAppear(_ animated: Bool) {
  98. if ThirdTabViewController.inView {
  99. return
  100. }
  101. ThirdTabViewController.inView = true
  102. let me = User.getMyPin()
  103. var myURL : URL?
  104. let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? "en"
  105. var intLang = 0
  106. if lang == "id" {
  107. speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
  108. intLang = 1
  109. }
  110. if PrefsUtil.getURLThirdTab() != nil {
  111. ViewController.tab3 = PrefsUtil.getURLThirdTab()!
  112. }
  113. switch(ViewController.tab3){
  114. case "0":
  115. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  116. myURL = URL(string: address)
  117. case "1":
  118. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  119. myURL = URL(string: address)
  120. case "2":
  121. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  122. myURL = URL(string: address)
  123. case "3":
  124. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  125. myURL = URL(string: address)
  126. case "4":
  127. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  128. myURL = URL(string: address)
  129. default:
  130. if(!ViewController.tab3.isEmpty){
  131. if(ViewController.tab3.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
  132. address = ViewController.tab3
  133. myURL = URL(string: address)
  134. }
  135. else {
  136. if ViewController.tab3.contains("nexilis/pages"){
  137. address = "\(PrefsUtil.getURLBase())\(ViewController.tab3)?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
  138. } else {
  139. address = "https://\(ViewController.tab3)"
  140. }
  141. myURL = URL(string: address)
  142. }
  143. }
  144. }
  145. //print(address)
  146. if let u = myURL{
  147. self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
  148. if ThirdTabViewController.forceRefresh {
  149. loadURLWithCookie(url: u)
  150. } else {
  151. self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
  152. }
  153. ThirdTabViewController.forceRefresh = false
  154. }
  155. navigationController?.setNavigationBarHidden(true, animated: false)
  156. }
  157. func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  158. if Utils.getIsLoadThemeFromOther() {
  159. self.webView.evaluateJavaScript("{window.localStorage.setItem('mobileConfiguration','"+Utils.getMyTheme()+"')}")
  160. }
  161. }
  162. override func viewDidAppear(_ animated: Bool) {
  163. DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
  164. // if (self.isUsingMyWebview() && self.webView.url != nil && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-commerce") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-video") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main")) || ThirdTabViewController.showModal {
  165. // ViewController.alwaysHideButton = true
  166. // self.hideTabBar()
  167. // ThirdTabViewController.atFirstPage = false
  168. // } else {
  169. var viewController = UIApplication.shared.windows.first!.rootViewController
  170. if !(viewController is ViewController) {
  171. viewController = self.parent
  172. }
  173. if ViewController.middleButton.isHidden {
  174. ViewController.isExpandButton = false
  175. if let viewController = viewController as? ViewController {
  176. if viewController.tabBar.isHidden {
  177. viewController.tabBar.isHidden = false
  178. ViewController.middleButton.isHidden = false
  179. ViewController.alwaysHideButton = false
  180. }
  181. }
  182. } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
  183. DispatchQueue.main.async {
  184. if let viewController = viewController as? ViewController {
  185. if viewController.tabBar.isHidden {
  186. viewController.tabBar.isHidden = false
  187. ViewController.alwaysHideButton = false
  188. }
  189. }
  190. }
  191. }
  192. // }
  193. })
  194. }
  195. @objc func onShowAC(notification: NSNotification) {
  196. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  197. view.endEditing(true)
  198. resignFirstResponder()
  199. }
  200. @objc func onRefreshWebView(notification: NSNotification) {
  201. ThirdTabViewController.forceRefresh = true
  202. }
  203. override func viewWillDisappear(_ animated: Bool) {
  204. if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
  205. self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
  206. }
  207. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  208. view.endEditing(true)
  209. resignFirstResponder()
  210. ThirdTabViewController.inView = false
  211. self.webView.evaluateJavaScript("hideAddToCart();")
  212. }
  213. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  214. if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
  215. showTabBar();
  216. }
  217. else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
  218. hideTabBar();
  219. }
  220. self.lastContentOffset = scrollView.contentOffset.y
  221. self.collapseDocked()
  222. }
  223. @objc func collapseDocked() {
  224. if ViewController.isExpandButton {
  225. ViewController.expandButton()
  226. }
  227. }
  228. @objc func reloadWebView(_ sender: UIRefreshControl) {
  229. webView.reload()
  230. ViewController.alwaysHideButton = false
  231. showTabBar()
  232. sender.endRefreshing()
  233. }
  234. func hideTabBar() {
  235. var viewController = UIApplication.shared.windows.first!.rootViewController
  236. if !(viewController is ViewController) {
  237. viewController = self.parent
  238. }
  239. if ViewController.middleButton.isDescendant(of: viewController!.view) {
  240. DispatchQueue.main.async {
  241. if ViewController.isExpandButton {
  242. ViewController.expandButton()
  243. }
  244. ViewController.hideDockedButton()
  245. if let viewController = viewController as? ViewController {
  246. viewController.tabBar.isHidden = true
  247. }
  248. ViewController.removeMiddleButton()
  249. }
  250. } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
  251. DispatchQueue.main.async {
  252. if let viewController = viewController as? ViewController {
  253. if !viewController.tabBar.isHidden {
  254. viewController.tabBar.isHidden = true
  255. }
  256. }
  257. }
  258. }
  259. }
  260. func showTabBar() {
  261. if(ViewController.alwaysHideButton){
  262. return
  263. }
  264. var viewController = UIApplication.shared.windows.first!.rootViewController
  265. if !(viewController is ViewController) {
  266. viewController = self.parent
  267. }
  268. if ViewController.middleButton.isHidden {
  269. if let viewController = viewController as? ViewController {
  270. viewController.tabBar.isHidden = false
  271. ViewController.middleButton.isHidden = false
  272. }
  273. } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
  274. DispatchQueue.main.async {
  275. if let viewController = viewController as? ViewController {
  276. if viewController.tabBar.isHidden {
  277. viewController.tabBar.isHidden = false
  278. }
  279. }
  280. }
  281. }
  282. }
  283. func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
  284. scrollView.pinchGestureRecognizer?.isEnabled = false
  285. }
  286. func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  287. if message.name == "checkProfile" {
  288. guard let dict = message.body as? [String: AnyObject],
  289. let param1 = dict["param1"] as? String,
  290. let param2 = dict["param2"] as? String else {
  291. return
  292. }
  293. if ViewController.checkIsChangePerson() {
  294. if param2 == "like" {
  295. self.webView.evaluateJavaScript("likeProduct('\(param1)',1,true);")
  296. } else if param2 == "comment" {
  297. self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
  298. } else if param2 == "report_user" {
  299. self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
  300. } else if param2 == "report_content" {
  301. self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
  302. } else if param2 == "block_user" {
  303. self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
  304. } else if param2 == "follow_user" {
  305. self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
  306. } else if param2 == "homepage" || param2 == "gif" {
  307. self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
  308. } else if param2 == "block_content" {
  309. self.webView.evaluateJavaScript("blockContent('\(param1)',true);")
  310. } else {
  311. self.webView.evaluateJavaScript("openNewPost(true);")
  312. }
  313. } else {
  314. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  315. }
  316. } else if message.name == "setIsProductModalOpen" {
  317. guard let dict = message.body as? [String: AnyObject],
  318. let param1 = dict["param1"] as? Bool else {
  319. return
  320. }
  321. if param1 {
  322. if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
  323. self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
  324. }
  325. }
  326. ThirdTabViewController.showModal = param1
  327. } else if message.name == "toggleVoiceSearch" {
  328. if !isAllowSpeech {
  329. setupSpeech()
  330. } else {
  331. runVoice()
  332. }
  333. } else if message.name == "blockUser" {
  334. guard let dict = message.body as? [String: AnyObject],
  335. let param1 = dict["param1"] as? String,
  336. let param2 = dict["param2"] as? Bool else {
  337. return
  338. }
  339. if param2 {
  340. DispatchQueue.global().async {
  341. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
  342. if response.isOk() {
  343. DispatchQueue.main.async {
  344. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  345. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  346. "ex_block" : "1"
  347. ], _where: "f_pin = '\(param1)'")
  348. })
  349. }
  350. }
  351. }
  352. }
  353. } else {
  354. DispatchQueue.global().async {
  355. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
  356. if response.isOk() {
  357. DispatchQueue.main.async {
  358. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  359. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  360. "ex_block" : "0"
  361. ], _where: "f_pin = '\(param1)'")
  362. })
  363. }
  364. }
  365. }
  366. }
  367. }
  368. } else if message.name == "showAlert" {
  369. guard let dict = message.body as? [String: AnyObject],
  370. let param1 = dict["param1"] as? String else {
  371. return
  372. }
  373. self.view.makeToast(param1, duration: 3)
  374. } else if message.name == "blockUser" {
  375. guard let dict = message.body as? [String: AnyObject],
  376. let param1 = dict["param1"] as? String,
  377. let param2 = dict["param2"] as? Bool else {
  378. return
  379. }
  380. if param2 {
  381. DispatchQueue.global().async {
  382. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
  383. if response.isOk() {
  384. DispatchQueue.main.async {
  385. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  386. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  387. "ex_block" : "1"
  388. ], _where: "f_pin = '\(param1)'")
  389. })
  390. }
  391. }
  392. }
  393. }
  394. } else {
  395. DispatchQueue.global().async {
  396. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
  397. if response.isOk() {
  398. DispatchQueue.main.async {
  399. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  400. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  401. "ex_block" : "0"
  402. ], _where: "f_pin = '\(param1)'")
  403. })
  404. }
  405. }
  406. }
  407. }
  408. }
  409. } else if message.name == "tabShowHide" {
  410. guard let dict = message.body as? [String: AnyObject],
  411. let param1 = dict["param1"] as? Bool else {
  412. return
  413. }
  414. if param1 {
  415. ViewController.alwaysHideButton = false
  416. showTabBar()
  417. } else {
  418. if self.viewIfLoaded?.window != nil {
  419. ViewController.alwaysHideButton = true
  420. hideTabBar()
  421. }
  422. }
  423. } else if message.name == "shareText" {
  424. guard let dict = message.body as? [String: AnyObject],
  425. let param1 = dict["param1"] as? String else {
  426. return
  427. }
  428. let activityViewController = UIActivityViewController(activityItems: [param1], applicationActivities: nil)
  429. self.present(activityViewController, animated: true, completion: nil)
  430. } else if message.name == "openGalleryiOS" {
  431. guard let dict = message.body as? [String: AnyObject],
  432. let param1 = dict["param1"] as? Int else {
  433. return
  434. }
  435. indexImageVideoWv = param1
  436. let alertController = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
  437. if let action = self.actionImageVideo(for: "image", title: "Choose Photo".localized()) {
  438. alertController.addAction(action)
  439. }
  440. if let action = self.actionImageVideo(for: "video", title: "Choose Video".localized()) {
  441. alertController.addAction(action)
  442. }
  443. alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
  444. self.present(alertController, animated: true)
  445. }
  446. }
  447. private func actionImageVideo(for type: String, title: String) -> UIAlertAction? {
  448. return UIAlertAction(title: title, style: .default) { [unowned self] _ in
  449. switch type {
  450. case "image":
  451. imageVideoPicker.present(source: .imageAlbum)
  452. case "video":
  453. imageVideoPicker.present(source: .videoAlbum)
  454. default:
  455. imageVideoPicker.present(source: .imageAlbum)
  456. }
  457. }
  458. }
  459. func didSelect(imagevideo: Any?) {
  460. if imagevideo != nil {
  461. let imageData = imagevideo! as! [UIImagePickerController.InfoKey : Any]
  462. if (imageData[.mediaType] as! String == "public.image") {
  463. let compressedImage = (imageData[.originalImage] as! UIImage).pngData()!
  464. let base64String = compressedImage.base64EncodedString()
  465. let base64ToWeb = "data:image/jpeg;base64,\(base64String)"
  466. webView.evaluateJavaScript("loadFromMobile('\(base64ToWeb)',\(indexImageVideoWv))") { (result, error) in
  467. if let error = error {
  468. print("Error executing JavaScript: \(error)")
  469. }
  470. }
  471. } else {
  472. guard var dataVideo = try? Data(contentsOf: imageData[.mediaURL] as! URL) else {
  473. return
  474. }
  475. let sizeOfVideo = Double(dataVideo.count / 1048576)
  476. if (sizeOfVideo > 10.0) {
  477. let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + UUID().uuidString + ".mp4")
  478. compressVideo(inputURL: imageData[.mediaURL] as! URL,
  479. outputURL: compressedURL) { exportSession in
  480. guard let session = exportSession else {
  481. return
  482. }
  483. switch session.status {
  484. case .unknown:
  485. break
  486. case .waiting:
  487. break
  488. case .exporting:
  489. break
  490. case .completed:
  491. guard let compressedData = try? Data(contentsOf: compressedURL) else {
  492. return
  493. }
  494. dataVideo = compressedData
  495. case .failed:
  496. break
  497. case .cancelled:
  498. break
  499. @unknown default:
  500. break
  501. }
  502. }
  503. }
  504. let base64String = dataVideo.base64EncodedString()
  505. let base64ToWeb = "data:video/mp4;base64,\(base64String)"
  506. webView.evaluateJavaScript("loadFromMobile('\(base64ToWeb)',\(indexImageVideoWv))") { (result, error) in
  507. if let error = error {
  508. print("Error executing JavaScript: \(error)")
  509. }
  510. }
  511. }
  512. }
  513. }
  514. func compressVideo(inputURL: URL,
  515. outputURL: URL,
  516. handler:@escaping (_ exportSession: AVAssetExportSession?) -> Void) {
  517. let urlAsset = AVURLAsset(url: inputURL, options: nil)
  518. guard let exportSession = AVAssetExportSession(asset: urlAsset,
  519. presetName: AVAssetExportPresetMediumQuality) else {
  520. handler(nil)
  521. return
  522. }
  523. exportSession.outputURL = outputURL
  524. exportSession.outputFileType = .mp4
  525. exportSession.exportAsynchronously {
  526. handler(exportSession)
  527. }
  528. }
  529. func setupSpeech() {
  530. self.speechRecognizer?.delegate = self
  531. SFSpeechRecognizer.requestAuthorization { (authStatus) in
  532. var isButtonEnabled = false
  533. switch authStatus {
  534. case .authorized:
  535. isButtonEnabled = true
  536. case .denied:
  537. isButtonEnabled = false
  538. //print("User denied access to speech recognition")
  539. case .restricted:
  540. isButtonEnabled = false
  541. //print("Speech recognition restricted on this device")
  542. case .notDetermined:
  543. isButtonEnabled = false
  544. //print("Speech recognition not yet authorized")
  545. @unknown default:
  546. isButtonEnabled = false
  547. }
  548. OperationQueue.main.addOperation() {
  549. self.isAllowSpeech = isButtonEnabled
  550. if isButtonEnabled {
  551. SecureUserDefaults.shared.set(isButtonEnabled, forKey: "allowSpeech")
  552. self.runVoice()
  553. }
  554. }
  555. }
  556. }
  557. func runVoice() {
  558. if !audioEngine.isRunning {
  559. alertController = LibAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
  560. self.present(alertController, animated: true)
  561. self.webView.evaluateJavaScript("toggleVoiceButton(true)")
  562. self.startRecording()
  563. }
  564. }
  565. func startRecording() {
  566. // Clear all previous session data and cancel task
  567. if recognitionTask != nil {
  568. recognitionTask?.cancel()
  569. recognitionTask = nil
  570. }
  571. // Create instance of audio session to record voice
  572. let audioSession = AVAudioSession.sharedInstance()
  573. do {
  574. try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
  575. try audioSession.setMode(AVAudioSession.Mode.measurement)
  576. try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
  577. } catch {
  578. //print("audioSession properties weren't set because of an error.")
  579. }
  580. self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
  581. let inputNode = audioEngine.inputNode
  582. guard let recognitionRequest = recognitionRequest else {
  583. fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
  584. }
  585. recognitionRequest.shouldReportPartialResults = true
  586. self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
  587. var isFinal = false
  588. var text = ""
  589. if result != nil {
  590. text = result?.bestTranscription.formattedString ?? ""
  591. isFinal = (result?.isFinal)!
  592. self.alertController.dismiss(animated: true)
  593. self.audioEngine.stop()
  594. self.recognitionRequest?.endAudio()
  595. } else {
  596. self.alertController.dismiss(animated: true)
  597. }
  598. if error != nil || isFinal {
  599. if error == nil {
  600. self.webView.evaluateJavaScript("toggleVoiceButton(false)")
  601. self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
  602. } else {
  603. self.audioEngine.stop()
  604. self.recognitionRequest?.endAudio()
  605. }
  606. inputNode.removeTap(onBus: 0)
  607. self.recognitionRequest = nil
  608. self.recognitionTask = nil
  609. self.isAllowSpeech = true
  610. }
  611. })
  612. let recordingFormat = inputNode.outputFormat(forBus: 0)
  613. inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
  614. self.recognitionRequest?.append(buffer)
  615. }
  616. self.audioEngine.prepare()
  617. do {
  618. try self.audioEngine.start()
  619. } catch {
  620. //print("audioEngine couldn't start because of an error.")
  621. }
  622. }
  623. func isUsingMyWebview() -> Bool{
  624. return PrefsUtil.getURLThirdTab() == "0" || PrefsUtil.getURLThirdTab() == "1" || PrefsUtil.getURLThirdTab() == "2" || PrefsUtil.getURLThirdTab() == "3" || PrefsUtil.getURLThirdTab() == "4"
  625. }
  626. }
  627. extension ThirdTabViewController: SFSpeechRecognizerDelegate {
  628. func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
  629. if available {
  630. self.isAllowSpeech = true
  631. } else {
  632. self.isAllowSpeech = false
  633. }
  634. }
  635. }
  636. extension ThirdTabViewController: WKUIDelegate {
  637. func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) {
  638. guard let url = navigationAction.request.url else {
  639. decisionHandler(.cancel)
  640. return
  641. }
  642. if allowedURLs.contains(url.absoluteString) {
  643. if ViewController.alwaysHideButton {
  644. ViewController.alwaysHideButton = false
  645. showTabBar()
  646. }
  647. print("✅ URL already allowed: \(url)")
  648. decisionHandler(.allow)
  649. return
  650. }
  651. validateSSLCertificate(url: url) { isValid in
  652. print("is VALID? : \(isValid)")
  653. if isValid {
  654. self.allowedURLs.insert(url.absoluteString)
  655. decisionHandler(.allow)
  656. } else {
  657. let host = url.host ?? ""
  658. DispatchQueue.main.async {
  659. var messageText = "You're about to access a website that is not currently trusted by your Nexilis Browser. This website's security certificate is not recognized.\n\nDo you wish to proceed to <<domain>> and trust the website's security certificate?\n\nNote: Adding a website to the trusted list may increase your risk of security vulnerability".localized()
  660. messageText = messageText.replacingOccurrences(of: "<<domain>>", with: host)
  661. let alert = UIAlertController(title: "Warning Unknown Url!".localized(),
  662. message: messageText,
  663. preferredStyle: .alert)
  664. let yesAction = UIAlertAction(title: "Yes", style: .default) { _ in
  665. let storedCertificate = Utils.getCertificatePinningWebview()
  666. if let jsonData = storedCertificate.data(using: .utf8),
  667. let certJson = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] {
  668. var certJson = certJson
  669. certJson[host] = self.blockedCertificate
  670. if let jsonData = try? JSONSerialization.data(withJSONObject: certJson, options: []),
  671. let jsonString = String(data: jsonData, encoding: .utf8) {
  672. Utils.setCertificatePinningWebview(value: jsonString)
  673. }
  674. }
  675. self.allowedURLs.insert(url.absoluteString)
  676. decisionHandler(.allow)
  677. }
  678. let noAction = UIAlertAction(title: "No", style: .cancel) { _ in
  679. decisionHandler(.cancel)
  680. }
  681. alert.addAction(yesAction)
  682. alert.addAction(noAction)
  683. self.present(alert, animated: true, completion: nil)
  684. }
  685. }
  686. }
  687. }
  688. private func validateSSLCertificate(url: URL, completion: @escaping (Bool) -> Void) {
  689. let session = URLSession(configuration: .ephemeral, delegate: self, delegateQueue: nil)
  690. let request = URLRequest(url: url)
  691. let task = session.dataTask(with: request) { _, response, error in
  692. if let error = error {
  693. print("SSL Validation Error: \(error.localizedDescription)")
  694. completion(false)
  695. return
  696. }
  697. completion(true)
  698. }
  699. task.resume()
  700. }
  701. }
  702. extension ThirdTabViewController: URLSessionDelegate {
  703. func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
  704. guard let serverTrust = challenge.protectionSpace.serverTrust else {
  705. completionHandler(.cancelAuthenticationChallenge, nil)
  706. return
  707. }
  708. if let publicKeyHash = extractPublicKeyHash(from: serverTrust) {
  709. let domain = challenge.protectionSpace.host
  710. let storedCertificate = Utils.getCertificatePinningWebview()
  711. if let jsonData = storedCertificate.data(using: .utf8),
  712. let certJson = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] {
  713. if publicKeyHash == certJson[domain] {
  714. print("✅ Certificate Matched. Allowing Navigation.")
  715. completionHandler(.useCredential, URLCredential(trust: serverTrust))
  716. } else {
  717. print("❌ Certificate Mismatch! Blocking Navigation.")
  718. blockedCertificate = publicKeyHash
  719. completionHandler(.cancelAuthenticationChallenge, nil)
  720. }
  721. }
  722. } else {
  723. completionHandler(.cancelAuthenticationChallenge, nil)
  724. }
  725. }
  726. func extractPublicKeyHash(from serverTrust: SecTrust) -> String? {
  727. guard let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else { return nil }
  728. guard let publicKey = SecCertificateCopyKey(certificate) else { return nil }
  729. var error: Unmanaged<CFError>?
  730. guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
  731. print("❌ Failed to extract public key")
  732. return nil
  733. }
  734. // Compute SHA-256 hash
  735. var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
  736. publicKeyData.withUnsafeBytes {
  737. _ = CC_SHA256($0.baseAddress, CC_LONG(publicKeyData.count), &hash)
  738. }
  739. let hashData = Data(hash)
  740. let base64Hash = hashData.base64EncodedString()
  741. return base64Hash
  742. }
  743. }