ckb-next  beta-v0.2.8 at branch testing
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
KbFirmware Class Reference

#include <src/ckb/kbfirmware.h>

+ Inheritance diagram for KbFirmware:
+ Collaboration diagram for KbFirmware:

Data Structures

struct  FW
 

Signals

void downloaded ()
 

Static Public Member Functions

static bool checkUpdates ()
 
static bool hasDownloaded ()
 
static float versionForBoard (const QString &features, bool waitForComplete=false)
 
static QByteArray dataForBoard (const QString &features)
 

Private Types

enum  { UNKNOWN = -1, NO, YES }
 

Private Slots

void processDownload (QNetworkReply *reply)
 
void downloadFinished ()
 

Private Member Functions

 KbFirmware ()
 
 ~KbFirmware ()
 
void initManager ()
 
bool _checkUpdates ()
 
float _latestForBoard (const QString &features, bool waitForComplete)
 
QByteArray _fileForBoard (const QString &features)
 

Private Attributes

quint64 lastCheck
 
quint64 lastFinished
 
QMap< QString, FWfwTable
 
QByteArray fwTableHash
 
QNetworkAccessManager * networkManager
 
QNetworkReply * tableDownload
 
enum KbFirmware:: { ... }  hasGPG
 

Static Private Attributes

static KbFirmware instance
 

Detailed Description

Definition at line 10 of file kbfirmware.h.

Member Enumeration Documentation

anonymous enum
private
Enumerator
UNKNOWN 
NO 
YES 

Definition at line 53 of file kbfirmware.h.

53 { UNKNOWN = -1, NO, YES } hasGPG :2;
enum KbFirmware::@1 hasGPG

Constructor & Destructor Documentation

KbFirmware::KbFirmware ( )
private

Definition at line 14 of file kbfirmware.cpp.

14  :
16 {
17 }
QNetworkAccessManager * networkManager
Definition: kbfirmware.h:47
quint64 lastFinished
Definition: kbfirmware.h:32
quint64 lastCheck
Definition: kbfirmware.h:32
enum KbFirmware::@1 hasGPG
QNetworkReply * tableDownload
Definition: kbfirmware.h:50
KbFirmware::~KbFirmware ( )
private

Definition at line 19 of file kbfirmware.cpp.

19  {
20  //delete networkManager;
21  // ^ This can cause a crash (QT bug?)
22 }

Member Function Documentation

bool KbFirmware::_checkUpdates ( )
private

Definition at line 30 of file kbfirmware.cpp.

References AUTO_CHECK_TIME, downloadFinished(), initManager(), lastCheck, networkManager, and tableDownload.

Referenced by checkUpdates().

30  {
31  initManager();
32  quint64 now = QDateTime::currentMSecsSinceEpoch();
33  if(now < lastCheck + AUTO_CHECK_TIME)
34  return false;
35  // First location is for debugging only.
36  // tableDownload = networkManager->get(QNetworkRequest(QUrl("https://raw.githubusercontent.com/frickler24/ckb-next/issues-26-Firmware-Incident/FIRMWARE")));
37  // This one is the production one.
38  tableDownload = networkManager->get(QNetworkRequest(QUrl("https://raw.githubusercontent.com/mattanger/ckb-next/master/FIRMWARE")));
39  connect(tableDownload, SIGNAL(finished()), this, SLOT(downloadFinished()));
40  lastCheck = now;
41  return true;
42 }
QNetworkAccessManager * networkManager
Definition: kbfirmware.h:47
void initManager()
Definition: kbfirmware.cpp:24
static const quint64 AUTO_CHECK_TIME
Definition: kbfirmware.cpp:9
quint64 lastCheck
Definition: kbfirmware.h:32
QNetworkReply * tableDownload
Definition: kbfirmware.h:50
void downloadFinished()
Definition: kbfirmware.cpp:144

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

QByteArray KbFirmware::_fileForBoard ( const QString &  features)
private

Definition at line 183 of file kbfirmware.cpp.

References QuaZip::csInsensitive, KbFirmware::FW::fileName, fwTable, KbFirmware::FW::hash, QuaZip::mdUnzip, networkManager, QuaZip::open(), QuaZipFile::open(), quit(), QuaZip::setCurrentFile(), tableName(), and KbFirmware::FW::url.

Referenced by dataForBoard().

183  {
184  QString name = tableName(features);
185  FW info = fwTable.value(name);
186  if(info.hash.isEmpty())
187  return "";
188  // Download zip from URL. Wait for it to finish.
189  QNetworkReply* reply = networkManager->get(QNetworkRequest(QUrl(info.url)));
190  QEventLoop loop(this);
191  connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
192  loop.exec();
193  // Download finished, process data
194  if(reply->error() != QNetworkReply::NoError)
195  return "";
196  QByteArray zipData = reply->readAll();
197  QBuffer buffer(&zipData);
198  // Open zip archive
199  QuaZip zip(&buffer);
200  if(!zip.open(QuaZip::mdUnzip))
201  return "";
202  // Find the desired file
203  if(!zip.setCurrentFile(info.fileName, QuaZip::csInsensitive))
204  return "";
205  QuaZipFile binFile(&zip);
206  if(!binFile.open(QIODevice::ReadOnly))
207  return "";
208  QByteArray binary = binFile.readAll();
209  // Check the hash
210  if(QCryptographicHash::hash(binary, QCryptographicHash::Sha256) != info.hash)
211  return "";
212  return binary;
213 }
QNetworkAccessManager * networkManager
Definition: kbfirmware.h:47
static void quit()
quit Stop working the daemon. function is called if the daemon received a sigterm In this case...
Definition: main.c:30
ZIP file is open for reading files inside it.
Definition: quazip.h:96
QMap< QString, FW > fwTable
Definition: kbfirmware.h:41
static QString tableName(const QString &features)
Definition: kbfirmware.cpp:153
ZIP archive.
Definition: quazip.h:84
A file inside ZIP archive.
Definition: quazipfile.h:74
Case insensitive.
Definition: quazip.h:117

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

float KbFirmware::_latestForBoard ( const QString &  features,
bool  waitForComplete 
)
private

Definition at line 165 of file kbfirmware.cpp.

References checkUpdates(), KbManager::ckbDaemonVersionF(), KbManager::ckbGuiVersionF(), KbFirmware::FW::ckbVersion, downloaded(), fwTable, KbFirmware::FW::fwVersion, KbFirmware::FW::hash, quit(), tableDownload, and tableName().

Referenced by versionForBoard().

165  {
166  if((tableDownload || checkUpdates()) && waitForComplete){
167  // If waiting is desired, enter an event loop and stay here until the download is finished
168  QEventLoop loop(this);
169  connect(this, SIGNAL(downloaded()), &loop, SLOT(quit()));
170  loop.exec();
171  }
172  // Find this board
173  QString name = tableName(features);
174  FW info = fwTable.value(name);
175  if(info.hash.isEmpty())
176  return 0.f;
177  // Don't return the new version if the current ckb doesn't support it
178  if(info.ckbVersion > KbManager::ckbGuiVersionF() || info.ckbVersion > KbManager::ckbDaemonVersionF())
179  return -1.f;
180  return info.fwVersion;
181 }
static void quit()
quit Stop working the daemon. function is called if the daemon received a sigterm In this case...
Definition: main.c:30
static float ckbDaemonVersionF()
Definition: kbmanager.h:31
static float ckbGuiVersionF()
Definition: kbmanager.h:30
QMap< QString, FW > fwTable
Definition: kbfirmware.h:41
static bool checkUpdates()
Definition: kbfirmware.h:15
static QString tableName(const QString &features)
Definition: kbfirmware.cpp:153
QNetworkReply * tableDownload
Definition: kbfirmware.h:50

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool KbFirmware::checkUpdates ( )
inlinestatic

Definition at line 15 of file kbfirmware.h.

References _checkUpdates(), and instance.

Referenced by _latestForBoard(), and MainWindow::timerTick().

15 { return instance._checkUpdates(); }
static KbFirmware instance
Definition: kbfirmware.h:59
bool _checkUpdates()
Definition: kbfirmware.cpp:30

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static QByteArray KbFirmware::dataForBoard ( const QString &  features)
inlinestatic

Definition at line 25 of file kbfirmware.h.

References _fileForBoard(), and instance.

Referenced by FwUpgradeDialog::exec().

25 { return instance._fileForBoard(features); }
static KbFirmware instance
Definition: kbfirmware.h:59
QByteArray _fileForBoard(const QString &features)
Definition: kbfirmware.cpp:183

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void KbFirmware::downloaded ( )
signal

Definition at line 148 of file moc_kbfirmware.cpp.

Referenced by _latestForBoard(), and downloadFinished().

149 {
150  QMetaObject::activate(this, &staticMetaObject, 0, Q_NULLPTR);
151 }

+ Here is the caller graph for this function:

void KbFirmware::downloadFinished ( )
privateslot

Definition at line 144 of file kbfirmware.cpp.

References downloaded(), processDownload(), and tableDownload.

Referenced by _checkUpdates().

144  {
145  if(!tableDownload)
146  return;
148  tableDownload->deleteLater();
149  tableDownload = 0;
150  emit downloaded();
151 }
void processDownload(QNetworkReply *reply)
Definition: kbfirmware.cpp:44
QNetworkReply * tableDownload
Definition: kbfirmware.h:50

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool KbFirmware::hasDownloaded ( )
inlinestatic

Definition at line 18 of file kbfirmware.h.

References instance, and lastFinished.

Referenced by KbWidget::on_fwUpdButton_clicked(), and KbWidget::updateFwButton().

18 { return instance.lastFinished != 0; }
static KbFirmware instance
Definition: kbfirmware.h:59
quint64 lastFinished
Definition: kbfirmware.h:32

+ Here is the caller graph for this function:

void KbFirmware::initManager ( )
private

Definition at line 24 of file kbfirmware.cpp.

References networkManager.

Referenced by _checkUpdates().

24  {
25  if(networkManager)
26  return;
27  networkManager = new QNetworkAccessManager();
28 }
QNetworkAccessManager * networkManager
Definition: kbfirmware.h:47

+ Here is the caller graph for this function:

void KbFirmware::processDownload ( QNetworkReply *  reply)
privateslot

Definition at line 44 of file kbfirmware.cpp.

References KbFirmware::FW::ckbVersion, KbFirmware::FW::fileName, fwTable, fwTableHash, KbFirmware::FW::fwVersion, hasGPG, KbFirmware::FW::hash, lastCheck, lastFinished, NO, KbManager::parseVersionString(), UNKNOWN, KbFirmware::FW::url, and YES.

Referenced by downloadFinished().

44  {
45  if(reply->error() != QNetworkReply::NoError)
46  return;
47  // Update last check
48  lastCheck = lastFinished = QDateTime::currentMSecsSinceEpoch();
49  QByteArray data = reply->readAll();
50  // Don't do anything if this is the same as the last version downloaded
51  QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
52  if(hash == fwTableHash)
53  return;
54  fwTableHash = hash;
55  if(hasGPG == UNKNOWN){
56  // Check for a GPG installation
57  QProcess gpg;
58  gpg.start("gpg", QStringList("--version"));
59  gpg.waitForFinished();
60  if(gpg.error() == QProcess::FailedToStart)
61  // No GPG install
62  hasGPG = NO;
63  else {
64  QString output = QString::fromUtf8(gpg.readAll());
65  // Must support RSA keys and SHA256
66  if(output.contains("RSA", Qt::CaseInsensitive) && output.contains("SHA256", Qt::CaseInsensitive))
67  hasGPG = YES;
68  else
69  hasGPG = NO;
70  }
71  if(!hasGPG)
72  qDebug() << "No GPG detected, signature verification disabled";
73  }
74  if(hasGPG){
75  // If GPG is available, check the signature on the file before proceeding.
76  QDir tmp = QDir::temp();
77  // Save file to a temporary path. Include PID to avoid conflicts
78  qint64 pid = QCoreApplication::applicationPid();
79  QString fwPath = tmp.absoluteFilePath(QString("ckb-%1-firmware").arg(pid));
80  QFile firmware(fwPath);
81  if(!firmware.open(QIODevice::WriteOnly)
82  || firmware.write(data) != data.length()){
83  qDebug() << "Failed to write firmware file to temporary location, aborting firmware check";
84  return;
85  }
86  firmware.close();
87  // Write GPG key
88  QString keyPath = tmp.absoluteFilePath(QString("ckb-%1-key.gpg").arg(pid));
89  if(!QFile::copy(":/bin/ckb-next-key.gpg", keyPath)){
90  firmware.remove();
91  qDebug() << "Failed to write GPG key to temporary location, aborting firmware check";
92  return;
93  }
94  // Check signature
95  QProcess gpg;
96  gpg.start("gpg", QStringList("--no-default-keyring") << "--keyring" << keyPath << "--verify" << fwPath);
97  gpg.waitForFinished();
98  // Clean up temp files
99  tmp.remove(fwPath);
100  tmp.remove(keyPath);
101  if(gpg.error() != QProcess::UnknownError || gpg.exitCode() != 0){
102  qDebug() << "GPG couldn't verify firmware signature:";
103  qDebug() << gpg.readAllStandardOutput();
104  qDebug() << gpg.readAllStandardError();
105  return;
106  }
107  // Signature good, proceed to update database
108  }
109  fwTable.clear();
110  QStringList lines = QString::fromUtf8(data).split("\n");
111  bool scan = false;
112  foreach(QString line, lines){
113  // Collapse whitespace
114  line.replace(QRegExp("\\s+"), " ").remove(QRegExp("^\\s")).remove(QRegExp("\\s$"));
115  // Skip empty or commented-out lines
116  if(line.length() == 0 || line.at(0) == '#')
117  continue;
118  // Don't read anything until the entries begin and don't read anything after they end
119  if(!scan){
120  if(line == "!BEGIN FW ENTRIES")
121  scan = true;
122  else
123  continue;
124  }
125  if(line == "!END FW ENTRIES")
126  break;
127  QStringList components = line.split(" ");
128  if(components.length() != 7)
129  continue;
130  // "VENDOR-PRODUCT"
131  QString device = components[0].toUpper() + "-" + components[1].toUpper();
132  FW fw;
133  fw.fwVersion = components[2].toFloat(); // Firmware blob version
134  fw.url = QUrl::fromPercentEncoding(components[3].toLatin1()); // URL to zip file
135  fw.ckbVersion = KbManager::parseVersionString(components[4]); // Minimum ckb version
136  fw.fileName = QUrl::fromPercentEncoding(components[5].toLatin1()); // Name of file inside zip
137  fw.hash = QByteArray::fromHex(components[6].toLatin1()); // SHA256 of file inside zip
138  // Update entry
139  fwTable[device] = fw;
140  }
141  qDebug() << "Downloaded new firmware list." << fwTable.count() << "entries found.";
142 }
static float parseVersionString(QString version)
Definition: kbmanager.cpp:45
QByteArray fwTableHash
Definition: kbfirmware.h:43
quint64 lastFinished
Definition: kbfirmware.h:32
quint64 lastCheck
Definition: kbfirmware.h:32
enum KbFirmware::@1 hasGPG
QMap< QString, FW > fwTable
Definition: kbfirmware.h:41

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static float KbFirmware::versionForBoard ( const QString &  features,
bool  waitForComplete = false 
)
inlinestatic

Definition at line 22 of file kbfirmware.h.

References _latestForBoard(), and instance.

Referenced by MainWindow::checkFwUpdates(), KbWidget::on_fwUpdButton_clicked(), and KbWidget::updateFwButton().

22 { return instance._latestForBoard(features, waitForComplete); }
static KbFirmware instance
Definition: kbfirmware.h:59
float _latestForBoard(const QString &features, bool waitForComplete)
Definition: kbfirmware.cpp:165

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Field Documentation

QMap<QString, FW> KbFirmware::fwTable
private

Definition at line 41 of file kbfirmware.h.

Referenced by _fileForBoard(), _latestForBoard(), and processDownload().

QByteArray KbFirmware::fwTableHash
private

Definition at line 43 of file kbfirmware.h.

Referenced by processDownload().

enum { ... } KbFirmware::hasGPG

Referenced by processDownload().

KbFirmware KbFirmware::instance
staticprivate

Definition at line 59 of file kbfirmware.h.

Referenced by checkUpdates(), dataForBoard(), hasDownloaded(), and versionForBoard().

quint64 KbFirmware::lastCheck
private

Definition at line 32 of file kbfirmware.h.

Referenced by _checkUpdates(), and processDownload().

quint64 KbFirmware::lastFinished
private

Definition at line 32 of file kbfirmware.h.

Referenced by hasDownloaded(), and processDownload().

QNetworkAccessManager* KbFirmware::networkManager
private

Definition at line 47 of file kbfirmware.h.

Referenced by _checkUpdates(), _fileForBoard(), and initManager().

QNetworkReply* KbFirmware::tableDownload
private

Definition at line 50 of file kbfirmware.h.

Referenced by _checkUpdates(), _latestForBoard(), and downloadFinished().


The documentation for this class was generated from the following files: