Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F37954992
keyfiltermanager.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
15 KB
Subscribers
None
keyfiltermanager.cpp
View Options
/*
keyfiltermanager.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
<config-libkleo.h>
#include
"keyfiltermanager.h"
#include
"defaultkeyfilter.h"
#include
"kconfigbasedkeyfilter.h"
#include
"stl_util.h"
#include
<libkleo/algorithm.h>
#include
<libkleo/compliance.h>
#include
<libkleo/gnupg.h>
#include
<libkleo/keyhelpers.h>
#include
<libkleo_debug.h>
#include
<KConfig>
#include
<KConfigGroup>
#include
<KLocalizedString>
#include
<KSharedConfig>
#include
<QAbstractListModel>
#include
<QCoreApplication>
#include
<QIcon>
#include
<QModelIndex>
#include
<QRegularExpression>
#include
<QStringList>
#include
<algorithm>
#include
<climits>
#include
<functional>
using
namespace
Kleo
;
using
namespace
GpgME
;
namespace
{
class
Model
:
public
QAbstractListModel
{
KeyFilterManager
::
Private
*
m_keyFilterManagerPrivate
;
public
:
explicit
Model
(
KeyFilterManager
::
Private
*
p
)
:
QAbstractListModel
(
nullptr
)
,
m_keyFilterManagerPrivate
(
p
)
{
}
int
rowCount
(
const
QModelIndex
&
)
const
override
;
QVariant
data
(
const
QModelIndex
&
idx
,
int
role
)
const
override
;
/* upgrade to public */
using
QAbstractListModel
::
beginResetModel
;
/* upgrade to public */
using
QAbstractListModel
::
endResetModel
;
};
class
AllCertificatesKeyFilter
:
public
DefaultKeyFilter
{
public
:
AllCertificatesKeyFilter
()
:
DefaultKeyFilter
()
{
setSpecificity
(
UINT_MAX
);
// overly high for ordering
setName
(
i18nc
(
"All Certificates"
,
"All"
));
setDescription
(
i18n
(
"All certificates"
));
setId
(
QStringLiteral
(
"all-certificates"
));
setMatchContexts
(
Filtering
);
}
};
class
MyCertificatesKeyFilter
:
public
DefaultKeyFilter
{
public
:
MyCertificatesKeyFilter
()
:
DefaultKeyFilter
()
{
setHasSecret
(
Set
);
setSpecificity
(
UINT_MAX
-
2
);
// overly high for ordering
setName
(
i18nc
(
"My own Certificates"
,
"My Own"
));
setDescription
(
i18n
(
"My own certificates"
));
setId
(
QStringLiteral
(
"my-certificates"
));
setMatchContexts
(
AnyMatchContext
);
setBold
(
true
);
}
};
class
FullCertificatesKeyFilter
:
public
DefaultKeyFilter
{
public
:
FullCertificatesKeyFilter
()
:
DefaultKeyFilter
()
{
setRevoked
(
NotSet
);
setValidity
(
IsAtLeast
);
setValidityReferenceLevel
(
UserID
::
Full
);
setSpecificity
(
UINT_MAX
-
4
);
setName
(
i18nc
(
"Certified Certificates"
,
"Certified"
));
setDescription
(
i18n
(
"Certificates for which the primary user ID is certified"
));
setId
(
QStringLiteral
(
"trusted-certificates"
));
setMatchContexts
(
Filtering
);
}
};
class
OtherCertificatesKeyFilter
:
public
DefaultKeyFilter
{
public
:
OtherCertificatesKeyFilter
()
:
DefaultKeyFilter
()
{
setHasSecret
(
NotSet
);
setValidity
(
IsAtMost
);
setValidityReferenceLevel
(
UserID
::
Marginal
);
setSpecificity
(
UINT_MAX
-
6
);
// overly high for ordering
setName
(
i18nc
(
"Not Certified Certificates"
,
"Not Certified"
));
setDescription
(
i18n
(
"Certificates for which the primary user ID is not certified"
));
setId
(
QStringLiteral
(
"other-certificates"
));
setMatchContexts
(
Filtering
);
}
};
/* This filter selects uncertified OpenPGP keys, i.e. "good" OpenPGP keys with
* unrevoked user IDs that are not fully valid. */
class
UncertifiedOpenPGPKeysFilter
:
public
DefaultKeyFilter
{
public
:
UncertifiedOpenPGPKeysFilter
()
:
DefaultKeyFilter
()
{
setSpecificity
(
UINT_MAX
-
7
);
// overly high for ordering
setName
(
i18nc
(
"Certificates to certify by the user"
,
"To Certify"
));
setDescription
(
i18n
(
"Certificates that are not fully certified and that you may want to certify yourself"
));
setId
(
QStringLiteral
(
"not-certified-certificates"
));
setMatchContexts
(
Filtering
);
setIsOpenPGP
(
Set
);
setIsBad
(
NotSet
);
}
bool
matches
(
const
Key
&
key
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
key
,
contexts
)
&&
!
Kleo
::
allUserIDsHaveFullValidity
(
key
);
}
bool
matches
(
const
UserID
&
userID
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
userID
.
parent
(),
contexts
)
&&
userID
.
validity
()
<
UserID
::
Full
;
}
};
/* This filter selects only invalid keys (i.e. those where not all
* UIDs are at least fully valid). */
class
KeyNotValidFilter
:
public
DefaultKeyFilter
{
public
:
KeyNotValidFilter
()
:
DefaultKeyFilter
()
{
setSpecificity
(
UINT_MAX
-
5
);
// overly high for ordering
setName
(
i18nc
(
"Not Fully Certified Certificates"
,
"Not Fully Certified"
));
setDescription
(
i18n
(
"Certificates for which not all user IDs are certified"
));
setId
(
QStringLiteral
(
"not-validated-certificates"
));
setMatchContexts
(
Filtering
);
}
bool
matches
(
const
Key
&
key
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
key
,
contexts
)
&&
!
Kleo
::
allUserIDsHaveFullValidity
(
key
);
}
bool
matches
(
const
UserID
&
userID
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
userID
.
parent
(),
contexts
)
&&
userID
.
validity
()
<
UserID
::
Full
;
}
};
}
class
KeyFullyCertifiedFilter
:
public
DefaultKeyFilter
{
public
:
KeyFullyCertifiedFilter
()
:
DefaultKeyFilter
()
{
setSpecificity
(
UINT_MAX
-
3
);
setName
(
i18nc
(
"Fully Certified Certificates"
,
"Fully Certified"
));
setDescription
(
i18n
(
"Certificates for which all user IDs are certified"
));
setId
(
QStringLiteral
(
"full-certificates"
));
setMatchContexts
(
Filtering
);
}
bool
matches
(
const
Key
&
key
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
key
,
contexts
)
&&
Kleo
::
allUserIDsHaveFullValidity
(
key
);
}
bool
matches
(
const
UserID
&
userID
,
MatchContexts
contexts
)
const
override
{
return
DefaultKeyFilter
::
matches
(
userID
.
parent
(),
contexts
)
&&
userID
.
validity
()
>=
UserID
::
Full
;
}
};
static
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
defaultFilters
()
{
return
{
std
::
shared_ptr
<
KeyFilter
>
(
new
MyCertificatesKeyFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
FullCertificatesKeyFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
OtherCertificatesKeyFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
AllCertificatesKeyFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
UncertifiedOpenPGPKeysFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
KeyFullyCertifiedFilter
),
std
::
shared_ptr
<
KeyFilter
>
(
new
KeyNotValidFilter
),
};
}
class
KeyFilterManager
::
Private
{
public
:
Private
()
:
filters
()
,
model
(
this
)
{
}
void
clear
()
{
model
.
beginResetModel
();
filters
.
clear
();
model
.
endResetModel
();
}
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
filters
;
Model
model
;
GpgME
::
Protocol
protocol
=
GpgME
::
UnknownProtocol
;
};
KeyFilterManager
*
KeyFilterManager
::
mSelf
=
nullptr
;
KeyFilterManager
::
KeyFilterManager
(
QObject
*
parent
)
:
QObject
(
parent
)
,
d
(
new
Private
)
{
mSelf
=
this
;
// ### DF: doesn't a KStaticDeleter work more reliably?
if
(
QCoreApplication
*
app
=
QCoreApplication
::
instance
())
{
connect
(
app
,
&
QCoreApplication
::
aboutToQuit
,
this
,
&
QObject
::
deleteLater
);
}
reload
();
}
KeyFilterManager
::~
KeyFilterManager
()
{
mSelf
=
nullptr
;
if
(
d
)
{
d
->
clear
();
}
}
KeyFilterManager
*
KeyFilterManager
::
instance
()
{
if
(
!
mSelf
)
{
mSelf
=
new
KeyFilterManager
();
}
return
mSelf
;
}
void
KeyFilterManager
::
alwaysFilterByProtocol
(
GpgME
::
Protocol
protocol
)
{
if
(
protocol
!=
d
->
protocol
)
{
d
->
protocol
=
protocol
;
reload
();
}
}
const
std
::
shared_ptr
<
KeyFilter
>
&
KeyFilterManager
::
filterMatching
(
const
Key
&
key
,
KeyFilter
::
MatchContexts
contexts
)
const
{
const
auto
it
=
std
::
find_if
(
d
->
filters
.
cbegin
(),
d
->
filters
.
cend
(),
[
&
key
,
contexts
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
matches
(
key
,
contexts
);
});
if
(
it
!=
d
->
filters
.
cend
())
{
return
*
it
;
}
static
const
std
::
shared_ptr
<
KeyFilter
>
null
;
return
null
;
}
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
KeyFilterManager
::
filtersMatching
(
const
Key
&
key
,
KeyFilter
::
MatchContexts
contexts
)
const
{
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
result
;
result
.
reserve
(
d
->
filters
.
size
());
std
::
remove_copy_if
(
d
->
filters
.
begin
(),
d
->
filters
.
end
(),
std
::
back_inserter
(
result
),
[
&
key
,
contexts
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
!
filter
->
matches
(
key
,
contexts
);
});
return
result
;
}
namespace
{
static
const
auto
byDecreasingSpecificity
=
[](
const
std
::
shared_ptr
<
KeyFilter
>
&
lhs
,
const
std
::
shared_ptr
<
KeyFilter
>
&
rhs
)
{
return
lhs
->
specificity
()
>
rhs
->
specificity
();
};
}
void
KeyFilterManager
::
reload
()
{
d
->
clear
();
d
->
filters
=
defaultFilters
();
KSharedConfigPtr
config
=
KSharedConfig
::
openConfig
(
QStringLiteral
(
"libkleopatrarc"
));
const
QStringList
groups
=
config
->
groupList
().
filter
(
QRegularExpression
(
QStringLiteral
(
"^Key Filter #
\\
d+$"
)));
const
bool
ignoreDeVs
=
!
DeVSCompliance
::
isCompliant
();
for
(
QStringList
::
const_iterator
it
=
groups
.
begin
();
it
!=
groups
.
end
();
++
it
)
{
const
KConfigGroup
cfg
(
config
,
*
it
);
if
(
cfg
.
hasKey
(
"is-de-vs"
)
&&
ignoreDeVs
)
{
/* Don't show de-vs filters in other compliance modes */
continue
;
}
d
->
filters
.
push_back
(
std
::
shared_ptr
<
KeyFilter
>
(
new
KConfigBasedKeyFilter
(
cfg
)));
}
std
::
stable_sort
(
d
->
filters
.
begin
(),
d
->
filters
.
end
(),
byDecreasingSpecificity
);
if
(
d
->
protocol
!=
GpgME
::
UnknownProtocol
)
{
// remove filters with conflicting isOpenPGP rule
const
auto
conflictingValue
=
(
d
->
protocol
==
GpgME
::
OpenPGP
)
?
DefaultKeyFilter
::
NotSet
:
DefaultKeyFilter
::
Set
;
Kleo
::
erase_if
(
d
->
filters
,
[
conflictingValue
](
const
auto
&
f
)
{
const
auto
filter
=
std
::
dynamic_pointer_cast
<
DefaultKeyFilter
>
(
f
);
Q_ASSERT
(
filter
);
return
filter
->
isOpenPGP
()
==
conflictingValue
;
});
// add isOpenPGP rule to all filters
const
auto
isOpenPGPValue
=
(
d
->
protocol
==
GpgME
::
OpenPGP
)
?
DefaultKeyFilter
::
Set
:
DefaultKeyFilter
::
NotSet
;
std
::
for_each
(
std
::
begin
(
d
->
filters
),
std
::
end
(
d
->
filters
),
[
isOpenPGPValue
](
auto
&
f
)
{
const
auto
filter
=
std
::
dynamic_pointer_cast
<
DefaultKeyFilter
>
(
f
);
Q_ASSERT
(
filter
);
return
filter
->
setIsOpenPGP
(
isOpenPGPValue
);
});
}
qCDebug
(
LIBKLEO_LOG
)
<<
"KeyFilterManager::"
<<
__func__
<<
"final filter count is"
<<
d
->
filters
.
size
();
}
QAbstractItemModel
*
KeyFilterManager
::
model
()
const
{
return
&
d
->
model
;
}
const
std
::
shared_ptr
<
KeyFilter
>
&
KeyFilterManager
::
keyFilterByID
(
const
QString
&
id
)
const
{
const
auto
it
=
std
::
find_if
(
d
->
filters
.
begin
(),
d
->
filters
.
end
(),
[
id
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
id
()
==
id
;
});
if
(
it
!=
d
->
filters
.
end
())
{
return
*
it
;
}
static
const
std
::
shared_ptr
<
KeyFilter
>
null
;
return
null
;
}
const
std
::
shared_ptr
<
KeyFilter
>
&
KeyFilterManager
::
fromModelIndex
(
const
QModelIndex
&
idx
)
const
{
if
(
!
idx
.
isValid
()
||
idx
.
model
()
!=
&
d
->
model
||
idx
.
row
()
<
0
||
static_cast
<
unsigned
>
(
idx
.
row
())
>=
d
->
filters
.
size
())
{
static
const
std
::
shared_ptr
<
KeyFilter
>
null
;
return
null
;
}
return
d
->
filters
[
idx
.
row
()];
}
QModelIndex
KeyFilterManager
::
toModelIndex
(
const
std
::
shared_ptr
<
KeyFilter
>
&
kf
)
const
{
if
(
!
kf
)
{
return
{};
}
const
auto
pair
=
std
::
equal_range
(
d
->
filters
.
cbegin
(),
d
->
filters
.
cend
(),
kf
,
byDecreasingSpecificity
);
const
auto
it
=
std
::
find
(
pair
.
first
,
pair
.
second
,
kf
);
if
(
it
!=
pair
.
second
)
{
return
d
->
model
.
index
(
it
-
d
->
filters
.
begin
());
}
else
{
return
QModelIndex
();
}
}
int
Model
::
rowCount
(
const
QModelIndex
&
)
const
{
return
m_keyFilterManagerPrivate
->
filters
.
size
();
}
QVariant
Model
::
data
(
const
QModelIndex
&
idx
,
int
role
)
const
{
if
(
!
idx
.
isValid
()
||
idx
.
model
()
!=
this
||
idx
.
row
()
<
0
||
static_cast
<
unsigned
>
(
idx
.
row
())
>
m_keyFilterManagerPrivate
->
filters
.
size
())
{
return
QVariant
();
}
const
auto
filter
=
m_keyFilterManagerPrivate
->
filters
[
idx
.
row
()];
switch
(
role
)
{
case
Qt
::
DecorationRole
:
return
filter
->
icon
();
case
Qt
::
DisplayRole
:
case
Qt
::
EditRole
:
return
filter
->
name
();
case
Qt
::
ToolTipRole
:
return
filter
->
description
();
case
KeyFilterManager
::
FilterIdRole
:
return
filter
->
id
();
case
KeyFilterManager
::
FilterMatchContextsRole
:
return
QVariant
::
fromValue
(
filter
->
availableMatchContexts
());
default
:
return
QVariant
();
}
}
static
KeyFilter
::
FontDescription
get_fontdescription
(
const
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
&
filters
,
const
Key
&
key
,
const
KeyFilter
::
FontDescription
&
initial
)
{
return
kdtools
::
accumulate_if
(
filters
.
begin
(),
filters
.
end
(),
[
&
key
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
matches
(
key
,
KeyFilter
::
Appearance
);
},
initial
,
[](
const
KeyFilter
::
FontDescription
&
lhs
,
const
std
::
shared_ptr
<
KeyFilter
>
&
rhs
)
{
return
lhs
.
resolve
(
rhs
->
fontDescription
());
});
}
QFont
KeyFilterManager
::
font
(
const
Key
&
key
,
const
QFont
&
baseFont
)
const
{
const
KeyFilter
::
FontDescription
fd
=
get_fontdescription
(
d
->
filters
,
key
,
KeyFilter
::
FontDescription
());
return
fd
.
font
(
baseFont
);
}
static
QColor
get_color
(
const
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
&
filters
,
const
Key
&
key
,
QColor
(
KeyFilter
::*
fun
)()
const
)
{
const
auto
it
=
std
::
find_if
(
filters
.
cbegin
(),
filters
.
cend
(),
[
&
fun
,
&
key
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
matches
(
key
,
KeyFilter
::
Appearance
)
&&
(
filter
.
get
()
->*
fun
)().
isValid
();
});
if
(
it
==
filters
.
cend
())
{
return
{};
}
else
{
return
(
it
->
get
()
->*
fun
)();
}
}
static
QColor
get_color
(
const
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
&
filters
,
const
UserID
&
userID
,
QColor
(
KeyFilter
::*
fun
)()
const
)
{
const
auto
it
=
std
::
find_if
(
filters
.
cbegin
(),
filters
.
cend
(),
[
&
fun
,
&
userID
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
matches
(
userID
,
KeyFilter
::
Appearance
)
&&
(
filter
.
get
()
->*
fun
)().
isValid
();
});
if
(
it
==
filters
.
cend
())
{
return
{};
}
else
{
return
(
it
->
get
()
->*
fun
)();
}
}
static
QString
get_string
(
const
std
::
vector
<
std
::
shared_ptr
<
KeyFilter
>>
&
filters
,
const
Key
&
key
,
QString
(
KeyFilter
::*
fun
)()
const
)
{
const
auto
it
=
std
::
find_if
(
filters
.
cbegin
(),
filters
.
cend
(),
[
&
fun
,
&
key
](
const
std
::
shared_ptr
<
KeyFilter
>
&
filter
)
{
return
filter
->
matches
(
key
,
KeyFilter
::
Appearance
)
&&
!
(
filter
.
get
()
->*
fun
)().
isEmpty
();
});
if
(
it
==
filters
.
cend
())
{
return
QString
();
}
else
{
return
(
*
it
)
->
icon
();
}
}
QColor
KeyFilterManager
::
bgColor
(
const
Key
&
key
)
const
{
return
get_color
(
d
->
filters
,
key
,
&
KeyFilter
::
bgColor
);
}
QColor
KeyFilterManager
::
fgColor
(
const
Key
&
key
)
const
{
return
get_color
(
d
->
filters
,
key
,
&
KeyFilter
::
fgColor
);
}
QColor
KeyFilterManager
::
bgColor
(
const
UserID
&
userID
)
const
{
return
get_color
(
d
->
filters
,
userID
,
&
KeyFilter
::
bgColor
);
}
QColor
KeyFilterManager
::
fgColor
(
const
UserID
&
userID
)
const
{
return
get_color
(
d
->
filters
,
userID
,
&
KeyFilter
::
fgColor
);
}
QIcon
KeyFilterManager
::
icon
(
const
Key
&
key
)
const
{
const
QString
icon
=
get_string
(
d
->
filters
,
key
,
&
KeyFilter
::
icon
);
return
icon
.
isEmpty
()
?
QIcon
()
:
QIcon
::
fromTheme
(
icon
);
}
#include
"moc_keyfiltermanager.cpp"
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Thu, Mar 19, 6:06 PM (1 d, 15 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
6f/dc/7a69111f2ada5475caa333cf3b42
Attached To
rLIBKLEO Libkleo
Event Timeline
Log In to Comment