This commit is contained in:
Craig Everett 2017-11-29 07:32:23 +09:00
parent e765209ee3
commit 82ea25f1ec

162
zx
View File

@ -1403,6 +1403,11 @@ dialyze() ->
%%% Create Realm & Sysop %%% Create Realm & Sysop
create_realm() -> create_realm() ->
ConfFile = filename:join(zomp_dir(), "zomp.conf"),
{ok, ZompConf} = file:consult(ConfFile),
create_realm(ZompConf).
create_realm(ZompConf) ->
Instructions = Instructions =
"~n" "~n"
" Enter a name for your new realm.~n" " Enter a name for your new realm.~n"
@ -1415,22 +1420,64 @@ create_realm() ->
RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"), RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
case filelib:is_regular(RealmFile) of case filelib:is_regular(RealmFile) of
false -> false ->
create_realm(Realm); create_realm(ZompConf, Realm);
true -> true ->
ok = io:format("That realm already exists. Be more original.~n"), ok = io:format("That realm already exists. Be more original.~n"),
create_realm() create_realm(ZompConf)
end; end;
false -> false ->
ok = io:format("Bad realm name ~tp. Try again.~n", [Realm]), ok = io:format("Bad realm name ~tp. Try again.~n", [Realm]),
create_realm() create_realm(ZompConf)
end. end.
create_realm(Realm) -> create_realm(ZompConf, Realm) ->
{external_address, XA} = lists:keyfind(external_address, 1, ZompConf),
XAString =
case inet:ntoa(XA) of
{error, einval} -> XA;
String -> String
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 = HostInstructions =
"~n" "~n"
" Enter the prime (permanent) server's publicly accessible hostname or~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~n" "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" "as either a normal IPv4 dot-notation or IPv6 colon-notation.~n"
" Note that address ranges will not be checked for validity.~n", " Note that address ranges will not be checked for validity.~n",
ok = io:format(HostInstructions), ok = io:format(HostInstructions),
HostString = get_input(), HostString = get_input(),
@ -1439,29 +1486,43 @@ create_realm(Realm) ->
{ok, Address} -> Address; {ok, Address} -> Address;
{error, einval} -> HostString {error, einval} -> HostString
end, end,
PortInstructions =
"~n" create_prime(Realm, Host) ->
" Enter the port number the host will be listening on.~n" ok = io:format("~n Enter the local port number on which the host listen.~n"),
" The port can be any number from 1 to 65535.~n" case prompt_port_number() of
" [Press enter for the default: 11311]~n", {ok, ExPort} -> create_prime(Realm, Host, ExPort);
ok = io:format(PortInstructions), 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),
case prompt_port_number() of
{ok, ExPort} -> create_prime(Realm, Host, ExPort, InPort);
error -> create_prime(Realm, Host, ExPort)
end.
prompt_port_number() ->
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),
case get_input() of case get_input() of
"" -> "" ->
create_realm(Realm, {HostString, 11311}); {ok, 11311};
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 ->
create_realm(Realm, {Host, Port}); {ok, Port};
Illegal -> Illegal ->
Whoops = "~p is out of bounds (1~65535). Try again...", Whoops = "~p is out of bounds (1~65535). Try again...",
ok = io:format(Whoops, [Illegal]), error
create_realm(Realm)
end end
catch error:badarg -> catch error:badarg ->
Error = "~tp is not a port number. Try again...", ok = io:format("~tp is not a port number. Try again...", [S]),
ok = io:format(Error, [S]), error
create_realm(Realm)
end end
end. end.
@ -1485,9 +1546,9 @@ create_realm(Realm, Prime, UserName) ->
Instructions = Instructions =
"~n" "~n"
" Enter an email address for the realm sysop.~n" " Enter an email address for the realm sysop.~n"
" Valid email address rules apply though the checking done here is quite~n" " Valid email address rules apply though the checking done here is quite "
" minimal. Check the address you enter carefully. The only people who will~n" "minimal. Check the address you enter carefully. The only people who will "
" suffer from an invalid address are your users.~n", "suffer from an invalid address are your users.~n",
ok = io:format(Instructions), ok = io:format(Instructions),
Email = get_input(), Email = get_input(),
[User, Host] = string:lexemes(Email, "@"), [User, Host] = string:lexemes(Email, "@"),
@ -1519,7 +1580,8 @@ create_realm(Realm, Prime, UserName, Email) ->
{ok, RealmKey, RealmPub} = generate_rsa({Realm, Realm ++ ".1.realm"}), {ok, RealmKey, RealmPub} = generate_rsa({Realm, Realm ++ ".1.realm"}),
{ok, PackageKey, PackagePub} = generate_rsa({Realm, Realm ++ ".1.package"}), {ok, PackageKey, PackagePub} = generate_rsa({Realm, Realm ++ ".1.package"}),
{ok, SysopKey, SysopPub} = generate_rsa({Realm, UserName ++ ".1"}), {ok, SysopKey, SysopPub} = generate_rsa({Realm, UserName ++ ".1"}),
AllKeys = [RealmKey, RealmPub, PackageKey, PackagePub, SysopKey, SysopPub], AllKeys = [RealmKey, RealmPub, PackageKey, PackagePub, SysopKey, SysopPub],
DangerousKeys = [PackageKey, SysopKey],
Copy = Copy =
fun(From) -> fun(From) ->
To = filename:basename(From), To = filename:basename(From),
@ -1540,21 +1602,23 @@ create_realm(Realm, Prime, UserName, Email) ->
ok = file:delete(File), ok = file:delete(File),
log(info, "Deleting ~ts", [File]) log(info, "Deleting ~ts", [File])
end, end,
DangerousKeys = [PackageKey, SysopKey],
ok = lists:foreach(Copy, AllKeys), ok = lists:foreach(Copy, AllKeys),
ok = lists:foreach(Drop, DangerousKeys), ok = lists:foreach(Drop, DangerousKeys),
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"
"~n"
" MAKE AND SECURELY STORE COPIES OF THESE KEYS.~n" " MAKE AND SECURELY STORE COPIES OF THESE KEYS.~n"
" The private package and sysop login keys have been deleted from the~n" "~n"
" key directory. These should only exist on your local system, not a prime.~n" " The private package and sysop login keys have been deleted from the "
" realm server (particularly if other services are run on that machine).~n" "key directory. These should only exist on your local system, not a prime "
" The package and sysop keys will need to be copied to the ~~/.zomp/keys/~p/~n" "realm server (particularly if other services are run on that machine).~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()), 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"),
RealmMeta = RealmMeta =
[{realm, Realm}, [{realm, Realm},
{revision, 0}, {revision, 0},
@ -1564,7 +1628,15 @@ create_realm(Realm, Prime, UserName, Email) ->
{sysops, [UserRecord]}, {sysops, [UserRecord]},
{realm_keys, [RealmPub]}, {realm_keys, [RealmPub]},
{package_keys, [PackagePub]}], {package_keys, [PackagePub]}],
ok = log(info, "Would be writing~n ~tp", [RealmMeta]), ZompFile = filename:join(zomp_dir(), "zomp.conf"),
ZompConf =
[{prime, Prime},
{external_port, ExPort},
{internal_port, InPort}],
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]),
halt(0). halt(0).
@ -2124,6 +2196,7 @@ ensure_zomp_home() ->
SubDirs = ["tmp", "key", "var", "lib", "zrp", "etc"], SubDirs = ["tmp", "key", "var", "lib", "zrp", "etc"],
ok = lists:foreach(fun file:make_dir/1, SubDirs), ok = lists:foreach(fun file:make_dir/1, SubDirs),
ok = write_terms(default_realm_file(), default_realm()), ok = write_terms(default_realm_file(), default_realm()),
ok = write_terms("zomp.conf", default_conf()),
ok = file:write_file(default_pubkey_file(), default_pubkey()), ok = file:write_file(default_pubkey_file(), default_pubkey()),
ok = log(info, "Zomp userland directory initialized."), ok = log(info, "Zomp userland directory initialized."),
file:set_cwd(CWD) file:set_cwd(CWD)
@ -2240,18 +2313,31 @@ realm_file(Realm) ->
Realm ++ ".realm". Realm ++ ".realm".
-spec default_realm() -> RealmData -spec default_realm() -> [{Key :: atom(), Value :: term()}].
when RealmData :: [{atom(), term()}].
%% @private %% @private
%% Returns the default realm file's data contents for the default "otpr" realm. %% Returns the default realm file's data contents for the default "otpr" realm.
default_realm() -> default_realm() ->
[{name, "otpr"}, [{realm, "otpr"},
% {prime, {"repo.psychobitch.party", 11311}}, {revision, 0},
{prime, {"localhost", 11311}}, {prime, {"repo.psychobitch.party", 11311}},
{pubkey, default_pubkey_file()}, {private, [{"localhost", 11311}]},
{serial, 0}, {mirrors, []},
{mirrors, []}]. {sysops, [{"otpr, ""zxq9"}]},
{realm_keys, []},
{package_keys, [default_pubkey_file()]}].
-spec default_conf() -> [{Key :: atom(), Value :: term()}].
%% @private
%% Return the default local config values for a zomp server.
%% The external and local port values are global values needed to make a zomp server
%% work in the face of unique port forwarding and NAT configurations outside the control
%% of the zomp server itself. zx references these values in a few places (namely when
%% setting up a mirror or prime realm).
default_conf() ->
[{external_port, 11311},
{local_port, 11311}].
-spec default_pubkey_file() -> file:filename(). -spec default_pubkey_file() -> file:filename().