Realm creation
This commit is contained in:
parent
82ea25f1ec
commit
20f27cbcab
227
zx
227
zx
@ -1404,8 +1404,10 @@ dialyze() ->
|
||||
|
||||
create_realm() ->
|
||||
ConfFile = filename:join(zomp_dir(), "zomp.conf"),
|
||||
{ok, ZompConf} = file:consult(ConfFile),
|
||||
create_realm(ZompConf).
|
||||
case file:consult(ConfFile) of
|
||||
{ok, ZompConf} -> create_realm(ZompConf);
|
||||
{error, enoent} -> create_realm([])
|
||||
end.
|
||||
|
||||
create_realm(ZompConf) ->
|
||||
Instructions =
|
||||
@ -1426,107 +1428,115 @@ create_realm(ZompConf) ->
|
||||
create_realm(ZompConf)
|
||||
end;
|
||||
false ->
|
||||
ok = io:format("Bad realm name ~tp. Try again.~n", [Realm]),
|
||||
ok = io:format("Bad realm name \"~ts\". Try again.~n", [Realm]),
|
||||
create_realm(ZompConf)
|
||||
end.
|
||||
|
||||
create_realm(ZompConf, Realm) ->
|
||||
{external_address, XA} = lists:keyfind(external_address, 1, ZompConf),
|
||||
ExAddress =
|
||||
case lists:keyfind(external_address, 1, ZompConf) of
|
||||
false -> prompt_external_address();
|
||||
{external_address, none} -> prompt_external_address();
|
||||
{external_address, Current} -> prompt_external_address(Current)
|
||||
end,
|
||||
create_realm(ZompConf, Realm, ExAddress).
|
||||
|
||||
prompt_external_address() ->
|
||||
Message = external_address_prompt(),
|
||||
ok = io:format(Message),
|
||||
case get_input() of
|
||||
"" ->
|
||||
ok = io:format("You need to enter an address.~n"),
|
||||
prompt_external_address();
|
||||
String ->
|
||||
parse_address(String)
|
||||
end.
|
||||
|
||||
prompt_external_address(Current) ->
|
||||
XAString =
|
||||
case inet:ntoa(XA) of
|
||||
{error, einval} -> XA;
|
||||
String -> String
|
||||
case inet:ntoa(Current) of
|
||||
{error, einval} -> Current;
|
||||
XAS -> XAS
|
||||
end,
|
||||
Message =
|
||||
external_address_prompt() ++
|
||||
" [The current public address is: ~ts. Press <ENTER> to keep this address.]~n",
|
||||
ok = io:format(Message, [XAString]),
|
||||
case get_input() of
|
||||
"" -> Current;
|
||||
String -> parse_address(String)
|
||||
end.
|
||||
|
||||
external_address_prompt() ->
|
||||
"~n"
|
||||
" Enter a static, valid hostname or IPv4 or IPv6 address at which this host "
|
||||
"can be reached from the public internet (or internal network if it will never "
|
||||
"need to be reached from the internet).~n"
|
||||
" DO NOT INCLUDE A PORT NUMBER IN THIS STEP~n".
|
||||
|
||||
parse_address(String) ->
|
||||
case inet:parse_address(String) of
|
||||
{ok, Address} -> Address;
|
||||
{error, einval} -> String
|
||||
end.
|
||||
|
||||
create_realm(ZompConf, Realm, ExAddress) ->
|
||||
Current =
|
||||
case lists:keyfind(external_port, 1, ZompConf) of
|
||||
false -> 11311;
|
||||
{external_port, none} -> 11311;
|
||||
{external_port, P} -> P
|
||||
end,
|
||||
Message =
|
||||
"~n"
|
||||
" Enter a static, valid hostname or IPv4 or IPv6 address at which this host "
|
||||
"can be reached from the public internet (or internal network if it will never "
|
||||
"need to be reached from the internet).~n"
|
||||
" The current public address is: ~ts. Press <ENTER> to keep this address.~n"
|
||||
" DO NOT INCLUDE A PORT NUMBER IN THIS STEP~n",
|
||||
ok = io:format(Message, [XAString]),
|
||||
Input = get_input(),
|
||||
ExAddress =
|
||||
case
|
||||
|
||||
|
||||
|
||||
{Host, Port} =
|
||||
case proplists:get(external_address, 1, ZompConf) of
|
||||
{external_address, ExAddress} ->
|
||||
{external_port, ExPort} = lists:keyfind(external_port, 1, ZompConf),
|
||||
{ExAddress, ExPort};
|
||||
false ->
|
||||
prompt_prime(Realm)
|
||||
end,
|
||||
HostString =
|
||||
Instructions =
|
||||
"~n"
|
||||
" Accept current config?~n"
|
||||
" Host: ~ts Port: ~w~n",
|
||||
ok = io:format(Instructions, [Host, Port]),
|
||||
case string:trim(io:get_line("(^C to quit) [Y]/n: ")) of
|
||||
"" -> create_realm(Realm, Prime);
|
||||
"Y" -> create_realm(Realm, Prime);
|
||||
"y" -> create_realm(Realm, Prime);
|
||||
_ -> prompt_prime(Realm)
|
||||
end.
|
||||
|
||||
prompt_prime(Realm) ->
|
||||
HostInstructions =
|
||||
"~n"
|
||||
" Enter the prime (permanent) server's publicly accessible hostname or "
|
||||
"address. If prime is identified by an address and not a name, enter it "
|
||||
"as either a normal IPv4 dot-notation or IPv6 colon-notation.~n"
|
||||
" Note that address ranges will not be checked for validity.~n",
|
||||
ok = io:format(HostInstructions),
|
||||
HostString = get_input(),
|
||||
Host =
|
||||
case inet:parse_address(HostString) of
|
||||
{ok, Address} -> Address;
|
||||
{error, einval} -> HostString
|
||||
end,
|
||||
|
||||
create_prime(Realm, Host) ->
|
||||
ok = io:format("~n Enter the local port number on which the host listen.~n"),
|
||||
case prompt_port_number() of
|
||||
{ok, ExPort} -> create_prime(Realm, Host, ExPort);
|
||||
error -> create_prime(Realm, Host)
|
||||
end.
|
||||
|
||||
|
||||
create_realm(Realm, Host, InPort) ->
|
||||
Message = "~n Enter the global port number on which the host will be available.~n",
|
||||
" Enter the public (external) port number at which this service should be "
|
||||
"available. (This might be different from the local port number if you are "
|
||||
"forwarding ports or have a complex network layout.)~n",
|
||||
ok = io:format(Message),
|
||||
case prompt_port_number() of
|
||||
{ok, ExPort} -> create_prime(Realm, Host, ExPort, InPort);
|
||||
error -> create_prime(Realm, Host, ExPort)
|
||||
end.
|
||||
ExPort = prompt_port_number(Current),
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort).
|
||||
|
||||
prompt_port_number() ->
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort) ->
|
||||
Current =
|
||||
case lists:keyfind(internal_port, 1, ZompConf) of
|
||||
false -> 11311;
|
||||
{internal_port, none} -> 11311;
|
||||
{internal_port, P} -> P
|
||||
end,
|
||||
Message =
|
||||
"~n"
|
||||
" Enter the local (internal/LAN) port number at which this service should be "
|
||||
"available. (This might be different from the public port visible from the internet"
|
||||
"if you are port forwarding or have a complex network layout.)~n",
|
||||
ok = io:format(Message),
|
||||
InPort = prompt_port_number(Current),
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort).
|
||||
|
||||
prompt_port_number(Current) ->
|
||||
Instructions =
|
||||
" A port can be any number from 1 to 65535.~n"
|
||||
" [Press enter to accept the default port: 11311]~n",
|
||||
ok = io:format(Instructions),
|
||||
" A valid port is any number from 1 to 65535."
|
||||
" [Press enter to accept the current setting: ~tw]~n",
|
||||
ok = io:format(Instructions, [Current]),
|
||||
case get_input() of
|
||||
"" ->
|
||||
{ok, 11311};
|
||||
Current;
|
||||
S ->
|
||||
try
|
||||
case list_to_integer(S) of
|
||||
Port when 16#ffff >= Port, Port > 0 ->
|
||||
{ok, Port};
|
||||
Port;
|
||||
Illegal ->
|
||||
Whoops = "~p is out of bounds (1~65535). Try again...",
|
||||
error
|
||||
Whoops = "Whoops! ~tw is out of bounds (1~65535). Try again...~n",
|
||||
ok = io:format(Whoops, [Illegal]),
|
||||
prompt_port_number(Current)
|
||||
end
|
||||
catch error:badarg ->
|
||||
ok = io:format("~tp is not a port number. Try again...", [S]),
|
||||
error
|
||||
prompt_port_number(Current)
|
||||
end
|
||||
end.
|
||||
|
||||
create_realm(Realm, Prime) ->
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) ->
|
||||
Instructions =
|
||||
"~n"
|
||||
" Enter a username for the realm sysop.~n"
|
||||
@ -1536,13 +1546,13 @@ create_realm(Realm, Prime) ->
|
||||
UserName = get_input(),
|
||||
case valid_lower0_9(UserName) of
|
||||
true ->
|
||||
create_realm(Realm, Prime, UserName);
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||
false ->
|
||||
ok = io:format("Bad username ~tp. Try again.~n", [UserName]),
|
||||
create_realm(Realm, Prime)
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort)
|
||||
end.
|
||||
|
||||
create_realm(Realm, Prime, UserName) ->
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) ->
|
||||
Instructions =
|
||||
"~n"
|
||||
" Enter an email address for the realm sysop.~n"
|
||||
@ -1554,22 +1564,22 @@ create_realm(Realm, Prime, UserName) ->
|
||||
[User, Host] = string:lexemes(Email, "@"),
|
||||
case {valid_lower0_9(User), valid_label(Host)} of
|
||||
{true, true} ->
|
||||
create_realm(Realm, Prime, UserName, Email);
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email);
|
||||
{false, true} ->
|
||||
Message = "The user part of the email address seems invalid. Try again.~n",
|
||||
ok = io:format(Message),
|
||||
create_realm(Realm, Prime, UserName);
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||
{true, false} ->
|
||||
Message = "The host part of the email address seems invalid. Try again.~n",
|
||||
ok = io:format(Message),
|
||||
create_realm(Realm, Prime, UserName);
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||
{false, false} ->
|
||||
Message = "This email address seems like its totally bonkers. Try again.~n",
|
||||
ok = io:format(Message),
|
||||
create_realm(Realm, Prime, UserName)
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName)
|
||||
end.
|
||||
|
||||
create_realm(Realm, Prime, UserName, Email) ->
|
||||
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) ->
|
||||
Instructions =
|
||||
"~n"
|
||||
" Enter the real name (or whatever name people recognize) for the sysop.~n"
|
||||
@ -1604,6 +1614,21 @@ create_realm(Realm, Prime, UserName, Email) ->
|
||||
end,
|
||||
ok = lists:foreach(Copy, AllKeys),
|
||||
ok = lists:foreach(Drop, DangerousKeys),
|
||||
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
||||
{ok, RealmPubData} = file:read_file(RealmPub),
|
||||
RealmPubRecord =
|
||||
{{Realm, filename:basename(RealmPub)},
|
||||
realm,
|
||||
{realm, Realm},
|
||||
crypto:hash(sha512, RealmPubData),
|
||||
Timestamp},
|
||||
{ok, PackagePubData} = file:read_file(PackagePub),
|
||||
PackagePubRecord =
|
||||
{{Realm, filename:basename(PackagePub)},
|
||||
package,
|
||||
{realm, Realm},
|
||||
crypto:hash(sha512, PackagePubData),
|
||||
Timestamp},
|
||||
Message =
|
||||
"~n"
|
||||
" All of the keys generated have been moved to the current directory.~n"
|
||||
@ -1616,27 +1641,33 @@ create_realm(Realm, Prime, UserName, Email) ->
|
||||
" The package and sysop keys will need to be copied to the ~~/.zomp/keys/~s/~n"
|
||||
" directory on your personal or dev machine.~n",
|
||||
ok = io:format(Message, [Realm]),
|
||||
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
||||
UserRecord = {{UserName, Realm}, [SysopPub], Email, RealName, 1, Timestamp},
|
||||
RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
|
||||
RealmMeta =
|
||||
[{realm, Realm},
|
||||
{revision, 0},
|
||||
{prime, Prime},
|
||||
{prime, {ExAddress, ExPort}},
|
||||
{private, []},
|
||||
{mirrors, []},
|
||||
{sysops, [UserRecord]},
|
||||
{realm_keys, [RealmPub]},
|
||||
{package_keys, [PackagePub]}],
|
||||
{realm_keys, [RealmPubRecord]},
|
||||
{package_keys, [PackagePubRecord]}],
|
||||
Realms =
|
||||
case lists:keyfind(managed, 1, ZompConf) of
|
||||
{managed, M} -> [Realm | M];
|
||||
false -> [Realm]
|
||||
end,
|
||||
ZompFile = filename:join(zomp_dir(), "zomp.conf"),
|
||||
ZompConf =
|
||||
[{prime, Prime},
|
||||
{external_port, ExPort},
|
||||
{internal_port, InPort}],
|
||||
Update = fun({K, V}, ZC) -> lists:keystore(K, 1, ZC, {K, V}) end,
|
||||
NewConf =
|
||||
[{managed, Realms},
|
||||
{external_address, ExAddress},
|
||||
{external_port, ExPort},
|
||||
{internal_port, InPort}],
|
||||
NewZompConf = lists:foldl(Update, ZompConf, NewConf),
|
||||
ok = write_terms(RealmFile, RealmMeta),
|
||||
ok = write_terms(ZompFile, ZompConf),
|
||||
ok = log(info, "Wrote to ~ts:~n ~tp", [RealmFile, RealmMeta]),
|
||||
ok = log(info, "Wrote to ~ts:~n ~tp", [ZompFile, ZompConf]),
|
||||
ok = write_terms(ZompFile, NewZompConf),
|
||||
ok = log(info, "Realm ~ts created.", [Realm]),
|
||||
halt(0).
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user