<commit_before>%%% ocs_eap_fsm.erl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% @copyright 2016 SigScale Global Inc.
%%% @end
%%% 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% @reference <a href="http://tools.ietf.org/rfc/rfc3579.txt">
%%% 	RFC3579 - RADIUS Support For EAP</a>
%%%
-module(ocs_eap_fsm).
-copyright('Copyright (c) 2016 SigScale Global Inc.').

-behaviour(gen_fsm).

%% export the ocs_eap_fsm API
-export([]).

%% export the ocs_eap_fsm state callbacks
-export([idle/2, wait_for_id/2, wait_for_commit/2, wait_for_confirm/2]).

%% export the call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
			terminate/3, code_change/4]).

%% @headerfile "include/radius.hrl"
-include_lib("radius/include/radius.hrl").
-include("ocs_eap_codec.hrl").
-record(statedata,
		{address :: inet:ip_address(),
		port :: pos_integer(),
		session_id:: {NAS :: inet:ip_address() | string(),
				Port :: string(), Peer :: string()},
		radius_id :: byte(),
		eap_id :: byte(),
		grp_dec  = 19 :: byte(),
		rand_func = 1 :: byte(),
		prf = 1 :: byte(),
		authenticator :: binary(),
		secret :: binary(),
		password :: binary(),
		radius_fsm :: pid(),
		token :: binary(),
		prep :: none | rfc2759 | saslprep,
		peer_id :: string(),
		pwe :: binary(),
		s_rand :: integer(),
		scalar_s :: binary(),
		element_s :: binary(),
		scalar_p :: binary(),
		element_p :: binary(),
		ks :: binary(),
		confirm_s :: binary()}).

-define(TIMEOUT, 30000).

%%----------------------------------------------------------------------
%%  The ocs_eap_fsm API
%%----------------------------------------------------------------------

%%----------------------------------------------------------------------
%%  The ocs_eap_fsm gen_fsm call backs
%%----------------------------------------------------------------------

-spec init(Args :: list()) ->
	Result :: {ok, StateName :: atom(), StateData :: #statedata{}}
		| {ok, StateName :: atom(), StateData :: #statedata{},
			Timeout :: non_neg_integer() | infinity}
		| {ok, StateName :: atom(), StateData :: #statedata{}, hibernate}
		| {stop, Reason :: term()} | ignore.
%% @doc Initialize the {@module} finite state machine.
%% @see //stdlib/gen_fsm:init/1
%% @private
%%
init([RadiusFsm, Address, Port, Identifier,
		Authenticator, Secret, SessionID] = _Args) ->
	process_flag(trap_exit, true),
	StateData = #statedata{radius_fsm = RadiusFsm, address = Address,
			port = Port, authenticator = Authenticator, secret = Secret,
			radius_id = Identifier, session_id = SessionID},
	{ok, idle, StateData, 0}.

-spec idle(Event :: timeout | term(), StateData :: #statedata{}) ->
	Result :: {next_state, NextStateName :: atom(), NewStateData :: #statedata{}}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{},
		Timeout :: non_neg_integer() | infinity}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{}, hibernate}
		| {stop, Reason :: normal | term(), NewStateData :: #statedata{}}.
%% @doc Handle events sent with {@link //stdlib/gen_fsm:send_event/2.
%%		gen_fsm:send_event/2} in the <b>idle</b> state.
%% @@see //stdlib/gen_fsm:StateName/2
%% @private
idle(timeout, #statedata{radius_fsm = RadiusFsm, radius_id = RadiusID,
		authenticator = RequestAuthenticator, secret = Secret} = StateData) ->
	EapID = 1,
	Token = crypto:rand_bytes(4),
	{ok, HostName} = inet:gethostname(),
	Body = #eap_pwd_id{group_desc = 19, rand_func = 1, prf = 1, token = <PASSWORD>,
			pwd_prep = none, identity = HostName},
	BodyData = ocs_eap_codec:eap_pwd_id(Body),
	Header = #eap_pwd{type = ?PWD, length = false,
			more = false, pwd_exch = id, data = BodyData},
	EAPData = ocs_eap_codec:eap_pwd(Header),
	Packet = #eap_packet{code = ?Request,
			identifier = EapID, data = EAPData},
	EAPPacketData = ocs_eap_codec:eap_packet(Packet),
	AttributeList0 = radius_attributes:new(),
	AttributeList1 = radius_attributes:store(?EAPMessage,
			EAPPacketData, AttributeList0),
	AttributeList2 = radius_attributes:store(?MessageAuthenticator,
			<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>, AttributeList1),
	AttrList2bin = radius_attributes:codec(AttributeList2),
	Response1 = #radius{code = ?AccessChallenge, id = RadiusID,
			authenticator = RequestAuthenticator, attributes = AttrList2bin},
	ResponsePacket1 = radius:codec(Response1),
	MessageAuthenticator = crypto:hmac(md5, Secret, ResponsePacket1),
	AttributeList3 = radius_attributes:store(?MessageAuthenticator,
			MessageAuthenticator, AttributeList1),
	AttributeData = radius_attributes:codec(AttributeList3),
	Length = size(AttributeData) + 20,
	ResponseAuthenticator = crypto:hash(md5,[<<?AccessChallenge, RadiusID,
			Length:16>>, RequestAuthenticator, AttributeData, Secret]),
	Response = #radius{code = ?AccessChallenge, id = RadiusID,
			authenticator = ResponseAuthenticator, attributes = AttributeData},
	ResponsePacket = radius:codec(Response),
	radius:response(RadiusFsm, {response, ResponsePacket}),
	NewStateData = StateData#statedata{eap_id = EapID,
			token = Token, prep = none},
	{next_state, wait_for_id, NewStateData, ?TIMEOUT}.

-spec wait_for_id(Event :: timeout | term(), StateData :: #statedata{}) ->
	Result :: {next_state, NextStateName :: atom(), NewStateData :: #statedata{}}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{},
		Timeout :: non_neg_integer() | infinity}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{}, hibernate}
		| {stop, Reason :: normal | term(), NewStateData :: #statedata{}}.
%% @doc Handle events sent with {@link //stdlib/gen_fsm:send_event/2.
%%		gen_fsm:send_event/2} in the <b>wait_for_id</b> state. This state is responsible
%%		for sending EAP-PWD-ID request to peer.
%% @@see //stdlib/gen_fsm:StateName/2
%% @private
%%
wait_for_id(timeout, #statedata{session_id = SessionID} = StateData)->
	{stop, {shutdown, SessionID}, StateData};
wait_for_id({eap_response, RadiusFsm, EAPPacket} , #statedata{token = Token,
		eap_id = EapID, radius_id = RadiusID, secret = Secret,
		authenticator = RequestAuthenticator} = StateData)->
	{ok, HostName_s} = inet:gethostname(),
	HostName = list_to_binary(HostName_s),
	S_rand = crypto:rand_uniform(1, ?R),
	try<commit_msg>add missing data to record and statedata<commit_after>%%% ocs_eap_fsm.erl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% @copyright 2016 SigScale Global Inc.
%%% @end
%%% 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% @reference <a href="http://tools.ietf.org/rfc/rfc3579.txt">
%%% 	RFC3579 - RADIUS Support For EAP</a>
%%%
-module(ocs_eap_fsm).
-copyright('Copyright (c) 2016 SigScale Global Inc.').

-behaviour(gen_fsm).

%% export the ocs_eap_fsm API
-export([]).

%% export the ocs_eap_fsm state callbacks
-export([idle/2, wait_for_id/2, wait_for_commit/2, wait_for_confirm/2]).

%% export the call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
			terminate/3, code_change/4]).

%% @headerfile "include/radius.hrl"
-include_lib("radius/include/radius.hrl").
-include("ocs_eap_codec.hrl").
-record(statedata,
		{address :: inet:ip_address(),
		port :: pos_integer(),
		session_id:: {NAS :: inet:ip_address() | string(),
				Port :: string(), Peer :: string()},
		radius_id :: byte(),
		eap_id :: byte(),
		grp_dec  = 19 :: byte(),
		rand_func = 1 :: byte(),
		prf = 1 :: byte(),
		authenticator :: binary(),
		secret :: binary(),
		password :: binary(),
		radius_fsm :: pid(),
		token :: binary(),
		prep :: none | rfc2759 | saslprep,
		peer_id :: string(),
		pwe :: binary(),
		s_rand :: integer(),
		scalar_s :: binary(),
		element_s :: binary(),
		scalar_p :: binary(),
		element_p :: binary(),
		ks :: binary(),
		confirm_s :: binary()}).

-define(TIMEOUT, 30000).

%%----------------------------------------------------------------------
%%  The ocs_eap_fsm API
%%----------------------------------------------------------------------

%%----------------------------------------------------------------------
%%  The ocs_eap_fsm gen_fsm call backs
%%----------------------------------------------------------------------

-spec init(Args :: list()) ->
	Result :: {ok, StateName :: atom(), StateData :: #statedata{}}
		| {ok, StateName :: atom(), StateData :: #statedata{},
			Timeout :: non_neg_integer() | infinity}
		| {ok, StateName :: atom(), StateData :: #statedata{}, hibernate}
		| {stop, Reason :: term()} | ignore.
%% @doc Initialize the {@module} finite state machine.
%% @see //stdlib/gen_fsm:init/1
%% @private
%%
init([RadiusFsm, Address, Port, Identifier,
		Authenticator, Secret, SessionID] = _Args) ->
	process_flag(trap_exit, true),
	StateData = #statedata{radius_fsm = RadiusFsm, address = Address,
			port = Port, authenticator = Authenticator, secret = Secret,
			radius_id = Identifier, session_id = SessionID},
	{ok, idle, StateData, 0}.

-spec idle(Event :: timeout | term(), StateData :: #statedata{}) ->
	Result :: {next_state, NextStateName :: atom(), NewStateData :: #statedata{}}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{},
		Timeout :: non_neg_integer() | infinity}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{}, hibernate}
		| {stop, Reason :: normal | term(), NewStateData :: #statedata{}}.
%% @doc Handle events sent with {@link //stdlib/gen_fsm:send_event/2.
%%		gen_fsm:send_event/2} in the <b>idle</b> state.
%% @@see //stdlib/gen_fsm:StateName/2
%% @private
idle(timeout, #statedata{radius_fsm = RadiusFsm, radius_id = RadiusID,
		authenticator = RequestAuthenticator, secret = Secret} = StateData) ->
	EapID = 1,
	Token = crypto:rand_bytes(4),
	{ok, HostName} = inet:gethostname(),
	Body = #eap_pwd_id{group_desc = 19, random_fun = 1, prf = 1, token = Token,
			pwd_prep = none, identity = HostName},
	BodyData = ocs_eap_codec:eap_pwd_id(Body),
	Header = #eap_pwd{type = ?PWD, length = false,
			more = false, pwd_exch = id, data = BodyData},
	EAPData = ocs_eap_codec:eap_pwd(Header),
	Packet = #eap_packet{code = ?Request,
			identifier = EapID, data = EAPData},
	EAPPacketData = ocs_eap_codec:eap_packet(Packet),
	AttributeList0 = radius_attributes:new(),
	AttributeList1 = radius_attributes:store(?EAPMessage,
			EAPPacketData, AttributeList0),
	AttributeList2 = radius_attributes:store(?MessageAuthenticator,
			<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>, AttributeList1),
	AttrList2bin = radius_attributes:codec(AttributeList2),
	Response1 = #radius{code = ?AccessChallenge, id = RadiusID,
			authenticator = RequestAuthenticator, attributes = AttrList2bin},
	ResponsePacket1 = radius:codec(Response1),
	MessageAuthenticator = crypto:hmac(md5, Secret, ResponsePacket1),
	AttributeList3 = radius_attributes:store(?MessageAuthenticator,
			MessageAuthenticator, AttributeList1),
	AttributeData = radius_attributes:codec(AttributeList3),
	Length = size(AttributeData) + 20,
	ResponseAuthenticator = crypto:hash(md5,[<<?AccessChallenge, RadiusID,
			Length:16>>, RequestAuthenticator, AttributeData, Secret]),
	Response = #radius{code = ?AccessChallenge, id = RadiusID,
			authenticator = ResponseAuthenticator, attributes = AttributeData},
	ResponsePacket = radius:codec(Response),
	radius:response(RadiusFsm, {response, ResponsePacket}),
	NewStateData = StateData#statedata{eap_id = EapID, grp_dec = 19,
			rand_func = 1, prf = 1, token = Token, prep = none},
	{next_state, wait_for_id, NewStateData, ?TIMEOUT}.

-spec wait_for_id(Event :: timeout | term(), StateData :: #statedata{}) ->
	Result :: {next_state, NextStateName :: atom(), NewStateData :: #statedata{}}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{},
		Timeout :: non_neg_integer() | infinity}
		| {next_state, NextStateName :: atom(), NewStateData :: #statedata{}, hibernate}
		| {stop, Reason :: normal | term(), NewStateData :: #statedata{}}.
%% @doc Handle events sent with {@link //stdlib/gen_fsm:send_event/2.
%%		gen_fsm:send_event/2} in the <b>wait_for_id</b> state. This state is responsible
%%		for sending EAP-PWD-ID request to peer.
%% @@see //stdlib/gen_fsm:StateName/2
%% @private
%%
wait_for_id(timeout, #statedata{session_id = SessionID} = StateData)->
	{stop, {shutdown, SessionID}, StateData};
wait_for_id({eap_response, RadiusFsm, EAPPacket} , #statedata{token = Token,
		eap_id = EapID, radius_id = RadiusID, secret = Secret,
		authenticator = RequestAuthenticator} = StateData)->
	{ok, HostName_s} = inet:gethostname(),
	HostName = list_to_binary(HostName_s),
	S_rand = crypto:rand_uniform(1, ?R),
	try
{'fraction_non_alphanumeric': 0.21064899118653943, 'fraction_numerical': 0.014130672299511982, 'mean_word_length': 4.264570552147239, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 38, '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': '71120', 'n_tokens_mistral': 4780, 'n_tokens_neox': 4463, 'n_words': 1061}