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
            jrd-record->json
31
            json->jrd-record
32
33
            make-link-record
34
            link-record?
35
            link-record-rel
36
            link-record-type
37
            link-record-href
38
            link-record-titles
39
            link-record-properties
40
            link-record->json
41
            json->link-record
42
43
            webfinger-query
44
            find-actor-object
45
            jrd->string))
46
47
(define-json-mapping <link-record> make-link-record link-record?
48
  json->link-record <=> link-record->json
49
  (rel        link-record-rel) ; string
50
  (type       link-record-type) ; string
51
  (href       link-record-href) ; string
52
  (titles     link-record-titles) ; alist whose keys are languages or "und" and values ar strings
53
  (properties link-record-properties)) ; alist whose keys and values are strings
54
55
(define-json-mapping <jrd-record> make-jrd-record jrd-record?
56
  json->jrd-record <=> jrd-record->json
57
  (subject    jrd-record-subject) ; string
58
  (aliases    jrd-record-aliases "aliases" ; string list
59
              (lambda (val)
60
                (if val (array->list val) '()))
61
              (lambda (val)
62
                (if (null? val) *unspecified* (list->array 1 val))))
63
  (properties jrd-record-properties) ; alist whose keys and values are strings
64
  (links      jrd-record-links "links" ; list of links
65
              (lambda (val)
66
                (if val (map json->link-record (array->list val)) '()))
67
              (lambda (val) (list->array 1 (map (lambda (v) (json-string->scm (link-record->json v))) val)))))
68
69
(define (download-json uri)
70
  (json-string->scm
71
    (call-with-values
72
      (lambda ()
73
        (http-get uri #:headers '((Accept . "application/jrd+json"))))
74
      (lambda (hdr body)
75
        (utf8->string body)))))
76
77
(define* (webfinger-query server resource #:optional rel)
78
  "Queries a webfinger @var{server} for @var{resource}.  This follows the
79
webfinger specification at @url{https://tools.ietf.org/html/rfc7033}.  Returns
80
a @code{jrd-record} object."
81
  (let* ((uri (or (string->uri server) (build-uri 'https #:host server)))
82
         (query (string-append "resource=" resource
83
                               (if rel
84
                                   (apply
85
                                     string-append
86
                                     (map
87
                                       (lambda (rel)
88
                                         (string-append "rel=" rel))
89
                                       rel))
90
                                   "")))
91
         (uri (build-uri
92
                'https
93
                #:host (uri-host uri)
94
                #:path "/.well-known/webfinger"
95
                #:query query)))
96
    (json->jrd-record (download-json uri))))
97
98
(define (find-actor-object user server)
99
  "Find the actor object of @var{user} on @var{server}.  This uses the webfinger
100
protocol to find the user actor object URL, which does not have any default
101
or common location.  This is used in many services that implement the
102
ActivityPub protocol."
103
  (let* ((server (if (string->uri server) (uri-host (string->uri server)) server))
104
         (resource (webfinger-query server (string-append "acct:" user "@"
105
                                                          server)))
106
         (links (jrd-record-links resource)))
107
    (link-record-href
108
      (car (filter
109
             (lambda (link)
110
               (equal? (link-record-type link) "application/activity+json"))
111
             links)))))
112
113
(define jrd->string jrd-record->json)
114