]>
Commit | Line | Data |
---|---|---|
0854fb22 DM |
1 | package PMG::Service::pmgproxy; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::SafeSyslog; | |
7 | use PVE::Daemon; | |
8 | use HTTP::Response; | |
9 | use URI; | |
10 | use URI::QueryParam; | |
11 | use Data::Dumper; | |
12 | ||
13 | use PVE::Tools; | |
14 | use PVE::APIServer::Formatter; | |
15 | use PVE::APIServer::Formatter::Standard; | |
16 | use PVE::APIServer::Formatter::HTML; | |
17 | use PVE::APIServer::AnyEvent; | |
18 | ||
19 | use PMG::HTTPServer; | |
20 | use PMG::API2; | |
21 | ||
803b4163 | 22 | use Template; |
0854fb22 DM |
23 | |
24 | use base qw(PVE::Daemon); | |
25 | ||
26 | my $cmdline = [$0, @ARGV]; | |
27 | ||
28 | my %daemon_options = ( | |
29 | max_workers => 3, | |
30 | restart_on_error => 5, | |
31 | stop_wait_time => 15, | |
32 | leave_children_open_on_reload => 1, | |
33 | setuid => 'www-data', | |
34 | setgid => 'www-data', | |
35 | pidfile => '/var/run/pmgproxy/pmgproxy.pid', | |
36 | ); | |
37 | ||
38 | my $daemon = __PACKAGE__->new('pmgproxy', $cmdline, %daemon_options); | |
39 | ||
40 | sub add_dirs { | |
41 | my ($result_hash, $alias, $subdir) = @_; | |
42 | ||
43 | PVE::APIServer::AnyEvent::add_dirs($result_hash, $alias, $subdir); | |
44 | } | |
45 | ||
803b4163 | 46 | my $gui_base_dir = "/usr/share/javascript/proxmox-mailgateway-gui"; |
61ab886a | 47 | my $fontawesome_dir = "/usr/share/fonts-font-awesome"; |
803b4163 | 48 | |
0854fb22 DM |
49 | sub init { |
50 | my ($self) = @_; | |
51 | ||
52 | my $accept_lock_fn = "/var/lock/pmgproxy.lck"; | |
53 | ||
54 | my $lockfh = IO::File->new(">>${accept_lock_fn}") || | |
55 | die "unable to open lock file '${accept_lock_fn}' - $!\n"; | |
56 | ||
57 | my $family = PVE::Tools::get_host_address_family($self->{nodename}); | |
58 | my $socket = $self->create_reusable_socket(8006, undef, $family); | |
59 | ||
60 | my $dirs = {}; | |
61 | ||
62 | add_dirs($dirs, '/pve2/ext6/', '/usr/share/javascript/extjs/'); | |
803b4163 DM |
63 | add_dirs($dirs, '/pve2/images/' => "$gui_base_dir/images/"); |
64 | add_dirs($dirs, '/pve2/css/' => "$gui_base_dir/css/"); | |
65 | add_dirs($dirs, '/pve2/js/' => "$gui_base_dir/js/"); | |
61ab886a DM |
66 | add_dirs($dirs, '/fontawesome/css/' => "$fontawesome_dir/css"); |
67 | add_dirs($dirs, '/fontawesome/fonts/' => "$fontawesome_dir/fonts"); | |
68 | ||
0854fb22 | 69 | #add_dirs($dirs, '/pve-docs/' => '/usr/share/pve-docs/'); |
0854fb22 DM |
70 | #add_dirs($dirs, '/novnc/' => '/usr/share/novnc-pve/'); |
71 | ||
72 | $self->{server_config} = { | |
73 | title => 'Proxmox Mail Gateway API', | |
74 | cookie_name => 'PMG', | |
75 | keep_alive => 100, | |
76 | max_conn => 500, | |
77 | max_requests => 1000, | |
78 | lockfile => $accept_lock_fn, | |
79 | socket => $socket, | |
80 | lockfh => $lockfh, | |
81 | debug => $self->{debug}, | |
82 | trusted_env => 0, # not trusted, anyone can connect | |
83 | logfile => '/var/log/pmgproxy/pmgproxy.log', | |
84 | ssl => { | |
85 | # Note: older versions are considered insecure, for example | |
86 | # search for "Poodle"-Attac | |
87 | method => 'any', | |
88 | sslv2 => 0, | |
89 | sslv3 => 0, | |
90 | cipher_list => 'HIGH:MEDIUM:!aNULL:!MD5', | |
91 | cert_file => '/etc/proxmox/pmg-api.pem', | |
92 | dh => 'skip2048', | |
93 | }, | |
94 | # Note: there is no authentication for those pages and dirs! | |
95 | pages => { | |
96 | '/' => sub { get_index($self->{nodename}, @_) }, | |
97 | # avoid authentication when accessing favicon | |
cb159468 DM |
98 | '/favicon.ico' => { |
99 | file => '/usr/share/doc/proxmox-mailgateway-api/favicon.ico', | |
100 | }, | |
0854fb22 DM |
101 | }, |
102 | dirs => $dirs, | |
103 | }; | |
104 | } | |
105 | ||
106 | sub run { | |
107 | my ($self) = @_; | |
108 | ||
109 | my $server = PMG::HTTPServer->new(%{$self->{server_config}}); | |
110 | $server->run(); | |
111 | } | |
112 | ||
113 | $daemon->register_start_command(); | |
114 | $daemon->register_restart_command(1); | |
115 | $daemon->register_stop_command(); | |
116 | $daemon->register_status_command(); | |
117 | ||
118 | our $cmddef = { | |
119 | start => [ __PACKAGE__, 'start', []], | |
120 | restart => [ __PACKAGE__, 'restart', []], | |
121 | stop => [ __PACKAGE__, 'stop', []], | |
122 | status => [ __PACKAGE__, 'status', [], undef, sub { print shift . "\n";} ], | |
123 | }; | |
124 | ||
0854fb22 DM |
125 | sub get_index { |
126 | my ($nodename, $server, $r, $args) = @_; | |
127 | ||
128 | my $lang = 'en'; | |
129 | my $username; | |
130 | my $token = 'null'; | |
131 | ||
132 | if (my $cookie = $r->header('Cookie')) { | |
133 | if (my $newlang = ($cookie =~ /(?:^|\s)PMGLangCookie=([^;]*)/)[0]) { | |
134 | if ($newlang =~ m/^[a-z]{2,3}(_[A-Z]{2,3})?$/) { | |
135 | $lang = $newlang; | |
136 | } | |
137 | } | |
138 | my $ticket = PVE::APIServer::Formatter::extract_auth_cookie($cookie, $server->{cookie_name}); | |
139 | if (($username = PMG::Ticket::verify_ticket($ticket, 1))) { | |
140 | $token = PMG::Ticket::assemble_csrf_prevention_token($username); | |
141 | } | |
142 | } | |
143 | ||
144 | $username = '' if !$username; | |
145 | ||
803b4163 DM |
146 | my $config = { |
147 | INCLUDE_PATH => $gui_base_dir, | |
148 | }; | |
149 | ||
150 | my $template = Template->new($config); | |
151 | my $vars = { | |
152 | lang => $lang, | |
153 | debug => $server->{debug}, | |
154 | username => $username, | |
155 | csrftoken => $token, | |
156 | nodename => $nodename, | |
157 | }; | |
158 | ||
159 | my $page = ''; | |
160 | ||
161 | $template->process("index.html", $vars, \$page) || | |
162 | die $template->error(); | |
163 | ||
0854fb22 DM |
164 | my $headers = HTTP::Headers->new(Content_Type => "text/html; charset=utf-8"); |
165 | my $resp = HTTP::Response->new(200, "OK", $headers, $page); | |
166 | ||
167 | return $resp; | |
168 | } | |
169 | ||
170 | 1; |