git ssb

0+

Dominic / ssb-validate



Tree: 8901e7fd06735d6b52b84477d86ed7d34d092b33

Files: 8901e7fd06735d6b52b84477d86ed7d34d092b33 / index.js

4026 bytesRaw
1var ref = require('ssb-ref')
2var ssbKeys = require('ssb-keys')
3
4exports.initial = function () {
5 return {
6 validated: 0,
7 queued: 0,
8 queue: [],
9 feeds: {},
10 error: null
11 }
12}
13
14exports.checkInvalidCheap = function (state, msg) {
15 //the message is just invalid
16 if(!ref.isFeedId(msg.author))
17 return new Error('invalid message: must have author')
18
19 //state is id, sequence, timestamp
20 if(state) {
21 //the message is possibly a fork, but only if the signature is valid.
22 if(msg.sequence != state.sequence + 1)
23 return new Error('invalid message: expected sequence ' + (state.sequence + 1) + ' but got:'+ msg.sequence + 'in state:'+JSON.stringify(state))
24 if(msg.timestamp <= state.ts)
25 return new Error('invalid message: timestamp not increasing')
26 if(msg.previous != state.id)
27 return new Error('invalid message: expected different previous message')
28 //and check type, and length, and some other stuff. finaly check the signature.
29 }
30 else {
31 if(msg.previous !== null)
32 return new Error('initial message must have previous: null')
33 if(msg.sequence !== 1)
34 return new Error('initial message must have sequence: 1')
35 if('number' !== typeof msg.timestamp)
36 return new Error('initial message must have timestamp')
37 }
38}
39
40exports.checkInvalid = function (state, msg) {
41 var err = exports.checkInvalidCheap(state, msg)
42 if(err) return err
43 if(!ssbKeys.verifyObj({public: msg.author.substring(1)}, msg))
44 return new Error('invalid signature')
45 return false //not invalid
46}
47
48/*
49{
50 //an array of messages which have been validated, but not written to the database yet.
51 valid: [],
52 //a map of information needed to know if something should be appeneded to the valid queue.
53 feeds: {
54 <feed>: {id, sequence, ts}
55 },
56 error: null
57}
58*/
59
60exports.queue = function (state, msg) {
61 var err
62 if(state.error = exports.checkInvalidCheap(flatState(state.feeds[msg.author]), msg))
63 return state
64 state.feeds[msg.author] = state.feeds[msg.author] || {
65 id: null, sequence: null, timestamp: null, queue: []
66 }
67 state.queued += 1
68 state.feeds[msg.author].queue.push(msg)
69 return state
70}
71
72function flatState (fstate) {
73 if(!fstate) return null
74 if(fstate.queue.length) {
75 var last = fstate.queue[fstate.queue.length - 1]
76 return {
77 id: exports.id(last),
78 timestamp: last.timestamp,
79 sequence: last.sequence
80 }
81 }
82 else
83 return fstate
84}
85
86exports.append = function (state, msg) {
87 if(state.error = exports.checkInvalid(flatState(state.feeds[msg.author]), msg))
88 return state
89
90 else if(state.feeds[msg.author]) {
91 var a = state.feeds[msg.author]
92 a.id = exports.id(msg)
93 a.sequence = msg.sequence
94 a.timestamp = msg.timestamp
95 var q = state.feeds[msg.author].queue
96 state.validated += q.length
97 state.queued -= q.length
98 while(q.length)
99 state.queue.push(q.shift())
100 }
101 else {
102 state.feeds[msg.author] = {id: exports.id(msg), sequence: msg.sequence, timestamp: msg.timestamp, queue: []}
103 }
104 state.queue.push(msg)
105 state.validated += 1
106 return state
107}
108
109exports.validate = function (state, feed) {
110 if(!state.feeds[feed] || !state.feeds[feed].queue.length) {
111 return state
112 }
113 var msg = state.feeds[feed].queue.pop()
114 state.queued -= 1
115 return exports.append(state, msg)
116}
117
118//pass in your own timestamp, so it's completely deterministic
119exports.create = function (keys, hmac_key, state, content, timestamp) {
120 state = flatState(state)
121 return ssbKeys.signObj(keys, hmac_key, {
122 previous: state ? state.id : null,
123 sequence: state ? state.sequence + 1 : 1,
124 author: keys.id,
125 timestamp: timestamp,
126 hash: 'sha256',
127 content: content,
128 })
129}
130
131exports.id = function (msg) {
132 return '%'+ssbKeys.hash(JSON.stringify(msg, null, 2))
133}
134
135exports.appendNew = function (state, hmac_key, keys, content, timestamp) {
136 var msg = exports.create(keys, hmac_key, state.feeds[keys.id], content, timestamp)
137 state = exports.append(state, msg)
138 return state
139}
140
141
142
143

Built with git-ssb-web