From cdb167b57b6503b7386b5ac62fd99c2bd1c26831 Mon Sep 17 00:00:00 2001 From: swrup Date: Tue, 3 Feb 2026 20:36:33 +0100 Subject: [PATCH] --- .gitignore | 5 ----- data/auditor_private_key | 1 + data/auditor_public_key | 1 + src/crypto.ml | 5 ++--- src/http_keys.ml | 5 +++-- src/http_management.ml | 6 +++++- src/pg.ml | 38 +++++++++++--------------------------- tools/do_management.sh | 12 ++++++++++-- tools/offline.ml | 36 +++++++++++++++++++++++++++++++++++- tools/offline_impl.ml | 24 ++++++++++++++++++++++-- 10 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 data/auditor_private_key create mode 100644 data/auditor_public_key diff --git a/.gitignore b/.gitignore index 672457c9..dbd4866f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ _build data/secmod/* !data/secmod/.gitkeep - - -# default output files of offline-tool -response.json -request.json diff --git a/data/auditor_private_key b/data/auditor_private_key new file mode 100644 index 00000000..82aad694 --- /dev/null +++ b/data/auditor_private_key @@ -0,0 +1 @@ +Iî÷q¸àwÇ´Y—›gbÙ'R+5µ™â°ƒˆyë> \ No newline at end of file diff --git a/data/auditor_public_key b/data/auditor_public_key new file mode 100644 index 00000000..2824b9ce --- /dev/null +++ b/data/auditor_public_key @@ -0,0 +1 @@ +A17JXR3E6J4CXDPYT7S1H25PGJ3ABS26TQ38654QCX0TB59RPMF0==== diff --git a/src/crypto.ml b/src/crypto.ml index b61979e4..c304962b 100644 --- a/src/crypto.ml +++ b/src/crypto.ml @@ -28,9 +28,8 @@ module EddsaPublicKey = struct let* pub = of_octets octets in Ok pub - let jsont = - let to_b32 t = B32.encode (to_octets t) in - Jsont.of_of_string ~kind:"EddsaPublicKey" of_b32 ~enc:to_b32 + let to_b32 t = B32.encode (to_octets t) + let jsont = Jsont.of_of_string ~kind:"EddsaPublicKey" of_b32 ~enc:to_b32 let caqti = Caqti_type.custom diff --git a/src/http_keys.ml b/src/http_keys.ml index 9c9957d7..9ba359a4 100644 --- a/src/http_keys.ml +++ b/src/http_keys.ml @@ -194,8 +194,9 @@ let mk_keys ~db_conn (module Sm : Secmod.S) ~last_issue_date = let* global_fees = Pg.get_global_fees db_conn ~start_date:Timestamp.epoch |> unwrap_err_caqti in - let auditors = - (* TODO /management/auditors + /auditors/$AUDITOR_PUB/$H_DENOM_PUB *) [] + let* auditors = + (* TODO /auditors/$AUDITOR_PUB/$H_DENOM_PUB *) + Pg.get_auditor_keys db_conn in let extensions = None in let extensions_sig = None in diff --git a/src/http_management.ml b/src/http_management.ml index 3e3f046e..a1fa3bc4 100644 --- a/src/http_management.ml +++ b/src/http_management.ml @@ -308,12 +308,16 @@ module Auditors = struct match last_date_opt with | None -> let+ () = Pg.insert_auditor db_conn v |> unwrap_err_caqti in + Logs.info (fun m -> m "enabled auditor"); () | Some last_date -> let cmp = Timestamp.compare last_date validity_start |> Option.get in - if cmp > 0 then Error "more recent management auditor already present" + if cmp > 0 then + Error + "database has more recent auditor data for this auditor public key" else let+ () = Pg.update_auditor db_conn v |> unwrap_err_caqti in + Logs.info (fun m -> m "updated auditor"); () let jsont = AuditorSetupMessage.jsont diff --git a/src/pg.ml b/src/pg.ml index d133a757..0d877ba6 100644 --- a/src/pg.ml +++ b/src/pg.ml @@ -11,7 +11,9 @@ transaction - should check validity of signatures got from db, for /management at least *) + should check validity of signatures got from db, for /management at least + + clean up caqti error type *) (* TODO time fix comparison with timestamp footgun *) @@ -186,39 +188,21 @@ let insert_auditor_denom_sig = fun (module Conn : CONN) ~auditor_pub ~h_denom_pub ~auditor_sig -> Conn.exec insert_auditor_denom_sig (auditor_pub, h_denom_pub, auditor_sig) -let _get_auditors = - let get_auditors = - Caqti_type.(unit ->* t3 eddsa_pub string string) - "SELECT auditor_pub, auditor_url, auditor_name FROM auditors WHERE \ - is_active" - in - fun (module Conn : CONN) () -> Conn.collect_list get_auditors () - -let _get_auditor_denoms = - let get_auditor_denoms = - let auditor_sig = Bin_sig.ExchangeKeyValidity.caqti in - Caqti_type.(unit ->* t3 eddsa_pub denomination_hash auditor_sig) - "SELECT auditors.auditor_pub, denominations.denom_pub_hash, \ - auditor_denom_sigs.auditor_sig FROM auditor_denom_sigs JOIN auditors \ - USING (auditor_uuid) JOIN denominations USING (denominations_serial) \ - WHERE auditors.is_active" - in - fun (module Conn : CONN) () -> Conn.collect_list get_auditor_denoms () - -(* TODO auditors +(* todo auditors maybe check that url and name are unique/same for each auditor_pub - do the ht logic out of pg.ml *) + and do the ht logic out of pg.ml? *) +(* this does not return auditors that are not auditing any denom *) let get_auditor_keys = let get_auditor_keys = let auditor_sig = Bin_sig.ExchangeKeyValidity.caqti in Caqti_type.( unit ->* t5 eddsa_pub string string denomination_hash auditor_sig) - "SELECT auditors.auditor_pub, auditors.url, auditors.name, \ - denominations.denom_pub_hash, auditor_denom_sigs.auditor_sig FROM \ - auditor_denom_sigs JOIN auditors USING (auditor_uuid) JOIN \ - denominations USING (denominations_serial) WHERE auditors.is_active" + "SELECT a.auditor_pub, a.auditor_url, a.auditor_name, dn.denom_pub_hash, \ + ads.auditor_sig FROM auditor_denom_sigs AS ads JOIN auditors AS a USING \ + (auditor_uuid) JOIN denominations AS dn USING (denominations_serial) \ + WHERE a.is_active" in - fun (module Conn : CONN) () -> + fun (module Conn : CONN) -> let open Syntax in let* l = Conn.collect_list get_auditor_keys () |> unwrap_err_caqti in let ht = Hashtbl.create 0xff in diff --git a/tools/do_management.sh b/tools/do_management.sh index ca1958a3..bb27251f 100755 --- a/tools/do_management.sh +++ b/tools/do_management.sh @@ -5,13 +5,21 @@ set -e file1="tmp_file1.json" file2="tmp_file2.json" file3="tmp_file3.json" +file4="tmp_file4.json" + +auditor_pub=$(<"./data/auditor_public_key") dune exec offline -- download --output $file1 dune exec offline -- sign --input $file1 --output $file2 dune exec offline -- upload --input $file2 --url "/management/keys" -dune exec offline -- global-fees --output $file3 --start_date "0.0" --end_date "99999999.9" --history_fee "EUR:0.0" --account_fee "EUR:0.0" --purse_fee "EUR:0.0" --history_expiration "9999999.0" --purse_account_limit 1 --purse_timeout "9999999.0" -dune exec offline -- upload --input $file3 --url "/management/global-fees" + +dune exec offline -- enable-auditor --output $file3 --auditor_url "auditor.example.com" --auditor_name "auditor example" --auditor_pub $auditor_pub --validity_start "0.0" +dune exec offline -- upload --input $file3 --url "/management/auditors" + +dune exec offline -- global-fees --output $file4 --start_date "0.0" --end_date "99999999.9" --history_fee "EUR:0.0" --account_fee "EUR:0.0" --purse_fee "EUR:0.0" --history_expiration "9999999.0" --purse_account_limit 1 --purse_timeout "9999999.0" +dune exec offline -- upload --input $file4 --url "/management/global-fees" rm $file1 rm $file2 rm $file3 +rm $file4 diff --git a/tools/offline.ml b/tools/offline.ml index cf2adb37..589685f0 100644 --- a/tools/offline.ml +++ b/tools/offline.ml @@ -16,6 +16,14 @@ module Arg = struct let amount = Arg.Conv.make ~docv:"amount argument" ~parser:Amount.of_string ~pp:Amount.pp () + + let eddsa_pub = + let parser s = Crypto.EddsaPublicKey.of_b32 s in + let pp fmt key = + let s = Crypto.EddsaPublicKey.to_b32 key in + Fmt.pf fmt "%s" s + in + Arg.Conv.make ~docv:"eddsa public key argument" ~parser ~pp () end let default_master_offline_key_file = "data/master_offline_private_key" @@ -96,13 +104,38 @@ let revoke_signkey_cmd = let doc = "Revoke signkey." in let signkey = let doc = "public signing key" in - Arg.(required & pos 0 (some string) None & info [] ~doc) + Arg.(required & pos 0 (some eddsa_pub) None & info [] ~doc) in Cmd.make (Cmd.info "revoke-signkey" ~doc) @@ let+ output = output and+ master_key = master_key and+ signkey = signkey in revoke_signkey ~output ~master_key ~signkey +let enable_auditor_cmd = + let doc = "Enable auditor." in + let auditor_url = + Arg.(required & opt (some string) None & info [ "auditor_url" ]) + in + let auditor_name = + Arg.(required & opt (some string) None & info [ "auditor_name" ]) + in + let auditor_pub = + Arg.(required & opt (some eddsa_pub) None & info [ "auditor_pub" ]) + in + let validity_start = + Arg.(required & opt (some timestamp) None & info [ "validity_start" ]) + in + Cmd.make (Cmd.info "enable-auditor" ~doc) + @@ + let+ output = output + and+ master_key = master_key + and+ auditor_url = auditor_url + and+ auditor_name = auditor_name + and+ auditor_pub = auditor_pub + and+ validity_start = validity_start in + enable_auditor ~output ~master_key ~auditor_url ~auditor_name ~auditor_pub + ~validity_start + let global_fees_cmd = let doc = "Provides global fee configuration." in let start_date = @@ -159,6 +192,7 @@ let cli = upload_cmd; revoke_denom_cmd; revoke_signkey_cmd; + enable_auditor_cmd; global_fees_cmd; ] diff --git a/tools/offline_impl.ml b/tools/offline_impl.ml index c6e38015..4dcde9c9 100644 --- a/tools/offline_impl.ml +++ b/tools/offline_impl.ml @@ -74,11 +74,10 @@ let revoke_denom ~output ~master_key ~h_denom = let revoke_signkey ~output ~master_key ~signkey = let* key = read_master_key_file master_key in - let* exchange_pub = Crypto.EddsaPublicKey.of_b32 signkey in let signkey_revoke = let master_sig = let open Bin_sig.MasterSigningKeyRevocation in - sign_f ~f:(Crypto.EddsaSignature.sign ~key) { exchange_pub } + sign_f ~f:(Crypto.EddsaSignature.sign ~key) { exchange_pub= signkey } in Api.SignkeyRevocationSignature.{ master_sig } in @@ -135,3 +134,24 @@ let global_fees ~output ~master_key ~start_date ~end_date ~history_fee let* s = Api.encode Api.GlobalFees.jsont global_fees in let* () = write_file output s in Ok () + +let enable_auditor ~output ~master_key ~auditor_url ~auditor_name ~auditor_pub + ~validity_start = + let open Crypto in + let* key = read_master_key_file master_key in + let master_sig = + let open Bin_sig.MasterAddAuditor in + sign_f ~f:(EddsaSignature.sign ~key) + { + start_date= validity_start; + auditor_pub; + h_auditor_url= Bin_type.Hash_64_cstr.hash auditor_url; + } + in + let v = + Api.AuditorSetupMessage. + { auditor_url; auditor_name; auditor_pub; master_sig; validity_start } + in + let* s = Api.encode Api.AuditorSetupMessage.jsont v in + let* () = write_file output s in + Ok ()