+sub assemble_spice_ticket {
+ my ($username, $vmid, $node) = @_;
+
+ my $secret = &$get_csrfr_secret();
+
+ return PVE::Ticket::assemble_spice_ticket(
+ $secret, $username, $vmid, $node);
+}
+
+sub verify_spice_connect_url {
+ my ($connect_str) = @_;
+
+ my $secret = &$get_csrfr_secret();
+
+ return PVE::Ticket::verify_spice_connect_url($secret, $connect_str);
+}
+
+sub read_x509_subject_spice {
+ my ($filename) = @_;
+
+ # read x509 subject
+ my $bio = Net::SSLeay::BIO_new_file($filename, 'r');
+ die "Could not open $filename using OpenSSL\n"
+ if !$bio;
+
+ my $x509 = Net::SSLeay::PEM_read_bio_X509($bio);
+ Net::SSLeay::BIO_free($bio);
+
+ die "Could not parse X509 certificate in $filename\n"
+ if !$x509;
+
+ my $nameobj = Net::SSLeay::X509_get_subject_name($x509);
+ my $subject = Net::SSLeay::X509_NAME_oneline($nameobj);
+ Net::SSLeay::X509_free($x509);
+
+ # remote-viewer wants comma as seperator (not '/')
+ $subject =~ s!^/!!;
+ $subject =~ s!/(\w+=)!,$1!g;
+
+ return $subject;
+}
+
+# helper to generate SPICE remote-viewer configuration
+sub remote_viewer_config {
+ my ($authuser, $vmid, $node, $proxy, $title, $port) = @_;
+
+ if (!$proxy) {
+ my $host = `hostname -f` || PVE::INotify::nodename();
+ chomp $host;
+ $proxy = $host;