Reimplement handling of BAD_AUTH inside browser_window
We now handle authentication requests via an `about:` page which presents a nice form built into the browser window. In order to do this, we add internal navigation as a concept to the browser window and we strip the 401login support from all frontends except monkey. The 401login callback is now intended for password safe type support rather than an immediately interactive prompt. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
This commit is contained in:
parent
9c9c26a308
commit
8469f4cc8e
|
@ -712,6 +712,23 @@ fetch_multipart_data_clone(const struct fetch_multipart_data *list)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in content/fetch.h */
|
||||
const char *
|
||||
fetch_multipart_data_find(const struct fetch_multipart_data *list,
|
||||
const char *name)
|
||||
{
|
||||
while (list != NULL) {
|
||||
if (strcmp(list->name, name) == 0) {
|
||||
return list->value;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in content/fetch.h */
|
||||
void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
|
||||
{
|
||||
|
@ -730,6 +747,43 @@ void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in content/fetch.h */
|
||||
nserror
|
||||
fetch_multipart_data_new_kv(struct fetch_multipart_data **list,
|
||||
const char *name,
|
||||
const char *value)
|
||||
{
|
||||
struct fetch_multipart_data *newdata;
|
||||
|
||||
assert(list);
|
||||
|
||||
newdata = calloc(sizeof(*newdata), 1);
|
||||
|
||||
if (newdata == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
newdata->name = strdup(name);
|
||||
if (newdata->name == NULL) {
|
||||
free(newdata);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
newdata->value = strdup(value);
|
||||
if (newdata->value == NULL) {
|
||||
free(newdata->name);
|
||||
free(newdata);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
newdata->next = *list;
|
||||
*list = newdata;
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in content/fetch.h */
|
||||
void
|
||||
fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
|
||||
|
|
|
@ -184,6 +184,30 @@ void fetch_multipart_data_destroy(struct fetch_multipart_data *list);
|
|||
*/
|
||||
struct fetch_multipart_data *fetch_multipart_data_clone(const struct fetch_multipart_data *list);
|
||||
|
||||
/**
|
||||
* Find an entry in a fetch_multipart_data
|
||||
*
|
||||
* \param list Pointer to the multipart list
|
||||
* \param name The name to look for in the list
|
||||
* \return The value found, or NULL if not present
|
||||
*/
|
||||
const char *fetch_multipart_data_find(const struct fetch_multipart_data *list,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Create an entry for a fetch_multipart_data
|
||||
*
|
||||
* If an entry exists of the same name, it will *NOT* be overwritten
|
||||
*
|
||||
* \param list Pointer to the pointer to the current multipart list
|
||||
* \param name The name of the entry to create
|
||||
* \param value The value of the entry to create
|
||||
* \return The result of the attempt
|
||||
*/
|
||||
nserror fetch_multipart_data_new_kv(struct fetch_multipart_data **list,
|
||||
const char *name,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* send message to fetch
|
||||
*/
|
||||
|
|
|
@ -2290,7 +2290,7 @@ static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
|
|||
event.type = LLCACHE_EVENT_ERROR;
|
||||
/** \todo More appropriate error message */
|
||||
event.data.error.code = NSERROR_BAD_AUTH;
|
||||
event.data.error.msg = messages_get("FetchFailed");
|
||||
event.data.error.msg = realm;
|
||||
|
||||
error = llcache_send_event_to_users(object, &event);
|
||||
} else {
|
||||
|
|
|
@ -167,6 +167,8 @@ struct browser_window {
|
|||
bool throbbing;
|
||||
/** Add loading_content to the window history when it loads. */
|
||||
bool history_add;
|
||||
/** Internal navigation, do not update URL etc */
|
||||
bool internal_nav;
|
||||
|
||||
/** Fragment identifier for current_content. */
|
||||
lwc_string *frag_id;
|
||||
|
|
|
@ -91,6 +91,33 @@ static nserror browser_window__navigate_internal(
|
|||
struct browser_window *bw, struct browser_fetch_parameters *params);
|
||||
|
||||
|
||||
/**
|
||||
* Close and destroy all child browser window.
|
||||
*
|
||||
* \param bw browser window
|
||||
*/
|
||||
static void browser_window_destroy_children(struct browser_window *bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bw->children) {
|
||||
for (i = 0; i < (bw->rows * bw->cols); i++)
|
||||
browser_window_destroy_internal(&bw->children[i]);
|
||||
free(bw->children);
|
||||
bw->children = NULL;
|
||||
bw->rows = 0;
|
||||
bw->cols = 0;
|
||||
}
|
||||
if (bw->iframes) {
|
||||
for (i = 0; i < bw->iframe_count; i++)
|
||||
browser_window_destroy_internal(&bw->iframes[i]);
|
||||
free(bw->iframes);
|
||||
bw->iframes = NULL;
|
||||
bw->iframe_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the stored fetch parameters
|
||||
*
|
||||
|
@ -679,14 +706,16 @@ static nserror browser_window_content_ready(struct browser_window *bw)
|
|||
bw->current_content = bw->loading_content;
|
||||
bw->loading_content = NULL;
|
||||
|
||||
/* Transfer the fetch parameters */
|
||||
browser_window__free_fetch_parameters(&bw->current_parameters);
|
||||
bw->current_parameters = bw->loading_parameters;
|
||||
memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters));
|
||||
if (!bw->internal_nav) {
|
||||
/* Transfer the fetch parameters */
|
||||
browser_window__free_fetch_parameters(&bw->current_parameters);
|
||||
bw->current_parameters = bw->loading_parameters;
|
||||
memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters));
|
||||
/* Transfer the SSL info */
|
||||
bw->current_ssl_info = bw->loading_ssl_info;
|
||||
bw->loading_ssl_info.num = 0;
|
||||
}
|
||||
|
||||
/* Transfer the SSL info */
|
||||
bw->current_ssl_info = bw->loading_ssl_info;
|
||||
bw->loading_ssl_info.num = 0;
|
||||
|
||||
/* Format the new content to the correct dimensions */
|
||||
browser_window_get_dimensions(bw, &width, &height);
|
||||
|
@ -800,7 +829,9 @@ browser_window_content_done(struct browser_window *bw)
|
|||
}
|
||||
|
||||
browser_window_history_update(bw, bw->current_content);
|
||||
hotlist_update_url(hlcache_handle_get_url(bw->current_content));
|
||||
if (!bw->internal_nav) {
|
||||
hotlist_update_url(hlcache_handle_get_url(bw->current_content));
|
||||
}
|
||||
|
||||
if (bw->refresh_interval != -1) {
|
||||
guit->misc->schedule(bw->refresh_interval * 10,
|
||||
|
@ -810,12 +841,8 @@ browser_window_content_done(struct browser_window *bw)
|
|||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/* Cheeky import for now */
|
||||
nserror netsurf__handle_login(const char * realm, nsurl *url,
|
||||
browser_window_query_callback cb, void *cbpw);
|
||||
|
||||
/**
|
||||
* Handle query responses from authentication or SSL requests
|
||||
* Handle query responses from SSL requests
|
||||
*/
|
||||
static nserror
|
||||
browser_window__handle_query_response(bool proceed, void *pw)
|
||||
|
@ -837,6 +864,215 @@ browser_window__handle_query_response(bool proceed, void *pw)
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a "username:password" to components.
|
||||
*
|
||||
* \param[in] userpass The input string to split.
|
||||
* \param[in] username_out Returns username on success. Owned by caller.
|
||||
* \param[out] password_out Returns password on success. Owned by caller.
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
static nserror
|
||||
browser_window__unpack_userpass(const char *userpass,
|
||||
char **username_out,
|
||||
char **password_out)
|
||||
{
|
||||
const char *tmp;
|
||||
char *username;
|
||||
char *password;
|
||||
size_t len;
|
||||
|
||||
if (userpass == NULL) {
|
||||
username = malloc(1);
|
||||
password = malloc(1);
|
||||
if (username == NULL || password == NULL) {
|
||||
free(username);
|
||||
free(password);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
username[0] = '\0';
|
||||
password[0] = '\0';
|
||||
|
||||
*username_out = username;
|
||||
*password_out = password;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
tmp = strchr(userpass, ':');
|
||||
if (tmp == NULL) {
|
||||
return NSERROR_BAD_PARAMETER;
|
||||
} else {
|
||||
size_t len2;
|
||||
len = tmp - userpass;
|
||||
len2 = strlen(++tmp);
|
||||
|
||||
username = malloc(len + 1);
|
||||
password = malloc(len2 + 1);
|
||||
if (username == NULL || password == NULL) {
|
||||
free(username);
|
||||
free(password);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
memcpy(username, userpass, len);
|
||||
username[len] = '\0';
|
||||
memcpy(password, tmp, len2 + 1);
|
||||
}
|
||||
|
||||
*username_out = username;
|
||||
*password_out = password;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "username:password" from components.
|
||||
*
|
||||
* \param[in] username The username component.
|
||||
* \param[in] password The password component.
|
||||
* \param[out] userpass_out Returns combined string on success.
|
||||
* Owned by caller.
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
static nserror
|
||||
browser_window__build_userpass(const char *username,
|
||||
const char *password,
|
||||
char **userpass_out)
|
||||
{
|
||||
char *userpass;
|
||||
size_t len;
|
||||
|
||||
len = strlen(username) + 1 + strlen(password) + 1;
|
||||
|
||||
userpass = malloc(len);
|
||||
if (userpass == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
snprintf(userpass, len, "%s:%s", username, password);
|
||||
|
||||
*userpass_out = userpass;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a response from the UI when prompted for credentials
|
||||
*/
|
||||
static nserror
|
||||
browser_window__handle_userpass_response(nsurl *url,
|
||||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *pw)
|
||||
{
|
||||
struct browser_window *bw = (struct browser_window *)pw;
|
||||
char *userpass;
|
||||
nserror err;
|
||||
|
||||
err = browser_window__build_userpass(username, password, &userpass);
|
||||
if (err != NSERROR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
urldb_set_auth_details(url, realm, userpass);
|
||||
|
||||
free(userpass);
|
||||
|
||||
/**
|
||||
* \todo QUERY - Eventually this should fill out the form *NOT* nav
|
||||
* to the original location
|
||||
*/
|
||||
/* Finally navigate to the original loading parameters */
|
||||
if (bw->loading_content != NULL) {
|
||||
/* We had a loading content (maybe auth page?) */
|
||||
browser_window_stop(bw);
|
||||
browser_window_remove_caret(bw, false);
|
||||
browser_window_destroy_children(bw);
|
||||
}
|
||||
bw->internal_nav = false;
|
||||
return browser_window__navigate_internal(bw, &bw->loading_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle login request (BAD_AUTH) during fetch
|
||||
*
|
||||
*/
|
||||
static nserror
|
||||
browser_window__handle_login(struct browser_window *bw,
|
||||
const char *realm,
|
||||
nsurl *url) {
|
||||
char *username = NULL, *password = NULL;
|
||||
nserror err = NSERROR_OK;
|
||||
struct browser_fetch_parameters params;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
/* Step one, retrieve what we have */
|
||||
err = browser_window__unpack_userpass(
|
||||
urldb_get_auth_details(url, realm),
|
||||
&username, &password);
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Step two, construct our fetch parameters */
|
||||
err = nsurl_create("about:query/auth", ¶ms.url);
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
params.referrer = nsurl_ref(url);
|
||||
params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
|
||||
|
||||
err = fetch_multipart_data_new_kv(¶ms.post_multipart,
|
||||
"siteurl",
|
||||
nsurl_access(url));
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = fetch_multipart_data_new_kv(¶ms.post_multipart,
|
||||
"realm",
|
||||
realm);
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = fetch_multipart_data_new_kv(¶ms.post_multipart,
|
||||
"username",
|
||||
username);
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = fetch_multipart_data_new_kv(¶ms.post_multipart,
|
||||
"password",
|
||||
password);
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now we issue the fetch */
|
||||
bw->internal_nav = true;
|
||||
err = browser_window__navigate_internal(bw, ¶ms);
|
||||
|
||||
if (err != NSERROR_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = guit->misc->login(url, realm, username, password,
|
||||
browser_window__handle_userpass_response, bw);
|
||||
|
||||
if (err == NSERROR_NOT_IMPLEMENTED) {
|
||||
err = NSERROR_OK;
|
||||
}
|
||||
out:
|
||||
if (username != NULL) {
|
||||
free(username);
|
||||
}
|
||||
if (password != NULL) {
|
||||
free(password);
|
||||
}
|
||||
browser_window__free_fetch_parameters(¶ms);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle errors during content fetch
|
||||
|
@ -891,9 +1127,7 @@ browser_window__handle_error(struct browser_window *bw,
|
|||
|
||||
switch (code) {
|
||||
case NSERROR_BAD_AUTH:
|
||||
res = netsurf__handle_login(message, url,
|
||||
browser_window__handle_query_response,
|
||||
bw);
|
||||
res = browser_window__handle_login(bw, message, url);
|
||||
break;
|
||||
case NSERROR_BAD_CERTS:
|
||||
res = guit->misc->cert_verify(url,
|
||||
|
@ -1234,33 +1468,6 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close and destroy all child browser window.
|
||||
*
|
||||
* \param bw browser window
|
||||
*/
|
||||
static void browser_window_destroy_children(struct browser_window *bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bw->children) {
|
||||
for (i = 0; i < (bw->rows * bw->cols); i++)
|
||||
browser_window_destroy_internal(&bw->children[i]);
|
||||
free(bw->children);
|
||||
bw->children = NULL;
|
||||
bw->rows = 0;
|
||||
bw->cols = 0;
|
||||
}
|
||||
if (bw->iframes) {
|
||||
for (i = 0; i < bw->iframe_count; i++)
|
||||
browser_window_destroy_internal(&bw->iframes[i]);
|
||||
free(bw->iframes);
|
||||
bw->iframes = NULL;
|
||||
bw->iframe_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* internal scheduled reformat callback.
|
||||
*
|
||||
|
@ -2717,12 +2924,23 @@ nserror browser_window_refresh_url_bar(struct browser_window *bw)
|
|||
ret = browser_window_refresh_url_bar_internal(bw,
|
||||
corestring_nsurl_about_blank);
|
||||
} else if (bw->frag_id == NULL) {
|
||||
ret = browser_window_refresh_url_bar_internal(bw,
|
||||
hlcache_handle_get_url(bw->current_content));
|
||||
nsurl *url;
|
||||
if (bw->internal_nav) {
|
||||
url = bw->loading_parameters.url;
|
||||
} else {
|
||||
url = hlcache_handle_get_url(bw->current_content);
|
||||
}
|
||||
ret = browser_window_refresh_url_bar_internal(bw, url);
|
||||
} else {
|
||||
/* Combine URL and Fragment */
|
||||
nsurl *url;
|
||||
if (bw->internal_nav) {
|
||||
url = bw->loading_parameters.url;
|
||||
} else {
|
||||
url = hlcache_handle_get_url(bw->current_content);
|
||||
}
|
||||
ret = nsurl_refragment(
|
||||
hlcache_handle_get_url(bw->current_content),
|
||||
url,
|
||||
bw->frag_id, &display_url);
|
||||
if (ret == NSERROR_OK) {
|
||||
ret = browser_window_refresh_url_bar_internal(bw,
|
||||
|
@ -2752,12 +2970,38 @@ browser_window_navigate(struct browser_window *bw,
|
|||
llcache_post_data post;
|
||||
hlcache_child_context child;
|
||||
nserror error;
|
||||
bool is_internal = false;
|
||||
struct browser_fetch_parameters params, *pass_params = NULL;
|
||||
lwc_string *scheme, *path;
|
||||
|
||||
assert(bw);
|
||||
assert(url);
|
||||
|
||||
NSLOG(netsurf, INFO, "bw %p, url %s", bw, nsurl_access(url));
|
||||
|
||||
/* Check if this is an internal navigation URL, if so, we do not
|
||||
* do certain things during the load
|
||||
*/
|
||||
scheme = nsurl_get_component(url, NSURL_SCHEME);
|
||||
path = nsurl_get_component(url, NSURL_PATH);
|
||||
if (scheme == corestring_lwc_about) {
|
||||
if (path == corestring_lwc_query_auth) {
|
||||
is_internal = true;
|
||||
}
|
||||
}
|
||||
lwc_string_unref(scheme);
|
||||
lwc_string_unref(path);
|
||||
|
||||
if (is_internal &&
|
||||
!(flags & BW_NAVIGATE_INTERNAL)) {
|
||||
/* Internal navigation detected, but flag not set, only allow
|
||||
* this is there's a fetch multipart
|
||||
*/
|
||||
if (post_multipart == NULL) {
|
||||
return NSERROR_NEED_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're navigating and we have a history entry and a content
|
||||
* then update the history entry before we navigate to save our
|
||||
* current state. However since history navigation pre-moves
|
||||
|
@ -2768,6 +3012,7 @@ browser_window_navigate(struct browser_window *bw,
|
|||
if (bw->current_content != NULL &&
|
||||
bw->history != NULL &&
|
||||
bw->history->current != NULL &&
|
||||
!is_internal &&
|
||||
!(flags & BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE)) {
|
||||
browser_window_history_update(bw, bw->current_content);
|
||||
}
|
||||
|
@ -2872,31 +3117,43 @@ browser_window_navigate(struct browser_window *bw,
|
|||
browser_window_remove_caret(bw, false);
|
||||
browser_window_destroy_children(bw);
|
||||
|
||||
/* At this point, we're navigating, so store the fetch parameters */
|
||||
browser_window__free_fetch_parameters(&bw->loading_parameters);
|
||||
/* Set up the fetch parameters */
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
bw->loading_parameters.url = nsurl_ref(url);
|
||||
params.url = nsurl_ref(url);
|
||||
|
||||
if (referrer != NULL) {
|
||||
bw->loading_parameters.referrer = nsurl_ref(referrer);
|
||||
params.referrer = nsurl_ref(referrer);
|
||||
}
|
||||
|
||||
bw->loading_parameters.flags = flags;
|
||||
params.flags = flags;
|
||||
|
||||
if (post_urlenc != NULL) {
|
||||
bw->loading_parameters.post_urlenc = strdup(post_urlenc);
|
||||
params.post_urlenc = strdup(post_urlenc);
|
||||
}
|
||||
|
||||
if (post_multipart != NULL) {
|
||||
bw->loading_parameters.post_multipart = fetch_multipart_data_clone(post_multipart);
|
||||
params.post_multipart = fetch_multipart_data_clone(post_multipart);
|
||||
}
|
||||
|
||||
if (parent != NULL) {
|
||||
bw->loading_parameters.parent_charset = strdup(child.charset);
|
||||
bw->loading_parameters.parent_quirks = child.quirks;
|
||||
params.parent_charset = strdup(child.charset);
|
||||
params.parent_quirks = child.quirks;
|
||||
}
|
||||
|
||||
error = browser_window__navigate_internal(bw, &bw->loading_parameters);
|
||||
bw->internal_nav = is_internal;
|
||||
|
||||
if (is_internal) {
|
||||
pass_params = ¶ms;
|
||||
} else {
|
||||
/* At this point, we're navigating, so store the fetch parameters */
|
||||
browser_window__free_fetch_parameters(&bw->loading_parameters);
|
||||
memcpy(&bw->loading_parameters, ¶ms, sizeof(params));
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
pass_params = &bw->loading_parameters;
|
||||
}
|
||||
|
||||
error = browser_window__navigate_internal(bw, pass_params);
|
||||
|
||||
nsurl_unref(url);
|
||||
|
||||
|
@ -2904,12 +3161,16 @@ browser_window_navigate(struct browser_window *bw,
|
|||
nsurl_unref(referrer);
|
||||
}
|
||||
|
||||
if (is_internal) {
|
||||
browser_window__free_fetch_parameters(¶ms);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
nserror
|
||||
browser_window__navigate_internal(struct browser_window *bw,
|
||||
struct browser_fetch_parameters *params)
|
||||
static nserror
|
||||
browser_window__navigate_internal_real(struct browser_window *bw,
|
||||
struct browser_fetch_parameters *params)
|
||||
{
|
||||
uint32_t fetch_flags = 0;
|
||||
bool fetch_is_post = (params->post_urlenc != NULL || params->post_multipart != NULL);
|
||||
|
@ -2985,6 +3246,118 @@ browser_window__navigate_internal(struct browser_window *bw,
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal navigation handler for the authentication query handler
|
||||
*
|
||||
* If the parameters indicate we're processing a *response* from the handler
|
||||
* then we deal with that, otherwise we pass it on to the about: handler
|
||||
*/
|
||||
static nserror
|
||||
browser_window__navigate_internal_query_auth(struct browser_window *bw,
|
||||
struct browser_fetch_parameters *params)
|
||||
{
|
||||
char *userpass = NULL;
|
||||
const char *username, *password, *realm, *siteurl;
|
||||
nsurl *sitensurl;
|
||||
nserror res;
|
||||
bool is_login = false, is_cancel = false;
|
||||
|
||||
assert(params->post_multipart != NULL);
|
||||
|
||||
is_login = fetch_multipart_data_find(params->post_multipart, "login") != NULL;
|
||||
is_cancel = fetch_multipart_data_find(params->post_multipart, "cancel") != NULL;
|
||||
|
||||
if (!(is_login || is_cancel)) {
|
||||
/* This is a request, so pass it on */
|
||||
return browser_window__navigate_internal_real(bw, params);
|
||||
}
|
||||
|
||||
if (is_cancel) {
|
||||
/* We're processing a cancel, do a rough-and-ready nav to
|
||||
* about:blank
|
||||
*/
|
||||
browser_window__free_fetch_parameters(&bw->loading_parameters);
|
||||
res = nsurl_create("about:blank", &bw->loading_parameters.url);
|
||||
if (res != NSERROR_OK) {
|
||||
return res;
|
||||
}
|
||||
bw->loading_parameters.flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
|
||||
bw->internal_nav = true;
|
||||
return browser_window__navigate_internal(bw, &bw->loading_parameters);
|
||||
}
|
||||
|
||||
/* We're processing a "login" attempt from the form */
|
||||
|
||||
/* Retrieve the data */
|
||||
username = fetch_multipart_data_find(params->post_multipart, "username");
|
||||
password = fetch_multipart_data_find(params->post_multipart, "password");
|
||||
realm = fetch_multipart_data_find(params->post_multipart, "realm");
|
||||
siteurl = fetch_multipart_data_find(params->post_multipart, "siteurl");
|
||||
|
||||
if (username == NULL || password == NULL ||
|
||||
realm == NULL || siteurl == NULL) {
|
||||
/* Bad inputs, simply fail */
|
||||
return NSERROR_INVALID;
|
||||
}
|
||||
|
||||
/* Parse the URL */
|
||||
res = nsurl_create(siteurl, &sitensurl);
|
||||
if (res != NSERROR_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Construct the username/password */
|
||||
res = browser_window__build_userpass(username, password, &userpass);
|
||||
if (res != NSERROR_OK) {
|
||||
nsurl_unref(sitensurl);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* And let urldb know */
|
||||
urldb_set_auth_details(sitensurl, realm, userpass);
|
||||
|
||||
/* Clean up */
|
||||
free(userpass);
|
||||
nsurl_unref(sitensurl);
|
||||
|
||||
/* Finally navigate to the original loading parameters */
|
||||
return browser_window__navigate_internal_real(bw, &bw->loading_parameters);
|
||||
}
|
||||
|
||||
|
||||
nserror
|
||||
browser_window__navigate_internal(struct browser_window *bw,
|
||||
struct browser_fetch_parameters *params)
|
||||
{
|
||||
lwc_string *scheme, *path;
|
||||
/* Here we determine if we're navigating to an internal query URI
|
||||
* and if so, what we need to do about it.
|
||||
*
|
||||
* If we're not, then we just move on to the real navigate.
|
||||
*/
|
||||
|
||||
/* All our special URIs are in the about: scheme */
|
||||
scheme = nsurl_get_component(params->url, NSURL_SCHEME);
|
||||
if (scheme != corestring_lwc_about) {
|
||||
lwc_string_unref(scheme);
|
||||
goto normal_fetch;
|
||||
}
|
||||
lwc_string_unref(scheme);
|
||||
|
||||
/* Is it the auth query handler? */
|
||||
path = nsurl_get_component(params->url, NSURL_PATH);
|
||||
if (path == corestring_lwc_query_auth) {
|
||||
lwc_string_unref(path);
|
||||
return browser_window__navigate_internal_query_auth(bw, params);
|
||||
}
|
||||
lwc_string_unref(path);
|
||||
|
||||
/* Fall through to a normal about: fetch */
|
||||
|
||||
normal_fetch:
|
||||
return browser_window__navigate_internal_real(bw, params);
|
||||
}
|
||||
|
||||
|
||||
/* Exported interface, documented in netsurf/browser_window.h */
|
||||
bool browser_window_up_available(struct browser_window *bw)
|
||||
|
|
|
@ -691,12 +691,14 @@ static nserror gui_default_cert_verify(nsurl *url,
|
|||
return NSERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static nserror gui_default_401login_open(nsurl *url, const char *realm,
|
||||
const char *username, const char *password,
|
||||
nserror (*cb)(const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw)
|
||||
static nserror gui_default_401login_open(
|
||||
nsurl *url, const char *realm,
|
||||
const char *username, const char *password,
|
||||
nserror (*cb)(nsurl *url, const char * realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw)
|
||||
{
|
||||
return NSERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -98,206 +98,6 @@ static void netsurf_lwc_iterator(lwc_string *str, void *pw)
|
|||
(int)lwc_string_length(str), lwc_string_data(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "username:password" from components.
|
||||
*
|
||||
* \param[in] username The username component.
|
||||
* \param[in] password The password component.
|
||||
* \param[out] userpass_out Returns combined string on success.
|
||||
* Owned by caller.
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
static nserror netsurf__build_userpass(
|
||||
const char *username,
|
||||
const char *password,
|
||||
char **userpass_out)
|
||||
{
|
||||
char *userpass;
|
||||
size_t len;
|
||||
|
||||
len = strlen(username) + 1 + strlen(password) + 1;
|
||||
|
||||
userpass = malloc(len);
|
||||
if (userpass == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
snprintf(userpass, len, "%s:%s", username, password);
|
||||
|
||||
*userpass_out = userpass;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a "username:password" to components.
|
||||
*
|
||||
* \param[in] userpass The input string to split.
|
||||
* \param[in] username_out Returns username on success. Owned by caller.
|
||||
* \param[out] password_out Returns password on success. Owned by caller.
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
static nserror netsurf__unpack_userpass(
|
||||
const char *userpass,
|
||||
char **username_out,
|
||||
char **password_out)
|
||||
{
|
||||
const char *tmp;
|
||||
char *username;
|
||||
char *password;
|
||||
size_t len;
|
||||
|
||||
if (userpass == NULL) {
|
||||
username = malloc(1);
|
||||
password = malloc(1);
|
||||
if (username == NULL || password == NULL) {
|
||||
free(username);
|
||||
free(password);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
username[0] = '\0';
|
||||
password[0] = '\0';
|
||||
|
||||
*username_out = username;
|
||||
*password_out = password;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
tmp = strchr(userpass, ':');
|
||||
if (tmp == NULL) {
|
||||
return NSERROR_BAD_PARAMETER;
|
||||
} else {
|
||||
size_t len2;
|
||||
len = tmp - userpass;
|
||||
len2 = strlen(++tmp);
|
||||
|
||||
username = malloc(len + 1);
|
||||
password = malloc(len2 + 1);
|
||||
if (username == NULL || password == NULL) {
|
||||
free(username);
|
||||
free(password);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
memcpy(username, userpass, len);
|
||||
username[len] = '\0';
|
||||
memcpy(password, tmp, len2 + 1);
|
||||
}
|
||||
|
||||
*username_out = username;
|
||||
*password_out = password;
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contect for login callbacks to front ends.
|
||||
*/
|
||||
struct auth_data {
|
||||
char *realm;
|
||||
nsurl *url;
|
||||
|
||||
browser_window_query_callback cb;
|
||||
void *pw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function passed to front ends for handling logins.
|
||||
*
|
||||
* \param[in] username The username.
|
||||
* \param[in] password The password.
|
||||
* \param[in] cbpw Our context.
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
static nserror netsurf__handle_login_response(
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *cbpw)
|
||||
{
|
||||
struct auth_data *ctx = cbpw;
|
||||
bool proceed = false;
|
||||
nserror err;
|
||||
|
||||
if (username != NULL && password != NULL) {
|
||||
char *userpass;
|
||||
|
||||
err = netsurf__build_userpass(username, password, &userpass);
|
||||
if (err != NSERROR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
urldb_set_auth_details(ctx->url, ctx->realm, userpass);
|
||||
free(userpass);
|
||||
proceed = true;
|
||||
}
|
||||
|
||||
err = ctx->cb(proceed, ctx->pw);
|
||||
nsurl_unref(ctx->url);
|
||||
free(ctx->realm);
|
||||
free(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Cheeky */
|
||||
nserror netsurf__handle_login(const char * realm, nsurl *url,
|
||||
browser_window_query_callback cb, void *cbpw);
|
||||
/**
|
||||
* Helper for getting front end to handle logins.
|
||||
*
|
||||
* \param[in] query Query descriptor
|
||||
* \param[in] pw Private data
|
||||
* \param[in] cb Continuation callback
|
||||
* \param[in] cbpw Private data for continuation
|
||||
* \return NSERROR_OK, or appropriate error code.
|
||||
*/
|
||||
nserror netsurf__handle_login(const char * realm, nsurl *url,
|
||||
browser_window_query_callback cb, void *cbpw)
|
||||
{
|
||||
struct auth_data *ctx;
|
||||
char *username;
|
||||
char *password;
|
||||
nserror err;
|
||||
|
||||
NSLOG(llcache, INFO, "HTTP Auth for: %s: %s",
|
||||
realm, nsurl_access(url));
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
ctx->realm = strdup(realm);
|
||||
if (ctx->realm == NULL) {
|
||||
free(ctx);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
ctx->url = nsurl_ref(url);
|
||||
ctx->cb = cb;
|
||||
ctx->pw = cbpw;
|
||||
|
||||
err = netsurf__unpack_userpass(
|
||||
urldb_get_auth_details(ctx->url, ctx->realm),
|
||||
&username, &password);
|
||||
if (err != NSERROR_OK) {
|
||||
nsurl_unref(ctx->url);
|
||||
free(ctx->realm);
|
||||
free(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = guit->misc->login(ctx->url, ctx->realm, username, password,
|
||||
netsurf__handle_login_response, ctx);
|
||||
free(username);
|
||||
free(password);
|
||||
if (err != NSERROR_OK) {
|
||||
ctx->cb(false, ctx->pw);
|
||||
nsurl_unref(ctx->url);
|
||||
free(ctx->realm);
|
||||
free(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in netsurf/netsurf.h */
|
||||
nserror netsurf_init(const char *store_path)
|
||||
{
|
||||
|
|
|
@ -6087,7 +6087,6 @@ static struct gui_misc_table amiga_misc_table = {
|
|||
.quit = gui_quit,
|
||||
.launch_url = gui_launch_url,
|
||||
.cert_verify = ami_cert_verify,
|
||||
.login = gui_401login_open,
|
||||
};
|
||||
|
||||
/** Normal entry point from OS */
|
||||
|
|
|
@ -1108,7 +1108,6 @@ static struct gui_misc_table atari_misc_table = {
|
|||
|
||||
.quit = gui_quit,
|
||||
.cert_verify = gui_cert_verify,
|
||||
.login = gui_401login_open,
|
||||
};
|
||||
|
||||
/* #define WITH_DBG_LOGFILE 1 */
|
||||
|
|
|
@ -997,7 +997,7 @@ static struct gui_misc_table beos_misc_table = {
|
|||
gui_quit,
|
||||
gui_launch_url,
|
||||
NULL, //cert_verify
|
||||
gui_401login_open,
|
||||
NULL, //401login
|
||||
NULL, // pdf_password (if we have Haru support)
|
||||
};
|
||||
|
||||
|
|
|
@ -1073,7 +1073,6 @@ static struct gui_misc_table nsgtk_misc_table = {
|
|||
.quit = gui_quit,
|
||||
.launch_url = gui_launch_url,
|
||||
.cert_verify = gtk_cert_verify,
|
||||
.login = gui_401login_open,
|
||||
.pdf_password = nsgtk_pdf_password,
|
||||
};
|
||||
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
struct monkey401 {
|
||||
struct monkey401 *r_next, *r_prev;
|
||||
uint32_t num;
|
||||
nserror (*cb)(const char *, const char *, void *);
|
||||
nserror (*cb)(struct nsurl*, const char *, const char *, const char *, void *);
|
||||
void *cbpw;
|
||||
char *username;
|
||||
char *password;
|
||||
char *realm;
|
||||
struct nsurl *url;
|
||||
};
|
||||
|
||||
static struct monkey401 *m401_ring = NULL;
|
||||
|
@ -45,7 +47,9 @@ gui_401login_open(struct nsurl *url,
|
|||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
nserror (*cb)(const char *username,
|
||||
nserror (*cb)(struct nsurl *url,
|
||||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw)
|
||||
|
@ -56,6 +60,12 @@ gui_401login_open(struct nsurl *url,
|
|||
if (m401_ctx == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
m401_ctx->realm = strdup(realm);
|
||||
if (m401_ctx->realm == NULL) {
|
||||
free(m401_ctx);
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
m401_ctx->url = nsurl_ref(url);
|
||||
m401_ctx->cb = cb;
|
||||
m401_ctx->cbpw = cbpw;
|
||||
m401_ctx->num = m401_ctr++;
|
||||
|
@ -102,6 +112,8 @@ static void free_login_context(struct monkey401 *m401_ctx) {
|
|||
if (m401_ctx->password != NULL) {
|
||||
free(m401_ctx->password);
|
||||
}
|
||||
free(m401_ctx->realm);
|
||||
nsurl_unref(m401_ctx->url);
|
||||
free(m401_ctx);
|
||||
}
|
||||
|
||||
|
@ -121,7 +133,7 @@ monkey_login_handle_go(int argc, char **argv)
|
|||
return;
|
||||
}
|
||||
|
||||
m401_ctx->cb(m401_ctx->username, m401_ctx->password, m401_ctx->cbpw);
|
||||
m401_ctx->cb(m401_ctx->url, m401_ctx->realm, m401_ctx->username, m401_ctx->password, m401_ctx->cbpw);
|
||||
|
||||
free_login_context(m401_ctx);
|
||||
}
|
||||
|
@ -142,8 +154,6 @@ monkey_login_handle_destroy(int argc, char **argv)
|
|||
return;
|
||||
}
|
||||
|
||||
m401_ctx->cb(NULL, NULL, m401_ctx->cbpw);
|
||||
|
||||
free_login_context(m401_ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@ nserror gui_401login_open(struct nsurl *url,
|
|||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
nserror (*cb)(const char *username,
|
||||
nserror (*cb)(struct nsurl *url,
|
||||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw);
|
||||
|
|
|
@ -2432,7 +2432,6 @@ static struct gui_misc_table riscos_misc_table = {
|
|||
.quit = gui_quit,
|
||||
.launch_url = gui_launch_url,
|
||||
.cert_verify = gui_cert_verify,
|
||||
.login = gui_401login_open,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -314,7 +314,6 @@ static struct gui_misc_table win32_misc_table = {
|
|||
.warning = win32_warning,
|
||||
|
||||
.cert_verify = nsw32_cert_verify,
|
||||
.login = nsw32_401login,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -120,7 +120,10 @@ enum browser_window_nav_flags {
|
|||
BW_NAVIGATE_UNVERIFIABLE = (1 << 2),
|
||||
|
||||
/** suppress initial history updates (used by back/fwd/etc) */
|
||||
BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE = (1 << 3)
|
||||
BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE = (1 << 3),
|
||||
|
||||
/** Internal navigation (set only by core features using such) */
|
||||
BW_NAVIGATE_INTERNAL = (1 << 4)
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -98,19 +98,29 @@ struct gui_misc_table {
|
|||
void *cbpw);
|
||||
|
||||
/**
|
||||
* Prompt user for login
|
||||
* Retrieve username/password for a given url+realm if there is one
|
||||
* stored in a frontend-specific way (e.g. gnome-keyring)
|
||||
*
|
||||
* To cancel a login, clients should call the `cb` callback passing
|
||||
* NULL for username, and password. Otherwise, for logins, username
|
||||
* and password should both be non-NULL. Pass "" if the empty string
|
||||
* To respond, call the callback with the url, realm, username,
|
||||
* and password. Pass "" if the empty string
|
||||
* is required.
|
||||
*
|
||||
* If the front end returns NSERROR_OK for this function, they must,
|
||||
* To keep hold of the url, remember to nsurl_ref() it, and to keep
|
||||
* the realm, you will need to strdup() it.
|
||||
*
|
||||
* If the front end returns NSERROR_OK for this function, they may,
|
||||
* at some future time, call the `cb` with `cbpw` callback exactly once.
|
||||
*
|
||||
* If ther front end returns other than NSERROR_OK, they should not
|
||||
* If the front end returns other than NSERROR_OK, they should not
|
||||
* call the `cb` callback.
|
||||
*
|
||||
* The callback should not be called immediately upon receipt of this
|
||||
* call as the browser window may not be reentered.
|
||||
*
|
||||
* **NOTE** The lifetime of the cbpw is not well defined. In general
|
||||
* do not use the cb if *any* browser window has navigated or been
|
||||
* destroyed.
|
||||
*
|
||||
* \param url The URL being verified.
|
||||
* \param realm The authorization realm.
|
||||
* \param username Any current username (or empty string).
|
||||
|
@ -120,11 +130,13 @@ struct gui_misc_table {
|
|||
* \return NSERROR_OK on sucess else error and cb never called
|
||||
*/
|
||||
nserror (*login)(struct nsurl *url, const char *realm,
|
||||
const char *username, const char *password,
|
||||
nserror (*cb)(const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw);
|
||||
const char *username, const char *password,
|
||||
nserror (*cb)(struct nsurl *url,
|
||||
const char *realm,
|
||||
const char *username,
|
||||
const char *password,
|
||||
void *pw),
|
||||
void *cbpw);
|
||||
|
||||
/**
|
||||
* Prompt the user for a password for a PDF.
|
||||
|
|
|
@ -146,6 +146,7 @@ CORESTRING_LWC_VALUE(slash_, "/");
|
|||
CORESTRING_LWC_VALUE(max_age, "max-age");
|
||||
CORESTRING_LWC_VALUE(no_cache, "no-cache");
|
||||
CORESTRING_LWC_VALUE(no_store, "no-store");
|
||||
CORESTRING_LWC_VALUE(query_auth, "query/auth");
|
||||
|
||||
/* mime types */
|
||||
CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");
|
||||
|
|
Loading…
Reference in New Issue