braid-text 0.2.51 → 0.2.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +21 -5
- package/package.json +1 -1
- package/simpleton-client.js +20 -4
- package/test/test.html +50 -3
package/index.js
CHANGED
|
@@ -114,7 +114,7 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
114
114
|
res.setHeader("Current-Version", get_current_version())
|
|
115
115
|
res.setHeader("Version", ascii_ify(x.version.map((x) => JSON.stringify(x)).join(", ")))
|
|
116
116
|
var buffer = Buffer.from(x.body, "utf8")
|
|
117
|
-
res.setHeader("Repr-Digest",
|
|
117
|
+
res.setHeader("Repr-Digest", get_digest(buffer))
|
|
118
118
|
res.setHeader("Content-Length", buffer.length)
|
|
119
119
|
return my_end(200, req.method === "HEAD" ? null : buffer)
|
|
120
120
|
}
|
|
@@ -136,10 +136,8 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
136
136
|
|
|
137
137
|
// this is a sanity/rhobustness check..
|
|
138
138
|
// ..this digest is checked on the client..
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
x["Repr-Digest"] = `sha-256=:${require('crypto').createHash('sha256').update(Buffer.from(resource.val, "utf8")).digest('base64')}:`
|
|
142
|
-
}
|
|
139
|
+
if (x.version && v_eq(x.version, resource.version))
|
|
140
|
+
x["Repr-Digest"] = get_digest(resource.val)
|
|
143
141
|
|
|
144
142
|
res.sendVersion(x)
|
|
145
143
|
},
|
|
@@ -211,6 +209,19 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
211
209
|
|
|
212
210
|
var {change_count} = await braid_text.put(resource, { peer, version: req.version, parents: req.parents, patches, body, merge_type })
|
|
213
211
|
|
|
212
|
+
// if Repr-Digest is set,
|
|
213
|
+
// and the request version is also our new current version,
|
|
214
|
+
// then verify the digest..
|
|
215
|
+
if (req.headers['repr-digest'] &&
|
|
216
|
+
v_eq(req.version, resource.version) &&
|
|
217
|
+
req.headers['repr-digest'] !== get_digest(resource.val)) {
|
|
218
|
+
console.log(`repr-digest mismatch!`)
|
|
219
|
+
|
|
220
|
+
// we return a special 550 error code,
|
|
221
|
+
// which simpleton will pick up on to stop retrying
|
|
222
|
+
return done_my_turn(550, "repr-digest mismatch!")
|
|
223
|
+
}
|
|
224
|
+
|
|
214
225
|
if (req.version) got_event(options.key, req.version[0], change_count)
|
|
215
226
|
|
|
216
227
|
res.setHeader("Version", get_current_version())
|
|
@@ -2098,6 +2109,11 @@ function sorted_set_delete(arr, val) {
|
|
|
2098
2109
|
if (arr[i] === val) arr.splice(i, 1)
|
|
2099
2110
|
}
|
|
2100
2111
|
|
|
2112
|
+
function get_digest(s) {
|
|
2113
|
+
if (typeof s === 'string') s = Buffer.from(s, "utf8")
|
|
2114
|
+
return `sha-256=:${require('crypto').createHash('sha256').update(s).digest('base64')}:`
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2101
2117
|
braid_text.get_resource = get_resource
|
|
2102
2118
|
|
|
2103
2119
|
braid_text.encode_filename = encode_filename
|
package/package.json
CHANGED
package/simpleton-client.js
CHANGED
|
@@ -65,7 +65,7 @@ function simpleton_client(url, {
|
|
|
65
65
|
signal: ac.signal
|
|
66
66
|
}).then(res => {
|
|
67
67
|
if (on_res) on_res(res)
|
|
68
|
-
res.subscribe(update => {
|
|
68
|
+
res.subscribe(async update => {
|
|
69
69
|
// Only accept the update if its parents == our current version
|
|
70
70
|
update.parents.sort()
|
|
71
71
|
if (current_version.length === update.parents.length
|
|
@@ -110,6 +110,14 @@ function simpleton_client(url, {
|
|
|
110
110
|
} else prev_state = apply_patches(prev_state, patches)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// if the server gave us a digest,
|
|
114
|
+
// go ahead and check it against our new state..
|
|
115
|
+
if (update.extra_headers &&
|
|
116
|
+
update.extra_headers["repr-digest"] &&
|
|
117
|
+
update.extra_headers["repr-digest"].startsWith('sha-256=') &&
|
|
118
|
+
update.extra_headers["repr-digest"] !== await get_digest(prev_state))
|
|
119
|
+
throw new Error('repr-digest mismatch')
|
|
120
|
+
|
|
113
121
|
if (on_state) on_state(prev_state)
|
|
114
122
|
}
|
|
115
123
|
}, on_error)
|
|
@@ -166,10 +174,13 @@ function simpleton_client(url, {
|
|
|
166
174
|
outstanding_changes++
|
|
167
175
|
try {
|
|
168
176
|
var r = await braid_fetch(url, {
|
|
169
|
-
headers: {
|
|
170
|
-
|
|
177
|
+
headers: {
|
|
178
|
+
"Merge-Type": "simpleton",
|
|
179
|
+
"Repr-Digest": await get_digest(prev_state),
|
|
180
|
+
...(content_type ? {"Content-Type": content_type} : {})
|
|
181
|
+
},
|
|
171
182
|
method: "PUT",
|
|
172
|
-
retry: () =>
|
|
183
|
+
retry: (res) => res.status !== 550,
|
|
173
184
|
version, parents, patches,
|
|
174
185
|
peer
|
|
175
186
|
})
|
|
@@ -220,4 +231,9 @@ function simpleton_client(url, {
|
|
|
220
231
|
}
|
|
221
232
|
return state
|
|
222
233
|
}
|
|
234
|
+
|
|
235
|
+
async function get_digest(s) {
|
|
236
|
+
var bytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s))
|
|
237
|
+
return `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(bytes)))}:`
|
|
238
|
+
}
|
|
223
239
|
}
|
package/test/test.html
CHANGED
|
@@ -96,6 +96,56 @@ async function runTest(testName, testFunction, expectedResult) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
runTest(
|
|
100
|
+
"test PUT digest (good)",
|
|
101
|
+
async () => {
|
|
102
|
+
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
103
|
+
|
|
104
|
+
async function get_digest(s) {
|
|
105
|
+
var bytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s))
|
|
106
|
+
return `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(bytes)))}:`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let r = await braid_fetch(`/${key}`, {
|
|
110
|
+
method: 'PUT',
|
|
111
|
+
version: ['hi-1'],
|
|
112
|
+
parents: [],
|
|
113
|
+
body: 'xx',
|
|
114
|
+
headers: {
|
|
115
|
+
'Repr-Digest': await get_digest('xx')
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
if (!r.ok) return 'got: ' + r.status
|
|
119
|
+
return 'ok'
|
|
120
|
+
},
|
|
121
|
+
'ok'
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
runTest(
|
|
125
|
+
"test PUT digest (bad)",
|
|
126
|
+
async () => {
|
|
127
|
+
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
128
|
+
|
|
129
|
+
async function get_digest(s) {
|
|
130
|
+
var bytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s))
|
|
131
|
+
return `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(bytes)))}:`
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let r = await braid_fetch(`/${key}`, {
|
|
135
|
+
method: 'PUT',
|
|
136
|
+
version: ['hi-1'],
|
|
137
|
+
parents: [],
|
|
138
|
+
body: 'xx',
|
|
139
|
+
headers: {
|
|
140
|
+
'Repr-Digest': await get_digest('yy')
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
if (!r.ok) return 'got: ' + r.status
|
|
144
|
+
return 'ok'
|
|
145
|
+
},
|
|
146
|
+
'got: 550'
|
|
147
|
+
)
|
|
148
|
+
|
|
99
149
|
runTest(
|
|
100
150
|
"test subscribing and verifying digests [simpleton]",
|
|
101
151
|
async () => {
|
|
@@ -157,9 +207,6 @@ runTest(
|
|
|
157
207
|
var parts = []
|
|
158
208
|
var p = new Promise(async (done, fail) => {
|
|
159
209
|
r2.subscribe(update => {
|
|
160
|
-
|
|
161
|
-
console.log(`update: ${JSON.stringify(update, null, 4)}`)
|
|
162
|
-
|
|
163
210
|
parts.push(update.extra_headers['repr-digest'])
|
|
164
211
|
if (parts.length > 1) done()
|
|
165
212
|
}, fail)
|