diff --git a/apps/iot/src/endpoint/iot_jinzhi_endpoint.erl b/apps/iot/src/endpoint/iot_jinzhi_endpoint.erl index df1f5e4..2cb7743 100644 --- a/apps/iot/src/endpoint/iot_jinzhi_endpoint.erl +++ b/apps/iot/src/endpoint/iot_jinzhi_endpoint.erl @@ -93,11 +93,16 @@ handle_call(_Request, _From, State = #state{}) -> {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). handle_cast({forward, LocationCode, DynamicLocationCode, EventType, Params}, State = #state{id = Id, timer_map = TimerMap, pri_key = PriKey, url = Url}) -> - ReqBody = format_events(LocationCode, DynamicLocationCode, EventType, Params, PriKey), - catch do_post(Url, Id, ReqBody), - TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}), + try + ReqBody = format_event(LocationCode, DynamicLocationCode, EventType, Params, PriKey), + catch do_post(Url, Id, ReqBody), + TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}), - {noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}}. + {noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}} + catch _:Err:Stack -> + lager:warning("[iot_jinzhi_endpoint] format_event get error: ~p, stack: ~p", [Err, Stack]), + {noreply, State} + end. %% @private %% @doc Handling all non call/cast messages @@ -174,8 +179,8 @@ do_post(Url, Id, Body) when is_list(Url), is_integer(Id), is_binary(Body) -> end). %% 格式话要发送的数据,避免多次格式化处理 --spec format_events(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map(), PriKey :: public_key:private_key()) -> binary(). -format_events(LocationCode, DynamicLocationCode, EventType, #{<<"event_code">> := EventCode, <<"description">> := Description, <<"datetime">> := Datetime, <<"attachments">> := Attachments0}, PriKey) +-spec format_event(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map(), PriKey :: public_key:private_key()) -> binary(). +format_event(LocationCode, DynamicLocationCode, EventType, #{<<"event_code">> := EventCode, <<"description">> := Description, <<"datetime">> := Datetime, <<"attachments">> := Attachments0}, PriKey) when is_binary(LocationCode), is_binary(DynamicLocationCode), is_integer(EventType) -> Attachments = lists:map(fun(#{<<"filename">> := Filename}) -> @@ -205,7 +210,7 @@ format_events(LocationCode, DynamicLocationCode, EventType, #{<<"event_code">> : }, ReqData = #{ - <<"sign">> => iot_jinzhi_signer:sign(DeviceInfo, PriKey), + <<"sign">> => sign(DeviceInfo, PriKey), <<"sysId">> => ?SYS_ID, <<"taskId">> => generate_task_id(DynamicLocationCode, EventCode), <<"count">> => 1, @@ -232,4 +237,43 @@ generate_private_key(PriFile) when is_list(PriFile) -> %% 私钥保存解析后的 {ok, PriKeyData} = file:read_file(PriKeyFile), PriDerData = base64:decode(PriKeyData), - public_key:der_decode('PrivateKeyInfo', PriDerData). \ No newline at end of file + public_key:der_decode('PrivateKeyInfo', PriDerData). + + +%% 数据签名 +-spec sign(M :: #{}, PrivateKey :: public_key:private_key()) -> binary(). +sign(M, PrivateKey) when is_map(M) -> + Json = serialize(M), + Hash = iolist_to_binary(io_lib:format("~64.16.0b", [binary:decode_unsigned(crypto:hash(sha256, Json))])), + RsaEncoded = public_key:encrypt_private(Hash, PrivateKey), + base64:encode(RsaEncoded). + +%% 简单的序列号,sign签名 +-spec serialize(M :: map()) -> JsonString :: binary(). +serialize(M) when is_map(M) -> + L = maps:to_list(M), + L1 = lists:sort(fun({K, _}, {K1, _}) -> K < K1 end, L), + serialize0(L1, []). + +serialize0([], Target) -> + B = iolist_to_binary(lists:join(<<$,>>, lists:reverse(Target))), + <<${, B/binary, $}>>; +serialize0([{K, V}|T], Target) -> + V1 = if + is_integer(V) -> + integer_to_binary(V); + is_float(V) -> + float_to_binary(V); + is_binary(V) -> + <<$", V/binary, $">>; + is_boolean(V) andalso V -> + <<"true">>; + is_boolean(V) andalso not V -> + <<"false">>; + is_list(V) -> + Items = lists:map(fun(E) -> serialize(E) end, V), + V0 = iolist_to_binary(lists:join(<<$,>>, Items)), + <<$[, V0/binary, $]>> + end, + Item = <<$", K/binary, $", $:, V1/binary>>, + serialize0(T, [Item|Target]). \ No newline at end of file diff --git a/apps/iot/src/util/iot_jinzhi_signer.erl b/apps/iot/src/util/iot_jinzhi_signer.erl deleted file mode 100644 index 67a6483..0000000 --- a/apps/iot/src/util/iot_jinzhi_signer.erl +++ /dev/null @@ -1,51 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author anlicheng -%%% @copyright (C) 2024, -%%% @doc -%%% 中电的签名逻辑 -%%% @end -%%% Created : 02. 9月 2024 11:28 -%%%------------------------------------------------------------------- --module(iot_jinzhi_signer). --author("anlicheng"). - -%% API --export([sign/2]). - -%% 数据签名 --spec sign(M :: #{}, PrivateKey :: public_key:private_key()) -> binary(). -sign(M, PrivateKey) when is_map(M) -> - Json = serialize(M), - Hash = iolist_to_binary(io_lib:format("~64.16.0b", [binary:decode_unsigned(crypto:hash(sha256, Json))])), - RsaEncoded = public_key:encrypt_private(Hash, PrivateKey), - - base64:encode(RsaEncoded). - -%% 简单的序列号,sign签名 --spec serialize(M :: map()) -> JsonString :: binary(). -serialize(M) when is_map(M) -> - L = maps:to_list(M), - L1 = lists:sort(fun({K, _}, {K1, _}) -> K < K1 end, L), - serialize(L1, []). -serialize([], Target) -> - B = iolist_to_binary(lists:join(<<$,>>, lists:reverse(Target))), - <<${, B/binary, $}>>; -serialize([{K, V}|T], Target) -> - V1 = if - is_integer(V) -> - integer_to_binary(V); - is_float(V) -> - float_to_binary(V); - is_binary(V) -> - <<$", V/binary, $">>; - is_boolean(V) andalso V -> - <<"true">>; - is_boolean(V) andalso not V -> - <<"false">>; - is_list(V) -> - Items = lists:map(fun(E) -> serialize(E) end, V), - V0 = iolist_to_binary(lists:join(<<$,>>, Items)), - <<$[, V0/binary, $]>> - end, - Item = <<$", K/binary, $", $:, V1/binary>>, - serialize(T, [Item|Target]). \ No newline at end of file