/* * Box Social™ * http://boxsocial.net/ * Copyright © 2007, David Lachlan Smith * * $Id:$ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Data; using System.IO; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Xml; using System.Xml.Serialization; using BoxSocial.IO; namespace BoxSocial.Internals { [DataTable("user_sessions", DataTableTypes.Volatile)] public class Session : NumberedItem { [DataField("session_id", DataFieldKeys.Primary)] private long sessionId; [DataField("user_id")] private long userId; [DataField("session_string", DataFieldKeys.Unique, 32)] private string sessionString; [DataField("session_start_ut")] private long sessionStartRaw; [DataField("session_time_ut")] private long sessionTimeRaw; [DataField("session_signed_in")] private bool sessionSignedIn; [DataField("session_ip", IP)] private string sessionIp; private User user; internal long SessionId { get { return sessionId; } } internal long UserId { get { return userId; } } internal User User { get { if (user == null || userId != user.Id) { core.LoadUserProfile(userId); user = core.PrimitiveCache[userId]; return user; } else { return user; } } } internal string SessionString { get { return sessionString; } } internal long StartRaw { get { return sessionStartRaw; } } internal long TimeRaw { get { return sessionTimeRaw; } } internal bool SignedIn { get { return sessionSignedIn; } } internal string Ip { get { return sessionIp; } } public DateTime GetStart(UnixTime tz) { return tz.DateTimeFromMysql(sessionStartRaw); } public DateTime GetTime(UnixTime tz) { return tz.DateTimeFromMysql(sessionTimeRaw); } internal Session(Core core, DataRow sessionRow) : base(core) { ItemLoad += new ItemLoadHandler(Session_ItemLoad); loadItemInfo(sessionRow); } void Session_ItemLoad() { } public override long Id { get { return sessionId; } } public override string Uri { get { throw new NotImplementedException(); } } } [DataTable("session_keys", DataTableTypes.NonVolatile)] internal sealed class SessionKey : Item { [DataField("key_id", DataFieldKeys.Primary, "ternary", 32)] private string keyId; [DataField("user_id", DataFieldKeys.Primary, "ternary")] private long userId; [DataField("key_last_ip", IP)] private string lastIp; [DataField("key_last_visit_ut")] private long lastVisitRaw; internal string KeyId { get { return keyId; } } internal long UserId { get { return userId; } } internal string Ip { get { return lastIp; } } internal long VisitRaw { get { return lastVisitRaw; } } public DateTime GetVisit(UnixTime tz) { return tz.DateTimeFromMysql(lastVisitRaw); } internal SessionKey(Core core, DataRow keyRow) : base (core) { ItemLoad += new ItemLoadHandler(SessionKey_ItemLoad); loadItemInfo(keyRow); } void SessionKey_ItemLoad() { } public override string Uri { get { throw new NotImplementedException(); } } } /// /// Summary description for Session /// public class SessionState { private const int SESSION_EXPIRES = 3600; private User loggedInMember; private IPAddress ipAddress; private bool isLoggedIn; private HttpRequest Request; private HttpResponse Response; private Mysql db; private SessionMethods sessionMethod; private SessionCookie sessionData; private Core core; private string sessionId; public string SessionId { get { return sessionId; } } public SessionMethods SessionMethod { get { return sessionMethod; } } public bool IsLoggedIn { get { return isLoggedIn; } } public SessionState(Core core, Mysql db, System.Security.Principal.IPrincipal User, HttpRequest Request, HttpResponse Response) { this.Request = Request; this.Response = Response; this.db = db; this.core = core; this.isLoggedIn = false; ipAddress = IPAddress.Parse(SessionState.ReturnRealIPAddress(Request.ServerVariables)); SessionPagestart(ipAddress.ToString()); return; } public SessionState(Core core, User user) { this.core = core; this.db = core.Db; isLoggedIn = true; loggedInMember = user; ipAddress = new IPAddress(0); } // // The following session algorithm was borrowed from phpBB2.0.22, // it is considered secure and widely implemented // public string SessionBegin(long userId) { return SessionBegin(userId, false, false, false); } public string SessionBegin(long userId, bool autoCreate) { return SessionBegin(userId, autoCreate, false, false); } public string SessionBegin(long userId, bool autoCreate, bool enableAutologin) { return SessionBegin(userId, autoCreate, enableAutologin, false); } public string SessionBegin(long userId, bool autoCreate, bool enableAutologin, bool admin) { return SessionBegin(userId, autoCreate, enableAutologin, admin, null); } /// /// /// /// /// /// /// public string SessionBegin(long userId, bool autoCreate, bool enableAutologin, bool admin, DnsRecord record) { string cookieName = "hailToTheChef"; XmlSerializer xs; StringWriter stw; sessionData = null; sessionId = null; if (record == null) { if (Request.Cookies[cookieName + "_sid"] != null || Request.Cookies[cookieName + "_data"] != null) { if (Request.Cookies[cookieName + "_sid"] != null) { sessionId = Request.Cookies[cookieName + "_sid"].Value; } if (Request.Cookies[cookieName + "_data"] != null) { xs = new XmlSerializer(typeof(SessionCookie)); StringReader sr = new StringReader(HttpUtility.UrlDecode(Request.Cookies[cookieName + "_data"].Value)); try { sessionData = (SessionCookie)xs.Deserialize(sr); } catch { sessionData = new SessionCookie(); } } else { sessionData = new SessionCookie(); } if (string.IsNullOrEmpty(sessionId)) { sessionId = (string)Request.QueryString["sid"]; } sessionMethod = SessionMethods.Cookie; } else { sessionData = new SessionCookie(); if (Request.QueryString["sid"] != null) { sessionId = (string)Request.QueryString["sid"]; } sessionMethod = SessionMethods.Get; } } else { sessionData = new SessionCookie(); } if (!string.IsNullOrEmpty(sessionId)) { if (!Regex.IsMatch(sessionId, "^[A-Za-z0-9]*$")) { sessionId = ""; } } if (record != null) { sessionMethod = SessionMethods.Get; } DateTime lastVisit = new DateTime(1000, 1, 1); // // First off attempt to join with the autologin value if we have one // If not, just use the user_id value // loggedInMember = null; if (userId != 0) { //if (isset($sessiondata['autologinid']) && (string) $sessiondata['autologinid'] != '' && $user_id) if (!string.IsNullOrEmpty(sessionData.autoLoginId) && userId > 0) { SelectQuery query = User.GetSelectQueryStub(UserLoadOptions.Info); query.AddJoin(JoinTypes.Inner, "session_keys", "user_id", "user_id"); query.AddCondition("user_keys.user_id", userId); query.AddCondition("user_active", true); query.AddCondition("key_id", SessionState.SessionMd5(sessionData.autoLoginId)); DataTable userSessionTable = db.Query(query); if (userSessionTable.Rows.Count == 1) { loggedInMember = new User(core, userSessionTable.Rows[0], UserLoadOptions.Info); enableAutologin = isLoggedIn = true; } else { core.Template.Parse("REDIRECT_URI", "/"); if (record == null) { Response.Cookies.Clear(); HttpCookie sessionDataCookie = new HttpCookie(cookieName + "_data"); sessionDataCookie.Value = ""; sessionDataCookie.Expires = DateTime.MinValue; sessionDataCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(sessionDataCookie); HttpCookie sessionSidCookie = new HttpCookie(cookieName + "_sid"); sessionSidCookie.Value = ""; sessionSidCookie.Expires = DateTime.MinValue; sessionSidCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(sessionSidCookie); } //core.Display.ShowMessage("Error", "Error starting session"); Response.Write("Error starting session"); if (db != null) { db.CloseConnection(); } Response.End(); return null; } } else if (!autoCreate) { sessionData.autoLoginId = ""; sessionData.userId = userId; SelectQuery query = User.GetSelectQueryStub(UserLoadOptions.Info | UserLoadOptions.Icon); query.AddCondition("user_active", true); query.AddCondition("user_keys.user_id", userId); DataTable userSessionTable = db.Query(query); if (userSessionTable.Rows.Count == 1) { loggedInMember = new User(core, userSessionTable.Rows[0], UserLoadOptions.Info | UserLoadOptions.Icon); isLoggedIn = true; } else { // TODO: activation //core.Display.ShowMessage("Inactive account", "You have attempted to use an inactive account. If you have just registered, check for an e-mail with an activation link at the e-mail address you provided."); Response.Write("You have attempted to use an inactive account. If you have just registered, check for an e-mail with an activation link at the e-mail address you provided."); //Display.ShowMessage(this, "Error", "Error starting session"); //Response.Write("fail 1"); if (db != null) { db.CloseConnection(); } Response.End(); } } } // // At this point either loggedInMember should be populated or // one of the below is true // * Key didn't match one in the DB // * User does not exist // * User is inactive // if (loggedInMember == null) { if (sessionData == null) { sessionData = new SessionCookie(); } sessionData.autoLoginId = ""; sessionData.userId = userId = 0; enableAutologin = isLoggedIn = false; SelectQuery query = User.GetSelectQueryStub(UserLoadOptions.Info | UserLoadOptions.Icon); query.AddCondition("user_keys.user_id", userId); DataTable userTable = db.Query(query); if (userTable.Rows.Count == 1) { loggedInMember = new User(core, userTable.Rows[0], UserLoadOptions.Info | UserLoadOptions.Icon); } } // INFO: phpBB2 performs a ban check, we don't have those facilities so let's skip // // Create or update the session // long changedRows = 0; if (record == null) { changedRows = db.UpdateQuery(string.Format("UPDATE user_sessions SET session_time_ut = UNIX_TIMESTAMP(), user_id = {0}, session_signed_in = {1} WHERE session_string = '{3}' AND session_ip = '{2}';", userId, isLoggedIn, ipAddress.ToString(), sessionId)); } if (changedRows == 0) { Random rand = new Random((int)(DateTime.Now.Ticks & 0xFFFF)); sessionId = SessionState.SessionMd5(rand.NextDouble().ToString() + "zzseed" + DateTime.Now.Ticks.ToString() + ipAddress.ToString()).ToLower(); db.UpdateQuery(string.Format("INSERT INTO user_sessions (session_string, session_time_ut, session_start_ut, session_signed_in, session_ip, user_id) VALUES ('{0}', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), {1}, '{2}', {3})", sessionId, isLoggedIn, ipAddress.ToString(), userId)); } if (record == null) { if (userId != 0) { TimeSpan ts = DateTime.Now - loggedInMember.Info.LastOnlineTime; if (ts.TotalMinutes >= 5) { db.UpdateQuery(string.Format("UPDATE user_info SET user_last_visit_ut = UNIX_TIMESTAMP() where user_id = {0}", loggedInMember.UserId)); Random rand = new Random(); // 1 in 10 chance of deleting stale sessions if (rand.NextDouble() * 10 < 1) { db.UpdateQuery(string.Format("DELETE FROM user_sessions WHERE session_time_ut + {0} < UNIX_TIMESTAMP()", SessionState.SESSION_EXPIRES)); } } if (enableAutologin) { Random rand = new Random(); string autoLoginKey = SessionState.SessionMd5(rand.NextDouble().ToString() + "zzseed").Substring(4, 16) + SessionState.SessionMd5(rand.NextDouble().ToString() + "zzseed").Substring(4, 16); if (!string.IsNullOrEmpty(sessionData.autoLoginId)) { db.UpdateQuery(string.Format("UPDATE session_keys SET key_last_ip = '{0}', key_id = '{1}', key_last_visit_ut = UNIX_TIMESTAMP() WHERE key_id = '{2}'", ipAddress.ToString(), SessionState.SessionMd5(autoLoginKey), SessionState.SessionMd5(sessionData.autoLoginId))); } else { db.UpdateQuery(string.Format("INSERT INTO session_keys (key_id, user_id, key_last_ip, key_last_visit_ut) VALUES ('{0}', {1}, '{2}', UNIX_TIMESTAMP())", SessionState.SessionMd5(autoLoginKey), userId, ipAddress.ToString())); } sessionData.autoLoginId = autoLoginKey; autoLoginKey = ""; } else { sessionData.autoLoginId = ""; } } } core.Uri.Sid = sessionId; if (record == null) { Response.Cookies.Clear(); xs = new XmlSerializer(typeof(SessionCookie)); StringBuilder sb = new StringBuilder(); stw = new StringWriter(sb); HttpCookie newSessionDataCookie = new HttpCookie(cookieName + "_data"); xs.Serialize(stw, sessionData); stw.Flush(); stw.Close(); newSessionDataCookie.Value = sb.ToString().Replace("\r", "").Replace("\n", ""); newSessionDataCookie.Expires = DateTime.Now.AddYears(1); newSessionDataCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionDataCookie); HttpCookie newSessionSidCookie = new HttpCookie(cookieName + "_sid"); newSessionSidCookie.Value = sessionId; newSessionSidCookie.Expires = DateTime.MinValue; newSessionSidCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionSidCookie); } return sessionId; } public void SessionPagestart(string userIp) { string cookieName = "hailToTheChef"; XmlSerializer xs; StringWriter stw; sessionData = null; sessionId = null; if (Request.Cookies[cookieName + "_sid"] != null || Request.Cookies[cookieName + "_data"] != null) { if (Request.Cookies[cookieName + "_sid"] != null) { sessionId = Request.Cookies[cookieName + "_sid"].Value; } if (Request.Cookies[cookieName + "_data"] != null) { xs = new XmlSerializer(typeof(SessionCookie)); StringReader sr = new StringReader(HttpUtility.UrlDecode(Request.Cookies[cookieName + "_data"].Value)); try { sessionData = (SessionCookie)xs.Deserialize(sr); } catch { sessionData = new SessionCookie(); } } else { sessionData = new SessionCookie(); } if (string.IsNullOrEmpty(sessionId)) { sessionId = (string)Request.QueryString["sid"]; } if ((Linker.Domain != core.Uri.CurrentDomain) && (sessionId != (string)Request.QueryString["sid"]) && (!string.IsNullOrEmpty((string)Request.QueryString["sid"]))) { sessionData = new SessionCookie(); sessionId = (string)Request.QueryString["sid"]; } if ((core.Uri.CurrentDomain != Linker.Domain) && string.IsNullOrEmpty(sessionId)) { HttpContext.Current.Response.Redirect(Linker.Uri + string.Format("session.aspx?domain={0}&path={1}", HttpContext.Current.Request.Url.Host, core.PagePath.TrimStart(new char[] { '/' }))); //return; } sessionMethod = SessionMethods.Cookie; } else { sessionData = new SessionCookie(); if (Request.QueryString["sid"] != null) { sessionId = (string)Request.QueryString["sid"]; } sessionMethod = SessionMethods.Get; } if (!string.IsNullOrEmpty(sessionId)) { if (!Regex.IsMatch(sessionId, "^[A-Za-z0-9]*$")) { sessionId = ""; } } DateTime lastVisit = new DateTime(1000, 1, 1); if (!string.IsNullOrEmpty(sessionId)) { // // session_id exists so go ahead and attempt to grab all // data in preparation // SelectQuery query = User.GetSelectQueryStub(UserLoadOptions.Info | UserLoadOptions.Icon); query.AddFields("session_ip", "session_time_ut"); query.AddJoin(JoinTypes.Inner, "user_sessions", "user_id", "user_id"); query.AddCondition("session_string", sessionId); DataTable userSessionTable = db.Query(query); // // Did the session exist in the DB? // if (userSessionTable.Rows.Count == 1) { DataRow userSessionRow = userSessionTable.Rows[0]; loggedInMember = new User(core, userSessionRow, UserLoadOptions.Info | UserLoadOptions.Icon); core.Uri.Sid = sessionId; if (loggedInMember.UserId != 0) { isLoggedIn = true; } // // Do not check IP assuming equivalence, if IPv4 we'll check only first 24 // bits ... I've been told (by vHiker) this should alleviate problems with // load balanced et al proxies while retaining some reliance on IP security. // // we will use complete matches on ZinZam if ((string)userSessionRow["session_ip"] == userIp) { UnixTime tzz = new UnixTime(core, UnixTime.UTC_CODE); // UTC TimeSpan tss = DateTime.UtcNow - tzz.DateTimeFromMysql(userSessionRow["session_time_ut"]); // // Only update session DB a minute or so after last update // if (tss.TotalMinutes >= 1) { long changedRows = db.UpdateQuery(string.Format("UPDATE user_sessions SET session_time_ut = UNIX_TIMESTAMP() WHERE session_string = '{0}';", sessionId)); if (isLoggedIn) { TimeSpan ts = DateTime.Now - loggedInMember.Info.LastOnlineTime; if (ts.TotalMinutes >= 5) { db.UpdateQuery(string.Format("UPDATE user_info SET user_last_visit_ut = UNIX_TIMESTAMP() where user_id = {0}", loggedInMember.UserId)); Random rand = new Random(); // 1 in 10 chance of deleting stale sessions if (rand.NextDouble() * 10 < 1) { db.UpdateQuery(string.Format("DELETE FROM user_sessions WHERE session_time_ut + {0} < UNIX_TIMESTAMP()", SessionState.SESSION_EXPIRES)); } } } SessionClean(sessionId); } Response.Cookies.Clear(); xs = new XmlSerializer(typeof(SessionCookie)); StringBuilder sb = new StringBuilder(); stw = new StringWriter(sb); HttpCookie newSessionDataCookie = new HttpCookie(cookieName + "_data"); xs.Serialize(stw, sessionData); stw.Flush(); stw.Close(); newSessionDataCookie.Value = sb.ToString().Replace("\r", "").Replace("\n", ""); newSessionDataCookie.Expires = DateTime.Now.AddYears(1); newSessionDataCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionDataCookie); HttpCookie newSessionSidCookie = new HttpCookie(cookieName + "_sid"); newSessionSidCookie.Value = sessionId; newSessionSidCookie.Expires = DateTime.MinValue; newSessionSidCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionSidCookie); // Add the session_key to the userdata array if it is set return; } } else { //Display.ShowMessage(this, "Error", "Error starting session"); //Response.Write("fail 3"); //Response.End(); } } // // If we reach here then no (valid) session exists. So we'll create a new one, // using the cookie user_id if available to pull basic user prefs. // long userId = (sessionData != null && sessionData.userId > 0) ? sessionData.userId : 0; // If the current domain is not the root domain, and the session is empty if ((core.Uri.CurrentDomain != Linker.Domain) && string.IsNullOrEmpty(sessionId)) { } else { SessionBegin(userId, true); } } public void SessionEnd(string sessionId, long userId) { SessionEnd(sessionId, userId, null); } public void SessionEnd(string sessionId, long userId, DnsRecord record) { string cookieName = "hailToTheChef"; //XmlSerializer xs; //StringWriter stw; if (!string.IsNullOrEmpty(sessionId)) { if (!Regex.IsMatch(sessionId, "^[A-Za-z0-9]*$")) { return; } } else { return; } // // Delete existing session // db.UpdateQuery(string.Format("DELETE FROM user_sessions WHERE session_id = '{0}' AND user_id = {1}", sessionId, userId)); // // Remove this auto-login entry (if applicable) // // // We expect that message_die will be called after this function, // but just in case it isn't, reset $userdata to the details for a guest // if (record == null) { Response.Cookies.Clear(); SelectQuery query = User.GetSelectQueryStub(UserLoadOptions.Info); query.AddCondition("user_keys.user_id", 0); DataTable userTable = db.Query(query); Response.Cookies.Clear(); if (userTable.Rows.Count == 1) { loggedInMember = new User(core, userTable.Rows[0], UserLoadOptions.Info); } HttpCookie newSessionDataCookie = new HttpCookie(cookieName + "_data"); newSessionDataCookie.Value = ""; newSessionDataCookie.Expires = DateTime.Now.AddYears(-1); newSessionDataCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionDataCookie); HttpCookie newSessionSidCookie = new HttpCookie(cookieName + "_sid"); newSessionSidCookie.Value = ""; newSessionSidCookie.Expires = DateTime.Now.AddYears(-1); newSessionSidCookie.Secure = false; // TODO: secure cookies Response.Cookies.Add(newSessionSidCookie); } return; } private void SessionClean(string sessionId) { //throw new Exception("The method or operation is not implemented."); } public IPAddress IPAddress { get { return ipAddress; } } public User LoggedInMember { get { return loggedInMember; } } public static string ReturnRealIPAddress(NameValueCollection ServerVariables) { // List syndicated from http://wikimedia.org/trusted-xff.html // TODO: automatically parse the above url with a script into a text file of IP addresses, will be faster string[] legitFowardFor = { "61.91.190.242", "61.91.190.246", "61.91.190.248", "61.91.190.249", "61.91.190.250", "61.91.190.251", "61.91.191.2", "61.91.191.4", "61.91.191.6", "61.91.191.8", "61.91.191.9", "61.91.191.10", "61.91.191.11", "203.144.143.2", "203.144.143.3", "203.144.143.4", "203.144.143.5", "203.144.143.6", "203.144.143.7", "203.144.143.8", "203.144.143.9", "203.144.143.10", "203.144.143.11"}; IPAddress remoteAddress = IPAddress.Parse(ServerVariables["REMOTE_ADDR"]); for (int i = 0; i < legitFowardFor.Length; i++) { if (remoteAddress.Equals(IPAddress.Parse(legitFowardFor[i]))) { return ServerVariables["HTTP_X_FORWARDED_FOR"]; } } return ServerVariables["REMOTE_ADDR"]; } public static string SessionMd5(string input) { return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(input, "MD5").ToLower(); } public static byte[] phpBBMd5(byte[] input) { System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); return md5.ComputeHash(input); } /*public static string phpBBMd5(string input) { System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); return ASCIIEncoding.ASCII.GetString(md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(input))); }*/ public static string phpBB3Hash(string password, string setting, ref string itoa64) { string output = "*"; // Check for correct hash if (setting.Substring(0, 3) != "$H$") { return output; } int count_log2 = itoa64.IndexOf(setting[3]); if (count_log2 <= 0) { count_log2 = 0; } if (count_log2 < 7 || count_log2 > 30) { return output; } int count = 1 << count_log2; string salt = setting.Substring(4, 8); if (salt.Length != 8) { return output; } byte[] hash = SessionState.phpBBMd5(ASCIIEncoding.ASCII.GetBytes(salt + password)); //Console.WriteLine(hash.Length); do { hash = SessionState.phpBBMd5(CombineByte(hash, ASCIIEncoding.ASCII.GetBytes(password))); } while ((--count) > 0); output = setting.Substring(0, 12); output += SessionState.phpBB3Encode64(hash, 16, ref itoa64); return output; } private static byte[] CombineByte(byte[] one, byte[] two) { byte[] ret = new byte[one.Length + two.Length]; Array.Copy(one, 0, ret, 0, one.Length); Array.Copy(two, 0, ret, one.Length, two.Length); return ret; } private static string phpBB3Encode64(byte[] input, int count, ref string itoa64) { string output = ""; int i = 0; do { /*Console.WriteLine(UTF7Encoding.UTF7.GetBytes(input[i].ToString()).Length); Console.WriteLine(Convert.ToChar(Convert.ToByte(input[i]))); Console.WriteLine(input[i].ToString());*/ int val = Convert.ToByte(input[i++]); output += itoa64[val & 0x3f]; if (i < count) { val |= Convert.ToByte(input[i]) << 8; } output += itoa64[(val >> 6) & 0x3f]; if (i++ >= count) { break; } if (i < count) { val |= Convert.ToByte(input[i]) << 16; } output += itoa64[(val >> 12) & 0x3f]; if (i++ >= count) { break; } output += itoa64[(val >> 18) & 0x3f]; } while (i < count); return output; } public static void RedirectAuthenticate() { HttpContext.Current.Response.Redirect(string.Format("/sign-in/?redirect={0}", HttpUtility.UrlEncode(HttpContext.Current.Request.RawUrl)), true); } } [XmlRoot("zinzam-cookie")] public class SessionCookie { [XmlElement("autologinid")] public string autoLoginId; [XmlElement("userid")] public long userId; public SessionCookie() { autoLoginId = ""; userId = 0; } } public enum SessionMethods { /// /// /// Cookie, /// /// /// Get } public class InvalidSessionException : Exception { } }