summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2021-11-02 15:54:24 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2021-11-06 17:00:53 +0100
commit44f9f7cdfa24e3de0e166167aa97f02164bfa5c9 (patch)
treef04c780b81f1d2f21840812ae8822212b3e9dc70
parentddf2ddf06be7d2c45afdc4f411438e77020dd198 (diff)
Create a shared object with a client API
-rw-r--r--src/Makefile.am1
-rw-r--r--src/client/Disfluid-0.h126
-rw-r--r--src/client/Makefile.am25
-rw-r--r--src/client/libwebidoidc-client.c144
-rw-r--r--src/scm/webid-oidc/client/Makefile.am6
-rw-r--r--src/scm/webid-oidc/client/reverse-stubs.scm50
6 files changed, 350 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d19c38..61a4166 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,6 +80,7 @@ include %reldir%/pre-inst/Makefile.am
include %reldir%/inst/Makefile.am
include %reldir%/scm/Makefile.am
include %reldir%/ui/Makefile.am
+include %reldir%/client/Makefile.am
CLEANFILES += $(go_DATA) $(webidoidcgo_DATA) $(mod_DATA) $(webidoidcmod_DATA) \
$(serverwebidoidcgo_DATA) $(clientwebidoidcgo_DATA) \
diff --git a/src/client/Disfluid-0.h b/src/client/Disfluid-0.h
new file mode 100644
index 0000000..52afe0c
--- /dev/null
+++ b/src/client/Disfluid-0.h
@@ -0,0 +1,126 @@
+// disfluid, implementation of the Solid specification
+// Copyright (C) 2020, 2021 Vivien Kraus
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+#ifndef H_DISFLUID_INCLUDED
+#define H_DISFLUID_INCLUDED
+
+#include <stdlib.h>
+
+/**
+ * DisfluidApi:
+ *
+ * The context associated with the API is loaded when entering the
+ * @disfluid_init function, and unloaded when the function exits.
+ */
+struct DisfluidApi;
+typedef struct DisfluidApi DisfluidApi;
+
+/**
+ * DisfluidUser:
+ *
+ * @data: (closure):
+ *
+ * The type of function that is called with the API loaded.
+ */
+typedef void *(*DisfluidUser) (const struct DisfluidApi * api, void *data);
+
+/**
+ * disfluid_api_init:
+ *
+ * @func: (scope call) (not nullable): the function to call with the API loaded.
+ * @data: (closure func): the second argument for @func.
+ *
+ * Call @func in a context where the API function can be called. The
+ * API is unloaded when the function exits.
+ *
+ * Returns: (transfer none): the result of the callback.
+ */
+void *disfluid_api_init (DisfluidUser func, void *data);
+
+/**
+ * DisfluidClient: (unref-func disfluid_client_free):
+ *
+ * A client contains a client ID, redirection URI and an associated
+ * key pair.
+ */
+struct DisfluidClient;
+typedef struct DisfluidClient DisfluidClient;
+
+/**
+ * disfluid_client_make:
+ * @api: the context loaded with @disfluid_init.
+ * @client_id: the URI serving a client manifest on the web.
+ * @redirect_uri: the URI where we can get back an authorization code.
+ * @jwk: the JWK encoding of the key pair used by the client.
+ *
+ * Create a new client.
+ *
+ * Returns: (transfer full): the allocated client.
+ */
+struct DisfluidClient *disfluid_client_make (const struct DisfluidApi *api,
+ const char *client_id,
+ const char *redirect_uri,
+ const char *jwk);
+
+/**
+ * disfluid_client_free:
+ * @client: the client to free.
+ *
+ * Delete @client.
+ */
+void disfluid_client_free (struct DisfluidClient *client);
+
+/**
+ * disfluid_client_get_id:
+ * @api: the context API.
+ * @client: the client whose ID to lookup.
+ * @start: how many URL prefix bytes to skip.
+ * @max: how many URL bytes to copy after the skipped prefix.
+ * @id: (array length=max) (element-type char): where to copy the URL bytes.
+ * Returns: the total number of bytes in the URL.
+ */
+size_t disfluid_client_get_id (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max, char *id);
+
+/**
+ * disfluid_client_get_redirect_uri:
+ * @api: the context API.
+ * @client: the client whose redirection URI to lookup.
+ * @start: how many URL prefix bytes to skip.
+ * @max: how many URL bytes to copy after the skipped prefix.
+ * @redirect_uri: (array length=max) (element-type char): where to copy the URL bytes.
+ * Returns: the total number of bytes in the URL.
+ */
+size_t disfluid_client_get_redirect_uri (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max,
+ char *redirect_uri);
+
+/**
+ * disfluid_client_get_key_pair:
+ * @api: the context API.
+ * @client: the client whose key pair to dump.
+ * @start: how many JWK prefix bytes to skip.
+ * @max: how many JWK bytes to copy after the skipped prefix.
+ * @jwk: (array length=max) (element-type char): where to copy the JWK bytes.
+ * Returns: the total number of bytes in the JWK.
+ */
+size_t disfluid_client_get_key_pair (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max, char *jwk);
+
+#endif
diff --git a/src/client/Makefile.am b/src/client/Makefile.am
new file mode 100644
index 0000000..20a17a7
--- /dev/null
+++ b/src/client/Makefile.am
@@ -0,0 +1,25 @@
+# disfluid, implementation of the Solid specification
+# Copyright (C) 2020, 2021 Vivien Kraus
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES += %reldir%/libwebidoidc-client.la
+
+include_HEADERS += %reldir%/Disfluid-0.h
+
+%canon_reldir%_libwebidoidc_client_la_LIBADD = $(GUILE_LIBS)
+
+AM_CFLAGS += -I %reldir% -I $(srcdir)/%reldir%
+
+INDENTED += %reldir%/libwebidoidc-client.c %reldir%/Disfluid-0.h
diff --git a/src/client/libwebidoidc-client.c b/src/client/libwebidoidc-client.c
new file mode 100644
index 0000000..8c22cc6
--- /dev/null
+++ b/src/client/libwebidoidc-client.c
@@ -0,0 +1,144 @@
+// disfluid, implementation of the Solid specification
+// Copyright (C) 2020, 2021 Vivien Kraus
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+#include <Disfluid-0.h>
+#include <libguile.h>
+#include <string.h>
+
+struct DisfluidApi
+{
+ SCM scm_make_client;
+ SCM scm_get_client_id;
+ SCM scm_get_key_pair;
+ SCM scm_get_redirect_uri;
+};
+
+struct user_code
+{
+ DisfluidUser func;
+ void *data;
+};
+
+static void *
+inner_guile (void *data)
+{
+ struct user_code *user = data;
+ struct DisfluidApi api;
+ api.scm_make_client =
+ scm_c_public_ref ("webid-oidc client reverse-stubs", "make-client");
+ api.scm_get_client_id =
+ scm_c_public_ref ("webid-oidc client reverse-stubs", "get-client-id");
+ api.scm_get_key_pair =
+ scm_c_public_ref ("webid-oidc client reverse-stubs", "get-key-pair");
+ api.scm_get_redirect_uri =
+ scm_c_public_ref ("webid-oidc client reverse-stubs", "get-redirect-uri");
+ return user->func (&api, user->data);
+}
+
+void *
+disfluid_api_init (DisfluidUser func, void *data)
+{
+ struct user_code code;
+ code.func = func;
+ code.data = data;
+ return scm_with_guile (inner_guile, &code);
+}
+
+struct DisfluidClient
+{
+ SCM object;
+};
+
+struct DisfluidClient *
+disfluid_client_make (const struct DisfluidApi *api,
+ const char *client_id,
+ const char *redirect_uri, const char *jwk)
+{
+ SCM scm_client_id = scm_from_utf8_string (client_id);
+ SCM scm_redirect_uri = scm_from_utf8_string (redirect_uri);
+ SCM scm_jwk = SCM_BOOL_F;
+ if (jwk)
+ {
+ scm_jwk = scm_from_utf8_string (jwk);
+ }
+ SCM object =
+ scm_call_3 (api->scm_make_client, scm_client_id, scm_redirect_uri,
+ scm_jwk);
+ scm_dynwind_begin (0);
+ struct DisfluidClient *ret = scm_malloc (sizeof (struct DisfluidClient));
+ scm_dynwind_unwind_handler (free, ret, 0);
+ ret->object = scm_gc_protect_object (object);
+ scm_dynwind_end ();
+ return ret;
+}
+
+void
+disfluid_client_free (struct DisfluidClient *client)
+{
+ scm_gc_unprotect_object (client->object);
+ free (client);
+}
+
+static size_t
+copy_scm_string (SCM string, size_t start, size_t max, char *dest)
+{
+ size_t total_length = 0;
+ scm_dynwind_begin (0);
+ char *all_bytes = scm_to_utf8_stringn (string, &total_length);
+ scm_dynwind_free (all_bytes);
+ const size_t requested_length = max;
+ const size_t available_length = total_length - start;
+ size_t copied_length = requested_length;
+ if (available_length < copied_length)
+ {
+ copied_length = available_length;
+ }
+ memcpy (dest, all_bytes + start, copied_length);
+ if (copied_length < max)
+ {
+ dest[copied_length] = '\0';
+ }
+ scm_dynwind_end ();
+ return total_length;
+}
+
+size_t
+disfluid_client_get_id (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max, char *id)
+{
+ SCM scm_id = scm_call_1 (api->scm_get_client_id, client->object);
+ return copy_scm_string (scm_id, start, max, id);
+}
+
+size_t
+disfluid_client_get_key_pair (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max, char *jwk)
+{
+ SCM scm_jwk = scm_call_1 (api->scm_get_key_pair, client->object);
+ return copy_scm_string (scm_jwk, start, max, jwk);
+}
+
+size_t
+disfluid_client_get_redirect_uri (const struct DisfluidApi *api,
+ const struct DisfluidClient *client,
+ size_t start, size_t max,
+ char *redirect_uri)
+{
+ SCM scm_uri = scm_call_1 (api->scm_get_redirect_uri, client->object);
+ return copy_scm_string (scm_uri, start, max, redirect_uri);
+}
diff --git a/src/scm/webid-oidc/client/Makefile.am b/src/scm/webid-oidc/client/Makefile.am
index 8ecf7d5..7d999dc 100644
--- a/src/scm/webid-oidc/client/Makefile.am
+++ b/src/scm/webid-oidc/client/Makefile.am
@@ -18,12 +18,14 @@ dist_clientwebidoidcmod_DATA += \
%reldir%/accounts.scm \
%reldir%/client.scm \
%reldir%/application.scm \
- %reldir%/gui.scm
+ %reldir%/gui.scm \
+ %reldir%/reverse-stubs.scm
clientwebidoidcgo_DATA += \
%reldir%/accounts.go \
%reldir%/client.go \
%reldir%/application.go \
- %reldir%/gui.go
+ %reldir%/gui.go \
+ %reldir%/reverse-stubs.go
include %reldir%/gui/Makefile.am
diff --git a/src/scm/webid-oidc/client/reverse-stubs.scm b/src/scm/webid-oidc/client/reverse-stubs.scm
new file mode 100644
index 0000000..faecf83
--- /dev/null
+++ b/src/scm/webid-oidc/client/reverse-stubs.scm
@@ -0,0 +1,50 @@
+;; disfluid, implementation of the Solid specification
+;; Copyright (C) 2021 Vivien Kraus
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+;; You should have received a copy of the GNU Affero General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define-module (webid-oidc client reverse-stubs)
+ #:use-module (webid-oidc client)
+ #:use-module (webid-oidc client accounts)
+ #:use-module (webid-oidc client application)
+ #:use-module (webid-oidc jwk)
+ #:use-module ((webid-oidc stubs) #:prefix stubs:)
+ #:duplicates (merge-generics)
+ #:declarative? #t
+ #:export
+ (
+ make-client
+ get-client-id
+ get-client-jwk
+ get-client-redirect-uri
+ ))
+
+(define (make-client client-id jwk redirect-uri)
+ (make <client>
+ #:client-id client-id
+ #:key-pair
+ (if jwk
+ (jwk->key (stubs:json-string->scm jwk))
+ ;; Generate a new one:
+ #t)
+ #:redirect-uri redirect-uri))
+
+(define (get-client-id client)
+ (uri->string (client-id client)))
+
+(define (get-key-pair client)
+ (stubs:scm->json-string (key->jwk (key-pair client))))
+
+(define (get-redirect-uri client)
+ (uri->string (redirect-uri client)))