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
|
// Free Software under GPL-3.0, see LICENSE
// Copyright 2017 Bryan Newbold
//! This is a hobby/learning implementation of the dat distributed data synchronization system.
//!
//! Subcomponents are roughly organized in library form for easier reading/review, but buyer-beware
//! actually trying to reuse this code for anything other than education or interop testing.
//!
//! ### References
//!
//! [Dat Whitepaper](https://github.com/datproject/docs)
//!
//! Additional notes in the source code for this repo, under the 'notes' directory. Also, see
//! README.
extern crate crypto;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate integer_encoding;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate rand;
extern crate sodiumoxide;
extern crate bit_field;
extern crate resolve;
extern crate data_encoding;
#[cfg(test)]
extern crate tempdir;
#[allow(unused_doc_comment)]
mod errors {
// Create the Error, ErrorKind, ResultExt, and Result types
error_chain! {
foreign_links { Fmt(::std::fmt::Error);
Io(::std::io::Error) #[cfg(unix)];
AddrParseError(::std::net::AddrParseError);
Protobuf(::protobuf::ProtobufError); }
}
}
#[doc(hidden)]
pub use errors::*;
// Organize code internally (files, modules), but pull it all into a flat namespace to export.
mod sleep_file;
pub use sleep_file::*;
mod sleep_register;
pub use sleep_register::*;
mod drive;
pub use drive::*;
mod protocol;
pub use protocol::*;
pub mod network_msgs;
pub mod metadata_msgs;
mod node;
pub use node::*;
mod discovery;
pub use discovery::*;
// Shared functions
use crypto::digest::Digest;
use crypto::blake2b::Blake2b;
/// Helper to calculate a discovery key from a public key. 'key' should be 32 bytes; the returned
/// array will also be 32 bytes long.
///
/// dat discovery keys are calculated as a BLAKE2b "keyed hash" (using the passed key) of the string
/// "hypercore" (with no trailing null byte).
pub fn make_discovery_key(key: &[u8]) -> Vec<u8> {
let mut discovery_key = [0; 32];
let mut hash = Blake2b::new_keyed(32, key);
hash.input(&"hypercore".as_bytes());
hash.result(&mut discovery_key);
discovery_key.to_vec()
}
/// Helper to parse a dat address (aka, public key) in string format.
///
/// Address can start with 'dat://'. It should contain 64 hexadecimal characters.
pub fn parse_dat_address(input: &str) -> Result<Vec<u8>> {
let raw_key = if input.starts_with("dat://") {
&input[6..]
} else {
input
};
if raw_key.len() != 32 * 2 {
bail!("dat key not correct length");
}
let mut key_bytes = vec![];
for i in 0..32 {
let r = u8::from_str_radix(&raw_key[2 * i..2 * i + 2], 16);
match r {
Ok(b) => key_bytes.push(b),
Err(e) => bail!("Problem with hex: {}", e),
};
}
Ok(key_bytes)
}
#[test]
fn test_parse_dat_address() {
assert!(parse_dat_address(
"c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_ok());
assert!(parse_dat_address(
"C7638882870ABD4044D6467B0738F15E3A36F57C3A7F7F3417FD7E4E0841D597").is_ok());
assert!(parse_dat_address(
"dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_ok());
assert!(parse_dat_address(
"c7638882870ab").is_err());
assert!(parse_dat_address(
"g7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_err());
assert!(parse_dat_address(
"dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d5970").is_err());
assert!(parse_dat_address(
"dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d59").is_err());
}
|