Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - validate user ip address during typing

So i want to validate the user ip during typing. In the VC i did the following :

extension NetworkSettingsViewController: UITextFieldDelegate {
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    self.staticMask.resignFirstResponder()
    self.staticGateway.resignFirstResponder()
    self.staticIp.resignFirstResponder()
    self.staticDns.resignFirstResponder()
    return true
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    var isValidate: Bool
    //verify deletion not happening 
    if !(range.length == 1) {
        if validatorManager.verifyTarget(test: string) {

            isValidate = true
        } else {
            isValidate = false
        }
    } else {
        isValidate = true
    }
    return isValidate
}

}

This is the validation class :

 class ValidatorManager: NSObject {

   func verifyTarget(test: String) -> Bool {
    //        let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
    let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){0,3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])?$"
    let ipTest = NSPredicate(format:"SELF MATCHES %@", validIpAddressRegex)
    print(ipTest.evaluate(with:test))
    return ipTest.evaluate(with:test)
  }
}

i have tried the 2 regex but nothing. i want to check char by char and then all the 3 before the dot() for all the octets.

like image 618
ironRoei Avatar asked Sep 03 '18 13:09

ironRoei


3 Answers

Here are two functions: the first one checks what the user is typing is valid (unfinished IP), and the second one checks the whole thing:

func verifyWhileTyping(test: String) -> Bool {
    let pattern_1 = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){0,3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])?$"
    let regexText_1 = NSPredicate(format: "SELF MATCHES %@", pattern_1)
    let result_1 = regexText_1.evaluate(with: test)
    return result_1
}

func verifyWholeIP(test: String) -> Bool {
    let pattern_2 = "(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"
    let regexText_2 = NSPredicate(format: "SELF MATCHES %@", pattern_2)
    let result_2 = regexText_2.evaluate(with: test)
    return result_2
}

Use verifyWhileTyping(test:)in textField(_ textField: , shouldChangeCharactersIn range:, replacementString string:) To check while typing. When the user is finished and clicks a button or hits the Enter key call verifyWholeIP(test:):

//While typing
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if let text = textField.text {
        verifyWhileTyping(test: text + string)
    }
    //...
}

//When Enter is tapped
func textFieldShouldReturn(_ textField: UITextField) -> Bool {   
    textField.resignFirstResponder()
    if let text = textField.text {
        verifyWholeIP(test: text)
    }
    //...
    return true
}

pattern_1 checks as the user is typing if it is the beginning of correct IP:

regexText_1.evaluate(with: "0")        //true
regexText_1.evaluate(with: "255")      //true
regexText_1.evaluate(with: "256")      //false
regexText_1.evaluate(with: "10.10.")   //true
regexText_1.evaluate(with: "1.2..")    //false
regexText_1.evaluate(with: "1.2.3.4")  //true
regexText_1.evaluate(with: "1.2.3.4.") //false

As to pattern_2, it evaluates a whole IPv4:

"(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"

Here are more test cases:

regexText_2.evaluate(with: "0.0.0.0")    //true
regexText_2.evaluate(with: "1.1.1.256")  //false
regexText_2.evaluate(with: "-1.0.1.2")   //false
regexText_2.evaluate(with: "12.34.56")   //false
regexText_2.evaluate(with: "I.am.an.IP") //false

For IPv6 this the regex to use: "[0-9A-Fa-f]{1,4}" in pattern_2.

like image 116
ielyamani Avatar answered Nov 09 '22 14:11

ielyamani


You can use a regex, You can also separate the IP address string by dots and check to see if each part is an integer in the range 0 to 255:

func isValidIP(s: String) -> Bool {
    let parts = s.componentsSeparatedByString(".")
    let nums = parts.flatMap { Int($0) }
    return parts.count == 4 && nums.count == 4 && nums.filter { $0 >= 0 && $0 < 256}.count == 4
}

(Assuming you're only checking IPv4 strings.)

You can also do it pretty nicely with a regex.

import UIKit

infix operator =~ {}

func =~ (left: String, right: String) -> Bool {
    do {
        let regex = try NSRegularExpression(pattern: right, options: [])
        return regex.numberOfMatchesInString(left, options: [], range: NSMakeRange(0, (left as NSString).length)) > 0
    } catch {
        return false
    }
}

func isValidIP(s: String) -> Bool {
    let regex = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"
    return s =~ regex
}

:The problem is that it will match strings like "192.168.256.1", which is not a valid IP address. The regex for checking only valid IPs is actually fairly detailed and non-trivial.

Hope it helps

like image 36
Chetu Test Avatar answered Nov 09 '22 13:11

Chetu Test


The following allows you to perform an action with each character added/removed from your textField. You will have to adjust the action inside the method. I currently use this method in a production app

textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged)

I also faced the issue you are having with the shouldChangeCharactersIn method being a character too slow. After reading many sources online I came to the conclusion this method should really only be used with simple logic (Just my opinion)

Once you've added the line of code above, you'll need to implement the UITextFieldDelegate as follows:

//MARK: UITextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
    //Do something here
}
like image 1
Brandon Stillitano Avatar answered Nov 09 '22 14:11

Brandon Stillitano