libzypp  17.32.5
repoinfowf.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 #include "repoinfowf.h"
11 #include <zypp-core/ManagedFile.h>
12 #include <zypp-core/base/String.h>
13 #include <zypp-core/base/Gettext.h>
14 #include <zypp-core/fs/TmpPath.h>
15 #include <zypp/base/StrMatcher.h>
16 #include <zypp/KeyRing.h>
17 #include <zypp/PublicKey.h>
18 #include <zypp/ZYppCallbacks.h>
19 
20 #include <utility>
21 #include <zypp-core/zyppng/pipelines/Transform>
22 #include <zypp-core/zyppng/pipelines/Expected>
23 #include <zypp-core/zyppng/pipelines/MTry>
24 #include <zypp-media/ng/Provide>
25 #include <zypp-media/ng/ProvideSpec>
26 #include <zypp/MediaSetAccess.h>
27 #include <zypp/ng/Context>
28 #include <zypp/ng/UserRequest>
30 
31 #include <fstream>
32 
33 
34 namespace zyppng {
35 
36  namespace {
37 
38  using namespace zyppng::operators;
39 
40  template<class Executor, class OpType>
41  struct RepoInfoProvideKeyLogic : public LogicBase<Executor, OpType> {
42 
43  using ZyppContextRefType = MaybeAsyncContextRef<OpType>;
44  using ZyppContextType = remove_smart_ptr_t<ZyppContextRefType>;
45  using ProvideType = typename ZyppContextType::ProvideType;
46  using MediaHandle = typename ProvideType::MediaHandle;
47  using ProvideRes = typename ProvideType::Res;
48 
49  RepoInfoProvideKeyLogic( ZyppContextRefType &&zyppContext, zypp::RepoInfo &&info, std::string &&keyID_r, zypp::Pathname &&targetDirectory_r )
50  : _zyppContext( std::move(zyppContext) )
51  , _info( std::move(info) )
52  , _keyID_r(std::move( keyID_r ))
53  , _targetDirectory_r(std::move( targetDirectory_r ))
54  , _keyIDStr( _keyID_r.size() > 8 ? _keyID_r.substr( _keyID_r.size()-8 ) : _keyID_r ) // print short ID in Jobreports
56  { }
57 
58  ZYPP_ENABLE_LOGIC_BASE( Executor, OpType );
59 
60  MaybeAsyncRef<zypp::filesystem::Pathname> execute () {
61  using namespace zyppng::operators;
62  using zyppng::operators::operator|;
63  using zyppng::expected;
64 
65 
66  if ( _keyID_r.empty() )
68 
69  importKeysInTargetDir();
70 
72  return makeReadyResult(writeKeysToTargetDir());
73  }
74 
75  if ( _info.gpgKeyUrlsEmpty() ) {
76  // translator: %1% is a repositories name
77  executor()->info( zypp::str::Format(_("Repository %1% does not define additional 'gpgkey=' URLs.") ) % _info.asUserString() );
78  return makeReadyResult(writeKeysToTargetDir());
79  }
80 
81  // no key in the cache is what we are looking for, lets download
82  // all keys specified in gpgkey= entries
83 
84  // translator: %1% is a gpg key ID like 3DBDC284
85  // %2% is a repositories name
86  executor()->info( zypp::str::Format(_("Looking for gpg key ID %1% in repository %2%.") ) % _keyIDStr % _info.asUserString() );
87 
88  return _info.gpgKeyUrls()
89  | transform( [this]( const zypp::Url &url ) {
90 
91  executor()->info( " gpgkey=" + url.asString() );
92  return fetchKey( url )
93  | and_then( [this, url]( zypp::ManagedFile f ) -> expected<void> {
94  try {
95  if ( f->empty() )
96  return expected<void>::error(std::make_exception_ptr( zypp::Exception("Empty ManagedFile returned.") ));
97 
98  zypp::PublicKey key(f);
99  if ( !key.isValid() )
100  return expected<void>::error(std::make_exception_ptr( zypp::Exception("Invalid public key.") ));
101 
102  // import all keys into our temporary keyring
103  _tempKeyRing.multiKeyImport(f, true);
104 
105  } catch ( const std::exception & e ) {
106  //ignore and continue to next url
107  ZYPP_CAUGHT(e);
108  MIL << "Key import from url:'"<<url<<"' failed." << std::endl;
109  return expected<void>::error( std::current_exception() );
110  }
111 
112  return expected<void>::success();
113  });
114 
115  })
116  | [this]( std::list<expected<void>> && ) ->zypp::Pathname {
117  return writeKeysToTargetDir();
118  };
119  }
120 
121  protected:
122 
123  MaybeAsyncRef<zyppng::expected<zypp::ManagedFile>> fetchKey ( const zypp::Url &url ) {
124  return _zyppContext->provider ()->provide( url, zyppng::ProvideFileSpec() )
125  | and_then( ProvideType::copyResultToDest( _zyppContext->provider(), _targetDirectory_r / zypp::Pathname( url.getPathName() ).basename() ) );
126  }
127 
128  void importKeysInTargetDir () {
129  MIL << "Check for " << _keyID_r << " at " << _targetDirectory_r << std::endl;
130 
131  // translator: %1% is a gpg key ID like 3DBDC284
132  // %2% is a cache directories path
133  executor()->info( zypp::str::Format(_("Looking for gpg key ID %1% in cache %2%.") ) % _keyIDStr % _targetDirectory_r );
136  [this]( const zypp::Pathname & dir_r, const std::string & str_r ){
137  try {
138 
139  // deprecate a month old keys
140  zypp::PathInfo fileInfo ( dir_r/str_r );
141  if ( zypp::Date::now() - fileInfo.mtime() > zypp::Date::month ) {
142  //if unlink fails, the file will be overriden in the next step, no need
143  //to show a error
144  zypp::filesystem::unlink( dir_r/str_r );
145  } else {
146  _tempKeyRing.multiKeyImport(dir_r/str_r, true);
147  }
148  } catch (const zypp::KeyRingException& e) {
149  ZYPP_CAUGHT(e);
150  ERR << "Error importing cached key from file '"<<dir_r/str_r<<"'."<<std::endl;
151  }
152  return true;
153  });
154  }
155 
156  zypp::Pathname writeKeysToTargetDir() {
157 
159 
160  //now write all keys into their own files in cache, override existing ones to always have
161  //up to date key data
162  for ( const auto & key: _tempKeyRing.trustedPublicKeyData()) {
163  MIL << "KEY ID in KEYRING: " << key.id() << std::endl;
164 
165  zypp::Pathname keyFile = _targetDirectory_r/(zypp::str::Format("%1%.key") % key.rpmName()).asString();
166 
167  std::ofstream fout( keyFile.c_str(), std::ios_base::out | std::ios_base::trunc );
168 
169  if (!fout)
170  ZYPP_THROW(zypp::Exception(zypp::str::form("Cannot open file %s",keyFile.c_str())));
171 
172  _tempKeyRing.dumpTrustedPublicKey( key.id(), fout );
173  }
174 
175  // key is STILL not known, we give up
177  return zypp::Pathname();
178  }
179 
181  if ( !keyData ) {
182  ERR << "Error when exporting key from temporary keychain." << std::endl;
183  return zypp::Pathname();
184  }
185 
186  return _targetDirectory_r/(zypp::str::Format("%1%.key") % keyData.rpmName()).asString();
187  }
188 
189  ZyppContextRefType _zyppContext;
191  const std::string _keyID_r;
193  const std::string _keyIDStr;
194 
197  };
198 
199 
200  struct AsyncRepoInfoProvideKey : public RepoInfoProvideKeyLogic<AsyncRepoInfoProvideKey, zyppng::AsyncOp<zypp::Pathname>>
201  {
202  using RepoInfoProvideKeyLogic::RepoInfoProvideKeyLogic;
203  bool info( const std::string & msg_r, const UserData & userData_r = UserData() ) {
204  _zyppContext->sendUserRequest( ShowMessageRequest::create( msg_r, ShowMessageRequest::MType::Info, userData_r ) );
205  return true;
206  }
207  };
208 
209  struct SyncRepoInfoProvideKey : public RepoInfoProvideKeyLogic<SyncRepoInfoProvideKey, zyppng::SyncOp<zypp::Pathname>>
210  {
211  using RepoInfoProvideKeyLogic::RepoInfoProvideKeyLogic;
212  bool info( const std::string & msg_r, const UserData & userData_r = UserData() ) {
213  return zypp::JobReport::info( msg_r, userData_r );
214  }
215  };
216  }
217 
218  zypp::filesystem::Pathname RepoInfoWorkflow::provideKey( SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::filesystem::Pathname targetDirectory_r )
219  {
220  return SyncRepoInfoProvideKey::run( std::move(ctx), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) );
221  }
222 
224  {
225  return AsyncRepoInfoProvideKey::run( std::move(ctx), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) );
226  }
227 
228 }
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:320
#define MIL
Definition: Logger.h:96
url_set gpgKeyUrls() const
The list of gpgkey URLs defined for this repo.
Definition: RepoInfo.cc:617
auto transform(Transformation &&transformation)
Definition: transform.h:70
#define _(MSG)
Definition: Gettext.h:37
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:429
void dumpTrustedPublicKey(const std::string &id, std::ostream &stream)
Definition: KeyRing.h:237
Gpg key handling.
Definition: KeyRing.h:186
String matching (STRING|SUBSTRING|GLOB|REGEX).
Definition: StrMatcher.h:297
Class representing one GPG Public Keys data.
Definition: PublicKey.h:207
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition: PathInfo.cc:32
const char * c_str() const
String representation.
Definition: Pathname.h:110
const zypp::Pathname _targetDirectory_r
Definition: repoinfowf.cc:192
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
std::list< PublicKeyData > trustedPublicKeyData()
Get a list of trusted public key data in the keyring (key data only)
Definition: KeyRing.cc:483
std::string asUserString() const
User string: label (alias or name)
Definition: RepoInfoBase.h:87
Convenient building of std::string with boost::format.
Definition: String.h:252
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
const std::string _keyIDStr
Definition: repoinfowf.cc:193
#define ERR
Definition: Logger.h:98
static const ValueType month
Definition: Date.h:49
const std::string _keyID_r
Definition: repoinfowf.cc:191
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Definition: Bit.h:57
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
ZyppContextRefType _zyppContext
Definition: repoinfowf.cc:189
zypp::callback::UserData UserData
Definition: userrequest.h:18
const zypp::RepoInfo _info
Definition: repoinfowf.cc:190
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:501
bool gpgKeyUrlsEmpty() const
Whether gpgkey URLs are defined.
Definition: RepoInfo.cc:611
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:181
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:701
zypp::KeyRing _tempKeyRing
Definition: repoinfowf.cc:196
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition: logichelpers.h:199
Match at string end.
Definition: StrMatcher.h:45
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition: asyncop.h:297
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Initial import from RpmDb.
Definition: KeyRing.cc:465
static expected success(ConsParams &&...params)
Definition: expected.h:115
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:437
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition: asyncop.h:255
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:364
Base class for Exception.
Definition: Exception.h:146
static Date now()
Return the current time.
Definition: Date.h:78
zypp::Pathname provideKey(SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r)
Definition: repoinfowf.cc:218
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:608
auto and_then(Fun &&function)
Definition: expected.h:554
zypp::filesystem::TmpDir _tmpKeyRingDir
Definition: repoinfowf.cc:195
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
static bool info(const std::string &msg_r, const UserData &userData_r=UserData())
send message text
bool isKeyTrusted(const std::string &id)
true if the key id is trusted
Definition: KeyRing.cc:506
Url manipulation class.
Definition: Url.h:91