-
Notifications
You must be signed in to change notification settings - Fork 48
/
main.c
181 lines (147 loc) · 7.01 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <glib.h>
#include <gio/gio.h>
#include "version.h"
#include "main.h"
#include "../common/common.h"
static gint handle_local_options (GApplication *application,
GVariantDict *options,
gpointer user_data);
static int command_line (GApplication *application,
GApplicationCommandLine *cmdline,
gpointer user_data);
static gboolean parse_options (GApplicationCommandLine *cmdline,
CmdlineOpts *cmdline_opts);
static void g_free_cmdline_opts (CmdlineOpts *co);
gint
main (gint argc,
gchar **argv)
{
GOptionEntry entries[] =
{
#ifndef USE_FLATPAK_APP_FOLDER
{ "database", 'd', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "(optional) path to the database. Default value is taken from otpclient.cfg", NULL },
#endif
{ "show", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show a token for a given account.", NULL },
{ "account", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "Account name (to be used with --show, mandatory)", NULL},
{ "issuer", 'i', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "Issuer (to be used with --show, optional)", NULL},
{ "match-exact", 'm', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Match exactly the provided account/issuer (to be used with --show, optional)", NULL},
{ "show-next", 'n', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show also next OTP (to be used with --show, optional)", NULL},
{ "list", 'l', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "List all accounts and issuers for a given database.", NULL },
{ "export", 'e', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Export a database.", NULL },
{ "type", 't', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "The export type for the database. Must be either one of: andotp_plain, andotp_encrypted, freeotpplus, aegis_plain, aegis_encrypted, twofas_plain, twofas_encrypted, authpro_plain, authpro_encrypted (to be used with --export, mandatory)", NULL },
#ifndef USE_FLATPAK_APP_FOLDER
{ "output-dir", 'o', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "The output directory (defaults to the user's home. To be used with --export, optional)", NULL },
#endif
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the program version.", NULL },
{ NULL }
};
const gchar *ctx_text = "- Highly secure and easy to use OTP client that supports both TOTP and HOTP";
GApplication *app = g_application_new ("com.github.paolostivanin.OTPClient", G_APPLICATION_HANDLES_COMMAND_LINE);
g_application_add_main_option_entries (app, entries);
g_application_set_option_context_parameter_string (app, ctx_text);
g_signal_connect (app, "handle-local-options", G_CALLBACK (handle_local_options), NULL);
g_signal_connect (app, "command-line", G_CALLBACK(command_line), NULL);
int status = g_application_run (app, argc, argv);
g_object_unref (app);
return status;
}
void
free_dbdata (DatabaseData *db_data)
{
gcry_free (db_data->key);
g_free (db_data->db_path);
g_slist_free_full (db_data->objects_hash, g_free);
json_decref (db_data->json_data);
g_free (db_data);
}
static gint
handle_local_options (GApplication *application __attribute__((unused)),
GVariantDict *options,
gpointer user_data __attribute__((unused)))
{
guint32 count;
if (g_variant_dict_lookup (options, "version", "b", &count)) {
gchar *msg = g_strconcat ("OTPClient version ", PROJECT_VER, NULL);
g_print ("%s\n", msg);
g_free (msg);
return 0;
}
return -1;
}
static int
command_line (GApplication *application __attribute__((unused)),
GApplicationCommandLine *cmdline,
gpointer user_data __attribute__((unused)))
{
DatabaseData *db_data = g_new0 (DatabaseData, 1);
db_data->key_stored = FALSE;
db_data->objects_hash = NULL;
db_data->max_file_size_from_memlock = get_max_file_size_from_memlock ();
gchar *init_msg = init_libs (db_data->max_file_size_from_memlock);
if (init_msg != NULL) {
g_application_command_line_printerr(cmdline, "Error while initializing GCrypt: %s\n", init_msg);
g_free (init_msg);
g_free (db_data);
return -1;
}
CmdlineOpts *cmdline_opts = g_new0 (CmdlineOpts, 1);
cmdline_opts->database = NULL;
cmdline_opts->show = FALSE;
cmdline_opts->account = NULL;
cmdline_opts->issuer = NULL;
cmdline_opts->match_exact = FALSE;
cmdline_opts->show_next = FALSE;
cmdline_opts->list = FALSE;
cmdline_opts->export = FALSE;
cmdline_opts->export_type = NULL;
cmdline_opts->export_dir = NULL;
if (!parse_options (cmdline, cmdline_opts)) {
g_free (db_data);
g_free_cmdline_opts (cmdline_opts);
return -1;
}
if (!exec_action (cmdline_opts, db_data)) {
g_free_cmdline_opts (cmdline_opts);
return -1;
}
free_dbdata (db_data);
g_free_cmdline_opts (cmdline_opts);
return 0;
}
static gboolean
parse_options (GApplicationCommandLine *cmdline,
CmdlineOpts *cmdline_opts)
{
GVariantDict *options = g_application_command_line_get_options_dict (cmdline);
g_variant_dict_lookup (options, "database", "s", &cmdline_opts->database);
if (g_variant_dict_lookup (options, "show", "b", &cmdline_opts->show)) {
if (!g_variant_dict_lookup (options, "account", "s", &cmdline_opts->account)) {
g_application_command_line_print (cmdline, "Please provide at least the account option.\n");
return FALSE;
}
g_variant_dict_lookup (options, "issuer", "s", &cmdline_opts->issuer);
g_variant_dict_lookup (options, "match-exact", "b", &cmdline_opts->match_exact);
g_variant_dict_lookup (options, "show-next", "b", &cmdline_opts->show_next);
}
g_variant_dict_lookup (options, "list", "b", &cmdline_opts->list);
if (g_variant_dict_lookup (options, "export", "b", &cmdline_opts->export)) {
if (!g_variant_dict_lookup (options, "type", "s", &cmdline_opts->export_type)) {
g_application_command_line_print (cmdline, "Please provide at least export type.\n");
return FALSE;
}
#ifndef USE_FLATPAK_APP_FOLDER
g_variant_dict_lookup (options, "output-dir", "s", &cmdline_opts->export_dir);
#endif
}
return TRUE;
}
static void
g_free_cmdline_opts (CmdlineOpts *co)
{
g_free (co->database);
g_free (co->account);
g_free (co->issuer);
g_free (co->export_type);
g_free (co->export_dir);
g_free (co);
}