Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/archlinux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ requires+=(
make
mate-common
mate-desktop
poppler
poppler-glib
texlive-bin
webkit2gtk
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/debian.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ requires+=(
libkpathsea-dev
libmate-desktop-dev
libpoppler-glib-dev
poppler-utils
libsecret-1-dev
libsm-dev
libspectre-dev
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/fedora.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ requires+=(
mate-common
mate-desktop-devel
poppler-glib-devel
poppler-utils
redhat-rpm-config
texlive-lib-devel
webkit2gtk4.1-devel
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ requires+=(
libkpathsea-dev
libmate-desktop-dev
libpoppler-glib-dev
poppler-utils
libsecret-1-dev
libsm-dev
libspectre-dev
Expand Down
1 change: 1 addition & 0 deletions atril-document.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <libdocument/ev-document-links.h>
#include <libdocument/ev-document-misc.h>
#include <libdocument/ev-document-security.h>
#include <libdocument/ev-document-signatures.h>
#include <libdocument/ev-document-thumbnails.h>
#include <libdocument/ev-document-transition.h>
#include <libdocument/ev-document-type-builtins.h>
Expand Down
323 changes: 323 additions & 0 deletions backend/pdf/ev-poppler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "ev-document-annotations.h"
#include "ev-document-attachments.h"
#include "ev-document-text.h"
#include "ev-document-signatures.h"
#include "ev-selection.h"
#include "ev-transition-effect.h"
#include "ev-attachment.h"
Expand Down Expand Up @@ -123,6 +124,7 @@ static void pdf_document_document_layers_iface_init (EvDocumentLayersInterf
static void pdf_document_document_print_iface_init (EvDocumentPrintInterface *iface);
static void pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface);
static void pdf_document_document_attachments_iface_init (EvDocumentAttachmentsInterface *iface);
static void pdf_document_signatures_iface_init (EvDocumentSignaturesInterface *iface);
static void pdf_document_find_iface_init (EvDocumentFindInterface *iface);
static void pdf_document_file_exporter_iface_init (EvFileExporterInterface *iface);
static void pdf_selection_iface_init (EvSelectionInterface *iface);
Expand Down Expand Up @@ -176,6 +178,8 @@ EV_BACKEND_REGISTER_WITH_CODE (PdfDocument, pdf_document,
pdf_document_page_transition_iface_init);
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_TEXT,
pdf_document_text_iface_init);
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SIGNATURES,
pdf_document_signatures_iface_init);
});

static void
Expand Down Expand Up @@ -3334,3 +3338,322 @@ pdf_document_document_layers_iface_init (EvDocumentLayersInterface *iface)
iface->hide_layer = pdf_document_layers_hide_layer;
iface->layer_is_visible = pdf_document_layers_layer_is_visible;
}

#if POPPLER_CHECK_VERSION(22, 2, 0)
typedef struct {
EvDocumentSignatures *document;
GAsyncReadyCallback callback;
gpointer user_data;
PopplerSigningData *signing_data;
} PdfSignClosure;

static void
pdf_sign_closure_free (PdfSignClosure *closure)
{
if (!closure)
return;

poppler_signing_data_free (closure->signing_data);
g_object_unref (closure->document);
g_free (closure);
}

static void
pdf_document_sign_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
PdfSignClosure *closure = (PdfSignClosure *)user_data;
GTask *task;
GError *error = NULL;

task = g_task_new (closure->document, NULL, closure->callback, closure->user_data);

if (poppler_document_sign_finish (POPPLER_DOCUMENT (source_object), result, &error))
g_task_return_boolean (task, TRUE);
else
g_task_return_error (task, error);

g_object_unref (task);
pdf_sign_closure_free (closure);
}

static EvDocumentSignatureState
pdf_document_signatures_get_signature_state (EvDocumentSignatures *document,
guint *n_signatures)
{
PdfDocument *pdf_document = PDF_DOCUMENT (document);
GList *signatures;
gboolean all_valid;
gboolean any_invalid;
gint total_signatures;

total_signatures = poppler_document_get_n_signatures (POPPLER_DOCUMENT (pdf_document->document));
if (n_signatures)
*n_signatures = total_signatures > 0 ? (guint) total_signatures : 0;

if (total_signatures <= 0)
return EV_DOCUMENT_SIGNATURE_STATE_NONE;

signatures = poppler_document_get_signature_fields (POPPLER_DOCUMENT (pdf_document->document));
if (!signatures)
return EV_DOCUMENT_SIGNATURE_STATE_PRESENT;

all_valid = TRUE;
any_invalid = FALSE;

for (GList *list = signatures; list != NULL; list = list->next) {
PopplerFormField *field = POPPLER_FORM_FIELD (list->data);
PopplerSignatureInfo *signature_info;
PopplerSignatureStatus signature_status;
PopplerCertificateStatus certificate_status;
g_autoptr(GError) error = NULL;

signature_info = poppler_form_field_signature_validate_sync (field,
POPPLER_SIGNATURE_VALIDATION_FLAG_VALIDATE_CERTIFICATE,
NULL,
&error);
if (!signature_info) {
all_valid = FALSE;
continue;
}

signature_status = poppler_signature_info_get_signature_status (signature_info);
certificate_status = poppler_signature_info_get_certificate_status (signature_info);

switch (signature_status) {
case POPPLER_SIGNATURE_VALID:
break;
case POPPLER_SIGNATURE_INVALID:
case POPPLER_SIGNATURE_DIGEST_MISMATCH:
case POPPLER_SIGNATURE_DECODING_ERROR:
all_valid = FALSE;
any_invalid = TRUE;
break;
case POPPLER_SIGNATURE_GENERIC_ERROR:
case POPPLER_SIGNATURE_NOT_FOUND:
case POPPLER_SIGNATURE_NOT_VERIFIED:
all_valid = FALSE;
break;
}

switch (certificate_status) {
case POPPLER_CERTIFICATE_TRUSTED:
break;
case POPPLER_CERTIFICATE_REVOKED:
case POPPLER_CERTIFICATE_EXPIRED:
case POPPLER_CERTIFICATE_UNTRUSTED_ISSUER:
all_valid = FALSE;
any_invalid = TRUE;
break;
case POPPLER_CERTIFICATE_UNKNOWN_ISSUER:
case POPPLER_CERTIFICATE_GENERIC_ERROR:
case POPPLER_CERTIFICATE_NOT_VERIFIED:
all_valid = FALSE;
break;
}

poppler_signature_info_free (signature_info);
}

g_list_free_full (signatures, g_object_unref);

if (any_invalid)
return EV_DOCUMENT_SIGNATURE_STATE_INVALID;

if (all_valid)
return EV_DOCUMENT_SIGNATURE_STATE_VALID;

return EV_DOCUMENT_SIGNATURE_STATE_PRESENT;
}

static gboolean
pdf_document_signatures_sign (EvDocumentSignatures *document,
EvSignaturesData *data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data,
GError **error)
{
PdfDocument *pdf_document = PDF_DOCUMENT (document);
PopplerColor *color;
PopplerSigningData *signing_data = poppler_signing_data_new ();
PopplerCertificateInfo *cert_info;
PdfSignClosure *closure;
gchar *field_partial_name;

if (!data || !data->certificate_info || !data->destination_file || !data->rect) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
_("Digital signature setup is incomplete."));
poppler_signing_data_free (signing_data);
return FALSE;
}

cert_info = poppler_get_certificate_info_by_id (ev_certificate_info_get_id (data->certificate_info));

if (!cert_info) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
_("No signing certificate was found."));
poppler_signing_data_free (signing_data);
return FALSE;
}

poppler_signing_data_set_certificate_info (signing_data, cert_info);
poppler_certificate_info_free (cert_info);
poppler_signing_data_set_page (signing_data, data->page);
field_partial_name = g_uuid_string_random ();
poppler_signing_data_set_field_partial_name (signing_data, field_partial_name);
g_free (field_partial_name);
poppler_signing_data_set_destination_filename (signing_data, data->destination_file);

if (data->password)
poppler_signing_data_set_password (signing_data, data->password);
poppler_signing_data_set_signature_text (signing_data, data->signature);
poppler_signing_data_set_signature_text_left (signing_data, data->signature_left);

color = poppler_color_new ();
color->red = data->font_color.red * 255;
color->green = data->font_color.green * 255;
color->blue = data->font_color.blue * 255;
poppler_signing_data_set_font_color (signing_data, color);
g_clear_pointer (&color, poppler_color_free);

poppler_signing_data_set_font_size (signing_data, data->font_size);
poppler_signing_data_set_left_font_size (signing_data, data->left_font_size);
poppler_signing_data_set_border_width (signing_data, data->border_width);

color = poppler_color_new ();
color->red = data->border_color.red * 255;
color->green = data->border_color.green * 255;
color->blue = data->border_color.blue * 255;
poppler_signing_data_set_border_color (signing_data, color);
g_clear_pointer (&color, poppler_color_free);

color = poppler_color_new ();
color->red = data->background_color.red * 255;
color->green = data->background_color.green * 255;
color->blue = data->background_color.blue * 255;
poppler_signing_data_set_background_color (signing_data, color);
g_clear_pointer (&color, poppler_color_free);

if (data->document_owner_password)
poppler_signing_data_set_document_owner_password (signing_data, data->document_owner_password);

if (data->document_user_password)
poppler_signing_data_set_document_user_password (signing_data, data->document_user_password);

gdouble height;
ev_document_get_page_size (EV_DOCUMENT (document), data->page, NULL, &height);

PopplerRectangle *signing_rect = poppler_rectangle_new ();
signing_rect->x1 = data->rect->x1;
signing_rect->y1 = height - data->rect->y1;
signing_rect->x2 = data->rect->x2;
signing_rect->y2 = height - data->rect->y2;

poppler_signing_data_set_signature_rectangle (signing_data, signing_rect);
poppler_rectangle_free (signing_rect);

closure = g_new0 (PdfSignClosure, 1);
closure->document = EV_DOCUMENT_SIGNATURES (g_object_ref (document));
closure->callback = callback;
closure->user_data = user_data;
closure->signing_data = signing_data;

poppler_document_sign (POPPLER_DOCUMENT (pdf_document->document), signing_data, cancellable, pdf_document_sign_cb, closure);

return TRUE;
}

static gboolean
pdf_document_signatures_sign_finish (EvDocumentSignatures *document,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}

static gboolean
pdf_document_signatures_can_sign (EvDocumentSignatures *document)
{
GList *certs = poppler_get_available_signing_certificates ();
gboolean can_sign = certs != NULL;

g_list_free_full (certs, (GDestroyNotify) poppler_certificate_info_free);

return can_sign;
}

static void
pdf_document_set_password_callback (EvDocumentSignatures *document,
EvSignaturePasswordCallback cb)
{
poppler_set_nss_password_callback (cb);
}

static GList *
pdf_document_get_available_signing_certificates (EvDocumentSignatures *document)
{
GList *certs = poppler_get_available_signing_certificates ();
GList *ev_certs = NULL;

if (!certs)
return NULL;

for (GList *list = certs; list != NULL; list = list->next) {
PopplerCertificateInfo *info = (PopplerCertificateInfo *)list->data;
EvCertificateInfo *cert_info = ev_certificate_info_new (poppler_certificate_info_get_id (info), poppler_certificate_info_get_subject_common_name (info));

ev_certs = g_list_append (ev_certs, cert_info);
}

g_list_free_full (certs, (GDestroyNotify) poppler_certificate_info_free);

return ev_certs;
}

static EvCertificateInfo *
pdf_document_get_certificate_info (EvDocumentSignatures *document,
const char *id)
{
GList *certs;
GList *list;
EvCertificateInfo *info = NULL;

if (!id || strlen (id) == 0)
return NULL;

certs = pdf_document_get_available_signing_certificates (document);

for (list = certs; list != NULL; list = list->next) {
EvCertificateInfo *cert_info = (EvCertificateInfo *)list->data;

if (g_strcmp0 (ev_certificate_info_get_id (cert_info), id) == 0) {
info = ev_certificate_info_copy (cert_info);
break;
}
}

g_list_free_full (certs, (GDestroyNotify) ev_certificate_info_free);

return info;
}
#endif /* POPPLER_CHECK_VERSION(22, 2, 0) */

static void
pdf_document_signatures_iface_init (EvDocumentSignaturesInterface *iface)
{
#if POPPLER_CHECK_VERSION(22, 2, 0)
iface->set_password_callback = pdf_document_set_password_callback;
iface->get_available_signing_certificates = pdf_document_get_available_signing_certificates;
iface->get_certificate_info = pdf_document_get_certificate_info;
iface->sign = pdf_document_signatures_sign;
iface->sign_finish = pdf_document_signatures_sign_finish;
iface->can_sign = pdf_document_signatures_can_sign;
iface->get_signature_state = pdf_document_signatures_get_signature_state;
#endif
}
Loading
Loading