aboutsummaryrefslogtreecommitdiff
path: root/server/_build/default/lib/bcrypt/src
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2025-09-03 21:15:36 -0400
committerCalvin Morrison <calvin@pobox.com>2025-09-03 21:15:36 -0400
commit49fa5aa2a127bdf8924d02bf77e5086b39c7a447 (patch)
tree61d86a7705dacc9fddccc29fa79d075d83ab8059 /server/_build/default/lib/bcrypt/src
i vibe coded itHEADmaster
Diffstat (limited to 'server/_build/default/lib/bcrypt/src')
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt.app.src15
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt.erl91
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_app.erl27
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_nif.erl99
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl50
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl144
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_pool.erl140
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_port.erl157
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl21
-rw-r--r--server/_build/default/lib/bcrypt/src/bcrypt_sup.erl28
10 files changed, 772 insertions, 0 deletions
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt.app.src b/server/_build/default/lib/bcrypt/src/bcrypt.app.src
new file mode 100644
index 0000000..d834377
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt.app.src
@@ -0,0 +1,15 @@
+{application,bcrypt,
+ [{description,"An Erlang wrapper (NIF or port program) for the OpenBSD password scheme, bcrypt."},
+ {vsn,"1.2.0"},
+ {registered,[bcrypt_sup,bcrypt_port_sup,bcrypt_pool]},
+ {mod,{bcrypt_app,[]}},
+ {applications,[kernel,stdlib,crypto,poolboy]},
+ {env,[{default_log_rounds,12},
+ {mechanism,nif},
+ {pool_size,4},
+ {nif_pool_size,4},
+ {nif_pool_max_overflow,10}]},
+ {exclude_files,["priv/bcrypt"]},
+ {maintainers,["Hunter Morris","Mrinal Wadhwa","ErlangPack"]},
+ {licenses,["MIT"]},
+ {links,[{"Github","https://github.com/erlangpack/bcrypt"}]}]}.
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt.erl b/server/_build/default/lib/bcrypt/src/bcrypt.erl
new file mode 100644
index 0000000..f1997c2
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt.erl
@@ -0,0 +1,91 @@
+%% Copyright (c) 2011 Hunter Morris
+%% Distributed under the MIT license; see LICENSE for details.
+%% @doc The OpenBSD Blowfish password hashing algorithm wrapper module.
+-module(bcrypt).
+-author('Hunter Morris <hunter.morris@smarkets.com>').
+
+%% API
+-export([start/0, stop/0]).
+-export([mechanism/0]).
+-export([gen_salt/0, gen_salt/1, hashpw/2]).
+
+-type mechanism() :: nif | port.
+-type rounds() :: 4..31.
+-type pwerr() :: invalid_salt | invalid_salt_length | invalid_rounds.
+
+-export_type([ mechanism/0, rounds/0, pwerr/0 ]).
+
+%% @doc Starts `Application' `bcrypt'.
+%% <b>See also:</b>
+%% [http://erlang.org/doc/man/application.html#start-1 application:start/1].
+
+start() -> application:start(bcrypt).
+
+%% @doc Stops `Application' `bcrypt'.
+%% <b>See also:</b>
+%% [http://erlang.org/doc/man/application.html#stop-1 application:stop/1].
+
+stop() -> application:stop(bcrypt).
+
+%% @doc Get environment setting of hash generation.
+
+-spec mechanism() -> mechanism().
+mechanism() ->
+ {ok, M} = application:get_env(bcrypt, mechanism),
+ M.
+
+%% @doc Returns a random string data.
+
+-spec gen_salt() -> Result when
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt() ->
+ do_gen_salt(mechanism()).
+
+%% @doc Generate a random string data.
+
+-spec gen_salt( Rounds ) -> Result when
+ Rounds :: rounds(),
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt(Rounds) when is_integer(Rounds), Rounds < 32, Rounds > 3 ->
+ do_gen_salt(mechanism(), Rounds).
+
+%% @doc Make hash string based on `Password' and `Salt'.
+
+-spec hashpw( Password, Salt ) -> Result when
+ Password :: [byte()] | binary(),
+ Salt :: [byte()] | binary(),
+ Result :: {ok, Hash} | {error, ErrorDescription},
+ Hash :: [byte()],
+ ErrorDescription :: pwerr().
+hashpw(Password, Salt) ->
+ do_hashpw(mechanism(), Password, Salt).
+
+%% @private
+
+-spec do_gen_salt(nif | port) -> Result when
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+do_gen_salt(nif) -> bcrypt_nif_worker:gen_salt();
+do_gen_salt(port) -> bcrypt_pool:gen_salt().
+
+%% @private
+
+-spec do_gen_salt(nif | port, Rounds) -> Result when
+ Rounds :: rounds(),
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+do_gen_salt(nif, Rounds) -> bcrypt_nif_worker:gen_salt(Rounds);
+do_gen_salt(port, Rounds) -> bcrypt_pool:gen_salt(Rounds).
+
+%% @private
+
+-spec do_hashpw(nif | port, Password, Salt) -> Result when
+ Password :: [byte()] | binary(),
+ Salt :: [byte()],
+ Result :: {ok, Hash} | {error, ErrorDescription},
+ Hash :: [byte()],
+ ErrorDescription :: pwerr().
+do_hashpw(nif, Password, Salt) -> bcrypt_nif_worker:hashpw(Password, Salt);
+do_hashpw(port, Password, Salt) -> bcrypt_pool:hashpw(Password, Salt).
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_app.erl b/server/_build/default/lib/bcrypt/src/bcrypt_app.erl
new file mode 100644
index 0000000..d83db7d
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_app.erl
@@ -0,0 +1,27 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `application' behaviour.
+%% @private
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_app).
+-author('Hunter Morris <hunter.morris@smarkets.com>').
+
+-behaviour(application).
+
+-export([start/2, stop/1]).
+
+-spec start(StartType, StartArgs) -> Result when
+ StartType :: normal,
+ StartArgs :: term(),
+ Result :: {ok, pid()} | {error, Reason},
+ Reason :: term().
+start(normal, _Args) ->
+ case bcrypt_sup:start_link() of
+ {ok, Pid} -> {ok, Pid};
+ {error, _} = Error -> Error
+ end.
+
+-spec stop(State) -> Result when
+ State :: term(),
+ Result :: ok.
+stop(_State) -> ok.
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl
new file mode 100644
index 0000000..348d8df
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl
@@ -0,0 +1,99 @@
+%% @author Hunter Morris <hunter.morris@smarkets.com>
+%% @copyright 2011 Hunter Morris
+%%
+%% @doc Bcrypt Erlang wrapper. <div>The wrapper around the OpenBSD Blowfish password hashing algorithm, as
+%% described in: [http://www.openbsd.org/papers/bcrypt-paper.ps "A Future-Adaptable Password Scheme"]
+%% by Niels Provos and David Mazieres.</div>
+%% @end
+%%
+%% Permission to use, copy, modify, and distribute this software for any
+%% purpose with or without fee is hereby granted, provided that the above
+%% copyright notice and this permission notice appear in all copies.
+
+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-module(bcrypt_nif).
+-author('Hunter Morris <hunter.morris@smarkets.com>').
+
+%% API
+-export([init/0]).
+-export([gen_salt/1, hashpw/5, create_ctx/0]).
+
+-on_load(init/0).
+
+%%--------------------------------------------------------------------
+%% @doc Load the bcrypt NIFs
+%% @private
+%% @end
+%%--------------------------------------------------------------------
+
+-spec init() -> Result when
+ Result :: ok | Error,
+ Error :: {error, {Reason, ErrorText}},
+ Reason :: load_failed | bad_lib | load | reload | upgrade | old_code,
+ ErrorText :: string().
+init() ->
+ Dir = case code:priv_dir(bcrypt) of
+ {error, bad_name} ->
+ case code:which(bcrypt) of
+ Filename when is_list(Filename) ->
+ filename:join(
+ [filename:dirname(Filename), "../priv"]);
+ _ ->
+ "../priv"
+ end;
+ Priv -> Priv
+ end,
+ erlang:load_nif(filename:join(Dir, "bcrypt_nif"), 0).
+
+%%--------------------------------------------------------------------
+%% @doc Generate a random text salt for use with hashpw/3. LogRounds
+%% defines the complexity of the hashing, increasing the cost as
+%% 2^log_rounds.
+%% @end
+%%--------------------------------------------------------------------
+
+-spec gen_salt(LogRounds) -> Result when
+ LogRounds :: integer(),
+ Result :: [byte()].
+gen_salt(LogRounds)
+ when is_integer(LogRounds), LogRounds < 32, LogRounds > 3 ->
+ R = crypto:strong_rand_bytes(16),
+ encode_salt(R, LogRounds).
+
+encode_salt(_R, _LogRounds) ->
+ nif_stub_error(?LINE).
+
+%%--------------------------------------------------------------------
+%% @doc Create a context which hashes passwords in a separate thread.
+%% @end
+%%--------------------------------------------------------------------
+
+-spec create_ctx() -> Context when
+ Context :: term().
+create_ctx() ->
+ nif_stub_error(?LINE).
+
+%%--------------------------------------------------------------------
+%% @doc Hash the specified password and the salt using the OpenBSD
+%% Blowfish password hashing algorithm. Returns the hashed password.
+%% @end
+%%--------------------------------------------------------------------
+
+-spec hashpw(Ctx, Ref, Pid, Password, Salt) -> Result when
+ Ctx :: term(),
+ Ref :: reference(),
+ Pid :: pid(),
+ Password :: [byte()],
+ Salt :: [byte()],
+ Result :: ok.
+hashpw(_Ctx, _Ref, _Pid, _Password, _Salt) ->
+ nif_stub_error(?LINE).
+
+nif_stub_error(Line) ->
+ erlang:nif_error({nif_not_loaded, module, ?MODULE, line, Line}).
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl
new file mode 100644
index 0000000..dbd5868
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl
@@ -0,0 +1,50 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `supervisor' behaviour.
+%% @private
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_nif_pool_sup).
+
+-behaviour(supervisor).
+
+-export([start_link/0, start_child/0, init/1]).
+
+%% @doc Creates a supervisor process as part of a supervision tree.
+
+
+-spec start_link() -> Result when
+ Result :: {ok, pid()} | ignore | {error, StartlinkError},
+ StartlinkError :: {already_started, pid()} | {shutdown, term()} | term().
+start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% @doc Dynamically adds a child specification to supervisor,
+%% which starts the corresponding child process.
+
+-spec start_child() -> Result when
+ Info :: term(),
+ Child :: undefined | pid(),
+ Result :: {ok, Child} | {ok, Child, Info} | {error, StartChildError},
+ StartChildError :: already_present | {already_started, Child} | term().
+start_child() -> supervisor:start_child(?MODULE, []).
+
+-spec init(Args) -> Result when
+ Args :: list(),
+ Result :: {ok,{SupFlags, ChildSpec}} | ignore,
+ SupFlags :: {one_for_one, 10, 10},
+ ChildSpec :: [supervisor:child_spec()].
+init([]) ->
+ {ok, PoolSize} = application:get_env(bcrypt, nif_pool_size),
+ {ok, MaxOverFlow} = application:get_env(bcrypt, nif_pool_max_overflow),
+
+ PoolArgs = [
+ {name, {local, bcrypt_nif_pool}},
+ {size, PoolSize},
+ {max_overflow, MaxOverFlow},
+ {worker_module, bcrypt_nif_worker}
+ ],
+
+ PoolSpecs = [
+ poolboy:child_spec(bcrypt_nif_pool, PoolArgs, [])
+ ],
+
+ {ok, {{one_for_one, 10, 10}, PoolSpecs}}. \ No newline at end of file
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl
new file mode 100644
index 0000000..70b8eed
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl
@@ -0,0 +1,144 @@
+%% @copyright 2011 Hunter Morris.
+%% @doc Implementation of `gen_server' behaviour.
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_nif_worker).
+-author('Hunter Morris <huntermorris@gmail.com>').
+
+-behaviour(gen_server).
+
+-export([start_link/1]).
+-export([gen_salt/0, gen_salt/1]).
+-export([hashpw/2]).
+
+%% gen_server
+-export([init/1, code_change/3, terminate/2,
+ handle_call/3, handle_cast/2, handle_info/2]).
+
+-record(state, {
+ default_log_rounds :: integer(),
+ context :: term()
+ }).
+
+-type state() :: #state{default_log_rounds :: integer(), context :: term()}.
+
+%% @doc Creates a `gen_server' process as part of a supervision tree.
+
+-spec start_link(Args) -> Result when
+ Args :: term(),
+ Result :: {ok,Pid} | ignore | {error,Error},
+ Pid :: pid(),
+ Error :: {already_started,Pid} | term().
+start_link(Args) -> gen_server:start_link(?MODULE, Args, []).
+
+%% @doc Returns bcrypt salt.
+
+-spec gen_salt() -> Result when
+ Result :: [byte()].
+gen_salt() ->
+ poolboy:transaction(bcrypt_nif_pool, fun(Worker) ->
+ gen_server:call(Worker, gen_salt, infinity)
+ end).
+
+%% @doc Returns bcrypt salt.
+
+-spec gen_salt(Rounds) -> Result when
+ Rounds :: bcrypt:rounds(),
+ Result :: [byte()].
+gen_salt(Rounds) ->
+ poolboy:transaction(bcrypt_nif_pool, fun(Worker) ->
+ gen_server:call(Worker, {gen_salt, Rounds}, infinity)
+ end).
+
+%% @doc Make hash string based on `Password' and `Salt'.
+
+-spec hashpw( Password, Salt ) -> Result when
+ Password :: [byte()] | binary(),
+ Salt :: [byte()] | binary(),
+ Result :: {ok, Hash} | {error, ErrorDescription},
+ Hash :: [byte()],
+ ErrorDescription :: bcrypt:pwerr().
+hashpw(Password, Salt) ->
+ poolboy:transaction(bcrypt_nif_pool, fun(Worker) ->
+ gen_server:call(Worker, {hashpw, Password, Salt}, infinity)
+ end).
+
+%% @private
+
+-spec init(Args) -> Result when
+ Args :: list(),
+ Result :: {ok, state()}.
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, Default} = application:get_env(bcrypt, default_log_rounds),
+ Ctx = bcrypt_nif:create_ctx(),
+ {ok, #state{default_log_rounds = Default, context = Ctx}}.
+
+%% @private
+
+terminate(shutdown, _) -> ok.
+
+%% @private
+
+-spec handle_call(Request, From, State) -> Result when
+ Request :: gen_salt,
+ From :: {pid(), atom()},
+ State :: state(),
+ Result :: {reply, Reply, State},
+ Reply :: {ok, Salt},
+ Salt :: integer();
+(Request, From, State) -> Result when
+ Request :: {gen_salt, Rounds},
+ From :: {pid(), atom()},
+ State :: state(),
+ Rounds :: bcrypt:rounds(),
+ Result :: {reply, Reply, State},
+ Reply :: {ok, Salt},
+ Salt :: integer();
+(Request, From, State) -> Result when
+ Request :: {hashpw, Password, Salt},
+ From :: {pid(), atom()},
+ State :: state(),
+ Password :: [byte()],
+ Salt :: integer(),
+ Result :: {reply, Reply, State} | {reply, Reply, State},
+ Reply :: {ok, ResultInfo} | {error, ResultInfo},
+ ResultInfo :: term().
+
+handle_call(gen_salt, _From, #state{default_log_rounds = R} = State) ->
+ Salt = bcrypt_nif:gen_salt(R),
+ {reply, {ok, Salt}, State};
+handle_call({gen_salt, R}, _From, State) ->
+ Salt = bcrypt_nif:gen_salt(R),
+ {reply, {ok, Salt}, State};
+handle_call({hashpw, Password, Salt}, _From, #state{context=Ctx}=State) ->
+ Ref = make_ref(),
+ ok = bcrypt_nif:hashpw(Ctx, Ref, self(), to_list(Password), to_list(Salt)),
+ receive
+ {ok, Ref, Result} ->
+ {reply, {ok, Result}, State};
+ {error, Ref, Result} ->
+ {reply, {error, Result}, State}
+ end;
+handle_call(Msg, _, _) -> exit({unknown_call, Msg}).
+
+%% @private
+
+handle_cast(Msg, _) -> exit({unknown_cast, Msg}).
+
+%% @private
+
+handle_info(Msg, _) -> exit({unknown_info, Msg}).
+
+%% @private
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+-spec to_list(List) -> Result when
+ List :: [byte()],
+ Result :: [byte()];
+(Binary) -> Result when
+ Binary :: binary(),
+ Result :: [byte()].
+to_list(L) when is_list(L) -> L;
+to_list(B) when is_binary(B) -> binary_to_list(B).
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl b/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl
new file mode 100644
index 0000000..7b6ea91
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl
@@ -0,0 +1,140 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `gen_server' behaviour.
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_pool).
+-author('Hunter Morris <huntermorris@gmail.com>').
+
+-behaviour(gen_server).
+
+-export([start_link/0, available/1]).
+-export([gen_salt/0, gen_salt/1]).
+-export([hashpw/2]).
+
+%% gen_server
+-export([init/1, code_change/3, terminate/2,
+ handle_call/3, handle_cast/2, handle_info/2]).
+
+-record(state, {
+ size = 0,
+ busy = 0,
+ requests = queue:new(),
+ ports = queue:new()
+ }).
+
+-record(req, {mon :: reference(), from :: {pid(), atom()}}).
+
+-type state() :: #state{size :: 0, busy :: 0, requests :: queue:queue(), ports :: queue:queue()}.
+
+%% @doc Creates a `gen_server' process as part of a supervision tree.
+
+-spec start_link() -> Result when
+ Result :: {ok,Pid} | ignore | {error,Error},
+ Pid :: pid(),
+ Error :: {already_started,Pid} | term().
+start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+%% @doc Asynchronosly check if `Pid' in `#state:requests' queue or not.
+
+-spec available(Pid) -> Result when
+ Pid :: pid(),
+ Result :: ok.
+available(Pid) -> gen_server:cast(?MODULE, {available, Pid}).
+
+%% @doc Generate a random text salt.
+
+-spec gen_salt() -> Result when
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt() -> do_call(fun bcrypt_port:gen_salt/1, []).
+
+%% @doc Generate a random text salt. Rounds defines the complexity of
+%% the hashing, increasing the cost as 2^log_rounds.
+
+-spec gen_salt(Rounds) -> Result when
+ Rounds :: bcrypt:rounds(),
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt(Rounds) -> do_call(fun bcrypt_port:gen_salt/2, [Rounds]).
+
+%% @doc Hash the specified password and the salt.
+
+hashpw(Password, Salt) -> do_call(fun bcrypt_port:hashpw/3, [Password, Salt]).
+
+%% @private
+
+-spec init([]) -> Result when
+ Result :: {ok, state()}.
+init([]) ->
+ {ok, Size} = application:get_env(bcrypt, pool_size),
+ {ok, #state{size = Size}}.
+
+%% @private
+
+terminate(shutdown, _) -> ok.
+
+%% @private
+
+-spec handle_call(Request, From, State) -> Result when
+ Request :: request,
+ From :: {RPid, atom()},
+ RPid :: pid(),
+ State :: state(),
+ Result :: {noreply, state()} | {reply, {ok, pid()}, state()}.
+handle_call(request, {RPid, _} = From, #state{ports = P} = State) ->
+ case queue:out(P) of
+ {empty, P} ->
+ #state{size = Size, busy = B, requests = R} = State,
+ B1 =
+ if Size > B ->
+ {ok, _} = bcrypt_port_sup:start_child(),
+ B + 1;
+ true ->
+ B
+ end,
+ RRef = erlang:monitor(process, RPid),
+ R1 = queue:in(#req{mon = RRef, from = From}, R),
+ {noreply, State#state{requests = R1,
+ busy = B1}};
+ {{value, PPid}, P1} ->
+ #state{busy = B} = State,
+ {reply, {ok, PPid}, State#state{busy = B + 1, ports = P1}}
+ end;
+handle_call(Msg, _, _) -> exit({unknown_call, Msg}).
+
+%% @private
+
+-spec handle_cast({available, Pid}, state()) -> Result when
+ Pid :: pid(),
+ Result :: {noreply, state()}.
+handle_cast(
+ {available, Pid},
+ #state{requests = R, ports = P, busy = B} = S) ->
+ case queue:out(R) of
+ {empty, R} ->
+ {noreply, S#state{ports = queue:in(Pid, P), busy = B - 1}};
+ {{value, #req{mon = Mon, from = F}}, R1} ->
+ true = erlang:demonitor(Mon, [flush]),
+ gen_server:reply(F, {ok, Pid}),
+ {noreply, S#state{requests = R1}}
+ end;
+handle_cast(Msg, _) -> exit({unknown_cast, Msg}).
+
+%% @private
+
+handle_info({'DOWN', Ref, process, _Pid, _Reason}, #state{requests = R} = State) ->
+ R1 = queue:from_list(lists:keydelete(Ref, #req.mon, queue:to_list(R))),
+ {noreply, State#state{requests = R1}};
+
+%% @private
+
+handle_info(Msg, _) -> exit({unknown_info, Msg}).
+
+%% @private
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+do_call(F, Args0) ->
+ {ok, Pid} = gen_server:call(?MODULE, request, infinity),
+ Args = [Pid|Args0],
+ apply(F, Args).
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_port.erl b/server/_build/default/lib/bcrypt/src/bcrypt_port.erl
new file mode 100644
index 0000000..6365de6
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_port.erl
@@ -0,0 +1,157 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `gen_server' behaviour.
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_port).
+-author('Hunter Morris <hunter.morris@smarkets.com>').
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0, stop/0]).
+-export([gen_salt/1, gen_salt/2]).
+-export([hashpw/3]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-record(state, {
+ port :: port(),
+ default_log_rounds :: non_neg_integer(),
+ cmd_from :: {pid(), term()} | undefined
+ }).
+
+-type state() :: #state{port :: port(),
+ default_log_rounds :: non_neg_integer(),
+ cmd_from :: {pid(), term()} | undefined}.
+
+-define(CMD_SALT, 0).
+-define(CMD_HASH, 1).
+-define(BCRYPT_ERROR(F, D), error_logger:error_msg(F, D)).
+-define(BCRYPT_WARNING(F, D), error_logger:warning_msg(F, D)).
+
+-spec start_link() -> Result when
+ Result :: {ok,Pid} | ignore | {error,Error},
+ Pid :: pid(),
+ Error :: {already_started,Pid} | term(),
+ Pid :: pid().
+start_link() ->
+ Dir = case code:priv_dir(bcrypt) of
+ {error, bad_name} ->
+ case code:which(bcrypt) of
+ Filename when is_list(Filename) ->
+ filename:join(
+ [filename:dirname(Filename), "../priv"]);
+ _ ->
+ "../priv"
+ end;
+ Priv -> Priv
+ end,
+ Port = filename:join(Dir, "bcrypt"),
+ gen_server:start_link(?MODULE, [Port], []).
+
+-spec stop() -> Result when
+ Result :: {stop, normal, ok, state()}.
+stop() -> gen_server:call(?MODULE, stop).
+
+-spec gen_salt(Pid) -> Result when
+ Pid :: pid(),
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt(Pid) ->
+ R = crypto:strong_rand_bytes(16),
+ gen_server:call(Pid, {encode_salt, R}, infinity).
+
+-spec gen_salt(Pid, LogRounds) -> Result when
+ Pid :: pid(),
+ LogRounds :: bcrypt:rounds(),
+ Result :: {ok, Salt},
+ Salt :: [byte()].
+gen_salt(Pid, LogRounds) ->
+ R = crypto:strong_rand_bytes(16),
+ gen_server:call(Pid, {encode_salt, R, LogRounds}, infinity).
+
+-spec hashpw(Pid, Password, Salt) -> Result when
+ Pid :: pid(),
+ Password :: [byte()],
+ Salt :: [byte()],
+ Result :: [byte()].
+hashpw(Pid, Password, Salt) ->
+ gen_server:call(Pid, {hashpw, Password, Salt}, infinity).
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+%% @private
+
+init([Filename]) ->
+ case file:read_file_info(Filename) of
+ {ok, _Info} ->
+ Port = open_port(
+ {spawn, Filename}, [{packet, 2}, binary, exit_status]),
+ ok = bcrypt_pool:available(self()),
+ {ok, Rounds} = application:get_env(bcrypt, default_log_rounds),
+ {ok, #state{port = Port, default_log_rounds = Rounds}};
+ {error, Reason} ->
+ ?BCRYPT_ERROR("Can't open file ~p: ~p", [Filename, Reason]),
+ {stop, error_opening_bcrypt_file}
+ end.
+
+%% @private
+
+terminate(_Reason, #state{port=Port}) ->
+ catch port_close(Port),
+ ok.
+
+%% @private
+
+handle_call({encode_salt, R}, From, #state{default_log_rounds = LogRounds} = State) ->
+ handle_call({encode_salt, R, LogRounds}, From, State);
+handle_call({encode_salt, R, LogRounds}, From, #state{ cmd_from = undefined } = State) ->
+ Port = State#state.port,
+ Data = term_to_binary({?CMD_SALT, {iolist_to_binary(R), LogRounds}}),
+ erlang:port_command(Port, Data),
+ {noreply, State#state{ cmd_from = From }};
+handle_call({encode_salt, _R, _Rounds}, From, #state{ cmd_from = CmdFrom } = State) ->
+ ?BCRYPT_ERROR("bcrypt: Salt request from ~p whilst busy for ~p", [ From, CmdFrom ]),
+ {reply, {error, {busy, From}}, State};
+handle_call({hashpw, Password, Salt}, From, #state{ cmd_from = undefined } = State) ->
+ Port = State#state.port,
+ Data = term_to_binary({?CMD_HASH, {iolist_to_binary(Password), iolist_to_binary(Salt)}}),
+ erlang:port_command(Port, Data),
+ {noreply, State#state{ cmd_from = From }};
+handle_call({hashpw, _Password, _Salt}, From, #state{ cmd_from = CmdFrom } = State) ->
+ ?BCRYPT_ERROR("bcrypt: Hash request from ~p whilst busy for ~p", [ From, CmdFrom ]),
+ {reply, {error, {busy, From}}, State};
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+handle_call(Msg, _, State) ->
+ {stop, {unknown_call, Msg}, State}.
+
+handle_cast(Msg, State) ->
+ {stop, {unknown_cast, Msg}, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+handle_info({Port, {data, Data}}, #state{ port = Port, cmd_from = From } = State) ->
+ Reply =
+ case binary_to_term(Data) of
+ {_, Error} when is_atom(Error) ->
+ {error, Error};
+ {?CMD_SALT, Result} when is_binary(Result) ->
+ {ok, binary_to_list(Result)};
+ {?CMD_HASH, Result} when is_binary(Result) ->
+ {ok, binary_to_list(Result)}
+ end,
+ gen_server:reply(From, Reply),
+ ok = bcrypt_pool:available(self()),
+ {noreply, State#state{ cmd_from = undefined }};
+handle_info({Port, {exit_status, Status}}, #state{port=Port}=State) ->
+ %% Rely on whomever is supervising this process to restart.
+ ?BCRYPT_WARNING("Port died: ~p", [Status]),
+ {stop, port_died, State};
+handle_info(Msg, _) ->
+ exit({unknown_info, Msg}).
+
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl
new file mode 100644
index 0000000..89fe33d
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl
@@ -0,0 +1,21 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `supervisor' behaviour.
+%% @private
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_port_sup).
+-author('Hunter Morris <huntermorris@gmail.com>').
+
+-behaviour(supervisor).
+
+-export([start_link/0, start_child/0, init/1]).
+
+start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+start_child() -> supervisor:start_child(?MODULE, []).
+
+init([]) ->
+ {ok, {{simple_one_for_one, 1, 1},
+ [{undefined,
+ {bcrypt_port, start_link, []},
+ transient, brutal_kill, worker, [bcrypt_port]}]}}.
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl
new file mode 100644
index 0000000..502a6a3
--- /dev/null
+++ b/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl
@@ -0,0 +1,28 @@
+%% @copyright 2011 Hunter Morris
+%% @doc Implementation of `supervisor' behaviour.
+%% @private
+%% @end
+%% Distributed under the MIT license; see LICENSE for details.
+-module(bcrypt_sup).
+-author('Hunter Morris <huntermorris@gmail.com>').
+
+-behaviour(supervisor).
+
+-export([start_link/0, init/1]).
+
+start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+ PortChildren
+ = [{bcrypt_port_sup, {bcrypt_port_sup, start_link, []}, permanent,
+ 16#ffffffff, supervisor, [bcrypt_port_sup]},
+ {bcrypt_pool, {bcrypt_pool, start_link, []}, permanent,
+ 16#ffffffff, worker, [bcrypt_pool]}],
+ NifChildren
+ = [{bcrypt_nif_pool_sup, {bcrypt_nif_pool_sup, start_link, []}, permanent,
+ 16#ffffffff, supervisor, [bcrypt_nif_pool_sup]}],
+ case application:get_env(bcrypt, mechanism) of
+ undefined -> {stop, no_mechanism_defined};
+ {ok, nif} -> {ok, {{one_for_all, 15, 60}, NifChildren}};
+ {ok, port} -> {ok, {{one_for_all, 15, 60}, PortChildren}}
+ end.