<commit_before>% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.

-module(couch_auth_cache).
-behaviour(gen_server).
-vsn(2).
-behaviour(config_listener).

% public API
-export([get_user_creds/1, get_user_creds/2, update_user_creds/3]).
-export([get_admin/1, add_roles/2, auth_design_doc/1]).

% gen_server API
-export([start_link/0, init/1, handle_call/3, handle_info/2, handle_cast/2]).
-export([code_change/3, terminate/2]).

-export([handle_config_change/5, handle_config_terminate/3]).
-export([handle_db_event/3]).

-include_lib("couch/include/couch_db.hrl").
-include_lib("couch/include/couch_js_functions.hrl").

-define(STATE, auth_state_ets).
-define(BY_USER, auth_by_user_ets).
-define(BY_ATIME, auth_by_atime_ets).

-record(state, {
    max_cache_size = 0,
    cache_size = 0,
    db_notifier = nil,
    db_mon_ref = nil,
    closed = [],
    event_listener = nil
}).


-spec get_user_creds(UserName::string() | binary()) ->
    {ok, Credentials::list(), term()} | nil.

get_user_creds(UserName) ->
    get_user_creds(nil, UserName).

-spec get_user_creds(Req::#httpd{}, UserName::string() | binary()) ->
    {ok, Credentials::list(), term()} | nil.

get_user_creds(Req, UserName) when is_list(UserName) ->
    get_user_creds(Req, ?l2b(UserName));

get_user_creds(_Req, UserName) ->
    UserCreds = case get_admin(UserName) of
    nil ->
        get_from_cache(UserName);
    Props ->
        case get_from_cache(UserName) of
        nil ->
            Props;
        UserProps when is_list(UserProps) ->
            add_roles(Props, couch_util:get_value(<<"roles">>, UserProps))
        end
    end,
    validate_user_creds(UserCreds).

update_user_creds(_Req, UserDoc, _AuthCtx) ->
    DbNameList = config:get("couch_httpd_auth", "authentication_db", "_users"),
    couch_util:with_db(?l2b(DbNameList), fun(UserDb) ->
        {ok, _NewRev} = couch_db:update_doc(UserDb, UserDoc, []),
        ok
    end).

add_roles(Props, ExtraRoles) ->
    CurrentRoles = couch_util:get_value(<<"roles">>, Props),
    lists:keyreplace(<<"roles">>, 1, Props, {<<"roles">>, CurrentRoles ++ ExtraRoles}).

get_admin(UserName) when is_binary(UserName) -><commit_msg>get_user_creds can receive nil as first arg<commit_after>% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.

-module(couch_auth_cache).
-behaviour(gen_server).
-vsn(2).
-behaviour(config_listener).

% public API
-export([get_user_creds/1, get_user_creds/2, update_user_creds/3]).
-export([get_admin/1, add_roles/2, auth_design_doc/1]).

% gen_server API
-export([start_link/0, init/1, handle_call/3, handle_info/2, handle_cast/2]).
-export([code_change/3, terminate/2]).

-export([handle_config_change/5, handle_config_terminate/3]).
-export([handle_db_event/3]).

-include_lib("couch/include/couch_db.hrl").
-include_lib("couch/include/couch_js_functions.hrl").

-define(STATE, auth_state_ets).
-define(BY_USER, auth_by_user_ets).
-define(BY_ATIME, auth_by_atime_ets).

-record(state, {
    max_cache_size = 0,
    cache_size = 0,
    db_notifier = nil,
    db_mon_ref = nil,
    closed = [],
    event_listener = nil
}).


-spec get_user_creds(UserName::string() | binary()) ->
    {ok, Credentials::list(), term()} | nil.

get_user_creds(UserName) ->
    get_user_creds(nil, UserName).

-spec get_user_creds(Req::#httpd{} | nil, UserName::string() | binary()) ->
    {ok, Credentials::list(), term()} | nil.

get_user_creds(Req, UserName) when is_list(UserName) ->
    get_user_creds(Req, ?l2b(UserName));

get_user_creds(_Req, UserName) ->
    UserCreds = case get_admin(UserName) of
    nil ->
        get_from_cache(UserName);
    Props ->
        case get_from_cache(UserName) of
        nil ->
            Props;
        UserProps when is_list(UserProps) ->
            add_roles(Props, couch_util:get_value(<<"roles">>, UserProps))
        end
    end,
    validate_user_creds(UserCreds).

update_user_creds(_Req, UserDoc, _AuthCtx) ->
    DbNameList = config:get("couch_httpd_auth", "authentication_db", "_users"),
    couch_util:with_db(?l2b(DbNameList), fun(UserDb) ->
        {ok, _NewRev} = couch_db:update_doc(UserDb, UserDoc, []),
        ok
    end).

add_roles(Props, ExtraRoles) ->
    CurrentRoles = couch_util:get_value(<<"roles">>, Props),
    lists:keyreplace(<<"roles">>, 1, Props, {<<"roles">>, CurrentRoles ++ ExtraRoles}).

get_admin(UserName) when is_binary(UserName) ->
{'fraction_non_alphanumeric': 0.141707225758143, 'fraction_numerical': 0.009734181954324224, 'mean_word_length': 4.222873900293255, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 45, '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': '4859185', 'n_tokens_mistral': 1907, 'n_tokens_neox': 1888, 'n_words': 405}