File indexing completed on 2024-12-01 08:10:07

0001 /*
0002     SPDX-FileCopyrightText: 2011 Ilia Kats <ilia-kats@gmx.net>, based on work by Paul Marchouk <pmarchouk@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "simpleipv6addressvalidator.h"
0008 
0009 #include <QList>
0010 #include <QStringList>
0011 
0012 SimpleIpV6AddressValidator::SimpleIpV6AddressValidator(AddressStyle style, QObject *parent)
0013     : QValidator(parent)
0014     , m_addressStyle(style)
0015 {
0016     switch (style) {
0017     case Base:
0018         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("([0-9a-fA-F]{1,4}|:)+")));
0019         break;
0020     case WithCidr:
0021         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("([0-9a-fA-F]{1,4}|:){2,15}/[0-9]{1,3}")));
0022         break;
0023     case WithPort:
0024         m_validator.setRegularExpression(QRegularExpression(QStringLiteral("\\[([0-9a-fA-F]{1,4}|:)+\\]:[0-9]{1,5}")));
0025     }
0026 }
0027 
0028 SimpleIpV6AddressValidator::~SimpleIpV6AddressValidator() = default;
0029 
0030 QValidator::State SimpleIpV6AddressValidator::validate(QString &address, int &pos) const
0031 {
0032     if (QValidator::Invalid == checkWithInputMask(address, pos)) {
0033         return QValidator::Invalid;
0034     }
0035 
0036     return checkTetradsRanges(address);
0037 }
0038 
0039 QValidator::State SimpleIpV6AddressValidator::checkWithInputMask(QString &value, int &pos) const
0040 {
0041     return m_validator.validate(value, pos);
0042 }
0043 
0044 QValidator::State SimpleIpV6AddressValidator::checkTetradsRanges(QString &value) const
0045 {
0046     QStringList addrParts;
0047     QStringList cidrParts;
0048     QStringList portParts;
0049     bool foundBracket = false;
0050     QValidator::State result = QValidator::Acceptable;
0051 
0052     switch (m_addressStyle) {
0053     case Base:
0054         addrParts = value.split(QLatin1Char(':'));
0055         break;
0056 
0057     case WithCidr:
0058         cidrParts = value.split(QLatin1Char('/'));
0059         addrParts = cidrParts[0].split(QLatin1Char(':'));
0060         break;
0061 
0062     case WithPort:
0063         if (value.isEmpty())
0064             return QValidator::Intermediate;
0065         if (value[0] != '[') {
0066             return QValidator::Invalid;
0067         } else {
0068             // Input: "[1:2:3:4:5:6:7:8]:123"
0069             // bracketParts: "[1:2:3:4:5:6:7:8" , ":123"
0070             // addrParts: "" , "1:2:3:4:5:6:7:8"
0071             // portParts: "", "123"
0072             QStringList bracketParts = value.split(QLatin1Char(']'));
0073             if (bracketParts.size() < 2)
0074                 portParts = QStringList();
0075             else {
0076                 foundBracket = true;
0077                 if (!bracketParts[1].isEmpty() && bracketParts[1][0] != ':')
0078                     return QValidator::Invalid;
0079                 else
0080                     portParts = bracketParts[1].split(QLatin1Char(':'));
0081             }
0082             addrParts = bracketParts[0].split(QLatin1Char('['))[1].split(QLatin1Char(':'));
0083         }
0084     }
0085 
0086     int number = addrParts.size();
0087     // There is no case where can be more than 8 colons (9 parts)
0088     // and only one unusual case where there are 8 colons (1:2:3:4:5:6:7::)
0089     if (number > 9)
0090         return QValidator::Invalid;
0091     else if (number == 9 && (!addrParts[7].isEmpty() || !addrParts[8].isEmpty()))
0092         return QValidator::Invalid;
0093 
0094     // lets check address parts
0095     bool emptypresent = false;
0096     int i = 1;
0097     for (QString part : std::as_const(addrParts)) {
0098         if (part.isEmpty() && i < number) {
0099             // There is only one case where you can have 3 empty parts
0100             // and that is when you have the string: "::" which is valid
0101             // and useful and of course it can also be extended to ::123 for
0102             // instance. Anywhere other than the beginning though, having 3 empty
0103             // parts indicates either a run of 3 colons ("1:::6")" or two sets of
0104             // 2 colons ("1:2::3:4::") which are always invalid
0105             if (emptypresent && i != 2) {
0106                 // qCDebug(PLASMA_NM_EDITOR_LOG) << "part.isEmpty()";
0107                 return QValidator::Invalid;
0108             } else {
0109                 // If this is an empty part then set it to zero to not fail
0110                 // the next test
0111                 part.setNum(0, 16);
0112                 emptypresent = true;
0113             }
0114         }
0115         i++;
0116 
0117         bool ok;
0118         if (part.toInt(&ok, 16) > 65535) {
0119             return QValidator::Invalid;
0120         }
0121     }
0122 
0123     // A special case: a single colon needs to be  Intermediate not Acceptable
0124     if (number == 2 && addrParts[0].isEmpty() && addrParts[1].isEmpty())
0125         result = QValidator::Intermediate;
0126 
0127     // Another special case: a single colon followed by something (i.e. ":123"
0128     // is invalid
0129     else if (number > 1 && addrParts[0].isEmpty() && !addrParts[1].isEmpty())
0130         result = QValidator::Invalid;
0131 
0132     // If we don't have 8 parts yet and none of them are empty we aren't done yet
0133     else if (number < 8 && !emptypresent)
0134         result = QValidator::Intermediate;
0135 
0136     // If we have 8 parts but the last one is empty we aren't done yet
0137     else if (number == 8 && addrParts[7].isEmpty())
0138         result = QValidator::Intermediate;
0139 
0140     if (m_addressStyle == WithCidr) {
0141         int cidrSize = cidrParts.size();
0142 
0143         // If we have a '/' and the basic address portion is not
0144         // yet complete (i.e. Intermediate) then the whole thing  is Invalid
0145         if (cidrSize == 2 && result == QValidator::Intermediate)
0146             return QValidator::Invalid;
0147 
0148         if (cidrSize == 1 || (cidrSize == 2 && cidrParts[1].isEmpty()))
0149             return QValidator::Intermediate;
0150 
0151         int cidrValue = cidrParts[1].toInt();
0152         if (cidrValue > 128)
0153             return QValidator::Invalid;
0154     } else if (m_addressStyle == WithPort) {
0155         int portSize = portParts.size();
0156 
0157         // If we have a ']' and the basic address portion is not
0158         // yet complete (i.e. Intermediate) then the whole thing  is Invalid
0159         if (foundBracket && result == QValidator::Intermediate)
0160             return QValidator::Invalid;
0161 
0162         if (portSize < 2 || (portSize == 2 && portParts[1].isEmpty())) {
0163             return QValidator::Intermediate;
0164         } else {
0165             int portValue = portParts[1].toInt();
0166             if (portValue > 65535)
0167                 return QValidator::Invalid;
0168         }
0169     }
0170     return result;
0171 }
0172 
0173 #include "moc_simpleipv6addressvalidator.cpp"