]> git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/SACustom.pm
add SACustom Package and API Calls for custom SpamAssassin scores
[pmg-api.git] / src / PMG / API2 / SACustom.pm
1 package PMG::API2::SACustom;
2
3 use strict;
4 use warnings;
5
6 use PVE::SafeSyslog;
7 use PVE::JSONSchema qw(get_standard_option);
8 use PVE::RESTHandler;
9 use PVE::INotify;
10 use PVE::Tools qw(extract_param);
11 use PVE::Exception qw(raise_param_exc);
12
13 use PMG::RESTEnvironment;
14 use PMG::Utils;
15 use PMG::SACustom;
16
17 use base qw(PVE::RESTHandler);
18
19 my $score_properties = {
20 name => {
21 type => 'string',
22 description => "The name of the rule.",
23 pattern => '[a-zA-Z\_\-\.0-9]+',
24 },
25 score => {
26 type => 'number',
27 description => "The score the rule should be valued at.",
28 },
29 comment => {
30 type => 'string',
31 description => 'The Comment.',
32 optional => 1,
33 },
34 };
35
36 sub json_config_properties {
37 my ($props, $optional) = @_;
38
39 foreach my $opt (keys %$score_properties) {
40 # copy values and not the references
41 foreach my $prop (keys %{$score_properties->{$opt}}) {
42 $props->{$opt}->{$prop} = $score_properties->{$opt}->{$prop};
43 }
44 if ($optional->{$opt}) {
45 $props->{$opt}->{optional} = 1;
46 }
47 }
48
49 return $props;
50 }
51
52 __PACKAGE__->register_method({
53 name => 'list_scores',
54 path => '',
55 method => 'GET',
56 description => "List custom scores.",
57 # protected => 1,
58 permissions => { check => [ 'admin', 'audit' ] },
59 proxyto => 'master',
60 parameters => {
61 additionalProperties => 0,
62 properties => { },
63 },
64 returns => {
65 type => 'array',
66 items => {
67 type => 'object',
68 properties => json_config_properties({
69 digest => get_standard_option('pve-config-digest'),
70 },
71 {
72 # mark all properties optional, so that we can have
73 # one entry with only digest, and all others without digest
74 name => 1,
75 score => 1,
76 comment => 1,
77 }),
78 },
79 links => [ { rel => 'child', href => "{name}" } ],
80 },
81 code => sub {
82 my ($param) = @_;
83
84 my $restenv = PMG::RESTEnvironment->get();
85
86 my $tmp = PVE::INotify::read_file('pmg-scores.cf', 1);
87
88 my $changes = $tmp->{changes};
89 $restenv->set_result_attrib('changes', $changes) if $changes;
90
91 my $res = [];
92
93 for my $rule (sort keys %{$tmp->{data}}) {
94 push @$res, $tmp->{data}->{$rule};
95 }
96
97 my $digest = PMG::SACustom::calc_digest($tmp->{data});
98
99 push @$res, {
100 digest => $digest,
101 };
102
103 return $res;
104 }});
105
106 __PACKAGE__->register_method({
107 name => 'apply_score_changes',
108 path => '',
109 method => 'PUT',
110 protected => 1,
111 description => "Apply custom score changes.",
112 proxyto => 'master',
113 permissions => { check => [ 'admin' ] },
114 parameters => {
115 additionalProperties => 0,
116 properties => {
117 'restart-daemon' => {
118 type => 'boolean',
119 description => 'If set, also restarts pmg-smtp-filter. '.
120 'This is necessary for the changes to work.',
121 default => 0,
122 optional => 1,
123 },
124 digest => get_standard_option('pve-config-digest'),
125 },
126 },
127 returns => { type => "string" },
128 code => sub {
129 my ($param) = @_;
130
131 my $restenv = PMG::RESTEnvironment->get();
132
133 my $user = $restenv->get_user();
134
135 my $config = PVE::INotify::read_file('pmg-scores.cf');
136
137 my $digest = PMG::SACustom::calc_digest($config);
138 PVE::Tools::assert_if_modified($digest, $param->{digest})
139 if $param->{digest};
140
141 my $realcmd = sub {
142 my $upid = shift;
143
144 PMG::SACustom::apply_changes();
145 if ($param->{'restart-daemon'}) {
146 syslog('info', "re-starting service pmg-smtp-filter: $upid\n");
147 PMG::Utils::service_cmd('pmg-smtp-filter', 'restart');
148 }
149 };
150
151 return $restenv->fork_worker('applycustomscores', undef, $user, $realcmd);
152 }});
153
154 __PACKAGE__->register_method({
155 name => 'revert_score_changes',
156 path => '',
157 method => 'DELETE',
158 protected => 1,
159 description => "Revert custom score changes.",
160 proxyto => 'master',
161 permissions => { check => [ 'admin' ] },
162 parameters => {
163 additionalProperties => 0,
164 properties => { },
165 },
166 returns => { type => "null" },
167 code => sub {
168 my ($param) = @_;
169
170 unlink PMG::SACustom::get_shadow_path();
171
172 return undef;
173 }});
174
175
176 __PACKAGE__->register_method({
177 name => 'create_score',
178 path => '',
179 method => 'POST',
180 description => "Create custom SpamAssassin score",
181 protected => 1,
182 proxyto => 'master',
183 parameters => {
184 additionalProperties => 0,
185 properties => json_config_properties({
186 digest => get_standard_option('pve-config-digest'),
187 }),
188 },
189 returns => { type => 'null' },
190 code => sub {
191 my ($param) = @_;
192
193 my $name = extract_param($param, 'name');
194 my $score = extract_param($param, 'score');
195 my $comment = extract_param($param, 'comment');
196
197 my $code = sub {
198 my $config = PVE::INotify::read_file('pmg-scores.cf');
199
200 my $digest = PMG::SACustom::calc_digest($config);
201 PVE::Tools::assert_if_modified($digest, $param->{digest})
202 if $param->{digest};
203
204 $config->{$name} = {
205 name => $name,
206 score => $score,
207 comment => $comment,
208 };
209
210 PVE::INotify::write_file('pmg-scores.cf', $config);
211 };
212
213 PVE::Tools::lock_file("/var/lock/pmg-scores.cf.lck", 10, $code);
214 die $@ if $@;
215
216 return undef;
217 }});
218
219 __PACKAGE__->register_method({
220 name => 'get_score',
221 path => '{name}',
222 method => 'GET',
223 description => "Get custom SpamAssassin score",
224 protected => 1,
225 proxyto => 'master',
226 parameters => {
227 additionalProperties => 0,
228 properties => {
229 name => {
230 type => 'string',
231 description => "The name of the rule.",
232 pattern => '[a-zA-Z\_\-\.0-9]+',
233 },
234 },
235 },
236 returns => {
237 type => 'object',
238 properties => json_config_properties(),
239 },
240 code => sub {
241 my ($param) = @_;
242
243 my $name = extract_param($param, 'name');
244 my $config = PVE::INotify::read_file('pmg-scores.cf');
245
246 raise_param_exc({ name => "$name not found" })
247 if !$config->{$name};
248
249 return $config->{$name};
250 }});
251
252 __PACKAGE__->register_method({
253 name => 'edit_score',
254 path => '{name}',
255 method => 'PUT',
256 description => "Edit custom SpamAssassin score",
257 protected => 1,
258 proxyto => 'master',
259 parameters => {
260 additionalProperties => 0,
261 properties => json_config_properties({
262 digest => get_standard_option('pve-config-digest'),
263 }),
264 },
265 returns => { type => 'null' },
266 code => sub {
267 my ($param) = @_;
268
269 my $name = extract_param($param, 'name');
270 my $score = extract_param($param, 'score');
271 my $comment = extract_param($param, 'comment');
272
273 my $code = sub {
274 my $config = PVE::INotify::read_file('pmg-scores.cf');
275
276 my $digest = PMG::SACustom::calc_digest($config);
277 PVE::Tools::assert_if_modified($digest, $param->{digest})
278 if $param->{digest};
279
280 $config->{$name} = {
281 name => $name,
282 score => $score,
283 comment => $comment,
284 };
285
286 PVE::INotify::write_file('pmg-scores.cf', $config);
287 };
288
289 PVE::Tools::lock_file("/var/lock/pmg-scores.cf.lck", 10, $code);
290 die $@ if $@;
291
292 return undef;
293 }});
294
295 __PACKAGE__->register_method({
296 name => 'delete_score',
297 path => '{name}',
298 method => 'DELETE',
299 description => "Edit custom SpamAssassin score",
300 protected => 1,
301 proxyto => 'master',
302 parameters => {
303 additionalProperties => 0,
304 properties => {
305 name => {
306 type => 'string',
307 description => "The name of the rule.",
308 pattern => '[a-zA-Z\_\-\.0-9]+',
309 },
310 digest => get_standard_option('pve-config-digest'),
311 },
312 },
313 returns => { type => 'null' },
314 code => sub {
315 my ($param) = @_;
316
317 my $name = extract_param($param, 'name');
318
319 my $code = sub {
320 my $config = PVE::INotify::read_file('pmg-scores.cf');
321
322 my $digest = PMG::SACustom::calc_digest($config);
323 PVE::Tools::assert_if_modified($digest, $param->{digest})
324 if $param->{digest};
325
326 delete $config->{$name};
327
328 PVE::INotify::write_file('pmg-scores.cf', $config);
329 };
330
331 PVE::Tools::lock_file("/var/lock/pmg-scores.cf.lck", 10, $code);
332 die $@ if $@;
333
334 return undef;
335 }});
336
337 1;