From 8a360fb92785831a14bdf43c22a5f23e21044d71 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 6 Jun 2018 12:07:50 +0900 Subject: [PATCH 1/2] Add a few things --- README.unix | 14 ++-- README.windows | 9 +++ zomp/lib/otpr/zx/0.1.0/src/zx.erl | 11 ++- zomp/lib/otpr/zx/0.1.0/src/zx_local.erl | 80 ++++++++++++++++++++-- zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl | 21 +++--- 5 files changed, 107 insertions(+), 28 deletions(-) diff --git a/README.unix b/README.unix index 6dfac7e..83a87f7 100644 --- a/README.unix +++ b/README.unix @@ -1,20 +1,14 @@ Unix installation information for ZX - This file contains information about how to install and run ZX on a Unix-type system. Consult README.md for general information about ZX as a program and as a project. -Current versions of ZX and this file can be found at https://zxq9.com/zx/ +Current versions of ZX and this file can be found at https://zxq9.com/projects/zomp/ - -The unix startup script, "install_unix", is a BASH script and must be set as executable -to be used. To set the script as executable: - - -From the command line: - -To set the file permission correctly you will need to run the following command: +The unix startup script, "install_unix", must be set as executable to be used. +To set the script as executable: chmod +x install_unix + Then to execute the installer you will need to run the following command: ./install_unix diff --git a/README.windows b/README.windows index 4e0ad05..94c4247 100644 --- a/README.windows +++ b/README.windows @@ -1,2 +1,11 @@ +Windows installation information for Windows + This file contains information about how to install and run ZX on a Windows system. Consult README.md for general information about ZX as a program and as a project. + +A quickstart guide for getting your system ready to run ZX (or any Erlang program) +is here: https://zxq9.com/projects/zomp/ + +Once you have an Erlang runtime installed (via the installer provided by Erlang +Solutions https://www.erlang-solutions.com/resources/download.html) you can click +to run the "install_windows" file in this directory. diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx.erl b/zomp/lib/otpr/zx/0.1.0/src/zx.erl index e32de44..76655d2 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx.erl @@ -103,6 +103,14 @@ do(["list", "deps", PackageString]) -> do(["install", PackageFile]) -> ok = start(), done(zx_daemon:install(PackageFile)); +do(["set", "timeout", String]) -> + done(zx_local:set_timeout(String)); +do(["add", "mirror"]) -> + done(zx_local:add_mirror()); +do(["drop", "mirror"]) -> + done(zx_local:drop_mirror()); +do(["status"]) -> + done(zx_local:status()); do(["set", "dep", PackageString]) -> done(zx_local:set_dep(PackageString)); do(["set", "version", VersionString]) -> @@ -588,7 +596,8 @@ usage() -> " zx logpath [Package [1-10]]~n" " zx status~n" " zx set timeout Value~n" -" zx set mirror Realm Host:Port~n" +" zx add mirror Realm Host:Port~n" +" zx drop mirror Realm Host:Port~n" "~n" "Developer/Packager/Maintainer Actions:~n" " zx create project [app | lib] PackageID~n" diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl b/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl index 1a0d11f..e55bcd1 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl @@ -14,7 +14,7 @@ list_realms/0, list_packages/1, list_versions/1, set_dep/1, list_deps/0, list_deps/1, drop_dep/1, verup/1, package/1, import_realm/1, drop_realm/1, - takeover/1, abdicate/1, + takeover/1, abdicate/1, set_timeout/1, add_mirror/0, drop_mirror/0, create_plt/0, dialyze/0, grow_a_pair/0, drop_key/1, create_user/0, create_realm/0, create_realmfile/2]). @@ -872,7 +872,7 @@ create_realm(R = #realm_init{realm = Realm, addr = Addr, port = Port, url = URL} "[3] Port Number : ~w~n" "[4] URL : ~ts~n" "Press a number to select something to change, or [ENTER] to continue.~n", - ok = io:format(Instructions, [Realm, Addr, Port, URL]), + ok = io:format(Instructions, [Realm, stringify_address(Addr), Port, URL]), case zx_tty:get_input() of "1" -> create_realm(R#realm_init{realm = none}); "2" -> create_realm(R#realm_init{addr = none}); @@ -892,10 +892,9 @@ store_realm(#realm_init{realm = Realm, sysop = Sysop = #user_data{username = UserName, keys = [KeyName]}}) -> ok = make_realm_dirs(Realm), - Address = parse_maybe_address(Addr), RealmConf = [{realm, Realm}, - {prime, {Address, Port}}, + {prime, {Addr, Port}}, {sysop, UserName}, {key, KeyName}, {url, URL}], @@ -966,7 +965,7 @@ ask_addr() -> ok = io:format("You need to enter an address.~n"), ask_addr(); String -> - String + parse_maybe_address(String) end. @@ -979,6 +978,15 @@ parse_maybe_address(String) -> end. +-spec stringify_address(inet:hostname() | inet:ip_address()) -> string(). + +stringify_address(Address) -> + case inet:ntoa(Address) of + {error, einval} -> Address; + String -> String + end. + + -spec ask_port() -> inet:port_number(). ask_port() -> @@ -1341,3 +1349,65 @@ abdicate(Realm) -> {ok, NewConf} -> zx_sys_conf:save(NewConf); {error, unmanaged} -> log(error, "Cannot abdicate an unmanaged realm.") end. + + +-spec set_timeout(string()) -> zx:outcome(). + +set_timeout(String) -> + case string:to_integer(String) of + {Value, ""} when Value > 0 -> + zx_sys_conf:save(zx_sys_conf:timeout(Value, zx_sys_conf:load())); + _ -> + {error, "Enter a positive integer. Common values are 3, 5 and 10.", 22} + end. + + +-spec add_mirror() -> ok. + +add_mirror() -> + ok = log(info, "Adding a mirror to the local configuration..."), + SysConf = zx_sys_conf:load(), + ok = + case zx_sys_conf:mirrors(SysConf) of + [] -> + ok; + Current -> + ok = io:format("Current mirrors:~n"), + Print = + fun({A, P}) -> + S = stringify_address(A), + io:format("* ~s:~w~n", [S, P]) + end, + lists:foreach(Print, Current) + end, + Host = ask_addr(), + Port = ask_port(), + zx_sys_conf:save(zx_sys_conf:add_mirror({Host, Port}, SysConf)). + + +-spec drop_mirror() -> ok. + +drop_mirror() -> + ok = log(info, "Removing mirrors from the local configuration..."), + SysConf = zx_sys_conf:load(), + zx_sys_conf:save(drop_mirror(SysConf)). + + +-spec drop_mirror(zx_sys_conf:data()) -> zx_sys_conf:data(). + +drop_mirror(SysConf) -> + case zx_sys_conf:mirrors(SysConf) of + [] -> + ok = log(info, "No mirrors to drop!"), + SysConf; + Current -> + ok = io:format("Pick a host to drop:~n"), + Optionize = + fun(Host = {A, P}) -> + Label = io_lib:format("~s:~w", [stringify_address(A), P]), + {Label, Host} + end, + Options = lists:map(Optionize, Current), + Selection = zx_tty:select(Options), + zx_sys_conf:rem_mirror(Selection, SysConf) + end. diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl b/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl index 8d8ecc9..44452dc 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl @@ -41,7 +41,7 @@ retries = 3 :: non_neg_integer(), maxconn = 5 :: pos_integer(), managed = sets:new() :: sets:set(zx:realm()), - mirrors = [] :: [zx:host()]}). + mirrors = sets:new() :: sets:set(zx:host())}). -opaque data() :: #d{}. @@ -92,8 +92,8 @@ populate_data(List) -> end, Mirrors = case proplists:get_value(mirrors, List, []) of - MR when is_list(MR) -> MR; - _ -> [] + MR when is_list(MR) -> sets:from_list(MR); + _ -> sets:new() end, #d{timeout = Timeout, retries = Retries, @@ -116,7 +116,7 @@ save(#d{timeout = Timeout, {retries, Retries}, {maxconn, MaxConn}, {managed, sets:to_list(Managed)}, - {mirrors, Mirrors}], + {mirrors, sets:to_list(Mirrors)}], ok = zx_lib:write_terms(path(), Terms), log(info, "Wrote etc/sys.conf"). @@ -275,7 +275,7 @@ rem_managed(Realm, Data = #d{managed = Managed}) -> %% Return the list of private mirrors. mirrors(#d{mirrors = Mirrors}) -> - Mirrors. + sets:to_list(Mirrors). -spec mirrors(Hosts, Data) -> NewData @@ -286,7 +286,7 @@ mirrors(#d{mirrors = Mirrors}) -> %% Reset the mirror configuration. mirrors(Hosts, Data) -> - Data#d{mirrors = Hosts}. + Data#d{mirrors = sets:from_list(Hosts)}. -spec add_mirror(Host, Data) -> NewData @@ -296,11 +296,8 @@ mirrors(Hosts, Data) -> %% @doc %% Add a mirror to the permanent configuration. -add_mirror(Data = #d{mirrors = Mirrors}, Host) -> - case lists:member(Host, Mirrors) of - false -> Data#d{mirrors = [Host | Mirrors]}; - true -> Data - end. +add_mirror(Host, Data = #d{mirrors = Mirrors}) -> + Data#d{mirrors = sets:add_element(Host, Mirrors)}. -spec rem_mirror(Host, Data) -> NewData @@ -311,7 +308,7 @@ add_mirror(Data = #d{mirrors = Mirrors}, Host) -> %% Remove a host from the list of permanent mirrors. rem_mirror(Host, Data = #d{mirrors = Mirrors}) -> - Data#d{mirrors = lists:delete(Host, Mirrors)}. + Data#d{mirrors = sets:del_element(Host, Mirrors)}. -spec reset() -> data(). From 05a457bbc217d8c0dd6d854b2bc4d64359670ae9 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 6 Jun 2018 15:44:09 +0900 Subject: [PATCH 2/2] Does more stuff now. --- zomp/lib/otpr/zx/0.1.0/src/zx.erl | 10 +- zomp/lib/otpr/zx/0.1.0/src/zx_local.erl | 198 ++++++++++++++++++--- zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl | 2 +- 3 files changed, 179 insertions(+), 31 deletions(-) diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx.erl b/zomp/lib/otpr/zx/0.1.0/src/zx.erl index 76655d2..427034f 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx.erl @@ -147,6 +147,12 @@ do(["dialyze"]) -> done(zx_local:dialyze()); do(["create", "user"]) -> done(zx_local:create_user()); +do(["create", "userfile"]) -> + done(zx_local:create_userfile()); +do(["export", "user"]) -> + done(zx_local:export_user()); +do(["import", "user", ZdufFile]) -> + done(zx_local:import_user(ZdufFile)); do(["create", "keypair"]) -> done(zx_local:grow_a_pair()); do(["drop", "key", Realm, KeyName]) -> @@ -155,8 +161,8 @@ do(["create", "plt"]) -> done(zx_local:create_plt()); do(["create", "realm"]) -> done(zx_local:create_realm()); -do(["create", "realmfile", Realm]) -> - done(zx_local:create_realmfile(Realm, ".")); +do(["create", "realmfile"]) -> + done(zx_local:create_realmfile()); do(["takeover", Realm]) -> done(zx_local:takeover(Realm)); do(["abdicate", Realm]) -> diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl b/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl index e55bcd1..327ecdc 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx_local.erl @@ -17,7 +17,8 @@ takeover/1, abdicate/1, set_timeout/1, add_mirror/0, drop_mirror/0, create_plt/0, dialyze/0, grow_a_pair/0, drop_key/1, - create_user/0, create_realm/0, create_realmfile/2]). + create_user/0, create_userfile/0, export_user/0, import_user/1, + create_realm/0, create_realmfile/0, create_realmfile/1]). -include("zx_logger.hrl"). @@ -785,30 +786,15 @@ dialyze() -> %% Execute the key generation procedure for 16k RSA keys once and then terminate. grow_a_pair() -> - ok = file:set_cwd(zx_lib:zomp_dir()), - case zx_lib:list_realms() of - [] -> - {error, "No realms configured.", 61}; - [Realm] -> - grow_a_pair(Realm); - Realms -> - Realm = zx_tty:select_string(Realms), - grow_a_pair(Realm) + case select_realm() of + error -> {error, "No realms configured.", 61}; + Realm -> grow_a_pair(Realm) end. grow_a_pair(Realm) -> - Pattern = zx_lib:path(etc, Realm) ++ "*.user", - case [filename:basename(F, ".user") || F <- filelib:wildcard(Pattern)] of - [] -> - {ok, UserName} = create_user(#user_data{realm = Realm}), - grow_a_pair(UserName); - [UserName] -> - grow_a_pair(Realm, UserName); - UserNames -> - UserName = zx_tty:select_string(UserNames), - grow_a_pair(Realm, UserName) - end. + UserName = select_user(Realm), + grow_a_pair(Realm, UserName). grow_a_pair(Realm, UserName) -> @@ -901,7 +887,7 @@ store_realm(#realm_init{realm = Realm, ok = store_user(Sysop), RealmConfPath = filename:join(zx_lib:path(etc, Realm), "realm.conf"), ok = zx_lib:write_terms(RealmConfPath, RealmConf), - ok = create_realmfile(Realm, "."), + ok = create_realmfile(Realm), ZRF = Realm ++ ".zrf", Message = "===========================================================================~n" @@ -1119,7 +1105,7 @@ create_user(U = #user_data{realm = Realm, create_user(U#user_data{contact_info = none}); "" -> ok = store_user(U), - {ok, UserName}; + UserName; _ -> ok = io:format("~nArglebargle, glop-glyf!?!~n~n"), create_user(U) @@ -1145,6 +1131,136 @@ store_user(#user_data{realm = Realm, log(info, "User ~tp created.", [{Realm, UserName}]). +-spec create_userfile() -> ok. + +create_userfile() -> + case select_realm() of + error -> {error, "No realms configured.", 61}; + Realm -> create_userfile(Realm) + end. + + +create_userfile(Realm) -> + UserName = select_user(Realm), + UserConf = filename:join(zx_lib:path(etc, Realm), UserName ++ ".user"), + {ok, UserData} = file:consult(UserConf), + Keys = proplists:get_value(keys, UserData), + Load = + fun(KeyName, Acc) -> + case file:read_file(zx_key:path(public, {Realm, KeyName})) of + {ok, Data} -> [{KeyName, Data} | Acc]; + _ -> Acc + end + end, + PubKeyData = lists:foldl(Load, [], Keys), + UserFile = Realm ++ "-" ++ UserName ++ ".zpuf", + Bin = term_to_binary({UserData, PubKeyData}), + ok = file:write_file(UserFile, Bin), + Message = + "Wrote Zomp public user file to ~tp.~n" + "This file can be given to a sysop from ~tp and added to the realm.~n" + "It ONLY contains PUBLIC KEY data.~n", + io:format(Message, [UserFile, Realm]). + + +-spec export_user() -> ok. + +export_user() -> + case select_realm() of + error -> {error, "No realms configured.", 61}; + Realm -> export_user(Realm) + end. + + +export_user(Realm) -> + UserName = select_user(Realm), + UserConf = filename:join(zx_lib:path(etc, Realm), UserName ++ ".user"), + {ok, UserData} = file:consult(UserConf), + Keys = proplists:get_value(keys, UserData), + Load = + fun(KeyName, Acc) -> + Pub = + case file:read_file(zx_key:path(public, {Realm, KeyName})) of + {ok, PD} -> PD; + _ -> none + end, + Key = + case file:read_file(zx_key:path(private, {Realm, KeyName})) of + {ok, KD} -> KD; + _ -> none + end, + [{KeyName, Key, Pub} | Acc] + end, + KeyData = lists:foldl(Load, [], Keys), + UserFile = Realm ++ "-" ++ UserName ++ ".zduf", + Bin = term_to_binary({UserData, KeyData}), + ok = file:write_file(UserFile, Bin), + Message = + "Wrote Zomp DANGEROUS user file to ~tp.~n" + "WARNING: This file contains your PRIVATE KEYS and should NEVER be shared with " + "anyone. Its only use is for the \"import user [.zduf]\" command!~n", + io:format(Message, [UserFile]). + + +-spec import_user(file:filename()) -> zx:outcome(). + +import_user(ZDUF) -> + case file:read_file(ZDUF) of + {ok, Bin} -> import_user2(Bin); + {error, enoent} -> {error, "Bad path/missing file.", 2}; + {error, eacces} -> {error, "Can't read file: bad permissions.", 13}; + {error, eisdir} -> {error, "The path provided is a directory.", 21}; + Error -> Error + end. + + +import_user2(Bin) -> + case zx_lib:b_to_t(Bin) of + {ok, {UserData, []}} -> + ok = log(info, "Note: This user file does not have any keys."), + import_user3(UserData, []); + {ok, {UserData, KeyData}} -> + import_user3(UserData, KeyData); + error -> + {error, "Bad .zduf data. Is this really a legitimate .zduf?", 1} + end. + + +import_user3(UserData, KeyData) -> + Realm = proplists:get_value(realm, UserData), + UserName = proplists:get_value(username, UserData), + case filelib:is_dir(zx_lib:path(etc, Realm)) of + true -> + UserConf = filename:join(zx_lib:path(etc, Realm), UserName ++ ".user"), + ok = zx_lib:write_terms(UserConf, UserData), + import_user4(Realm, UserName, KeyData); + false -> + {error, "User is from a realm which is not available locally.", 1} + end. + + +import_user4(Realm, UserName, KeyData) -> + Write = + fun + ({KeyName, KeyBin, none}) -> + KeyID = {Realm, KeyName}, + file:write_file(zx_key:path(private, KeyID), KeyBin); + ({KeyName, none, PubBin}) -> + KeyID = {Realm, KeyName}, + file:write_file(zx_key:path(public, KeyID), PubBin); + ({KeyName, KeyBin, PubBin}) -> + KeyID = {Realm, KeyName}, + file:write_file(zx_key:path(private, KeyID), KeyBin), + file:write_file(zx_key:path(public, KeyID), PubBin); + ({KeyName, PubBin}) -> + ok = log(info, "This file is probably a .zpuf, not a .zduf"), + KeyID = {Realm, KeyName}, + file:write_file(zx_key:path(public, KeyID), PubBin) + end, + ok = lists:foreach(Write, KeyData), + log(info, "Imported user ~ts to realm ~ts.", [UserName, Realm]). + + -spec list_users(Realm) -> UserNames when Realm :: zx:realm(), UserNames :: [zx:user_name()]. @@ -1288,18 +1404,23 @@ make_realm_dirs(Realm) -> % io:format("~tp~n", [ZompSettings]). --spec create_realmfile(Realm, Dir) -> ok - when Realm :: zx:realm(), - Dir :: file:filename(). +-spec create_realmfile() -> ok. -create_realmfile(Realm, Dir) -> +create_realmfile() -> + Realm = select_realm(), + create_realmfile(Realm). + + +-spec create_realmfile(zx:realm()) -> ok. + +create_realmfile(Realm) -> {ok, RealmConf} = zx_lib:load_realm_conf(Realm), ok = log(info, "Realm found, creating realm file..."), KeyName = maps:get(key, RealmConf), PubKeyPath = zx_key:path(public, {Realm, KeyName}), {ok, PubDER} = file:read_file(PubKeyPath), Blob = term_to_binary({RealmConf, PubDER}), - ZRF = filename:join(Dir, Realm ++ ".zrf"), + ZRF = Realm ++ ".zrf", ok = file:write_file(ZRF, Blob), log(info, "Realm conf file written to ~ts", [ZRF]). @@ -1411,3 +1532,24 @@ drop_mirror(SysConf) -> Selection = zx_tty:select(Options), zx_sys_conf:rem_mirror(Selection, SysConf) end. + + +-spec select_realm() -> {ok, zx:realm()} | error. + +select_realm() -> + case zx_lib:list_realms() of + [] -> error; + [Realm] -> Realm; + Realms -> zx_tty:select_string(Realms) + end. + + +-spec select_user(zx:realm()) -> zx:user_name(). + +select_user(Realm) -> + Pattern = filename:join(zx_lib:path(etc, Realm), "*.user"), + case [filename:basename(F, ".user") || F <- filelib:wildcard(Pattern)] of + [] -> create_user(#user_data{realm = Realm}); + [UserName] -> UserName; + UserNames -> zx_tty:select_string(UserNames) + end. diff --git a/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl b/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl index 44452dc..5c48108 100644 --- a/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl +++ b/zomp/lib/otpr/zx/0.1.0/src/zx_sys_conf.erl @@ -136,7 +136,7 @@ timeout(#d{timeout = Timeout}) -> %% @doc %% Set the timeout attribute to a new value. -timeout(Value, Data) when is_integer(Value) and Value > 0 -> +timeout(Value, Data) when Value > 0 -> Data#d{timeout = Value}.