]>
git.proxmox.com Git - pmg-api.git/blob - PMG/API2/Quarantine.pm
1 package PMG
:: API2
:: Quarantine
;
13 use PVE
:: Exception
qw(raise_param_exc raise_perm_exc) ;
14 use PVE
:: Tools
qw(extract_param) ;
15 use PVE
:: JSONSchema
qw(get_standard_option) ;
18 use PVE
:: APIServer
:: Formatter
;
21 use PMG
:: AccessControl
;
26 use base
qw(PVE::RESTHandler) ;
30 my $verify_optional_pmail = sub {
31 my ( $authuser, $role, $pmail ) = @_ ;
33 if ( $role eq 'quser' ) {
34 raise_param_exc
({ pmail
=> "paramater not allwed with role ' $role '" })
38 raise_param_exc
({ pmail
=> "paramater required with role ' $role '" })
47 $spamdesc = PMG
:: Utils
:: load_sa_descriptions
() if ! $spamdesc ;
51 foreach my $test ( split ( ',' , $info )) {
52 my ( $name, $score ) = split ( ':' , $test );
54 my $info = { name
=> $name, score
=> $score, desc
=> '-' };
55 if ( my $si = $spamdesc ->{ $name }) {
56 $info ->{ desc
} = $si ->{ desc
};
57 $info ->{ url
} = $si ->{ url
} if defined ( $si ->{ url
});
65 my $extract_email = sub {
68 return $data if ! $data ;
70 if ( $data =~ m/^.*\s(\S+)\s*$/ ) {
74 if ( $data =~ m/^<([^<>\s]+)>$/ ) {
78 if ( $data !~ m/[\s><]/ && $data =~ m/^(.+\@[^\.]+\..*[^\.]+)$/ ) {
87 my $get_real_sender = sub {
90 my @lines = split ( ' \n ' , $ref ->{ header
});
91 my $head = Mail
:: Header-
> new ( \
@lines );
93 my @fromarray = split ( '\s*,\s*' , $head -> get ( 'from' ) || $ref ->{ sender
});
94 my $from = $extract_email ->( $fromarray [ 0 ]) || $ref ->{ sender
};;
95 my $sender = $extract_email ->( $head -> get ( 'sender' ));
97 return $sender if $sender ;
102 my $parse_header_info = sub {
105 my $res = { subject
=> '' , from
=> '' };
107 my @lines = split ( ' \n ' , $ref ->{ header
});
108 my $head = Mail
:: Header-
> new ( \
@lines );
110 $res ->{ subject
} = PMG
:: Utils
:: decode_rfc1522
( PVE
:: Tools
:: trim
( $head -> get ( 'subject' ))) // '' ;
112 my @fromarray = split ( '\s*,\s*' , $head -> get ( 'from' ) || $ref ->{ sender
});
114 $res ->{ from
} = PMG
:: Utils
:: decode_rfc1522
( PVE
:: Tools
:: trim
( $fromarray [ 0 ])) // '' ;
116 my $sender = PMG
:: Utils
:: decode_rfc1522
( PVE
:: Tools
:: trim
( $head -> get ( 'sender' )));
117 $res ->{ sender
} = $sender if $sender && ( $sender ne $res ->{ from
});
119 $res ->{ envelope_sender
} = $ref ->{ sender
};
120 $res ->{ receiver
} = $ref ->{ receiver
};
121 $res ->{ id
} = 'C' . $ref ->{ cid
} . 'R' . $ref ->{ rid
};
122 $res ->{ time } = $ref ->{ time };
123 $res ->{ bytes
} = $ref ->{ bytes
};
125 my $qtype = $ref ->{ qtype
};
128 $res ->{ virusname
} = $ref ->{ info
};
129 } elsif ( $qtype eq 'S' ) {
130 $res ->{ spamlevel
} = $ref ->{ spamlevel
} // 0 ;
136 my $pmail_param_type = {
137 description
=> "List entries for the user with this primary email address. Quarantine users cannot speficy this parameter, but it is required for all other roles." ,
138 type
=> 'string' , format
=> 'email' ,
142 __PACKAGE__-
> register_method ({
146 permissions
=> { user
=> 'all' },
147 description
=> "Directory index." ,
149 additionalProperties
=> 0 ,
158 links
=> [ { rel
=> 'child' , href
=> "{name}" } ],
164 { name
=> 'whitelist' },
165 { name
=> 'blacklist' },
166 { name
=> 'content' },
175 my $read_user_bw_list = sub {
176 my ( $listname, $param ) = @_ ;
178 my $rpcenv = PMG
:: RESTEnvironment-
> get ();
179 my $authuser = $rpcenv -> get_user ();
180 my $role = $rpcenv -> get_role ();
182 my $pmail = $verify_optional_pmail ->( $authuser, $role, $param ->{ pmail
});
184 my $dbh = PMG
:: DBTools
:: open_ruledb
();
186 my $list = PMG
:: DBTools
:: add_to_blackwhite
( $dbh, $pmail, $listname );
189 foreach my $a ( @$list ) { push @$res, { address
=> $a }; }
193 __PACKAGE__-
> register_method ({
197 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'audit' , 'quser' ] },
198 description
=> "Show user whitelist." ,
200 additionalProperties
=> 0 ,
202 pmail
=> $pmail_param_type,
219 return $read_user_bw_list ->( 'WL' , $param );
222 __PACKAGE__-
> register_method ({
226 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'audit' , 'quser' ] },
227 description
=> "Show user blacklist." ,
229 additionalProperties
=> 0 ,
231 pmail
=> $pmail_param_type,
248 return $read_user_bw_list ->( 'BL' , $param );
251 __PACKAGE__-
> register_method ({
255 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'audit' , 'quser' ] },
256 description
=> "Show spam mails distribution (per day)." ,
258 additionalProperties
=> 0 ,
261 description
=> "Only consider entries newer than 'startime' (unix epoch)." ,
267 description
=> "Only consider entries older than 'endtime' (unix epoch)." ,
272 pmail
=> $pmail_param_type,
281 description
=> "Day (as unix epoch)." ,
285 description
=> "Number of quarantine entries." ,
289 description
=> "Average spam level." ,
294 links
=> [ { rel
=> 'child' , href
=> "{day}" } ],
299 my $rpcenv = PMG
:: RESTEnvironment-
> get ();
300 my $authuser = $rpcenv -> get_user ();
301 my $role = $rpcenv -> get_role ();
303 my $pmail = $verify_optional_pmail ->( $authuser, $role, $param ->{ pmail
});
307 my $dbh = PMG
:: DBTools
:: open_ruledb
();
309 my $start = $param ->{ starttime
};
310 my $end = $param ->{ endtime
};
312 my $timezone = tz_local_offset
();
314 my $sth = $dbh -> prepare (
316 "((time + $timezone ) / 86400) * 86400 - $timezone as day, " .
317 "count (ID) as count, avg (Spamlevel) as spamavg " .
318 "FROM CMailStore, CMSReceivers WHERE " .
319 ( defined ( $start ) ?
"time >= $start AND " : '' ) .
320 ( defined ( $end ) ?
"time < $end AND " : '' ) .
322 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
323 "AND Status = 'N' " .
325 "ORDER BY day DESC" );
327 $sth -> execute ( $pmail );
329 while ( my $ref = $sth -> fetchrow_hashref ()) {
336 __PACKAGE__-
> register_method ({
338 path
=> 'spam/{starttime}' ,
340 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'audit' , 'quser' ] },
341 description
=> "Show spam mails distribution (per day)." ,
343 additionalProperties
=> 0 ,
346 description
=> "Only consider entries newer than 'starttime' (unix epoch)." ,
351 description
=> "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default." ,
356 pmail
=> $pmail_param_type,
365 description
=> 'Unique ID' ,
369 description
=> "Size of raw email." ,
373 description
=> "SMTP envelope sender." ,
377 description
=> "Header 'From' field." ,
381 description
=> "Header 'Sender' field." ,
386 description
=> "Receiver email address" ,
390 description
=> "Header 'Subject' field." ,
394 description
=> "Receive time stamp" ,
398 description
=> "Spam score." ,
407 my $rpcenv = PMG
:: RESTEnvironment-
> get ();
408 my $authuser = $rpcenv -> get_user ();
409 my $role = $rpcenv -> get_role ();
411 my $pmail = $verify_optional_pmail ->( $authuser, $role, $param ->{ pmail
});
415 my $dbh = PMG
:: DBTools
:: open_ruledb
();
417 my $start = $param ->{ starttime
};
418 my $end = $param ->{ endtime
} // ( $start + 86400 );
420 my $sth = $dbh -> prepare (
422 "FROM CMailStore, CMSReceivers WHERE " .
423 "pmail = ? AND time >= $start AND time < $end AND " .
424 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
425 "AND Status = 'N' ORDER BY pmail, time, receiver" );
427 $sth -> execute ( $pmail );
429 while ( my $ref = $sth -> fetchrow_hashref ()) {
430 my $data = $parse_header_info ->( $ref );
437 __PACKAGE__-
> register_method ({
441 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'audit' , 'quser' ] },
442 description
=> "Get email data. There is a special formatter called 'htmlmail' to get sanitized html view of the mail content (use the '/api2/htmlmail/quarantine/content' url)." ,
444 additionalProperties
=> 0 ,
447 description
=> 'Unique ID' ,
449 pattern
=> 'C\d+R\d+' ,
453 description
=> "Display 'raw' eml data. This is only used with the 'htmlmail' formatter." ,
464 description
=> 'Unique ID' ,
468 description
=> "Size of raw email." ,
472 description
=> "SMTP envelope sender." ,
476 description
=> "Header 'From' field." ,
480 description
=> "Header 'Sender' field." ,
485 description
=> "Receiver email address" ,
489 description
=> "Header 'Subject' field." ,
493 description
=> "Receive time stamp" ,
497 description
=> "Spam score." ,
501 description
=> "Information about matched spam tests (name, score, desc, url)." ,
505 description
=> "Raw email header data." ,
509 description
=> "Raw email data (first 4096 bytes). Useful for preview. NOTE: The 'htmlmail' formatter displays the whole email." ,
517 my $rpcenv = PMG
:: RESTEnvironment-
> get ();
518 my $authuser = $rpcenv -> get_user ();
519 my $role = $rpcenv -> get_role ();
520 my $format = $rpcenv -> get_format ();
522 my ( $cid, $rid ) = $param ->{ id
} =~ m/^C(\d+)R(\d+)$/ ;
526 my $dbh = PMG
:: DBTools
:: open_ruledb
();
528 my $ref = PMG
:: DBTools
:: load_mail_data
( $dbh, $cid, $rid );
530 if ( $role eq 'quser' ) {
531 raise_perm_exc
( "mail does not belong to user ' $authuser '" )
532 if $authuser ne $ref ->{ pmail
};
535 my $res = $parse_header_info ->( $ref );
538 my $filename = $ref ->{ file
};
539 my $spooldir = $PMG :: MailQueue
:: spooldir
;
541 my $path = " $spooldir/$filename " ;
543 if ( $format eq 'htmlmail' ) {
545 my $cfg = PMG
:: Config-
> new ();
546 my $viewimages = $cfg -> get ( 'spamquar' , 'viewimages' );
547 my $allowhref = $cfg -> get ( 'spamquar' , 'allowhrefs' );
549 $res ->{ content
} = PMG
:: HTMLMail
:: email_to_html
( $path, $param ->{ raw
}, $viewimages, $allowhref );
551 # to make result verification happy
554 $res ->{ spaminfo
} = [];
556 # include additional details
558 my ( $header, $content ) = PMG
:: HTMLMail
:: read_raw_email
( $path, 4096 );
560 $res ->{ file
} = $ref ->{ file
};
561 $res ->{ spaminfo
} = decode_spaminfo
( $ref ->{ info
});
562 $res ->{ header
} = $header ;
563 $res ->{ content
} = $content ;
571 PVE
:: APIServer
:: Formatter
:: register_page_formatter
(
572 'format' => 'htmlmail' ,
574 path
=> '/quarantine/content' ,
576 my ( $res, $data, $param, $path, $auth, $config ) = @_ ;
578 if (! HTTP
:: Status
:: is_success
( $res ->{ status
})) {
579 return ( "Error $res ->{status}: $res ->{message}" , "text/plain" );
582 my $ct = "text/html;charset=UTF-8" ;
584 my $raw = $data ->{ content
};
586 return ( encode
( 'UTF-8' , $raw ), $ct, 1 );
589 __PACKAGE__-
> register_method ({
593 description
=> "Execute quarantine actions." ,
594 permissions
=> { check
=> [ 'admin' , 'qmanager' , 'quser' ] },
597 additionalProperties
=> 0 ,
600 description
=> 'Unique ID' ,
602 pattern
=> 'C\d+R\d+' ,
606 description
=> 'Action - specify what you want to do with the mail.' ,
608 enum
=> [ 'whitelist' , 'blacklist' , 'deliver' , 'delete' ],
612 returns
=> { type
=> "null" },
616 my $rpcenv = PMG
:: RESTEnvironment-
> get ();
617 my $authuser = $rpcenv -> get_user ();
618 my $role = $rpcenv -> get_role ();
619 my $action = $param ->{ action
};
621 my ( $cid, $rid ) = $param ->{ id
} =~ m/^C(\d+)R(\d+)$/ ;
625 my $dbh = PMG
:: DBTools
:: open_ruledb
();
627 my $ref = PMG
:: DBTools
:: load_mail_data
( $dbh, $cid, $rid );
629 if ( $role eq 'quser' ) {
630 raise_perm_exc
( "mail does not belong to user ' $authuser '" )
631 if $authuser ne $ref ->{ pmail
};
634 my $sender = $get_real_sender ->( $ref );
635 my $username = $ref ->{ pmail
};
637 if ( $action eq 'whitelist' ) {
638 PMG
:: DBTools
:: add_to_blackwhite
( $dbh, $username, 'WL' , [ $sender ]);
639 } elsif ( $action eq 'blacklist' ) {
640 PMG
:: DBTools
:: add_to_blackwhite
( $dbh, $username, 'BL' , [ $sender ]);
641 } elsif ( $action eq 'deliver' ) {
642 } elsif ( $action eq 'delete' ) {