OCaml HTML5 parser/serialiser based on Python's JustHTML

-webfinger

-2454
-4
ocaml-webfinger/bin/dune
··· 1 - (executables 2 - (public_names webfinger) 3 - (names webfinger_cli) 4 - (libraries webfinger eio_main cmdliner logs logs.cli logs.fmt fmt.cli fmt.tty jsont jsont.bytesrw))
-122
ocaml-webfinger/bin/webfinger_cli.ml
··· 1 - (*--------------------------------------------------------------------------- 2 - Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 5 - 6 - (** WebFinger command-line tool. 7 - 8 - A CLI for performing WebFinger (RFC 7033) queries against any host. *) 9 - 10 - open Cmdliner 11 - 12 - (** {1 Command-line Arguments} *) 13 - 14 - let resource = 15 - let doc = "Resource URI to query (e.g., acct:user@example.com)" in 16 - Arg.(required & pos 0 (some string) None & info [] ~docv:"RESOURCE" ~doc) 17 - 18 - let rels = 19 - let doc = "Filter links by relation type (can be specified multiple times)" in 20 - Arg.(value & opt_all string [] & info ["r"; "rel"] ~docv:"REL" ~doc) 21 - 22 - let json_output = 23 - let doc = "Output raw JSON instead of formatted text" in 24 - Arg.(value & flag & info ["j"; "json"] ~doc) 25 - 26 - let show_links_only = 27 - let doc = "Show only links, not subject/aliases/properties" in 28 - Arg.(value & flag & info ["l"; "links-only"] ~doc) 29 - 30 - (** {1 Logging Setup} *) 31 - 32 - let setup_log style_renderer level = 33 - Fmt_tty.setup_std_outputs ?style_renderer (); 34 - Logs.set_level level; 35 - Logs.set_reporter (Logs_fmt.reporter ()); 36 - (* Return whether we should be quiet (log level is None) *) 37 - Option.is_none level 38 - 39 - (** {1 Output Formatting} *) 40 - 41 - let pp_link_compact ppf link = 42 - let href = Option.value ~default:"(no href)" (Webfinger.Link.href link) in 43 - Format.fprintf ppf "@[<h>%s@ ->@ %s" (Webfinger.Link.rel link) href; 44 - Option.iter (fun t -> Format.fprintf ppf "@ [%s]" t) (Webfinger.Link.type_ link); 45 - Format.fprintf ppf "@]" 46 - 47 - let pp_jrd_compact ppf jrd = 48 - Option.iter (fun s -> Format.fprintf ppf "@[<v>Subject: %s@]@," s) (Webfinger.Jrd.subject jrd); 49 - let aliases = Webfinger.Jrd.aliases jrd in 50 - if aliases <> [] then begin 51 - Format.fprintf ppf "@[<v>Aliases:@,"; 52 - List.iter (fun a -> Format.fprintf ppf " %s@," a) aliases; 53 - Format.fprintf ppf "@]" 54 - end; 55 - let props = Webfinger.Jrd.properties jrd in 56 - if props <> [] then begin 57 - Format.fprintf ppf "@[<v>Properties:@,"; 58 - List.iter (fun (k, v) -> 59 - let v = Option.value ~default:"null" v in 60 - Format.fprintf ppf " %s: %s@," k v 61 - ) props; 62 - Format.fprintf ppf "@]" 63 - end; 64 - let links = Webfinger.Jrd.links jrd in 65 - if links <> [] then begin 66 - Format.fprintf ppf "@[<v>Links:@,"; 67 - List.iter (fun link -> Format.fprintf ppf " %a@," pp_link_compact link) links; 68 - Format.fprintf ppf "@]" 69 - end 70 - 71 - let pp_links_only ppf jrd = 72 - List.iter (fun link -> Format.fprintf ppf "%a@," pp_link_compact link) (Webfinger.Jrd.links jrd) 73 - 74 - (** {1 Main Command} *) 75 - 76 - let run quiet resource rels json_output links_only = 77 - Eio_main.run @@ fun env -> 78 - Eio.Switch.run @@ fun sw -> 79 - let session = Requests.create ~sw env in 80 - match Webfinger.query session ~resource ~rels () with 81 - | Error e -> 82 - if not quiet then Format.eprintf "Error: %a@." Webfinger.pp_error e; 83 - `Error (false, Webfinger.error_to_string e) 84 - | Ok jrd -> 85 - if not quiet then begin 86 - if json_output then 87 - Format.printf "%s@." (Webfinger.Jrd.to_string jrd) 88 - else if links_only then 89 - Format.printf "%a" pp_links_only jrd 90 - else 91 - Format.printf "%a" pp_jrd_compact jrd 92 - end; 93 - `Ok () 94 - 95 - let run_term = 96 - let quiet = Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ()) in 97 - Term.(ret (const run $ quiet $ resource $ rels $ json_output $ show_links_only)) 98 - 99 - (** {1 Command Definition} *) 100 - 101 - let cmd = 102 - let doc = "Query WebFinger (RFC 7033) resources" in 103 - let man = [ 104 - `S Manpage.s_description; 105 - `P "$(tname) queries WebFinger servers to discover information about \ 106 - resources identified by URIs. This is commonly used for discovering \ 107 - ActivityPub profiles, OpenID Connect providers, and other federated \ 108 - services."; 109 - `S Manpage.s_examples; 110 - `P "Query a Mastodon user's WebFinger record:"; 111 - `Pre " $(tname) acct:gargron@mastodon.social"; 112 - `P "Get only ActivityPub-related links:"; 113 - `Pre " $(tname) --rel self acct:user@example.com"; 114 - `P "Output raw JSON for processing:"; 115 - `Pre " $(tname) --json acct:user@example.com | jq ."; 116 - `S Manpage.s_see_also; 117 - `P "RFC 7033 - WebFinger: $(b,https://datatracker.ietf.org/doc/html/rfc7033)"; 118 - ] in 119 - let info = Cmd.info "webfinger" ~version:"0.1.0" ~doc ~man in 120 - Cmd.v info run_term 121 - 122 - let () = exit (Cmd.eval cmd)
-1
ocaml-webfinger/dune
··· 1 - (data_only_dirs spec)
-36
ocaml-webfinger/dune-project
··· 1 - (lang dune 3.20) 2 - 3 - (name webfinger) 4 - 5 - (generate_opam_files true) 6 - 7 - (license ISC) 8 - (authors "Anil Madhavapeddy") 9 - (homepage "https://tangled.org/@anil.recoil.org/ocaml-webfinger") 10 - (maintainers "Anil Madhavapeddy <anil@recoil.org>") 11 - (bug_reports "https://tangled.org/@anil.recoil.org/ocaml-webfinger/issues") 12 - (maintenance_intent "(latest)") 13 - 14 - (package 15 - (name webfinger) 16 - (synopsis "RFC 7033 WebFinger protocol implementation for OCaml") 17 - (description 18 - "A complete implementation of RFC 7033 (WebFinger) for discovering 19 - information about resources identified by URIs. Includes type-safe 20 - JSON Resource Descriptor (JRD) encoding/decoding using jsont, 21 - an Eio-based HTTP client using the requests library, and a 22 - command-line tool for WebFinger lookups.") 23 - (depends 24 - (ocaml (>= 5.2.0)) 25 - (dune (>= 3.0)) 26 - (jsont (>= 0.1.0)) 27 - (jsont-bytesrw (>= 0.1.0)) 28 - (eio (>= 1.0)) 29 - (eio_main (>= 1.0)) 30 - (requests (>= 0.1.0)) 31 - (uri (>= 4.0.0)) 32 - (cmdliner (>= 1.2.0)) 33 - (logs (>= 0.7.0)) 34 - (fmt (>= 0.9.0)) 35 - (odoc :with-doc) 36 - (alcotest :with-test)))
-4
ocaml-webfinger/lib/dune
··· 1 - (library 2 - (name webfinger) 3 - (public_name webfinger) 4 - (libraries jsont jsont.bytesrw uri eio requests logs))
-252
ocaml-webfinger/lib/webfinger.ml
··· 1 - (*--------------------------------------------------------------------------- 2 - Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 5 - 6 - (** RFC 7033 WebFinger: Protocol for discovering resource information. 7 - 8 - This module implements the WebFinger protocol as specified in 9 - {{:https://datatracker.ietf.org/doc/html/rfc7033}RFC 7033}, providing 10 - type-safe JSON Resource Descriptor (JRD) encoding/decoding and an 11 - HTTP client for WebFinger queries. 12 - 13 - {2 References} 14 - {ul 15 - {- {{:https://datatracker.ietf.org/doc/html/rfc7033}RFC 7033} - WebFinger} 16 - {- {{:https://datatracker.ietf.org/doc/html/rfc6415}RFC 6415} - Web Host Metadata}} *) 17 - 18 - let src = Logs.Src.create "webfinger" ~doc:"WebFinger Protocol" 19 - module Log = (val Logs.src_log src : Logs.LOG) 20 - 21 - (** {1 Error Types} *) 22 - 23 - type error = 24 - | Invalid_resource of string 25 - | Http_error of { status : int; body : string } 26 - | Json_error of string 27 - | Https_required 28 - | Not_found 29 - 30 - let pp_error ppf = function 31 - | Invalid_resource s -> Format.fprintf ppf "Invalid resource: %s" s 32 - | Http_error { status; body } -> Format.fprintf ppf "HTTP error %d: %s" status body 33 - | Json_error s -> Format.fprintf ppf "JSON parse error: %s" s 34 - | Https_required -> Format.fprintf ppf "WebFinger requires HTTPS" 35 - | Not_found -> Format.fprintf ppf "Resource not found" 36 - 37 - let error_to_string e = Format.asprintf "%a" pp_error e 38 - 39 - exception Webfinger_error of error 40 - 41 - let raise_error e = raise (Webfinger_error e) 42 - 43 - (** {1 Internal JSON helpers} *) 44 - 45 - module String_map = Map.Make(String) 46 - 47 - let properties_jsont : (string * string option) list Jsont.t = 48 - let inner = 49 - Jsont.Object.map ~kind:"Properties" Fun.id 50 - |> Jsont.Object.keep_unknown (Jsont.Object.Mems.string_map (Jsont.option Jsont.string)) ~enc:Fun.id 51 - |> Jsont.Object.finish 52 - in 53 - Jsont.map 54 - ~dec:(fun m -> List.of_seq (String_map.to_seq m)) 55 - ~enc:(fun l -> String_map.of_list l) 56 - inner 57 - 58 - let titles_jsont : (string * string) list Jsont.t = 59 - let inner = 60 - Jsont.Object.map ~kind:"Titles" Fun.id 61 - |> Jsont.Object.keep_unknown (Jsont.Object.Mems.string_map Jsont.string) ~enc:Fun.id 62 - |> Jsont.Object.finish 63 - in 64 - Jsont.map 65 - ~dec:(fun m -> List.of_seq (String_map.to_seq m)) 66 - ~enc:(fun l -> String_map.of_list l) 67 - inner 68 - 69 - (** {1 Link Module} *) 70 - 71 - module Link = struct 72 - type t = { 73 - rel : string; 74 - type_ : string option; 75 - href : string option; 76 - titles : (string * string) list; 77 - properties : (string * string option) list; 78 - } 79 - 80 - let make ~rel ?type_ ?href ?(titles = []) ?(properties = []) () = 81 - { rel; type_; href; titles; properties } 82 - 83 - let rel t = t.rel 84 - let type_ t = t.type_ 85 - let href t = t.href 86 - let titles t = t.titles 87 - let properties t = t.properties 88 - 89 - let title ?(lang = "und") t = 90 - match List.assoc_opt lang t.titles with 91 - | Some title -> Some title 92 - | None -> List.assoc_opt "und" t.titles 93 - 94 - let property ~uri t = List.assoc_opt uri t.properties |> Option.join 95 - 96 - let jsont = 97 - let make rel type_ href titles properties = 98 - { rel; type_; href; titles; properties } 99 - in 100 - Jsont.Object.map ~kind:"Link" make 101 - |> Jsont.Object.mem "rel" Jsont.string ~enc:(fun (l : t) -> l.rel) 102 - |> Jsont.Object.opt_mem "type" Jsont.string ~enc:(fun (l : t) -> l.type_) 103 - |> Jsont.Object.opt_mem "href" Jsont.string ~enc:(fun (l : t) -> l.href) 104 - |> Jsont.Object.mem "titles" titles_jsont ~dec_absent:[] ~enc_omit:(fun x -> x = []) ~enc:(fun (l : t) -> l.titles) 105 - |> Jsont.Object.mem "properties" properties_jsont ~dec_absent:[] ~enc_omit:(fun x -> x = []) ~enc:(fun (l : t) -> l.properties) 106 - |> Jsont.Object.skip_unknown 107 - |> Jsont.Object.finish 108 - 109 - let pp ppf t = 110 - Format.fprintf ppf "@[<v 2>Link:@,rel: %s@," t.rel; 111 - Option.iter (Format.fprintf ppf "type: %s@,") t.type_; 112 - Option.iter (Format.fprintf ppf "href: %s@,") t.href; 113 - if t.titles <> [] then begin 114 - Format.fprintf ppf "titles:@,"; 115 - List.iter (fun (lang, title) -> Format.fprintf ppf " %s: %s@," lang title) t.titles 116 - end; 117 - if t.properties <> [] then begin 118 - Format.fprintf ppf "properties:@,"; 119 - List.iter (fun (uri, value) -> 120 - match value with 121 - | Some v -> Format.fprintf ppf " %s: %s@," uri v 122 - | None -> Format.fprintf ppf " %s: null@," uri 123 - ) t.properties 124 - end; 125 - Format.fprintf ppf "@]" 126 - end 127 - 128 - (** {1 JRD Module} *) 129 - 130 - module Jrd = struct 131 - type t = { 132 - subject : string option; 133 - aliases : string list; 134 - properties : (string * string option) list; 135 - links : Link.t list; 136 - } 137 - 138 - let make ?subject ?(aliases = []) ?(properties = []) ?(links = []) () = 139 - { subject; aliases; properties; links } 140 - 141 - let subject t = t.subject 142 - let aliases t = t.aliases 143 - let properties t = t.properties 144 - let links t = t.links 145 - 146 - let find_link ~rel t = List.find_opt (fun l -> Link.rel l = rel) t.links 147 - let find_links ~rel t = List.filter (fun l -> Link.rel l = rel) t.links 148 - let property ~uri t = List.assoc_opt uri t.properties |> Option.join 149 - 150 - let jsont = 151 - let make subject aliases properties links = 152 - { subject; aliases; properties; links } 153 - in 154 - Jsont.Object.map ~kind:"JRD" make 155 - |> Jsont.Object.opt_mem "subject" Jsont.string ~enc:(fun (j : t) -> j.subject) 156 - |> Jsont.Object.mem "aliases" (Jsont.list Jsont.string) ~dec_absent:[] ~enc_omit:(fun x -> x = []) ~enc:(fun (j : t) -> j.aliases) 157 - |> Jsont.Object.mem "properties" properties_jsont ~dec_absent:[] ~enc_omit:(fun x -> x = []) ~enc:(fun (j : t) -> j.properties) 158 - |> Jsont.Object.mem "links" (Jsont.list Link.jsont) ~dec_absent:[] ~enc_omit:(fun x -> x = []) ~enc:(fun (j : t) -> j.links) 159 - |> Jsont.Object.skip_unknown 160 - |> Jsont.Object.finish 161 - 162 - let of_string s = 163 - match Jsont_bytesrw.decode_string jsont s with 164 - | Ok jrd -> Ok jrd 165 - | Error e -> Error (Json_error e) 166 - 167 - let to_string t = 168 - match Jsont_bytesrw.encode_string jsont t with 169 - | Ok s -> s 170 - | Error e -> failwith ("JSON encoding error: " ^ e) 171 - 172 - let pp ppf t = 173 - Format.fprintf ppf "@[<v>"; 174 - Option.iter (Format.fprintf ppf "subject: %s@,") t.subject; 175 - if t.aliases <> [] then begin 176 - Format.fprintf ppf "aliases:@,"; 177 - List.iter (Format.fprintf ppf " - %s@,") t.aliases 178 - end; 179 - if t.properties <> [] then begin 180 - Format.fprintf ppf "properties:@,"; 181 - List.iter (fun (uri, value) -> 182 - match value with 183 - | Some v -> Format.fprintf ppf " %s: %s@," uri v 184 - | None -> Format.fprintf ppf " %s: null@," uri 185 - ) t.properties 186 - end; 187 - if t.links <> [] then begin 188 - Format.fprintf ppf "links:@,"; 189 - List.iter (fun link -> Format.fprintf ppf " %a@," Link.pp link) t.links 190 - end; 191 - Format.fprintf ppf "@]" 192 - end 193 - 194 - (** {1 Common Link Relations} *) 195 - 196 - module Rel = struct 197 - let activitypub = "self" 198 - let openid = "http://openid.net/specs/connect/1.0/issuer" 199 - let profile = "http://webfinger.net/rel/profile-page" 200 - let avatar = "http://webfinger.net/rel/avatar" 201 - let feed = "http://schemas.google.com/g/2010#updates-from" 202 - let portable_contacts = "http://portablecontacts.net/spec/1.0" 203 - let oauth_authorization = "http://tools.ietf.org/html/rfc6749#section-3.1" 204 - let oauth_token = "http://tools.ietf.org/html/rfc6749#section-3.2" 205 - let subscribe = "http://ostatus.org/schema/1.0/subscribe" 206 - let salmon = "salmon" 207 - let magic_key = "magic-public-key" 208 - end 209 - 210 - (** {1 URL Construction} *) 211 - 212 - let webfinger_url ~resource ?(rels = []) host = 213 - let base = Printf.sprintf "https://%s/.well-known/webfinger" host in 214 - let uri = Uri.of_string base in 215 - let uri = Uri.add_query_param' uri ("resource", resource) in 216 - let uri = List.fold_left (fun u rel -> Uri.add_query_param' u ("rel", rel)) uri rels in 217 - Uri.to_string uri 218 - 219 - let host_of_resource resource = 220 - if String.length resource > 5 && String.sub resource 0 5 = "acct:" then begin 221 - match String.index_opt resource '@' with 222 - | Some idx -> 223 - let host_part = String.sub resource (idx + 1) (String.length resource - idx - 1) in 224 - Ok host_part 225 - | None -> Error (Invalid_resource "acct: URI must contain @") 226 - end else begin 227 - let uri = Uri.of_string resource in 228 - match Uri.host uri with 229 - | Some host -> Ok host 230 - | None -> Error (Invalid_resource "Cannot determine host from resource URI") 231 - end 232 - 233 - (** {1 HTTP Client} *) 234 - 235 - let query session ~resource ?(rels = []) () = 236 - match host_of_resource resource with 237 - | Error e -> Error e 238 - | Ok host -> 239 - let url = webfinger_url ~resource ~rels host in 240 - Log.info (fun m -> m "WebFinger query: %s" url); 241 - let headers = Requests.Headers.empty |> Requests.Headers.set `Accept "application/jrd+json" in 242 - let response = Requests.get session ~headers url in 243 - let status = Requests.Response.status_code response in 244 - let body = Eio.Flow.read_all (Requests.Response.body response) in 245 - if status = 404 then Error Not_found 246 - else if status >= 400 then Error (Http_error { status; body }) 247 - else Jrd.of_string body 248 - 249 - let query_exn session ~resource ?rels () = 250 - match query session ~resource ?rels () with 251 - | Ok jrd -> jrd 252 - | Error e -> raise_error e
-220
ocaml-webfinger/lib/webfinger.mli
··· 1 - (*--------------------------------------------------------------------------- 2 - Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 5 - 6 - (** RFC 7033 WebFinger: Protocol for discovering resource information. 7 - 8 - This module implements the WebFinger protocol as specified in 9 - {{:https://datatracker.ietf.org/doc/html/rfc7033}RFC 7033}, providing 10 - type-safe JSON Resource Descriptor (JRD) encoding/decoding and an 11 - HTTP client for WebFinger queries. 12 - 13 - {2 Example} 14 - {[ 15 - Eio_main.run @@ fun env -> 16 - Eio.Switch.run @@ fun sw -> 17 - let session = Requests.create ~sw env in 18 - match Webfinger.query session ~resource:"acct:user@example.com" () with 19 - | Ok jrd -> 20 - Format.printf "%a@." Webfinger.Jrd.pp jrd; 21 - begin match Webfinger.Jrd.find_link ~rel:"self" jrd with 22 - | Some link -> Format.printf "ActivityPub: %s@." (Option.get (Webfinger.Link.href link)) 23 - | None -> () 24 - end 25 - | Error e -> 26 - Format.eprintf "Error: %a@." Webfinger.pp_error e 27 - ]} 28 - 29 - {2 References} 30 - {ul 31 - {- {{:https://datatracker.ietf.org/doc/html/rfc7033}RFC 7033} - WebFinger} 32 - {- {{:https://datatracker.ietf.org/doc/html/rfc6415}RFC 6415} - Web Host Metadata}} *) 33 - 34 - (** {1 Error Types} *) 35 - 36 - type error = 37 - | Invalid_resource of string 38 - (** The resource parameter is missing or malformed. *) 39 - | Http_error of { status : int; body : string } 40 - (** HTTP request failed with the given status code. *) 41 - | Json_error of string 42 - (** Failed to parse JRD JSON response. *) 43 - | Https_required 44 - (** WebFinger requires HTTPS but HTTP was requested. *) 45 - | Not_found 46 - (** The server has no information about the requested resource. *) 47 - 48 - val pp_error : Format.formatter -> error -> unit 49 - (** [pp_error fmt e] pretty-prints an error. *) 50 - 51 - val error_to_string : error -> string 52 - (** [error_to_string e] converts an error to a human-readable string. *) 53 - 54 - exception Webfinger_error of error 55 - (** Exception raised by [*_exn] functions. *) 56 - 57 - (** {1 Link} 58 - 59 - Link relation object as specified in 60 - {{:https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4}RFC 7033 Section 4.4.4}. *) 61 - 62 - module Link : sig 63 - type t 64 - (** A link relation in a JRD. *) 65 - 66 - val make : 67 - rel:string -> 68 - ?type_:string -> 69 - ?href:string -> 70 - ?titles:(string * string) list -> 71 - ?properties:(string * string option) list -> 72 - unit -> t 73 - (** [make ~rel ?type_ ?href ?titles ?properties ()] creates a link. *) 74 - 75 - val rel : t -> string 76 - (** [rel link] returns the link relation type. *) 77 - 78 - val type_ : t -> string option 79 - (** [type_ link] returns the media type. *) 80 - 81 - val href : t -> string option 82 - (** [href link] returns the target URI. *) 83 - 84 - val titles : t -> (string * string) list 85 - (** [titles link] returns all title/language pairs. *) 86 - 87 - val properties : t -> (string * string option) list 88 - (** [properties link] returns all link properties. *) 89 - 90 - val title : ?lang:string -> t -> string option 91 - (** [title ?lang link] returns the title for [lang] (default "und"). *) 92 - 93 - val property : uri:string -> t -> string option 94 - (** [property ~uri link] returns the property value for [uri]. *) 95 - 96 - val jsont : t Jsont.t 97 - (** JSON type descriptor for links. *) 98 - 99 - val pp : Format.formatter -> t -> unit 100 - (** [pp fmt link] pretty-prints a link. *) 101 - end 102 - 103 - (** {1 JRD} 104 - 105 - JSON Resource Descriptor as specified in 106 - {{:https://datatracker.ietf.org/doc/html/rfc7033#section-4.4}RFC 7033 Section 4.4}. *) 107 - 108 - module Jrd : sig 109 - type t 110 - (** A JSON Resource Descriptor. *) 111 - 112 - val make : 113 - ?subject:string -> 114 - ?aliases:string list -> 115 - ?properties:(string * string option) list -> 116 - ?links:Link.t list -> 117 - unit -> t 118 - (** [make ?subject ?aliases ?properties ?links ()] creates a JRD. *) 119 - 120 - val subject : t -> string option 121 - (** [subject jrd] returns the subject URI. *) 122 - 123 - val aliases : t -> string list 124 - (** [aliases jrd] returns the list of alias URIs. *) 125 - 126 - val properties : t -> (string * string option) list 127 - (** [properties jrd] returns subject properties. *) 128 - 129 - val links : t -> Link.t list 130 - (** [links jrd] returns all links. *) 131 - 132 - val find_link : rel:string -> t -> Link.t option 133 - (** [find_link ~rel jrd] returns the first link with relation [rel]. *) 134 - 135 - val find_links : rel:string -> t -> Link.t list 136 - (** [find_links ~rel jrd] returns all links with relation [rel]. *) 137 - 138 - val property : uri:string -> t -> string option 139 - (** [property ~uri jrd] returns the property value for [uri]. *) 140 - 141 - val jsont : t Jsont.t 142 - (** JSON type descriptor for JRD. *) 143 - 144 - val of_string : string -> (t, error) result 145 - (** [of_string s] parses a JRD from JSON. *) 146 - 147 - val to_string : t -> string 148 - (** [to_string jrd] serializes a JRD to JSON. *) 149 - 150 - val pp : Format.formatter -> t -> unit 151 - (** [pp fmt jrd] pretty-prints a JRD. *) 152 - end 153 - 154 - (** {1 Common Link Relations} *) 155 - 156 - module Rel : sig 157 - val activitypub : string 158 - (** ["self"] - ActivityPub actor profile. *) 159 - 160 - val openid : string 161 - (** OpenID Connect issuer. *) 162 - 163 - val profile : string 164 - (** Profile page. *) 165 - 166 - val avatar : string 167 - (** Avatar image. *) 168 - 169 - val feed : string 170 - (** Atom/RSS feed. *) 171 - 172 - val portable_contacts : string 173 - (** Portable Contacts. *) 174 - 175 - val oauth_authorization : string 176 - (** OAuth 2.0 authorization endpoint. *) 177 - 178 - val oauth_token : string 179 - (** OAuth 2.0 token endpoint. *) 180 - 181 - val subscribe : string 182 - (** Subscribe to resource (OStatus). *) 183 - 184 - val salmon : string 185 - (** Salmon endpoint (legacy). *) 186 - 187 - val magic_key : string 188 - (** Magic public key (legacy). *) 189 - end 190 - 191 - (** {1 URL Construction} *) 192 - 193 - val webfinger_url : resource:string -> ?rels:string list -> string -> string 194 - (** [webfinger_url ~resource ?rels host] constructs the WebFinger query URL. *) 195 - 196 - val host_of_resource : string -> (string, error) result 197 - (** [host_of_resource resource] extracts the host from an acct: or https: URI. *) 198 - 199 - (** {1 HTTP Client} *) 200 - 201 - val query : 202 - Requests.t -> 203 - resource:string -> 204 - ?rels:string list -> 205 - unit -> (Jrd.t, error) result 206 - (** [query session ~resource ?rels ()] performs a WebFinger query. 207 - 208 - Per {{:https://datatracker.ietf.org/doc/html/rfc7033#section-4}RFC 7033 Section 4}: 209 - - Queries use HTTPS 210 - - The Accept header requests application/jrd+json 211 - - 200 OK returns a JRD 212 - - 404 means no information available *) 213 - 214 - val query_exn : 215 - Requests.t -> 216 - resource:string -> 217 - ?rels:string list -> 218 - unit -> Jrd.t 219 - (** [query_exn session ~resource ?rels ()] is like {!query} but raises 220 - {!Webfinger_error} on failure. *)
-1571
ocaml-webfinger/spec/rfc7033.txt
··· 1 - 2 - 3 - 4 - 5 - 6 - 7 - Internet Engineering Task Force (IETF) P. Jones 8 - Request for Comments: 7033 G. Salgueiro 9 - Category: Standards Track Cisco Systems 10 - ISSN: 2070-1721 M. Jones 11 - Microsoft 12 - J. Smarr 13 - Google 14 - September 2013 15 - 16 - 17 - WebFinger 18 - 19 - Abstract 20 - 21 - This specification defines the WebFinger protocol, which can be used 22 - to discover information about people or other entities on the 23 - Internet using standard HTTP methods. WebFinger discovers 24 - information for a URI that might not be usable as a locator 25 - otherwise, such as account or email URIs. 26 - 27 - Status of This Memo 28 - 29 - This is an Internet Standards Track document. 30 - 31 - This document is a product of the Internet Engineering Task Force 32 - (IETF). It represents the consensus of the IETF community. It has 33 - received public review and has been approved for publication by the 34 - Internet Engineering Steering Group (IESG). Further information on 35 - Internet Standards is available in Section 2 of RFC 5741. 36 - 37 - Information about the current status of this document, any errata, 38 - and how to provide feedback on it may be obtained at 39 - http://www.rfc-editor.org/info/rfc7033. 40 - 41 - Copyright Notice 42 - 43 - Copyright (c) 2013 IETF Trust and the persons identified as the 44 - document authors. All rights reserved. 45 - 46 - This document is subject to BCP 78 and the IETF Trust's Legal 47 - Provisions Relating to IETF Documents 48 - (http://trustee.ietf.org/license-info) in effect on the date of 49 - publication of this document. Please review these documents 50 - carefully, as they describe your rights and restrictions with respect 51 - to this document. Code Components extracted from this document must 52 - include Simplified BSD License text as described in Section 4.e of 53 - the Trust Legal Provisions and are provided without warranty as 54 - described in the Simplified BSD License. 55 - 56 - 57 - 58 - Jones, et al. Standards Track [Page 1] 59 - 60 - RFC 7033 WebFinger September 2013 61 - 62 - 63 - Table of Contents 64 - 65 - 1. Introduction ....................................................3 66 - 2. Terminology .....................................................3 67 - 3. Example Uses of WebFinger .......................................4 68 - 3.1. Identity Provider Discovery for OpenID Connect .............4 69 - 3.2. Getting Author and Copyright Information for a Web Page ....5 70 - 4. WebFinger Protocol ..............................................7 71 - 4.1. Constructing the Query Component of the Request URI.......7 72 - 4.2. Performing a WebFinger Query..............................8 73 - 4.3. The "rel" Parameter.......................................9 74 - 4.4. The JSON Resource Descriptor (JRD).......................11 75 - 4.4.1. subject.............................................11 76 - 4.4.2. aliases.............................................11 77 - 4.4.3. properties..........................................12 78 - 4.4.4. links...............................................12 79 - 4.5. WebFinger and URIs.......................................14 80 - 5. Cross-Origin Resource Sharing (CORS) ...........................14 81 - 6. Access Control .................................................15 82 - 7. Hosted WebFinger Services ......................................15 83 - 8. Definition of WebFinger Applications ...........................16 84 - 8.1. Specification of the URI Scheme and URI ...................17 85 - 8.2. Host Resolution ...........................................17 86 - 8.3. Specification of Properties ...............................17 87 - 8.4. Specification of Links ....................................18 88 - 8.5. One URI, Multiple Applications ............................18 89 - 8.6. Registration of Link Relation Types and Properties ........19 90 - 9. Security Considerations ........................................19 91 - 9.1. Transport-Related Issues ..................................19 92 - 9.2. User Privacy Considerations ...............................19 93 - 9.3. Abuse Potential ...........................................21 94 - 9.4. Information Reliability ...................................21 95 - 10. IANA Considerations ...........................................22 96 - 10.1. Well-Known URI ...........................................22 97 - 10.2. JSON Resource Descriptor (JRD) Media Type ................22 98 - 10.3. Registering Link Relation Types ..........................24 99 - 10.4. Establishment of the "WebFinger Properties" Registry .....24 100 - 10.4.1. The Registration Template .........................24 101 - 10.4.2. The Registration Procedures .......................25 102 - 11. Acknowledgments ...............................................26 103 - 12. References ....................................................26 104 - 12.1. Normative References .....................................26 105 - 12.2. Informative References ...................................27 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - Jones, et al. Standards Track [Page 2] 115 - 116 - RFC 7033 WebFinger September 2013 117 - 118 - 119 - 1. Introduction 120 - 121 - WebFinger is used to discover information about people or other 122 - entities on the Internet that are identified by a URI [6] using 123 - standard Hypertext Transfer Protocol (HTTP) [2] methods over a secure 124 - transport [12]. A WebFinger resource returns a JavaScript Object 125 - Notation (JSON) [5] object describing the entity that is queried. 126 - The JSON object is referred to as the JSON Resource Descriptor (JRD). 127 - 128 - For a person, the type of information that might be discoverable via 129 - WebFinger includes a personal profile address, identity service, 130 - telephone number, or preferred avatar. For other entities on the 131 - Internet, a WebFinger resource might return JRDs containing link 132 - relations [8] that enable a client to discover, for example, that a 133 - printer can print in color on A4 paper, the physical location of a 134 - server, or other static information. 135 - 136 - Information returned via WebFinger might be for direct human 137 - consumption (e.g., looking up someone's phone number), or it might be 138 - used by systems to help carry out some operation (e.g., facilitating, 139 - with additional security mechanisms, logging into a web site by 140 - determining a user's identity service). The information is intended 141 - to be static in nature, and, as such, WebFinger is not intended to be 142 - used to return dynamic information like the temperature of a CPU or 143 - the current toner level in a laser printer. 144 - 145 - The WebFinger protocol is designed to be used across many 146 - applications. Applications that wish to utilize WebFinger will need 147 - to specify properties, titles, and link relation types that are 148 - appropriate for the application. Further, applications will need to 149 - define the appropriate URI scheme to utilize for the query target. 150 - 151 - Use of WebFinger is illustrated in the examples in Section 3 and 152 - described more formally in Section 4. Section 8 describes how 153 - applications of WebFinger may be defined. 154 - 155 - 2. Terminology 156 - 157 - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 158 - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 159 - document are to be interpreted as described in RFC 2119 [1]. 160 - 161 - WebFinger makes heavy use of "link relations". A link relation is an 162 - attribute-value pair in which the attribute identifies the type of 163 - relationship between the linked entity or resource and the 164 - information specified in the value. In Web Linking [4], the link 165 - relation is represented using an HTTP entity-header of "Link", where 166 - the "rel" attribute specifies the type of relationship and the "href" 167 - 168 - 169 - 170 - Jones, et al. Standards Track [Page 3] 171 - 172 - RFC 7033 WebFinger September 2013 173 - 174 - 175 - attribute specifies the information that is linked to the entity or 176 - resource. In WebFinger, the same concept is represented using a JSON 177 - array of "links" objects, where each member named "rel" specifies the 178 - type of relationship and each member named "href" specifies the 179 - information that is linked to the entity or resource. Note that 180 - WebFinger narrows the scope of a link relation beyond what is defined 181 - for Web Linking by stipulating that the value of the "rel" member 182 - needs to be either a single IANA-registered link relation type [8] or 183 - a URI [6]. 184 - 185 - The use of URIs throughout this document refers to URIs following the 186 - syntax specified in Section 3 of RFC 3986 [6]. Relative URIs, having 187 - syntax following that of Section 4.2 of RFC 3986, are not used with 188 - WebFinger. 189 - 190 - 3. Example Uses of WebFinger 191 - 192 - This section shows a few sample uses of WebFinger. Any application 193 - of WebFinger would be specified outside of this document, as 194 - described in Section 8. The examples in this section should be 195 - simple enough to understand without having seen the formal 196 - specifications of the applications. 197 - 198 - 3.1. Identity Provider Discovery for OpenID Connect 199 - 200 - Suppose Carol wishes to authenticate with a web site she visits using 201 - OpenID Connect [15]. She would provide the web site with her OpenID 202 - Connect identifier, say carol@example.com. The visited web site 203 - would perform a WebFinger query looking for the OpenID Connect 204 - provider. Since the site is interested in only one particular link 205 - relation, the WebFinger resource might utilize the "rel" parameter as 206 - described in Section 4.3: 207 - 208 - GET /.well-known/webfinger? 209 - resource=acct%3Acarol%40example.com& 210 - rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer 211 - HTTP/1.1 212 - Host: example.com 213 - 214 - 215 - 216 - 217 - 218 - 219 - 220 - 221 - 222 - 223 - 224 - 225 - 226 - Jones, et al. Standards Track [Page 4] 227 - 228 - RFC 7033 WebFinger September 2013 229 - 230 - 231 - The server might respond like this: 232 - 233 - HTTP/1.1 200 OK 234 - Access-Control-Allow-Origin: * 235 - Content-Type: application/jrd+json 236 - 237 - { 238 - "subject" : "acct:carol@example.com", 239 - "links" : 240 - [ 241 - { 242 - "rel" : "http://openid.net/specs/connect/1.0/issuer", 243 - "href" : "https://openid.example.com" 244 - } 245 - ] 246 - } 247 - 248 - Since the "rel" parameter only serves to filter the link relations 249 - returned by the resource, other name/value pairs in the response, 250 - including any aliases or properties, would be returned. Also, since 251 - support for the "rel" parameter is not guaranteed, the client must 252 - not assume the "links" array will contain only the requested link 253 - relation. 254 - 255 - 3.2. Getting Author and Copyright Information for a Web Page 256 - 257 - Suppose an application is defined to retrieve metadata information 258 - about a web page URL, such as author and copyright information. To 259 - retrieve that information, the client can utilize WebFinger to issue 260 - a query for the specific URL. Suppose the URL of interest is 261 - http://blog.example.com/article/id/314. The client would issue a 262 - query similar to the following: 263 - 264 - GET /.well-known/webfinger? 265 - resource=http%3A%2F%2Fblog.example.com%2Farticle%2Fid%2F314 266 - HTTP/1.1 267 - Host: blog.example.com 268 - 269 - 270 - 271 - 272 - 273 - 274 - 275 - 276 - 277 - 278 - 279 - 280 - 281 - 282 - Jones, et al. Standards Track [Page 5] 283 - 284 - RFC 7033 WebFinger September 2013 285 - 286 - 287 - The server might then reply in this way: 288 - 289 - HTTP/1.1 200 OK 290 - Access-Control-Allow-Origin: * 291 - Content-Type: application/jrd+json 292 - 293 - { 294 - "subject" : "http://blog.example.com/article/id/314", 295 - "aliases" : 296 - [ 297 - "http://blog.example.com/cool_new_thing", 298 - "http://blog.example.com/steve/article/7" 299 - ], 300 - "properties" : 301 - { 302 - "http://blgx.example.net/ns/version" : "1.3", 303 - "http://blgx.example.net/ns/ext" : null 304 - }, 305 - "links" : 306 - [ 307 - { 308 - "rel" : "copyright", 309 - "href" : "http://www.example.com/copyright" 310 - }, 311 - { 312 - "rel" : "author", 313 - "href" : "http://blog.example.com/author/steve", 314 - "titles" : 315 - { 316 - "en-us" : "The Magical World of Steve", 317 - "fr" : "Le Monde Magique de Steve" 318 - }, 319 - "properties" : 320 - { 321 - "http://example.com/role" : "editor" 322 - } 323 - } 324 - 325 - ] 326 - } 327 - 328 - In the above example, we see that the server returned a list of 329 - aliases, properties, and links related to the subject URL. The links 330 - contain references to information for each link relation type. For 331 - the author link, the server provided a reference to the author's 332 - blog, along with a title for the blog in two languages. The server 333 - also returned a single property related to the author, indicating the 334 - author's role as editor of the blog. 335 - 336 - 337 - 338 - Jones, et al. Standards Track [Page 6] 339 - 340 - RFC 7033 WebFinger September 2013 341 - 342 - 343 - It is worth noting that, while the server returned just two links in 344 - the "links" array in this example, a server might return any number 345 - of links when queried. 346 - 347 - 4. WebFinger Protocol 348 - 349 - The WebFinger protocol is used to request information about an entity 350 - identified by a query target (a URI). The client can optionally 351 - specify one or more link relation types for which it would like to 352 - receive information. 353 - 354 - A WebFinger request is an HTTPS request to a WebFinger resource. A 355 - WebFinger resource is a well-known URI [3] using the HTTPS scheme 356 - constructed along with the required query target and optional link 357 - relation types. WebFinger resources MUST NOT be served with any 358 - other URI scheme (such as HTTP). 359 - 360 - A WebFinger resource is always given a query target, which is another 361 - URI that identifies the entity whose information is sought. GET 362 - requests to a WebFinger resource convey the query target in the 363 - "resource" parameter of the WebFinger URI's query string; see Section 364 - 4.1 for details. 365 - 366 - The host to which a WebFinger query is issued is significant. If the 367 - query target contains a "host" portion (Section 3.2.2 of RFC 3986), 368 - then the host to which the WebFinger query is issued SHOULD be the 369 - same as the "host" portion of the query target, unless the client 370 - receives instructions through some out-of-band mechanism to send the 371 - query to another host. If the query target does not contain a "host" 372 - portion, then the client chooses a host to which it directs the query 373 - using additional information it has. 374 - 375 - The path component of a WebFinger URI MUST be the well-known path 376 - "/.well-known/webfinger". A WebFinger URI MUST contain a query 377 - component that encodes the query target and optional link relation 378 - types as specified in Section 4.1. 379 - 380 - The WebFinger resource returns a JSON Resource Descriptor (JRD) as 381 - the resource representation to convey information about an entity on 382 - the Internet. Also, the Cross-Origin Resource Sharing (CORS) [7] 383 - specification is utilized to facilitate queries made via a web 384 - browser. 385 - 386 - 4.1. Constructing the Query Component of the Request URI 387 - 388 - A WebFinger URI MUST contain a query component (see Section 3.4 of 389 - RFC 3986). The query component MUST contain a "resource" parameter 390 - and MAY contain one or more "rel" parameters. The "resource" 391 - 392 - 393 - 394 - Jones, et al. Standards Track [Page 7] 395 - 396 - RFC 7033 WebFinger September 2013 397 - 398 - 399 - parameter MUST contain the query target (URI), and the "rel" 400 - parameters MUST contain encoded link relation types according to the 401 - encoding described in this section. 402 - 403 - To construct the query component, the client performs the following 404 - steps. First, each parameter value is percent-encoded, as per 405 - Section 2.1 of RFC 3986. The encoding is done to conform to the 406 - query production in Section 3.4 of that specification, with the 407 - addition that any instances of the "=" and "&" characters within the 408 - parameter values are also percent-encoded. Next, the client 409 - constructs a string to be placed in the query component by 410 - concatenating the name of the first parameter together with an equal 411 - sign ("=") and the percent-encoded parameter value. For any 412 - subsequent parameters, the client appends an ampersand ("&") to the 413 - string, the name of the next parameter, an equal sign, and the 414 - parameter value. The client MUST NOT insert any spaces while 415 - constructing the string. The order in which the client places each 416 - attribute-value pair within the query component does not matter in 417 - the interpretation of the query component. 418 - 419 - 4.2. Performing a WebFinger Query 420 - 421 - A WebFinger client issues a query using the GET method to the well- 422 - known [3] resource identified by the URI whose path component is 423 - "/.well-known/webfinger" and whose query component MUST include the 424 - "resource" parameter exactly once and set to the value of the URI for 425 - which information is being sought. 426 - 427 - If the "resource" parameter is absent or malformed, the WebFinger 428 - resource MUST indicate that the request is bad as per Section 10.4.1 429 - of RFC 2616 [2]. 430 - 431 - If the "resource" parameter is a value for which the server has no 432 - information, the server MUST indicate that it was unable to match the 433 - request as per Section 10.4.5 of RFC 2616. 434 - 435 - A client MUST query the WebFinger resource using HTTPS only. If the 436 - client determines that the resource has an invalid certificate, the 437 - resource returns a 4xx or 5xx status code, or if the HTTPS connection 438 - cannot be established for any reason, then the client MUST accept 439 - that the WebFinger query has failed and MUST NOT attempt to reissue 440 - the WebFinger request using HTTP over a non-secure connection. 441 - 442 - A WebFinger resource MUST return a JRD as the representation for the 443 - resource if the client requests no other supported format explicitly 444 - via the HTTP "Accept" header. The client MAY include the "Accept" 445 - header to indicate a desired representation; representations other 446 - than JRD might be defined in future specifications. The WebFinger 447 - 448 - 449 - 450 - Jones, et al. Standards Track [Page 8] 451 - 452 - RFC 7033 WebFinger September 2013 453 - 454 - 455 - resource MUST silently ignore any requested representations that it 456 - does not understand or support. The media type used for the JSON 457 - Resource Descriptor (JRD) is "application/jrd+json" (see Section 458 - 10.2). 459 - 460 - The properties, titles, and link relation types returned by the 461 - server in a JRD might be varied and numerous. For example, the 462 - server might return information about a person's blog, vCard [14], 463 - avatar, OpenID Connect provider, RSS or ATOM feed, and so forth in a 464 - reply. Likewise, if a server has no information to provide, it might 465 - return a JRD with an empty "links" array or no "links" array. 466 - 467 - A WebFinger resource MAY redirect the client; if it does, the 468 - redirection MUST only be to an "https" URI and the client MUST 469 - perform certificate validation again when redirected. 470 - 471 - A WebFinger resource can include cache validators in a response to 472 - enable conditional requests by the client and/or expiration times as 473 - per Section 13 of RFC 2616. 474 - 475 - 4.3. The "rel" Parameter 476 - 477 - When issuing a request to a WebFinger resource, the client MAY 478 - utilize the "rel" parameter to request only a subset of the 479 - information that would otherwise be returned without the "rel" 480 - parameter. When the "rel" parameter is used and accepted, only the 481 - link relation types that match the link relation type provided via 482 - the "rel" parameter are included in the array of links returned in 483 - the JRD. If there are no matching link relation types defined for 484 - the resource, the "links" array in the JRD will be either absent or 485 - empty. All other information present in a resource descriptor 486 - remains present, even when "rel" is employed. 487 - 488 - The "rel" parameter MAY be included multiple times in order to 489 - request multiple link relation types. 490 - 491 - The purpose of the "rel" parameter is to return a subset of "link 492 - relation objects" (see Section 4.4.4) that would otherwise be 493 - returned in the resource descriptor. Use of the parameter might 494 - reduce processing requirements on either the client or server, and it 495 - might also reduce the bandwidth required to convey the partial 496 - resource descriptor, especially if there are numerous link relation 497 - values to convey for a given "resource" value. Note that if a client 498 - requests a particular link relation type for which the server has no 499 - information, the server MAY return a JRD with an empty "links" array 500 - or no "links" array. 501 - 502 - 503 - 504 - 505 - 506 - Jones, et al. Standards Track [Page 9] 507 - 508 - RFC 7033 WebFinger September 2013 509 - 510 - 511 - WebFinger resources SHOULD support the "rel" parameter. If the 512 - resource does not support the "rel" parameter, it MUST ignore the 513 - parameter and process the request as if no "rel" parameter values 514 - were present. 515 - 516 - The following example uses the "rel" parameter to request links for 517 - two link relation types: 518 - 519 - GET /.well-known/webfinger? 520 - resource=acct%3Abob%40example.com& 521 - rel=http%3A%2F%2Fwebfinger.example%2Frel%2Fprofile-page& 522 - rel=http%3A%2F%2Fwebfinger.example%2Frel%2Fbusinesscard HTTP/1.1 523 - Host: example.com 524 - 525 - In this example, the client requests the link relations of type 526 - "http://webfinger.example/rel/profile-page" and 527 - "http://webfinger.example/rel/businesscard". The server then 528 - responds with a message like this: 529 - 530 - HTTP/1.1 200 OK 531 - Access-Control-Allow-Origin: * 532 - Content-Type: application/jrd+json 533 - 534 - { 535 - "subject" : "acct:bob@example.com", 536 - "aliases" : 537 - [ 538 - "https://www.example.com/~bob/" 539 - ], 540 - "properties" : 541 - { 542 - "http://example.com/ns/role" : "employee" 543 - }, 544 - "links" : 545 - [ 546 - { 547 - "rel" : "http://webfinger.example/rel/profile-page", 548 - "href" : "https://www.example.com/~bob/" 549 - }, 550 - { 551 - "rel" : "http://webfinger.example/rel/businesscard", 552 - "href" : "https://www.example.com/~bob/bob.vcf" 553 - } 554 - ] 555 - } 556 - 557 - 558 - 559 - 560 - 561 - 562 - Jones, et al. Standards Track [Page 10] 563 - 564 - RFC 7033 WebFinger September 2013 565 - 566 - 567 - As you can see in the response, the resource representation contains 568 - only the links of the types requested by the client and for which the 569 - server had information, but the other parts of the JRD are still 570 - present. Note also in the above example that the links returned in 571 - the "links" array all use HTTPS, which is important if the data 572 - indirectly obtained via WebFinger needs to be returned securely. 573 - 574 - 4.4. The JSON Resource Descriptor (JRD) 575 - 576 - The JSON Resource Descriptor (JRD), originally introduced in RFC 6415 577 - [16] and based on the Extensible Resource Descriptor (XRD) format 578 - [17], is a JSON object that comprises the following name/value pairs: 579 - 580 - o subject 581 - o aliases 582 - o properties 583 - o links 584 - 585 - The member "subject" is a name/value pair whose value is a string, 586 - "aliases" is an array of strings, "properties" is an object 587 - comprising name/value pairs whose values are strings, and "links" is 588 - an array of objects that contain link relation information. 589 - 590 - When processing a JRD, the client MUST ignore any unknown member and 591 - not treat the presence of an unknown member as an error. 592 - 593 - Below, each of these members of the JRD is described in more detail. 594 - 595 - 4.4.1. subject 596 - 597 - The value of the "subject" member is a URI that identifies the entity 598 - that the JRD describes. 599 - 600 - The "subject" value returned by a WebFinger resource MAY differ from 601 - the value of the "resource" parameter used in the client's request. 602 - This might happen, for example, when the subject's identity changes 603 - (e.g., a user moves his or her account to another service) or when 604 - the resource prefers to express URIs in canonical form. 605 - 606 - The "subject" member SHOULD be present in the JRD. 607 - 608 - 4.4.2. aliases 609 - 610 - The "aliases" array is an array of zero or more URI strings that 611 - identify the same entity as the "subject" URI. 612 - 613 - The "aliases" array is OPTIONAL in the JRD. 614 - 615 - 616 - 617 - 618 - Jones, et al. Standards Track [Page 11] 619 - 620 - RFC 7033 WebFinger September 2013 621 - 622 - 623 - 4.4.3. properties 624 - 625 - The "properties" object comprises zero or more name/value pairs whose 626 - names are URIs (referred to as "property identifiers") and whose 627 - values are strings or null. Properties are used to convey additional 628 - information about the subject of the JRD. As an example, consider 629 - this use of "properties": 630 - 631 - "properties" : { "http://webfinger.example/ns/name" : "Bob Smith" } 632 - 633 - The "properties" member is OPTIONAL in the JRD. 634 - 635 - 4.4.4. links 636 - 637 - The "links" array has any number of member objects, each of which 638 - represents a link [4]. Each of these link objects can have the 639 - following members: 640 - 641 - o rel 642 - o type 643 - o href 644 - o titles 645 - o properties 646 - 647 - The "rel" and "href" members are strings representing the link's 648 - relation type and the target URI, respectively. The context of the 649 - link is the "subject" (see Section 4.4.1). 650 - 651 - The "type" member is a string indicating what the media type of the 652 - result of dereferencing the link ought to be. 653 - 654 - The order of elements in the "links" array MAY be interpreted as 655 - indicating an order of preference. Thus, if there are two or more 656 - link relations having the same "rel" value, the first link relation 657 - would indicate the user's preferred link. 658 - 659 - The "links" array is OPTIONAL in the JRD. 660 - 661 - Below, each of the members of the objects found in the "links" array 662 - is described in more detail. Each object in the "links" array, 663 - referred to as a "link relation object", is completely independent 664 - from any other object in the array; any requirement to include a 665 - given member in the link relation object refers only to that 666 - particular object. 667 - 668 - 669 - 670 - 671 - 672 - 673 - 674 - Jones, et al. Standards Track [Page 12] 675 - 676 - RFC 7033 WebFinger September 2013 677 - 678 - 679 - 4.4.4.1. rel 680 - 681 - The value of the "rel" member is a string that is either a URI or a 682 - registered relation type [8] (see RFC 5988 [4]). The value of the 683 - "rel" member MUST contain exactly one URI or registered relation 684 - type. The URI or registered relation type identifies the type of the 685 - link relation. 686 - 687 - The other members of the object have meaning only once the type of 688 - link relation is understood. In some instances, the link relation 689 - will have associated semantics enabling the client to query for other 690 - resources on the Internet. In other instances, the link relation 691 - will have associated semantics enabling the client to utilize the 692 - other members of the link relation object without fetching additional 693 - external resources. 694 - 695 - URI link relation type values are compared using the "Simple String 696 - Comparison" algorithm of Section 6.2.1 of RFC 3986. 697 - 698 - The "rel" member MUST be present in the link relation object. 699 - 700 - 4.4.4.2. type 701 - 702 - The value of the "type" member is a string that indicates the media 703 - type [9] of the target resource (see RFC 6838 [10]). 704 - 705 - The "type" member is OPTIONAL in the link relation object. 706 - 707 - 4.4.4.3. href 708 - 709 - The value of the "href" member is a string that contains a URI 710 - pointing to the target resource. 711 - 712 - The "href" member is OPTIONAL in the link relation object. 713 - 714 - 4.4.4.4. titles 715 - 716 - The "titles" object comprises zero or more name/value pairs whose 717 - names are a language tag [11] or the string "und". The string is 718 - human-readable and describes the link relation. More than one title 719 - for the link relation MAY be provided for the benefit of users who 720 - utilize the link relation, and, if used, a language identifier SHOULD 721 - be duly used as the name. If the language is unknown or unspecified, 722 - then the name is "und". 723 - 724 - A JRD SHOULD NOT include more than one title identified with the same 725 - language tag (or "und") within the link relation object. Meaning is 726 - undefined if a link relation object includes more than one title 727 - 728 - 729 - 730 - Jones, et al. Standards Track [Page 13] 731 - 732 - RFC 7033 WebFinger September 2013 733 - 734 - 735 - named with the same language tag (or "und"), though this MUST NOT be 736 - treated as an error. A client MAY select whichever title or titles 737 - it wishes to utilize. 738 - 739 - Here is an example of the "titles" object: 740 - 741 - "titles" : 742 - { 743 - "en-us" : "The Magical World of Steve", 744 - "fr" : "Le Monde Magique de Steve" 745 - } 746 - 747 - The "titles" member is OPTIONAL in the link relation object. 748 - 749 - 4.4.4.5. properties 750 - 751 - The "properties" object within the link relation object comprises 752 - zero or more name/value pairs whose names are URIs (referred to as 753 - "property identifiers") and whose values are strings or null. 754 - Properties are used to convey additional information about the link 755 - relation. As an example, consider this use of "properties": 756 - 757 - "properties" : { "http://webfinger.example/mail/port" : "993" } 758 - 759 - The "properties" member is OPTIONAL in the link relation object. 760 - 761 - 4.5. WebFinger and URIs 762 - 763 - WebFinger requests include a "resource" parameter (see Section 4.1) 764 - specifying the query target (URI) for which the client requests 765 - information. WebFinger is neutral regarding the scheme of such a 766 - URI: it could be an "acct" URI [18], an "http" or "https" URI, a 767 - "mailto" URI [19], or some other scheme. 768 - 769 - 5. Cross-Origin Resource Sharing (CORS) 770 - 771 - WebFinger resources might not be accessible from a web browser due to 772 - "Same-Origin" policies. The current best practice is to make 773 - resources available to browsers through Cross-Origin Resource Sharing 774 - (CORS) [7], and servers MUST include the Access-Control-Allow-Origin 775 - HTTP header in responses. Servers SHOULD support the least 776 - restrictive setting by allowing any domain access to the WebFinger 777 - resource: 778 - 779 - Access-Control-Allow-Origin: * 780 - 781 - 782 - 783 - 784 - 785 - 786 - Jones, et al. Standards Track [Page 14] 787 - 788 - RFC 7033 WebFinger September 2013 789 - 790 - 791 - There are cases where defaulting to the least restrictive setting is 792 - not appropriate. For example, a server on an intranet that provides 793 - sensitive company information SHOULD NOT allow CORS requests from any 794 - domain, as that could allow leaking of that sensitive information. A 795 - server that wishes to restrict access to information from external 796 - entities SHOULD use a more restrictive Access-Control-Allow-Origin 797 - header. 798 - 799 - 6. Access Control 800 - 801 - As with all web resources, access to the WebFinger resource could 802 - require authentication. Further, failure to provide required 803 - credentials might result in the server forbidding access or providing 804 - a different response than had the client authenticated with the 805 - server. 806 - 807 - Likewise, a WebFinger resource MAY provide different responses to 808 - different clients based on other factors, such as whether the client 809 - is inside or outside a corporate network. As a concrete example, a 810 - query performed on the internal corporate network might return link 811 - relations to employee pictures, whereas link relations for employee 812 - pictures might not be provided to external entities. 813 - 814 - Further, link relations provided in a WebFinger resource 815 - representation might point to web resources that impose access 816 - restrictions. For example, the aforementioned corporate server may 817 - provide both internal and external entities with URIs to employee 818 - pictures, but further authentication might be required in order for 819 - the client to access the picture resources if the request comes from 820 - outside the corporate network. 821 - 822 - The decisions made with respect to what set of link relations a 823 - WebFinger resource provides to one client versus another and what 824 - resources require further authentication, as well as the specific 825 - authentication mechanisms employed, are outside the scope of this 826 - document. 827 - 828 - 7. Hosted WebFinger Services 829 - 830 - As with most services provided on the Internet, it is possible for a 831 - domain owner to utilize "hosted" WebFinger services. By way of 832 - example, a domain owner might control most aspects of their domain 833 - but use a third-party hosting service for email. In the case of 834 - email, mail exchange (MX) records identify mail servers for a domain. 835 - An MX record points to the mail server to which mail for the domain 836 - should be delivered. To the sending server, it does not matter 837 - whether those MX records point to a server in the destination domain 838 - or a different domain. 839 - 840 - 841 - 842 - Jones, et al. Standards Track [Page 15] 843 - 844 - RFC 7033 WebFinger September 2013 845 - 846 - 847 - Likewise, a domain owner might utilize the services of a third party 848 - to provide WebFinger services on behalf of its users. Just as a 849 - domain owner is required to insert MX records into DNS to allow for 850 - hosted email services, the domain owner is required to redirect HTTP 851 - queries to its domain to allow for hosted WebFinger services. 852 - 853 - When a query is issued to the WebFinger resource, the web server MUST 854 - return a response with a redirection status code that includes a 855 - Location header pointing to the location of the hosted WebFinger 856 - service URI. This WebFinger service URI does not need to point to 857 - the well-known WebFinger location on the hosting service provider 858 - server. 859 - 860 - As an example, assume that example.com's WebFinger services are 861 - hosted by wf.example.net. Suppose a client issues a query for 862 - acct:alice@example.com like this: 863 - 864 - GET /.well-known/webfinger? 865 - resource=acct%3Aalice%40example.com HTTP/1.1 866 - Host: example.com 867 - 868 - The server might respond with this: 869 - 870 - HTTP/1.1 307 Temporary Redirect 871 - Access-Control-Allow-Origin: * 872 - Location: https://wf.example.net/example.com/webfinger? 873 - resource=acct%3Aalice%40example.com 874 - 875 - The client can then follow the redirection, reissuing the request to 876 - the URI provided in the Location header. Note that the server will 877 - include any required URI parameters in the Location header value, 878 - which could be different than the URI parameters the client 879 - originally used. 880 - 881 - 8. Definition of WebFinger Applications 882 - 883 - This specification details the protocol syntax used to query a domain 884 - for information about a URI, the syntax of the JSON Resource 885 - Descriptor (JRD) that is returned in response to that query, security 886 - requirements and considerations, hosted WebFinger services, various 887 - expected HTTP status codes, and so forth. However, this 888 - specification does not enumerate the various possible properties or 889 - link relation types that might be used in conjunction with WebFinger 890 - for a particular application, nor does it define what properties or 891 - link relation types one might expect to see in response to querying 892 - for a particular URI or URI scheme. Nonetheless, all of these 893 - unspecified elements are important in order to implement an 894 - interoperable application that utilizes the WebFinger protocol and 895 - 896 - 897 - 898 - Jones, et al. Standards Track [Page 16] 899 - 900 - RFC 7033 WebFinger September 2013 901 - 902 - 903 - MUST be specified in the relevant document(s) defining the particular 904 - application making use of the WebFinger protocol according to the 905 - procedures described in this section. 906 - 907 - 8.1. Specification of the URI Scheme and URI 908 - 909 - Any application that uses WebFinger MUST specify the URI scheme(s), 910 - and to the extent appropriate, what forms the URI(s) might take. For 911 - example, when querying for information about a user's account at some 912 - domain, it might make sense to specify the use of the "acct" URI 913 - scheme [18]. When trying to obtain the copyright information for a 914 - web page, it makes sense to specify the use of the web page URI 915 - (either http or https). 916 - 917 - The examples in Sections 3.1 and 3.2 illustrate the use of different 918 - URI schemes with WebFinger applications. In the example in Section 919 - 3.1, WebFinger is used to retrieve information pertinent to OpenID 920 - Connect. In the example in Section 3.2, WebFinger is used to 921 - discover metadata information about a web page, including author and 922 - copyright information. Each of these WebFinger applications needs to 923 - be fully specified to ensure interoperability. 924 - 925 - 8.2. Host Resolution 926 - 927 - As explained in Section 4, the host to which a WebFinger query is 928 - issued is significant. In general, WebFinger applications would 929 - adhere to the procedures described in Section 4 in order to properly 930 - direct a WebFinger query. 931 - 932 - However, some URI schemes do not have host portions and there might 933 - be some applications of WebFinger for which the host portion of a URI 934 - cannot or should not be utilized. In such instances, the application 935 - specification MUST clearly define the host resolution procedures, 936 - which might include provisioning a "default" host within the client 937 - to which queries are directed. 938 - 939 - 8.3. Specification of Properties 940 - 941 - WebFinger defines both subject-specific properties (i.e., properties 942 - described in Section 4.4.3 that relate to the URI for which 943 - information is queried) and link-specific properties (see Section 944 - 4.4.4.5). This section refers to subject-specific properties. 945 - 946 - Applications that utilize subject-specific properties MUST define the 947 - URIs used in identifying those properties, along with valid property 948 - values. 949 - 950 - 951 - 952 - 953 - 954 - Jones, et al. Standards Track [Page 17] 955 - 956 - RFC 7033 WebFinger September 2013 957 - 958 - 959 - Consider this portion of the JRD found in the example in Section 3.2. 960 - 961 - "properties" : 962 - { 963 - "http://blgx.example.net/ns/version" : "1.3", 964 - "http://blgx.example.net/ns/ext" : null 965 - } 966 - 967 - Here, two properties are returned in the WebFinger response. Each of 968 - these would be defined in a WebFinger application specification. 969 - These two properties might be defined in the same WebFinger 970 - application specification or separately in different specifications. 971 - Since the latter is possible, it is important that WebFinger clients 972 - not assume that one property has any specific relationship with 973 - another property, unless some relationship is explicitly defined in 974 - the particular WebFinger application specification. 975 - 976 - 8.4. Specification of Links 977 - 978 - The links returned in a WebFinger response each comprise several 979 - pieces of information, some of which are optional (refer to Section 980 - 4.4.4). The WebFinger application specification MUST define each 981 - link and any values associated with a link, including the link 982 - relation type ("rel"), the expected media type ("type"), properties, 983 - and titles. 984 - 985 - The target URI to which the link refers (i.e., the "href"), if 986 - present, would not normally be specified in an application 987 - specification. However, the URI scheme or any special 988 - characteristics of the URI would usually be specified. If a 989 - particular link does not require an external reference, then all of 990 - the semantics related to the use of that link MUST be defined within 991 - the application specification. Such links might rely only on 992 - properties or titles in the link to convey meaning. 993 - 994 - 8.5. One URI, Multiple Applications 995 - 996 - It is important to be mindful of the fact that different WebFinger 997 - applications might specify the use of the same URI scheme, and in 998 - effect, the same URI for different purposes. That should not be a 999 - problem, since each of property identifier (see Sections 4.4.3 and 1000 - 4.4.4.5) and link relation type would be uniquely defined for a 1001 - specific application. 1002 - 1003 - It should be noted that when a client requests information about a 1004 - particular URI and receives a response with a number of different 1005 - property identifiers or link relation types that the response is 1006 - providing information about the URI without any particular semantics. 1007 - 1008 - 1009 - 1010 - Jones, et al. Standards Track [Page 18] 1011 - 1012 - RFC 7033 WebFinger September 2013 1013 - 1014 - 1015 - How the client interprets the information SHOULD be in accordance 1016 - with the particular application specification or set of 1017 - specifications the client implements. 1018 - 1019 - Any syntactically valid properties or links the client receives and 1020 - that are not fully understood SHOULD be ignored and SHOULD NOT cause 1021 - the client to report an error. 1022 - 1023 - 8.6. Registration of Link Relation Types and Properties 1024 - 1025 - Application specifications MAY define a simple token as a link 1026 - relation type for a link. In that case, the link relation type MUST 1027 - be registered with IANA as specified in Sections 10.3. 1028 - 1029 - Further, any defined properties MUST be registered with IANA as 1030 - described in Section 10.4. 1031 - 1032 - 9. Security Considerations 1033 - 1034 - 9.1. Transport-Related Issues 1035 - 1036 - Since this specification utilizes Cross-Origin Resource Sharing 1037 - (CORS) [7], all of the security considerations applicable to CORS are 1038 - also applicable to this specification. 1039 - 1040 - The use of HTTPS is REQUIRED to ensure that information is not 1041 - modified during transit. It should be acknowledged that in 1042 - environments where a web server is normally available, there exists 1043 - the possibility that a compromised network might have its WebFinger 1044 - resource operating on HTTPS replaced with one operating only over 1045 - HTTP. As such, clients MUST NOT issue queries over a non-secure 1046 - connection. 1047 - 1048 - Clients MUST verify that the certificate used on an HTTPS connection 1049 - is valid (as defined in [12]) and accept a response only if the 1050 - certificate is valid. 1051 - 1052 - 9.2. User Privacy Considerations 1053 - 1054 - Service providers and users should be aware that placing information 1055 - on the Internet means that any user can access that information, and 1056 - WebFinger can be used to make it even easier to discover that 1057 - information. While WebFinger can be an extremely useful tool for 1058 - discovering one's avatar, blog, or other personal data, users should 1059 - also understand the risks. 1060 - 1061 - 1062 - 1063 - 1064 - 1065 - 1066 - Jones, et al. Standards Track [Page 19] 1067 - 1068 - RFC 7033 WebFinger September 2013 1069 - 1070 - 1071 - Systems or services that expose personal data via WebFinger MUST 1072 - provide an interface by which users can select which data elements 1073 - are exposed through the WebFinger interface. For example, social 1074 - networking sites might allow users to mark certain data as "public" 1075 - and then utilize that marking as a means of determining what 1076 - information to expose via WebFinger. The information published via 1077 - WebFinger would thus comprise only the information marked as public 1078 - by the user. Further, the user has the ability to remove information 1079 - from publication via WebFinger by removing this marking. 1080 - 1081 - WebFinger MUST NOT be used to provide any personal data unless 1082 - publishing that data via WebFinger by the relevant service was 1083 - explicitly authorized by the person whose information is being 1084 - shared. Publishing one's personal data within an access-controlled 1085 - or otherwise limited environment on the Internet does not equate to 1086 - providing implicit authorization of further publication of that data 1087 - via WebFinger. 1088 - 1089 - The privacy and security concerns with publishing personal data via 1090 - WebFinger are worth emphasizing again with respect to personal data 1091 - that might reveal a user's current context (e.g., the user's 1092 - location). The power of WebFinger comes from providing a single 1093 - place where others can find pointers to information about a person, 1094 - but service providers and users should be mindful of the nature of 1095 - that information shared and the fact that it might be available for 1096 - the entire world to see. Sharing location information, for example, 1097 - would potentially put a person in danger from any individual who 1098 - might seek to inflict harm on that person. 1099 - 1100 - Users should be aware of how easily personal data that one might 1101 - publish can be used in unintended ways. In one study relevant to 1102 - WebFinger-like services, Balduzzi et al. [20] took a large set of 1103 - leaked email addresses and demonstrated a number of potential privacy 1104 - concerns, including the ability to cross-correlate the same user's 1105 - accounts over multiple social networks. The authors also describe 1106 - potential mitigation strategies. 1107 - 1108 - The easy access to user information via WebFinger was a design goal 1109 - of the protocol, not a limitation. If one wishes to limit access to 1110 - information available via WebFinger, such as WebFinger resources for 1111 - use inside a corporate network, the network administrator needs to 1112 - take necessary measures to limit access from outside the network. 1113 - Using standard methods for securing web resources, network 1114 - administrators do have the ability to control access to resources 1115 - that might return sensitive information. Further, a server can be 1116 - employed in such a way as to require authentication and prevent 1117 - disclosure of information to unauthorized entities. 1118 - 1119 - 1120 - 1121 - 1122 - Jones, et al. Standards Track [Page 20] 1123 - 1124 - RFC 7033 WebFinger September 2013 1125 - 1126 - 1127 - 9.3. Abuse Potential 1128 - 1129 - Service providers should be mindful of the potential for abuse using 1130 - WebFinger. 1131 - 1132 - As one example, one might query a WebFinger server only to discover 1133 - whether or not a given URI is valid. With such a query, the person 1134 - may deduce that an email identifier is valid, for example. Such an 1135 - approach could help spammers maintain a current list of known email 1136 - addresses and to discover new ones. 1137 - 1138 - WebFinger could be used to associate a name or other personal data 1139 - with an email address, allowing spammers to craft more convincing 1140 - email messages. This might be of particular value in phishing 1141 - attempts. 1142 - 1143 - It is RECOMMENDED that implementers of WebFinger server software take 1144 - steps to mitigate abuse, including malicious over-use of the server 1145 - and harvesting of user information. Although there is no mechanism 1146 - that can guarantee that publicly accessible WebFinger databases won't 1147 - be harvested, rate-limiting by IP address will prevent or at least 1148 - dramatically slow harvest by private individuals without access to 1149 - botnets or other distributed systems. The reason these mitigation 1150 - strategies are not mandatory is that the correct choice of mitigation 1151 - strategy (if any) depends greatly on the context. Implementers 1152 - should not construe this as meaning that they do not need to consider 1153 - whether to use a mitigation strategy, and if so, what strategy to 1154 - use. 1155 - 1156 - WebFinger client developers should also be aware of potential abuse 1157 - by spammers or those phishing for information about users. As an 1158 - example, suppose a mail client was configured to automatically 1159 - perform a WebFinger query on the sender of each received mail 1160 - message. If a spammer sent an email using a unique identifier in the 1161 - 'From' header, then when the WebFinger query was performed, the 1162 - spammer would be able to associate the request with a particular 1163 - user's email address. This would provide information to the spammer, 1164 - including the user's IP address, the fact the user just checked 1165 - email, what kind of WebFinger client the user utilized, and so on. 1166 - For this reason, it is strongly advised that clients not perform 1167 - WebFinger queries unless authorized by the user to do so. 1168 - 1169 - 9.4. Information Reliability 1170 - 1171 - A WebFinger resource has no means of ensuring that information 1172 - provided by a user is accurate. Likewise, neither the resource nor 1173 - the client can be absolutely guaranteed that information has not been 1174 - manipulated either at the server or along the communication path 1175 - 1176 - 1177 - 1178 - Jones, et al. Standards Track [Page 21] 1179 - 1180 - RFC 7033 WebFinger September 2013 1181 - 1182 - 1183 - between the client and server. Use of HTTPS helps to address some 1184 - concerns with manipulation of information along the communication 1185 - path, but it clearly cannot address issues where the resource 1186 - provided incorrect information, either due to being provided false 1187 - information or due to malicious behavior on the part of the server 1188 - administrator. As with any information service available on the 1189 - Internet, users should be wary of information received from untrusted 1190 - sources. 1191 - 1192 - 10. IANA Considerations 1193 - 1194 - 10.1. Well-Known URI 1195 - 1196 - This specification registers the "webfinger" well-known URI in the 1197 - "Well-Known URIs" registry as defined by RFC 5785 [3]. 1198 - 1199 - URI suffix: webfinger 1200 - 1201 - Change controller: IETF 1202 - 1203 - Specification document(s): RFC 7033 1204 - 1205 - Related information: The query to the WebFinger resource will 1206 - include one or more parameters in the query string; see Section 4.1 1207 - of RFC 7033. Resources at this location are able to return a JSON 1208 - Resource Descriptor (JRD) as described in Section 4.4 of RFC 7033. 1209 - 1210 - 10.2. JSON Resource Descriptor (JRD) Media Type 1211 - 1212 - This specification registers the media type application/jrd+json for 1213 - use with WebFinger in accordance with media type registration 1214 - procedures defined in RFC 6838 [10]. 1215 - 1216 - Type name: application 1217 - 1218 - Subtype name: jrd+json 1219 - 1220 - Required parameters: N/A 1221 - 1222 - Optional parameters: N/A 1223 - 1224 - In particular, because RFC 4627 already defines the character 1225 - encoding for JSON, no "charset" parameter is used. 1226 - 1227 - Encoding considerations: See RFC 6839, Section 3.1. 1228 - 1229 - 1230 - 1231 - 1232 - 1233 - 1234 - Jones, et al. Standards Track [Page 22] 1235 - 1236 - RFC 7033 WebFinger September 2013 1237 - 1238 - 1239 - Security considerations: 1240 - 1241 - The JSON Resource Descriptor (JRD) is a JavaScript Object Notation 1242 - (JSON) object. It is a text format that must be parsed by entities 1243 - that wish to utilize the format. Depending on the language and 1244 - mechanism used to parse a JSON object, it is possible for an 1245 - attacker to inject behavior into a running program. Therefore, 1246 - care must be taken to properly parse a received JRD to ensure that 1247 - only a valid JSON object is present and that no JavaScript or other 1248 - code is injected or executed unexpectedly. 1249 - 1250 - Interoperability considerations: 1251 - 1252 - This media type is a JavaScript Object Notation (JSON) object and 1253 - can be consumed by any software application that can consume JSON 1254 - objects. 1255 - 1256 - Published specification: RFC 7033 1257 - 1258 - Applications that use this media type: 1259 - 1260 - The JSON Resource Descriptor (JRD) is used by the WebFinger 1261 - protocol (RFC 7033) to enable the exchange of information between a 1262 - client and a WebFinger resource over HTTPS. 1263 - 1264 - Fragment identifier considerations: 1265 - 1266 - The syntax and semantics of fragment identifiers SHOULD be as 1267 - specified for "application/json". (At publication of this 1268 - document, there is no fragment identification syntax defined for 1269 - "application/json".) 1270 - 1271 - Additional information: 1272 - 1273 - Deprecated alias names for this type: N/A 1274 - 1275 - Magic number(s): N/A 1276 - 1277 - File extension(s): jrd 1278 - 1279 - Macintosh file type code(s): N/A 1280 - 1281 - Person & email address to contact for further information: 1282 - 1283 - Paul E. Jones <paulej@packetizer.com> 1284 - 1285 - Intended usage: COMMON 1286 - 1287 - 1288 - 1289 - 1290 - Jones, et al. Standards Track [Page 23] 1291 - 1292 - RFC 7033 WebFinger September 2013 1293 - 1294 - 1295 - Restrictions on usage: N/A 1296 - 1297 - Author: Paul E. Jones <paulej@packetizer.com> 1298 - 1299 - Change controller: 1300 - 1301 - IESG has change control over this registration. 1302 - 1303 - Provisional registration? (standards tree only): N/A 1304 - 1305 - 10.3. Registering Link Relation Types 1306 - 1307 - RFC 5988 established a "Link Relation Types" registry that is reused 1308 - by WebFinger applications. 1309 - 1310 - Link relation types used by WebFinger applications are registered in 1311 - the "Link Relation Types" registry as per the procedures of Section 1312 - 6.2.1 of RFC 5988. The "Notes" entry for the registration SHOULD 1313 - indicate if property values associated with the link relation type 1314 - are registered in the "WebFinger Properties" registry with a link to 1315 - the registry. 1316 - 1317 - 10.4. Establishment of the "WebFinger Properties" Registry 1318 - 1319 - WebFinger utilizes URIs to identify properties of a subject or link 1320 - and the associated values (see Sections 8.3 and 8.6). This 1321 - specification establishes a new "WebFinger Properties" registry to 1322 - record property identifiers. 1323 - 1324 - 10.4.1. The Registration Template 1325 - 1326 - The registration template for WebFinger properties is: 1327 - 1328 - o Property Identifier: 1329 - 1330 - o Link Type: 1331 - 1332 - o Description: 1333 - 1334 - o Reference: 1335 - 1336 - o Notes: [optional] 1337 - 1338 - The "Property Identifier" must be a URI that identifies the property 1339 - being registered. 1340 - 1341 - 1342 - 1343 - 1344 - 1345 - 1346 - Jones, et al. Standards Track [Page 24] 1347 - 1348 - RFC 7033 WebFinger September 2013 1349 - 1350 - 1351 - The "Link Type" contains the name of a link relation type with which 1352 - this property identifier is used. If the property is a subject- 1353 - specific property, then this field is specified as "N/A". 1354 - 1355 - The "Description" is intended to explain the purpose of the property. 1356 - 1357 - The "Reference" field points to the specification that defines the 1358 - registered property. 1359 - 1360 - The optional "Notes" field is for conveying any useful information 1361 - about the property that might be of value to implementers. 1362 - 1363 - 10.4.2. The Registration Procedures 1364 - 1365 - The IETF has created a mailing list, webfinger@ietf.org, which can be 1366 - used for public discussion of the WebFinger protocol and any 1367 - applications that use it. Prior to registration of a WebFinger 1368 - property, discussion on the mailing list is strongly encouraged. The 1369 - IESG has appointed Designated Experts [13] who will monitor the 1370 - webfinger@ietf.org mailing list and review registrations. 1371 - 1372 - A WebFinger property is registered with a Specification Required (see 1373 - RFC 5226 [13]) after a review by the Designated Experts. The review 1374 - is normally expected to take on the order of two to four weeks. 1375 - However, the Designated Experts may approve a registration prior to 1376 - publication of a specification once the Designated Experts are 1377 - satisfied that such a specification will be published. In evaluating 1378 - registration requests, the Designated Experts should make an effort 1379 - to avoid registering two different properties that have the same 1380 - meaning. Where a proposed property is similar to an already-defined 1381 - property, the Designated Experts should insist that enough text be 1382 - included in the description or notes section of the template to 1383 - sufficiently differentiate the new property from an existing one. 1384 - 1385 - The registration procedure begins with a completed registration 1386 - template (as defined above) sent to webfinger@ietf.org. Once 1387 - consensus is reached on the mailing list, the registration template 1388 - is sent to iana@iana.org. IANA will then contact the Designated 1389 - Experts and communicate the results to the registrant. The WebFinger 1390 - mailing list provides an opportunity for community discussion and 1391 - input, and the Designated Experts may use that input to inform their 1392 - review. Denials should include an explanation and, if applicable, 1393 - suggestions as to how to make the request successful if resubmitted. 1394 - 1395 - 1396 - 1397 - 1398 - 1399 - 1400 - 1401 - 1402 - Jones, et al. Standards Track [Page 25] 1403 - 1404 - RFC 7033 WebFinger September 2013 1405 - 1406 - 1407 - The specification registering the WebFinger property MUST include the 1408 - completed registration template shown above. Once the registration 1409 - procedure concludes successfully, IANA creates or modifies the 1410 - corresponding record in the "WebFinger Properties" registry. 1411 - 1412 - 11. Acknowledgments 1413 - 1414 - This document has benefited from extensive discussion and review by 1415 - many of the members of the APPSAWG working group. The authors would 1416 - like to especially acknowledge the invaluable input of Eran Hammer- 1417 - Lahav, Blaine Cook, Brad Fitzpatrick, Laurent-Walter Goix, Joe 1418 - Clarke, Peter Saint-Andre, Dick Hardt, Tim Bray, James Snell, Melvin 1419 - Carvalho, Evan Prodromou, Mark Nottingham, Elf Pavlik, Bjoern 1420 - Hoehrmann, Subramanian Moonesamy, Joe Gregorio, John Bradley, and 1421 - others that we have undoubtedly, but inadvertently, missed. 1422 - 1423 - The authors would also like to express their gratitude to the chairs 1424 - of the APPSAWG working group, especially Salvatore Loreto for his 1425 - assistance in shepherding this document. We also want to thank Barry 1426 - Leiba and Pete Resnick, the Applications Area Directors, for their 1427 - support and exhaustive reviews. 1428 - 1429 - 12. References 1430 - 1431 - 12.1. Normative References 1432 - 1433 - [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement 1434 - Levels", BCP 14, RFC 2119, March 1997. 1435 - 1436 - [2] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., 1437 - Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol 1438 - -- HTTP/1.1", RFC 2616, June 1999. 1439 - 1440 - [3] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known 1441 - Uniform Resource Identifiers (URIs)", RFC 5785, April 2010. 1442 - 1443 - [4] Nottingham, M., "Web Linking", RFC 5988, October 2010. 1444 - 1445 - [5] Crockford, D., "The application/json Media Type for JavaScript 1446 - Object Notation (JSON)", RFC 4627, July 2006. 1447 - 1448 - [6] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform 1449 - Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, 1450 - January 2005. 1451 - 1452 - [7] Van Kesteren, A., "Cross-Origin Resource Sharing", W3C CORS, 1453 - July 2010, <http://www.w3.org/TR/cors/>. 1454 - 1455 - 1456 - 1457 - 1458 - Jones, et al. Standards Track [Page 26] 1459 - 1460 - RFC 7033 WebFinger September 2013 1461 - 1462 - 1463 - [8] IANA, "Link Relations", 1464 - <http://www.iana.org/assignments/link-relations/>. 1465 - 1466 - [9] IANA, "MIME Media Types", 1467 - <http://www.iana.org/assignments/media-types>. 1468 - 1469 - [10] Freed, N., Klensin, J., and T. Hansen, "Media Type 1470 - Specifications and Registration Procedures", BCP 13, RFC 6838, 1471 - January 2013. 1472 - 1473 - [11] Phillips, A., Ed., and M. Davis, Ed., "Tags for Identifying 1474 - Languages", BCP 47, RFC 5646, September 2009. 1475 - 1476 - [12] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000. 1477 - 1478 - [13] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA 1479 - Considerations Section in RFCs", BCP 26, RFC 5226, May 2008. 1480 - 1481 - 12.2. Informative References 1482 - 1483 - [14] Perreault, S., "vCard Format Specification", RFC 6350, August 1484 - 2011. 1485 - 1486 - [15] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., 1487 - Mortimore, C., and E. Jay, "OpenID Connect Messages 1.0", 1488 - July 2013, 1489 - <http://openid.net/specs/openid-connect-messages-1_0.html>. 1490 - 1491 - [16] Hammer-Lahav, E., Ed., and B. Cook, "Web Host Metadata", RFC 1492 - 6415, October 2011. 1493 - 1494 - [17] Hammer-Lahav, E. and W. Norris, "Extensible Resource Descriptor 1495 - (XRD) Version 1.0", 1496 - <http://docs.oasis-open.org/xri/xrd/v1.0/xrd-1.0.html>. 1497 - 1498 - [18] Saint-Andre, P., "The 'acct' URI Scheme", Work in Progress, 1499 - July 2013. 1500 - 1501 - [19] Duerst, M., Masinter, L., and J. Zawinski, "The 'mailto' URI 1502 - Scheme", RFC 6068, October 2010. 1503 - 1504 - [20] Balduzzi, M., Platzer, C., Thorsten, H., Kirda, E., Balzarotti, 1505 - D., and C. Kruegel "Abusing Social Networks for Automated User 1506 - Profiling", Recent Advances in Intrusion Detection, Springer 1507 - Berlin Heidelberg, March 2010, 1508 - <https://www.eurecom.fr/en/publication/3042/download/ 1509 - rs-publi-3042_1.pdf>. 1510 - 1511 - 1512 - 1513 - 1514 - Jones, et al. Standards Track [Page 27] 1515 - 1516 - RFC 7033 WebFinger September 2013 1517 - 1518 - 1519 - Authors' Addresses 1520 - 1521 - Paul E. Jones 1522 - Cisco Systems, Inc. 1523 - 7025 Kit Creek Rd. 1524 - Research Triangle Park, NC 27709 1525 - USA 1526 - 1527 - Phone: +1 919 476 2048 1528 - EMail: paulej@packetizer.com 1529 - IM: xmpp:paulej@packetizer.com 1530 - 1531 - 1532 - Gonzalo Salgueiro 1533 - Cisco Systems, Inc. 1534 - 7025 Kit Creek Rd. 1535 - Research Triangle Park, NC 27709 1536 - USA 1537 - 1538 - Phone: +1 919 392 3266 1539 - EMail: gsalguei@cisco.com 1540 - IM: xmpp:gsalguei@cisco.com 1541 - 1542 - 1543 - Michael B. Jones 1544 - Microsoft 1545 - 1546 - EMail: mbj@microsoft.com 1547 - URI: http://self-issued.info/ 1548 - 1549 - 1550 - Joseph Smarr 1551 - Google 1552 - 1553 - EMail: jsmarr@google.com 1554 - URI: http://josephsmarr.com/ 1555 - 1556 - 1557 - 1558 - 1559 - 1560 - 1561 - 1562 - 1563 - 1564 - 1565 - 1566 - 1567 - 1568 - 1569 - 1570 - Jones, et al. Standards Track [Page 28] 1571 -
-3
ocaml-webfinger/test/dune
··· 1 - (test 2 - (name test_webfinger) 3 - (libraries webfinger alcotest))
-197
ocaml-webfinger/test/test_webfinger.ml
··· 1 - (*--------------------------------------------------------------------------- 2 - Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 5 - 6 - (** Tests for the WebFinger library. *) 7 - 8 - let test_jrd_roundtrip () = 9 - let jrd = Webfinger.Jrd.make 10 - ~subject:"acct:user@example.com" 11 - ~aliases:["https://example.com/users/user"] 12 - ~properties:[ 13 - ("http://example.com/ns/role", Some "admin"); 14 - ("http://example.com/ns/verified", None); 15 - ] 16 - ~links:[ 17 - Webfinger.Link.make 18 - ~rel:"self" 19 - ~type_:"application/activity+json" 20 - ~href:"https://example.com/users/user" 21 - ~titles:[("en", "User Profile"); ("und", "Profile")] 22 - ~properties:[("http://example.com/ns/verified", Some "true")] 23 - (); 24 - Webfinger.Link.make 25 - ~rel:"http://webfinger.net/rel/profile-page" 26 - ~type_:"text/html" 27 - ~href:"https://example.com/@user" 28 - (); 29 - ] 30 - () 31 - in 32 - let json = Webfinger.Jrd.to_string jrd in 33 - match Webfinger.Jrd.of_string json with 34 - | Error e -> 35 - Alcotest.fail (Webfinger.error_to_string e) 36 - | Ok parsed -> 37 - Alcotest.(check (option string)) "subject" (Webfinger.Jrd.subject jrd) (Webfinger.Jrd.subject parsed); 38 - Alcotest.(check int) "aliases count" (List.length (Webfinger.Jrd.aliases jrd)) (List.length (Webfinger.Jrd.aliases parsed)); 39 - Alcotest.(check int) "links count" (List.length (Webfinger.Jrd.links jrd)) (List.length (Webfinger.Jrd.links parsed)) 40 - 41 - let test_jrd_minimal () = 42 - let json = {|{}|} in 43 - match Webfinger.Jrd.of_string json with 44 - | Error e -> 45 - Alcotest.fail (Webfinger.error_to_string e) 46 - | Ok jrd -> 47 - Alcotest.(check (option string)) "subject" None (Webfinger.Jrd.subject jrd); 48 - Alcotest.(check int) "aliases" 0 (List.length (Webfinger.Jrd.aliases jrd)); 49 - Alcotest.(check int) "properties" 0 (List.length (Webfinger.Jrd.properties jrd)); 50 - Alcotest.(check int) "links" 0 (List.length (Webfinger.Jrd.links jrd)) 51 - 52 - let test_jrd_with_all_fields () = 53 - let json = {|{ 54 - "subject": "acct:user@example.com", 55 - "aliases": ["https://example.com/~user", "https://example.com/users/user"], 56 - "properties": { 57 - "http://example.com/ns/role": "admin", 58 - "http://example.com/ns/nullable": null 59 - }, 60 - "links": [ 61 - { 62 - "rel": "self", 63 - "type": "application/activity+json", 64 - "href": "https://example.com/users/user", 65 - "titles": { 66 - "en": "User's ActivityPub Profile", 67 - "und": "Profile" 68 - }, 69 - "properties": { 70 - "http://example.com/ns/verified": "true" 71 - } 72 - }, 73 - { 74 - "rel": "http://webfinger.net/rel/profile-page", 75 - "type": "text/html", 76 - "href": "https://example.com/@user" 77 - } 78 - ] 79 - }|} in 80 - match Webfinger.Jrd.of_string json with 81 - | Error e -> 82 - Alcotest.fail (Webfinger.error_to_string e) 83 - | Ok jrd -> 84 - Alcotest.(check (option string)) "subject" 85 - (Some "acct:user@example.com") (Webfinger.Jrd.subject jrd); 86 - Alcotest.(check int) "aliases count" 2 (List.length (Webfinger.Jrd.aliases jrd)); 87 - Alcotest.(check int) "properties count" 2 (List.length (Webfinger.Jrd.properties jrd)); 88 - Alcotest.(check int) "links count" 2 (List.length (Webfinger.Jrd.links jrd)); 89 - 90 - (* Check first link *) 91 - let link = List.hd (Webfinger.Jrd.links jrd) in 92 - Alcotest.(check string) "link rel" "self" (Webfinger.Link.rel link); 93 - Alcotest.(check (option string)) "link type" (Some "application/activity+json") (Webfinger.Link.type_ link); 94 - Alcotest.(check (option string)) "link href" (Some "https://example.com/users/user") (Webfinger.Link.href link); 95 - Alcotest.(check int) "link titles" 2 (List.length (Webfinger.Link.titles link)); 96 - Alcotest.(check int) "link properties" 1 (List.length (Webfinger.Link.properties link)) 97 - 98 - let test_host_extraction () = 99 - (* acct: URIs *) 100 - Alcotest.(check (result string Alcotest.reject)) "acct URI" 101 - (Ok "example.com") 102 - (Webfinger.host_of_resource "acct:user@example.com"); 103 - 104 - Alcotest.(check (result string Alcotest.reject)) "acct URI with port" 105 - (Ok "example.com:8080") 106 - (Webfinger.host_of_resource "acct:user@example.com:8080"); 107 - 108 - (* https: URIs *) 109 - Alcotest.(check (result string Alcotest.reject)) "https URI" 110 - (Ok "example.com") 111 - (Webfinger.host_of_resource "https://example.com/users/user"); 112 - 113 - (* Invalid URIs *) 114 - let invalid = Webfinger.host_of_resource "acct:noatsign" in 115 - Alcotest.(check bool) "invalid acct URI" true (Result.is_error invalid) 116 - 117 - let test_webfinger_url () = 118 - let url = Webfinger.webfinger_url ~resource:"acct:user@example.com" "example.com" in 119 - (* Uri library doesn't percent-encode @ and : in query params - both forms are valid *) 120 - Alcotest.(check string) "basic URL" 121 - "https://example.com/.well-known/webfinger?resource=acct:user@example.com" 122 - url; 123 - 124 - let url_with_rels = Webfinger.webfinger_url 125 - ~resource:"acct:user@example.com" 126 - ~rels:["self"; "http://webfinger.net/rel/profile-page"] 127 - "example.com" 128 - in 129 - Alcotest.(check bool) "URL has rel params" 130 - true 131 - (String.length url_with_rels > String.length url) 132 - 133 - let test_find_link () = 134 - let jrd = Webfinger.Jrd.make 135 - ~links:[ 136 - Webfinger.Link.make ~rel:"self" ~href:"https://example.com/1" (); 137 - Webfinger.Link.make ~rel:"alternate" ~href:"https://example.com/2" (); 138 - Webfinger.Link.make ~rel:"self" ~href:"https://example.com/3" (); 139 - ] 140 - () 141 - in 142 - (* find_link returns first match *) 143 - match Webfinger.Jrd.find_link ~rel:"self" jrd with 144 - | None -> Alcotest.fail "Expected to find link" 145 - | Some link -> 146 - Alcotest.(check (option string)) "href" 147 - (Some "https://example.com/1") (Webfinger.Link.href link); 148 - 149 - (* find_links returns all matches *) 150 - let links = Webfinger.Jrd.find_links ~rel:"self" jrd in 151 - Alcotest.(check int) "found all self links" 2 (List.length links); 152 - 153 - (* Non-existent rel *) 154 - Alcotest.(check (option Alcotest.reject)) "no match" 155 - None 156 - (Webfinger.Jrd.find_link ~rel:"nonexistent" jrd) 157 - 158 - let test_link_title () = 159 - let link = Webfinger.Link.make 160 - ~rel:"self" 161 - ~titles:[("en", "English Title"); ("de", "German Title"); ("und", "Default")] 162 - () 163 - in 164 - Alcotest.(check (option string)) "English" 165 - (Some "English Title") 166 - (Webfinger.Link.title ~lang:"en" link); 167 - 168 - Alcotest.(check (option string)) "German" 169 - (Some "German Title") 170 - (Webfinger.Link.title ~lang:"de" link); 171 - 172 - (* Falls back to "und" *) 173 - Alcotest.(check (option string)) "French falls back to und" 174 - (Some "Default") 175 - (Webfinger.Link.title ~lang:"fr" link); 176 - 177 - (* Default is "und" *) 178 - Alcotest.(check (option string)) "default is und" 179 - (Some "Default") 180 - (Webfinger.Link.title link) 181 - 182 - let () = 183 - Alcotest.run "webfinger" [ 184 - "jrd", [ 185 - Alcotest.test_case "roundtrip" `Quick test_jrd_roundtrip; 186 - Alcotest.test_case "minimal" `Quick test_jrd_minimal; 187 - Alcotest.test_case "all fields" `Quick test_jrd_with_all_fields; 188 - ]; 189 - "url", [ 190 - Alcotest.test_case "host extraction" `Quick test_host_extraction; 191 - Alcotest.test_case "webfinger URL" `Quick test_webfinger_url; 192 - ]; 193 - "accessors", [ 194 - Alcotest.test_case "find_link" `Quick test_find_link; 195 - Alcotest.test_case "link_title" `Quick test_link_title; 196 - ]; 197 - ]
-44
ocaml-webfinger/webfinger.opam
··· 1 - # This file is generated by dune, edit dune-project instead 2 - opam-version: "2.0" 3 - synopsis: "RFC 7033 WebFinger protocol implementation for OCaml" 4 - description: """ 5 - A complete implementation of RFC 7033 (WebFinger) for discovering 6 - information about resources identified by URIs. Includes type-safe 7 - JSON Resource Descriptor (JRD) encoding/decoding using jsont, 8 - an Eio-based HTTP client using the requests library, and a 9 - command-line tool for WebFinger lookups.""" 10 - maintainer: ["Anil Madhavapeddy <anil@recoil.org>"] 11 - authors: ["Anil Madhavapeddy"] 12 - license: "ISC" 13 - homepage: "https://tangled.org/@anil.recoil.org/ocaml-webfinger" 14 - bug-reports: "https://tangled.org/@anil.recoil.org/ocaml-webfinger/issues" 15 - depends: [ 16 - "ocaml" {>= "5.2.0"} 17 - "dune" {>= "3.20" & >= "3.0"} 18 - "jsont" {>= "0.1.0"} 19 - "jsont-bytesrw" {>= "0.1.0"} 20 - "eio" {>= "1.0"} 21 - "eio_main" {>= "1.0"} 22 - "requests" {>= "0.1.0"} 23 - "uri" {>= "4.0.0"} 24 - "cmdliner" {>= "1.2.0"} 25 - "logs" {>= "0.7.0"} 26 - "fmt" {>= "0.9.0"} 27 - "odoc" {with-doc} 28 - "alcotest" {with-test} 29 - ] 30 - build: [ 31 - ["dune" "subst"] {dev} 32 - [ 33 - "dune" 34 - "build" 35 - "-p" 36 - name 37 - "-j" 38 - jobs 39 - "@install" 40 - "@runtest" {with-test} 41 - "@doc" {with-doc} 42 - ] 43 - ] 44 - x-maintenance-intent: ["(latest)"]