From c8872cb4a17b6c859754f00ff8ff1434ff583ea0 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 29 Apr 2019 15:52:21 +0200 Subject: [PATCH] Use a separate function to validate IP address CURA-6483 --- cura/CuraApplication.py | 4 +++ cura/Utils/QtUtil.py | 21 ++++++++++++++ cura/Utils/networking.py | 26 +++++++++++++++++ .../WelcomePages/AddPrinterByIpContent.qml | 29 ++++++++++++++++++- 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 cura/Utils/QtUtil.py create mode 100644 cura/Utils/networking.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49eec1d778..cc80c6dbfe 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -117,6 +117,8 @@ from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel from cura.UI.WelcomePagesModel import WelcomePagesModel from cura.UI.WhatsNewPagesModel import WhatsNewPagesModel +from cura.Utils.QtUtil import QtUtil + from .SingleInstance import SingleInstance from .AutoSave import AutoSave from . import PlatformPhysics @@ -1028,6 +1030,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 0, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) + qmlRegisterType(QtUtil, "Cura", 1, 0, "QtUtil") + qmlRegisterType(WelcomePagesModel, "Cura", 1, 0, "WelcomePagesModel") qmlRegisterType(WhatsNewPagesModel, "Cura", 1, 0, "WhatsNewPagesModel") qmlRegisterType(AddPrinterPagesModel, "Cura", 1, 0, "AddPrinterPagesModel") diff --git a/cura/Utils/QtUtil.py b/cura/Utils/QtUtil.py new file mode 100644 index 0000000000..60860fcd78 --- /dev/null +++ b/cura/Utils/QtUtil.py @@ -0,0 +1,21 @@ +# Copyright (c) 2019 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from typing import Optional + +from PyQt5.QtCore import QObject, pyqtSlot + +from . import networking + + +# +# Exposes the util functions to QML using a QObject. +# +class QtUtil(QObject): + + def __init__(self, parent: Optional["QObject"] = None) -> None: + super().__init__(parent = parent) + + @pyqtSlot(str, result = bool) + def isValidIP(self, address: str) -> bool: + return networking.isValidIP(address) diff --git a/cura/Utils/networking.py b/cura/Utils/networking.py new file mode 100644 index 0000000000..ba2bbddff6 --- /dev/null +++ b/cura/Utils/networking.py @@ -0,0 +1,26 @@ +# Copyright (c) 2019 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import re + + +_REGEX_IPV4 = re.compile(r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$") +_REGEX_IPV6 = re.compile(r"^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$") + + +# Checks if the given string is a valid IPv4 address. +def isIPv4(address: str) -> bool: + return _REGEX_IPV4.fullmatch(address) is not None + + +# Checks if the given string is a valid IPv6 address. +def isIPv6(address: str) -> bool: + return _REGEX_IPV6.fullmatch(address) is not None + + +# Checks if the given string is a valid IPv4 or IPv6 address. +def isValidIP(address: str) -> bool: + return isIPv4(address) or isIPv6(address) + + +__all__ = ["isIPv4", "isIPv6", "isValidIP"] diff --git a/resources/qml/WelcomePages/AddPrinterByIpContent.qml b/resources/qml/WelcomePages/AddPrinterByIpContent.qml index de9562908c..565fa325cb 100644 --- a/resources/qml/WelcomePages/AddPrinterByIpContent.qml +++ b/resources/qml/WelcomePages/AddPrinterByIpContent.qml @@ -26,6 +26,9 @@ Item property var discoveredPrinter: null property var isPrinterDiscovered: discoveredPrinter != null + // For validating IP address + property var util: Cura.QtUtil{} + // Make sure to cancel the current request when this page closes. onVisibleChanged: { @@ -93,17 +96,36 @@ Item anchors.verticalCenter: addPrinterButton.verticalCenter anchors.left: parent.left + signal invalidInputDetected() + + onInvalidInputDetected: invalidInputLabel.visible = true + validator: RegExpValidator { - regExp: /((^\s*((([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]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))?/ + regExp: /([a-zA-Z0-9.:]+)?/ } + onTextEdited: invalidInputLabel.visible = false + placeholderText: catalog.i18nc("@text", "Place enter your printer's IP address.") enabled: { ! (addPrinterByIpScreen.hasRequestInProgress || addPrinterByIpScreen.isPrinterDiscovered) } onAccepted: addPrinterButton.clicked() } + Label + { + id: invalidInputLabel + anchors.top: hostnameField.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + anchors.left: parent.left + visible: false + text: catalog.i18nc("@text", "Place enter a valid IP address.") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + } + Cura.SecondaryButton { id: addPrinterButton @@ -115,6 +137,11 @@ Item onClicked: { const address = hostnameField.text + if (!util.isValidIP(address)) + { + hostnameField.invalidInputDetected() + return + } // This address is already in the discovered printer model, no need to add a manual discovery. if (CuraApplication.getDiscoveredPrintersModel().discoveredPrintersByAddress[address])