diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8c0020..1d5963d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,7 @@ jobs: runs-on: macos-latest env: MACOSX_DEPLOYMENT_TARGET: 10.15 + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 steps: - name: Checkout uses: actions/checkout@v3 @@ -61,7 +62,7 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v2 with: - version: 6.4.1 + version: 6.4.2 arch: win64_msvc2019_64 - name: Build run: | diff --git a/Common.cpp b/Common.cpp index 8a7f6ad..807f714 100644 --- a/Common.cpp +++ b/Common.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -48,7 +47,9 @@ Common::Common( int &argc, char **argv, const QString &app, const QString &icon Q_INIT_RESOURCE(common_tr); #if defined(Q_OS_WIN) AllowSetForegroundWindow( ASFW_ANY ); +#ifdef NDEBUG setLibraryPaths({ applicationDirPath() }); +#endif #elif defined(Q_OS_MAC) qputenv("OPENSSL_CONF", applicationDirPath().toUtf8() + "../Resources/openssl.cnf"); #ifdef NDEBUG @@ -66,7 +67,7 @@ QString Common::applicationOs() { #if defined(Q_OS_MAC) const auto version = QOperatingSystemVersion::current(); - return QStringLiteral("%1 %2.%3.%4 (%5/%6)") + return QLatin1String("%1 %2.%3.%4 (%5/%6)") .arg(version.name()) .arg(version.majorVersion()) .arg(version.minorVersion()) @@ -77,7 +78,7 @@ QString Common::applicationOs() QString product = QSysInfo::productType(); product[0] = product[0].toUpper(); QString version = QSysInfo::productVersion(); - version.replace(QStringLiteral("server"), QStringLiteral("Server ")); + version.replace(QLatin1String("server"), QLatin1String("Server ")); return QStringLiteral("%1 %2 %3 (%4/%5)") .arg(product) .arg(version) @@ -106,27 +107,14 @@ void Common::msgHandler(QtMsgType type, const QMessageLogContext &ctx, const QSt case QtFatalMsg: f.write("F"); break; default: f.write("I"); break; } - f.write(QStringLiteral(" %1 ").arg(ctx.category).toUtf8()); + f.write(QStringLiteral(" %1 ").arg(QLatin1String(ctx.category)).toUtf8()); if(ctx.line > 0) { f.write(QStringLiteral("%1:%2 \"%3\" ") - .arg(QFileInfo(ctx.file).fileName()) + .arg(QFileInfo(QString::fromLatin1(ctx.file)).fileName()) .arg(ctx.line) - .arg(ctx.function).toUtf8()); + .arg(QLatin1String(ctx.function)).toUtf8()); } f.write(msg.toUtf8()); f.write("\n"); } - -QString Common::language() -{ - QString deflang; - switch( QLocale().language() ) - { - case QLocale::Russian: deflang = QStringLiteral("ru"); break; - case QLocale::Estonian: deflang = QStringLiteral("et"); break; - case QLocale::English: - default: deflang = QStringLiteral("en"); break; - } - return QSettings().value(QStringLiteral("Language"), deflang).toString(); -} diff --git a/Common.h b/Common.h index 2f3919f..e07b5fd 100644 --- a/Common.h +++ b/Common.h @@ -40,8 +40,6 @@ class Common: public BaseApplication #endif static QString applicationOs(); - static void setAccessibleName( QLabel *widget ); - static QString language(); private: static void msgHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg); diff --git a/Configuration.cpp b/Configuration.cpp index 6554f81..0dcc32e 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -52,8 +52,7 @@ static QJsonObject toObject(const QByteArray &data) { } static QByteArray readFile(const QString &file) { - QFile f(file); - if(f.open(QFile::ReadOnly)) + if(QFile f(file); f.open(QFile::ReadOnly)) return f.readAll(); qWarning() << "Failed to read file" << file; return {}; @@ -83,8 +82,8 @@ class Configuration::Private void Configuration::Private::initCache(bool clear) { #ifndef NO_CACHE - auto readAll = [clear, this](const QString &fileName, const QString ©) { - QFile f(cache + fileName); + auto readAll = [clear, this](const QUrl &url, const QString ©) { + QFile f(cache + url.fileName()); if(clear && f.exists()) f.remove(); if(!f.exists()) @@ -94,8 +93,8 @@ void Configuration::Private::initCache(bool clear) } return f.open(QFile::ReadOnly) ? f.readAll() : QByteArray(); }; - setData(readAll(url.fileName(), QStringLiteral(":/config.json")), - readAll(rsaurl.fileName(), QStringLiteral(":/config.rsa"))); + setData(readAll(url, QStringLiteral(":/config.json")), + readAll(rsaurl, QStringLiteral(":/config.rsa"))); #else setData(readFile(QStringLiteral(":/config.json")), readFile(QStringLiteral(":/config.rsa"))); @@ -107,25 +106,23 @@ void Configuration::Private::setData(const QByteArray &_data, const QByteArray & data = _data; signature = _signature; dataobject = toObject(data); -#ifdef Q_OS_MAC - QSettings s2(QSettings::SystemScope, nullptr); +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + QSettings system(QSettings::SystemScope); #else - QSettings s2(QSettings::SystemScope, QApplication::organizationName(), QApplication::applicationName()); + QSettings system(QSettings::SystemScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()); #endif - - for(const QString &key: s2.childKeys()) + for(const QString &key: system.childKeys()) { - if(dataobject.contains(key)) + if(!dataobject.contains(key)) + continue; + QVariant value = system.value(key); + switch(value.type()) { - QVariant value = s2.value(key); - switch(value.type()) - { - case QVariant::String: - dataobject[key] = QJsonValue(value.toString()); break; - case QVariant::StringList: - dataobject[key] = QJsonValue(QJsonArray::fromStringList(value.toStringList())); break; - default: break; - } + case QVariant::String: + dataobject[key] = QJsonValue(value.toString()); break; + case QVariant::StringList: + dataobject[key] = QJsonValue(QJsonArray::fromStringList(value.toStringList())); break; + default: break; } } } @@ -179,7 +176,7 @@ Configuration::Configuration(QObject *parent) QFileInfo(d->url.fileName()).baseName()); d->req.setRawHeader("User-Agent", QStringLiteral("%1/%2 (%3) Lang: %4 Devices: %5") .arg(QApplication::applicationName(), QApplication::applicationVersion(), - Common::applicationOs(), Common::language(), QPCSC::instance().drivers().join('/')).toUtf8()); + Common::applicationOs(), QLocale().uiLanguages().first(), QPCSC::instance().drivers().join('/')).toUtf8()); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) d->req.setTransferTimeout(); #endif @@ -298,11 +295,9 @@ Configuration::Configuration(QObject *parent) d->s.setValue(QStringLiteral("LastCheck"), QDate::currentDate().toString(QStringLiteral("yyyyMMdd"))); update(); } - // Scheduled update - else if(lastCheck < QDate::currentDate().addDays(-LAST_CHECK_DAYS)) - update(); - // DigiDoc4 updated - else if(QVersionNumber::fromString(QSettings().value(QStringLiteral("LastVersion")).toString()) < + // Scheduled update or DigiDoc4 updated + else if(lastCheck < QDate::currentDate().addDays(-LAST_CHECK_DAYS) || + QVersionNumber::fromString(QSettings().value(QStringLiteral("LastVersion")).toString()) < QVersionNumber::fromString(QApplication::applicationVersion())) update(); #endif diff --git a/QPCSC.cpp b/QPCSC.cpp index e849e11..57f20e5 100644 --- a/QPCSC.cpp +++ b/QPCSC.cpp @@ -44,7 +44,7 @@ Q_LOGGING_CATEGORY(SCard,"QPCSC.SCard") static QStringList stateToString(DWORD state) { QStringList result; - #define STATE(X) if(state & SCARD_STATE_##X) result << QStringLiteral(#X) + #define STATE(X) if(state & SCARD_STATE_##X) result.append(QStringLiteral(#X)) STATE(IGNORE); STATE(CHANGED); STATE(UNKNOWN); @@ -69,28 +69,13 @@ LONG SCCall( const char *file, int line, const char *function, Func func, Args.. } #define SC(API, ...) SCCall(__FILE__, __LINE__, "SCard"#API, SCard##API, __VA_ARGS__) -QByteArray QPCSCReader::Private::attrib( DWORD id ) const -{ - if(!card) - return {}; - DWORD size = 0; - LONG err = SC(GetAttrib, card, id, nullptr, &size); - if( err != SCARD_S_SUCCESS || !size ) - return {}; - QByteArray data(int(size), 0); - err = SC(GetAttrib, card, id, LPBYTE(data.data()), &size); - if( err != SCARD_S_SUCCESS || !size ) - return {}; - return data; -} - QHash QPCSCReader::Private::features() { if(!featuresList.isEmpty()) return featuresList; DWORD size = 0; std::array feature{}; - if(SC(Control, card, DWORD(CM_IOCTL_GET_FEATURE_REQUEST), nullptr, 0U, feature.data(), feature.size(), &size)) + if(SC(Control, card, DWORD(CM_IOCTL_GET_FEATURE_REQUEST), nullptr, 0U, feature.data(), DWORD(feature.size()), &size)) return featuresList; for(auto p = feature.cbegin(); std::distance(feature.cbegin(), p) < size; ) { @@ -218,9 +203,9 @@ void QPCSC::run() if(std::none_of(list.cbegin(), list.cend(), [&name](const SCARD_READERSTATE &state) { return strcmp(state.szReader, name) == 0; })) list.push_back({ strdup(name), nullptr, 0, 0, 0, {} }); } - if(SC(GetStatusChange, pcsc.d->context, 5*1000, list.data(), DWORD(list.size())) != SCARD_S_SUCCESS) + if(SC(GetStatusChange, pcsc.d->context, 5*1000U, list.data(), DWORD(list.size())) != SCARD_S_SUCCESS) continue; - for(std::vector::iterator i = list.begin(); i != list.end(); ) + for(auto i = list.begin(); i != list.end(); ) { if((i->dwEventState & SCARD_STATE_CHANGED) == 0) { @@ -312,16 +297,6 @@ bool QPCSCReader::endTransaction( Reset reset ) return result; } -QString QPCSCReader::friendlyName() const -{ - return QString::fromLocal8Bit( d->attrib( SCARD_ATTR_DEVICE_FRIENDLY_NAME_A ) ); -} - -bool QPCSCReader::isConnected() const -{ - return d->card; -} - bool QPCSCReader::isPinPad() const { if(d->reader.contains("HID Global OMNIKEY 3x21 Smart Card Reader") || @@ -350,7 +325,7 @@ QHash QPCSCReader::properties() const { DWORD size = 0; std::array recv{}; - if(SC(Control, d->card, ioctl, nullptr, 0U, recv.data(), recv.size(), &size)) + if(SC(Control, d->card, ioctl, nullptr, 0U, recv.data(), DWORD(recv.size()), &size)) return properties; for(auto p = recv.cbegin(); std::distance(recv.cbegin(), p) < size; ) { @@ -385,7 +360,7 @@ QStringList QPCSCReader::state() const QPCSCReader::Result QPCSCReader::transfer( const QByteArray &apdu ) const { QByteArray data( 1024, 0 ); - DWORD size = DWORD(data.size()); + auto size = DWORD(data.size()); qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex().constData(); LONG ret = SC(Transmit, d->card, &d->io, @@ -431,53 +406,49 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify } quint8 PINFrameOffset = 0, PINLengthOffset = 0; - #define SET() \ - data->bTimerOut = 30; \ - data->bTimerOut2 = 30; \ - data->bmFormatString = FormatASCII|AlignLeft|quint8(PINFrameOffset << 4)|PINFrameOffsetUnitBits; \ - data->bmPINBlockString = PINLengthNone << 5|PINFrameSizeAuto; \ - data->bmPINLengthFormat = PINLengthOffsetUnitBits|PINLengthOffset; \ - data->wPINMaxExtraDigit = quint16(minlen << 8) | 12; \ - data->bEntryValidationCondition = ValidOnKeyPressed; \ - data->wLangId = lang; \ - data->bTeoPrologue[0] = 0x00; \ - data->bTeoPrologue[1] = 0x00; \ - data->bTeoPrologue[2] = 0x00; \ - data->ulDataLength = quint32(apdu.size()) - - QByteArray cmd( 255, 0 ); + auto toByteArray = [&](auto &data) { + data.bTimerOut = 30; + data.bTimerOut2 = 30; + data.bmFormatString = FormatASCII|AlignLeft|quint8(PINFrameOffset << 4)|PINFrameOffsetUnitBits; + data.bmPINBlockString = PINLengthNone << 5|PINFrameSizeAuto; + data.bmPINLengthFormat = PINLengthOffsetUnitBits|PINLengthOffset; + data.wPINMaxExtraDigit = quint16(minlen << 8) | 12; + data.bEntryValidationCondition = ValidOnKeyPressed; + data.wLangId = lang; + data.ulDataLength = quint32(apdu.size()); + return QByteArray((const char*)&data, sizeof(data) - 1) + apdu; + }; + + QByteArray cmd; if( verify ) { - PIN_VERIFY_STRUCTURE *data = (PIN_VERIFY_STRUCTURE*)cmd.data(); - SET(); - data->bNumberMessage = display ? CCIDDefaultInvitationMessage : NoInvitationMessage; - data->bMsgIndex = NoInvitationMessage; - cmd.resize( sizeof(PIN_VERIFY_STRUCTURE) - 1 ); + PIN_VERIFY_STRUCTURE data{}; + data.bNumberMessage = display ? CCIDDefaultInvitationMessage : NoInvitationMessage; + data.bMsgIndex = NoInvitationMessage; + cmd = toByteArray(data); } else { - PIN_MODIFY_STRUCTURE *data = (PIN_MODIFY_STRUCTURE*)cmd.data(); - SET(); - data->bNumberMessage = display ? ThreeInvitationMessage : NoInvitationMessage; - data->bInsertionOffsetOld = 0x00; - data->bInsertionOffsetNew = newPINOffset; - data->bConfirmPIN = ConfirmNewPin; + PIN_MODIFY_STRUCTURE data{}; + data.bNumberMessage = display ? ThreeInvitationMessage : NoInvitationMessage; + data.bInsertionOffsetOld = 0x00; + data.bInsertionOffsetNew = newPINOffset; + data.bConfirmPIN = ConfirmNewPin; if(requestCurrentPIN) { - data->bConfirmPIN |= RequestCurrentPin; - data->bMsgIndex1 = NoInvitationMessage; - data->bMsgIndex2 = OneInvitationMessage; - data->bMsgIndex3 = TwoInvitationMessage; + data.bConfirmPIN |= RequestCurrentPin; + data.bMsgIndex1 = NoInvitationMessage; + data.bMsgIndex2 = OneInvitationMessage; + data.bMsgIndex3 = TwoInvitationMessage; } else { - data->bMsgIndex1 = OneInvitationMessage; - data->bMsgIndex2 = TwoInvitationMessage; - data->bMsgIndex3 = ThreeInvitationMessage; + data.bMsgIndex1 = OneInvitationMessage; + data.bMsgIndex2 = TwoInvitationMessage; + data.bMsgIndex3 = ThreeInvitationMessage; } - cmd.resize( sizeof(PIN_MODIFY_STRUCTURE) - 1 ); + cmd = toByteArray(data); } - cmd += apdu; DWORD ioctl = features.value( verify ? FEATURE_VERIFY_PIN_START : FEATURE_MODIFY_PIN_START ); if( !ioctl ) @@ -486,7 +457,7 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "> " << apdu.toHex().constData(); qCDebug(APDU).nospace() << "CTL" << "> " << cmd.toHex().constData(); QByteArray data( 255 + 3, 0 ); - DWORD size = DWORD(data.size()); + auto size = DWORD(data.size()); LONG err = SC(Control, d->card, ioctl, cmd.constData(), DWORD(cmd.size()), LPVOID(data.data()), DWORD(data.size()), &size); if( DWORD finish = features.value( verify ? FEATURE_VERIFY_PIN_FINISH : FEATURE_MODIFY_PIN_FINISH ) ) @@ -495,7 +466,7 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify err = SC(Control, d->card, finish, nullptr, 0U, LPVOID(data.data()), DWORD(data.size()), &size); } - Result result = { data.mid(int(size - 2), 2), data.left(int(size - 2)), quint32(err) }; + Result result { data.mid(int(size - 2), 2), data.left(int(size - 2)), quint32(err) }; qCDebug(APDU).nospace() << 'T' << d->io.dwProtocol - 1 << "< " << result.SW.toHex().constData(); if(!result.data.isEmpty()) qCDebug(APDU).nospace() << data.left(int(size)).toHex().constData(); return result; diff --git a/QPCSC.h b/QPCSC.h index 13f201f..dd7ed07 100644 --- a/QPCSC.h +++ b/QPCSC.h @@ -106,8 +106,6 @@ class QPCSCReader final: public QObject ~QPCSCReader() final; QByteArray atr() const; - QString friendlyName() const; - bool isConnected() const; bool isPinPad() const; bool isPresent() const; QString name() const; diff --git a/QPCSC_p.h b/QPCSC_p.h index 52f5b4f..19fab0b 100644 --- a/QPCSC_p.h +++ b/QPCSC_p.h @@ -184,32 +184,24 @@ using DISPLAY_PROPERTIES_STRUCTURE = struct { #pragma pack(pop) #endif -#ifndef SCARD_ATTR_DEVICE_FRIENDLY_NAME_A -#define SCARD_ATTR_VALUE(Class, Tag) ((ULONG(Class) << 16) | ULONG(Tag)) -#define SCARD_CLASS_SYSTEM 0x7fff -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0003) -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_A -#endif - class QPCSC::Private { public: - SCARDCONTEXT context = 0; + SCARDCONTEXT context {}; QHash lock; }; class QPCSCReader::Private { public: - QByteArray attrib( DWORD id ) const; QHash features(); - QPCSC::Private *d = nullptr; - SCARDHANDLE card = 0; - SCARD_IO_REQUEST io = {SCARD_PROTOCOL_UNDEFINED, sizeof(SCARD_IO_REQUEST)}; - SCARD_READERSTATE state = {}; + QPCSC::Private *d {}; + SCARDHANDLE card {}; + SCARD_IO_REQUEST io {SCARD_PROTOCOL_UNDEFINED, sizeof(SCARD_IO_REQUEST)}; + SCARD_READERSTATE state {}; QByteArray reader; - bool isTransacted = false; + bool isTransacted {}; QHash featuresList; };