123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824 |
- //
- // ThirdTabViewController.swift
- // AppBuilder
- //
- // Created by Kevin Maulana on 30/03/22.
- //
- import UIKit
- import WebKit
- import NexilisLite
- import Speech
- import CommonCrypto
- class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler, ImageVideoPickerDelegate {
- var webView: WKWebView!
- var address = ""
- private var lastContentOffset: CGFloat = 0
-
- var isAllowSpeech = false
-
- var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))
- var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
- var recognitionTask : SFSpeechRecognitionTask?
- let audioEngine = AVAudioEngine()
- var alertController = LibAlertController()
-
- public static var forceRefresh = true
- public static var inView = false
- public static var atFirstPage = true
- public static var showModal = false
-
- var indexImageVideoWv = 0
- var imageVideoPicker: ImageVideoPicker!
- var blockedCertificate = ""
- var allowedURLs = Set<String>()
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
-
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
- tapGesture.cancelsTouchesInView = false
- tapGesture.delegate = self
- let configuration = WKWebViewConfiguration()
- configuration.allowsInlineMediaPlayback = true
- 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())"
- let finalUserAgent = "\(customUserAgent)"
- configuration.applicationNameForUserAgent = finalUserAgent
- webView = WKWebView(frame: .zero, configuration: configuration)
- view.addSubview(webView)
- webView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
- ])
- webView.scrollView.addGestureRecognizer(tapGesture)
- let refreshControl = UIRefreshControl()
- refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
- webView.scrollView.addSubview(refreshControl)
- webView.scrollView.delegate = self
- webView.navigationDelegate = self
- webView.allowsBackForwardNavigationGestures = true
-
- let contentController = self.webView.configuration.userContentController
- contentController.add(self, name: "checkProfile")
- contentController.add(self, name: "setIsProductModalOpen")
- contentController.add(self, name: "toggleVoiceSearch")
- contentController.add(self, name: "blockUser")
- contentController.add(self, name: "showAlert")
- contentController.add(self, name: "closeProfile")
- contentController.add(self, name: "tabShowHide")
- contentController.add(self, name: "shareText")
- contentController.add(self, name: "openGalleryiOS")
-
- let source: String = "var meta = document.createElement('meta');" +
- "meta.name = 'viewport';" +
- "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
- "var head = document.getElementsByTagName('head')[0];" +
- "head.appendChild(meta);" +
- "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
- "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
- let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
- contentController.addUserScript(script)
-
- let cookieScript1 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[0])';"
- let cookieScriptInjection1 = WKUserScript(source: cookieScript1, injectionTime: .atDocumentStart, forMainFrameOnly: false)
- configuration.userContentController.addUserScript(cookieScriptInjection1)
-
- let cookieScript2 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[1])';"
- let cookieScriptInjection2 = WKUserScript(source: cookieScript2, injectionTime: .atDocumentStart, forMainFrameOnly: false)
- configuration.userContentController.addUserScript(cookieScriptInjection2)
-
- NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
- NotificationCenter.default.addObserver(self, selector: #selector(onRefreshWebView(notification:)), name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil)
-
- imageVideoPicker = ImageVideoPicker(presentationController: self, delegate: self)
- }
-
- func loadURLWithCookie(url: URL) {
- var urlRequest = URLRequest(url: url)
- 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())"
- urlRequest.setValue(customUserAgent, forHTTPHeaderField: "User-Agent")
- if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
- for cookie in cookies {
- webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
- }
- webView.load(urlRequest)
- }
- }
-
- override func viewWillAppear(_ animated: Bool) {
- if ThirdTabViewController.inView {
- return
- }
- ThirdTabViewController.inView = true
- let me = User.getMyPin()
-
- var myURL : URL?
- let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? "en"
- var intLang = 0
- if lang == "id" {
- speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
- intLang = 1
- }
- if PrefsUtil.getURLThirdTab() != nil {
- ViewController.tab3 = PrefsUtil.getURLThirdTab()!
- }
- switch(ViewController.tab3){
- case "0":
- address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- myURL = URL(string: address)
- case "1":
- address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- myURL = URL(string: address)
- case "2":
- address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- myURL = URL(string: address)
- case "3":
- address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- myURL = URL(string: address)
- case "4":
- address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- myURL = URL(string: address)
- default:
- if(!ViewController.tab3.isEmpty){
- if(ViewController.tab3.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
- address = ViewController.tab3
- myURL = URL(string: address)
- }
- else {
- if ViewController.tab3.contains("nexilis/pages"){
- address = "\(PrefsUtil.getURLBase())\(ViewController.tab3)?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
- } else {
- address = "https://\(ViewController.tab3)"
- }
- myURL = URL(string: address)
- }
- }
- }
- //print(address)
- if let u = myURL{
- self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
- if ThirdTabViewController.forceRefresh {
- loadURLWithCookie(url: u)
- } else {
- self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
- }
- ThirdTabViewController.forceRefresh = false
- }
- navigationController?.setNavigationBarHidden(true, animated: false)
- }
-
- func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
- if Utils.getIsLoadThemeFromOther() {
- self.webView.evaluateJavaScript("{window.localStorage.setItem('mobileConfiguration','"+Utils.getMyTheme()+"')}")
- }
- }
-
- override func viewDidAppear(_ animated: Bool) {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
- // 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 {
- // ViewController.alwaysHideButton = true
- // self.hideTabBar()
- // ThirdTabViewController.atFirstPage = false
- // } else {
- var viewController = UIApplication.shared.windows.first!.rootViewController
- if !(viewController is ViewController) {
- viewController = self.parent
- }
- if ViewController.middleButton.isHidden {
- ViewController.isExpandButton = false
- if let viewController = viewController as? ViewController {
- if viewController.tabBar.isHidden {
- viewController.tabBar.isHidden = false
- ViewController.middleButton.isHidden = false
- ViewController.alwaysHideButton = false
- }
- }
- } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
- DispatchQueue.main.async {
- if let viewController = viewController as? ViewController {
- if viewController.tabBar.isHidden {
- viewController.tabBar.isHidden = false
- ViewController.alwaysHideButton = false
- }
- }
- }
- }
- // }
- })
- }
-
- @objc func onShowAC(notification: NSNotification) {
- self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
- view.endEditing(true)
- resignFirstResponder()
- }
-
- @objc func onRefreshWebView(notification: NSNotification) {
- ThirdTabViewController.forceRefresh = true
- }
-
- override func viewWillDisappear(_ animated: Bool) {
- if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
- self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
- }
- self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
- view.endEditing(true)
- resignFirstResponder()
- ThirdTabViewController.inView = false
- self.webView.evaluateJavaScript("hideAddToCart();")
- }
-
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
- if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
- showTabBar();
- }
- else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
- hideTabBar();
- }
- self.lastContentOffset = scrollView.contentOffset.y
- self.collapseDocked()
- }
-
- @objc func collapseDocked() {
- if ViewController.isExpandButton {
- ViewController.expandButton()
- }
- }
-
- @objc func reloadWebView(_ sender: UIRefreshControl) {
- webView.reload()
- ViewController.alwaysHideButton = false
- showTabBar()
- sender.endRefreshing()
- }
- func hideTabBar() {
- var viewController = UIApplication.shared.windows.first!.rootViewController
- if !(viewController is ViewController) {
- viewController = self.parent
- }
- if ViewController.middleButton.isDescendant(of: viewController!.view) {
- DispatchQueue.main.async {
- if ViewController.isExpandButton {
- ViewController.expandButton()
- }
- ViewController.hideDockedButton()
- if let viewController = viewController as? ViewController {
- viewController.tabBar.isHidden = true
- }
- ViewController.removeMiddleButton()
- }
- } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
- DispatchQueue.main.async {
- if let viewController = viewController as? ViewController {
- if !viewController.tabBar.isHidden {
- viewController.tabBar.isHidden = true
- }
- }
- }
- }
- }
- func showTabBar() {
- if(ViewController.alwaysHideButton){
- return
- }
- var viewController = UIApplication.shared.windows.first!.rootViewController
- if !(viewController is ViewController) {
- viewController = self.parent
- }
- if ViewController.middleButton.isHidden {
- if let viewController = viewController as? ViewController {
- viewController.tabBar.isHidden = false
- ViewController.middleButton.isHidden = false
- }
- } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
- DispatchQueue.main.async {
- if let viewController = viewController as? ViewController {
- if viewController.tabBar.isHidden {
- viewController.tabBar.isHidden = false
- }
- }
- }
- }
- }
- func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
- scrollView.pinchGestureRecognizer?.isEnabled = false
- }
- func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
- if message.name == "checkProfile" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? String,
- let param2 = dict["param2"] as? String else {
- return
- }
- if ViewController.checkIsChangePerson() {
- if param2 == "like" {
- self.webView.evaluateJavaScript("likeProduct('\(param1)',1,true);")
- } else if param2 == "comment" {
- self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
- } else if param2 == "report_user" {
- self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
- } else if param2 == "report_content" {
- self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
- } else if param2 == "block_user" {
- self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
- } else if param2 == "follow_user" {
- self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
- } else if param2 == "homepage" || param2 == "gif" {
- self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
- } else if param2 == "block_content" {
- self.webView.evaluateJavaScript("blockContent('\(param1)',true);")
- } else {
- self.webView.evaluateJavaScript("openNewPost(true);")
- }
- } else {
- self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
- }
- } else if message.name == "setIsProductModalOpen" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? Bool else {
- return
- }
- if param1 {
- if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
- self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
- }
- }
- ThirdTabViewController.showModal = param1
- } else if message.name == "toggleVoiceSearch" {
- if !isAllowSpeech {
- setupSpeech()
- } else {
- runVoice()
- }
- } else if message.name == "blockUser" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? String,
- let param2 = dict["param2"] as? Bool else {
- return
- }
- if param2 {
- DispatchQueue.global().async {
- if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
- if response.isOk() {
- DispatchQueue.main.async {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
- "ex_block" : "1"
- ], _where: "f_pin = '\(param1)'")
- })
- }
- }
- }
- }
- } else {
- DispatchQueue.global().async {
- if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
- if response.isOk() {
- DispatchQueue.main.async {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
- "ex_block" : "0"
- ], _where: "f_pin = '\(param1)'")
- })
- }
- }
- }
- }
- }
- } else if message.name == "showAlert" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? String else {
- return
- }
- self.view.makeToast(param1, duration: 3)
- } else if message.name == "blockUser" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? String,
- let param2 = dict["param2"] as? Bool else {
- return
- }
- if param2 {
- DispatchQueue.global().async {
- if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
- if response.isOk() {
- DispatchQueue.main.async {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
- "ex_block" : "1"
- ], _where: "f_pin = '\(param1)'")
- })
- }
- }
- }
- }
- } else {
- DispatchQueue.global().async {
- if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
- if response.isOk() {
- DispatchQueue.main.async {
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
- "ex_block" : "0"
- ], _where: "f_pin = '\(param1)'")
- })
- }
- }
- }
- }
- }
- } else if message.name == "tabShowHide" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? Bool else {
- return
- }
- if param1 {
- ViewController.alwaysHideButton = false
- showTabBar()
- } else {
- if self.viewIfLoaded?.window != nil {
- ViewController.alwaysHideButton = true
- hideTabBar()
- }
- }
- } else if message.name == "shareText" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? String else {
- return
- }
- let activityViewController = UIActivityViewController(activityItems: [param1], applicationActivities: nil)
- self.present(activityViewController, animated: true, completion: nil)
- } else if message.name == "openGalleryiOS" {
- guard let dict = message.body as? [String: AnyObject],
- let param1 = dict["param1"] as? Int else {
- return
- }
- indexImageVideoWv = param1
- let alertController = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
-
- if let action = self.actionImageVideo(for: "image", title: "Choose Photo".localized()) {
- alertController.addAction(action)
- }
- if let action = self.actionImageVideo(for: "video", title: "Choose Video".localized()) {
- alertController.addAction(action)
- }
- alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
- self.present(alertController, animated: true)
- }
- }
-
- private func actionImageVideo(for type: String, title: String) -> UIAlertAction? {
- return UIAlertAction(title: title, style: .default) { [unowned self] _ in
- switch type {
- case "image":
- imageVideoPicker.present(source: .imageAlbum)
- case "video":
- imageVideoPicker.present(source: .videoAlbum)
- default:
- imageVideoPicker.present(source: .imageAlbum)
- }
- }
- }
-
- func didSelect(imagevideo: Any?) {
- if imagevideo != nil {
- let imageData = imagevideo! as! [UIImagePickerController.InfoKey : Any]
- if (imageData[.mediaType] as! String == "public.image") {
- let compressedImage = (imageData[.originalImage] as! UIImage).pngData()!
- let base64String = compressedImage.base64EncodedString()
- let base64ToWeb = "data:image/jpeg;base64,\(base64String)"
- webView.evaluateJavaScript("loadFromMobile('\(base64ToWeb)',\(indexImageVideoWv))") { (result, error) in
- if let error = error {
- print("Error executing JavaScript: \(error)")
- }
- }
- } else {
- guard var dataVideo = try? Data(contentsOf: imageData[.mediaURL] as! URL) else {
- return
- }
- let sizeOfVideo = Double(dataVideo.count / 1048576)
- if (sizeOfVideo > 10.0) {
- let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + UUID().uuidString + ".mp4")
- compressVideo(inputURL: imageData[.mediaURL] as! URL,
- outputURL: compressedURL) { exportSession in
- guard let session = exportSession else {
- return
- }
-
- switch session.status {
- case .unknown:
- break
- case .waiting:
- break
- case .exporting:
- break
- case .completed:
- guard let compressedData = try? Data(contentsOf: compressedURL) else {
- return
- }
- dataVideo = compressedData
- case .failed:
- break
- case .cancelled:
- break
- @unknown default:
- break
- }
- }
- }
- let base64String = dataVideo.base64EncodedString()
- let base64ToWeb = "data:video/mp4;base64,\(base64String)"
- webView.evaluateJavaScript("loadFromMobile('\(base64ToWeb)',\(indexImageVideoWv))") { (result, error) in
- if let error = error {
- print("Error executing JavaScript: \(error)")
- }
- }
- }
- }
- }
-
- func compressVideo(inputURL: URL,
- outputURL: URL,
- handler:@escaping (_ exportSession: AVAssetExportSession?) -> Void) {
- let urlAsset = AVURLAsset(url: inputURL, options: nil)
- guard let exportSession = AVAssetExportSession(asset: urlAsset,
- presetName: AVAssetExportPresetMediumQuality) else {
- handler(nil)
-
- return
- }
-
- exportSession.outputURL = outputURL
- exportSession.outputFileType = .mp4
- exportSession.exportAsynchronously {
- handler(exportSession)
- }
- }
-
- func setupSpeech() {
- self.speechRecognizer?.delegate = self
- SFSpeechRecognizer.requestAuthorization { (authStatus) in
- var isButtonEnabled = false
- switch authStatus {
- case .authorized:
- isButtonEnabled = true
- case .denied:
- isButtonEnabled = false
- //print("User denied access to speech recognition")
- case .restricted:
- isButtonEnabled = false
- //print("Speech recognition restricted on this device")
- case .notDetermined:
- isButtonEnabled = false
- //print("Speech recognition not yet authorized")
- @unknown default:
- isButtonEnabled = false
- }
- OperationQueue.main.addOperation() {
- self.isAllowSpeech = isButtonEnabled
- if isButtonEnabled {
- SecureUserDefaults.shared.set(isButtonEnabled, forKey: "allowSpeech")
- self.runVoice()
- }
- }
- }
- }
-
- func runVoice() {
- if !audioEngine.isRunning {
- alertController = LibAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
- self.present(alertController, animated: true)
- self.webView.evaluateJavaScript("toggleVoiceButton(true)")
- self.startRecording()
- }
- }
-
- func startRecording() {
- // Clear all previous session data and cancel task
- if recognitionTask != nil {
- recognitionTask?.cancel()
- recognitionTask = nil
- }
- // Create instance of audio session to record voice
- let audioSession = AVAudioSession.sharedInstance()
- do {
- try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
- try audioSession.setMode(AVAudioSession.Mode.measurement)
- try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
- } catch {
- //print("audioSession properties weren't set because of an error.")
- }
- self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
- let inputNode = audioEngine.inputNode
- guard let recognitionRequest = recognitionRequest else {
- fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
- }
- recognitionRequest.shouldReportPartialResults = true
- self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
- var isFinal = false
- var text = ""
- if result != nil {
- text = result?.bestTranscription.formattedString ?? ""
- isFinal = (result?.isFinal)!
- self.alertController.dismiss(animated: true)
- self.audioEngine.stop()
- self.recognitionRequest?.endAudio()
- } else {
- self.alertController.dismiss(animated: true)
- }
- if error != nil || isFinal {
- if error == nil {
- self.webView.evaluateJavaScript("toggleVoiceButton(false)")
- self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
- } else {
- self.audioEngine.stop()
- self.recognitionRequest?.endAudio()
- }
- inputNode.removeTap(onBus: 0)
- self.recognitionRequest = nil
- self.recognitionTask = nil
- self.isAllowSpeech = true
- }
- })
- let recordingFormat = inputNode.outputFormat(forBus: 0)
- inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
- self.recognitionRequest?.append(buffer)
- }
- self.audioEngine.prepare()
- do {
- try self.audioEngine.start()
- } catch {
- //print("audioEngine couldn't start because of an error.")
- }
- }
-
- func isUsingMyWebview() -> Bool{
- return PrefsUtil.getURLThirdTab() == "0" || PrefsUtil.getURLThirdTab() == "1" || PrefsUtil.getURLThirdTab() == "2" || PrefsUtil.getURLThirdTab() == "3" || PrefsUtil.getURLThirdTab() == "4"
- }
- }
- extension ThirdTabViewController: SFSpeechRecognizerDelegate {
- func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
- if available {
- self.isAllowSpeech = true
- } else {
- self.isAllowSpeech = false
- }
- }
- }
- extension ThirdTabViewController: WKUIDelegate {
- func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) {
- guard let url = navigationAction.request.url else {
- decisionHandler(.cancel)
- return
- }
- if allowedURLs.contains(url.absoluteString) {
- if ViewController.alwaysHideButton {
- ViewController.alwaysHideButton = false
- showTabBar()
- }
- print("✅ URL already allowed: \(url)")
- decisionHandler(.allow)
- return
- }
- validateSSLCertificate(url: url) { isValid in
- print("is VALID? : \(isValid)")
- if isValid {
- self.allowedURLs.insert(url.absoluteString)
- decisionHandler(.allow)
- } else {
- let host = url.host ?? ""
- DispatchQueue.main.async {
- 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()
- messageText = messageText.replacingOccurrences(of: "<<domain>>", with: host)
- let alert = UIAlertController(title: "Warning Unknown Url!".localized(),
- message: messageText,
- preferredStyle: .alert)
- let yesAction = UIAlertAction(title: "Yes", style: .default) { _ in
- let storedCertificate = Utils.getCertificatePinningWebview()
- if let jsonData = storedCertificate.data(using: .utf8),
- let certJson = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] {
- var certJson = certJson
- certJson[host] = self.blockedCertificate
- if let jsonData = try? JSONSerialization.data(withJSONObject: certJson, options: []),
- let jsonString = String(data: jsonData, encoding: .utf8) {
- Utils.setCertificatePinningWebview(value: jsonString)
- }
- }
- self.allowedURLs.insert(url.absoluteString)
- decisionHandler(.allow)
- }
- let noAction = UIAlertAction(title: "No", style: .cancel) { _ in
- decisionHandler(.cancel)
- }
- alert.addAction(yesAction)
- alert.addAction(noAction)
- self.present(alert, animated: true, completion: nil)
- }
- }
- }
- }
-
- private func validateSSLCertificate(url: URL, completion: @escaping (Bool) -> Void) {
- let session = URLSession(configuration: .ephemeral, delegate: self, delegateQueue: nil)
- let request = URLRequest(url: url)
- let task = session.dataTask(with: request) { _, response, error in
- if let error = error {
- print("SSL Validation Error: \(error.localizedDescription)")
- completion(false)
- return
- }
- completion(true)
- }
- task.resume()
- }
- }
- extension ThirdTabViewController: URLSessionDelegate {
- func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
- guard let serverTrust = challenge.protectionSpace.serverTrust else {
- completionHandler(.cancelAuthenticationChallenge, nil)
- return
- }
- if let publicKeyHash = extractPublicKeyHash(from: serverTrust) {
- let domain = challenge.protectionSpace.host
- let storedCertificate = Utils.getCertificatePinningWebview()
- if let jsonData = storedCertificate.data(using: .utf8),
- let certJson = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] {
- if publicKeyHash == certJson[domain] {
- print("✅ Certificate Matched. Allowing Navigation.")
- completionHandler(.useCredential, URLCredential(trust: serverTrust))
- } else {
- print("❌ Certificate Mismatch! Blocking Navigation.")
- blockedCertificate = publicKeyHash
- completionHandler(.cancelAuthenticationChallenge, nil)
- }
- }
- } else {
- completionHandler(.cancelAuthenticationChallenge, nil)
- }
- }
-
- func extractPublicKeyHash(from serverTrust: SecTrust) -> String? {
- guard let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else { return nil }
- guard let publicKey = SecCertificateCopyKey(certificate) else { return nil }
-
- var error: Unmanaged<CFError>?
- guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
- print("❌ Failed to extract public key")
- return nil
- }
-
- // Compute SHA-256 hash
- var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
- publicKeyData.withUnsafeBytes {
- _ = CC_SHA256($0.baseAddress, CC_LONG(publicKeyData.count), &hash)
- }
-
- let hashData = Data(hash)
- let base64Hash = hashData.base64EncodedString()
-
- return base64Hash
- }
- }
|