Files: 741d8d7903a47fb1572e9b2f2b0196a051559834 / util.js
3501 bytesRaw
1 | var ssbKeys = require('ssb-keys') |
2 | var timestamp = require('monotonic-timestamp') |
3 | var isRef = require('ssb-ref') |
4 | var isHash = isRef.isHash |
5 | var isFeedId = isRef.isFeedId |
6 | |
7 | var encode = exports.encode = function (obj) { |
8 | return JSON.stringify(obj, null, 2) |
9 | } |
10 | |
11 | function isString (s) { |
12 | return 'string' === typeof s |
13 | } |
14 | |
15 | function isInteger (n) { |
16 | return ~~n === n |
17 | } |
18 | |
19 | function isObject (o) { |
20 | return o && 'object' === typeof o |
21 | } |
22 | |
23 | function clone (obj) { |
24 | var o = {} |
25 | for(var k in obj) o[k] = obj[k]; |
26 | return o |
27 | } |
28 | |
29 | function isEncrypted (str) { |
30 | return isString(str) && /^[0-9A-Za-z\/+]+={0,2}\.box/.test(str) |
31 | } |
32 | |
33 | exports.BatchQueue = function BatchQueue (db) { |
34 | |
35 | var batch = [], writing = false |
36 | |
37 | function drain () { |
38 | writing = true |
39 | var _batch = batch |
40 | batch = [] |
41 | |
42 | db.batch(_batch, function () { |
43 | writing = false |
44 | write.size = batch.length |
45 | if(batch.length) drain() |
46 | _batch.forEach(function (op) { |
47 | op.cb(null, {key:op.key, value: op.value}) |
48 | }) |
49 | }) |
50 | } |
51 | |
52 | function write (op) { |
53 | batch.push(op) |
54 | write.size = batch.length |
55 | if(!writing) drain() |
56 | } |
57 | |
58 | write.size = 0 |
59 | |
60 | return write |
61 | } |
62 | |
63 | exports.create = function (keys, type, content, prev, prev_key) { |
64 | |
65 | //this noise is to handle things calling this with legacy api. |
66 | if(isString(type) && (Buffer.isBuffer(content) || isString(content))) |
67 | content = {type: type, value: content} |
68 | if(isObject(content)) |
69 | content.type = content.type || type |
70 | //noise end |
71 | |
72 | prev_key = !prev_key && prev ? ('%'+ssbKeys.hash(encode(prev))) : prev_key || null |
73 | |
74 | return ssbKeys.signObj(keys, { |
75 | previous: prev_key, |
76 | author: keys.id, |
77 | sequence: prev ? prev.sequence + 1 : 1, |
78 | timestamp: timestamp(), |
79 | hash: 'sha256', |
80 | content: content, |
81 | }) |
82 | } |
83 | |
84 | var isInvalidContent = exports.isInvalidContent = function (content) { |
85 | if(!isEncrypted(content)) { |
86 | |
87 | type = content.type |
88 | |
89 | if (!(isString(type) && type.length <= 52 && type.length >= 3)) { |
90 | return new Error('type must be a string' + |
91 | '3 <= type.length < 52, was:' + type |
92 | ) |
93 | } |
94 | } |
95 | return false |
96 | } |
97 | |
98 | exports.isInvalidShape = function (msg) { |
99 | if( |
100 | !isObject(msg) || |
101 | !isInteger(msg.sequence) || |
102 | !isFeedId(msg.author) || |
103 | !(isObject(msg.content) || isEncrypted(msg.content)) |
104 | ) |
105 | return new Error('message has invalid properties') |
106 | |
107 | //allow encrypted messages, where content is a base64 string. |
108 | |
109 | var asJson = encode(msg) |
110 | if (asJson.length > 8192) // 8kb |
111 | return new Error( 'encoded message must not be larger than 8192 bytes') |
112 | |
113 | return isInvalidContent(msg.content) |
114 | } |
115 | |
116 | exports.isInvalid = function validateSync (pub, msg, previous) { |
117 | // :TODO: is there a faster way to measure the size of this message? |
118 | |
119 | var key = previous.key |
120 | var prev = previous.value |
121 | |
122 | if(prev) { |
123 | if(msg.previous !== key) |
124 | return new Error( |
125 | 'expected previous: ' |
126 | + key |
127 | + 'but found:' + msg.previous |
128 | ) |
129 | |
130 | if(msg.sequence !== prev.sequence + 1 |
131 | || msg.timestamp <= prev.timestamp) |
132 | return new Error('out of order') |
133 | } |
134 | else { |
135 | if(!(msg.previous == null |
136 | && msg.sequence === 1 && msg.timestamp > 0)) |
137 | return new Error('expected initial message') |
138 | } |
139 | |
140 | if(msg.author !== pub) { |
141 | |
142 | return new Error( |
143 | 'expected different author:' |
144 | + hash(pub.public || pub).toString('base64') |
145 | + 'but found:' + msg.author.toString('base64') |
146 | ) |
147 | } |
148 | |
149 | if(!ssbKeys.verifyObj(pub, msg)) |
150 | return new Error('signature was invalid') |
151 | |
152 | return false |
153 | } |
154 | |
155 |
Built with git-ssb-web