diff options
| author | Daniil Baturin <daniil@baturin.org> | 2022-10-19 17:48:09 +0100 | 
|---|---|---|
| committer | Daniil Baturin <daniil@baturin.org> | 2022-11-04 14:20:46 +0000 | 
| commit | 986c556c28976bcd7add93f3b08908a79dd21a5c (patch) | |
| tree | bf74e9551f092e3b26ec109e947dc6623a81c56c | |
| parent | ea7d9ad2e3aa97c9d5d2f0b2ee91ae5787bb9fc3 (diff) | |
| download | vyos-utils-986c556c28976bcd7add93f3b08908a79dd21a5c.tar.gz vyos-utils-986c556c28976bcd7add93f3b08908a79dd21a5c.zip | |
T4761: add a URL value validator
| -rwxr-xr-x | debian/rules | 1 | ||||
| -rw-r--r-- | src/url.ml | 73 | 
2 files changed, 74 insertions, 0 deletions
| diff --git a/debian/rules b/debian/rules index c6e8920..22202e9 100755 --- a/debian/rules +++ b/debian/rules @@ -9,6 +9,7 @@ override_dh_auto_build:  	eval `opam env`  	mkdir -p _build  	ocamlfind ocamlopt -o _build/numeric -package pcre -linkpkg src/numeric.ml +	ocamlfind ocamlopt -o _build/url -package pcre -linkpkg src/url.ml  	ocamlfind ocamlopt -o _build/validate-value -package pcre,unix,containers -linkpkg src/validate_value.ml  override_dh_auto_install: diff --git a/src/url.ml b/src/url.ml new file mode 100644 index 0000000..1985ff0 --- /dev/null +++ b/src/url.ml @@ -0,0 +1,73 @@ +(* Extract and validate the scheme part. +   As per the RFC: + +  Scheme names consist of a sequence of characters. The lower case +  letters "a"--"z", digits, and the characters plus ("+"), period +  ("."), and hyphen ("-") are allowed. For resiliency, programs +  interpreting URLs should treat upper case letters as equivalent to +  lower case in scheme names (e.g., allow "HTTP" as well as "http"). + *) +let split_scheme url = +  let aux url = +    let res = Pcre.exec ~pat:{|^([a-zA-Z0-9\.\-]+):(.*)$|} url in +    let scheme = Pcre.get_substring res 1 in +    let uri = Pcre.get_substring res 2 in +    (String.lowercase_ascii scheme, uri) +  in +  try Ok (aux url) +  with Not_found -> Error (Printf.sprintf {|"%s" is not a valid URL|} url) + +let is_scheme_allowed allowed_schemes scheme = +  match List.find_opt ((=) scheme) allowed_schemes with +  | Some _ -> Ok () +  | None -> Error (Printf.sprintf {|URL scheme "%s:" is not allowed|} scheme) + +let regex_matches regex s = +  try +    let _ = Pcre.exec ~pat:regex s in +    true +  with Not_found -> false + +let validate_uri scheme uri = +  match scheme with +  | "http" | "https" -> +    if regex_matches {|//[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(:[0-9]+)*(/.* )?|} uri then Ok () +    else Error (Printf.sprintf {|"%s" is not a valid URI for the %s URL scheme|} uri scheme) +  | _ -> Ok () + +let validate_url allowed_schemes url = +  let (let*) = Result.bind in +  let* scheme, uri = split_scheme url in +  let* () = is_scheme_allowed allowed_schemes scheme in +  let* () = validate_uri scheme uri in +  Ok () + +let file_transport_schemes = ["http"; "https"; "ftp"; "sftp"; "scp"; "tftp"] + +let message_schemes = ["mailto"; "tel"; "sms"] + +let allowed_schemes = ref [] +let url = ref "" + +let args = [ +    ("--scheme", +     Arg.String (fun s -> allowed_schemes := s :: !allowed_schemes), +     "Allow only specified schemes"); +    ("--file-transport", +     Arg.Unit (fun () -> allowed_schemes := (List.append !allowed_schemes file_transport_schemes)), +     "Allow only file transport protocols (HTTP/S, FTP, SCP/SFTP, TFTP)"); +    ("--", Arg.Rest (fun s -> url := s), "Interpret next item as an argument"); +] + +let usage = Printf.sprintf "Usage: %s [OPTIONS] <URL>" Sys.argv.(0) + +let () = +  let () = Arg.parse args (fun s -> url := s) usage in +  (* Force all allowed scheme named to lowercase for ease of comparison. *) +  let allowed_schemes = List.map String.lowercase_ascii !allowed_schemes in +  let res = validate_url allowed_schemes !url in +  match res with +  | Ok () -> () +  | Error msg -> +    let () = Printf.fprintf stdout "%s" msg in +    exit 1 | 
