-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
129 lines (112 loc) · 3.1 KB
/
index.js
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
'use strict'
exports.resolve = resolve
exports.hash = hash
const multihashing = require('multihashing')
const base58 = require('bs58')
const jsonpointer = require('jsonpointer')
const path = require('path')
// ATTENTION: the current implementation suffers of
// https://en.wikipedia.org/wiki/Merkle_tree#Second_preimage_attack
function hash (obj) {
if (typeof obj === 'object') {
obj = JSON.stringify(obj)
}
var buf = new Buffer(obj)
return '/' + base58.encode(multihashing(buf, 'sha2-256'))
}
console.log(hash({test: 'hi'}))
/**
* Split an absolute or relative path in two [hash, path]
* E.g. /hashxyz/data/0 to [hashxyz, data/0]
* E.g. ./test to ['', test]
*
* @method resolve
* @param {merklePath} merklePath Merkle path
* @param {Function} get Function that resolve the hash
* @return {Function} callback
*/
function resolve (merklePath, get, callback) {
if (merklePath[0] !== '/') {
merklePath = '/' + merklePath
}
let sep = separe(merklePath)
let hash = sep[0]
let pointer = sep[1]
follow(hash, pointer)
function follow (hash, pointer) {
// if hash is not an hash, then pointer may be ../
get(hash, (err, obj) => {
// hash was not retrieved
if (err) {
callback(err)
return
}
if (!obj) {
return callback()
}
let result = findLeaf(obj, pointer)
let currentNode = result[0]
let nextPointer = result[1]
// found nothing, return
if (!currentNode) {
return callback()
}
// found a link, keep following
let link = currentNode['@link']
if (link) {
let sep = separe(link)
let nextHash = sep[0]
let merklePath = sep[1]
if (merklePath) {
nextPointer = path.join(merklePath, nextPointer)
}
follow(nextHash, nextPointer)
return
}
// found attribute/object return
if (!nextPointer) {
return callback(null, currentNode)
}
})
}
}
/**
* Find the node the pointer points to in the object
* if there is an extra path and the node is a hash, returns it
*
* @method findLeaf
* @param {String} obj The object we need to traverse
* @param {String} pointer The path we need to traverse in the object
* @return {Array} [leaf, remainderPath]
*/
function findLeaf (obj, pointer) {
let initial = pointer
// this can be optimized doing binary search
while (pointer !== '/' && pointer !== '.' && pointer !== '') {
let node = jsonpointer.get(obj, pointer)
if (node) {
return [node, initial.substr(pointer.length)]
}
pointer = path.dirname(pointer)
}
return [obj]
}
/**
* Split an absolute or relative path in two [hash, path]
* E.g. /hashxyz/data/0 to [hashxyz, data/0]
* E.g. ./test to ['', test]
*
* @method separe
* @param {String} path absolute or relative path from which we want to saparate hash from path
* @return {Array} [hash, path]
*/
function separe (path) {
if (path[0] !== '/') {
return ['', path]
}
path = path.slice(1)
let split = path.split('/')
let hash = split.shift()
let pointer = path.substr(hash.length)
return [hash, pointer]
}