wip
This commit is contained in:
parent
428f7e0565
commit
11d5f3f767
208
zx
208
zx
@ -348,7 +348,7 @@ ensure_installed(PackageID = {Realm, Name, Version}) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec ensure_installed(Realm, Name, Version) -> Result
|
-spec ensure_installed(Realm, Name, Version) -> Result | no_return()
|
||||||
when Realm :: realm(),
|
when Realm :: realm(),
|
||||||
Name :: name(),
|
Name :: name(),
|
||||||
Version :: version(),
|
Version :: version(),
|
||||||
@ -707,13 +707,10 @@ valid_package({Realm, Name}) ->
|
|||||||
{false, false} ->
|
{false, false} ->
|
||||||
ok = log(error, "Invalid realm ~tp and package ~tp", [Realm, Name]),
|
ok = log(error, "Invalid realm ~tp and package ~tp", [Realm, Name]),
|
||||||
halt(1)
|
halt(1)
|
||||||
end;
|
end.
|
||||||
valid_package(Bad) ->
|
|
||||||
ok = log(error, "Invalid package() value: ~160tp", [Bad]),
|
|
||||||
halt(1).
|
|
||||||
|
|
||||||
|
|
||||||
-spec string_to_package(string()) -> ok | no_return().
|
-spec string_to_package(string()) -> package() | no_return().
|
||||||
%% @private
|
%% @private
|
||||||
%% Convert a string to a package() type if possible. If not then halt the system.
|
%% Convert a string to a package() type if possible. If not then halt the system.
|
||||||
|
|
||||||
@ -2306,35 +2303,31 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) ->
|
|||||||
" There are no rules for this one. Any valid UTF-8 printables are legal.~n",
|
" There are no rules for this one. Any valid UTF-8 printables are legal.~n",
|
||||||
ok = io:format(Instructions),
|
ok = io:format(Instructions),
|
||||||
RealName = get_input(),
|
RealName = get_input(),
|
||||||
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealName).
|
||||||
|
|
||||||
|
|
||||||
|
-spec create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealName) ->
|
||||||
|
no_return()
|
||||||
|
when ZompConf :: [{Key :: atom(), Value :: term()}],
|
||||||
|
Realm :: realm(),
|
||||||
|
ExAddress :: inet:hostname() | inet:ip_address(),
|
||||||
|
ExPort :: inet:port_number(),
|
||||||
|
InPort :: inet:port_number(),
|
||||||
|
UserName :: string(),
|
||||||
|
Email :: string(),
|
||||||
|
RealName :: string().
|
||||||
|
|
||||||
|
create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealName) ->
|
||||||
ok = io:format("~nGenerating keys. This might take a while, so settle in...~n"),
|
ok = io:format("~nGenerating keys. This might take a while, so settle in...~n"),
|
||||||
{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],
|
ok = log(info, "Generated 16k RSA pair ~ts ~ts", [RealmKey, RealmPub]),
|
||||||
DangerousKeys = [PackageKey, SysopKey],
|
ok = log(info, "Generated 16k RSA pair ~ts ~ts", [PackageKey, PackagePub]),
|
||||||
Copy =
|
ok = log(info, "Generated 16k RSA pair ~ts ~ts", [SysopKey, SysopPub]),
|
||||||
fun(From) ->
|
|
||||||
To = filename:basename(From),
|
|
||||||
case filelib:is_file(To) of
|
|
||||||
true ->
|
|
||||||
M = "Whoops! Keyfile local destination ~tp exists! Aborting",
|
|
||||||
ok = log(error, M, [To]),
|
|
||||||
ok = log(info, "Undoing all changes..."),
|
|
||||||
ok = lists:foreach(fun file:delete/1, AllKeys),
|
|
||||||
halt(0);
|
|
||||||
false ->
|
|
||||||
{ok, _} = file:copy(From, To),
|
|
||||||
log(info, "Copying to local directory: ~ts", [From])
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
Drop =
|
|
||||||
fun(File) ->
|
|
||||||
ok = file:delete(File),
|
|
||||||
log(info, "Deleting ~ts", [File])
|
|
||||||
end,
|
|
||||||
ok = lists:foreach(Copy, AllKeys),
|
|
||||||
ok = lists:foreach(Drop, DangerousKeys),
|
|
||||||
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
||||||
|
|
||||||
{ok, RealmPubData} = file:read_file(RealmPub),
|
{ok, RealmPubData} = file:read_file(RealmPub),
|
||||||
RealmPubRecord =
|
RealmPubRecord =
|
||||||
{{Realm, filename:basename(RealmPub, ".pub.der")},
|
{{Realm, filename:basename(RealmPub, ".pub.der")},
|
||||||
@ -2349,25 +2342,12 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) ->
|
|||||||
{realm, Realm},
|
{realm, Realm},
|
||||||
crypto:hash(sha512, PackagePubData),
|
crypto:hash(sha512, PackagePubData),
|
||||||
Timestamp},
|
Timestamp},
|
||||||
Message =
|
|
||||||
"~n"
|
|
||||||
" All of the keys generated have been moved to the current directory.~n"
|
|
||||||
"~n"
|
|
||||||
" MAKE AND SECURELY STORE COPIES OF THESE KEYS.~n"
|
|
||||||
"~n"
|
|
||||||
" The private package and sysop login keys have been deleted from the "
|
|
||||||
"key directory. These should only exist on your local system, not a prime "
|
|
||||||
"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",
|
|
||||||
ok = io:format(Message, [Realm]),
|
|
||||||
UserRecord =
|
UserRecord =
|
||||||
{{Realm, UserName},
|
{{Realm, UserName},
|
||||||
[filename:basename(SysopPub, ".pub.der")],
|
[filename:basename(SysopPub, ".pub.der")],
|
||||||
Email,
|
Email,
|
||||||
RealName},
|
RealName},
|
||||||
RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
|
RealmSettings =
|
||||||
RealmMeta =
|
|
||||||
[{realm, Realm},
|
[{realm, Realm},
|
||||||
{revision, 0},
|
{revision, 0},
|
||||||
{prime, {ExAddress, ExPort}},
|
{prime, {ExAddress, ExPort}},
|
||||||
@ -2376,23 +2356,86 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) ->
|
|||||||
{sysops, [UserRecord]},
|
{sysops, [UserRecord]},
|
||||||
{realm_keys, [RealmPubRecord]},
|
{realm_keys, [RealmPubRecord]},
|
||||||
{package_keys, [PackagePubRecord]}],
|
{package_keys, [PackagePubRecord]}],
|
||||||
Realms =
|
ZompSettings =
|
||||||
case lists:keyfind(managed, 1, ZompConf) of
|
[{managed, [Realm]},
|
||||||
{managed, M} -> [Realm | M];
|
|
||||||
false -> [Realm]
|
|
||||||
end,
|
|
||||||
ZompFile = filename:join(zomp_dir(), "zomp.conf"),
|
|
||||||
Update = fun({K, V}, ZC) -> lists:keystore(K, 1, ZC, {K, V}) end,
|
|
||||||
NewConf =
|
|
||||||
[{managed, Realms},
|
|
||||||
{external_address, ExAddress},
|
{external_address, ExAddress},
|
||||||
{external_port, ExPort},
|
{external_port, ExPort},
|
||||||
{internal_port, InPort}],
|
{internal_port, InPort}],
|
||||||
NewZompConf = lists:foldl(Update, ZompConf, NewConf),
|
|
||||||
ok = write_terms(RealmFile, RealmMeta),
|
RealmFN = Realm ++ ".realm",
|
||||||
ok = write_terms(ZompFile, NewZompConf),
|
RealmConf = filename:join(zomp_dir(), RealmFN),
|
||||||
ok = log(info, "Realm ~ts created.", [Realm]),
|
ok = write_terms(RealmConf, RealmSettings),
|
||||||
create_realmfile(Realm).
|
{ok, CWD} = file:get_cwd(),
|
||||||
|
{ok, TempDir} = mktemp_dir("zomp"),
|
||||||
|
ok = file:set_cwd(TempDir),
|
||||||
|
KeyDir = filename:join("key", Realm),
|
||||||
|
ok = filelib:ensure_dir(KeyDir),
|
||||||
|
ok = file:make_dir(KeyDir),
|
||||||
|
KeyCopy =
|
||||||
|
fun(K) ->
|
||||||
|
{ok, _} = file:copy(K, filename:join(KeyDir, filename:basename(K))),
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
TarOpts = [compressed, {cwd, TempDir}],
|
||||||
|
|
||||||
|
ok = write_terms(RealmFN, RealmSettings),
|
||||||
|
ok = KeyCopy(PackagePub),
|
||||||
|
ok = KeyCopy(RealmPub),
|
||||||
|
PublicZRF = filename:join(CWD, Realm ++ ".zrf"),
|
||||||
|
Files = filelib:wildcard("**"),
|
||||||
|
ok = erl_tar:create(PublicZRF, [RealmFN, "key"], TarOpts),
|
||||||
|
|
||||||
|
ok = KeyCopy(SysopPub),
|
||||||
|
ok = write_terms("zomp.conf", ZompSettings),
|
||||||
|
PrimeZRF = filename:join(CWD, Realm ++ ".zpf"),
|
||||||
|
ok = erl_tar:create(PrimeZRF, [RealmFN, "zomp.conf", "key"], TarOpts),
|
||||||
|
|
||||||
|
ok = file:set_cwd(zomp_dir()),
|
||||||
|
KeyBundle = filename:join(CWD, Realm ++ ".zkf"),
|
||||||
|
ok = erl_tar:create(KeyBundle, [KeyDir], [compressed]),
|
||||||
|
|
||||||
|
ok = file:set_cwd(CWD),
|
||||||
|
ok = rm_rf(TempDir),
|
||||||
|
|
||||||
|
Message =
|
||||||
|
"============================================================================~n"
|
||||||
|
"DONE!~n"
|
||||||
|
"~n"
|
||||||
|
"The realm ~ts has been created and is accessible from the current system.~n"
|
||||||
|
"Three configuration bundles have been created in the current directory:~n"
|
||||||
|
"~n"
|
||||||
|
" 1. ~ts ~n"
|
||||||
|
"This is the PRIVATE realm file you will need to install on the realm's prime~n"
|
||||||
|
"node. It includes the your (the sysop's) public key.~n"
|
||||||
|
"~n"
|
||||||
|
" 2. ~ts ~n"
|
||||||
|
"This file is the PUBLIC realm file other zomp nodes and zx users will need to~n"
|
||||||
|
"access the realm. It does not include your (the sysop's) public key.~n"
|
||||||
|
"~n"
|
||||||
|
" 3. ~ts ~n"
|
||||||
|
"This is the bundle of ALL KEYS that are defined in this realm at the moment.~n"
|
||||||
|
"~n"
|
||||||
|
"Now you need to make copies of these three files and back them up.~n"
|
||||||
|
"~n"
|
||||||
|
"On the PRIME NODE you need to run `zx add realm ~ts` and follow the prompts~n"
|
||||||
|
"to cause it to begin serving that realm as prime. (Node restart required.)~n"
|
||||||
|
"~n"
|
||||||
|
"On all zx CLIENTS that want to access your new realm and on all subordinate~n"
|
||||||
|
"MIRROR NODES the command `zx add realm ~ts` will need to be run.~n"
|
||||||
|
"The method of public realm file distribution (~ts) is up to you.~n"
|
||||||
|
"~n"
|
||||||
|
"~n"
|
||||||
|
"Public & Private key installation (if you need to recover them or perform~n"
|
||||||
|
"sysop functions from another computer) is `zx add keybundle ~ts`.~n"
|
||||||
|
"============================================================================~n",
|
||||||
|
Substitutions =
|
||||||
|
[Realm,
|
||||||
|
PrimeZRF, PublicZRF, KeyBundle,
|
||||||
|
PrimeZRF,
|
||||||
|
PublicZRF, PublicZRF,
|
||||||
|
KeyBundle],
|
||||||
|
ok = io:format(Message, Substitutions),
|
||||||
|
halt(0).
|
||||||
|
|
||||||
|
|
||||||
-spec create_realmfile(realm()) -> no_return().
|
-spec create_realmfile(realm()) -> no_return().
|
||||||
@ -2451,7 +2494,7 @@ install(PackageID) ->
|
|||||||
{TgzFile, TgzData} = lists:keyfind(TgzFile, 1, Files),
|
{TgzFile, TgzData} = lists:keyfind(TgzFile, 1, Files),
|
||||||
{"zomp.meta", MetaBin} = lists:keyfind("zomp.meta", 1, Files),
|
{"zomp.meta", MetaBin} = lists:keyfind("zomp.meta", 1, Files),
|
||||||
Meta = binary_to_term(MetaBin),
|
Meta = binary_to_term(MetaBin),
|
||||||
{KeyID, Signature} = maps:get(sig, 1, Meta),
|
{KeyID, Signature} = maps:get(sig, Meta),
|
||||||
{ok, PubKey} = loadkey(public, KeyID),
|
{ok, PubKey} = loadkey(public, KeyID),
|
||||||
ok = ensure_package_dirs(PackageID),
|
ok = ensure_package_dirs(PackageID),
|
||||||
PackageDir = filename:join("lib", PackageString),
|
PackageDir = filename:join("lib", PackageString),
|
||||||
@ -2558,6 +2601,24 @@ receive_zrp(Socket, PackageID) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec mktemp_dir(Prefix) -> Result
|
||||||
|
when Prefix :: string(),
|
||||||
|
Result :: {ok, TempDir :: file:filename()}
|
||||||
|
| {error, Reason :: file:posix()}.
|
||||||
|
|
||||||
|
mktemp_dir(Prefix) ->
|
||||||
|
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
|
||||||
|
TempPath = filename:basedir(user_cache, Prefix),
|
||||||
|
TempDir = filename:join(TempPath, Rand),
|
||||||
|
Result1 = filelib:ensure_dir(TempDir),
|
||||||
|
Result2 = file:make_dir(TempDir),
|
||||||
|
case {Result1, Result2} of
|
||||||
|
{ok, ok} -> {ok, TempDir};
|
||||||
|
{ok, Error} -> Error;
|
||||||
|
{Error, _} -> Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
%%% Utility functions
|
%%% Utility functions
|
||||||
|
|
||||||
-spec read_meta() -> package_meta() | no_return().
|
-spec read_meta() -> package_meta() | no_return().
|
||||||
@ -2674,6 +2735,33 @@ installed(PackageID) ->
|
|||||||
filelib:is_dir(PackageDir).
|
filelib:is_dir(PackageDir).
|
||||||
|
|
||||||
|
|
||||||
|
-spec rm_rf(file:filename()) -> ok | {error, file:posix()}.
|
||||||
|
%% @private
|
||||||
|
%% Recursively remove files and directories, equivalent to `rm -rf' on unix.
|
||||||
|
|
||||||
|
rm_rf(Path) ->
|
||||||
|
case filelib:is_dir(Path) of
|
||||||
|
true ->
|
||||||
|
Pattern = filename:join(Path, "**"),
|
||||||
|
Contents = lists:reverse(lists:sort(filelib:wildcard(Pattern))),
|
||||||
|
ok = lists:foreach(fun rm/1, Contents),
|
||||||
|
file:del_dir(Path);
|
||||||
|
false ->
|
||||||
|
file:delete(Path)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec rm(file:filename()) -> ok | {error, file:posix()}.
|
||||||
|
%% @private
|
||||||
|
%% An omnibus delete helper.
|
||||||
|
|
||||||
|
rm(Path) ->
|
||||||
|
case filelib:is_dir(Path) of
|
||||||
|
true -> file:del_dir(Path);
|
||||||
|
false -> file:delete(Path)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Input argument mangling
|
%%% Input argument mangling
|
||||||
|
|
||||||
@ -3225,4 +3313,4 @@ log(Level, Format, Args) ->
|
|||||||
warning -> "[WARNING]";
|
warning -> "[WARNING]";
|
||||||
error -> "[ERROR]"
|
error -> "[ERROR]"
|
||||||
end,
|
end,
|
||||||
io:format("~p ~s: " ++ Format ++ "~n", [self(), Tag | Args]).
|
io:format("~s ~p: " ++ Format ++ "~n", [Tag, self() | Args]).
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user