summaryrefslogtreecommitdiff |
diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | conf/yaws.conf.m4 | 2 | ||||
-rw-r--r-- | src/db/db_node.erl | 1 | ||||
-rw-r--r-- | src/player/plr_handler.erl | 40 | ||||
-rw-r--r-- | src/player/plr_shim.erl | 23 | ||||
-rw-r--r-- | src/player/query/plr_sign_in.erl | 131 | ||||
-rw-r--r-- | src/player/reply/plr_set_session.erl | 30 | ||||
-rw-r--r-- | src/query/qry_handler.erl | 1 | ||||
-rw-r--r-- | src/shared/shr_security.erl | 9 | ||||
-rw-r--r-- | src/shared/struct/shr_player.erl | 202 |
10 files changed, 437 insertions, 4 deletions
@@ -114,7 +114,7 @@ debug_rebuild: ifeq ($(wildcard $(DIALYZER_PLT_FILE)),) debug_run: - $(DIALYZER_EXEC) --build_plt --apps erts kernel stdlib jiffy mnesia \ + $(DIALYZER_EXEC) --build_plt --apps erts kernel stdlib crypto jiffy mnesia \ --output_plt $(DIALYZER_PLT_FILE) $(MAKE) debug_rebuild $(DIALYZER_EXEC) --add_to_plt --plt $(DIALYZER_PLT_FILE) -r $(BIN_DIR) diff --git a/conf/yaws.conf.m4 b/conf/yaws.conf.m4 index d108c73..f0bfeef 100644 --- a/conf/yaws.conf.m4 +++ b/conf/yaws.conf.m4 @@ -110,6 +110,6 @@ keepalive_timeout = 30000 listen = 0.0.0.0 docroot = __MAKEFILE_WWW_DIR auth_log = true - appmods = btl_character_turn btl_load map_load map_update + appmods = btl_character_turn btl_load map_load map_update plr_sign_in plr_sign_up start_mod = qry_handler </server> diff --git a/src/db/db_node.erl b/src/db/db_node.erl index aaf6ae3..f94e3bd 100644 --- a/src/db/db_node.erl +++ b/src/db/db_node.erl @@ -27,6 +27,7 @@ wait_for_stop () -> start () -> Mnesia = db_model:new("/tmp/to_db_node.mnesia", []), db_model:start(Mnesia), + db_model:add_db(player_db, Mnesia), db_model:add_db(battle_db, Mnesia), db_model:add_db(map_db, Mnesia), wait_for_stop(), diff --git a/src/player/plr_handler.erl b/src/player/plr_handler.erl new file mode 100644 index 0000000..e1cabe3 --- /dev/null +++ b/src/player/plr_handler.erl @@ -0,0 +1,40 @@ +-module(plr_handler). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([start/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec ensure_player_exists (binary()) -> 'ok'. +ensure_player_exists (ID) -> + case shr_database:fetch(player_db, ID, admin) of + {ok, _} -> ok; + not_found -> + shr_database:insert + ( + player_db, + ID, + any, + any, + plr_shim:generate_random_player(ID) + ) + end, + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec start (pid()) -> 'ok'. +start (TimedCachesManagerPid) -> + ensure_player_exists(<<"0">>), + ensure_player_exists(<<"1">>), + shr_timed_caches_manager:new_cache(TimedCachesManagerPid, player_db, none), + ok. diff --git a/src/player/plr_shim.erl b/src/player/plr_shim.erl new file mode 100644 index 0000000..c5da825 --- /dev/null +++ b/src/player/plr_shim.erl @@ -0,0 +1,23 @@ +-module(plr_shim). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([generate_random_player/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_random_player (binary()) -> shr_player:type(). +generate_random_player (ID) -> + Result = shr_player:new(ID, ID, <<"kalimero">>), + + Result. diff --git a/src/player/query/plr_sign_in.erl b/src/player/query/plr_sign_in.erl new file mode 100644 index 0000000..e872a55 --- /dev/null +++ b/src/player/query/plr_sign_in.erl @@ -0,0 +1,131 @@ +-module(plr_sign_in). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../../../include/yaws_api.hrl"). + +-record +( + input, + { + username :: binary(), + password :: binary() + } +). + +-record +( + query_state, + { + player :: shr_player:type() + } +). + +-type input() :: #input{}. +-type query_state() :: #query_state{}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([out/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec parse_input (binary()) -> input(). +parse_input (Req) -> + JSONReqMap = jiffy:decode(Req, [return_maps]), + Username = maps:get(<<"usr">>, JSONReqMap), + Password = maps:get(<<"pwd">>, JSONReqMap), + + #input + { + username = Username, + password = Password + }. + +-spec fetch_data (input()) -> query_state(). +fetch_data (Input) -> + PlayerID = Input#input.username, + + Player = shr_timed_cache:fetch(player_db, any, PlayerID), + + #query_state + { + player = Player + }. + +-spec update_data (query_state(), input()) -> query_state(). +update_data (QueryState, Input) -> + InputPassword = Input#input.password, + Player = QueryState#query_state.player, + + true = (shr_player:password_is(InputPassword, Player)), + + S0Player = shr_player:new_token(Player), + S1Player = shr_player:refresh_active(S0Player), + + QueryState#query_state + { + player = S1Player + }. + +-spec commit_update (query_state(), input()) -> 'ok'. +commit_update (QueryState, Input) -> + PlayerID = Input#input.username, + UpdatedPlayer = QueryState#query_state.player, + NewToken = shr_player:get_token(UpdatedPlayer), + NewActiveTime = shr_player:get_last_active(UpdatedPlayer), + + Query = + shr_db_query:new + ( + player_db, + PlayerID, + {user, PlayerID}, + [ + shr_db_query:set_field + ( + shr_player:get_token_field(), + NewToken + ), + shr_db_query:set_field + ( + shr_player:get_last_active_field(), + NewActiveTime + ) + ] + ), + + shr_database:commit(Query), + shr_timed_cache:update(player_db, PlayerID, PlayerID, UpdatedPlayer), + + 'ok'. + +-spec generate_reply(query_state()) -> binary(). +generate_reply (QueryState) -> + Player = QueryState#query_state.player, + + SetSession = plr_set_session:generate(Player), + Output = jiffy:encode([SetSession]), + + Output. + +-spec handle (binary()) -> binary(). +handle (Req) -> + Input = parse_input(Req), + QueryState = fetch_data(Input), + Update = update_data(QueryState, Input), + commit_update(Update, Input), + generate_reply(QueryState). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +out(A) -> + { + content, + "application/json; charset=UTF-8", + handle(A#arg.clidata) + }. diff --git a/src/player/reply/plr_set_session.erl b/src/player/reply/plr_set_session.erl new file mode 100644 index 0000000..8b38fd7 --- /dev/null +++ b/src/player/reply/plr_set_session.erl @@ -0,0 +1,30 @@ +-module(plr_set_session). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([generate/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate (shr_player:type()) -> {list(any())}. +generate (Player) -> + PID = shr_player:get_id(Player), + SessionToken = shr_player:get_token(Player), + + { + [ + {<<"msg">>, <<"sse">>}, + {<<"pid">>, PID}, + {<<"stk">>, SessionToken} + ] + }. diff --git a/src/query/qry_handler.erl b/src/query/qry_handler.erl index 15f766e..9ba88f0 100644 --- a/src/query/qry_handler.erl +++ b/src/query/qry_handler.erl @@ -19,6 +19,7 @@ -spec start (any()) -> 'ok'. start (_YawsParams) -> {ok, TimedCachesManagerPid} = shr_timed_caches_manager:start(), + ok = plr_handler:start(TimedCachesManagerPid), ok = btl_handler:start(TimedCachesManagerPid), ok = map_handler:start(TimedCachesManagerPid), ok. diff --git a/src/shared/shr_security.erl b/src/shared/shr_security.erl index 724b241..740e948 100644 --- a/src/shared/shr_security.erl +++ b/src/shared/shr_security.erl @@ -23,8 +23,13 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec assert_identity (any(), any()) -> 'unimplemented'. -assert_identity (_PlayerID, _SessionToken) -> unimplemented. +-spec assert_identity (any(), any()) -> 'ok'. +assert_identity (PlayerID, SessionToken) -> + Player = shr_timed_cache:fetch(player_db, any, PlayerID), + + true = (shr_player:get_token(Player) == SessionToken), + + ok. -spec lock_queries (any()) -> 'unimplemented'. lock_queries (_PlayerID) -> unimplemented. diff --git a/src/shared/struct/shr_player.erl b/src/shared/struct/shr_player.erl new file mode 100644 index 0000000..b036cb6 --- /dev/null +++ b/src/shared/struct/shr_player.erl @@ -0,0 +1,202 @@ +-module(shr_player). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type id() :: binary(). + +-record +( + player, + { + id :: id(), + username :: binary(), + % {salt(crypto:strong_rand_bytes(128)), hash(sha384)} + password :: {binary(), binary()}, + token :: binary(), % salt(crypto:strong_rand_bytes(512)) + email :: binary(), + last_active :: integer(), + maps :: list(binary()), + characters :: list(binary()) + } +). + +-opaque type() :: #player{}. + +-export_type([type/0, id/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( + [ + new/3 + ] +). + +%%%% Accessors +-export +( + [ + get_id/1, + get_username/1, + get_password/1, + get_token/1, + get_email/1, + get_last_active/1, + get_maps/1, + get_characters/1, + + set_username/2, + set_password/2, + new_token/1, + set_email/2, + refresh_active/1, + set_maps/2, + set_characters/2 + ] +). + +-export +( + [ + get_id_field/0, + get_username_field/0, + get_password_field/0, + get_token_field/0, + get_email_field/0, + get_last_active_field/0, + get_maps_field/0, + get_characters_field/0 + ] +). + +-export +( + [ + password_is/2 + ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec secure_value (binary(), binary()) -> binary(). +secure_value (Salt, Val) -> + SaltedVal = erlang:iolist_to_binary([Salt, Val]), + HashedSaltedVal = crypto:hash(sha384, SaltedVal), + + HashedSaltedVal. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new (binary(), binary(), binary()) -> type(). +new (ID, Username, Password) -> + Result = + #player + { + id = ID, + username = Username, + password = {<<"">>, <<"">>}, + token = <<"">>, + email = <<"">>, + last_active = 0, + maps = [], + characters = [] + }, + + S0Result = set_password(Password, Result), + S1Result = new_token(S0Result), + S2Result = refresh_active(S1Result), + + S2Result. + +%%%% Accessors +-spec get_id (type()) -> id(). +get_id (Player) -> Player#player.id. + +-spec get_username (type()) -> binary(). +get_username (Player) -> Player#player.username. + +-spec get_password (type()) -> {binary(), binary()}. +get_password (Player) -> Player#player.password. + +-spec get_token (type()) -> binary(). +get_token (Player) -> Player#player.token. + +-spec get_email (type()) -> binary(). +get_email (Player) -> Player#player.email. + +-spec get_last_active (type()) -> integer(). +get_last_active (Player) -> Player#player.last_active. + +-spec get_maps (type()) -> list(binary()). +get_maps (Player) -> Player#player.maps. + +-spec get_characters (type()) -> list(binary()). +get_characters (Player) -> Player#player.characters. + +-spec set_username (binary(), type()) -> type(). +set_username (Val, Player) -> Player#player{ username = Val }. + +-spec set_password (binary(), type()) -> type(). +set_password (Val, Player) -> + NewSalt = crypto:strong_rand_bytes(128), + HashedSaltedVal = secure_value(NewSalt, Val), + + Player#player + { + password = {NewSalt, HashedSaltedVal} + }. + +-spec new_token (type()) -> type(). +new_token (Player) -> Player#player{ token = crypto:strong_rand_bytes(512) }. + +-spec set_email (binary(), type()) -> type(). +set_email (Val, Player) -> Player#player{ email = Val }. + +-spec refresh_active (type()) -> type(). +refresh_active (Player) -> + Player#player + { + last_active = erlang:system_time(second) + }. + +-spec set_maps (list(binary()), type()) -> type(). +set_maps (Maps, Player) -> Player#player{ maps = Maps }. + +-spec set_characters (list(binary()), type()) -> type(). +set_characters (Characters, Player) -> Player#player{ characters = Characters }. + +-spec get_id_field () -> non_neg_integer(). +get_id_field () -> #player.id. + +-spec get_username_field () -> non_neg_integer(). +get_username_field () -> #player.username. + +-spec get_password_field () -> non_neg_integer(). +get_password_field () -> #player.password. + +-spec get_token_field () -> non_neg_integer(). +get_token_field () -> #player.token. + +-spec get_email_field () -> non_neg_integer(). +get_email_field () -> #player.email. + +-spec get_last_active_field () -> non_neg_integer(). +get_last_active_field () -> #player.last_active. + +-spec get_maps_field () -> non_neg_integer(). +get_maps_field () -> #player.maps. + +-spec get_characters_field () -> non_neg_integer(). +get_characters_field () -> #player.characters. + +-spec password_is (binary(), type()) -> boolean(). +password_is (Val, Player) -> + {Salt, HashedSaltedVal} = Player#player.password, + HashedSaltedCandidate = secure_value(Salt, Val), + + (HashedSaltedCandidate == HashedSaltedVal). |