Realm creation
This commit is contained in:
parent
82ea25f1ec
commit
20f27cbcab
227
zx
227
zx
@ -1404,8 +1404,10 @@ dialyze() ->
|
|||||||
|
|
||||||
create_realm() ->
|
create_realm() ->
|
||||||
ConfFile = filename:join(zomp_dir(), "zomp.conf"),
|
ConfFile = filename:join(zomp_dir(), "zomp.conf"),
|
||||||
{ok, ZompConf} = file:consult(ConfFile),
|
case file:consult(ConfFile) of
|
||||||
create_realm(ZompConf).
|
{ok, ZompConf} -> create_realm(ZompConf);
|
||||||
|
{error, enoent} -> create_realm([])
|
||||||
|
end.
|
||||||
|
|
||||||
create_realm(ZompConf) ->
|
create_realm(ZompConf) ->
|
||||||
Instructions =
|
Instructions =
|
||||||
@ -1426,107 +1428,115 @@ create_realm(ZompConf) ->
|
|||||||
create_realm(ZompConf)
|
create_realm(ZompConf)
|
||||||
end;
|
end;
|
||||||
false ->
|
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)
|
create_realm(ZompConf)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_realm(ZompConf, Realm) ->
|
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 =
|
XAString =
|
||||||
case inet:ntoa(XA) of
|
case inet:ntoa(Current) of
|
||||||
{error, einval} -> XA;
|
{error, einval} -> Current;
|
||||||
String -> String
|
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,
|
end,
|
||||||
Message =
|
Message =
|
||||||
"~n"
|
"~n"
|
||||||
" Enter a static, valid hostname or IPv4 or IPv6 address at which this host "
|
" Enter the public (external) port number at which this service should be "
|
||||||
"can be reached from the public internet (or internal network if it will never "
|
"available. (This might be different from the local port number if you are "
|
||||||
"need to be reached from the internet).~n"
|
"forwarding ports or have a complex network layout.)~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",
|
|
||||||
ok = io:format(Message),
|
ok = io:format(Message),
|
||||||
case prompt_port_number() of
|
ExPort = prompt_port_number(Current),
|
||||||
{ok, ExPort} -> create_prime(Realm, Host, ExPort, InPort);
|
create_realm(ZompConf, Realm, ExAddress, ExPort).
|
||||||
error -> create_prime(Realm, Host, ExPort)
|
|
||||||
end.
|
|
||||||
|
|
||||||
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 =
|
Instructions =
|
||||||
" A port can be any number from 1 to 65535.~n"
|
" A valid port is any number from 1 to 65535."
|
||||||
" [Press enter to accept the default port: 11311]~n",
|
" [Press enter to accept the current setting: ~tw]~n",
|
||||||
ok = io:format(Instructions),
|
ok = io:format(Instructions, [Current]),
|
||||||
case get_input() of
|
case get_input() of
|
||||||
"" ->
|
"" ->
|
||||||
{ok, 11311};
|
Current;
|
||||||
S ->
|
S ->
|
||||||
try
|
try
|
||||||
case list_to_integer(S) of
|
case list_to_integer(S) of
|
||||||
Port when 16#ffff >= Port, Port > 0 ->
|
Port when 16#ffff >= Port, Port > 0 ->
|
||||||
{ok, Port};
|
Port;
|
||||||
Illegal ->
|
Illegal ->
|
||||||
Whoops = "~p is out of bounds (1~65535). Try again...",
|
Whoops = "Whoops! ~tw is out of bounds (1~65535). Try again...~n",
|
||||||
error
|
ok = io:format(Whoops, [Illegal]),
|
||||||
|
prompt_port_number(Current)
|
||||||
end
|
end
|
||||||
catch error:badarg ->
|
catch error:badarg ->
|
||||||
ok = io:format("~tp is not a port number. Try again...", [S]),
|
ok = io:format("~tp is not a port number. Try again...", [S]),
|
||||||
error
|
prompt_port_number(Current)
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_realm(Realm, Prime) ->
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) ->
|
||||||
Instructions =
|
Instructions =
|
||||||
"~n"
|
"~n"
|
||||||
" Enter a username for the realm sysop.~n"
|
" Enter a username for the realm sysop.~n"
|
||||||
@ -1536,13 +1546,13 @@ create_realm(Realm, Prime) ->
|
|||||||
UserName = get_input(),
|
UserName = get_input(),
|
||||||
case valid_lower0_9(UserName) of
|
case valid_lower0_9(UserName) of
|
||||||
true ->
|
true ->
|
||||||
create_realm(Realm, Prime, UserName);
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||||
false ->
|
false ->
|
||||||
ok = io:format("Bad username ~tp. Try again.~n", [UserName]),
|
ok = io:format("Bad username ~tp. Try again.~n", [UserName]),
|
||||||
create_realm(Realm, Prime)
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_realm(Realm, Prime, UserName) ->
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) ->
|
||||||
Instructions =
|
Instructions =
|
||||||
"~n"
|
"~n"
|
||||||
" Enter an email address for the realm sysop.~n"
|
" Enter an email address for the realm sysop.~n"
|
||||||
@ -1554,22 +1564,22 @@ create_realm(Realm, Prime, UserName) ->
|
|||||||
[User, Host] = string:lexemes(Email, "@"),
|
[User, Host] = string:lexemes(Email, "@"),
|
||||||
case {valid_lower0_9(User), valid_label(Host)} of
|
case {valid_lower0_9(User), valid_label(Host)} of
|
||||||
{true, true} ->
|
{true, true} ->
|
||||||
create_realm(Realm, Prime, UserName, Email);
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email);
|
||||||
{false, true} ->
|
{false, true} ->
|
||||||
Message = "The user part of the email address seems invalid. Try again.~n",
|
Message = "The user part of the email address seems invalid. Try again.~n",
|
||||||
ok = io:format(Message),
|
ok = io:format(Message),
|
||||||
create_realm(Realm, Prime, UserName);
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||||
{true, false} ->
|
{true, false} ->
|
||||||
Message = "The host part of the email address seems invalid. Try again.~n",
|
Message = "The host part of the email address seems invalid. Try again.~n",
|
||||||
ok = io:format(Message),
|
ok = io:format(Message),
|
||||||
create_realm(Realm, Prime, UserName);
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName);
|
||||||
{false, false} ->
|
{false, false} ->
|
||||||
Message = "This email address seems like its totally bonkers. Try again.~n",
|
Message = "This email address seems like its totally bonkers. Try again.~n",
|
||||||
ok = io:format(Message),
|
ok = io:format(Message),
|
||||||
create_realm(Realm, Prime, UserName)
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_realm(Realm, Prime, UserName, Email) ->
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) ->
|
||||||
Instructions =
|
Instructions =
|
||||||
"~n"
|
"~n"
|
||||||
" Enter the real name (or whatever name people recognize) for the sysop.~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,
|
end,
|
||||||
ok = lists:foreach(Copy, AllKeys),
|
ok = lists:foreach(Copy, AllKeys),
|
||||||
ok = lists:foreach(Drop, DangerousKeys),
|
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 =
|
Message =
|
||||||
"~n"
|
"~n"
|
||||||
" All of the keys generated have been moved to the current directory.~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"
|
" The package and sysop keys will need to be copied to the ~~/.zomp/keys/~s/~n"
|
||||||
" directory on your personal or dev machine.~n",
|
" directory on your personal or dev machine.~n",
|
||||||
ok = io:format(Message, [Realm]),
|
ok = io:format(Message, [Realm]),
|
||||||
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
|
||||||
UserRecord = {{UserName, Realm}, [SysopPub], Email, RealName, 1, Timestamp},
|
UserRecord = {{UserName, Realm}, [SysopPub], Email, RealName, 1, Timestamp},
|
||||||
RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
|
RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
|
||||||
RealmMeta =
|
RealmMeta =
|
||||||
[{realm, Realm},
|
[{realm, Realm},
|
||||||
{revision, 0},
|
{revision, 0},
|
||||||
{prime, Prime},
|
{prime, {ExAddress, ExPort}},
|
||||||
{private, []},
|
{private, []},
|
||||||
{mirrors, []},
|
{mirrors, []},
|
||||||
{sysops, [UserRecord]},
|
{sysops, [UserRecord]},
|
||||||
{realm_keys, [RealmPub]},
|
{realm_keys, [RealmPubRecord]},
|
||||||
{package_keys, [PackagePub]}],
|
{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"),
|
ZompFile = filename:join(zomp_dir(), "zomp.conf"),
|
||||||
ZompConf =
|
Update = fun({K, V}, ZC) -> lists:keystore(K, 1, ZC, {K, V}) end,
|
||||||
[{prime, Prime},
|
NewConf =
|
||||||
{external_port, ExPort},
|
[{managed, Realms},
|
||||||
{internal_port, InPort}],
|
{external_address, ExAddress},
|
||||||
|
{external_port, ExPort},
|
||||||
|
{internal_port, InPort}],
|
||||||
|
NewZompConf = lists:foldl(Update, ZompConf, NewConf),
|
||||||
ok = write_terms(RealmFile, RealmMeta),
|
ok = write_terms(RealmFile, RealmMeta),
|
||||||
ok = write_terms(ZompFile, ZompConf),
|
ok = write_terms(ZompFile, NewZompConf),
|
||||||
ok = log(info, "Wrote to ~ts:~n ~tp", [RealmFile, RealmMeta]),
|
ok = log(info, "Realm ~ts created.", [Realm]),
|
||||||
ok = log(info, "Wrote to ~ts:~n ~tp", [ZompFile, ZompConf]),
|
|
||||||
halt(0).
|
halt(0).
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user