WIP
This commit is contained in:
parent
a164af45cd
commit
1a33e2d9e2
@ -55,6 +55,7 @@ start(normal, _Args) ->
|
|||||||
ok = tell(error, "DANGER! This node is in distributed mode!"),
|
ok = tell(error, "DANGER! This node is in distributed mode!"),
|
||||||
init:stop(1)
|
init:stop(1)
|
||||||
end,
|
end,
|
||||||
|
ok = application:ensure_started(sasl),
|
||||||
ok = application:ensure_started(hakuzaru),
|
ok = application:ensure_started(hakuzaru),
|
||||||
ok = application:ensure_started(zxwidgets),
|
ok = application:ensure_started(zxwidgets),
|
||||||
gmc_sup:start_link().
|
gmc_sup:start_link().
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
open_wallet/2, close_wallet/0, new_wallet/3, import_wallet/3, drop_wallet/2,
|
open_wallet/2, close_wallet/0, new_wallet/3, import_wallet/3, drop_wallet/2,
|
||||||
password/2,
|
password/2,
|
||||||
refresh/0,
|
refresh/0,
|
||||||
nonce/1, spend/2, chain/1, grids/1,
|
nonce/1, spend/2, chain/1, grids/1, sign_mess/1,
|
||||||
make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1,
|
make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1,
|
||||||
add_node/1, set_sole_node/1]).
|
add_node/1, set_sole_node/1]).
|
||||||
-export([encrypt/2, decrypt/2]).
|
-export([encrypt/2, decrypt/2]).
|
||||||
@ -147,6 +147,13 @@ grids(String) ->
|
|||||||
gen_server:cast(?MODULE, {grids, String}).
|
gen_server:cast(?MODULE, {grids, String}).
|
||||||
|
|
||||||
|
|
||||||
|
-spec sign_mess(Request) -> ok
|
||||||
|
when Request :: map().
|
||||||
|
|
||||||
|
sign_mess(Request) ->
|
||||||
|
gen_server:cast(?MODULE, {sign_mess, Request}).
|
||||||
|
|
||||||
|
|
||||||
-spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok
|
-spec make_key(Type, Size, Name, Seed, Encoding, Transform) -> ok
|
||||||
when Type :: {eddsa, ed25519},
|
when Type :: {eddsa, ed25519},
|
||||||
Size :: 256,
|
Size :: 256,
|
||||||
@ -335,6 +342,9 @@ handle_cast({chain, ID}, State) ->
|
|||||||
handle_cast({grids, String}, State) ->
|
handle_cast({grids, String}, State) ->
|
||||||
ok = do_grids(String),
|
ok = do_grids(String),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
handle_cast({sign_mess, Request}, State) ->
|
||||||
|
ok = do_sign_mess(Request, State),
|
||||||
|
{noreply, State};
|
||||||
handle_cast({make_key, Name, Seed, Encoding, Transform}, State) ->
|
handle_cast({make_key, Name, Seed, Encoding, Transform}, State) ->
|
||||||
NewState = do_make_key(Name, Seed, Encoding, Transform, State),
|
NewState = do_make_key(Name, Seed, Encoding, Transform, State),
|
||||||
{noreply, NewState};
|
{noreply, NewState};
|
||||||
@ -521,9 +531,82 @@ do_grids(String) ->
|
|||||||
Error -> gmc_gui:trouble(Error)
|
Error -> gmc_gui:trouble(Error)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
do_grids2({{sign, http}, URL}) ->
|
||||||
|
case httpc:request(URL) of
|
||||||
|
{ok, {{_, 200, _}, _, JSON}} -> do_grids_sig(JSON, URL);
|
||||||
|
Error -> gmc_gui:trouble(Error)
|
||||||
|
end;
|
||||||
do_grids2(Instruction) ->
|
do_grids2(Instruction) ->
|
||||||
tell("GRIDS: ~tp", [Instruction]).
|
tell("GRIDS: ~tp", [Instruction]).
|
||||||
|
|
||||||
|
do_grids_sig(JSON, URL) ->
|
||||||
|
case zj:decode(JSON) of
|
||||||
|
{ok, GRIDS} -> do_grids_sig2(GRIDS#{"url" => URL});
|
||||||
|
Error -> gmc_gui:trouble(Error)
|
||||||
|
end.
|
||||||
|
|
||||||
|
do_grids_sig2(Request = #{"grids" := 1, "type" := "message"}) ->
|
||||||
|
gmc_gui:grids_mess_sig(Request);
|
||||||
|
do_grids_sig2(WTF) ->
|
||||||
|
gmc_gui:trouble({trash, WTF}).
|
||||||
|
|
||||||
|
|
||||||
|
do_sign_mess(Request = #{"public_id" := ID, "payload" := Message},
|
||||||
|
#s{wallet = #wallet{keys = Keys}}) ->
|
||||||
|
case lists:keyfind(ID, #key.id, Keys) of
|
||||||
|
#key{pair = #{secret := PrivKey}} ->
|
||||||
|
Sig = base64:encode(sign_message(list_to_binary(Message), PrivKey)),
|
||||||
|
do_sign_mess2(Request#{"signature" => Sig});
|
||||||
|
false ->
|
||||||
|
gmc_gui:trouble({bad_key, ID})
|
||||||
|
end.
|
||||||
|
|
||||||
|
do_sign_mess2(Request = #{"url" := URL}) ->
|
||||||
|
ResponseKeys =
|
||||||
|
["grids",
|
||||||
|
"chain",
|
||||||
|
"network_id",
|
||||||
|
"type",
|
||||||
|
"public_id",
|
||||||
|
"payload",
|
||||||
|
"signature"],
|
||||||
|
Response = zj:encode(maps:with(ResponseKeys, Request)),
|
||||||
|
case httpc:request(post, {URL, [], "application/json", Response}, [], []) of
|
||||||
|
{ok, {{_, 200, _}, _, JSON}} -> log(info, "Signature posted: ~p", [JSON]);
|
||||||
|
Error -> gmc_gui:trouble(Error)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
% TODO: Should probably be part of Hakuzaru
|
||||||
|
sign_message(Message, PrivKey) ->
|
||||||
|
Prefix = <<"Gajumaru Signed Message:\n">>,
|
||||||
|
{ok, PSize} = vencode(byte_size(Prefix)),
|
||||||
|
{ok, MSize} = vencode(byte_size(Message)),
|
||||||
|
Smashed = iolist_to_binary([PSize, Prefix, MSize, Message]),
|
||||||
|
{ok, Hashed} = eblake2:blake2b(32, Smashed),
|
||||||
|
ecu_eddsa:sign_detached(Hashed, PrivKey).
|
||||||
|
|
||||||
|
|
||||||
|
vencode(N) when N < 0 ->
|
||||||
|
{error, {negative_N, N}};
|
||||||
|
vencode(N) when N < 16#FD ->
|
||||||
|
{ok, <<N>>};
|
||||||
|
vencode(N) when N =< 16#FFFF ->
|
||||||
|
NBytes = eu(N, 2),
|
||||||
|
{ok, <<16#FD, NBytes/binary>>};
|
||||||
|
vencode(N) when N =< 16#FFFF_FFFF ->
|
||||||
|
NBytes = eu(N, 4),
|
||||||
|
{ok, <<16#FE, NBytes/binary>>};
|
||||||
|
vencode(N) when N < (2 bsl 64) ->
|
||||||
|
NBytes = eu(N, 8),
|
||||||
|
{ok, <<16#FF, NBytes/binary>>}.
|
||||||
|
|
||||||
|
eu(N, Size) ->
|
||||||
|
Bytes = binary:encode_unsigned(N, little),
|
||||||
|
NExtraZeros = Size - byte_size(Bytes),
|
||||||
|
ExtraZeros = << <<0>> || _ <- lists:seq(1, NExtraZeros) >>,
|
||||||
|
<<Bytes/binary, ExtraZeros/binary>>.
|
||||||
|
|
||||||
|
|
||||||
do_spend(KeyID, TX, State = #s{wallet = #wallet{keys = Keys}}) ->
|
do_spend(KeyID, TX, State = #s{wallet = #wallet{keys = Keys}}) ->
|
||||||
case lists:keyfind(KeyID, #key.id, Keys) of
|
case lists:keyfind(KeyID, #key.id, Keys) of
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
-behavior(wx_object).
|
-behavior(wx_object).
|
||||||
-include_lib("wx/include/wx.hrl").
|
-include_lib("wx/include/wx.hrl").
|
||||||
-export([show/1, wallet/1, chain/2, trouble/1, ask_password/0]).
|
-export([show/1, wallet/1, chain/2, trouble/1, ask_password/0]).
|
||||||
|
-export([grids_mess_sig/1]).
|
||||||
-export([start_link/1]).
|
-export([start_link/1]).
|
||||||
-export([init/1, terminate/2, code_change/3,
|
-export([init/1, terminate/2, code_change/3,
|
||||||
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
|
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
|
||||||
@ -68,6 +69,10 @@ ask_password() ->
|
|||||||
wx_object:cast(?MODULE, password).
|
wx_object:cast(?MODULE, password).
|
||||||
|
|
||||||
|
|
||||||
|
grids_mess_sig(Request) ->
|
||||||
|
wx_object:cast(?MODULE, {grids_mess_sig, Request}).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Startup Functions
|
%%% Startup Functions
|
||||||
|
|
||||||
@ -235,6 +240,9 @@ handle_cast({trouble, Info}, State) ->
|
|||||||
handle_cast(password, State) ->
|
handle_cast(password, State) ->
|
||||||
ok = do_ask_password(State),
|
ok = do_ask_password(State),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
handle_cast({grids_mess_sig, Request}, State) ->
|
||||||
|
ok = do_grids_mess_sig(Request, State),
|
||||||
|
{noreply, State};
|
||||||
handle_cast(Unexpected, State) ->
|
handle_cast(Unexpected, State) ->
|
||||||
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
|
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
@ -925,6 +933,58 @@ do_ask_password(#s{frame = Frame, prefs = Prefs, j = J}) ->
|
|||||||
end,
|
end,
|
||||||
wxDialog:destroy(Dialog).
|
wxDialog:destroy(Dialog).
|
||||||
|
|
||||||
|
do_grids_mess_sig(_, #s{accounts = []}) ->
|
||||||
|
ok;
|
||||||
|
do_grids_mess_sig(Request = #{"public_id" := false},
|
||||||
|
State = #s{picker = Picker, accounts = Accounts}) ->
|
||||||
|
case wxListBox:getSelection(Picker) of
|
||||||
|
-1 ->
|
||||||
|
ok;
|
||||||
|
Selected ->
|
||||||
|
#poa{id = ID} = lists:nth(Selected + 1, Accounts),
|
||||||
|
do_grids_mess_sig2(Request#{"public_id" := ID}, State)
|
||||||
|
end.
|
||||||
|
|
||||||
|
do_grids_mess_sig2(Request = #{"url" := URL, "public_id" := ID, "payload" := Message},
|
||||||
|
#s{frame = Frame, j = J}) ->
|
||||||
|
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Message Signature Request")),
|
||||||
|
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
||||||
|
Instruction =
|
||||||
|
J("The server at the URL below is requesting you sign the following message."),
|
||||||
|
InstTx = wxStaticText:new(Dialog, ?wxID_ANY, Instruction),
|
||||||
|
AcctSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Signature Account")}]),
|
||||||
|
AcctTx = wxStaticText:new(Dialog, ?wxID_ANY, ID),
|
||||||
|
_ = wxStaticBoxSizer:add(AcctSz, AcctTx, zxw:flags(wide)),
|
||||||
|
URL_Label = J("Originating URL"),
|
||||||
|
URL_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, URL_Label}]),
|
||||||
|
URL_Tx = wxStaticText:new(Dialog, ?wxID_ANY, URL),
|
||||||
|
_ = wxStaticBoxSizer:add(URL_Sz, URL_Tx, zxw:flags(wide)),
|
||||||
|
MessSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Message")}]),
|
||||||
|
MessTx = wxStaticText:new(Dialog, ?wxID_ANY, Message),
|
||||||
|
_ = wxStaticBoxSizer:add(MessSz, MessTx, zxw:flags(wide)),
|
||||||
|
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||||
|
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
||||||
|
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
||||||
|
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(Sizer, InstTx, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(Sizer, AcctSz, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(Sizer, URL_Sz, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(Sizer, MessTx, zxw:flags(wide)),
|
||||||
|
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(base)),
|
||||||
|
ok = wxDialog:setSizer(Dialog, Sizer),
|
||||||
|
ok = wxFrame:setSize(Dialog, {500, 500}),
|
||||||
|
ok = wxBoxSizer:layout(Sizer),
|
||||||
|
ok = wxFrame:center(Dialog),
|
||||||
|
ok =
|
||||||
|
case wxDialog:showModal(Dialog) of
|
||||||
|
?wxID_OK -> gmc_con:sign_mess(Request);
|
||||||
|
?wxID_CANCEL -> ok
|
||||||
|
end,
|
||||||
|
wxDialog:destroy(Dialog);
|
||||||
|
do_grids_mess_sig2(BadRequest, _) ->
|
||||||
|
tell("Bad request: ~tp", [BadRequest]).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Helpers
|
%%% Helpers
|
||||||
|
@ -32,15 +32,13 @@ safe_size(Prefs) ->
|
|||||||
Display = wxDisplay:new(),
|
Display = wxDisplay:new(),
|
||||||
GSize = wxDisplay:getGeometry(Display),
|
GSize = wxDisplay:getGeometry(Display),
|
||||||
ok = wxDisplay:destroy(Display),
|
ok = wxDisplay:destroy(Display),
|
||||||
Geometry =
|
case maps:find(geometry, Prefs) of
|
||||||
case maps:find(geometry, Prefs) of
|
{ok, none} ->
|
||||||
{ok, none} ->
|
{X, Y, _, _} = GSize,
|
||||||
{X, Y, _, _} = GSize,
|
{center, {X, Y, 700, 500}};
|
||||||
{center, {X, Y, 700, 500}};
|
{ok, G} ->
|
||||||
{ok, G} ->
|
{pref, G};
|
||||||
{pref, G};
|
error ->
|
||||||
error ->
|
{X, Y, _, _} = GSize,
|
||||||
{X, Y, _, _} = GSize,
|
{center, {X, Y, 700, 500}}
|
||||||
{center, {X, Y, 700, 500}}
|
end.
|
||||||
end,
|
|
||||||
Geometry.
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user