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