libzypp 17.32.5
repodownloaderwf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "repodownloaderwf.h"
12
13#include <utility>
14#include <zypp-media/ng/Provide>
15#include <zypp-media/ng/ProvideSpec>
16#include <zypp/ng/Context>
17#include <zypp/ng/repo/Downloader>
18#include <zypp/PublicKey.h>
19#include <zypp/KeyRing.h>
20
25
26// sync workflow helpers
29
30namespace zyppng {
31 namespace {
32
33 using namespace zyppng::operators;
34
35 template < class Executor, class OpType >
36 struct DownloadMasterIndexLogic : public LogicBase<Executor, OpType>
37 {
38 public:
40
41 using DlContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, repo::AsyncDownloadContextRef, repo::SyncDownloadContextRef>;
42 using ZyppContextType = typename remove_smart_ptr_t<DlContextRefType>::ContextType;
43 using ProvideType = typename ZyppContextType::ProvideType;
44 using MediaHandle = typename ProvideType::MediaHandle;
45 using ProvideRes = typename ProvideType::Res;
46
47 DownloadMasterIndexLogic( DlContextRefType &&ctxRef, MediaHandle &&mediaHandle, zypp::filesystem::Pathname &&masterIndex_r )
48 : _dlContext( std::move(ctxRef) )
49 , _media(std::move( mediaHandle ))
51 { }
52
53 public:
55 // always download them, even if repoGpgCheck is disabled
56 _sigpath = _masterIndex.extend( ".asc" );
57 _keypath = _masterIndex.extend( ".key" );
58 _destdir = _dlContext->destDir();
59
60 auto providerRef = _dlContext->zyppContext()->provider();
61 return std::vector {
62 // fetch signature and keys
63 providerRef->provide( _media, _sigpath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) )
64 | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _sigpath ) ),
65 providerRef->provide( _media, _keypath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) )
66 | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _keypath ) ),
67 }
68 | join()
69 | [this]( std::vector<expected<zypp::ManagedFile>> &&res ) {
70
71 // remember downloaded files
72 std::for_each( res.begin (), res.end(),
74 if (f.is_valid () ) {
75 _dlContext->files().push_back( std::move(f.get()));
76 }
77 });
78
79 // get the master index file
80 return provider()->provide( _media, _masterIndex, ProvideFileSpec().setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) );
81 }
82 // execute plugin verification if there is one
83 | and_then( std::bind( &DownloadMasterIndexLogic::pluginVerification, this, std::placeholders::_1 ) )
84
85 // signature checking
86 | and_then( std::bind( &DownloadMasterIndexLogic::signatureCheck, this, std::placeholders::_1 ) )
87
88 // copy everything into a directory
89 | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _masterIndex ) )
90
91 // final tasks
93 // Accepted!
94 _dlContext->repoInfo().setMetadataPath( _destdir );
95 _dlContext->repoInfo().setValidRepoSignature( _repoSigValidated );
96
97 // release the media handle
98 _media = MediaHandle();
99 auto &allFiles = _dlContext->files();
100
101 // make sure the masterIndex is in front
102 allFiles.insert( allFiles.begin (), std::move(masterIndex) );
103 return make_expected_success( std::move(_dlContext) );
104 });
105 }
106
107
108 private:
109 auto provider () {
110 return _dlContext->zyppContext()->provider();
111 }
112
114
115 if ( _dlContext->repoInfo().repoGpgCheck() ) {
116
117 // The local files are in destdir_r, if they were present on the server
121
122 if ( isSigned || _dlContext->repoInfo().repoGpgCheckIsMandatory() ) {
123
125
126 // only add the signature if it exists
127 if ( isSigned )
128 verifyCtx.signature( sigpathLocal );
129
130 // only add the key if it exists
131 if ( zypp::PathInfo(keypathLocal).isExist() ) {
132 try {
133 _dlContext->zyppContext()->keyRing()->importKey( zypp::PublicKey(keypathLocal), false );
134 } catch (...) {
135 return makeReadyResult( expected<ProvideRes>::error( std::current_exception() ) );
136 }
137 }
138
139 // set the checker context even if the key is not known
140 // (unsigned repo, key file missing; bnc #495977)
141 verifyCtx.keyContext( _dlContext->repoInfo() );
142
143 return getExtraKeysInRepomd( std::move(res ) )
144 | and_then([this, vCtx = std::move(verifyCtx) ]( ProvideRes &&res ) mutable {
145 for ( const auto &keyData : _buddyKeys ) {
146 DBG << "Keyhint remember buddy " << keyData << std::endl;
147 vCtx.addBuddyKey( keyData.id() );
148 }
149
150 return SignatureFileCheckWorkflow::verifySignature( _dlContext->zyppContext(), std::move(vCtx))
151 | and_then([ this, res = std::move(res) ]( zypp::keyring::VerifyFileContext verRes ){
152 // remember the validation status
153 _repoSigValidated = verRes.fileValidated();
154 return make_expected_success(std::move(res));
155 });
156 });
157
158 } else {
159 WAR << "Accept unsigned repository because repoGpgCheck is not mandatory for " << _dlContext->repoInfo().alias() << std::endl;
160 }
161 } else {
162 WAR << "Signature checking disabled in config of repository " << _dlContext->repoInfo().alias() << std::endl;
163 }
165 }
166
167 // execute the repo verification if there is one
169 // The local files are in destdir_r, if they were present on the server
172 if ( _dlContext->pluginRepoverification() && _dlContext->pluginRepoverification()->isNeeded() ) {
173 try {
174 _dlContext->pluginRepoverification()->getChecker( sigpathLocal, keypathLocal, _dlContext->repoInfo() )( prevRes.file() );
175 } catch ( ... ) {
176 return expected<ProvideRes>::error( std::current_exception () );
177 }
178 }
179 return make_expected_success(std::move(prevRes));
180 }
181
187
188 if ( _masterIndex.basename() != "repomd.xml" ) {
189 return makeReadyResult( expected<ProvideRes>::success( std::move(res) ) );
190 }
191
192 std::vector<std::pair<std::string,std::string>> keyhints { zypp::parser::yum::RepomdFileReader(res.file()).keyhints() };
193 if ( keyhints.empty() )
194 return makeReadyResult( expected<ProvideRes>::success( std::move(res) ) );
195 DBG << "Check keyhints: " << keyhints.size() << std::endl;
196
197 auto keyRing { _dlContext->zyppContext()->keyRing() };
199 | transform([this, keyRing]( std::pair<std::string, std::string> val ) {
200
201 const auto& [ file, keyid ] = val;
202 auto keyData = keyRing->trustedPublicKeyData( keyid );
203 if ( keyData ) {
204 DBG << "Keyhint is already trusted: " << keyid << " (" << file << ")" << std::endl;
205 return makeReadyResult ( expected<zypp::PublicKeyData>::success(keyData) ); // already a trusted key
206 }
207
208 DBG << "Keyhint search key " << keyid << " (" << file << ")" << std::endl;
209
210 keyData = keyRing->publicKeyData( keyid );
211 if ( keyData )
213
214 // TODO: Enhance the key caching in general...
215 const zypp::ZConfig & conf = _dlContext->zyppContext()->config();
216 zypp::Pathname cacheFile = conf.repoManagerRoot() / conf.pubkeyCachePath() / file;
217
219 | [ keyid = keyid ]( auto &&key ){
220 if ( key.fileProvidesKey( keyid ) )
221 return make_expected_success( std::forward<decltype(key)>(key) );
222 else
223 return expected<zypp::PublicKey>::error( std::make_exception_ptr (zypp::Exception("File does not provide key")));
224 }
225 | or_else ([ this, file = file, keyid = keyid, cacheFile ] ( auto && ) mutable -> MaybeAsyncRef<expected<zypp::PublicKey>> {
226 auto providerRef = _dlContext->zyppContext()->provider();
227 return providerRef->provide( _media, file, ProvideFileSpec().setOptional(true) )
228 | and_then( ProvideType::copyResultToDest( providerRef, _destdir / file ) )
229 | and_then( [this, providerRef, file, keyid , cacheFile = std::move(cacheFile)]( zypp::ManagedFile &&res ) {
230
231 // remember we downloaded the file
232 _dlContext->files().push_back ( std::move(res) );
233
234 auto key = zypp::PublicKey::noThrow( _dlContext->files().back() );
235 if ( not key.fileProvidesKey( keyid ) ) {
236 const auto &str = zypp::str::Str() << "Keyhint " << file << " does not contain a key with id " << keyid << ". Skipping it.";
237 WAR << str << std::endl;
238 return makeReadyResult(expected<zypp::PublicKey>::error( std::make_exception_ptr( zypp::Exception(str)) ));
239 }
240
241 // Try to cache it...
243 return providerRef->copyFile( key.path(), cacheFile )
244 | [ key ]( expected<zypp::ManagedFile> res ) mutable {
245 if ( res ) {
246 // do not delete from cache
247 res->resetDispose ();
248 }
249 return expected<zypp::PublicKey>::success( std::move(key) );
250 };
251 });
252 })
253 | and_then( [ keyRing, keyid = keyid ]( zypp::PublicKey key ){
254 keyRing->importKey( key, false ); // store in general keyring (not trusted!)
255 return expected<zypp::PublicKeyData>::success(keyRing->publicKeyData( keyid )); // fetch back from keyring in case it was a hidden key
256 });
257 })
258 | [this, res = res] ( std::vector<expected<zypp::PublicKeyData>> &&keyHints ) mutable {
259 std::for_each( keyHints.begin(), keyHints.end(), [this]( expected<zypp::PublicKeyData> &keyData ){
260 if ( keyData && *keyData ) {
261 if ( not zypp::PublicKey::isSafeKeyId( keyData->id() ) ) {
262 WAR << "Keyhint " << keyData->id() << " for " << *keyData << " is not strong enough for auto import. Just caching it." << std::endl;
263 return;
264 }
265 _buddyKeys.push_back ( std::move(keyData.get()) );
266 }
267 });
268
269 MIL << "Check keyhints done. Buddy keys: " << _buddyKeys.size() << std::endl;
270 return expected<ProvideRes>::success (std::move(res));
271 };
272 }
273
274 DlContextRefType _dlContext;
275 MediaHandle _media;
277
281 zypp::TriBool _repoSigValidated = zypp::indeterminate;
282
283 std::vector<zypp::PublicKeyData> _buddyKeys;
284 };
285
286 }
287
288 AsyncOpRef<expected<repo::AsyncDownloadContextRef> > RepoDownloaderWorkflow::downloadMasterIndex(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::Pathname masterIndex_r)
289 {
290 return SimpleExecutor<DownloadMasterIndexLogic, AsyncOp<expected<repo::AsyncDownloadContextRef>>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) );
291 }
292
293 expected<repo::SyncDownloadContextRef> RepoDownloaderWorkflow::downloadMasterIndex(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, zypp::Pathname masterIndex_r)
294 {
295 return SimpleExecutor<DownloadMasterIndexLogic, SyncOp<expected<repo::SyncDownloadContextRef>>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) );
296 }
297
298
299 namespace {
300 template <class DlContextRefType, class MediaHandleType>
301 auto statusImpl ( DlContextRefType dlCtx, MediaHandleType &&mediaHandle ) {
302
303 constexpr bool isAsync = std::is_same_v<DlContextRefType,repo::AsyncDownloadContextRef>;
304
305 const auto finalizeStatus = [ dlCtx ]( zypp::RepoStatus status ){
306 return expected<zypp::RepoStatus>::success( zypp::RepoStatus( dlCtx->repoInfo()) && status );
307 };
308
309 switch( dlCtx->repoInfo().type().toEnum()) {
311 return RpmmdWorkflows::repoStatus( dlCtx, std::forward<MediaHandleType>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
313 return SuseTagsWorkflows::repoStatus( dlCtx, std::forward<MediaHandleType>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
315 return PlaindirWorkflows::repoStatus ( dlCtx, std::forward<MediaHandleType>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
317 break;
318 }
319
321 }
322 }
323
324 AsyncOpRef<expected<zypp::RepoStatus> > RepoDownloaderWorkflow::repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle) {
325 return statusImpl( dl, std::move(mediaHandle) );
326 }
327
328 expected<zypp::RepoStatus> RepoDownloaderWorkflow::repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle) {
329 return statusImpl( dl, std::move(mediaHandle) );
330 }
331
332
333 namespace {
334 template <class DlContextRefType, class MediaHandleType>
335 auto downloadImpl ( DlContextRefType dlCtx, MediaHandleType &&mediaHandle, ProgressObserverRef &&progressObserver ) {
336
337 constexpr bool isAsync = std::is_same_v<DlContextRefType,repo::AsyncDownloadContextRef>;
338
339 switch( dlCtx->repoInfo().type().toEnum()) {
341 return RpmmdWorkflows::download( std::move(dlCtx), std::forward<MediaHandleType>(mediaHandle), std::move(progressObserver) );
343 return SuseTagsWorkflows::download( std::move(dlCtx), std::forward<MediaHandleType>(mediaHandle), std::move(progressObserver) );
345 return PlaindirWorkflows::download ( std::move(dlCtx), std::forward<MediaHandleType>(mediaHandle) );
347 break;
348 }
349
351 }
352 }
353
354 AsyncOpRef<expected<repo::AsyncDownloadContextRef> > RepoDownloaderWorkflow::download(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
355 {
356 return downloadImpl( dl, std::move(mediaHandle), std::move(progressObserver) );
357 }
358
359 expected<repo::SyncDownloadContextRef> RepoDownloaderWorkflow::download(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver)
360 {
361 return downloadImpl( dl, std::move(mediaHandle), std::move(progressObserver) );
362 }
363
364}
Interface of repomd.xml file reader.
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
Store and operate with byte count.
Definition ByteCount.h:31
static const Unit MB
1000^2 Byte
Definition ByteCount.h:60
Base class for Exception.
Definition Exception.h:147
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:365
static PublicKey noThrow(const Pathname &keyFile_r)
Static ctor returning an empty PublicKey rather than throwing.
Definition PublicKey.cc:640
Track changing files or directories.
Definition RepoStatus.h:41
Interim helper class to collect global options and settings.
Definition ZConfig.h:64
Wrapper class for stat/lstat.
Definition PathInfo.h:222
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:282
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition Pathname.h:173
std::string basename() const
Return the last component of this path.
Definition Pathname.h:128
I/O context for KeyRing::verifyFileSignatureWorkflow.
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.
A ProvideRes object is a reference counted ownership of a resource in the cache provided by a Provide...
Definition provideres.h:36
static expected success(ConsParams &&...params)
Definition expected.h:115
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition Arch.h:364
typename conditional< B, T, F >::type conditional_t
Definition TypeTraits.h:39
String related utilities and Regular expression matching.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:320
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:30
expected< zypp::keyring::VerifyFileContext > verifySignature(SyncContextRef ctx, zypp::keyring::VerifyFileContext context)
auto join()
Definition wait.h:133
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition asyncop.h:297
typename remove_smart_ptr< T >::type remove_smart_ptr_t
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:341
ResultType or_else(const expected< T, E > &exp, Function &&f)
Definition expected.h:407
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition expected.h:367
Container< Ret > transform(Container< Msg, CArgs... > &&val, Transformation &&transformation)
Definition transform.h:31
zypp::Pathname _masterIndex
zypp::Pathname _keypath
MediaHandle _media
zypp::Pathname _destdir
std::vector< zypp::PublicKeyData > _buddyKeys
zypp::Pathname _sigpath
zypp::TriBool _repoSigValidated
DlContextRefType _dlContext
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:212
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:433
#define DBG
Definition Logger.h:95
#define MIL
Definition Logger.h:96
#define WAR
Definition Logger.h:97