Files: 17ac021e99559bfa480c415d010a6f35f1eb9c6a / util.js
3638 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.toBuffer = function (b) { |
34 | if('string' == typeof b) return new Buffer(b, 'base64') |
35 | return b |
36 | } |
37 | |
38 | |
39 | exports.BatchQueue = function BatchQueue (db) { |
40 | |
41 | var batch = [], writing = false |
42 | |
43 | function drain () { |
44 | writing = true |
45 | var _batch = batch |
46 | batch = [] |
47 | |
48 | db.batch(_batch, function () { |
49 | writing = false |
50 | write.size = batch.length |
51 | if(batch.length) drain() |
52 | _batch.forEach(function (op) { |
53 | op.cb(null, {key:op.key, value: op.value}) |
54 | }) |
55 | }) |
56 | } |
57 | |
58 | function write (op) { |
59 | batch.push(op) |
60 | write.size = batch.length |
61 | if(!writing) drain() |
62 | } |
63 | |
64 | write.size = 0 |
65 | |
66 | return write |
67 | } |
68 | |
69 | exports.create = function (keys, type, content, prev, prev_key, sign_cap) { |
70 | |
71 | //this noise is to handle things calling this with legacy api. |
72 | if(isString(type) && (Buffer.isBuffer(content) || isString(content))) |
73 | content = {type: type, value: content} |
74 | if(isObject(content)) |
75 | content.type = content.type || type |
76 | //noise end |
77 | |
78 | prev_key = !prev_key && prev ? ('%'+ssbKeys.hash(encode(prev))) : prev_key || null |
79 | |
80 | return ssbKeys.signObj(keys, sign_cap, { |
81 | previous: prev_key, |
82 | author: keys.id, |
83 | sequence: prev ? prev.sequence + 1 : 1, |
84 | timestamp: timestamp(), |
85 | hash: 'sha256', |
86 | content: content, |
87 | }) |
88 | } |
89 | |
90 | var isInvalidContent = exports.isInvalidContent = function (content) { |
91 | if(!isEncrypted(content)) { |
92 | |
93 | type = content.type |
94 | |
95 | if (!(isString(type) && type.length <= 52 && type.length >= 3)) { |
96 | return new Error('type must be a string' + |
97 | '3 <= type.length < 52, was:' + type |
98 | ) |
99 | } |
100 | } |
101 | return false |
102 | } |
103 | |
104 | exports.isInvalidShape = function (msg) { |
105 | if( |
106 | !isObject(msg) || |
107 | !isInteger(msg.sequence) || |
108 | !isFeedId(msg.author) || |
109 | !(isObject(msg.content) || isEncrypted(msg.content)) |
110 | ) |
111 | return new Error('message has invalid properties') |
112 | |
113 | //allow encrypted messages, where content is a base64 string. |
114 | |
115 | var asJson = encode(msg) |
116 | if (asJson.length > 8192) // 8kb |
117 | return new Error( 'encoded message must not be larger than 8192 bytes') |
118 | |
119 | return isInvalidContent(msg.content) |
120 | } |
121 | |
122 | exports.isInvalid = function (pub, msg, previous, sign_cap) { |
123 | // :TODO: is there a faster way to measure the size of this message? |
124 | |
125 | var key = previous.key |
126 | var prev = previous.value |
127 | |
128 | if(prev) { |
129 | if(msg.previous !== key) |
130 | return new Error( |
131 | 'expected previous: ' |
132 | + key |
133 | + 'but found:' + msg.previous |
134 | ) |
135 | |
136 | if(msg.sequence !== prev.sequence + 1 |
137 | || msg.timestamp <= prev.timestamp) |
138 | return new Error('out of order') |
139 | } |
140 | else { |
141 | if(!(msg.previous == null |
142 | && msg.sequence === 1 && msg.timestamp > 0)) |
143 | return new Error('expected initial message') |
144 | } |
145 | |
146 | if(msg.author !== pub) { |
147 | |
148 | return new Error( |
149 | 'expected different author:' |
150 | + hash(pub.public || pub).toString('base64') |
151 | + 'but found:' + msg.author.toString('base64') |
152 | ) |
153 | } |
154 | |
155 | if(!ssbKeys.verifyObj(pub, sign_cap, msg)) |
156 | return new Error('signature was invalid') |
157 | |
158 | return false |
159 | } |
160 | |
161 | |
162 |
Built with git-ssb-web