Add webfinger protocol

Julien LepillerMon Jan 27 05:33:36+0100 2020

4bf64ed

Add webfinger protocol

Makefile.am

55
66
SOURCES= \
77
  activitystreams/activitystreams.scm \
8-
  activitystreams/ontology.scm
8+
  activitystreams/ontology.scm \
9+
  webfinger/webfinger.scm
910
1011
info_TEXINFOS= doc/guile-fediverse.texi
1112

webfinger/webfinger.scm unknown status 1

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)))))