Терминальный проект КиберПлат [open source]
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

336 lines
9.8KB

  1. /* @file Реализация менеджера плагинов. */
  2. // Qt
  3. #include <Common/QtHeadersBegin.h>
  4. #include <QtCore/QCoreApplication>
  5. #include <QtCore/QDir>
  6. #include <QtCore/QFileInfo>
  7. #include <QtCore/QDirIterator>
  8. #include <QtConcurrent/QtConcurrentRun>
  9. #include <Common/QtHeadersEnd.h>
  10. #ifdef Q_OS_WIN
  11. #include <windows.h>
  12. #endif
  13. // Modules
  14. #include <SysUtils/ISysUtils.h>
  15. #include <WatchServiceClient/Constants.h>
  16. // Modules
  17. #include <Common/Version.h>
  18. // Plugin SDK
  19. #include <SDK/Plugins/IPluginFactory.h>
  20. #include <SDK/Plugins/PluginLoader.h>
  21. #include <SDK/Plugins/IExternalInterface.h>
  22. // Проект
  23. #include "System/SettingsConstants.h"
  24. #include "Services/ServiceNames.h"
  25. #include "Services/PluginService.h"
  26. #include "Services/EventService.h"
  27. namespace CPluginService
  28. {
  29. const QString CyberplatSignerName = "CYBERPLAT";
  30. }
  31. //------------------------------------------------------------------------------
  32. PluginService * PluginService::instance(IApplication * aApplication)
  33. {
  34. return static_cast<PluginService *>(aApplication->getCore()->getService(CServices::PluginService));
  35. }
  36. //------------------------------------------------------------------------------
  37. PluginService::PluginService(IApplication * aApplication)
  38. : ILogable("Plugins"),
  39. mPluginLoader(nullptr)
  40. {
  41. mApplication = aApplication;
  42. }
  43. //------------------------------------------------------------------------------
  44. PluginService::~PluginService()
  45. {
  46. }
  47. //------------------------------------------------------------------------------
  48. bool PluginService::initialize()
  49. {
  50. mPluginLoader = new SDK::Plugin::PluginLoader(this);
  51. mPluginLoader->addDirectory(mApplication->getPluginPath());
  52. mPluginLoader->addDirectory(mApplication->getUserPluginPath());
  53. // Запустим фоновую проверку плагинов на наличие цифровой подписи
  54. mPluginVerifierSynchronizer.addFuture(QtConcurrent::run(this, &PluginService::verifyPlugins));
  55. return true;
  56. }
  57. //------------------------------------------------------------------------------
  58. void PluginService::finishInitialize()
  59. {
  60. }
  61. //---------------------------------------------------------------------------
  62. bool PluginService::canShutdown()
  63. {
  64. return true;
  65. }
  66. //------------------------------------------------------------------------------
  67. #ifndef SM_SHUTTINGDOWN
  68. #define SM_SHUTTINGDOWN 0x2000
  69. #endif
  70. //------------------------------------------------------------------------------
  71. bool PluginService::shutdown()
  72. {
  73. // Не выгружаем библиотеки на выходе из ПО в процессе перезагрузки системы. #48972
  74. if (GetSystemMetrics(SM_SHUTTINGDOWN) == 0)
  75. {
  76. toLog(LogLevel::Debug, "Destroy plugins loader...");
  77. delete static_cast<SDK::Plugin::PluginLoader *>(mPluginLoader);
  78. }
  79. mPluginLoader = nullptr;
  80. toLog(LogLevel::Debug, "Plugin service shutdown OK.");
  81. return true;
  82. }
  83. //------------------------------------------------------------------------------
  84. QString PluginService::getName() const
  85. {
  86. return CServices::PluginService;
  87. }
  88. //------------------------------------------------------------------------------
  89. const QSet<QString> & PluginService::getRequiredServices() const
  90. {
  91. static QSet<QString> requiredResources;
  92. return requiredResources;
  93. }
  94. //------------------------------------------------------------------------------
  95. QVariantMap PluginService::getParameters() const
  96. {
  97. return QVariantMap();
  98. }
  99. //------------------------------------------------------------------------------
  100. void PluginService::resetParameters(const QSet<QString> & )
  101. {
  102. }
  103. //------------------------------------------------------------------------------
  104. QString PluginService::getState() const
  105. {
  106. QStringList result;
  107. if (mUnsignedPlugins.count())
  108. {
  109. result << QString("Unsigned : {%1}").arg(mUnsignedPlugins.join(";"));
  110. }
  111. QStringList signedKeys = mSignedPlugins.keys();
  112. signedKeys.removeDuplicates();
  113. foreach(QString signerName, signedKeys)
  114. {
  115. result << QString("Signed by %1 : {%2}").arg(signerName).arg(QStringList(mSignedPlugins.values(signerName)).join(";"));
  116. }
  117. return result.join(";");
  118. }
  119. //------------------------------------------------------------------------------
  120. SDK::Plugin::IPluginLoader * PluginService::getPluginLoader()
  121. {
  122. return mPluginLoader;
  123. }
  124. //------------------------------------------------------------------------------
  125. ILog * PluginService::getLog(const QString & aName) const
  126. {
  127. return aName.isEmpty() ? ILogable::getLog() : ILog::getInstance(aName);
  128. }
  129. //------------------------------------------------------------------------------
  130. QString PluginService::getVersion() const
  131. {
  132. return Cyberplat::getVersion();
  133. }
  134. //------------------------------------------------------------------------------
  135. QString PluginService::getDirectory() const
  136. {
  137. return mApplication->getWorkingDirectory();
  138. }
  139. //------------------------------------------------------------------------------
  140. QString PluginService::getDataDirectory() const
  141. {
  142. return mApplication->getUserDataPath();
  143. }
  144. //------------------------------------------------------------------------------
  145. QString PluginService::getLogsDirectory() const
  146. {
  147. return mApplication->getWorkingDirectory() + "/logs";
  148. }
  149. //------------------------------------------------------------------------------
  150. QString PluginService::getPluginDirectory() const
  151. {
  152. return mApplication->getPluginPath();
  153. }
  154. //------------------------------------------------------------------------------
  155. bool PluginService::canConfigurePlugin(const QString & /*aInstancePath*/) const
  156. {
  157. // Не используется.
  158. return false;
  159. }
  160. //------------------------------------------------------------------------------
  161. QVariantMap PluginService::getPluginConfiguration(const QString & /*aInstancePath*/) const
  162. {
  163. // Не используется.
  164. return QVariantMap();
  165. }
  166. //------------------------------------------------------------------------------
  167. bool PluginService::canSavePluginConfiguration(const QString & /*aInstancePath*/) const
  168. {
  169. // Не используется.
  170. return false;
  171. }
  172. //------------------------------------------------------------------------------
  173. bool PluginService::savePluginConfiguration(const QString & /*aInstancePath*/, const QVariantMap & /*aParamenters*/)
  174. {
  175. // Не используется.
  176. return false;
  177. }
  178. //------------------------------------------------------------------------------
  179. SDK::Plugin::IExternalInterface * PluginService::getInterface(const QString & aInterface)
  180. {
  181. if (aInterface == SDK::PaymentProcessor::CInterfaces::ICore)
  182. {
  183. return dynamic_cast<SDK::Plugin::IExternalInterface *>(mApplication->getCore());
  184. }
  185. throw SDK::PaymentProcessor::ServiceIsNotImplemented(aInterface);
  186. }
  187. //------------------------------------------------------------------------------
  188. void PluginService::verifyPlugins()
  189. {
  190. #ifdef Q_OS_WIN
  191. mSignedPlugins.clear();
  192. mUnsignedPlugins.clear();
  193. auto shortPath = [=](const QString & aFullPath) -> QString
  194. {
  195. // Удалим расширение
  196. QString result = aFullPath.left(aFullPath.length() - 4).toLower();
  197. // Удалим путь к плагину/экзешнику
  198. return result.contains(mApplication->getUserPluginPath().toLower()) ?
  199. result.mid(mApplication->getUserPluginPath().length()) + ".u":
  200. result.mid(QString(mApplication->getWorkingDirectory() + QDir::separator() + (result.contains("plugins") ? "plugins" : "")).length());
  201. };
  202. QStringList modules = mPluginLoader->getPluginPathList(QRegExp(".*"));
  203. // Добавим проверку исполняемых файлов
  204. QStringList exeModules = QStringList()
  205. << CWatchService::Modules::WatchService << CWatchService::Modules::PaymentProcessor
  206. << CWatchService::Modules::Updater << CWatchService::Modules::WatchServiceController;
  207. foreach(QString module, exeModules)
  208. {
  209. QString file = QString("%1%2%3.exe").arg(mApplication->getWorkingDirectory()).arg(QDir::separator()).arg(module);
  210. if (QFileInfo(file).exists())
  211. {
  212. modules.append(file);
  213. }
  214. }
  215. foreach(QString fullPath, modules)
  216. {
  217. QString plugin = QDir::toNativeSeparators(fullPath).split(QDir::separator()).last();
  218. qlonglong status = ISysUtils::verifyTrust(QDir::toNativeSeparators(fullPath));
  219. toLog(LogLevel::Normal, QString("Verifying %1...").arg(fullPath));
  220. if (status == ERROR_SUCCESS)
  221. {
  222. ISysUtils::SSignerInfo signer;
  223. bool result = ISysUtils::getSignerInfo(QDir::toNativeSeparators(fullPath), signer);
  224. if (result)
  225. {
  226. if (signer.name != CPluginService::CyberplatSignerName)
  227. {
  228. mSignedPlugins.insertMulti(signer.name, shortPath(fullPath));
  229. }
  230. toLog(LogLevel::Normal, QString("Signed. Subject name: %1").arg(signer.name));
  231. }
  232. else
  233. {
  234. toLog(LogLevel::Warning, QString("Signed. Subject name is unknown."));
  235. mUnsignedPlugins.append(shortPath(fullPath));
  236. }
  237. }
  238. else
  239. {
  240. toLog(LogLevel::Warning, QString("%1").arg(status == TRUST_E_NOSIGNATURE ?
  241. "No signature was present in the subject." :
  242. "Could not verify signer in the subject."));
  243. mUnsignedPlugins.append(shortPath(fullPath));
  244. }
  245. }
  246. try
  247. {
  248. auto * eventService = EventService::instance(mApplication);
  249. if (mUnsignedPlugins.count())
  250. {
  251. eventService->sendEvent(SDK::PaymentProcessor::Event(SDK::PaymentProcessor::EEventType::Warning, getName(),
  252. QString("Unsigned : {%1}").arg(mUnsignedPlugins.join(";"))));
  253. }
  254. QStringList signedKeys = mSignedPlugins.keys();
  255. signedKeys.removeDuplicates();
  256. foreach(QString signerName, signedKeys)
  257. {
  258. eventService->sendEvent(SDK::PaymentProcessor::Event(SDK::PaymentProcessor::EEventType::Warning, getName(),
  259. QString("Signed by %1 : {%2}").arg(signerName).arg(QStringList(mSignedPlugins.values(signerName)).join(";"))));
  260. }
  261. }
  262. catch (SDK::PaymentProcessor::ServiceIsNotImplemented & e)
  263. {
  264. toLog(LogLevel::Error, "Exception accured while verify plugins.");
  265. }
  266. #else
  267. #pragma warning "PluginService::verifyPlugins not implemented on this platfotm."
  268. #endif
  269. }
  270. //------------------------------------------------------------------------------