-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
138 lines (120 loc) · 4.12 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
130
131
132
133
134
135
136
137
138
'use strict';
var pull = require('pull-stream')
var mMessage = require('../microstar-message')
var mChain = require('../microstar-chain')
var mCrypto = require('../microstar-crypto')
var llibrarian = require('../level-librarian')
var _ = require('lodash')
var pl = require('pull-level')
var stringify = require('stable-stringify')
module.exports = {
write: write,
writeOne: llibrarian.makeWriteOne(write),
read: read,
readOne: llibrarian.makeReadOne(read),
sequential: sequential,
copy: mChain.copy,
format: format,
index_defs: mChain.index_defs
}
// settings = {
// crypto: JS,
// keys: JS,
// db: db
// }
// message = {
// content: JSON,
// type: String,
// chain_id: String
// }
// Formats messages and then writes them to db
function write (settings, callback) {
var previous
return pull(
pull.asyncMap(function (message, callback) {
if (!previous) {
// Get previous message from db
llibrarian.readOne(settings, {
k: ['public_key', 'chain_id', 'sequence'],
v: [settings.keys.public_key, message.chain_id],
peek: 'last'
}, function (err, prev) {
if (prev) { prev = prev.value }
format(settings, message, prev, function (err, batch, enveloped_enc) {
previous = enveloped_enc
callback(err, batch)
})
})
} else {
format(settings, message, previous, function (err, batch, enveloped_enc) {
previous = enveloped_enc
callback(err, batch)
})
}
}),
pull.flatten(),
pl.write(settings.db, settings.level_opts, callback)
)
}
function format (settings, message, prev, callback) {
encryptContent(settings, message, prev, function (err, message_enc) {
if (err) { return callback(err) }
mMessage.createEnvelope(settings, message_enc, prev, function (err, enveloped_enc) {
if (err) { return callback(err) }
settings.crypto.hash(stringify(enveloped_enc), function (err, hashed_enc) {
// Fully encrypted document. This is what will be saved.
var doc_enc = { key: hashed_enc, value: enveloped_enc }
doc_enc.type = 'put'
// Document used to generate indexes. Has unencrypted content.
var doc_mixed = { key: hashed_enc, value: _.cloneDeep(enveloped_enc) }
doc_mixed.value.content = message.content
// Make index docs
var batch = Object.keys(settings.index_defs).map(function (key) {
return llibrarian.makeIndexDoc(doc_mixed, settings.index_defs[key])
})
batch.push(doc_enc)
return callback(err, batch, enveloped_enc)
})
})
})
}
function encryptContent (settings, message, prev, callback) {
// Add chain_id and message sequence together to get non-repeating nonce.
mCrypto.hash(message.chain_id + (prev ? prev.sequence + 1 : 0), function (err, hash) {
if (err) { return callback(err) }
// 24 byte nonce from a 32 char string? this is really fishy. fix later
var nonce = hash.substring(0, 32)
mCrypto.secretbox(JSON.stringify(message.content), nonce, settings.keys.secret_key, function (err, cipher) {
message = _.cloneDeep(message)
message.content = cipher
return callback(err, message)
})
})
}
function read (settings, query) {
return pull(
mChain.read(settings, query),
pull.asyncMap(function (message, callback) {
decryptContent(settings, message, callback)
})
)
}
function decryptContent (settings, message, callback) {
mCrypto.hash(message.chain_id + message.sequence, function (err, hash) {
if (err) { return callback(err) }
// 24 byte nonce from a 32 char string? this is really fishy. fix later
var nonce = hash.substring(0, 32)
mCrypto.secretbox.open(message.content, nonce, settings.keys.secret_key, function (err, content) {
message.content = JSON.parse(content)
return callback(err, message)
})
})
}
function sequential (settings, public_key, chain_id, sequence) {
return pull(
mChain.sequential(settings, public_key, chain_id, sequence),
pull.asyncMap(function (message, callback) {
decryptContent(settings, message, callback)
})
)
}