001  (ns clj-activitypub.webfinger
002    (:require [clj-http.client :as client]
003              [clj-activitypub.internal.http-util :as http]
004              [clj-activitypub.internal.thread-cache :as thread-cache]))
005  
006  (def remote-uri-path "/.well-known/webfinger")
007  
008  (defn- resource-str [domain username]
009    (str "acct:" username "@" domain))
010  
011  (defn resource-url
012    "Builds a URL pointing to the user's account on the remote server."
013    [domain username & [params]]
014    (let [resource (resource-str domain username)
015          query-str (http/encode-url-params (merge params {:resource resource}))]
016      (str "https://" domain remote-uri-path "?" query-str)))
017  
018  (def ^:private user-id-cache
019    (thread-cache/make))
020  
021  (defn fetch-user-id
022    "Follows the webfinger request to a remote domain, retrieving the ID of the requested
023     account. Typically returns a string in the form of a URL."
024    [domain username]
025    ((:get-v user-id-cache)
026     (str domain "@" username) ;; cache key
027     (fn []
028       (let [response (some-> (resource-url domain username {:rel "self"})
029                              (client/get {:as :json :throw-exceptions false :ignore-unknown-host? true}))]
030         (some->> response :body :links
031                  (some #(when (= (:type %) "application/activity+json") %))
032                  :href)))))