525 lines
33 KiB
HTML
525 lines
33 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<link rel="stylesheet" href="../../coverage.css"/> <title> dog_and_duck/quack/quack.clj </title>
|
|
</head>
|
|
<body>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
001 (ns dog-and-duck.quack.quack
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
002 "Validator for ActivityPub objects: if it walks like a duck, and it quacks
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
003 like a duck...
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
004
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
005 **NOTE THAT the ActivityPub spec
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
006 [says](https://www.w3.org/TR/activitypub/#obj)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
007
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
008 > Servers SHOULD validate the content they receive to avoid content
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
009 > spoofing attacks
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
010
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
011 but in practice ActivityPub content collected in the wild bears only
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
012 a hazy relationship to the spec, so this is difficult. I suspect that
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
013 I may have to implement a `*strict*` dynamic variable, so that users can
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
014 toggle some checks off."
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
015
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
016 (:require [dog-and-duck.quack.picky :refer [activity-faults actor-faults
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
017 link-faults
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
018 persistent-object-faults]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
019 [dog-and-duck.quack.picky.control-variables :refer [*reject-severity*]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
020 [dog-and-duck.quack.picky.objects :refer [object-faults]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
021 [dog-and-duck.quack.picky.utils :refer [filter-severity]])
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
022
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
023 (:import [java.net URI URISyntaxException]))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
024
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
025 ;;; Copyright (C) Simon Brooke, 2022
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
026
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
027 ;;; This program is free software; you can redistribute it and/or
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
028 ;;; modify it under the terms of the GNU General Public License
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
029 ;;; as published by the Free Software Foundation; either version 2
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
030 ;;; of the License, or (at your option) any later version.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
031
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
032 ;;; This program is distributed in the hope that it will be useful,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
033 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
034 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
035 ;;; GNU General Public License for more details.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
036
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
037 ;;; You should have received a copy of the GNU General Public License
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
038 ;;; along with this program; if not, write to the Free Software
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
039 ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
040
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
041 (defn object?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
042 "Returns `true` iff `x` is recognisably an ActivityStreams object.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
043
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
044 **NOTE THAT** The ActivityStreams spec
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
045 [says](https://www.w3.org/TR/activitystreams-core/#object):
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
046
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
047 > All properties are optional (including the id and type)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
048
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
049 But we are *just not having that*, because otherwise we're flying blind.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
050 We *shall* reject objects lacking at least `:type`. Missing `:id` keys are
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
051 tolerable because they represent transient objects, which we expect to
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
052 handle.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
053
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
054 **NOTE THAT** The ActivityPub spec [says](https://www.w3.org/TR/activitypub/#obj)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
055
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
056 > Implementers SHOULD include the ActivityPub context in their object
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
057 > definitions
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
058
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
059 but in samples found in the wild they typically don't."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
060 ([x]
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
061 (object? x *reject-severity*))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
062 ([x severity]
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
063 (empty? (filter-severity (object-faults x) severity))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
064
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
065 (defn persistent-object?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
066 "`true` iff `x` is a persistent object.
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
067
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
068 Transient objects in ActivityPub are not required to have an `id` key, but persistent
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
069 ones must have a key, and it must be an IRI (but normally a URI)."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
070 ([x]
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
071 (persistent-object? x *reject-severity*))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
072 ([x severity]
|
|
</span><br/>
|
|
<span class="partial" title="7 out of 8 forms covered">
|
|
073 (empty? (filter-severity (persistent-object-faults x) severity))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
074
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
075 (defn actor?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
076 "Returns `true` if `x` quacks like an actor, else false."
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
077 ([x] (actor? x *reject-severity*))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
078 ([x severity]
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
079 (empty? (filter-severity (actor-faults x) severity))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
080
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
081 (defn actor-or-uri?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
082 "`true` if `x` is either a URI or an actor.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
083
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
084 **TODO**: I need to decide about whether to reify referenced objects
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
085 before validation or after. After reification, every reference to an actor
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
086 *must be* to an actor object, but before, may only be to a URI pointing to
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
087 one."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
088 [x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 3 forms covered">
|
|
089 (try
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 5 forms covered">
|
|
090 (and
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 9 forms covered">
|
|
091 (cond (string? x) (uri? (URI. x))
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 3 forms covered">
|
|
092 :else (actor? x))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
093 true)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
094 (catch URISyntaxException _ false)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
095 (catch NullPointerException _ false)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
096
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
097 (defn activity?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
098 "`true` iff `x` quacks like an activity, else false."
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 4 forms covered">
|
|
099 ([x] (activity? x *reject-severity*))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
100 ([x severity]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 8 forms covered">
|
|
101 (empty? (filter-severity (activity-faults x) severity))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
102
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
103 (defn link?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
104 "`true` iff `x` quacks like a link, else false."
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 4 forms covered">
|
|
105 ([x] (link? x *reject-severity*))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
106 ([x severity]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 8 forms covered">
|
|
107 (empty? (filter-severity (link-faults x) severity))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
108
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
109 (defn link-or-uri?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
110 "`true` iff `x` is either a URI or a link, else false.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
111
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
112 There are several points in the specification where e.g. the `:image`
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
113 property (if present) may be either a link or a URI."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
114 [x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 5 forms covered">
|
|
115 (and
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 9 forms covered">
|
|
116 (cond (string? x) (uri? (URI. x))
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 3 forms covered">
|
|
117 :else (link? x))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
118 true))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
119
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
120 (defn collection?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
121 "`true` iff `x` quacks like a collection of type `object-type`, else `false`.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
122
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
123 With one argument, will recognise plain collections and ordered collections,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
124 but (currently) not collection pages."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
125 ([x ^String object-type]
|
|
</span><br/>
|
|
<span class="partial" title="10 out of 11 forms covered">
|
|
126 (let [items (or (:items x) (:orderedItems x))]
|
|
</span><br/>
|
|
<span class="partial" title="14 out of 17 forms covered">
|
|
127 (and
|
|
</span><br/>
|
|
<span class="partial" title="5 out of 6 forms covered">
|
|
128 (cond
|
|
</span><br/>
|
|
<span class="partial" title="3 out of 8 forms covered">
|
|
129 (:items x) (nil? (:orderedItems x))
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
130 (:orderedItems x) (nil? (:items x)) ;; can't have both properties
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
131 (integer? (:totalItems x)) true ;; can have neither, provided it has totalItems.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
132 :else false)
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
133 (object? x)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
134 (= (:type x) object-type)
|
|
</span><br/>
|
|
<span class="partial" title="2 out of 3 forms covered">
|
|
135 (if items
|
|
</span><br/>
|
|
<span class="partial" title="10 out of 12 forms covered">
|
|
136 (and (coll? items)
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
137 (every? object? items) ;; if there are items, they must form a
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
138 ;; collection of objects.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
139 true)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
140 true) ;; but it's OK if there aren't.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
141 true)
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
142 ;; test for totalItems not done here, because collection pages don't
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
143 ;; have it.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
144 ))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
145 ([x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 9 forms covered">
|
|
146 (and
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 10 forms covered">
|
|
147 (or (collection? x "Collection")
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 2 forms covered">
|
|
148 (collection? x "OrderedCollection"))
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 5 forms covered">
|
|
149 (integer? (:totalItems x))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
150 true)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
151
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
152 (defn unordered-collection?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
153 "`true` iff `x` quacks like an unordered collection, else `false`."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
154 [x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 18 forms covered">
|
|
155 (and (collection? x "Collection") (integer? (:totalItems x)) true))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
156
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
157 (defn ordered-collection?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
158 "`true` iff `x` quacks like an ordered collection, else `false`."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
159 [x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 18 forms covered">
|
|
160 (and (collection? x "OrderedCollection") (integer? (:totalItems x)) true))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
161
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
162 (defn collection-page?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
163 "`true` iff `x` quacks like a page in a paged collection, else `false`."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
164 [x]
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 4 forms covered">
|
|
165 (collection? x "CollectionPage"))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
166
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
167 (defn ordered-collection-page?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
168 "`true` iff `x` quacks like a page in an ordered paged collection, else `false`."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
169 [x]
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
170 (collection? x "OrderedCollectionPage"))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
171
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
172
|
|
</span><br/>
|
|
</body>
|
|
</html>
|