nebraska: Fix a few issues

- A nit: Eliminate all \ line breakers.

- Set the metadata signature to empty string when its value is null
  otherwise the XML element tree will break.

- Attach / at the end of update and install payload addresses otherwise
  the update engine just concatenates the base address to the payload
  file name and if there is no /, the address will be invalid.

- sha256_hex is in base64 format (generated by paygen), not hex. convert
  it when reading from json files.

BUG=chromium:920404
TEST=unittest
TEST=cros flash

Change-Id: Ie9dcaeb35be6c02d9387d1c9a25fb9fda1fed554
Reviewed-on: https://chromium-review.googlesource.com/1592552
Commit-Ready: Amin Hassani <ahassani@chromium.org>
Tested-by: Amin Hassani <ahassani@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Xiaochu Liu <xiaochu@chromium.org>
diff --git a/nebraska/appindex_unittest.py b/nebraska/appindex_unittest.py
index 38a6e39..8e6c2d7 100755
--- a/nebraska/appindex_unittest.py
+++ b/nebraska/appindex_unittest.py
@@ -31,7 +31,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "1.0.0",
   "source_version": "null"
 }
@@ -44,7 +44,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "2.0.0",
   "source_version": "1.0.0"
 }
@@ -57,7 +57,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "1.0.0",
   "source_version": "null"
 }
@@ -70,7 +70,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "2.0.0",
   "source_version": "1.0.0"
 }
@@ -83,7 +83,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "1.0.0",
   "source_version": "null"
 }
@@ -95,7 +95,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "1.0.0",
   "source_version": "null"
 }
@@ -109,7 +109,7 @@
   "size": "9001",
   "metadata_signature": "0xdeadbeef",
   "metadata_size": "42",
-  "sha256_hex": "0xcafef00d",
+  "sha256_hex": "0xcafef00d==",
   "target_version": "1.0.0",
   "source_version": "null"
 }
diff --git a/nebraska/nebraska.py b/nebraska/nebraska.py
index 54367ab..dbfba21 100755
--- a/nebraska/nebraska.py
+++ b/nebraska/nebraska.py
@@ -10,6 +10,7 @@
 
 # pylint: disable=cros-logging-import
 import argparse
+import base64
 import copy
 import json
 import logging
@@ -355,15 +356,15 @@
         # that are available, but do not have an update available. Omaha treats
         # the former as an error, whereas the latter case should result in a
         # response containing a "noupdate" tag.
-        self._err_not_found = self._app_data is None and \
-            not update_index.Contains(app_request)
+        self._err_not_found = (self._app_data is None and
+                               not update_index.Contains(self._app_request))
 
       if self._app_data:
         logging.debug("Found matching payload: %s", str(self._app_data))
       elif self._err_not_found:
         logging.debug("No matches for appid %s", self._app_request.appid)
-      elif self._app_request.request_type == \
-          self._app_request.RequestType.UPDATE:
+      elif (self._app_request.request_type ==
+            self._app_request.RequestType.UPDATE):
         logging.debug("No updates available for %s", self._app_request.appid)
 
     def Compile(self):
@@ -413,8 +414,8 @@
       elif self._err_not_found:
         app_response.set('status',
                          Response.XMLResponseTemplates.ERROR_NOT_FOUND)
-      elif self._app_request.request_type == \
-          self._app_request.RequestType.UPDATE:
+      elif (self._app_request.request_type ==
+            self._app_request.RequestType.UPDATE):
         app_response.set('status', "ok")
         app_response.append(ElementTree.fromstring(
             Response.XMLResponseTemplates.UPDATE_CHECK_NO_UPDATE))
@@ -465,9 +466,18 @@
     self.source_version = (
         app_data[self.SOURCE_VERSION_KEY] if self.is_delta else None)
     self.size = app_data[self.SIZE_KEY]
-    self.metadata_signature = app_data[self.METADATA_SIG_KEY]
+    # Sometimes the payload is not signed, hence the matadata signature is null,
+    # but we should pass empty string instead of letting the value be null (the
+    # XML element tree will break).
+    self.metadata_signature = app_data[self.METADATA_SIG_KEY] or ''
     self.metadata_size = app_data[self.METADATA_SIZE_KEY]
-    self.sha256_hex = app_data[self.SHA256_HEX_KEY]
+    # Unfortunately the sha256_hex that paygen generates is actually a base64
+    # sha256 hash of the payload for some unknown historical reason. But the
+    # Omaha response contains the hex value of that hash. So here convert the
+    # value from base64 to hex so nebraska can send the correct version to the
+    # client. See b/131762584.
+    self.sha256_hex = base64.b64decode(
+        app_data[self.SHA256_HEX_KEY]).encode('hex')
     self.url = None # Determined per-request.
 
   def __str__(self):
@@ -642,10 +652,13 @@
       update_metadata_dir: Update payloads metadata directory.
       install_metadata_dir: Install payloads metadata directory.
     """
-    self._update_payloads_address = update_payloads_address
-    self._install_payloads_address = (install_payloads_address
+    # Attach '/' at the end of the addresses if they don't have any. The update
+    # engine just concatenates the base address with the payload file name and
+    # if there is no '/' the path will be invalid.
+    self._update_payloads_address = os.path.join(update_payloads_address, '')
+    self._install_payloads_address = (os.path.join(install_payloads_address, '')
                                       if install_payloads_address is not None
-                                      else update_payloads_address)
+                                      else self._update_payloads_address)
     self._update_index = AppIndex(update_metadata_dir)
     self._install_index = AppIndex(install_metadata_dir)
 
diff --git a/nebraska/nebraska_unittest.py b/nebraska/nebraska_unittest.py
index 884446f..c3cddcb 100755
--- a/nebraska/nebraska_unittest.py
+++ b/nebraska/nebraska_unittest.py
@@ -44,8 +44,8 @@
 
   def testDefaultInstallPayloadsAddress(self):
     """Tests the default install_payloads_address is correctly set."""
-    update_addr = 'foo/update'
-    install_addr = 'foo/install'
+    update_addr = 'foo/update/'
+    install_addr = 'foo/install/'
     # pylint: disable=protected-access
     n = nebraska.Nebraska(update_addr, install_addr)
     self.assertEqual(n._install_payloads_address, install_addr)