json: Make native messaging work.

* src/gpgme-json.c (opt_debug): New.
(process_request): Add optional arg nm_mode.  In this mode take the
request from a "message" object.
(native_messaging_repl): Add debug output and call process_request
in NM_MODE.
(main): Add option --debug.  Parse envvar GPGME_JSON_DEBUG as an
alternative way to enable this.  Use a default log file.
--

Note that the default log file is ~/.gnupg/S.gpgme-json.log .
Thus to debug a javascript application you should start

  watchgnupg --time-only --force ~/.gnupg/S.gpgme-json.log

in a separate tty and then use

 GPGME_JSON_DEBUG=1 firefox &

to run firefox.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2018-03-28 20:50:54 +02:00
parent 7c220e387d
commit 4b2fa657d1
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B

View File

@ -56,7 +56,8 @@ static char *error_object_string (const char *message,
/* True if interactive mode is active. */ /* True if interactive mode is active. */
static int opt_interactive; static int opt_interactive;
/* True is debug mode is active. */
static int opt_debug;
/* /*
@ -754,9 +755,10 @@ op_help (cjson_t request, cjson_t result)
/* Process a request and return the response. The response is a newly /* Process a request and return the response. The response is a newly
* allocated staring or NULL in case of an error. */ * allocated staring or NULL in case of an error. With NM_MODE set
* the actual request is taken from a "message" object. */
static char * static char *
process_request (const char *request) process_request (const char *request, int nm_mode)
{ {
static struct { static struct {
const char *op; const char *op;
@ -770,6 +772,7 @@ process_request (const char *request)
{ NULL } { NULL }
}; };
size_t erroff; size_t erroff;
cjson_t json_orig;
cjson_t json; cjson_t json;
cjson_t j_tmp, j_op; cjson_t j_tmp, j_op;
cjson_t response; cjson_t response;
@ -780,7 +783,7 @@ process_request (const char *request)
response = xjson_CreateObject (); response = xjson_CreateObject ();
json = cJSON_Parse (request, &erroff); json = json_orig = cJSON_Parse (request, &erroff);
if (!json) if (!json)
{ {
log_string (GPGRT_LOGLVL_INFO, request); log_string (GPGRT_LOGLVL_INFO, request);
@ -788,6 +791,16 @@ process_request (const char *request)
error_object (response, "invalid JSON object at offset %zu\n", erroff); error_object (response, "invalid JSON object at offset %zu\n", erroff);
goto leave; goto leave;
} }
if (nm_mode)
{
json = cJSON_GetObjectItem (json, "message");
if (!json)
{
log_info ("no \"message\" object in request\n");
error_object (response, "no \"message\" object in request\n");
goto leave;
}
}
j_tmp = cJSON_GetObjectItem (json, "help"); j_tmp = cJSON_GetObjectItem (json, "help");
helpmode = (j_tmp && cjson_is_true (j_tmp)); helpmode = (j_tmp && cjson_is_true (j_tmp));
@ -844,8 +857,7 @@ process_request (const char *request)
} }
leave: leave:
cJSON_Delete (json); cJSON_Delete (json_orig);
json = NULL;
if (opt_interactive) if (opt_interactive)
res = cJSON_Print (response); res = cJSON_Print (response);
else else
@ -930,7 +942,7 @@ process_meta_commands (const char *request)
"\"\\nMeta commands:\\n" "\"\\nMeta commands:\\n"
" ,help This help\\n" " ,help This help\\n"
" ,quit Terminate process\"" " ,quit Terminate process\""
"}"); "}", 0);
else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4])) else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
exit (0); exit (0);
else else
@ -1029,7 +1041,7 @@ interactive_repl (void)
} }
else if (request) else if (request)
{ {
response = process_request (request); response = process_request (request, 0);
} }
xfree (request); xfree (request);
request = NULL; request = NULL;
@ -1072,7 +1084,7 @@ interactive_repl (void)
} }
/* Read and process asingle request. */ /* Read and process a single request. */
static void static void
read_and_process_single_request (void) read_and_process_single_request (void)
{ {
@ -1093,7 +1105,7 @@ read_and_process_single_request (void)
if (request) if (request)
{ {
xfree (response); xfree (response);
response = process_request (request); response = process_request (request, 0);
if (response) if (response)
{ {
es_fputs (response, es_stdout); es_fputs (response, es_stdout);
@ -1126,6 +1138,7 @@ native_messaging_repl (void)
* binary mode. */ * binary mode. */
es_set_binary (es_stdin); es_set_binary (es_stdin);
es_set_binary (es_stdout); es_set_binary (es_stdout);
es_setbuf (es_stdin, NULL);
for (;;) for (;;)
{ {
@ -1149,7 +1162,7 @@ native_messaging_repl (void)
{ {
log_error ("error reading request: request too long (%zu MiB)\n", log_error ("error reading request: request too long (%zu MiB)\n",
(size_t)nrequest / (1024*1024)); (size_t)nrequest / (1024*1024));
/* Fixme: Shall we read the request t the bit bucket and /* Fixme: Shall we read the request to the bit bucket and
* return an error reponse or just return an error reponse * return an error reponse or just return an error reponse
* and terminate? Needs some testing. */ * and terminate? Needs some testing. */
break; break;
@ -1181,8 +1194,12 @@ native_messaging_repl (void)
} }
else /* Process request */ else /* Process request */
{ {
if (opt_debug)
log_debug ("request='%s'\n", request);
xfree (response); xfree (response);
response = process_request (request); response = process_request (request, 1);
if (opt_debug)
log_debug ("response='%s'\n", response);
} }
nresponse = strlen (response); nresponse = strlen (response);
@ -1263,12 +1280,18 @@ main (int argc, char *argv[])
enum { CMD_DEFAULT = 0, enum { CMD_DEFAULT = 0,
CMD_INTERACTIVE = 'i', CMD_INTERACTIVE = 'i',
CMD_SINGLE = 's', CMD_SINGLE = 's',
CMD_LIBVERSION = 501 CMD_LIBVERSION = 501,
} cmd = CMD_DEFAULT; } cmd = CMD_DEFAULT;
enum {
OPT_DEBUG = 600
};
static gpgrt_opt_t opts[] = { static gpgrt_opt_t opts[] = {
ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"), ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"), ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"), ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
ARGPARSE_s_n(OPT_DEBUG, "debug", "Flyswatter"),
ARGPARSE_end() ARGPARSE_end()
}; };
gpgrt_argparse_t pargs = { &argc, &argv}; gpgrt_argparse_t pargs = { &argc, &argv};
@ -1298,6 +1321,8 @@ main (int argc, char *argv[])
cmd = pargs.r_opt; cmd = pargs.r_opt;
break; break;
case OPT_DEBUG: opt_debug = 1; break;
default: default:
pargs.err = ARGPARSE_PRINT_WARNING; pargs.err = ARGPARSE_PRINT_WARNING;
break; break;
@ -1305,6 +1330,29 @@ main (int argc, char *argv[])
} }
gpgrt_argparse (NULL, &pargs, NULL); gpgrt_argparse (NULL, &pargs, NULL);
if (!opt_debug)
{
const char *s = getenv ("GPGME_JSON_DEBUG");
if (s && atoi (s) > 0)
opt_debug = 1;
}
if (opt_debug)
{
const char *home = getenv ("HOME");
char *file = xstrconcat ("socket://",
home? home:"/tmp",
"/.gnupg/S.gpgme-json.log", NULL);
log_set_file (file);
xfree (file);
}
if (opt_debug)
{ int i;
for (i=0; argv[i]; i++)
log_debug ("argv[%d]='%s'\n", i, argv[i]);
}
switch (cmd) switch (cmd)
{ {
case CMD_DEFAULT: case CMD_DEFAULT:
@ -1327,6 +1375,9 @@ main (int argc, char *argv[])
break; break;
} }
if (opt_debug)
log_debug ("ready");
#endif /* This is a modern libgp-error. */ #endif /* This is a modern libgp-error. */
return 0; return 0;
} }