guile-fediverse/webfinger/webfinger.scm

webfinger.scm

1
;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu>
2
;;;; 
3
;;;; This library is free software; you can redistribute it and/or
4
;;;; modify it under the terms of the GNU Lesser General Public
5
;;;; License as published by the Free Software Foundation; either
6
;;;; version 3 of the License, or (at your option) any later version.
7
;;;; 
8
;;;; This library is distributed in the hope that it will be useful,
9
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
;;;; Lesser General Public License for more details.
12
;;;; 
13
;;;; You should have received a copy of the GNU Lesser General Public
14
;;;; License along with this library; if not, write to the Free Software
15
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
;;;; 
17
18
(define-module (webfinger webfinger)
19
  #:use-module (json)
20
  #:use-module (rnrs bytevectors)
21
  #:use-module (srfi srfi-9)
22
  #:use-module (web client)
23
  #:use-module (web uri)
24
  #:export (jrd-record?
25
            make-jrd-record
26
            jrd-record-subject
27
            jrd-record-aliases
28
            jrd-record-properties
29
            jrd-record-links
30
31
            make-link-record
32
            link-record?
33
            link-record-rel
34
            link-record-type
35
            link-record-href
36
            link-record-titles
37
            link-record-properties
38
39
            webfinger-query
40
            find-actor-object))
41
42
(define-record-type <jrd-record>
43
  (make-jrd-record subject aliases properties links)
44
  jrd-record?
45
  (subject    jrd-record-subject) ; string
46
  (aliases    jrd-record-aliases) ; string list
47
  (properties jrd-record-properties) ; alist whose keys and values are strings
48
  (links      jrd-record-links)) ; list of links
49
50
(define-record-type <link-record>
51
  (make-link-record rel type href titles properties)
52
  link-record?
53
  (rel        link-record-rel) ; string
54
  (type       link-record-type) ; string
55
  (href       link-record-href) ; string
56
  (titles     link-record-titles) ; alist whose keys are languages or "und" and values ar strings
57
  (properties link-record-properties)) ; alist whose keys and values are strings
58
59
(define (download-json uri)
60
  (json-string->scm
61
    (call-with-values
62
      (lambda ()
63
        (http-get uri #:headers '((Accept . "application/jrd+json"))))
64
      (lambda (hdr body)
65
        (utf8->string body)))))
66
67
(define* (webfinger-query server resource #:optional rel)
68
  "Queries a webfinger @var{server} for @var{resource}.  This follows the
69
webfinger specification at @url{https://tools.ietf.org/html/rfc7033}.  Returns
70
a @code{jrd-record} object."
71
  (let* ((uri (or (string->uri server) (build-uri 'https #:host server)))
72
         (query (string-append "resource=" resource
73
                               (if rel
74
                                   (apply
75
                                     string-append
76
                                     (map
77
                                       (lambda (rel)
78
                                         (string-append "rel=" rel))
79
                                       rel))
80
                                   "")))
81
         (uri (build-uri
82
                'https
83
                #:host (uri-host uri)
84
                #:path "/.well-known/webfinger"
85
                #:query query))
86
         (json (download-json uri)))
87
    (let ((subject (assoc-ref json "subject"))
88
          (aliases (assoc-ref json "aliases"))
89
          (properties (assoc-ref json "properties"))
90
          (links (assoc-ref json "links")))
91
    (make-jrd-record
92
      subject
93
      (if aliases (array->list aliases) '())
94
      (or properties '())
95
      (if links
96
          (map
97
            (lambda (link)
98
              (make-link-record
99
                (assoc-ref link "rel")
100
                (assoc-ref link "type")
101
                (assoc-ref link "href")
102
                (assoc-ref link "titles")
103
                (assoc-ref link "properties")))
104
            (array->list links))
105
          '())))))
106
107
(define (find-actor-object user server)
108
  "Find the actor object of @var{user} on @var{server}.  This uses the webfinger
109
protocol to find the user actor object URL, which does not have any default
110
or common location.  This is used in many services that implement the
111
ActivityPub protocol."
112
  (let* ((server (if (string->uri server) (uri-host (string->uri server)) server))
113
         (resource (webfinger-query server (string-append "acct:" user "@"
114
                                                          server)))
115
         (links (jrd-record-links resource)))
116
    (link-record-href
117
      (car (filter
118
             (lambda (link)
119
               (equal? (link-record-type link) "application/activity+json"))
120
             links)))))
121