// 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 .
#include
#include
#include
struct DisfluidApi
{
SCM scm_make_client;
SCM scm_get_client_id;
SCM scm_get_client_jwk;
SCM scm_get_client_redirect_uri;
SCM scm_make_account_full;
SCM scm_get_account_subject;
SCM scm_get_account_issuer;
SCM scm_get_account_key_pair;
SCM scm_get_account_id_token_header;
SCM scm_get_account_id_token;
SCM scm_get_account_access_token;
SCM scm_get_account_refresh_token;
};
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_client_jwk =
scm_c_public_ref ("webid-oidc client reverse-stubs", "get-client-jwk");
api.scm_get_client_redirect_uri =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-client-redirect-uri");
api.scm_make_account_full =
scm_c_public_ref ("webid-oidc client reverse-stubs", "make-account-full");
api.scm_get_account_subject =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-subject");
api.scm_get_account_issuer =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-issuer");
api.scm_get_account_key_pair =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-key-pair");
api.scm_get_account_id_token_header =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-id-token-header");
api.scm_get_account_id_token =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-id-token");
api.scm_get_account_access_token =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-access-token");
api.scm_get_account_refresh_token =
scm_c_public_ref ("webid-oidc client reverse-stubs",
"get-account-refresh-token");
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;
};
void
disfluid_api_make_client (const struct DisfluidApi *api,
struct DisfluidClient **client,
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);
*client = scm_malloc (sizeof (struct DisfluidClient));
scm_dynwind_unwind_handler (free, *client, 0);
(*client)->object = scm_gc_protect_object (object);
scm_dynwind_end ();
}
void
disfluid_client_free (struct DisfluidClient *client)
{
if (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 = NULL;
if (scm_is_true (string))
{
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 DisfluidClient *client,
const struct DisfluidApi *api,
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 DisfluidClient *client,
const struct DisfluidApi *api,
size_t start, size_t max, char *jwk)
{
SCM scm_jwk = scm_call_1 (api->scm_get_client_jwk, client->object);
return copy_scm_string (scm_jwk, start, max, jwk);
}
size_t
disfluid_client_get_redirect_uri (const struct DisfluidClient *client,
const struct DisfluidApi *api,
size_t start, size_t max,
char *redirect_uri)
{
SCM scm_uri = scm_call_1 (api->scm_get_client_redirect_uri, client->object);
return copy_scm_string (scm_uri, start, max, redirect_uri);
}
struct DisfluidAccount
{
SCM object;
};
void
disfluid_api_make_account (const struct DisfluidApi *api,
struct DisfluidAccount **account,
const char *subject,
const char *issuer,
const char *key_pair,
const char *id_token_header,
const char *id_token,
const char *access_token,
const char *refresh_token)
{
SCM scm_subject = scm_from_utf8_string (subject);
SCM scm_issuer = scm_from_utf8_string (issuer);
SCM scm_key_pair = scm_from_utf8_string (key_pair);
SCM scm_id_token_header = SCM_BOOL_F;
SCM scm_id_token = SCM_BOOL_F;
SCM scm_access_token = SCM_BOOL_F;
SCM scm_refresh_token = SCM_BOOL_F;
if (id_token_header)
{
scm_id_token_header = scm_from_utf8_string (id_token_header);
}
if (id_token)
{
scm_id_token = scm_from_utf8_string (id_token);
}
if (access_token)
{
scm_access_token = scm_from_utf8_string (access_token);
}
if (refresh_token)
{
scm_refresh_token = scm_from_utf8_string (refresh_token);
}
}
void
disfluid_account_free (struct DisfluidAccount *account)
{
if (account)
{
scm_gc_unprotect_object (account->object);
}
free (account);
}
size_t
disfluid_account_get_subject (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *subject)
{
SCM scm_id = scm_call_1 (api->scm_get_account_subject, account->object);
return copy_scm_string (scm_id, start, max, subject);
}
size_t
disfluid_account_get_issuer (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *issuer)
{
SCM scm_id = scm_call_1 (api->scm_get_account_issuer, account->object);
return copy_scm_string (scm_id, start, max, issuer);
}
size_t
disfluid_account_get_key_pair (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *jwk)
{
SCM scm_id = scm_call_1 (api->scm_get_account_key_pair, account->object);
return copy_scm_string (scm_id, start, max, jwk);
}
size_t
disfluid_account_get_id_token_header (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *header)
{
SCM scm_id =
scm_call_1 (api->scm_get_account_id_token_header, account->object);
return copy_scm_string (scm_id, start, max, header);
}
size_t
disfluid_account_get_id_token (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *token)
{
SCM scm_id = scm_call_1 (api->scm_get_account_id_token, account->object);
return copy_scm_string (scm_id, start, max, token);
}
size_t
disfluid_account_get_access_token (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *token)
{
SCM scm_id =
scm_call_1 (api->scm_get_account_access_token, account->object);
return copy_scm_string (scm_id, start, max, token);
}
size_t
disfluid_account_get_refresh_token (const struct DisfluidAccount *account,
const struct DisfluidApi *api,
size_t start, size_t max, char *token)
{
SCM scm_id =
scm_call_1 (api->scm_get_account_refresh_token, account->object);
return copy_scm_string (scm_id, start, max, token);
}