Browse Source

Create the encrypt module.

Move all code related to encryption or signing to a dedicated
module. Leave only option parsing to the main yki module.
master
Damien Goutte-Gattat 2 years ago
parent
commit
3f06f88825
  1. 3
      src/Makefile.am
  2. 255
      src/encrypt.c
  3. 35
      src/encrypt.h
  4. 4
      src/gpgutil.c
  5. 219
      src/yki.c

3
src/Makefile.am

@ -1,7 +1,8 @@
bin_PROGRAMS = yki
yki_SOURCES = yki.c gpgutil.c gpgutil.h error.c error.h errors.h \
ykiutil.c ykiutil.h yki-encrypt.ui resources.xml
ykiutil.c ykiutil.h encrypt.c encrypt.h \
yki-encrypt.ui resources.xml
nodist_yki_SOURCES = resources.c

255
src/encrypt.c

@ -0,0 +1,255 @@
/*
* Yorkie - A task-oriented GnuPG frontend
* Copyright (C) 2020 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "encrypt.h"
#include <glib.h>
#include <gtk/gtk.h>
#include <gpgme.h>
#include "error.h"
#include "gpgutil.h"
/* GUI stuff. */
static void
symmetric_encrypt_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->symmetric = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
static void
sign_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->sign = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
static void
detach_sign_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->detached = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
static void
public_key_toggled(GtkCellRendererToggle *renderer,
gchar *path,
gpointer data)
{
yki_ctx_t *yki = (yki_ctx_t *)data;
GtkTreeIter iter;
gboolean selected;
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(yki->public_keys), &iter, path);
gtk_tree_model_get(GTK_TREE_MODEL(yki->public_keys), &iter, 0, &selected, -1);
selected = !selected;
yki->selected_keys += selected ? 1 : -1;
gtk_list_store_set(GTK_LIST_STORE(yki->public_keys), &iter, 0, selected, -1);
}
static GtkDialog *
create_encrypt_dialog(yki_ctx_t *yki)
{
GtkBuilder *builder;
GObject *widget;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
builder = gtk_builder_new_from_resource("/org/incenp/Yorkie/yki-encrypt.ui");
g_signal_connect(gtk_builder_get_object(builder, "chkSymEncrypt"),
"clicked", G_CALLBACK(symmetric_encrypt_toggled), yki);
g_signal_connect(gtk_builder_get_object(builder, "chkSign"),
"clicked", G_CALLBACK(sign_toggled), yki);
g_signal_connect(gtk_builder_get_object(builder, "chkDetachSign"),
"clicked", G_CALLBACK(detach_sign_toggled), yki);
widget = gtk_builder_get_object(builder, "trvPublicKeys");
yki->public_keys = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(widget)));
renderer = gtk_cell_renderer_toggle_new();
column = gtk_tree_view_column_new_with_attributes("Selected", renderer, "active", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
g_signal_connect(renderer, "toggled", G_CALLBACK(public_key_toggled), yki);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("User ID", renderer, "text", 1, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
return GTK_DIALOG(gtk_builder_get_object(builder, "dlgEncrypt"));
}
/* Dealing with public keys. */
static int
populate_public_key_list(gpgme_ctx_t ctx, GtkListStore *key_list, GError **error)
{
GtkTreeIter iter;
gpgme_key_t key;
gpgme_error_t gerr;
gerr = gpgme_op_keylist_start(ctx, NULL, 0);
while ( ! gerr ) {
gerr = gpgme_op_keylist_next(ctx, &key);
if ( ! gerr ) {
if ( key->revoked || key->expired || key->disabled || key->invalid || ! key->can_encrypt )
continue;
gtk_list_store_append(key_list, &iter);
gtk_list_store_set(key_list, &iter,
0, FALSE, /* Selected key? */
1, key->uids[0].uid, /* User ID */
2, key, /* The key itself */
-1);
}
}
if ( gpgme_err_code(gerr) == GPG_ERR_EOF )
gerr = 0; /* Normal end of list, not an error condition */
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_KEYLIST, gerr);
return gpgme_err_code(gerr) == 0;
}
static gboolean
free_key_in_list(GtkTreeModel *store, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
gpgme_key_t key;
gtk_tree_model_get(store, iter, 2, &key, -1);
gpgme_key_release(key);
return TRUE;
}
static gpgme_key_t *
get_selected_keys(yki_ctx_t *yki)
{
gpgme_key_t *keys;
GtkTreeIter iter;
gboolean loop;
unsigned i;
keys = g_malloc((yki->selected_keys + 1) * sizeof(gpgme_key_t));
loop = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(yki->public_keys), &iter);
i = 0;
while ( loop ) {
gboolean selected;
gpointer key;
gtk_tree_model_get(GTK_TREE_MODEL(yki->public_keys), &iter, 0, &selected, 2, &key, -1);
if ( selected )
keys[i++] = (gpgme_key_t)key;
loop = gtk_tree_model_iter_next(GTK_TREE_MODEL(yki->public_keys), &iter);
}
keys[i] = NULL;
return keys;
}
/* Actual encryption or sign operation. */
#define yki_can_encrypt(yki) ((yki).selected_keys || (yki).symmetric || (yki).sign)
static int
do_encrypt(yki_ctx_t *yki, gpgme_data_t in, gpgme_data_t out, GError **error)
{
gpgme_error_t gerr = 0;
if ( yki->symmetric || yki->selected_keys ) {
gpgme_key_t *keys = get_selected_keys(yki);
gpgme_encrypt_flags_t flags = yki->symmetric ? GPGME_ENCRYPT_SYMMETRIC : 0;
if ( yki->sign )
gerr = gpgme_op_encrypt_sign(yki->gpgme, keys, flags, in, out);
else
gerr = gpgme_op_encrypt(yki->gpgme, keys, flags, in, out);
g_free(keys);
}
else if ( yki->sign ) {
gpgme_sig_mode_t mode = yki->detached ? GPGME_SIG_MODE_DETACH : GPGME_SIG_MODE_NORMAL;
gerr = gpgme_op_sign(yki->gpgme, in, out, mode);
}
else
g_assert_not_reached();
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_CRYPTO, gerr);
return gpgme_err_code(gerr) == 0;
}
/* Public interface. */
int
yki_encrypt(yki_ctx_t *yki, const char *file, GError **error)
{
GtkDialog *dlg;
gpgutil_file_t in, out;
gchar *outname;
int ret;
g_assert(yki && file);
in.buffer = out.buffer = NULL;
dlg = create_encrypt_dialog(yki);
ret = populate_public_key_list(yki->gpgme, yki->public_keys, error);
if ( ret && gtk_dialog_run(dlg) == GTK_RESPONSE_OK && yki_can_encrypt(*yki) ) {
ret = gpgutil_open_file(file, "r", &in, error);
if ( ret ) {
outname = g_strdup_printf("%s.gpg", file);
ret = gpgutil_open_file(outname, "w", &out, error);
g_free(outname);
}
if ( ret )
ret = do_encrypt(yki, in.buffer, out.buffer, error);
}
gpgutil_close_file(&in, NULL);
gpgutil_close_file(&out, NULL);
gtk_tree_model_foreach(GTK_TREE_MODEL(yki->public_keys), free_key_in_list, NULL);
gtk_widget_destroy(GTK_WIDGET(dlg));
return ret;
}

35
src/encrypt.h

@ -0,0 +1,35 @@
/*
* Yorkie - A task-oriented GnuPG frontend
* Copyright (C) 2020 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ICP20200503_ENCRYPT_H
#define ICP20200503_ENCRYPT_H
#include "ykiutil.h"
#ifdef __cpluscplus
extern "C" {
#endif
int
yki_encrypt(yki_ctx_t *, const char *, GError **);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20200503_ENCRYPT_H */

4
src/gpgutil.c

@ -82,7 +82,7 @@ gpgutil_open_file(const char *name,
yki_error_gpgme(error, YKI_ERROR_GPGME_OPEN, gerr);
}
return gpgme_err_code(gerr);
return gpgme_err_code(gerr) == 0;
}
int
@ -104,5 +104,5 @@ gpgutil_close_file(gpgutil_file_t *file, GError **error)
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_CLOSE, gerr);
return gpgme_err_code(gerr);
return gpgme_err_code(gerr) == 0;
}

219
src/yki.c

@ -28,224 +28,10 @@
#include <gtk/gtk.h>
#include "error.h"
#include "gpgutil.h"
#include "encrypt.h"
#include "ykiutil.h"
static int
populate_public_key_list(gpgme_ctx_t ctx, GtkListStore *key_list, GError **error)
{
GtkTreeIter iter;
gpgme_key_t key;
gpgme_error_t gerr;
gerr = gpgme_op_keylist_start(ctx, NULL, 0);
while ( ! gerr ) {
gerr = gpgme_op_keylist_next(ctx, &key);
if ( ! gerr ) {
if ( key->revoked || key->expired || key->disabled || key->invalid || ! key->can_encrypt )
continue;
gtk_list_store_append(key_list, &iter);
gtk_list_store_set(key_list, &iter,
0, FALSE,
1, key->uids[0].uid,
2, key,
-1);
}
}
if ( gpgme_err_code(gerr) == GPG_ERR_EOF )
gerr = 0;
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_KEYLIST, gerr);
return gpgme_err_code(gerr);
}
static gpgme_key_t *
get_selected_keys(yki_ctx_t *yki)
{
gpgme_key_t *keys;
GtkTreeIter iter;
gboolean valid;
unsigned i;
keys = g_malloc((yki->selected_keys + 1) * sizeof(gpgme_key_t));
valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(yki->public_keys), &iter);
i = 0;
while ( valid ) {
gboolean selected;
gpointer key;
gtk_tree_model_get(GTK_TREE_MODEL(yki->public_keys), &iter,
0, &selected, 2, &key, -1);
if ( selected ) {
keys[i++] = (gpgme_key_t) key;
}
valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(yki->public_keys), &iter);
}
keys[i] = NULL;
return keys;
}
static gboolean
free_key_in_list(GtkTreeModel *store, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
gpgme_key_t key;
gtk_tree_model_get(store, iter, 2, &key, -1);
gpgme_key_release(key);
return TRUE;
}
static gpgme_error_t
encrypt_or_sign_buffer(yki_ctx_t *yki, gpgme_data_t in, gpgme_data_t out)
{
gpgme_error_t gerr;
if ( yki->symmetric || yki->selected_keys ) {
gpgme_key_t *keys = get_selected_keys(yki);
gpgme_encrypt_flags_t flags = yki->symmetric ? GPGME_ENCRYPT_SYMMETRIC : 0;
if ( yki->sign )
gerr = gpgme_op_encrypt_sign(yki->gpgme, keys, flags, in, out);
else
gerr = gpgme_op_encrypt(yki->gpgme, keys, flags, in, out);
g_free(keys);
}
else if ( yki->sign ) {
gpgme_sig_mode_t mode = yki->detached ? GPGME_SIG_MODE_DETACH : GPGME_SIG_MODE_NORMAL;
gerr = gpgme_op_sign(yki->gpgme, in, out, mode);
}
return gerr;
}
#define can_proceed(yki) ((yki).selected_keys || (yki).symmetric || (yki).sign)
static void
public_key_toggled(GtkCellRendererToggle *renderer,
gchar *path,
gpointer data)
{
yki_ctx_t *yki = (yki_ctx_t *)data;
GtkTreeIter iter;
gboolean selected;
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(yki->public_keys), &iter, path);
gtk_tree_model_get(GTK_TREE_MODEL(yki->public_keys), &iter, 0, &selected, -1);
selected = !selected;
yki->selected_keys += selected ? 1 : -1;
gtk_list_store_set(GTK_LIST_STORE(yki->public_keys), &iter, 0, selected, -1);
}
static void
symmetric_encrypt_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->symmetric = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
void
sign_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->sign = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
void
detach_sign_toggled(GtkWidget *widget, gpointer data)
{
((yki_ctx_t *)data)->detached = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
static GtkDialog *
create_encrypt_dialog(yki_ctx_t *yki)
{
GtkBuilder *builder;
GObject *widget;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
builder = gtk_builder_new_from_resource("/org/incenp/Yorkie/yki-encrypt.ui");
g_signal_connect(gtk_builder_get_object(builder, "chkSymEncrypt"),
"clicked", G_CALLBACK(symmetric_encrypt_toggled), yki);
g_signal_connect(gtk_builder_get_object(builder, "chkSign"),
"clicked", G_CALLBACK(sign_toggled), yki);
g_signal_connect(gtk_builder_get_object(builder, "chkDetachSign"),
"clicked", G_CALLBACK(detach_sign_toggled), yki);
widget = gtk_builder_get_object(builder, "trvPublicKeys");
yki->public_keys = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(widget)));
renderer = gtk_cell_renderer_toggle_new();
column = gtk_tree_view_column_new_with_attributes("Selected", renderer, "active", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
g_signal_connect(renderer, "toggled", G_CALLBACK(public_key_toggled), yki);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("User ID", renderer, "text", 1, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
return GTK_DIALOG(gtk_builder_get_object(builder, "dlgEncrypt"));
}
static int
encrypt_or_sign_file(yki_ctx_t *yki, const char *filename, GError **error)
{
gpgutil_file_t in, out;
gchar *outname;
int ret;
ret = gpgutil_open_file(filename, "r", &in, error);
if ( ! ret ) {
outname = g_strdup_printf("%s.gpg", filename);
ret = gpgutil_open_file(outname, "w", &out, error);
g_free(outname);
}
if ( ! ret ) {
gpgme_error_t gerr = encrypt_or_sign_buffer(yki, in.buffer, out.buffer);
if ( (ret = gpgme_err_code(gerr)) )
yki_error_gpgme(error, YKI_ERROR_GPGME_CRYPTO, gerr);
}
gpgutil_close_file(&in, NULL);
gpgutil_close_file(&out, NULL);
return ret;
}
static int
do_encrypt(yki_ctx_t *yki, const char *file, GError **error)
{
GtkDialog *dlg;
dlg = create_encrypt_dialog(yki);
populate_public_key_list(yki->gpgme, yki->public_keys, error);
if ( ! *error && gtk_dialog_run(dlg) == GTK_RESPONSE_OK && can_proceed(*yki) )
encrypt_or_sign_file(yki, file, error);
gtk_tree_model_foreach(GTK_TREE_MODEL(yki->public_keys), free_key_in_list, NULL);
gtk_widget_destroy(GTK_WIDGET(dlg));
return *error ? -1 : 0;
}
static gboolean
check_non_option_args(GOptionContext *parser, GOptionGroup *group, gpointer data, GError **error)
{
@ -264,7 +50,6 @@ check_non_option_args(GOptionContext *parser, GOptionGroup *group, gpointer data
return n == 1;
}
int
main(int argc, char **argv)
{
@ -299,7 +84,7 @@ main(int argc, char **argv)
if ( ! error ) {
if ( encrypt )
do_encrypt(&yki, files[0], &error);
yki_encrypt(&yki, files[0], &error);
else
g_set_error(&error, YKI_ERROR, YKI_ERROR_NOT_IMPLEMENTED, "Cannot decrypt");
}

Loading…
Cancel
Save