keepassxc
216 строк · 8.8 Кб
1/*
2* Copyright (C) 2019 Aetf <aetf@unlimitedcodeworks.xyz>
3* Copyright 2010, Michael Leupold <lemma@confuego.org>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 2 or (at your option)
8* version 3 of the License.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "fdosecrets/objects/Collection.h"
20#include "fdosecrets/objects/Item.h"
21#include "fdosecrets/objects/Prompt.h"
22#include "fdosecrets/objects/Service.h"
23#include "fdosecrets/objects/Session.h"
24
25#include <QDBusMetaType>
26
27namespace FdoSecrets
28{
29bool inherits(const QMetaObject* derived, const QMetaObject* base)
30{
31for (auto super = derived; super; super = super->superClass()) {
32if (super == base) {
33return true;
34}
35}
36return false;
37}
38
39template <typename T> void registerConverter(const QWeakPointer<DBusMgr>& weak)
40{
41// from parameter type to on-the-wire type
42QMetaType::registerConverter<T*, QDBusObjectPath>([](const T* obj) { return DBusMgr::objectPathSafe(obj); });
43QMetaType::registerConverter<QList<T*>, QList<QDBusObjectPath>>(
44[](const QList<T*> objs) { return DBusMgr::objectsToPath(objs); });
45
46// the opposite
47QMetaType::registerConverter<QDBusObjectPath, T*>([weak](const QDBusObjectPath& path) -> T* {
48if (auto dbus = weak.lock()) {
49return dbus->pathToObject<T>(path);
50}
51qDebug() << "No DBusMgr when looking up path" << path.path();
52return nullptr;
53});
54QMetaType::registerConverter<QList<QDBusObjectPath>, QList<T*>>([weak](const QList<QDBusObjectPath>& paths) {
55if (auto dbus = weak.lock()) {
56return dbus->pathsToObject<T>(paths);
57}
58qDebug() << "No DBusMgr when looking up paths";
59return QList<T*>{};
60});
61}
62
63void registerDBusTypes(const QSharedPointer<DBusMgr>& dbus)
64{
65// On the wire types:
66// - various primary types
67// - QDBusVariant
68// - wire::Secret
69// - wire::ObjectPathSecretMap
70// - QDBusObjectPath
71// - QList<QDBusObjectPath>
72
73// Parameter types:
74// - various primary types
75// - QVariant
76// - Secret
77// - ObjectSecretMap
78// - DBusObject* (and derived classes)
79// - QList<DBusObject*>
80
81// NOTE: when registering, in additional to the class' fully qualified name,
82// the partial-namespace/non-namespace name should also be registered as alias
83// otherwise all those usages in Q_INVOKABLE methods without FQN won't be included
84// in the meta type system.
85#define REG_METATYPE(type) \
86qRegisterMetaType<type>(); \
87qRegisterMetaType<type>(#type)
88
89// register on-the-wire types
90// Qt container types for builtin types don't need registration
91REG_METATYPE(wire::Secret);
92REG_METATYPE(wire::StringStringMap);
93REG_METATYPE(wire::ObjectPathSecretMap);
94
95qDBusRegisterMetaType<wire::Secret>();
96qDBusRegisterMetaType<wire::StringStringMap>();
97qDBusRegisterMetaType<wire::ObjectPathSecretMap>();
98
99// register parameter types
100REG_METATYPE(Secret);
101REG_METATYPE(StringStringMap);
102REG_METATYPE(ItemSecretMap);
103REG_METATYPE(DBusResult);
104REG_METATYPE(DBusClientPtr);
105
106#define REG_DBUS_OBJ(name) \
107REG_METATYPE(name*); \
108REG_METATYPE(QList<name*>)
109REG_DBUS_OBJ(DBusObject);
110REG_DBUS_OBJ(Service);
111REG_DBUS_OBJ(Collection);
112REG_DBUS_OBJ(Item);
113REG_DBUS_OBJ(Session);
114REG_DBUS_OBJ(PromptBase);
115#undef REG_DBUS_OBJ
116
117#undef REG_METATYPE
118
119QWeakPointer<DBusMgr> weak = dbus;
120// register converter between on-the-wire types and parameter types
121// some pairs are missing because that particular direction isn't used
122registerConverter<DBusObject>(weak);
123registerConverter<Service>(weak);
124registerConverter<Collection>(weak);
125registerConverter<Item>(weak);
126registerConverter<Session>(weak);
127registerConverter<PromptBase>(weak);
128
129QMetaType::registerConverter<wire::Secret, Secret>(
130[weak](const wire::Secret& from) { return from.unmarshal(weak); });
131QMetaType::registerConverter(&Secret::marshal);
132
133QMetaType::registerConverter<ItemSecretMap, wire::ObjectPathSecretMap>([](const ItemSecretMap& map) {
134wire::ObjectPathSecretMap ret;
135for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
136ret.insert(it.key()->objectPath(), it.value().marshal());
137}
138return ret;
139});
140
141QMetaType::registerConverter<QDBusVariant, QVariant>([](const QDBusVariant& obj) { return obj.variant(); });
142QMetaType::registerConverter<QVariant, QDBusVariant>([](const QVariant& obj) { return QDBusVariant(obj); });
143
144// structural types are received as QDBusArgument,
145// top level QDBusArgument in method parameters are directly handled
146// in prepareInputParams.
147// But in Collection::createItem, we need to convert a inner QDBusArgument to StringStringMap
148QMetaType::registerConverter<QDBusArgument, StringStringMap>([](const QDBusArgument& arg) {
149if (arg.currentSignature() != "a{ss}") {
150return StringStringMap{};
151}
152// QDBusArgument is COW and qdbus_cast modifies it by detaching even it is const.
153// we don't want to modify the instance (arg) stored in the qvariant so we create a copy
154const auto copy = arg; // NOLINT(performance-unnecessary-copy-initialization)
155return qdbus_cast<StringStringMap>(copy);
156});
157}
158
159ParamData typeToWireType(int id)
160{
161switch (id) {
162case QMetaType::QString:
163return {QByteArrayLiteral("s"), QMetaType::QString};
164case QMetaType::QVariant:
165return {QByteArrayLiteral("v"), qMetaTypeId<QDBusVariant>()};
166case QMetaType::QVariantMap:
167return {QByteArrayLiteral("a{sv}"), QMetaType::QVariantMap};
168case QMetaType::Bool:
169return {QByteArrayLiteral("b"), QMetaType::Bool};
170case QMetaType::ULongLong:
171return {QByteArrayLiteral("t"), QMetaType::ULongLong};
172default:
173break;
174}
175if (id == qMetaTypeId<StringStringMap>()) {
176return {QByteArrayLiteral("a{ss}"), qMetaTypeId<wire::StringStringMap>()};
177} else if (id == qMetaTypeId<ItemSecretMap>()) {
178return {QByteArrayLiteral("a{o(oayays)}"), qMetaTypeId<wire::ObjectPathSecretMap>()};
179} else if (id == qMetaTypeId<Secret>()) {
180return {QByteArrayLiteral("(oayays)"), qMetaTypeId<wire::Secret>()};
181} else if (id == qMetaTypeId<DBusObject*>()) {
182return {QByteArrayLiteral("o"), qMetaTypeId<QDBusObjectPath>()};
183} else if (id == qMetaTypeId<QList<DBusObject*>>()) {
184return {QByteArrayLiteral("ao"), qMetaTypeId<QList<QDBusObjectPath>>()};
185}
186
187QMetaType mt(id);
188if (!mt.isValid()) {
189return {};
190}
191if (QByteArray(QMetaType::typeName(id)).startsWith("QList")) {
192// QList<Object*>
193return {QByteArrayLiteral("ao"), qMetaTypeId<QList<QDBusObjectPath>>()};
194}
195if (!inherits(mt.metaObject(), &DBusObject::staticMetaObject)) {
196return {};
197}
198// DBusObjects
199return {QByteArrayLiteral("o"), qMetaTypeId<QDBusObjectPath>()};
200}
201
202::FdoSecrets::Secret wire::Secret::unmarshal(const QWeakPointer<DBusMgr>& weak) const
203{
204if (auto dbus = weak.lock()) {
205return {dbus->pathToObject<Session>(session), parameters, value, contentType};
206}
207qDebug() << "No DBusMgr when converting wire::Secret";
208return {nullptr, parameters, value, contentType};
209}
210
211wire::Secret Secret::marshal() const
212{
213return {DBusMgr::objectPathSafe(session), parameters, value, contentType};
214}
215
216} // namespace FdoSecrets
217