WIP: account cookie handling
authorChristian Thaeter <ct@pipapo.org>
Tue, 29 Jan 2008 22:37:20 +0000 (23:37 +0100)
committerChristian Thaeter <ct@pipapo.org>
Tue, 29 Jan 2008 22:37:20 +0000 (23:37 +0100)
Creating an account creates a tuple consisting loginname, realname, email
of the user.

The tuple is temporarly saved in '$accountsdir/pending/$loginname', this
dir should be regulary cleaned up by a cronjob, purging old entries which
got not activated.

The tuple is then signed by the servers secret and a link to activate
the account is send to the provided email address.

When the user activates an account, the data is moved from the pending dir
to '$accountsdir/$loginname[0]/$loginname' permanently.

The user revieves a http-cookie which hold the same data as the initial
activation link which then becomes his authentication cookie.

The activation link is permament for the account and can serve as bookmark
to reactivate an account after logged out, there is no other mean to
(re)activate an account except with this information.

In future a user might re-request the activation link via email.

12 files changed:
Makefile.am
src/account.c [new file with mode: 0644]
src/account.h [new file with mode: 0644]
src/actions.c
src/actions.h
src/login.c [new file with mode: 0644]
src/login.h [new file with mode: 0644]
src/options.c
src/query.c
src/query.h
src/webgit.c
src/webgit.h

index 37668f7..1071487 100644 (file)
@@ -52,6 +52,8 @@ webgit_SOURCES =                              \
        $(webgit_srcdir)/branch.c               \
        $(webgit_srcdir)/tag.c                  \
        $(webgit_srcdir)/log.c                  \
+       $(webgit_srcdir)/login.c                \
+       $(webgit_srcdir)/account.c              \
        $(webgit_srcdir)/rxpd_client.c
 
 noinst_HEADERS =                               \
@@ -66,6 +68,8 @@ noinst_HEADERS =                              \
        $(webgit_srcdir)/branch.h               \
        $(webgit_srcdir)/tag.h                  \
        $(webgit_srcdir)/log.h                  \
+       $(webgit_srcdir)/login.h                \
+       $(webgit_srcdir)/account.h              \
        $(webgit_srcdir)/rxpd_client.h
 
 webgit_DEPENDENCIES = $(abs_top_builddir)/git/libgit.a $(abs_top_builddir)/git/xdiff/lib.a
diff --git a/src/account.c b/src/account.c
new file mode 100644 (file)
index 0000000..560c11b
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "account.h"
+#include "actions.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <cwa.h>
+
+#define SHA1_HEADER <openssl/sha.h>
+#include "git/cache.h"
+
+Html
+webgit_account_create_link (struct webgit_query* query, Html text)
+{
+  return html (
+               html_tag ("a",
+                         html_attr ("href", html_fmt ("%s?action=account", query->request->script_name))
+                         ),
+               text
+               );
+}
+
+
+Html
+webgit_account_logout_link (struct webgit_query* query, Html text)
+{
+  return html (
+               html_tag ("a",
+                         html_attr ("href", html_fmt ("%s?expire=0", query->request->script_name))
+                         ),
+                   text
+               );
+}
+
+
+Html
+webgit_account_prefs_link (struct webgit_query* query, Html text)
+{
+  return html (
+               html_tag ("a",
+                         html_attr ("href", html_fmt ("%s?action=prefs", query->request->script_name))
+                         ),
+                   text
+               );
+}
+
+
+size_t
+webgit_account_user_validate (const char* user)
+{
+  size_t len = 0;
+
+  if (!user)
+    return 0;
+
+  while (*user)
+    {
+      if (!islower (*user) || !isascii (*user))
+        return 0;
+
+      ++len;
+      ++user;
+    }
+
+  if (len < 2 || len > 32)
+    return 0;
+
+  return len;
+}
+
+
+size_t
+webgit_account_name_validate (const char* name)
+{
+  size_t len = 0;
+
+  if (!name)
+    return 0;
+
+  if (!strchr (name, ' '))
+    return 0;
+
+  while (*name)
+    {
+      if (iscntrl (*name))
+        return 0;
+
+      ++len;
+      ++name;
+    }
+
+  if (len < 4 || len > 128)
+    return 0;
+
+  return len;
+}
+
+
+size_t
+webgit_account_email_validate (const char* email)
+{
+  size_t len = 0;
+
+  if (!email)
+    return 0;
+
+  if (!strchr (email, '@'))
+    return 0;
+
+  while (*email)
+    {
+      if (isspace (*email) || iscntrl (*email))
+        return 0;
+
+      ++len;
+      ++email;
+    }
+
+  if (len < 6 || len > 128)
+    return 0;
+
+  return len;
+}
+
+const char*
+webgit_account_signature (struct webgit_query* query)
+{
+  size_t buf_len =
+    strlen (query->user) + strlen (query->name) + strlen (query->email) + 40 /*secret*/ + sizeof ("; ; ; ");
+
+  char* buf = cwa_buffer_provide (buf_len);
+
+  sprintf (buf, "%s; %s; %s; %s", query->user, query->name, query->email, query->secret);
+  char* ret = sha1_to_hex (SHA1 ((unsigned char*)buf, buf_len, NULL));
+  memset (buf, 0, buf_len);
+
+  return ret;
+}
+
+
+int
+webgit_account_validate_signature (struct webgit_query* query)
+{
+  const char* sig = webgit_account_signature (query);
+  return !strcmp (sig, query->ssign);
+}
+
+
+int
+webgit_account_sendmail (struct webgit_query* query)
+{
+  /* TODO: sendmail as config option */
+  size_t len = snprintf (NULL, 0, "/usr/lib/sendmail %s", query->email);
+  char* mail = cwa_buffer_provide (len+1);
+  sprintf (mail, "/usr/lib/sendmail %s", query->email);
+
+  FILE* sendmail = popen (mail, "w");
+
+  fprintf (sendmail,
+           "Subject: %s webgit account activation\n"
+           "From: Webgit\n"
+           "To: %s"
+           "\n"
+           "TODO: Explain login ...\n"
+           "To (re)activate your account visit the following link:\n"
+           "http://%s%s?user=%s&name=%s&email=%s&ssign=%s\n"
+           "\n",
+
+           query->request->host_name,
+           query->email,
+
+           query->request->host_name,
+           query->request->script_name,
+           query->user,
+           cwa_urlencode (query->name),
+           cwa_urlencode (query->email),
+           webgit_account_signature (query)
+           );
+
+  return pclose (sendmail);
+}
+
+
+int
+webgit_account_create_pending (struct webgit_query* query)
+{
+  char * path = cwa_buffer_provide (strlen (query->accountdir) + sizeof ("/") + strlen (query->user));
+  char * path_pend = cwa_buffer_provide (strlen (query->accountdir) + sizeof ("/pending/") + strlen (query->user));
+
+  /* make directories when not already existing, errors are ignored */
+  sprintf (path, "%s/%c", query->accountdir, *query->user);
+  mkdir (path, 0770);
+  sprintf (path_pend, "%s/pending", query->accountdir);
+  mkdir (path_pend, 0770);
+
+  sprintf (path, "%s/%c/%s", query->accountdir, *query->user, query->user);
+  sprintf (path_pend, "%s/pending/%s", query->accountdir, query->user);
+
+  FILE* f = fopen (path_pend, "wx");
+
+  if (!access (path, F_OK) || !f)
+    {
+      /* account already exist or pending */
+      if (f)
+        {
+          fclose (f);
+          unlink (path_pend);
+        }
+      die ("account already exist");
+      return -1;
+    }
+  else
+    {
+      /* ok, lets make it pending */
+      fprintf (f, "user=%s; name=\"%s\"; email=%s;\n", query->user, query->name, query->email);
+      fclose (f);
+
+      /* send email */
+      return webgit_account_sendmail (query);
+    }
+}
+
+
+
+
+Html
+webgit_account_menu_action (struct webgit_query* query)
+{
+  Html menu = html_list ();
+
+  if (query->accountdir && query->secret)
+    {
+      if (!query->user)
+        {
+          /* create account or recover */
+        }
+      else if (query->user)
+        {
+          if (!query->ssign)
+            {
+              /* create 2nd step, must not exist send signed cookie */
+            }
+          else
+            {
+              /* change name/email */
+              html_list_append (menu,
+                                "Preferences", "<br />",
+                                "Deactivate&nbsp;Account", "<br />");
+            }
+        }
+    }
+  else
+    html_list_append (menu, "User accounts not enabled on this server<br/>");
+
+  return html (
+               menu, "<br />",
+               webgit_main_link (query, html ("Main")), "<br />"
+               );
+}
+
+
+Html
+webgit_account_content_action (struct webgit_query* query)
+{
+  Html content = html_list ();
+
+  if (query->accountdir && query->secret)
+    {
+      if (!query->user)
+        {
+          /* create account or recover */
+          html_list_append (content,
+                            "TODO: Explain account creation, cookies etc...",
+                            html (
+                                  html_tag ("form",
+                                            html_attr ("action", html_str (query->request->script_name)),
+                                            html_attr ("method","get")
+                                            ),
+                                  html_hidden ("action", "account"),
+                                  "Username: (2-32 lowercase ascii chars)<br/>",
+                                  html (
+                                        html_tag ("input", html_attr ("name", "user"))
+                                        ), "<br/>",
+                                  "Real Name: (must contain at least one space, utf8)<br/>",
+                                  html (
+                                        html_tag ("input", html_attr ("name", "name"))
+                                        ), "<br/>",
+                                  "Email: (must contain a @, used to recover account)<br/>",
+                                  html (
+                                        html_tag ("input", html_attr ("name", "email"))
+                                        ), "<br/>",
+                                  html (
+                                        html_tag ("input",
+                                                  html_attr ("type", "submit"),
+                                                  html_attr ("value", "Create Account.."))
+                                        )
+                                  )
+                            );
+        }
+      else if (query->user)
+        {
+          if (!query->ssign)
+            {
+              /* create 2nd step, must not exist send signed cookie */
+              if (!webgit_account_user_validate (query->user))
+                die ("invalid user name");
+              if (!webgit_account_name_validate (query->name))
+                die ("invalid name");
+              if (!webgit_account_email_validate (query->email))
+                die ("invalid email");
+
+              webgit_account_create_pending (query);
+
+              html_list_append (content, "account created, email send");
+
+            }
+          else
+            {
+              /* change name/email */
+              //free (query->login_cookie);
+              //query->login_cookie = cwa_strndup ("", SIZE_MAX);
+              //query->cookie_expire = 0;
+
+              html_list_append (content,
+                                html (
+                                      html_tag ("a",
+                                                html_attr ("href",
+                                                           html(
+                                                                html_str (query->request->script_name),
+                                                                "?expire=0"
+                                                                )
+                                                           )
+                                                ),
+                                      "Deactivate&nbsp;Account"
+                                      ), "<br />",
+
+
+
+
+                                "Delete&nbsp;Account", "<br />"
+
+                                );
+
+
+
+            }
+        }
+    }
+  else
+    html_list_append (content, "User accounts not enabled on this server<br/>");
+
+  return content;
+}
+
+
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/
diff --git a/src/account.h b/src/account.h
new file mode 100644 (file)
index 0000000..4b2eac9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef WEBGIT_ACCOUNT_H
+#define WEBGIT_ACCOUNT_H
+
+#include "webgit.h"
+
+
+Html
+webgit_account_create_link (struct webgit_query* query, Html text);
+
+Html
+webgit_account_logout_link (struct webgit_query* query, Html text);
+
+Html
+webgit_account_prefs_link (struct webgit_query* query, Html text);
+
+Html
+webgit_account_menu_action (struct webgit_query* query);
+
+Html
+webgit_account_content_action (struct webgit_query* query);
+
+#endif
+
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/
index e0f08f5..7b96545 100644 (file)
@@ -27,6 +27,7 @@
 #include "age.h"
 #include "branch.h"
 #include "tag.h"
+#include "account.h"
 
 #include "llist.h"
 #include <cwa.h>
@@ -65,7 +66,14 @@ webgit_main_menu_action (struct webgit_query* query)
                                )
                      ), "<br />",
                html_include (webgit_skinpath (query, "inc/site.inc")), "<br />",
-               // TODO: webgit_user_config_link (query), "<br />",
+               query->ssign
+               ? html (
+                       webgit_account_prefs_link (query, html ("Preferences")), "<br />",
+                       webgit_account_logout_link (query, html ("Logout")), "<br />"
+                       )
+               : html (
+                       webgit_account_create_link (query, html ("Create&nbsp;Account")), "<br />"
+                       ),
                html (
                      html_tag ("a",
                                html_attr ("href", webgit_webskinpath (query, "inc/about.html"))
@@ -552,6 +560,19 @@ webgit_config_action (struct webgit_query* query)
 }
 
 
+/*
+  account management
+*/
+static Html
+webgit_account_action (struct webgit_query* query)
+{
+  return html(
+              html(html_tag("div", html_attr ("id", "sub-menu")), webgit_account_menu_action (query)), html_nl (),
+              html(html_tag("div", html_attr ("id", "content")), webgit_account_content_action (query)), html_nl ()
+              );
+}
+
+
 /*
   edit an object
 */
@@ -562,6 +583,7 @@ webgit_edit_action (struct webgit_query* query)
   return html("edit");
 }
 
+
 /*
   commit changes
 */
index b57a67e..d9f7b8d 100644 (file)
@@ -37,6 +37,7 @@
  WEBGIT_ACTION(raw, "Show an object, raw format")                       \
  WEBGIT_ACTION(branch, "Show and manage branches")                      \
  WEBGIT_ACTION(tag, "Show and manage tags")                             \
+ WEBGIT_ACTION(account, "Show and edit the user account configuration") \
  WEBGIT_ACTION(config, "Show and edit the git configuration")           \
  WEBGIT_ACTION(edit, "Edit and object")                                 \
  WEBGIT_ACTION(commit, "Commit pending edits")
diff --git a/src/login.c b/src/login.c
new file mode 100644 (file)
index 0000000..d071d8a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "login.h"
+#include "account.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+
+void
+webgit_login_bakecookie (struct webgit_query* query)
+{
+  if (query->user && query->name && query->email && query->ssign)
+    {
+      if (webgit_account_validate_signature (query))
+        {
+          if (query->cookie_expire)
+            {
+              // if pending then activate
+              char * path = cwa_buffer_provide (strlen (query->accountdir) + sizeof ("/") + strlen (query->user));
+              char * path_pend = cwa_buffer_provide (strlen (query->accountdir) +
+                                                     sizeof ("/pending/") + strlen (query->user));
+
+              sprintf (path, "%s/%c/%s", query->accountdir, *query->user, query->user);
+              sprintf (path_pend, "%s/pending/%s", query->accountdir, query->user);
+
+              rename (path_pend, path);
+
+              //TODO: check path
+
+              size_t len = snprintf (NULL, 0, "user=%s; name=\"%s\"; email=%s; ssign=%s",
+                                     query->user, query->name, query->email, query->ssign);
+
+              free (query->login_cookie);
+              query->login_cookie = cwa_malloc (len+1);
+
+              snprintf (query->login_cookie, len+1, "user=%s; name=\"%s\"; email=%s; ssign=%s",
+                        query->user, query->name, query->email, query->ssign);
+
+            }
+          else
+            {
+              // logout
+              free (query->login_cookie);
+              query->login_cookie = cwa_strndup ("LOGOUT", SIZE_MAX);
+              free (query->ssign);
+              query->ssign = NULL;
+            }
+        }
+      else
+        {
+          die ("account spoofed");
+        }
+    }
+}
+
+
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/
diff --git a/src/login.h b/src/login.h
new file mode 100644 (file)
index 0000000..9dd78c6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    cehtehs git web frontend
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef WEBGIT_LOGIN_H
+#define WEBGIT_LOGIN_H
+
+#include "webgit.h"
+
+#include <cwa.h>
+
+void
+webgit_login_bakecookie (struct webgit_query* query);
+
+#endif
+
+/*
+//      Local Variables:
+//      mode: C
+//      c-file-style: "gnu"
+//      indent-tabs-mode: nil
+//      End:
+*/
index 0eda0fb..deae9df 100644 (file)
@@ -25,6 +25,9 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#define SHA1_HEADER <openssl/sha.h>
+#include "git/cache.h"
+
 static int
 conf_query_opt (struct webgit_query* query, char* arg)
 {
@@ -128,8 +131,11 @@ conf_count_opt (struct webgit_query* query, char* arg)
 static int
 conf_secret_opt (struct webgit_query* query, char* arg)
 {
+  if (strlen (arg) < 6)
+    die ("secret to short");
+
   free (query->secret);
-  query->secret = cwa_strndup (arg, SIZE_MAX);
+  query->secret = cwa_strndup (sha1_to_hex (SHA1 (arg, strlen(arg), NULL)), 40);
   return 0;
 }
 
index a3098c1..f61a73a 100644 (file)
@@ -36,6 +36,10 @@ webgit_query_init (struct webgit_query* q)
   q->deref_to_tree = 0;
   q->content_type = cwa_strndup ("text/html", SIZE_MAX);
 
+  q->login_cookie = NULL;
+  q->prefs_cookie = NULL;
+  q->cookie_expire = 365UL * 86400UL; /*1 year*/
+
   q->count_def = 100;
   q->rxpd = NULL;
   q->skindir = cwa_strndup (WEBGIT_SKINDIR_DEFAULT, SIZE_MAX);
@@ -66,6 +70,9 @@ webgit_query_destroy (struct webgit_query* q)
 {
   cgi_free (q->request);
 
+  free (q->login_cookie);
+  free (q->prefs_cookie);
+
   free (q->content_type);
   free (q->rxpd);
   free (q->skindir);
@@ -246,6 +253,19 @@ webgit_maxage_param (const Cgi self, const char* v, size_t v_sz, void* u_dat)
 }
 
 
+static void
+webgit_expire_param (const Cgi self, const char* v, size_t v_sz, void* u_dat)
+{
+  (void) self;
+  struct webgit_query* q = (struct webgit_query*) u_dat;
+
+  if (v_sz)
+    {
+      q->cookie_expire = atol (v) * 86400UL;
+    }
+}
+
+
 static void
 webgit_user_param (const Cgi self, const char* v, size_t v_sz, void* u_dat)
 {
index 30fbd3f..afdcddd 100644 (file)
@@ -39,6 +39,7 @@
  WEBGIT_PARAM(name, "Real name of the editing user")                    \
  WEBGIT_PARAM(email, "Email of the editing user")                       \
  WEBGIT_PARAM(ssign, "Server signature over user/name/email")           \
+ WEBGIT_PARAM(expire, "Cookie expire time in days")                     \
  WEBGIT_PARAM(skin, "Set skin")                                         \
  WEBGIT_PARAM(maxage, "Age in days to hide inactive repositories")      \
  WEBGIT_PARAM(login, "Login cookie")                                    \
index 42ce015..d3265e1 100644 (file)
@@ -27,6 +27,7 @@
 #define WEBGIT_CONFIG "/etc/webgit.conf"
 #endif
 
+#include "login.h"
 #include "actions.h"
 #include "query.h"
 #include "options.h"
@@ -48,7 +49,7 @@ jmp_buf err_jmp;
 static void
 webgit_err_vargs (const char *err, va_list params)
 {
-  html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag ("br")));
+  html_list_append (error_log, html (html_fmt_vargs (err, params, html_print_escaped), html_tag ("br")));
   longjmp (err_jmp, 0);
 }
 
@@ -66,7 +67,7 @@ webgit_err (const char *err, ...)
 static void
 webgit_warn_vargs (const char *err, va_list params)
 {
-  html_list_append (error_log, html (html_fmt_vargs (err, params), html_tag("br")));
+  html_list_append (error_log, html (html_fmt_vargs (err, params, html_print_escaped), html_tag("br")));
 }
 
 
@@ -260,20 +261,39 @@ main (int argc, char**argv)
 
   // check if in cache
 
-  // generate page
 
+  // Cookie prep
+
+  time_t expire = query.now + query.cookie_expire;
+  char expire_buf[32];
+  strftime (expire_buf, 32, "%a, %d %b %Y %T %z", gmtime (&expire));
+
+  webgit_login_bakecookie (&query);
+
+
+  // generate page
   Html content = webgit_action_dispatch (&query);
 
   if (query.content_type && !strcmp (query.content_type, "text/html"))
     {
       /* generate html page */
+
       page = html(
                   html_httpheader(
-                                  html_httpfield(
-                                                 "Content-type",
-                                                 query.content_type,
-                                                 html_attr("charset", "UTF-8")
-                                                 )//,
+                                  html_httpfield (
+                                                  "Content-type",
+                                                  query.content_type,
+                                                  html_attr("charset", "UTF-8")
+                                                  ),
+                                  query.login_cookie ?
+                                  html_httpfield (
+                                                  "Set-Cookie",
+                                                  html_attr ("login", html_str_printfn (query.login_cookie,
+                                                                                        html_print_urlencoded)),
+                                                  html_attr ("path", query.request->script_name),
+                                                  html_attr ("expires", expire_buf)
+                                                  // domain ...
+                                                  ) : html ()
                                   //html_httpfield("Last-Modified", cgit_page.modified),
                                   //html_httpfield("Expires", cgit_page.expires)
                                   ),
index a908697..d482d89 100644 (file)
@@ -47,8 +47,11 @@ struct webgit_query
 
   char* content_type;
 
+  char* login_cookie;
+  char* prefs_cookie;
+  time_t cookie_expire;
+
   /* confiuration parameters */
-  char* stylesheet;
   int count_def;
   char* rxpd;
   char* skindir;