15#include <zypp-media/ng/ProvideSpec>
21#include <zypp/ng/Context>
22#include <zypp/ng/media/Provide>
23#include <zypp/ng/repo/Downloader>
38#undef ZYPP_BASE_LOGGER_LOGGROUP
39#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
47 struct DownloadMasterIndexLogic
53 DownloadMasterIndexLogic( repo::DownloadContextRef &&ctxRef, MediaHandle &&mediaHandle,
zypp::filesystem::Pathname &&masterIndex_r )
54 : _dlContext( std::move(ctxRef) )
55 , _media(std::move( mediaHandle ))
56 , _masterIndex(std::move( masterIndex_r ))
60 MaybeAwaitable<expected<repo::DownloadContextRef>> execute( ) {
64 _sigpath = _masterIndex.extend(
".asc" );
65 _keypath = _masterIndex.extend(
".key" );
66 _destdir = _dlContext->destDir();
68 static const std::string rinfoSigcheckTag {
"repo_sigcheck_plugin" };
70 zypp::Pathname rmRoot { _dlContext->zyppContext()->config().repoManagerRoot() };
71 zypp::Pathname plugindir { _dlContext->zyppContext()->config().pluginsPath() };
73 if ( _sigcheckPlugins ) {
75 _sigcheckPlugins.launch( rmRoot );
82 auto providerRef = _dlContext->zyppContext()->provider();
98 _dlContext->files().push_back( std::move(*sigFile) );
102 if ( expKeyId && !_dlContext->zyppContext()->keyRing()->isKeyKnown(*expKeyId) ) {
104 bool needsMirrorToFetchKey = _dlContext->repoInfo().baseUrlsEmpty() && _dlContext->repoInfo().mirrorListUrl().isValid() ;
105 if ( needsMirrorToFetchKey ) {
108 JobReportHelper( _dlContext->zyppContext() ).warning(
_(
"Downloading signature key via mirrors, consider explicitly setting gpgKeyUrl via the repository configuration instead."));
116 _dlContext->files().push_back( std::move(keyFile));
126 return make_expected_success( std::move(masterres) );
134 _masterIndexFile = std::move(masterIndex);
139 |
and_then( std::bind( &DownloadMasterIndexLogic::pluginVerification,
this ) )
142 |
and_then( std::bind( &DownloadMasterIndexLogic::executeSigcheckPlugins,
this ) )
145 |
and_then( std::bind( &DownloadMasterIndexLogic::signatureCheck,
this ) )
150 _dlContext->repoInfo().setMetadataPath( _destdir );
151 _dlContext->repoInfo().setValidRepoSignature( _repoSigValidated );
154 _media = MediaHandle();
155 auto &allFiles = _dlContext->files();
158 allFiles.insert( allFiles.begin(), std::move(_masterIndexFile) );
159 return make_expected_success( std::move(_dlContext) );
165 ProvideRef provider () {
166 return _dlContext->zyppContext()->provider();
169 MaybeAwaitable<expected<void>> executeSigcheckPlugins()
172 if ( !_sigcheckPlugins ) {
179 for (
auto & plugin : _sigcheckPlugins.plugins() ) {
180 auto * pluginPtr = &plugin;
181 for (
const auto & ext : { plugin.sigExtension(), plugin.keyExtension() } ) {
188 chain = std::move(chain) |
and_then([
this, extpath, extdest, pluginPtr]() {
189 return provider()->provide( _media, extpath,
ProvideFileSpec().setOptional(
false ).setMirrorsAllowed(
false ) )
192 _dlContext->files().push_back( std::move(downloaded_r) );
199 chain = std::move(chain) |
and_then([
this, pluginPtr]() {
200 const zypp::Pathname masterIndexLocal { _destdir / _masterIndex };
202 if ( not pluginPtr->sigExtension().empty() ) {
203 sig = _destdir / _masterIndex.
extend( pluginPtr->sigExtension() );
206 if ( not pluginPtr->keyExtension().empty() ) {
207 key = _destdir / _masterIndex.
extend( pluginPtr->keyExtension() );
210 pluginPtr->sigcheck( masterIndexLocal, sig, key );
221 MaybeAwaitable<expected<void>> signatureCheck () {
224 if ( _dlContext->repoInfo().repoGpgCheck() ) {
232 if ( isSigned || _dlContext->repoInfo().repoGpgCheckIsMandatory() ) {
238 verifyCtx.signature( sigpathLocal );
243 _dlContext->zyppContext()->keyRing()->importKey(
zypp::PublicKey(keypathLocal),
false );
251 verifyCtx.keyContext( _dlContext->repoInfo() );
253 return getExtraKeysInRepomd()
254 |
and_then([
this, vCtx = std::move(verifyCtx) ]()
mutable {
255 for (
const auto &keyData : _buddyKeys ) {
256 DBG <<
"Keyhint remember buddy " << keyData << std::endl;
257 vCtx.addBuddyKey( keyData.id() );
269 WAR <<
"Accept unsigned repository because repoGpgCheck is not mandatory for " << _dlContext->repoInfo().alias() << std::endl;
272 WAR <<
"Signature checking disabled in config of repository " << _dlContext->repoInfo().alias() << std::endl;
284 if ( _dlContext->pluginRepoverification() && _dlContext->pluginRepoverification()->isNeeded() ) {
288 auto kr = _dlContext->zyppContext()->keyRing();
292 MIL <<
"Failed to read signature from file: " << sigpathLocal << std::endl;
294 std::ofstream os( keypathLocal.
c_str() );
295 if ( kr->isKeyKnown(*expKeyId) ) {
298 kr->isKeyTrusted(*expKeyId),
305 _dlContext->pluginRepoverification()->getChecker( sigpathLocal, keypathLocal, _dlContext->repoInfo() )( masterIndexLocal );
317 MaybeAwaitable<expected<void>> getExtraKeysInRepomd () {
319 const zypp::Pathname masterIndexLocal { _destdir / _masterIndex };
321 if ( _masterIndex.basename() !=
"repomd.xml" ) {
326 if ( keyhints.empty() )
328 DBG <<
"Check keyhints: " << keyhints.size() << std::endl;
330 auto keyRing { _dlContext->zyppContext()->keyRing() };
331 return std::move( keyhints )
332 |
transform( [
this, keyRing]( std::pair<std::string, std::string> val ) {
334 const auto& [ file, keyid ] = val;
336 const std::string
str {
zypp::str::Str() <<
"Keyhint is too short to safely identify a gpg key. Skip auto import:" << keyid <<
" (" << file <<
")" };
341 auto keyData = keyRing->trustedPublicKeyData( keyid );
343 DBG <<
"Keyhint is already trusted: " << keyid <<
" (" << file <<
")" << std::endl;
347 DBG <<
"Keyhint search key " << keyid <<
" (" << file <<
")" << std::endl;
349 keyData = keyRing->publicKeyData( keyid );
354 const zypp::ZConfig & conf = _dlContext->zyppContext()->config();
358 | [ keyid = keyid ](
auto &&key ){
359 if ( key.fileProvidesKey( keyid ) )
360 return make_expected_success( std::forward<
decltype(key)>(key) );
365 auto providerRef = _dlContext->zyppContext()->provider();
366 return providerRef->provide( _media, file,
ProvideFileSpec().setOptional(
true).setMirrorsAllowed(
false) )
371 _dlContext->files().push_back ( std::move(res) );
374 if ( not key.fileProvidesKey( keyid ) ) {
375 const std::string
str = (
zypp::str::Str() <<
"Keyhint " << file <<
" does not contain a key with id " << keyid <<
". Skipping it.");
382 return providerRef->copyFile( key.path(), cacheFile )
386 res->resetDispose ();
393 keyRing->importKey( key,
false );
399 if ( keyData && *keyData ) {
400 _buddyKeys.push_back ( std::move(keyData.get()) );
404 MIL <<
"Check keyhints done. Buddy keys: " << _buddyKeys.size() << std::endl;
409 repo::DownloadContextRef _dlContext;
419 std::vector<zypp::PublicKeyData> _buddyKeys;
428 DownloadMasterIndexLogic impl( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) );
429 zypp_co_return zypp_co_await( impl.execute() );
435 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
443 auto statusImpl ( repo::DownloadContextRef dlCtx,
ProvideMediaHandle &&mediaHandle ) {
448 switch( dlCtx->repoInfo().type().toEnum()) {
464 return statusImpl( dl, std::move(mediaHandle) );
469 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
476 auto downloadImpl ( repo::DownloadContextRef dlCtx,
ProvideMediaHandle &&mediaHandle, ProgressObserverRef &&progressObserver ) {
477 switch( dlCtx->repoInfo().type().toEnum()) {
479 return RpmmdWorkflows::download( std::move(dlCtx), std::forward<ProvideMediaHandle>(mediaHandle), std::move(progressObserver) );
481 return SuseTagsWorkflows::download( std::move(dlCtx), std::forward<ProvideMediaHandle>(mediaHandle), std::move(progressObserver) );
494 return downloadImpl( dl, std::move(mediaHandle), std::move(progressObserver) );
500 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
502 return downloadImpl( dl, std::move(handle), std::move(po) );
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Interface of repomd.xml file reader.
Store and operate with byte count.
static const Unit MB
1000^2 Byte
Base class for Exception.
std::string readSignatureKeyId(const Pathname &signature)
reads the public key id from a signature
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
static bool isSafeKeyId(const std::string &id_r)
!<
static PublicKey noThrow(const Pathname &keyFile_r)
Static ctor returning an empty PublicKey rather than throwing.
What is known about a repository.
bool hasExtraValue(const std::string &key_r) const
Whether an extra value for key_r is set.
std::string extraValue(const std::string &key_r) const
Return extra value for key_r or throws std::out_of_range.
Track changing files or directories.
Handle a bunch of SigcheckPlugins.
Interim helper class to collect global options and settings.
Pathname repoManagerRoot() const
The RepoManager root directory.
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Wrapper class for stat/lstat.
bool isExist() const
Return whether valid stat info exists.
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Pathname dirname() const
Return all but the last component od this path.
const char * c_str() const
String representation.
I/O context for KeyRing::verifyFileSignatureWorkflow.
bool fileValidated() const
Whether the signature was actually successfully verified.
Reads through a repomd.xml file and collects type, location, checksum and other data about metadata f...
std::vector< std::pair< std::string, std::string > > keyhints() const
gpg key hits shipped in keywords (bsc#1184326)
thrown when it was impossible to determine this repo type.
JobReportHelper(ContextRef r)
static auto copyResultToDest(ProvideRef provider, const zypp::Pathname &targetPath)
ProvideMediaHandle MediaHandle
static expected success(ConsParams &&...params)
static expected error(ConsParams &&...params)
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
String related utilities and Regular expression matching.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver=nullptr)
MaybeAwaitable< expected< repo::DownloadContextRef > > downloadMasterIndex(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r)
MaybeAwaitable< expected< void > > fetchGpgKeys(ContextRef ctx, zypp::RepoInfo info)
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
MaybeAwaitable< expected< zypp::keyring::VerifyFileContext > > verifySignature(ContextRef ctx, zypp::keyring::VerifyFileContext context)
auto or_else(Fun &&function)
auto and_then(Fun &&function)
auto transform(Transformation &&transformation)
auto mtry(Fun &&function)
ResultType and_then(const expected< T, E > &exp, Function &&f)
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...