123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- //
- // ScreenLockViewControllerSwift.swift
- // MCPlus
- //
- // Created by seo ha on 14/02/2019.
- // Copyright © 2019 KangSH. All rights reserved.
- //
- import Foundation
- import UIKit
- import LocalAuthentication
- import AudioToolbox
- class ScreenLockViewController: UIViewController {
- @IBOutlet weak var topContainer:UIView!
- @IBOutlet weak var mainTitle:UILabel!
- @IBOutlet weak var subTitle:UILabel!
- @IBOutlet weak var password1:UIView!
- @IBOutlet weak var password2:UIView!
- @IBOutlet weak var password3:UIView!
- @IBOutlet weak var password4:UIView!
- @IBOutlet weak var password5:UIView!
- @IBOutlet weak var password6:UIView!
- @IBOutlet weak var warningText:UILabel!
- @IBOutlet weak var topMargin:NSLayoutConstraint!
- @IBOutlet weak var btnCancel:UIButton!
-
- let userDefaults = UserDefaults.standard
- var arrPreviousPassword = [Int]()
- var arrPassword = [Int]()
-
- deinit {
- Notification.removeNotification(observer: self)
- }
-
- func chargingPasswordViews(){
- print("chargingPasswordViews count: \(arrPassword.count)");
-
- switch arrPassword.count {
- case 0:
- self.password1.backgroundColor = UIColor.white
- self.password2.backgroundColor = UIColor.white
- self.password3.backgroundColor = UIColor.white
- self.password4.backgroundColor = UIColor.white
- self.password5.backgroundColor = UIColor.white
- self.password6.backgroundColor = UIColor.white
- break;
- case 1:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.white
- self.password3.backgroundColor = UIColor.white
- self.password4.backgroundColor = UIColor.white
- self.password5.backgroundColor = UIColor.white
- self.password6.backgroundColor = UIColor.white
- break;
- case 2:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.black
- self.password3.backgroundColor = UIColor.white
- self.password4.backgroundColor = UIColor.white
- self.password5.backgroundColor = UIColor.white
- self.password6.backgroundColor = UIColor.white
- break;
- case 3:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.black
- self.password3.backgroundColor = UIColor.black
- self.password4.backgroundColor = UIColor.white
- self.password5.backgroundColor = UIColor.white
- self.password6.backgroundColor = UIColor.white
- break;
- case 4:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.black
- self.password3.backgroundColor = UIColor.black
- self.password4.backgroundColor = UIColor.black
- self.password5.backgroundColor = UIColor.white
- self.password6.backgroundColor = UIColor.white
- break;
- case 5:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.black
- self.password3.backgroundColor = UIColor.black
- self.password4.backgroundColor = UIColor.black
- self.password5.backgroundColor = UIColor.black
- self.password6.backgroundColor = UIColor.white
- break;
- case 6:
- self.password1.backgroundColor = UIColor.black
- self.password2.backgroundColor = UIColor.black
- self.password3.backgroundColor = UIColor.black
- self.password4.backgroundColor = UIColor.black
- self.password5.backgroundColor = UIColor.black
- self.password6.backgroundColor = UIColor.black
- break;
- default:
- break;
- }
- }
-
- func textRewrite(){
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- if let pwInputType = lockScreenDao.pwInputType{
- switch pwInputType {
- case .FIRST_INPUT:
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "암호를 입력해 주세요"
- case .CONFIRM_INPUT:
- self.mainTitle.text = "암호 재입력"
- self.subTitle.text = "확인을 위해 한 번 더 입력해 주세요"
- case .UNLOCK_INPUT:
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "암호를 입력해 주세요"
- case .UNLOCK_FAIL_RE_INPUT:
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
- case .CHANGE_FIRST_INPUT:
- self.mainTitle.text = "새로운 암호입력"
- self.subTitle.text = "새로운 암호를 입력해 주세요"
- case .CHANGE_CONFIRM_INPUT:
- self.mainTitle.text = "새로운 암호 재입력"
- self.subTitle.text = "확인을 위해 한 번 더 입력해 주세요"
- }
- }
- }
- }
- extension ScreenLockViewController{
- func appWillEnterBackground(notification:Notification){
- print("will enter background notification")
-
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- arrPreviousPassword = [Int]()
- arrPassword = [Int]()
-
- if let pwInputType = lockScreenDao.pwInputType{
- switch pwInputType {
- case .FIRST_INPUT:
- break
- case .CONFIRM_INPUT:
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
- case .UNLOCK_INPUT:
- break
- case .UNLOCK_FAIL_RE_INPUT:
- fallthrough
- case .CHANGE_FIRST_INPUT:
- fallthrough
- case .CHANGE_CONFIRM_INPUT:
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
- break
- }
- }
-
- self.textRewrite()
- self.chargingPasswordViews()
-
- }
-
- override func viewWillAppear(_ animated: Bool) {
-
- guard #available(iOS 11.0, *) else{ return }
-
- //지문인식
- let context = LAContext()
- var error2:NSError?
- guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error2) else {
- return
- }
-
- if context.biometryType == .faceID{
- return
- }
-
- let error:AutoreleasingUnsafeMutablePointer<NSError?>? = nil
- let temp = self.userDefaults.object(forKey: "fingerprint") as? String
- var isSwitchOn = true
- if let _temp = temp{
- isSwitchOn = temp != "OFF"
- }else{
- // 지문입력 받음
- }
- let lockScreenDao = LockScreenDAO.sharedInstance
- print("lockScreenDao.pwInputType >>>>>>>>>>>>> \(lockScreenDao.pwInputType)")
- // 지문입력은 락을 풀때만 사용해야 한다.
- var isUnlockStatus = false
- if lockScreenDao.pwInputType == LockScreenDAO.PASSWORD_INPUT_TYPE(rawValue: 2){
- isUnlockStatus = true
- }
- if isUnlockStatus, isSwitchOn, context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: error){
- context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "지문을 입력해주세요") { (success, error) in
- if error != nil{
- print("Touch 지원하지 않음")
- return
- }
- guard success == true else{
- print("@@@@실패")
- return
- }
- print("@@@@성공") // 지문 인증 성공했을때
- let now = Date()
- let dateFormatString = "yyyy-MM-dd hh:mm:ss"
- let date = now.fromString(format: dateFormatString)
- print(date)
- // String으로 저장
- self.userDefaults.set(date, forKey: "fingerprintAuthTime")
- self.dismissSelf()
- }
- }
-
- }
-
- override func viewDidAppear(_ animated: Bool) {
- print("viewDidAppear")
- }
-
-
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
-
-
- Notification.registerNotification(name: UIApplication.didEnterBackgroundNotification, queue: .main, block: appWillEnterBackground)
-
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- //업데이트로 인한 초기화 (v4 비밀번호 4자리 -> 6자리 변경이슈)
- if isOlderVersionPassword(){
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
- }
-
- print("lockScreenDao.pwInputType >>>>>>>>>>>>> \(lockScreenDao.pwInputType)")
-
- self.btnCancel.isHidden = lockScreenDao.pwInputType != LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_FIRST_INPUT &&
- lockScreenDao.pwInputType != LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_CONFIRM_INPUT
-
- switch Constants.kScreenHeight {
- case ...568:
- self.topMargin.constant = 40
- case ...480:
- self.topMargin.constant = 30
- default:
- break
- }
-
- self.password1.layer.cornerRadius = 10.0
- self.password1.layer.masksToBounds = true
-
- self.password2.layer.cornerRadius = 10.0
- self.password2.layer.masksToBounds = true
-
- self.password3.layer.cornerRadius = 10.0
- self.password3.layer.masksToBounds = true
-
- self.password4.layer.cornerRadius = 10.0
- self.password4.layer.masksToBounds = true
-
- self.password5.layer.cornerRadius = 10.0
- self.password5.layer.masksToBounds = true
-
- self.password6.layer.cornerRadius = 10.0
- self.password6.layer.masksToBounds = true
-
- lockScreenDao.loadOptionValues()
- if let pwInputType = lockScreenDao.pwInputType{
- switch pwInputType {
- case .FIRST_INPUT:
- break
- case .CONFIRM_INPUT:
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
- case .UNLOCK_INPUT:
- break
- case .UNLOCK_FAIL_RE_INPUT:
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
- case .CHANGE_FIRST_INPUT:
- break
- case .CHANGE_CONFIRM_INPUT:
- break
- }
- }
-
- self.textRewrite()
- self.chargingPasswordViews()
-
- }
-
-
-
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
-
- func savePasswordOnArray(number:Int){
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- print("arrPassword count: \(arrPassword.count)")
- print("lockScreenDao.pwInputType : \(lockScreenDao.pwInputType)")
-
- switch arrPassword.count {
- case ..<6:
- arrPassword.append(number)
-
- //뷰 초기화
- self.chargingPasswordViews()
- self.printPassword()
- self.printPreviousPassword()
-
- Thread.sleep(forTimeInterval: 0.1)
- if arrPassword.count == 6{
- fallthrough
- }
- case 6:
- if let pwInputType = lockScreenDao.pwInputType{
- switch pwInputType {
- case .FIRST_INPUT:
- let pw = self.arrPassword.reduce("", {"\($0)\($1)"})
- guard self.isValidNumber(pw: pw) else{
- arrPassword = [Int]()
- self.textRewrite()
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "연속된 암호를 사용할 수 없습니다. 다시 입력해 주세요"
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
- return
- }
-
- //처음 암호를 입력했을 때, 확인모드로 변경.
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CONFIRM_INPUT
- self.textRewrite()
-
- //암호 입력 새로 받음
- arrPreviousPassword = arrPassword.map({$0})
- arrPassword = [Int]()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
-
- case .CONFIRM_INPUT:
- // 암호가 일치하는지 판단
- if self.comparePasswords(){
- // 패스워드 저장 후 모달창 닫음.
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValues(arrPassword: arrPassword)
-
- //뷰 초기화
- self.chargingPasswordViews()
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.dismissSelf()
- }
-
- }else{
- // 처음부터 다시 입력 받음
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
-
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
-
- self.printPassword()
- self.printPreviousPassword()
-
- arrPreviousPassword = [Int]()
- arrPassword = [Int]()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
-
- }
- case .UNLOCK_INPUT:
- print("UNLOCK_INPUT 1")
-
- // 암호가 일치하는지 판단
- if self.comparePasswordWithStorage(){
- //모달창 닫음.
- print("UNLOCK_INPUT 2")
- // 패스워드 저장 후 모달창 닫음.
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
-
- print("UNLOCK_INPUT 3")
- //뷰 초기화
- self.chargingPasswordViews()
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.dismissSelf()
- }
- }else{
- //초기화 하고 다시 입력 받음
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_FAIL_RE_INPUT
- arrPassword = [Int]()
-
- self.mainTitle.text = "암호입력"
- self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
-
- self.printPassword()
- self.printPreviousPassword()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
- }
-
- case .UNLOCK_FAIL_RE_INPUT:
- if self.comparePasswordWithStorage(){
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValuesWithoutPassword()
-
- //모달창 닫음.
- //뷰 초기화
- self.chargingPasswordViews()
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.dismissSelf()
- }
- }else{
- //초기화 하고 다시 입력 받음
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_FAIL_RE_INPUT
- arrPassword = [Int]()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
- }
-
- case .CHANGE_FIRST_INPUT:
- //처음 암호를 입력했을 때, 변경확인모드로 변경.
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_CONFIRM_INPUT
- self.textRewrite()
-
- //암호 입력 새로 받음
- arrPreviousPassword = [Int]()
- arrPassword = [Int]()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
-
- case .CHANGE_CONFIRM_INPUT:
- // 암호가 일치하는지 판단
- if self.comparePasswords(){
- // 패스워드 저장 후 모달창 닫음.
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
- lockScreenDao.saveOptionValues(arrPassword: arrPassword)
-
- //뷰 초기화
- self.chargingPasswordViews()
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.dismissSelf()
- }
- }else{
- // 처음부터 다시 입력 받음
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_FIRST_INPUT
- self.mainTitle.text = "새로운 암호입력"
- self.subTitle.text = "암호가 틀렸습니다. 새로운 암호를 입력해 주세요"
- AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
-
- self.printPassword()
- self.printPreviousPassword()
-
- arrPreviousPassword = [Int]()
- arrPassword = [Int]()
-
- //뷰 초기화
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
- self?.chargingPasswordViews()
- }
- }
-
- }
- }
- default:
- break
- }
-
-
- }
-
- func comparePasswords() -> Bool {
- print("comparePasswords start")
-
- let pw1 = arrPreviousPassword.reduce("", {"\($0)\($1)"})
- let pw2 = arrPassword.reduce("", {"\($0)\($1)"})
-
- print("comparePasswords end")
- return pw1 == pw2
-
- }
-
- func comparePasswordWithStorage() -> Bool{
-
- var isEncEqual = false
-
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- //암호화 라이브러리 RNCrypter는 랜덤 salt를 쓰므로 복호화를 통하여 암호 비교
- let pw1 = arrPassword.reduce("", {"\($0)\($1)"})
- let pw2 = [0, 1, 2, 3, 4, 5].map({lockScreenDao.encryptedPasswordWithKey(key: "\($0)")})
- .compactMap({$0})
- .map({$0.decryptWithKey(key: Constants.PACS_APP_ENC_KEY)})
- .compactMap({$0})
- .reduce("", {"\($0)\($1)"})
- print("\(pw1),\(pw2)")
- isEncEqual = pw1 == pw2
- print("암호화된 키가 일치하는가?> \(isEncEqual ? "참" : "거짓")")
- return isEncEqual
-
- }
-
- func isValidNumber(pw:String) -> Bool {
- print(pw)
- let pwRegEx = "^(?!.*?(?:0(?:12|98)|123|234|3(?:45|21)|4(?:56|32)|5(?:67|43)|6(?:78|54)|7(?:89|65)|876|987))(?!.*?(.)\\1{2})[0-9]{6}"
- let pwTest = NSPredicate(format:"SELF MATCHES %@", pwRegEx)
- return pwTest.evaluate(with: pw)
- }
-
-
- func dismissSelf(){
- Notification.removeNotification(observer: self)
- self.dismiss(animated: false, completion: nil)
- }
-
-
-
- func printPassword(){
- for i in 0..<arrPassword.count{
- print("[arrPassword \(i)] = \(arrPassword[i])")
- }
- print("===========================\n")
- }
-
- func printPreviousPassword(){
- for i in 0..<arrPreviousPassword.count{
- print("[arrPreviousPassword \(i)] = \(arrPreviousPassword[i])")
- }
- print("===========================\n")
- }
-
- // MARK: - <Numberpad Functions>
-
- @IBAction func clickNum1(sender:Any?){
- self.savePasswordOnArray(number: 1)
- }
-
- @IBAction func clickNum2(sender:Any?){
- self.savePasswordOnArray(number: 2)
- }
-
- @IBAction func clickNum3(sender:Any?){
- self.savePasswordOnArray(number: 3)
- }
-
- @IBAction func clickNum4(sender:Any?){
- self.savePasswordOnArray(number: 4)
- }
-
- @IBAction func clickNum5(sender:Any?){
- self.savePasswordOnArray(number: 5)
- }
-
- @IBAction func clickNum6(sender:Any?){
- self.savePasswordOnArray(number: 6)
- }
-
- @IBAction func clickNum7(sender:Any?){
- self.savePasswordOnArray(number: 7)
- }
-
- @IBAction func clickNum8(sender:Any?){
- self.savePasswordOnArray(number: 8)
- }
-
- @IBAction func clickNum9(sender:Any?){
- self.savePasswordOnArray(number: 9)
- }
-
- @IBAction func clickNum0(sender:Any?){
- self.savePasswordOnArray(number: 0)
- }
-
- @IBAction func clickNumBackspace(sender:Any?){
- let count = arrPassword.count
-
- if count > 0{
- arrPassword.removeLast()
- }
-
- self.chargingPasswordViews()
- self.printPassword()
- }
-
- @IBAction func clickNumCancel(sender:Any?){
- print("취소")
- let lockScreenDao = LockScreenDAO.sharedInstance
- lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
-
- //뷰 초기화
- self.chargingPasswordViews()
- self.dismissSelf()
- }
-
- func isOlderVersionPassword() -> Bool{
- let lockScreenDao = LockScreenDAO.sharedInstance
-
- let pw = [0, 1, 2, 3, 4, 5].map({lockScreenDao.encryptedPasswordWithKey(key: "\($0)")})
- .compactMap({$0})
- .map({$0.decryptWithKey(key: Constants.PACS_APP_ENC_KEY)})
- .compactMap({$0})
- .reduce("", {"\($0)\($1)"})
-
- return pw.count == 4
- }
-
-
- }
|