allow proxy information to be url based instead of protocol based only,
[platform/upstream/libzypp.git] / zypp / PublicKey.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/PublicKey.cc
10  *
11 */
12 #include <climits>
13
14 #include <iostream>
15 #include <vector>
16
17 //#include "zypp/base/Logger.h"
18
19 #include "zypp/base/Gettext.h"
20 #include "zypp/base/String.h"
21 #include "zypp/base/Regex.h"
22 #include "zypp/PublicKey.h"
23 #include "zypp/ExternalProgram.h"
24 #include "zypp/TmpPath.h"
25 #include "zypp/PathInfo.h"
26 #include "zypp/base/Exception.h"
27 #include "zypp/base/Logger.h"
28 #include "zypp/Date.h"
29 #include "zypp/TmpPath.h"
30
31 #include <ctime>
32
33 using std::endl;
34
35 ///////////////////////////////////////////////////////////////////
36 namespace zypp
37 { /////////////////////////////////////////////////////////////////
38
39   /////////////////////////////////////////////////////////////////
40   //
41   //    CLASS NAME : PublicKey::Impl
42   //
43   /** PublicKey implementation. */
44   struct PublicKey::Impl
45   {
46     Impl()
47     {}
48
49     Impl( const Pathname & keyfile )
50     {
51       PathInfo info( keyfile );
52       MIL << "Takeing pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1") << endl;
53
54       if ( !info.isExist() )
55         ZYPP_THROW(Exception("Can't read public key from " + keyfile.asString() + ", file not found"));
56
57       if ( copy( keyfile, _data_file.path() ) != 0 )
58         ZYPP_THROW(Exception("Can't copy public key data from " + keyfile.asString() + " to " +  _data_file.path().asString() ));
59
60       readFromFile();
61     }
62
63     Impl( const filesystem::TmpFile & sharedfile )
64       : _data_file( sharedfile )
65     { readFromFile(); }
66
67     public:
68       /** Offer default Impl. */
69       static shared_ptr<Impl> nullimpl()
70       {
71         static shared_ptr<Impl> _nullimpl( new Impl );
72         return _nullimpl;
73       }
74
75       std::string asString() const
76       {
77         return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
78                           id().c_str(), str::hexstring(created(),8).substr(2).c_str(),
79                           name().c_str(),
80                           fingerprint().c_str(),
81                           daysToLive() );
82       }
83
84       std::string id() const
85       { return _id; }
86
87       std::string name() const
88       { return _name; }
89
90       std::string fingerprint() const
91       { return _fingerprint; }
92
93       std::string gpgPubkeyVersion() const
94       { return _id.empty() ? _id : str::toLower( _id.substr(8,8) ); }
95
96       std::string gpgPubkeyRelease() const
97       { return _created ? str::hexstring( _created ).substr(2) : std::string(); }
98
99       Date created() const
100       { return _created; }
101
102       Date expires() const
103       { return _expires; }
104
105       std::string expiresAsString() const
106       {
107         if ( !_expires )
108         { // translators: an annotation to a gpg keys expiry date
109           return _("(does not expire)");
110         }
111         std::string ret( _expires.asString() );
112         int ttl( daysToLive() );
113         if ( ttl <= 90 )
114         {
115           ret += " ";
116           if ( ttl < 0 )
117           { // translators: an annotation to a gpg keys expiry date
118             ret += _("(EXPIRED)");
119           }
120           else if ( ttl == 0 )
121           { // translators: an annotation to a gpg keys expiry date
122             ret += _("(expires within 24h)");
123           }
124           else
125           { // translators: an annotation to a gpg keys expiry date
126             ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
127           }
128         }
129         return ret;
130       }
131
132       Pathname path() const
133       { return _data_file.path(); }
134
135       bool expired() const
136       {
137         Date exp( expires() );
138         return( exp && exp < Date::now() );
139       }
140
141       int daysToLive() const
142       {
143         Date exp( expires() );
144         if ( ! expires() )
145           return INT_MAX;
146         exp -= Date::now();
147         return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
148       }
149
150     protected:
151
152       void readFromFile()
153       {
154         PathInfo info( _data_file.path() );
155         MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
156
157         static filesystem::TmpDir dir;
158         const char* argv[] =
159         {
160           "gpg",
161           "-v",
162           "--no-default-keyring",
163           "--fixed-list-mode",
164           "--with-fingerprint",
165           "--with-colons",
166           "--homedir",
167           dir.path().asString().c_str(),
168           "--quiet",
169           "--no-tty",
170           "--no-greeting",
171           "--batch",
172           "--status-fd",
173           "1",
174           _data_file.path().asString().c_str(),
175           NULL
176         };
177
178         ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
179
180         std::string line;
181         bool sawpub = false;
182         bool sawsig = false;
183
184         // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
185         // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
186         // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
187         // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
188         // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
189         // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
190         // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
191
192         for ( line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
193         {
194           // trim trailing NL.
195           if ( line.empty() )
196             continue;
197           if ( line[line.size()-1] == '\n' )
198             line.erase( line.size()-1 );
199
200           // split at ':'
201           std::vector<std::string> words;
202           str::splitFields( line, std::back_inserter(words), ":" );
203           if( words.empty() )
204             continue;
205
206           if ( words[0] == "pub" )
207           {
208             if ( sawpub )
209               continue;
210             sawpub = true;
211             // take default from pub
212             _id      = words[4];
213             _name    = words[9];
214             _created = Date(str::strtonum<Date::ValueType>(words[5]));
215             _expires = Date(str::strtonum<Date::ValueType>(words[6]));
216
217           }
218           else if ( words[0] == "sig" )
219           {
220             if ( sawsig || words[words.size()-2] != "13x"  )
221               continue;
222             sawsig = true;
223             // update creation and expire dates from 1st signature type "13x"
224             if ( ! words[5].empty() )
225               _created = Date(str::strtonum<Date::ValueType>(words[5]));
226             if ( ! words[6].empty() )
227               _expires = Date(str::strtonum<Date::ValueType>(words[6]));
228           }
229           else if ( words[0] == "fpr" )
230           {
231             _fingerprint = words[9];
232           }
233           else if ( words[0] == "uid" )
234           {
235             if ( ! words[9].empty() )
236               _name = words[9];
237           }
238         }
239         prog.close();
240
241         if ( _id.size() == 0 )
242           ZYPP_THROW( BadKeyException( "File " + _data_file.path().asString() + " doesn't contain public key data" , _data_file.path() ) );
243
244         //replace all escaped semicolon with real ':'
245         str::replaceAll( _name, "\\x3a", ":" );
246
247         MIL << "Read pubkey from " << info.path() << ": " << asString() << endl;
248       }
249
250     private:
251       filesystem::TmpFile _data_file;
252
253       std::string _id;
254       std::string _name;
255       std::string _fingerprint;
256       Date        _created;
257       Date        _expires;
258
259     private:
260       friend Impl * rwcowClone<Impl>( const Impl * rhs );
261       /** clone for RWCOW_pointer */
262       Impl * clone() const
263       { return new Impl( *this ); }
264   };
265   ///////////////////////////////////////////////////////////////////
266
267   ///////////////////////////////////////////////////////////////////
268   //
269   //    METHOD NAME : PublicKey::PublicKey
270   //    METHOD TYPE : Ctor
271   //
272   PublicKey::PublicKey()
273   : _pimpl( Impl::nullimpl() )
274   {}
275
276   PublicKey::PublicKey( const Pathname & file )
277   : _pimpl( new Impl(file) )
278   {}
279
280   PublicKey::PublicKey( const filesystem::TmpFile & sharedfile )
281   : _pimpl( new Impl(sharedfile) )
282   {}
283
284   ///////////////////////////////////////////////////////////////////
285   //
286   //    METHOD NAME : PublicKey::~PublicKey
287   //    METHOD TYPE : Dtor
288   //
289   PublicKey::~PublicKey()
290   {}
291
292   ///////////////////////////////////////////////////////////////////
293   //
294   // Forward to implementation:
295   //
296   ///////////////////////////////////////////////////////////////////
297
298   std::string PublicKey::asString() const
299   { return _pimpl->asString(); }
300
301   std::string PublicKey::id() const
302   { return _pimpl->id(); }
303
304   std::string PublicKey::name() const
305   { return _pimpl->name(); }
306
307   std::string PublicKey::fingerprint() const
308   { return _pimpl->fingerprint(); }
309
310   std::string PublicKey::gpgPubkeyVersion() const
311   { return _pimpl->gpgPubkeyVersion(); }
312
313   std::string PublicKey::gpgPubkeyRelease() const
314   { return _pimpl->gpgPubkeyRelease(); }
315
316   Date PublicKey::created() const
317   { return _pimpl->created(); }
318
319   Date PublicKey::expires() const
320   { return _pimpl->expires(); }
321
322   std::string PublicKey::expiresAsString() const
323   { return _pimpl->expiresAsString(); }
324
325   bool PublicKey::expired() const
326   { return _pimpl->expired(); }
327
328   int PublicKey::daysToLive() const
329   { return _pimpl->daysToLive(); }
330
331   Pathname PublicKey::path() const
332   { return _pimpl->path(); }
333
334   bool PublicKey::operator==( PublicKey b ) const
335   {
336     return (   b.id() == id()
337             && b.fingerprint() == fingerprint()
338             && b.created() == created() );
339   }
340
341   bool PublicKey::operator==( std::string sid ) const
342   {
343     return sid == id();
344   }
345
346   std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
347   {
348     str << "[" << obj.name() << "]" << endl;
349     str << "  fpr " << obj.fingerprint() << endl;
350     str << "   id " << obj.id() << endl;
351     str << "  cre " << obj.created() << endl;
352     str << "  exp " << obj.expiresAsString() << endl;
353     str << "  ttl " << obj.daysToLive() << endl;
354     str << "  rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
355     str << "]";
356     return str;
357   }
358
359   /////////////////////////////////////////////////////////////////
360 } // namespace zypp
361 ///////////////////////////////////////////////////////////////////