#include <iostream>
#include <vector>
-//#include "zypp/base/Logger.h"
-
#include "zypp/base/Gettext.h"
#include "zypp/base/String.h"
#include "zypp/base/Regex.h"
#include "zypp/TmpPath.h"
#include "zypp/PathInfo.h"
#include "zypp/base/Exception.h"
-#include "zypp/base/Logger.h"
+#include "zypp/base/LogTools.h"
#include "zypp/Date.h"
#include "zypp/TmpPath.h"
{ /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
- /// \class PublicKey::Impl
- /// \brief PublicKey implementation.
+ /// \class PublicKeyData::Impl
+ /// \brief PublicKeyData implementation.
///////////////////////////////////////////////////////////////////
- struct PublicKey::Impl
+ struct PublicKeyData::Impl
{
- /** Data we extract from one key. */
- struct KeyData
+ std::string _id;
+ std::string _name;
+ std::string _fingerprint;
+ Date _created;
+ Date _expires;
+
+ public:
+ /** Offer default Impl. */
+ static shared_ptr<Impl> nullimpl()
{
- std::string _id;
- std::string _name;
- std::string _fingerprint;
- Date _created;
- Date _expires;
- };
+ static shared_ptr<Impl> _nullimpl( new Impl );
+ return _nullimpl;
+ }
- Impl()
- {}
+ private:
+ friend Impl * rwcowClone<Impl>( const Impl * rhs );
+ /** clone for RWCOW_pointer */
+ Impl * clone() const
+ { return new Impl( *this ); }
+ };
+ ///////////////////////////////////////////////////////////////////
- Impl( const Pathname & keyfile )
- {
- PathInfo info( keyfile );
- MIL << "Takeing pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1") << endl;
+ ///////////////////////////////////////////////////////////////////
+ /// class PublicKeyData
+ ///////////////////////////////////////////////////////////////////
- if ( !info.isExist() )
- ZYPP_THROW(Exception("Can't read public key from " + keyfile.asString() + ", file not found"));
+ PublicKeyData::PublicKeyData()
+ : _pimpl( Impl::nullimpl() )
+ {}
- if ( copy( keyfile, _dataFile.path() ) != 0 )
- ZYPP_THROW(Exception("Can't copy public key data from " + keyfile.asString() + " to " + _dataFile.path().asString() ));
+ PublicKeyData::~PublicKeyData()
+ {}
- readFromFile();
- }
+ PublicKeyData::operator bool() const
+ { return !_pimpl->_fingerprint.empty(); }
- Impl( const filesystem::TmpFile & sharedfile )
- : _dataFile( sharedfile )
- { readFromFile(); }
+ std::string PublicKeyData::id() const
+ { return _pimpl->_id; }
- public:
- /** Offer default Impl. */
- static shared_ptr<Impl> nullimpl()
- {
- static shared_ptr<Impl> _nullimpl( new Impl );
- return _nullimpl;
- }
+ std::string PublicKeyData::name() const
+ { return _pimpl->_name; }
- std::string asString() const
- {
- return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
- id().c_str(), str::hexstring(created(),8).substr(2).c_str(),
- name().c_str(),
- fingerprint().c_str(),
- daysToLive() );
+ std::string PublicKeyData::fingerprint() const
+ { return _pimpl->_fingerprint; }
+
+ Date PublicKeyData::created() const
+ { return _pimpl->_created; }
+
+ Date PublicKeyData::expires() const
+ { return _pimpl->_expires; }
+
+ bool PublicKeyData::expired() const
+ { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); }
+
+ int PublicKeyData::daysToLive() const
+ {
+ if ( _pimpl->_expires )
+ {
+ Date exp( _pimpl->_expires - Date::now() );
+ return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
+ }
+ return INT_MAX;
+ }
+
+ std::string PublicKeyData::expiresAsString() const
+ {
+ if ( !_pimpl->_expires )
+ { // translators: an annotation to a gpg keys expiry date
+ return _("(does not expire)");
+ }
+ std::string ret( _pimpl->_expires.asString() );
+ int ttl( daysToLive() );
+ if ( ttl <= 90 )
+ {
+ ret += " ";
+ if ( ttl < 0 )
+ { // translators: an annotation to a gpg keys expiry date
+ ret += _("(EXPIRED)");
+ }
+ else if ( ttl == 0 )
+ { // translators: an annotation to a gpg keys expiry date
+ ret += _("(expires within 24h)");
+ }
+ else
+ { // translators: an annotation to a gpg keys expiry date
+ ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
}
+ }
+ return ret;
+ }
- std::string id() const
- { return _keyData._id; }
+ std::string PublicKeyData::gpgPubkeyVersion() const
+ { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); }
- std::string name() const
- { return _keyData._name; }
+ std::string PublicKeyData::gpgPubkeyRelease() const
+ { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); }
- std::string fingerprint() const
- { return _keyData._fingerprint; }
+ std::string PublicKeyData::asString() const
+ {
+ return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
+ _pimpl->_id.c_str(),
+ gpgPubkeyRelease().c_str(),
+ _pimpl->_name.c_str(),
+ _pimpl->_fingerprint.c_str(),
+ daysToLive() );
+ }
- std::string gpgPubkeyVersion() const
- { return _keyData._id.empty() ? _keyData._id : str::toLower( _keyData._id.substr(8,8) ); }
+ std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj )
+ {
+ str << "[" << obj.name() << "]" << endl;
+ str << " fpr " << obj.fingerprint() << endl;
+ str << " id " << obj.id() << endl;
+ str << " cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl;
+ str << " exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl;
+ str << " ttl " << obj.daysToLive() << endl;
+ str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
+ str << "]";
+ return str;
+ }
- std::string gpgPubkeyRelease() const
- { return _keyData._created ? str::hexstring( _keyData._created ).substr(2) : std::string(); }
+ bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs )
+ { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); }
- Date created() const
- { return _keyData._created; }
- Date expires() const
- { return _keyData._expires; }
+ ///////////////////////////////////////////////////////////////////
+ /// \class PublicKeyScanner::Impl
+ /// \brief PublicKeyScanner implementation.
+ ///////////////////////////////////////////////////////////////////
+ struct PublicKeyScanner::Impl
+ {
+ std::vector<std::string> _words;
+ enum { pNONE, pPUB, pSIG, pFPR, pUID } _parseEntry;
+
+ Impl()
+ : _parseEntry( pNONE )
+ {}
- std::string expiresAsString() const
+ void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
+ {
+ // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
+ // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
+ // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
+ // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
+ // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
+ // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
+ // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
+ // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
+ if ( line_r.empty() )
+ return;
+
+ // quick check for interesting entries
+ _parseEntry = pNONE;
+ switch ( line_r[0] )
{
- if ( !_keyData._expires )
- { // translators: an annotation to a gpg keys expiry date
- return _("(does not expire)");
- }
- std::string ret( _keyData._expires.asString() );
- int ttl( daysToLive() );
- if ( ttl <= 90 )
- {
- ret += " ";
- if ( ttl < 0 )
- { // translators: an annotation to a gpg keys expiry date
- ret += _("(EXPIRED)");
- }
- else if ( ttl == 0 )
- { // translators: an annotation to a gpg keys expiry date
- ret += _("(expires within 24h)");
- }
- else
- { // translators: an annotation to a gpg keys expiry date
- ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
- }
- }
- return ret;
+ #define DOTEST( C1, C2, C3, E ) case C1: if ( line_r[1] == C2 && line_r[2] == C3 && line_r[3] == ':' ) _parseEntry = E; break
+ DOTEST( 'p', 'u', 'b', pPUB );
+ DOTEST( 's', 'i', 'g', pSIG );
+ DOTEST( 'f', 'p', 'r', pFPR );
+ DOTEST( 'u', 'i', 'd', pUID );
+ #undef DOTEST
}
+ if ( _parseEntry == pNONE )
+ return;
- Pathname path() const
- { return _dataFile.path(); }
+ if ( line_r[line_r.size()-1] == '\n' )
+ line_r.erase( line_r.size()-1 );
+ // DBG << line_r << endl;
+
+ _words.clear();
+ str::splitFields( line_r, std::back_inserter(_words), ":" );
+
+ PublicKeyData * key( &keys_r.back() );
- bool expired() const
+ switch ( _parseEntry )
{
- Date exp( expires() );
- return( exp && exp < Date::now() );
+ case pPUB:
+ keys_r.push_back( PublicKeyData() ); // reset upon new key
+ key = &keys_r.back();
+ key->_pimpl->_id = _words[4];
+ key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
+ key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
+ key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
+ break;
+
+ case pSIG:
+ // Update creation/modification date from signatures type "13x".
+ if ( _words[_words.size()-2] == "13x" )
+ {
+ Date cdate(str::strtonum<Date::ValueType>(_words[5]));
+ if ( key->_pimpl->_created < cdate )
+ key->_pimpl->_created = cdate;
+ }
+ break;
+
+ case pFPR:
+ if ( key->_pimpl->_fingerprint.empty() )
+ key->_pimpl->_fingerprint = _words[9];
+ break;
+
+ case pUID:
+ if ( ! _words[9].empty() )
+ key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" );
+ break;
+
+ case pNONE:
+ break;
}
+ }
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ // class PublicKeyScanner
+ ///////////////////////////////////////////////////////////////////
+
+ PublicKeyScanner::PublicKeyScanner()
+ : _pimpl( new Impl )
+ {}
+
+ PublicKeyScanner::~PublicKeyScanner()
+ {}
- int daysToLive() const
+ void PublicKeyScanner::scan( std::string line_r )
+ { _pimpl->scan( line_r, _keys ); }
+
+
+ ///////////////////////////////////////////////////////////////////
+ /// \class PublicKey::Impl
+ /// \brief PublicKey implementation.
+ ///////////////////////////////////////////////////////////////////
+ struct PublicKey::Impl
+ {
+ Impl()
+ {}
+
+ Impl( const Pathname & keyFile_r )
+ {
+ PathInfo info( keyFile_r );
+ MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl;
+
+ if ( !info.isExist() )
+ ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found"));
+
+ if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 )
+ ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() ));
+
+ readFromFile();
+ }
+
+ Impl( const filesystem::TmpFile & sharedFile_r )
+ : _dataFile( sharedFile_r )
+ { readFromFile(); }
+
+ Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r )
+ : _dataFile( sharedFile_r )
+ , _keyData( keyData_r )
+ {
+ if ( ! keyData_r )
{
- Date exp( expires() );
- if ( ! expires() )
- return INT_MAX;
- exp -= Date::now();
- return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
+ WAR << "Invalid PublicKeyData supplied: scanning from file" << endl;
+ readFromFile();
}
+ }
- protected:
+ public:
+ const PublicKeyData & keyData() const
+ { return _keyData; }
+ Pathname path() const
+ { return _dataFile.path(); }
+
+ protected:
void readFromFile()
{
PathInfo info( _dataFile.path() );
_dataFile.path().asString().c_str(),
NULL
};
+ ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
- ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
-
- // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
- // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
- // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
- // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
- // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
- // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
- // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
- KeyData keyData;
- std::string line;
- std::vector<std::string> words;
- enum { pNONE, pPUB, pSIG, pFPR, pUID } parseEntry;
- bool sawSig = false;
- for ( line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
+ PublicKeyScanner scanner;
+ for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
{
- if ( line.empty() )
- continue;
-
- // quick check for interesting entries
- parseEntry = pNONE;
- switch ( line[0] )
- {
-#define DOTEST( C1, C2, C3, E ) case C1: if ( line[1] == C2 && line[2] == C3 && line[3] == ':' ) parseEntry = E; break
- DOTEST( 'p', 'u', 'b', pPUB );
- DOTEST( 's', 'i', 'g', pSIG );
- DOTEST( 'f', 'p', 'r', pFPR );
- DOTEST( 'u', 'i', 'd', pUID );
-#undef DOTEST
- }
- if ( parseEntry == pNONE )
- continue;
-
- if ( line[line.size()-1] == '\n' )
- line.erase( line.size()-1 );
-
- words.clear();
- str::splitFields( line, std::back_inserter(words), ":" );
-
- switch ( parseEntry )
- {
- case pPUB:
- keyData = KeyData(); // reset upon new key
- sawSig = false;
- keyData._id = words[4];
- keyData._name = words[9];
- keyData._created = Date(str::strtonum<Date::ValueType>(words[5]));
- keyData._expires = Date(str::strtonum<Date::ValueType>(words[6]));
- break;
-
- case pSIG:
- if ( !sawSig && words[words.size()-2] == "13x" )
- {
- // update creation and expire dates from 1st signature type "13x"
- if ( ! words[5].empty() )
- keyData._created = Date(str::strtonum<Date::ValueType>(words[5]));
- if ( ! words[6].empty() )
- keyData._expires = Date(str::strtonum<Date::ValueType>(words[6]));
- sawSig = true;
- }
- break;
-
- case pFPR:
- if ( ! words[9].empty() )
- keyData._fingerprint = words[9];
- break;
-
- case pUID:
- if ( ! words[9].empty() )
- keyData._name = words[9];
- break;
-
- case pNONE:
- break;
- }
- }
+ scanner.scan( line );
+ }
prog.close();
- if ( keyData._id.empty() )
- ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
+ switch ( scanner._keys.size() )
+ {
+ case 0:
+ ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) );
+ break;
- //replace all escaped semicolon with real ':'
- str::replaceAll( keyData._name, "\\x3a", ":" );
+ case 1:
+ // ok.
+ break;
- _keyData = keyData;
- MIL << "Read pubkey from " << info.path() << ": " << asString() << endl;
+ default:
+ WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl;
+ break;
+ }
+
+ _keyData = scanner._keys.back();
+ MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
}
private:
filesystem::TmpFile _dataFile;
- KeyData _keyData;
+ PublicKeyData _keyData;
+
+ public:
+ /** Offer default Impl. */
+ static shared_ptr<Impl> nullimpl()
+ {
+ static shared_ptr<Impl> _nullimpl( new Impl );
+ return _nullimpl;
+ }
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
- //
- // class PublicKey
- //
+ // class PublicKey
///////////////////////////////////////////////////////////////////
PublicKey::PublicKey()
: _pimpl( Impl::nullimpl() )
{}
PublicKey::PublicKey( const Pathname & file )
- : _pimpl( new Impl(file) )
+ : _pimpl( new Impl( file ) )
{}
PublicKey::PublicKey( const filesystem::TmpFile & sharedfile )
- : _pimpl( new Impl(sharedfile) )
+ : _pimpl( new Impl( sharedfile ) )
+ {}
+
+ PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata )
+ : _pimpl( new Impl( sharedfile, keydata ) )
{}
PublicKey::~PublicKey()
{}
- std::string PublicKey::asString() const
- { return _pimpl->asString(); }
+ const PublicKeyData & PublicKey::keyData() const
+ { return _pimpl->keyData(); }
+
+ Pathname PublicKey::path() const
+ { return _pimpl->path(); }
std::string PublicKey::id() const
- { return _pimpl->id(); }
+ { return keyData().id(); }
std::string PublicKey::name() const
- { return _pimpl->name(); }
+ { return keyData().name(); }
std::string PublicKey::fingerprint() const
- { return _pimpl->fingerprint(); }
-
- std::string PublicKey::gpgPubkeyVersion() const
- { return _pimpl->gpgPubkeyVersion(); }
-
- std::string PublicKey::gpgPubkeyRelease() const
- { return _pimpl->gpgPubkeyRelease(); }
+ { return keyData().fingerprint(); }
Date PublicKey::created() const
- { return _pimpl->created(); }
+ { return keyData().created(); }
Date PublicKey::expires() const
- { return _pimpl->expires(); }
-
- std::string PublicKey::expiresAsString() const
- { return _pimpl->expiresAsString(); }
+ { return keyData().expires(); }
bool PublicKey::expired() const
- { return _pimpl->expired(); }
+ { return keyData().expired(); }
int PublicKey::daysToLive() const
- { return _pimpl->daysToLive(); }
+ { return keyData().daysToLive(); }
- Pathname PublicKey::path() const
- { return _pimpl->path(); }
+ std::string PublicKey::expiresAsString() const
+ { return keyData().expiresAsString(); }
- bool PublicKey::operator==( PublicKey b ) const
- {
- return ( b.id() == id()
- && b.fingerprint() == fingerprint()
- && b.created() == created() );
- }
+ std::string PublicKey::gpgPubkeyVersion() const
+ { return keyData().gpgPubkeyVersion(); }
+
+ std::string PublicKey::gpgPubkeyRelease() const
+ { return keyData().gpgPubkeyRelease(); }
+
+ std::string PublicKey::asString() const
+ { return keyData().asString(); }
+
+ bool PublicKey::operator==( PublicKey rhs ) const
+ { return rhs.keyData() == keyData(); }
bool PublicKey::operator==( std::string sid ) const
- {
- return sid == id();
- }
+ { return sid == id(); }
std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
- {
- str << "[" << obj.name() << "]" << endl;
- str << " fpr " << obj.fingerprint() << endl;
- str << " id " << obj.id() << endl;
- str << " cre " << obj.created() << endl;
- str << " exp " << obj.expiresAsString() << endl;
- str << " ttl " << obj.daysToLive() << endl;
- str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
- str << "]";
- return str;
- }
+ { return dumpOn( str, obj.keyData() ); }
/////////////////////////////////////////////////////////////////
} // namespace zypp
#include "zypp/base/PtrTypes.h"
#include "zypp/base/Exception.h"
#include "zypp/Pathname.h"
+#include "zypp/Date.h"
///////////////////////////////////////////////////////////////////
namespace zypp
{
class TmpFile;
}
- class Date;
-
- /**
- * Exception thrown when the supplied key is
- * not a valid gpg key
- */
+ ///////////////////////////////////////////////////////////////////
+ /// \class BadKeyException
+ /// \brief Exception thrown when the supplied key is not a valid gpg key
+ ///////////////////////////////////////////////////////////////////
class BadKeyException : public Exception
{
public:
private:
Pathname _keyfile;
};
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ /// \class PublicKeyData
+ /// \brief Class representing one GPG Public Keys data.
+ /// \ref PublicKeyData are provided e.g. by a \ref PublicKey or
+ /// a \ref KeyRing. \ref PublicKeyData are usually easier to
+ /// retrieve and sufficient unless you actually need an ASCII
+ /// armored version of the key placed in a tempfile. In this
+ /// case use \ref PublicKey.
+ ///////////////////////////////////////////////////////////////////
+ class PublicKeyData
+ {
+ public:
+ /** Default constructed: empty data. */
+ PublicKeyData();
+
+ ~PublicKeyData();
+
+ /** Scan data from 'gpg --with-colons' key listings. */
+ friend class PublicKeyScanner;
+
+ /** Whether this contains valid data (not default constructed). */
+ explicit operator bool() const;
+
+ public:
+ /** Key ID. */
+ std::string id() const;
+
+ /** Key name. */
+ std::string name() const;
+
+ /** Key fingerprint.*/
+ std::string fingerprint() const;
+
+ /** Creation / last modification date (latest selfsig). */
+ Date created() const;
+
+ /** Expiry date, or \c Date() if the key never expires. */
+ Date expires() const;
+
+ /** Whether the key has expired. */
+ bool expired() const;
+
+ /** Number of days (24h) until the key expires (or since it exired).
+ * A value of \c 0 means the key will expire within the next 24h.
+ * Negative values indicate the key has expired less than \c N days ago.
+ * For keys without expiration date \c INT_MAX is returned.
+ */
+ int daysToLive() const;
+
+ /** * Expiry info in a human readable form.
+ * The exipry daye plus an annotation if the key has expired, or will
+ * expire within 90 days.
+ * \code
+ * (does not expire)
+ * Tue May 11 13:37:33 CEST 2010
+ * Tue May 11 13:37:33 CEST 2010 (expires in 90 days)
+ * Tue May 11 13:37:33 CEST 2010 (expires in 1 day)
+ * Tue May 11 13:37:33 CEST 2010 (expires within 24h)
+ * Tue May 11 13:37:33 CEST 2010 (EXPIRED)
+ * \endcode
+ */
+ std::string expiresAsString() const;
+
+ /** Gpg-pubkey version as computed by rpm (trailing 8 byte \ref id) */
+ std::string gpgPubkeyVersion() const;
+
+ /** Gpg-pubkey release as computed by rpm (hexencoded \ref created) */
+ std::string gpgPubkeyRelease() const;
+
+ /** Simple string representation.
+ * Encodes \ref id, \ref gpgPubkeyRelease, \ref name and \ref fingerprint.
+ * \code
+ * [E3A5C360307E3D54-4be01a65] [SuSE Package Signing Key <build@suse.de>] [4E98E67519D98DC7362A5990E3A5C360307E3D54]
+ * \endcode
+ */
+ std::string asString() const;
+
+ private:
+ class Impl;
+ RWCOW_pointer<Impl> _pimpl;
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ /** \relates PublicKeyData Stream output */
+ inline std::ostream & operator<<( std::ostream & str, const PublicKeyData & obj )
+ { return str << obj.asString(); }
+
+ /** \relates PublicKeyData Detailed stream output */
+ std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj );
+
+ /** \relates PublicKeyData Equal based on fingerprint anf creation date. */
+ bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs );
+
+ /** \relates PublicKeyData NotEqual. */
+ inline bool operator!=( const PublicKeyData & lhs, const PublicKeyData & rhs )
+ { return !( lhs == rhs ); }
+
+ ///////////////////////////////////////////////////////////////////
+ /// \class PublicKeyScanner
+ /// \brief Scan abstract from 'gpg --with-colons' key listings.
+ /// Feed gpg output line by line into \ref scan. The collected \ref PublicKeyData
+ /// contain the keys data (fingerprint, uid,...) but not the key itself (ASCII
+ /// armored stored in a file).
+ /// \code
+ /// std::list<PublicKeyData> result;
+ /// {
+ /// PublicKeyScanner scanner;
+ /// for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
+ /// scanner.scan( line );
+ /// result.swap( scanner._keys );
+ /// }
+ /// \endcode
+ /// \relates PublicKeyData
+ ///////////////////////////////////////////////////////////////////
+ struct PublicKeyScanner
+ {
+ PublicKeyScanner();
+ ~PublicKeyScanner();
+
+ /** Feed gpg output line by line into \ref scan. */
+ void scan( std::string line_r );
+
+ /** Extracted keys. */
+ std::list<PublicKeyData> _keys;
+
+ private:
+ class Impl;
+ RW_pointer<Impl, rw_pointer::Scoped<Impl> > _pimpl;
+ };
+ ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/// \class PublicKey
- /// \brief Class representing one GPG Public Key.
- /// If a key file actually contains multiple keys, the last one
- /// is taken.
+ /// \brief Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
+ /// If you don't need the ASCII armored version of the key stored in
+ /// a tempfile, using \ref PublicKeyData might be sufficient.
///////////////////////////////////////////////////////////////////
class PublicKey
{
- friend std::ostream & operator<<( std::ostream & str, const PublicKey & obj );
-
public:
/** Implementation */
class Impl;
*
* \throws when data does not make a key
*/
- explicit
- PublicKey( const Pathname & file );
+ explicit PublicKey( const Pathname & keyFile_r );
/** Ctor reading the key from a \ref TmpFile.
*
*
* \throws when data does not make a key
*/
- explicit
- PublicKey( const filesystem::TmpFile & sharedfile );
+ explicit PublicKey( const filesystem::TmpFile & sharedFile_r );
~PublicKey();
- bool isValid() const
- { return ( ! id().empty() && ! fingerprint().empty() && !path().empty() ); }
-
- std::string asString() const;
- std::string id() const;
- std::string name() const;
- std::string fingerprint() const;
-
- /** Version rpm would assign to this key if imported into the rpm database.
- * Rpm uses the lowercased trailing 8 byte from \ref id as \c version, and the
- * creations dates lowercased hexadecimal representation as \c release.
- * \see \ref gpgPubkeyRelease
- * \code
- * [zypp OBS Project <zypp@build.opensuse.org>]
- * fpr 47D7CE1DD600935B3B90365733D38EBC7FB7F464
- * id 33D38EBC7FB7F464 <-- trailing 8 byte
- * cre Thu Mar 13 19:15:40 2008 <-- converted to hex
- * exp Sat May 22 20:15:40 2010
- * ]
- *
- * Converting the creation date to its hexadecimal representation:
- * $ bc <<<"obase=16;$(date -d 'Thu Mar 13 19:15:40 2008' +%s)"
- * 47D96F4C
- *
- * Rpms name for this key: gpg-pubkey-7fb7f464-47d96f4c
- * \endcode
- */
- std::string gpgPubkeyVersion() const;
-
- /** Release rpm would assign to this key if imported into the rpm database.
- * This is the creations dates hexadecimal representation as \c release lowercased.
- * \see \ref gpgPubkeyVersion
- */
- std::string gpgPubkeyRelease() const;
-
- /**
- * Date when the key was created.
- */
- Date created() const;
-
- /**
- * Date when the key expires.
- * If the key never expires the date is Date() (i.e. 0 seconds since the epoch (1.1.1970))
- */
- Date expires() const;
+ public:
+ /** The public keys data (\see \ref PublicKeyData).*/
+ const PublicKeyData & keyData() const;
- /**
- * Expiry info in a human readable form.
- * The exipry daye plus an annotation if the key has expired, or will
- * expire within 90 days.
- * \code
- * (does not expire)
- * Tue May 11 13:37:33 CEST 2010
- * Tue May 11 13:37:33 CEST 2010 (expires in 90 days)
- * Tue May 11 13:37:33 CEST 2010 (expires in 1 day)
- * Tue May 11 13:37:33 CEST 2010 (expires within 24h)
- * Tue May 11 13:37:33 CEST 2010 (EXPIRED)
- * \endcode
- */
- std::string expiresAsString() const;
+ bool isValid() const
+ { return ! ( id().empty() || fingerprint().empty() ); }
- /** Whether the key has expired. */
- bool expired() const;
+ std::string id() const; //!< \see \ref PublicKeyData
+ std::string name() const; //!< \see \ref PublicKeyData
+ std::string fingerprint() const; //!< \see \ref PublicKeyData
+ Date created() const; //!< \see \ref PublicKeyData
+ Date expires() const; //!< \see \ref PublicKeyData
+ std::string expiresAsString() const; //!< \see \ref PublicKeyData
+ bool expired() const; //!< \see \ref PublicKeyData
+ int daysToLive() const; //!< \see \ref PublicKeyData
+ std::string gpgPubkeyVersion() const; //!< \see \ref PublicKeyData
+ std::string gpgPubkeyRelease() const; //!< \see \ref PublicKeyData
+ std::string asString() const; //!< \see \ref PublicKeyData
- /** Number of days (24h) until the key expires (or since it exired).
- * A value of \c 0 means the key will expire within the next 24h.
- * Negative values indicate the key has expired less than \c N days ago.
- * For keys without expiration date \c INT_MAX is returned.
- */
- int daysToLive() const;
+ public:
+ /** File containig the ASCII armored key. */
Pathname path() const;
- bool operator==( PublicKey b ) const;
- bool operator==( std::string sid ) const;
+ public:
+ bool operator==( PublicKey rhs ) const; // FIXME: change arg to const&
+ bool operator==( std::string sid ) const; // FIXME: change arg to const&
+
+ private:
+ friend class KeyRing;
+ /** KeyRing ctor: No need to parse file if KeyRing already had valid KeyData. */
+ PublicKey( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r );
private:
/** Pointer to implementation */