/*! * * Copyright (c) 2023 Diality Inc. - All Rights Reserved. * * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file Package.h * \author (last) Phil Braica * \date (last) 23-Jan-2023 * \author (original) Phil Braica * \date (original) 23-Jan-2023 */ #ifndef PACKAGE_H_ #define PACKAGE_H_ #include "UpdateProtocol.h" #include "UiUpdateStatus.h" #include "IDataProvider.h" #include #include #include #include #include // C++ 17 #include "PackageItem.h" #include "SignRsa.h" /*! * \brief Utility container for UI */ struct PackageInfo { std::string fullPath; ///< Full path and name. std::string fileName; ///< Just the file name. std::string packageName; ///< The release name. std::string packageVersionInfo; ///< Release version information. std::filesystem::file_time_type lastWritten; ///< Time it was last written. std::string reserved; ///< Reserved for UI. /*! * \brief Equals operator. * * \return True if all the strings are equal. */ bool operator == (const PackageInfo& rhs) const { return ( (fullPath == rhs.fullPath) && (fileName == rhs.fileName) && (packageName == rhs.packageName) && (packageVersionInfo == rhs.packageVersionInfo) && (lastWritten == rhs.lastWritten) && (reserved == rhs.reserved)); } /*! * \brief Not equals operator. * * \return True if any of the strings are not equal. */ bool operator !=(const PackageInfo& rhs) const { return !(*this == rhs); } /*! Default constructor. */ PackageInfo() = default; /*! * \brief Copy constructor. * \param rhs Right hand side. */ PackageInfo(const PackageInfo& rhs) { fullPath = rhs.fullPath; fileName = rhs.fileName; packageName = rhs.packageName; packageVersionInfo = rhs.packageVersionInfo; lastWritten = rhs.lastWritten; reserved = rhs.reserved; } /*! * \brief Full constructor. * \param fullPathStr Full path string. * \param fileNameStr Just the name string. * \param packageNameStr The package description string. * \param packageVersionInfoStr The version information string. * \param lastWrittenTime Last time written file value. * \param reservedStr Reserved for UI use. */ PackageInfo( const std::string& fullPathStr, const std::string& fileNameStr, const std::string& packageNameStr, const std::string& packageVersionInfoStr, const std::filesystem::file_time_type& lastWrittenTime, const std::string& reservedStr) { fullPath = fullPathStr; fileName = fileNameStr; packageName = packageNameStr; packageVersionInfo = packageVersionInfoStr; lastWritten = lastWrittenTime; reserved = reservedStr; } /*! * \brief Assignment operator. * \param rhs Right hand side. * \return Reference to this. */ PackageInfo& operator= (const PackageInfo& rhs) { fullPath = rhs.fullPath; fileName = rhs.fileName; packageName = rhs.packageName; packageVersionInfo = rhs.packageVersionInfo; lastWritten = rhs.lastWritten; reserved = rhs.reserved; return *this; } }; /*! * \brief Class to manage a package file. * *
 * The key things are:
 *   get_available(...) Given a directory get a list of updates 
 *                      that pass validation.
 *   
 *   start()   Given file name (optional key file) do a partial 
 *             or complete update.
 * 
 * UI workflow would typically be:
 * 1. set_public(key in base 64 as a string)
 * 2. get_available(directory) -> Show user their options.
 *    2b. Use parse to scan a specific file as an option.
 *    2c. Might use get_available against more than one directory 
 *        Old existing + USB.
 * 3. start_hasKey(filename)
 *    3a. progress() array of structs of progress.
 *    3b. abort() If user decides to stop.
 * 4. If it completes successfully, on the next  
 *    boot/powercycle U-Boot will update the UI processor (SOM).
 * 
 * The rest of the calls are mainly software development / FPGA 
 * development / manufacturing support, the update software 
 * can be run piecewise in different ways.
 * 
 * The proof of concept UI allows a user to select the encryption
 * file, individually validate a file, update pieces of the system,
 * etc. This allows firmware developers to test just the DG or HD
 * update mechanisms without fully updating the UI or slowing things 
 * down. It can also flash a test image of a DG, HD or one of the 
 * FPGAs.
 * 
 * Files are always:
 *     Signature (base64 text)
 *     XML (mildly encrypted) - decoded as stream till finding 
 *          Contains a catalog of PackageItems that map to different data blobs.
 *     data - binary blobs of bytes, 1 blob per XML 
 * 
*/ class Package { public: Package(); virtual ~Package(); bool parse( const std::string& filename, const std::string & key_location = ""); /*! * \brief Get the XML after the read if any. * * \return String with the recovered XML. */ std::string get_xml() { return _xml; } /*! * \brief Get the information about the read. * * \return String describing read info. */ std::string get_info() const { return _info; } /*! * \brief Get the items. * * \return Vector of package item objects. */ std::vector get_items() { return _items; } /*! * \brief Get the name of the last file parsed. * * \return Last parsed filename. */ std::string lastFileParsed() { return _lastFileName; } /*! * \brief Set the public key from a string. * * \param key The key, base 64. * * \return True on success. */ bool set_public(const std::string& key) { return _rsa.set_public(key); } std::vector targetsAvailable(); bool start_hasKey( const std::string &fileName, const std::vector& update); bool start( const std::string& fileName, const std::string& key_location, const std::vector& update); bool completedAll(); void abort(); std::vector progress(); std::vector get_available(const std::string& directory); std::vector get_available(const std::vector& directories); // Copy / cache it (if not already in there). bool copyUpdate(const std::string& fullNamePath, const std::string& cacheDirectory, uint32 maxCacheSize); std::string getScriptIfAny(); // Reboot to run the firmware (both HD and DG) apps if they are valid. void rebootFW(); protected: bool parseInternal(FILE *fp); void clear(); std::string get_signature(FILE *pFile); void updateCatalog(FILE* pFile); void recurseDirectory( const std::string& directory, int depth, std::vector& values); int findPackageVector( const std::vector& packages, const std::string& fullNamePath); void get_availableInternal(const std::string& directory, std::vector &info); std::vector _items; ///< The items. SignRsa _rsa; ///< Security. std::string _lastFileName; ///< Last package file name. std::string _packageName; ///< The name.txt file contents. std::string _packageVers; ///< The version.txt file contents. std::string _signature; ///< Digital signature of this file. std::string _xml; ///< XML catalog of this file. std::string _info; ///< Progress info for UI and debug. std::size_t _startXml; ///< Where XML starts in the file. std::size_t _startData; ///< Where data starts in the file. FILE * _pFileUpdating; ///< File being updated. std::vector _streams; ///< Target streams. std::vector _packages; ///< Packages. std::vector _avoid; ///< Avoid these. }; #endif // PACKAGE_H_