-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAshFileIntegrityPlugin.php
More file actions
266 lines (239 loc) · 8.54 KB
/
AshFileIntegrityPlugin.php
File metadata and controls
266 lines (239 loc) · 8.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<?php
/**
* @file plugins/generic/ashFileIntegrity/AshFileIntegrityPlugin.php
*
* Copyright (c) 2025 AshVisualTheme
* Copyright (c) 2014-2025 Simon Fraser University
* Copyright (c) 2003-2025 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class AshFileIntegrityPlugin
* @ingroup plugins_generic_ashFileIntegrity
*
* @brief Generic plugin to perform file integrity scanning (comparing local hashes with a baseline hash on GitHub).
*/
namespace APP\plugins\generic\ashFileIntegrity;
use PKP\plugins\GenericPlugin;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\linkAction\request\AjaxModal;
use PKP\plugins\Hook;
use PKP\core\JSONMessage;
use APP\plugins\generic\ashFileIntegrity\classes\AshFileIntegritySettingsForm;
use APP\core\Application;
use PKP\security\Role;
use Illuminate\Console\Scheduling\Schedule;
use APP\plugins\generic\ashFileIntegrity\classes\RunFileIntegrityScanCommand;
class AshFileIntegrityPlugin extends GenericPlugin
{
/**
* Registers the plugin with the system.
*
* @param string $category Plugin category.
* @param string $path Plugin path.
* @param int|null $mainContextId Main context ID.
* @return bool
*/
public function register($category, $path, $mainContextId = null)
{
$success = parent::register($category, $path, $mainContextId);
// Registers hooks only if the plugin is successfully registered and enabled.
if ($success && $this->getEnabled()) {
Hook::add('LoadHandler', [$this, 'callbackLoadHandler']);
Hook::add('Console::RegisterCommands', [$this, 'registerCommands']);
Hook::add('Console::Schedule', [$this, 'addSchedule']);
}
return $success;
}
/**
* Gets the display name of the plugin.
*
* @return string
*/
public function getDisplayName()
{
return __('plugins.generic.fileIntegrity.displayName');
}
/**
* Gets the description of the plugin.
*
* @return string
*/
public function getDescription()
{
return __('plugins.generic.fileIntegrity.description');
}
/**
* Site-wide plugins should override this function to return true.
*
* @return boolean
*/
function isSitePlugin()
{
return true;
}
/**
* Return if user can edit a plugin settings or not.
* @param $plugin Plugin
* @return boolean
*/
protected function _canEdit($plugin)
{
// Only site administrators can manage the settings for this site-wide plugin.
return in_array(Role::ROLE_ID_SITE_ADMIN, $this->_userRoles);
}
/**
* Gets LinkActions to display in the plugin grid.
*
* @param Request $request The request object.
* @param string $verb Action verb.
* @return array
*/
public function getActions($request, $verb)
{
$actions = parent::getActions($request, $verb);
// Always check against the site-wide context for this site-level plugin.
if (!$this->getEnabled(CONTEXT_SITE)) {
return $actions;
}
$router = $request->getRouter();
$actions[] = new LinkAction(
'settings',
new AjaxModal(
$router->url(
$request,
null,
null,
'manage',
null,
[
'verb' => 'settings',
'plugin' => $this->getName(),
'category' => 'generic'
]
),
$this->getDisplayName()
),
__('manager.plugins.settings'),
null
);
$dispatcher = $request->getDispatcher();
$csrfToken = $request->getSession()->token();
// Creates a LinkAction to run the file integrity scan.
$scanUrl = $dispatcher->url($request, ROUTE_PAGE, 'index', 'integrity', 'runScan', null, ['csrfToken' => $csrfToken]);
$actions[] = new LinkAction(
'runScan',
new RemoteActionConfirmationModal(
$request->getSession(),
__('plugins.generic.fileIntegrity.scan.run.description'),
__('plugins.generic.fileIntegrity.scan.run'),
$scanUrl,
'modal_confirm'
),
__('plugins.generic.fileIntegrity.scan.run'),
null
);
// Creates a LinkAction to clear the file integrity hash cache.
$clearCacheUrl = $dispatcher->url($request, ROUTE_PAGE, 'index', 'integrity', 'clearCache', null, ['csrfToken' => $csrfToken]);
$actions[] = new LinkAction(
'clearCache',
new RemoteActionConfirmationModal(
$request->getSession(),
__('plugins.generic.fileIntegrity.cache.clear.description'),
__('plugins.generic.fileIntegrity.cache.clear'),
$clearCacheUrl,
'modal_confirm'
),
__('plugins.generic.fileIntegrity.cache.clear'),
null
);
return $actions;
}
/**
* Callback for the LoadHandler hook. Loads the custom handler for integrity URLs.
*
* @param string $hookName Hook name.
* @param array $args Hook arguments, including page and operation.
* @return bool True if the handler was loaded successfully.
*/
public function callbackLoadHandler($hookName, $args)
{
$page = $args[0];
$op = $args[1];
// If the page is 'integrity' and the op is either 'runScan' or 'clearCache', load FileIntegrityHandler.
if ($page === 'integrity' && in_array($op, ['runScan', 'clearCache'])) {
$handlerPath = $this->getPluginPath() . '/AshFileIntegrityHandler.php';
if (file_exists($handlerPath)) {
require_once($handlerPath);
// Manual Dispatch: Instantiate and execute the handler directly to bypass Router issues
$handler = new AshFileIntegrityHandler();
$request = Application::get()->getRequest();
// Trigger lifecycle methods
$handler->initialize($request);
// Pass dummy args since we are handling auth internally in the method
$handler->authorize($request, $args, []);
// Execute the operation
$result = $handler->$op($args, $request);
// Output the JSON result and terminate OJS execution
echo $result->getString();
exit;
}
}
return false;
}
/**
* Performs plugin management actions (as displayed in the plugin grid).
*
* @param array $args Arguments passed to the manage function.
* @param Request $request The request object.
* @return string
*/
public function manage($args, $request)
{
switch ($request->getUserVar('verb')) {
case 'settings':
$form = new AshFileIntegritySettingsForm($this);
// Fetch the form the first time it loads, before
// the user has tried to save it
if (!$request->getUserVar('save')) {
$form->initData();
return new JSONMessage(true, $form->fetch($request));
}
// Validate and save the form data
$form->readInputData();
if ($form->validate()) {
$form->execute();
return new JSONMessage(true);
}
}
return parent::manage($args, $request);
}
/**
* Register the console commands.
*
* @param string $hookName
* @param array $args [array $commands]
*/
public function registerCommands($hookName, $args)
{
$commands = & $args[0];
$commands[] = new RunFileIntegrityScanCommand();
}
/**
* Add the schedule for the task.
*
* @param string $hookName
* @param array $args [Schedule $schedule]
*/
public function addSchedule($hookName, $args)
{
/** @var Schedule $schedule */
$schedule = $args[0];
$schedule->command('ash:scan-integrity')
->dailyAt('03:00') // Run daily at 3 AM
->withoutOverlapping();
}
}
if (!PKP_STRICT_MODE) {
class_alias('\APP\plugins\generic\ashFileIntegrity\AshFileIntegrityPlugin', '\AshFileIntegrityPlugin');
}