#include "zypp/RepoInfo.h"
#include "zypp/RepoManager.h"
+#include "zypp/ZYppFactory.h"
+#include "zypp/Target.h"
+#include "zypp/target/rpm/RpmDb.h"
+#include "zypp/FileChecker.h"
+
using std::endl;
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
class PackageProvider::Impl : private base::NonCopyable
{
+ typedef callback::UserData UserData;
public:
/** Ctor taking the Package to provide. */
Impl( RepoMediaAccess & access_r,
* Report start/problem/finish and retry loop are hadled by \ref providePackage.
* Here you trigger just progress and delta/plugin callbacks as needed.
*
- * Proxy methods for progressPackageDownload and failOnChecksum are provided here.
- * Create similar proxies for other progress callbacks in derived classes and link
- * it to ProvideFilePolicy for download:
+ * Proxy method for progressPackageDownload is provided here.
* \code
* ProvideFilePolicy policy;
* policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
- * policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
* return _access.provideFile( _package->repoInfo(), loc, policy );
* \endcode
*
- * \note The provoided default implementation retrieves the packages default
+ * \note The provided default implementation retrieves the packages default
* location.
*/
virtual ManagedFile doProvidePackage() const = 0;
bool progressPackageDownload( int value ) const
{ return report()->progress( value, _package ); }
- /** Redirect ProvideFilePolicy failOnChecksumError to this if needed. */
- bool failOnChecksumError() const
+ typedef target::rpm::RpmDb RpmDb;
+
+ RpmDb::CheckPackageResult packageSigCheck( const Pathname & path_r, UserData & userData ) const
{
- std::string package_str = _package->name() + "-" + _package->edition().asString();
+ if ( !_target )
+ _target = getZYpp()->getTarget();
+
+ RpmDb::CheckPackageResult ret = RpmDb::CHK_ERROR;
+ RpmDb::CheckPackageDetail detail;
+ if ( _target )
+ ret = _target->rpmDb().checkPackage( path_r, detail );
+ else
+ detail.push_back( RpmDb::CheckPackageDetail::value_type( ret, "OOps. Target is not initialized!" ) );
+
+ userData.set( "CheckPackageResult", ret );
+ userData.set( "CheckPackageDetail", std::move(detail) );
+ return ret;
+ }
- // TranslatorExplanation %s = package being checked for integrity
- switch ( report()->problem( _package, repo::DownloadResolvableReport::INVALID, str::form(_("Package %s seems to be corrupted during transfer. Do you want to retry retrieval?"), package_str.c_str() ) ) )
+ /** React on signature verification error user action
+ * \note: IGNORE == accept insecure file (no SkipRequestException!)
+ */
+ void resolveSignatureErrorAction( repo::DownloadResolvableReport::Action action_r ) const
+ {
+ switch ( action_r )
{
case repo::DownloadResolvableReport::RETRY:
_retry = true;
break;
case repo::DownloadResolvableReport::IGNORE:
- ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
+ WAR << _package->asUserString() << ": " << "User requested to accept insecure file" << endl;
break;
+ default:
case repo::DownloadResolvableReport::ABORT:
ZYPP_THROW(AbortRequestException("User requested to abort"));
break;
- default:
- break;
}
- return true; // anyway a failure
+ }
+
+ /** Default signature verification error handling. */
+ void defaultReportSignatureError( RpmDb::CheckPackageResult ret, const std::string & detail_r = std::string() ) const
+ {
+ str::Str msg;
+ msg << _package->asUserString() << ": " << _("Signature verification failed") << " " << ret;
+ if ( ! detail_r.empty() )
+ msg << "\n" << detail_r;
+ resolveSignatureErrorAction( report()->problem( _package, repo::DownloadResolvableReport::INVALID, msg.str() ) );
}
protected:
mutable bool _retry;
mutable shared_ptr<Report> _report;
+ mutable Target_Ptr _target;
};
///////////////////////////////////////////////////////////////////
ProvideFilePolicy policy;
policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
- policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
return _access.provideFile( _package->repoInfo(), loc, policy );
}
Url url = * info.baseUrlsBegin();
do {
_retry = false;
+ if ( ! ret->empty() )
+ {
+ ret.setDispose( filesystem::unlink );
+ ret.reset();
+ }
report()->start( _package, url );
- try // ELIMINATE try/catch by providing a log-guard
+ try
{
ret = doProvidePackage();
+
+ if ( info.pkgGpgCheck() )
+ {
+ UserData userData( "pkgGpgCheck" );
+ userData.set( "Package", _package );
+ userData.set( "Localpath", ret.value() );
+ RpmDb::CheckPackageResult res = packageSigCheck( ret, userData );
+ // publish the checkresult, even if it is OK. Apps may want to report something...
+ report()->pkgGpgCheck( userData );
+USR << "CHK: " << res << endl;
+ if ( res != RpmDb::CHK_OK )
+ {
+ if ( userData.hasvalue( "Action" ) ) // pkgGpgCheck report provided an user error action
+ {
+ resolveSignatureErrorAction( userData.get( "Action", repo::DownloadResolvableReport::ABORT ) );
+ }
+ else if ( userData.haskey( "Action" ) ) // pkgGpgCheck requests the default problem report (wo. details)
+ {
+ defaultReportSignatureError( res );
+ }
+ else // no advice from user => usedefaults
+ {
+ switch ( res )
+ {
+ case RpmDb::CHK_OK: // Signature is OK
+ break;
+
+ case RpmDb::CHK_NOKEY: // Public key is unavailable
+ case RpmDb::CHK_NOTFOUND: // Signature is unknown type
+ case RpmDb::CHK_FAIL: // Signature does not verify
+ case RpmDb::CHK_NOTTRUSTED: // Signature is OK, but key is not trusted
+ case RpmDb::CHK_ERROR: // File does not exist or can't be opened
+ default:
+ // report problem (w. details), throw if to abort, else retry/ignore
+ defaultReportSignatureError( res, str::Str() << userData.get<RpmDb::CheckPackageDetail>( "CheckPackageDetail" ) );
+ break;
+ }
+ }
+ }
+ }
}
catch ( const UserRequestException & excpt )
{
- // UserRequestException e.g. from failOnChecksumError was already reported.
ERR << "Failed to provide Package " << _package << endl;
- if ( ! _retry )
- {
- ZYPP_RETHROW( excpt );
- }
+ if ( ! _retry )
+ ZYPP_RETHROW( excpt );
}
+ catch ( const FileCheckException & excpt )
+ {
+ ERR << "Failed to provide Package " << _package << endl;
+ if ( ! _retry )
+ {
+ const std::string & package_str = _package->asUserString();
+ // TranslatorExplanation %s = package being checked for integrity
+ switch ( report()->problem( _package, repo::DownloadResolvableReport::INVALID, str::form(_("Package %s seems to be corrupted during transfer. Do you want to retry retrieval?"), package_str.c_str() ) ) )
+ {
+ case repo::DownloadResolvableReport::RETRY:
+ _retry = true;
+ break;
+ case repo::DownloadResolvableReport::IGNORE:
+ ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
+ break;
+ case repo::DownloadResolvableReport::ABORT:
+ ZYPP_THROW(AbortRequestException("User requested to abort"));
+ break;
+ default:
+ break;
+ }
+ }
+ }
catch ( const Exception & excpt )
{
ERR << "Failed to provide Package " << _package << endl;
if ( ! _retry )
- {
+ {
// Aything else gets reported
- std::string package_str = _package->name() + "-" + _package->edition().asString();
+ const std::string & package_str = _package->asUserString();
// TranslatorExplanation %s = name of the package being processed.
std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
_retry = true;
break;
case repo::DownloadResolvableReport::IGNORE:
- ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
+ ZYPP_THROW(SkipRequestException("User requested skip of file", excpt));
break;
case repo::DownloadResolvableReport::ABORT:
ZYPP_THROW(AbortRequestException("User requested to abort", excpt));