#include "zypp/base/Logger.h"
#include "zypp/base/DefaultIntegral.h"
+#include "zypp/ZYppFactory.h"
#include "zypp/Fetcher.h"
-
+#include "zypp/KeyRing.h"
using namespace std;
namespace zypp
{ /////////////////////////////////////////////////////////////////
+ Fetcher::ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
+ : _checksum(checksum)
+ {
+ }
+
+ bool Fetcher::ChecksumFileChecker::operator()( const Pathname &file )
+ {
+ callback::SendReport<DigestReport> report;
+ CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
+
+ if ( _checksum.empty() )
+ {
+ MIL << "File " << file << " has no checksum available." << std::endl;
+ if ( report->askUserToAcceptNoDigest(file) )
+ {
+ MIL << "User accepted " << file << " with no checksum." << std::endl;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ( (real_checksum == _checksum) )
+ {
+ if ( report->askUserToAcceptWrongDigest( file, _checksum.checksum(), real_checksum.checksum() ) )
+ {
+ WAR << "User accepted " << file << " with WRONG CHECKSUM." << std::endl;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+
+ bool Fetcher::NullFileChecker::operator()(const Pathname &file )
+ {
+ return true;
+ }
+
+ bool Fetcher::CompositeFileChecker::operator()(const Pathname &file )
+ {
+ bool result = true;
+ for ( list<Fetcher::FileChecker>::iterator it = _checkers.begin(); it != _checkers.end(); ++it )
+ {
+ result = result && (*it)(file);
+ }
+ return result;
+ }
+
+ void Fetcher::CompositeFileChecker::add( const FileChecker &checker )
+ {
+ _checkers.push_back(checker);
+ }
+
+ Fetcher::SignatureFileChecker::SignatureFileChecker( const Pathname &signature )
+ : _signature(signature)
+ {
+ }
+
+ Fetcher::SignatureFileChecker::SignatureFileChecker()
+ {
+ }
+
+ void Fetcher::SignatureFileChecker::addPublicKey( const Pathname &publickey )
+ {
+ ZYpp::Ptr z = getZYpp();
+ z->keyRing()->importKey(publickey, false);
+ }
+
+ bool Fetcher::SignatureFileChecker::operator()(const Pathname &file )
+ {
+ ZYpp::Ptr z = getZYpp();
+ MIL << "checking " << file << " file vailidity using digital signature.." << endl;
+ bool valid = z->keyRing()->verifyFileSignatureWorkflow( file, string(), _signature);
+ return valid;
+ }
+
+ /**
+ * Class to encapsulate the \ref OnMediaLocation object
+ * and the \ref Fetcher::FileChcker together
+ */
struct FetcherJob
{
FetcherJob( const OnMediaLocation &loc )
}
OnMediaLocation location;
+ Fetcher::CompositeFileChecker checkers;
};
///////////////////////////////////////////////////////////////////
public:
- void enqueue( const OnMediaLocation &resource );
+ void enqueue( const OnMediaLocation &resource, const Fetcher::FileChecker &checker );
+ void enqueueDigested( const OnMediaLocation &resource, const Fetcher::FileChecker &checker );
void addCachePath( const Pathname &cache_dir );
void reset();
void start( const Pathname &dest_dir, MediaSetAccess &media );
///////////////////////////////////////////////////////////////////
- void Fetcher::Impl::enqueue( const OnMediaLocation &resource )
+ void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
{
- _resources.push_back(FetcherJob(resource));
+ CompositeFileChecker composite;
+ composite.add(ChecksumFileChecker(resource.checksum()));
+ composite.add(checker);
+ enqueue(resource, composite);
}
+ void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
+ {
+ FetcherJob job(resource);
+ job.checkers.add(checker);
+ _resources.push_back(resource);
+ }
+
void Fetcher::Impl::reset()
{
_resources.clear();
Fetcher::~Fetcher()
{}
- void Fetcher::enqueue( const OnMediaLocation &resource )
+ void Fetcher::enqueueDigested( const OnMediaLocation &resource, const Fetcher::FileChecker &checker )
{
- _pimpl->enqueue(resource);
+ _pimpl->enqueue(resource, checker);
+ }
+
+ void Fetcher::enqueue( const OnMediaLocation &resource, const Fetcher::FileChecker &checker )
+ {
+ _pimpl->enqueue(resource, checker);
}
void Fetcher::addCachePath( const Pathname &cache_dir )
} // namespace zypp
///////////////////////////////////////////////////////////////////
-// callback::SendReport<DigestReport> report;
-// if ( checksum.empty() )
-// {
-// MIL << "File " << file_url << " has no checksum available." << std::endl;
-// if ( report->askUserToAcceptNoDigest(file_to_download) )
-// {
-// MIL << "User accepted " << file_url << " with no checksum." << std::endl;
-// return;
-// }
-// else
-// {
-// ZYPP_THROW(SourceMetadataException( file_url.asString() + " " + N_(" miss checksum.") ));
-// }
-// }
-// else
-// {
-// if (! is_checksum( destination, checksum))
-// ZYPP_THROW(SourceMetadataException( file_url.asString() + " " + N_(" fails checksum verification.") ));
-// }
-
#define ZYPP_FETCHER_H
#include <iosfwd>
+#include <list>
#include "zypp/base/PtrTypes.h"
#include "zypp/Pathname.h"
#include "zypp/Url.h"
#include "zypp/OnMediaLocation.h"
+#include "zypp/Digest.h"
#include "zypp/MediaSetAccess.h"
///////////////////////////////////////////////////////////////////
{ /////////////////////////////////////////////////////////////////
/**
- * This class allows to retrieve a group of files which can
- * be cached already on the local disk.
+ * This class allows to retrieve a group of files in a confortable
+ * way, providing some smartness that does not belong to the
+ * media layer like:
+ *
+ * \li Configurable local caches to retrieve already
+ * donwloaded files.
+ * \li File checkers that can check for right checksums
+ * digital signatures, etc.
*
* \code
* MediaSetAccess access(url, path);
* fetcher.start( "/download-dir, access );
* fetcher.reset();
* \endcode
+ *
+ * To use the checkers. just create a functor implementing
+ * bool operator()(const Pathname &file) \see FileChecker.
+ * Pass the necessary validation data in the constructor
+ * of the functor, and pass the object to the \ref enqueue
+ * method.
+ *
+ * \code
+ * ChecksumFileChecker checker(CheckSum("sha1", "....");
+ * fetcher.enqueue( location, checker);
+ * \endcode
+ *
+ * If you need to use more than one checker
+ * \see CompositeFileChecker
*/
class Fetcher
{
/** Implementation */
class Impl;
+ /**
+ * Functor signature used to check files.
+ * \param file File to check.
+ */
+ typedef boost::function<bool ( const Pathname &file )> FileChecker;
+
+ /**
+ * Built in file checkers
+ */
+
+ /**
+ * \short Checks for a valid checksum and interacts with the user.
+ */
+ class ChecksumFileChecker
+ {
+ public:
+ /**
+ * Constructor.
+ * \param checksum Checksum that validates the file
+ */
+ ChecksumFileChecker( const CheckSum &checksum );
+ /**
+ * \short Try to validate the file
+ * \param file File to validate.
+ */
+ bool operator()( const Pathname &file );
+
+ private:
+ CheckSum _checksum;
+ };
+
+ /**
+ * \short Checks for the validity of a signature
+ */
+ class SignatureFileChecker
+ {
+ public:
+ /**
+ * Constructor.
+ * \param signature Signature that validates the file
+ */
+ SignatureFileChecker( const Pathname &signature );
+
+ /**
+ * Default Constructor.
+ * \short Signature for unsigned files
+ * Use it when you dont have a signature but you want
+ * to check the user to accept an unsigned file.
+ */
+ SignatureFileChecker();
+
+
+ /**
+ * add a public key to the list of known keys
+ */
+ void addPublicKey( const Pathname &publickey );
+ /**
+ * \short Try to validate the file
+ * \param file File to validate.
+ */
+ bool operator()( const Pathname &file );
+
+ private:
+ Pathname _signature;
+ };
+
+ /**
+ * \short Checks for nothing
+ * Used as the default checker
+ */
+ class NullFileChecker
+ {
+ public:
+ bool operator()( const Pathname &file );
+ };
+
+ /**
+ * \short Checker composed of more checkers.
+ *
+ * Allows to create a checker composed of various
+ * checkers altothether. It will only
+ * validate if all the checkers validate.
+ *
+ * \code
+ * CompositeFileChecker com;
+ * com.add(checker1);
+ * com.add(checker2);
+ * fetcher.enqueue(location, com);
+ * \endcode
+ */
+ class CompositeFileChecker
+ {
+ public:
+ void add( const FileChecker &checker );
+ bool operator()( const Pathname &file );
+ private:
+ std::list<FileChecker> _checkers;
+ };
+
public:
/** Default ctor */
Fetcher();
/**
* Enqueue a object for transferal, they will not
* be transfered until \ref start() is called
+ *
+ */
+ void enqueue( const OnMediaLocation &resource, const FileChecker &checker = NullFileChecker() );
+
+ /**
+ * Enqueue a object for transferal, they will not
+ * be transfered until \ref start() is called
+ *
+ * \note As \ref OnMediaLocation contains the digest information,
+ * a \ref ChecksumFileChecker is automatically added to the
+ * transfer job, so make sure you don't add another one or
+ * the user could be asked twice.
+ *
+ * \todo FIXME implement checker == operator to avoid this.
*/
- void enqueue( const OnMediaLocation &resource );
+ void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker = NullFileChecker() );
+
/**
* adds a directory to the list of directories
* where to look for cached files
{ /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
- ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
- : _checksum(checksum)
- {
- }
-
- bool ChecksumFileChecker::operator()( const Pathname &file )
- {
- // FIXME probably this funcionality should be in CheckSum itself
- CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
- if ( real_checksum == _checksum )
- {
- return true;
- }
- else
- {
- ERR << "Got " << real_checksum << ", expected " << _checksum << std::endl;
- return false;
- }
- }
-
- bool NullFileChecker::operator()(const Pathname &file )
- {
- return true;
- }
-
-
MediaSetAccess::MediaSetAccess( const Url &url, const Pathname &path )
: _url(url),
_path(path)
return exists;
}
- Pathname MediaSetAccess::provideFile(const Pathname & file, unsigned media_nr, FileChecker checker )
- {
- Pathname p = provideFileInternal( file, media_nr, false, false);
-
- if ( ! checker(p) )
- {
- ZYPP_THROW(Exception("Error checker"));
- }
- return p;
- }
-
Pathname MediaSetAccess::provideFileInternal(const Pathname & file, unsigned media_nr, bool cached, bool checkonly )
{
callback::SendReport<media::MediaChangeReport> report;
DEFINE_PTR_TYPE(MediaSetAccess);
- typedef boost::function<bool ( const Pathname &file )> FileChecker;
-
- class NullFileChecker
- {
- public:
- bool operator()( const Pathname &file );
- };
-
- class ChecksumFileChecker
- {
- public:
- ChecksumFileChecker( const CheckSum &checksum );
- bool operator()( const Pathname &file );
- private:
- CheckSum _checksum;
- };
-
///////////////////////////////////////////////////////////////////
//
// CLASS NAME : MediaSetAccess
Pathname provideFile(const Pathname & file, unsigned media_nr = 1 );
/**
- * Provides \a file from media \a media_nr and use \a checker on provided
- * file.
- *
- * \throws Exception if \a checker returns false. TODO use ProvideFilePolicy
- */
- Pathname provideFile(const Pathname & file, unsigned media_nr, const FileChecker checker );
-
- /**
* check if a file exists on the specified media
*
* \param file file to check
* \param media_nr Media number
*/
- bool doesFileExist(const Pathname & file, unsigned media_nr );
+ bool doesFileExist(const Pathname & file, unsigned media_nr = 1 );
/**
* Replaces media number in specified url with given \a medianr.
bool YUMDownloader::patches_Callback( const OnMediaLocation &loc, const string &id )
{
MIL << id << " : " << loc << endl;
- _fetcher.enqueue(loc);
+ _fetcher.enqueueDigested(loc);
return true;
}
bool YUMDownloader::repomd_Callback( const OnMediaLocation &loc, const YUMResourceType &dtype )
{
MIL << dtype << " : " << loc << endl;
- _fetcher.enqueue(loc);
+ _fetcher.enqueueDigested(loc);
// We got a patches file we need to read, to add patches listed
// there, so we transfer what we have in the queue, and
void YUMDownloader::download( const Pathname &dest_dir )
{
+ Pathname repomdpath = "/repodata/repomd.xml";
+ Pathname keypath = "/repodata/repomd.xml.key";
+ Pathname sigpath = "/repodata/repomd.xml.asc";
+
+
_dest_dir = dest_dir;
- _fetcher.enqueue( OnMediaLocation().filename("/repodata/repomd.xml") );
- _fetcher.start( dest_dir, _media);
-
- //if ( _media.doesFile
+ if ( _media.doesFileExist(keypath) )
+ _fetcher.enqueue( OnMediaLocation().filename(keypath) );
+ if ( _media.doesFileExist(sigpath) )
+ _fetcher.enqueue( OnMediaLocation().filename(sigpath) );
+
+ _fetcher.start( dest_dir, _media );
+
+ Fetcher::SignatureFileChecker sigchecker;
+
+ if ( PathInfo( dest_dir + sigpath ).isExist() )
+ sigchecker = Fetcher::SignatureFileChecker(dest_dir + sigpath);
+
+ if ( PathInfo( dest_dir + keypath ).isExist() )
+ sigchecker.addPublicKey(dest_dir + keypath );
+
+ _fetcher.enqueue( OnMediaLocation().filename(repomdpath), sigchecker );
+ _fetcher.start( dest_dir, _media);
+
+
_fetcher.reset();
Reader reader( dest_dir + "/repodata/repomd.xml" );
} // ns zypp
+