I have made the following changes intended for :
  CE:MW:Shared / ssu

Please review and accept or decline.
BOSS has already run some checks on this request.
See the "Messages from BOSS" section below.

https://build.pub.meego.com//request/show/7284

Thank You,
aard

[This message was auto-generated]

---

Request # 7284:

Messages from BOSS:

State: review at 2012-11-04T18:20:55 by bossbot

Reviews:
       accepted by bossbot : Prechecks succeeded.
       new for CE-maintainers : Please replace this text with a review and 
approve/reject the review (not the SR). BOSS will take care of the rest

Changes:
  submit: home:aard:branches:CE:MW:Shared / ssu -> CE:MW:Shared / ssu
  
changes files:
--------------
--- ssu.changes
+++ ssu.changes
@@ -0,0 +1,4 @@
+* Sun Nov 04 2012 Bernd Wachter <[email protected]> - 0.14
+- Move device detection bits into configuration files
+- Allow downloading authorized_keys file during rnd registration
+

old:
----
  ssu-0.13.tar.gz

new:
----
  ssu-0.14.tar.gz

spec files:
-----------
--- ssu.spec
+++ ssu.spec
@@ -1,5 +1,5 @@
 Name: ssu
-Version: 0.13
+Version: 0.14
 Release: 1
 Summary: SSU enabler for RND
 Group: System/Base

other changes:
--------------

++++++ ssu-0.13.tar.gz -> ssu-0.14.tar.gz
--- board-mappings.ini
+++ board-mappings.ini
@@ -0,0 +1,70 @@
+### Don't edit this file manually. Update it in git, if there's a good reason 
to do so ###
+#
+# This file is used by SSU to find out which device (or device variant) it's
+# running on, and use this information to look for device family, and device
+# specific adaptation(s). The last two values are used when resolving URLs,
+# and therefore change depending on vendor setup.
+#
+# To avoid quoting in the search strings SSU will do each checks on the
+# _value_, and return the key, if successful. The device model returned
+# my either be the device model, or a variant. Before resolving the family
+# and adaptations variants will be resolved through entries under the
+# variants category.
+#
+# Valid categories for determining the model:
+# - file.exists -- checks for existince of a file in the filesystem
+# - systeminfo.equals -- compares the model returned by QSystemInfo
+#                        with the value provided
+# - cpuinfo.contains -- searches /proc/cpuinfo for a string
+# - arch.equals -- compares with zyppers arch (like i586)
+#
+# Resolve order is:
+#  file.exists -> systeminfo.equals -> cpuinfo.contains -> arch.equals
+#
+# The found model (after resolving variants) will be used as category. The
+# following keys are valid there:
+# - family -- the device family, used for the family specific adaptation
+# - adaptations -- list of additional adaptations, shared between families
+#
+# The value of adaptations gets converted into a QStringList, which uses
+# commas as separator. If one of the adaptation names contains a comma it
+# needs to be quoted:
+#   adaptation=foo
+#   adaptation="foo, bar", baz
+#   adaptation=foo, bar, baz
+#
+# The N9x mappings should be solved through sysinfo, but that's currently
+# broken on Mer/Nemo
+
+[file.exists]
+SDK=/mer-sdk-chroot
+
+[systeminfo.equals]
+
+[cpuinfo.contains]
+N900=Nokia RX-51 board
+N950=Nokia RM-680 board
+N9=Nokia RM-696 board
+
+[arch.equals]
+generic-x86=i586
+
+[variants]
+N950=N9
+
+[N9]
+family=n950-n9
+adaptations=n9xx
+
+[N900]
+family=n900
+adaptations=n9xx
+
+[SDK]
+
+[generic-x86]
+family=x86
+adaptations=x86
+
+[UNKNOWN]
+family=UNKNOWN
--- constants.h
+++ constants.h
@@ -16,6 +16,8 @@
 #define SSU_REPO_CONFIGURATION "/usr/share/ssu/repos.ini"
 /// Path to the main SSU configuration file
 #define SSU_DEFAULT_CONFIGURATION "/usr/share/ssu/ssu-defaults.ini"
+/// Path to board / device family mappings file
+#define SSU_BOARD_MAPPING_CONFIGURATION "/usr/share/ssu/board-mappings.ini"
 /// The SSU protocol version used by the ssu client libraries
 #define SSU_PROTOCOL_VERSION "1"
 #endif
--- libssu/ssu.cpp
+++ libssu/ssu.cpp
@@ -31,6 +31,7 @@
 
   settings = new QSettings(SSU_CONFIGURATION, QSettings::IniFormat);
   repoSettings = new QSettings(SSU_REPO_CONFIGURATION, QSettings::IniFormat);
+  boardMappings = new QSettings(SSU_BOARD_MAPPING_CONFIGURATION, 
QSettings::IniFormat);
   QSettings defaultSettings(SSU_DEFAULT_CONFIGURATION, QSettings::IniFormat);
 
   int configVersion=0;
@@ -136,46 +137,99 @@
 QString Ssu::deviceFamily(){
   QString model = deviceModel();
 
-  if (model == "N900")
-    return "n900";
-  if (model == "N9" || model == "N950")
-    return "n950-n9";
+  if (!cachedFamily.isEmpty())
+    return cachedFamily;
 
-  return "UNKNOWN";
+  cachedFamily = "UNKNOWN";
+
+  if (boardMappings->contains("variants/" + model))
+    model = boardMappings->value("variants/" + model).toString();
+
+  if (boardMappings->contains(model + "/family"))
+    cachedFamily = boardMappings->value(model + "/family").toString();
+
+  return cachedFamily;
 }
 
 QString Ssu::deviceModel(){
   QDir dir;
   QFile procCpuinfo;
+  QStringList keys;
+
+  if (!cachedModel.isEmpty())
+    return cachedModel;
+
+  boardMappings->beginGroup("file.exists");
+  keys = boardMappings->allKeys();
+
+  // check if the device can be identified by testing for a file
+  foreach (const QString &key, keys){
+    QString value = boardMappings->value(key).toString();
+    if (dir.exists(value)){
+      cachedModel = key;
+      break;
+    }
+  }
+  boardMappings->endGroup();
+  if (!cachedModel.isEmpty()) return cachedModel;
 
-  if (dir.exists("/mer-sdk-chroot"))
-    return "SDK";
+  // check if the QSystemInfo model is useful
+  QSystemDeviceInfo devInfo;
+  QString model = devInfo.model();
+  boardMappings->beginGroup("systeminfo.equals");
+  keys = boardMappings->allKeys();
+  foreach (const QString &key, keys){
+    QString value = boardMappings->value(key).toString();
+    if (model == value){
+      cachedModel = key;
+      break;
+    }
+  }
+  boardMappings->endGroup();
+  if (!cachedModel.isEmpty()) return cachedModel;
 
-  // This part should be handled using QTM::SysInfo, but that's currently 
broken
-  // on Nemo for N9/N950
+  // check if the device can be identified by a string in /proc/cpuinfo
   procCpuinfo.setFileName("/proc/cpuinfo");
   procCpuinfo.open(QIODevice::ReadOnly | QIODevice::Text);
   if (procCpuinfo.isOpen()){
     QTextStream in(&procCpuinfo);
     QString cpuinfo = in.readAll();
-    if (cpuinfo.contains("Nokia RX-51 board"))
-      return "N900";
-    if (cpuinfo.contains("Nokia RM-680 board"))
-      return "N950";
-    if (cpuinfo.contains("Nokia RM-696 board"))
-      return "N9";
+    boardMappings->beginGroup("cpuinfo.contains");
+    keys = boardMappings->allKeys();
+
+    foreach (const QString &key, keys){
+      QString value = boardMappings->value(key).toString();
+      if (cpuinfo.contains(value)){
+        cachedModel = key;
+        break;
+      }
+    }
+    boardMappings->endGroup();
+  }
+  if (!cachedModel.isEmpty()) return cachedModel;
+
+
+  // check if there's a match on arch ofr generic fallback. This probably
+  // only makes sense for x86
+  boardMappings->beginGroup("arch.equals");
+  keys = boardMappings->allKeys();
+  foreach (const QString &key, keys){
+    QString value = boardMappings->value(key).toString();
+    if (settings->value("arch").toString() == value){
+      cachedModel = key;
+      break;
+    }
   }
+  boardMappings->endGroup();
+  if (cachedModel.isEmpty()) cachedModel = "UNKNOWN";
 
-  return "UNKNOWN";
+  return cachedModel;
 }
 
 QString Ssu::deviceUid(){
   QString IMEI;
   QSystemDeviceInfo devInfo;
 
-  QString IMEIenv = getenv("imei");
-  bool ok;
-
   IMEI = devInfo.imei();
   // this might not be completely unique (or might change on reflash), but 
works for now
   if (IMEI == ""){
@@ -294,6 +348,7 @@
 
   repoParameters.insert("adaptation", 
settings->value("adaptation").toString());
   repoParameters.insert("deviceFamily", deviceFamily());
+  repoParameters.insert("deviceModel", deviceModel());
 
   if (settings->contains("repository-urls/" + repoName))
     r = settings->value("repository-urls/" + repoName).toString();
@@ -330,35 +385,57 @@
     qDebug() << "Cert from chain" << 
cert.subjectInfo(QSslCertificate::CommonName);
   }
 
-  if (reply->error() > 0){
-    setError(reply->errorString());
-    return;
-  } else {
-    QByteArray data = reply->readAll();
-    qDebug() << "RequestOutput" << data;
+  // what sucks more, this or goto?
+  do {
+    if (settings->contains("home-url")){
+      QString homeUrl = settings->value("home-url").toString().arg("");
+      homeUrl.remove(QRegExp("//+$"));
+      QNetworkRequest request = reply->request();
+
+      if (request.url().toString().startsWith(homeUrl, Qt::CaseInsensitive)){
+        // we don't care about errors on download request
+        if (reply->error() > 0) break;
+        QByteArray data = reply->readAll();
+        storeAuthorizedKeys(data);
+        break;
+      }
+    }
 
-    QDomDocument doc;
-    QString xmlError;
-    if (!doc.setContent(data, &xmlError)){
-      setError(tr("Unable to parse server response (%1)").arg(xmlError));
+    if (reply->error() > 0){
+      pendingRequests--;
+      setError(reply->errorString());
       return;
-    }
+    } else {
+      QByteArray data = reply->readAll();
+      qDebug() << "RequestOutput" << data;
 
-    QString action = doc.elementsByTagName("action").at(0).toElement().text();
+      QDomDocument doc;
+      QString xmlError;
+      if (!doc.setContent(data, &xmlError)){
+        pendingRequests--;
+        setError(tr("Unable to parse server response (%1)").arg(xmlError));
+        return;
+      }
 
-    if (!verifyResponse(&doc)) return;
+      QString action = 
doc.elementsByTagName("action").at(0).toElement().text();
 
-    if (action == "register"){
-      if (!registerDevice(&doc)) return;
-    } else if (action == "credentials"){
-      if (!setCredentials(&doc)) return;
-    } else {
-      setError(tr("Response to unknown action encountered: %1").arg(action));
-      return;
+      if (!verifyResponse(&doc)) break;
+
+      if (action == "register"){
+        if (!registerDevice(&doc)) break;
+      } else if (action == "credentials"){
+        if (!setCredentials(&doc)) break;
+      } else {
+        pendingRequests--;
+        setError(tr("Response to unknown action encountered: %1").arg(action));
+        return;
+      }
     }
+  } while (false);
 
+  pendingRequests--;
+  if (pendingRequests == 0)
     emit done();
-  }
 }
 
 void Ssu::sendRegistration(QString username, QString password){
@@ -407,8 +484,19 @@
   qDebug() << "Sending request to " << request.url();
   QNetworkReply *reply;
 
+  pendingRequests++;
   reply = manager->post(request, form.encodedQuery());
   // we could expose downloadProgress() from reply in case we want progress 
info
+
+  QString homeUrl = settings->value("home-url").toString().arg(username);
+  if (!homeUrl.isEmpty()){
+    // clear header, the other request bits are reusable
+    request.setHeader(QNetworkRequest::ContentTypeHeader, 0);
+    qDebug() << "sending request to " << homeUrl;
+    request.setUrl(homeUrl + "/authorized_keys");
+    pendingRequests++;
+    manager->get(request);
+  }
 }
 
 bool Ssu::setCredentials(QDomDocument *response){
@@ -457,6 +545,9 @@
 void Ssu::setError(QString errorMessage){
   errorFlag = true;
   errorString = errorMessage;
+
+  // assume that we don't even need to wait for other pending requests,
+  // and just die. This is only relevant for CLI, which well exit after done()
   emit done();
 }
 
@@ -472,6 +563,30 @@
     settings->setValue("release", release);
 }
 
+void Ssu::storeAuthorizedKeys(QByteArray data){
+  QDir dir;
+
+  // only set the key for unprivileged users
+  if (getuid() < 1000) return;
+
+  if (dir.exists(dir.homePath() + "/.ssh/authorized_keys"))
+    return;
+
+  if (!dir.exists(dir.homePath() + "/.ssh"))
+    if (!dir.mkdir(dir.homePath() + "/.ssh")) return;
+
+  QFile::setPermissions(dir.homePath() + "/.ssh",
+                        QFile::ReadOwner | QFile::WriteOwner | 
QFile::ExeOwner);
+
+  QFile authorizedKeys(dir.homePath() + "/.ssh/authorized_keys");
+  authorizedKeys.open(QIODevice::WriteOnly | QIODevice::Text | 
QIODevice::Truncate);
+  authorizedKeys.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
+  QTextStream out(&authorizedKeys);
+  out << data;
+  out.flush();
+  authorizedKeys.close();
+}
+
 void Ssu::updateCredentials(bool force){
   errorFlag = false;
 
@@ -535,7 +650,8 @@
   QUrl form;
   form.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
 
-  QNetworkReply *reply = manager->get(request);
+  pendingRequests++;
+  manager->get(request);
 }
 
 bool Ssu::useSslVerify(){
--- libssu/ssu.h
+++ libssu/ssu.h
@@ -114,12 +114,15 @@
 
   private:
     QString errorString;
+    QString cachedModel, cachedFamily;
     bool errorFlag;
     QNetworkAccessManager *manager;
-    QSettings *settings, *repoSettings;
+    int pendingRequests;
+    QSettings *settings, *repoSettings, *boardMappings;
     bool registerDevice(QDomDocument *response);
     bool setCredentials(QDomDocument *response);
     bool verifyResponse(QDomDocument *response);
+    void storeAuthorizedKeys(QByteArray data);
 
   private slots:
     void requestFinished(QNetworkReply *reply);
--- repos.ini
+++ repos.ini
@@ -3,8 +3,11 @@
 # Variables resolved during package build:
 # %(arch)          Package architecture, as in i586 or armv7hl
 #
-# Variables resolved by URL parameters in repository:
+# Variables resolved through information gathered on the device:
 # %(deviceFamily)  A device family in adaptation, like mrst or n9xx
+# %(deviceModel)   A device model, like N9, N950
+#
+# Variables resolved by URL parameters in repository:
 # %(debugSplit)    Set to debug if 'debug' parameter is present, to packages 
otherwise
 #
 # Variables resolved from configuration:
@@ -21,12 +24,12 @@
 #
 # baseurl=plugin:ssu?repo=non-oss&rnd
 # baseurl=plugin:ssu?repo=mer-core&rnd&debug
-# baseurl=plugin:ssu?repo=non-oss&rnd&deviceFamily=mrst
+# baseurl=plugin:ssu?repo=non-oss&rnd&fooBar=baz
 #
 # Valid url specifications in repo files for release repositories include:
 #
 # baseurl=plugin:ssu?repo=non-oss
-# baseurl=plugin:ssu?repo=non-oss&deviceFamily=mrst
+# baseurl=plugin:ssu?repo=non-oss&fooBar=baz
 
 
 [all]
--- rndregisterui/resources/qml/RndSsuPage.qml
+++ rndregisterui/resources/qml/RndSsuPage.qml
@@ -208,8 +208,16 @@
                     ButtonColumn {
                         width: parent.width
 
-                        Button { text: "latest"; onClicked: 
ssu.setRelease("latest", true) }
-                        Button { text: "next"; onClicked: 
ssu.setRelease("next", true) }
+                        Button {
+                            text: "latest"
+                            onClicked: ssu.setRelease("latest", true)
+                            checked: ssu.release(true) == "latest"
+                        }
+                        Button {
+                            text: "next"
+                            onClicked: ssu.setRelease("next", true)
+                            checked: ssu.release(true) == "next"
+                        }
                     }
                 }
             }
--- ssu.pro
+++ ssu.pro
@@ -20,7 +20,7 @@
 config.files = ssu.ini
 config.path  = /etc/ssu
 
-static_config.files = repos.ini ssu-defaults.ini
+static_config.files = repos.ini ssu-defaults.ini board-mappings.ini
 static_config.path  = /usr/share/ssu
 
 INSTALLS += config static_config



Reply via email to