package passage

  1. Overview
  2. Docs

Source file invariant.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
let get_expanded_recipient_names_from_folder path =
  try
    let recipients = Storage.Secrets.get_recipients_from_path_exn path in
    List.map (fun r -> r.Age.name) recipients |> List.sort_uniq String.compare
  with _ -> []

let error_not_recipient ~op_string path =
  let base_folder = Path.folder_of_path path in
  let () =
    Util.eprintfn "E: user is not a recipient of %s. Please ask one of the following to add you as a recipient:"
      (Util.Show.show_path base_folder)
  in
  let expanded_recipients = get_expanded_recipient_names_from_folder base_folder in
  let () = List.iter (Util.eprintfn "  %s") expanded_recipients in
  Exn.die "E: refusing to %s: violates invariant" op_string

let user_is_listed_as_recipient path =
  let open Storage.Secrets in
  let folder_recipients = get_recipients_from_path_exn path in
  let own_recipients = recipients_of_own_id () in
  List.exists (fun (own_recipient : Age.recipient) -> List.mem own_recipient folder_recipients) own_recipients

let run_if_recipient ~op_string ~path ~f =
  match user_is_listed_as_recipient path with
  | false -> error_not_recipient ~op_string path
  | true -> f ()

let die_if_invariant_fails ?use_sudo ~op_string path =
  let open Storage.Secrets in
  (* If the secret's folder doesn't exist yet or is empty, there's no invariant to check, allow the operation *)
  let full_path = path |> Path.folder_of_path |> Path.abs in
  if (not (Path.is_directory full_path)) || FileUtil.ls (Path.project full_path) = [] then ()
  else (
    (* check if i am listed on the .keys file, return early *)
    let base_folder = Path.folder_of_path path in
    match user_is_listed_as_recipient path with
    | false -> error_not_recipient ~op_string path
    | true ->
      (* if i am listed on the .keys file, check if i can decrypt all the secrets in the folder *)
      let fails_invariant =
        List.exists
          (fun s ->
            try
              let (_decrypted : string) = Util.Secret.decrypt_silently ?use_sudo s in
              false
            with _e ->
              let () =
                let open Util.Show in
                Printf.eprintf
                  "E: user is recipient of %s, but failed to decrypt %s. Please ask some user to refresh the whole \
                   folder.\n"
                  (show_path base_folder) (show_name s)
              in
              true)
          (get_secrets_in_folder base_folder)
      in
      if fails_invariant then Exn.die "E: refusing to %s: violates invariant" op_string else ())