<commit_before>﻿//  Copyright (C) 2015, The Duplicati Team

//  http://www.duplicati.com, <EMAIL>
//
//  This library is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as
//  published by the Free Software Foundation; either version 2.1 of the
//  License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Collections.Concurrent;
using System.Linq;
using HttpServer;
using HttpServer.HttpModules;
using System.Collections.Generic;

namespace Duplicati.Server.WebServer
{
    internal class AuthenticationHandler : HttpModule
    {
        private const string AUTH_COOKIE_NAME = "session-auth";
        private const string NONCE_COOKIE_NAME = "session-nonce";

        private const string XSRF_COOKIE_NAME = "xsrf-token";
        private const string XSRF_HEADER_NAME = "X-XSRF-Token";

        private const string TRAYICONPASSWORDSOURCE_HEADER = "X-TrayIcon-PasswordSource";

        public const string LOGIN_SCRIPT_URI = "/login.cgi";
        public const string LOGOUT_SCRIPT_URI = "/logout.cgi";
        public const string CAPTCHA_IMAGE_URI = RESTHandler.API_URI_PATH + "/captcha/";

        private const int XSRF_TIMEOUT_MINUTES = 10;
        private const int AUTH_TIMEOUT_MINUTES = 10;

        private ConcurrentDictionary<string, DateTime> m_activeTokens = new ConcurrentDictionary<string, DateTime>();
        private ConcurrentDictionary<string, Tuple<DateTime, string>> m_activeNonces = new ConcurrentDictionary<string, Tuple<DateTime, string>>();
        private ConcurrentDictionary<string, DateTime> m_activexsrf = new ConcurrentDictionary<string, DateTime>();

        System.Security.Cryptography.RandomNumberGenerator m_prng = System.Security.Cryptography.RNGCryptoServiceProvider.Create();

        private string FindXSRFToken(HttpServer.IHttpRequest request)
        {
            string xsrftoken = request.Headers[XSRF_HEADER_NAME] ?? "";

            if (!string.IsNullOrWhiteSpace(xsrftoken))
                xsrftoken = Duplicati.Library.Utility.Uri.UrlDecode(xsrftoken);

            if (string.IsNullOrWhiteSpace(xsrftoken))
            {
                var xsrfq = request.Form[XSRF_HEADER_NAME] ?? request.Form[Duplicati.Library.Utility.Uri.UrlEncode(XSRF_HEADER_NAME)];
                xsrftoken = (xsrfq == null || string.IsNullOrWhiteSpace(xsrfq.Value)) ? "" : xsrfq.Value;
            }

            if (string.IsNullOrWhiteSpace(xsrftoken))
            {
                var xsrfq = request.QueryString[XSRF_HEADER_NAME] ?? request.QueryString[Duplicati.Library.Utility.Uri.UrlEncode(XSRF_HEADER_NAME)];
                xsrftoken = (xsrfq == null || string.IsNullOrWhiteSpace(xsrfq.Value)) ? "" : xsrfq.Value;
            }

            return xsrftoken;
        }

        private bool AddXSRFTokenToRespone(HttpServer.IHttpResponse response)
        {
            if (m_activexsrf.Count > 500)
                return false;

            var buf = new byte[32];
            var expires = DateTime.UtcNow.AddMinutes(XSRF_TIMEOUT_MINUTES);
            m_prng.GetBytes(buf);
            // Don't use non-safe chars, as the current webserver has some "trouble" parsing it
            var token = BitConverter.ToString(buf).Replace("-", string.Empty); //Convert.ToBase64String(buf);

            m_activexsrf.AddOrUpdate(token, key => expires, (key, existingExpires) =>
            {
                // Simulate the original behavior => if the random token, against all odds, is already used
                // we throw an ArgumentException
                throw new ArgumentException("An element with the same key already exists in the dictionary.");
            });

            response.Cookies.Add(new HttpServer.ResponseCookie(XSRF_COOKIE_NAME, token, expires));
            return true;
        }

        private string FindAuthCookie(HttpServer.IHttpRequest request)<commit_msg>Removed some unnecessary changes, turned out it was a simple cache issue. This fixes #2699 This fixes #2635<commit_after>﻿//  Copyright (C) 2015, The Duplicati Team

//  http://www.duplicati.com, <EMAIL>
//
//  This library is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as
//  published by the Free Software Foundation; either version 2.1 of the
//  License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Collections.Concurrent;
using System.Linq;
using HttpServer;
using HttpServer.HttpModules;
using System.Collections.Generic;

namespace Duplicati.Server.WebServer
{
    internal class AuthenticationHandler : HttpModule
    {
        private const string AUTH_COOKIE_NAME = "session-auth";
        private const string NONCE_COOKIE_NAME = "session-nonce";

        private const string XSRF_COOKIE_NAME = "xsrf-token";
        private const string XSRF_HEADER_NAME = "X-XSRF-Token";

        private const string TRAYICONPASSWORDSOURCE_HEADER = "X-TrayIcon-PasswordSource";

        public const string LOGIN_SCRIPT_URI = "/login.cgi";
        public const string LOGOUT_SCRIPT_URI = "/logout.cgi";
        public const string CAPTCHA_IMAGE_URI = RESTHandler.API_URI_PATH + "/captcha/";

        private const int XSRF_TIMEOUT_MINUTES = 10;
        private const int AUTH_TIMEOUT_MINUTES = 10;

        private ConcurrentDictionary<string, DateTime> m_activeTokens = new ConcurrentDictionary<string, DateTime>();
        private ConcurrentDictionary<string, Tuple<DateTime, string>> m_activeNonces = new ConcurrentDictionary<string, Tuple<DateTime, string>>();
        private ConcurrentDictionary<string, DateTime> m_activexsrf = new ConcurrentDictionary<string, DateTime>();

        System.Security.Cryptography.RandomNumberGenerator m_prng = System.Security.Cryptography.RNGCryptoServiceProvider.Create();

        private string FindXSRFToken(HttpServer.IHttpRequest request)
        {
            string xsrftoken = request.Headers[XSRF_HEADER_NAME] ?? "";

            if (string.IsNullOrWhiteSpace(xsrftoken))
            {
                var xsrfq = request.Form[XSRF_HEADER_NAME] ?? request.Form[Duplicati.Library.Utility.Uri.UrlEncode(XSRF_HEADER_NAME)];
                xsrftoken = (xsrfq == null || string.IsNullOrWhiteSpace(xsrfq.Value)) ? "" : xsrfq.Value;
            }

            if (string.IsNullOrWhiteSpace(xsrftoken))
            {
                var xsrfq = request.QueryString[XSRF_HEADER_NAME] ?? request.QueryString[Duplicati.Library.Utility.Uri.UrlEncode(XSRF_HEADER_NAME)];
                xsrftoken = (xsrfq == null || string.IsNullOrWhiteSpace(xsrfq.Value)) ? "" : xsrfq.Value;
            }

            return xsrftoken;
        }

        private bool AddXSRFTokenToRespone(HttpServer.IHttpResponse response)
        {
            if (m_activexsrf.Count > 500)
                return false;

            var buf = new byte[32];
            var expires = DateTime.UtcNow.AddMinutes(XSRF_TIMEOUT_MINUTES);
            m_prng.GetBytes(buf);
            var token = Convert.ToBase64String(buf);

            m_activexsrf.AddOrUpdate(token, key => expires, (key, existingExpires) =>
            {
                // Simulate the original behavior => if the random token, against all odds, is already used
                // we throw an ArgumentException
                throw new ArgumentException("An element with the same key already exists in the dictionary.");
            });

            response.Cookies.Add(new HttpServer.ResponseCookie(XSRF_COOKIE_NAME, token, expires));
            return true;
        }

        private string FindAuthCookie(HttpServer.IHttpRequest request)
{'fraction_non_alphanumeric': 0.08608037274315666, 'fraction_numerical': 0.008153756552125802, 'mean_word_length': 2.922338967565098, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5930596', 'n_tokens_mistral': 2474, 'n_tokens_neox': 2364, 'n_words': 669}