aboutsummaryrefslogtreecommitdiff
path: root/gnu/gnunet/fs-uri.scm
blob: 31056143ec1f3749c1ffcb0b0aec009d05e1b43d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;;   This file is part of scheme-GNUnet, a partial Scheme port of GNUnet.
;;   Copyright (C) 2003--2014 GNUnet e.V.
;;   Copyright (C) 2020 Maxime Devos <maxime.devos@student.kuleuven.be>
;;
;;   GNUnet is free software: you can redistribute it and/or modify it
;;   under the terms of the GNU Affero General Public License as published
;;   by the Free Software Foundation, either version 3 of the License,
;;   or (at your option) any later version.
;;
;;   GNUnet is distributed in the hope that it will be useful, but
;;   WITHOUT ANY WARRANTY; without even the implied warranty of
;;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;   Affero General Public License for more details.
;;
;;   You should have received a copy of the GNU Affero General Public License
;;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;;   SPDX-License-Identifier: AGPL-3.0-or-later
;;
;;   As a special exception to the GNU Affero General Public License,
;;   the file may be relicensed under any license used for
;;   most source code of GNUnet 0.13.1, or later versions, as published by
;;   GNUnet e.V.

;; Upstream file header:
;; @file fs/fs_uri.c
;; @brief Parses and produces uri strings.
;; @author Igor Wronsky, Christian Grothoff
;;
;; GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
;; The specific structure of "IDENTIFIER" depends on the module and
;; maybe differenciated into additional subcategories if applicable.
;; This module only deals with fs identifiers (MODULE = "fs").
;; <p>
;;
;; This module only parses URIs for the AFS module.  The FS URIs fall
;; into four categories, "chk", "sks", "ksk" and "loc".  The first three
;; categories were named in analogy (!) to Freenet, but they do NOT
;; work in exactly the same way.  They are very similar from the user's
;; point of view (unique file identifier, subspace, keyword), but the
;; implementation is rather different in pretty much every detail.
;; The concrete URI formats are:
;;
;; </p>
;;
;; <ul><li>
;;
;; First, there are URIs that identify a file.  They have the format
;; "gnunet://fs/chk/HEX1.HEX2.SIZE".  These URIs can be used to
;; download the file.  The description, filename, mime-type and other
;; meta-data is NOT part of the file-URI since a URI uniquely
;; identifies a resource (and the contents of the file would be the
;; same even if it had a different description).
;;
;; </li><li>
;;
;; The second category identifies entries in a namespace.  The format
;; is "gnunet://fs/sks/NAMESPACE/IDENTIFIER" where the namespace
;; should be given in HEX.  Applications may allow using a nickname
;; for the namespace if the nickname is not ambiguous.  The identifier
;; can be either an ASCII sequence or a HEX-encoding.  If the
;; identifier is in ASCII but the format is ambiguous and could denote
;; a HEX-string a "/" is appended to indicate ASCII encoding.
;;
;; </li> <li>
;;
;; The third category identifies ordinary searches.  The format is
;; "gnunet://fs/ksk/KEYWORD[+KEYWORD]*".  Using the "+" syntax
;; it is possible to encode searches with the boolean "AND" operator.
;; "+" is used since it indicates a commutative 'and' operation and
;; is unlikely to be used in a keyword by itself.
;;
;; </li><li>
;;
;; The last category identifies a datum on a specific machine.  The
;; format is "gnunet://fs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME".  PEER is
;; the BinName of the public key of the peer storing the datum.  The
;; signature (SIG) certifies that this peer has this content.
;; HEX1, HEX2 and SIZE correspond to a 'chk' URI.
;;
;; </li></ul>
;;
;; The encoding for hexadecimal values is defined in the hashing.c
;; module in the gnunetutil library and discussed there.

(library (gnu gnunet fs-uri (1 1))
  (export chk? make-chk chk-key chk-query
          chk-uri? make-chk-uri chk-uri-file-length chk-uri-chk
	  chk-uri-parse)
  (import (rnrs base)
          (rnrs records syntactic)
	  (gnu gnunet hashcode)
	  (gnu gnunet hashcode-ascii)
	  ;; TODO portability
	  (only (guile) make-regexp regexp-exec)
	  (only (ice-9 regex) match:substring)
	  (only (srfi srfi-2) and-let*))

  ;; Size of the individual blocks used for file-sharing.
  ;; TODO: what is the proper place to define this constant
  #;(define DBLOCK_SIZE (* 32 1024))

  ;; Content hash key
  (define-record-type (<content-hash-key> %make-content-hash-key chk?)
    (fields ;; Hash of the original content, used for encryption.
            ;; Of type <hash-code>.
            (immutable key chk-key)
            ;; Hash of the encrypted content, used for querying.
            ;; Of type <hash-code>
            (immutable query chk-query)))

  (define (make-chk key query)
    "Construct a <content-hash-key>"
    (assert (hashcode? key))
    (assert (hashcode? query))
    (%make-content-hash-key key query))

  ;; Information needed to retrieve a file (content-hash-key
  ;; plus file size)
  (define-record-type (<chk-uri> %make-chk-uri chk-uri?)
    (fields ;; Total size of the file referred to in bytes.
            (immutable file-length chk-uri-file-length)
            ;; Query and key of the top GNUNET_EC_IBlock.
            ;; Of type <content-hash-key>.
            (immutable chk chk-uri-chk)))

  ;; TODO: is this limitation on file size
  ;; merely a limit of the implementation?
  (define file-length-limit (expt 2 64))

  (define (make-chk-uri file-length chk)
    "Make a chk-URI"
    (assert (and (exact? file-length)
		 (integer? file-length)))
    (assert (and (<= 0 file-length)
		 (< file-length file-length-limit)))
    (assert (chk? chk))
    (%make-chk-uri file-length chk))

  ;; TODO: location URIs, ksk URIs?
  ;; Why does GNUnet have location URIs?

  (define chk-uri-parse
    (let ((rx
	   (make-regexp
	    "^gnunet://fs/chk/([0-9A-Z]+).([0-9A-Z]+).(0|[1-9][0-9]+)$")))
      (lambda (str)
	"Parse a ‘Content Hash Key’ URI, return @lisp{#f} in case of a syntax
error."
	(and-let* ((match (regexp-exec rx str))
		   (key-match (match:substring match 1))
		   (query-match (match:substring match 2))
		   (size-match (match:substring match 3))
		   (key-hashcode (ascii->hashcode key-match))
		   (query-hashcode (ascii->hashcode query-match))
		   (size (string->number size-match 10))
		   (size-ok (< size file-length-limit)))
	  (%make-chk-uri size
			 (%make-content-hash-key key-hashcode
						 query-hashcode)))))))