@mblaney/holster 1.0.25 → 1.0.26
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/build/holster.js +3 -3
- package/build/holster.js.map +3 -3
- package/package.json +1 -1
- package/src/ham.js +7 -1
- package/src/sea.js +53 -0
- package/src/wire.js +1 -2
package/package.json
CHANGED
package/src/ham.js
CHANGED
|
@@ -95,6 +95,8 @@ Ham.mix = async (change, graph, secure, listen) => {
|
|
|
95
95
|
|
|
96
96
|
const signedTimestamps = new Set()
|
|
97
97
|
const signedProperties = new Set()
|
|
98
|
+
|
|
99
|
+
// Verify timestamp signatures (numeric keys in node._["s"])
|
|
98
100
|
for (const [key, sig] of Object.entries(node._["s"] || {})) {
|
|
99
101
|
const asNumber = Number(key)
|
|
100
102
|
if (!isNaN(asNumber) && asNumber > 0) {
|
|
@@ -103,7 +105,7 @@ Ham.mix = async (change, graph, secure, listen) => {
|
|
|
103
105
|
signedTimestamps.add(asNumber)
|
|
104
106
|
// Add all properties with this timestamp to signed set
|
|
105
107
|
for (const [prop, ts] of Object.entries(node._[">"] || {})) {
|
|
106
|
-
if (ts === asNumber) {
|
|
108
|
+
if (Number(ts) === asNumber) {
|
|
107
109
|
signedProperties.add(prop)
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -111,6 +113,10 @@ Ham.mix = async (change, graph, secure, listen) => {
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
116
|
+
// Verify per-property signatures (backward compatibility)
|
|
117
|
+
const perPropertySignedProps = await SEA.verifyProperties(node, pub)
|
|
118
|
+
perPropertySignedProps.forEach(prop => signedProperties.add(prop))
|
|
119
|
+
|
|
114
120
|
// If no properties verified, skip this update
|
|
115
121
|
if (signedProperties.size === 0) {
|
|
116
122
|
continue
|
package/src/sea.js
CHANGED
|
@@ -238,6 +238,59 @@ const SEA = {
|
|
|
238
238
|
return false
|
|
239
239
|
}
|
|
240
240
|
},
|
|
241
|
+
// Verify individual property signatures stored in node._["s"]
|
|
242
|
+
// Returns array of valid property names
|
|
243
|
+
verifyProperties: async (node, pub, cb) => {
|
|
244
|
+
if (!pub || !node) {
|
|
245
|
+
if (cb) cb([])
|
|
246
|
+
return []
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const key = await utils.subtle.importKey(
|
|
250
|
+
"jwk",
|
|
251
|
+
utils.jwk(pub),
|
|
252
|
+
{name: "ECDSA", namedCurve: "P-256"},
|
|
253
|
+
false,
|
|
254
|
+
["verify"],
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
const alg = {name: "ECDSA", hash: {name: "SHA-256"}}
|
|
258
|
+
const valid = []
|
|
259
|
+
const propertySignatures = (node._ && node._["s"]) || {}
|
|
260
|
+
|
|
261
|
+
// Verify each property individually
|
|
262
|
+
for (const k of Object.keys(node).sort()) {
|
|
263
|
+
if (k === "_" || k == userPublicKey) continue
|
|
264
|
+
|
|
265
|
+
const propSig = propertySignatures[k]
|
|
266
|
+
if (!propSig) {
|
|
267
|
+
console.log(`warning: property '${k}' missing signature`)
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
const hash = await utils.sha256(node[k])
|
|
273
|
+
const sig = new Uint8Array(SafeBuffer.from(propSig, "base64"))
|
|
274
|
+
|
|
275
|
+
const isValid = await utils.subtle.verify(
|
|
276
|
+
alg,
|
|
277
|
+
key,
|
|
278
|
+
sig,
|
|
279
|
+
new Uint8Array(hash),
|
|
280
|
+
)
|
|
281
|
+
if (isValid) {
|
|
282
|
+
valid.push(k)
|
|
283
|
+
} else {
|
|
284
|
+
console.log(`warning: property '${k}' signature verification failed`)
|
|
285
|
+
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
console.log(`warning: property '${k}' error verifying: ${err.message}`)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (cb) cb(valid)
|
|
292
|
+
return valid
|
|
293
|
+
},
|
|
241
294
|
work: async (data, salt, cb) => {
|
|
242
295
|
if (typeof salt === "function") {
|
|
243
296
|
cb = salt
|
package/src/wire.js
CHANGED
|
@@ -302,10 +302,9 @@ const Wire = opt => {
|
|
|
302
302
|
|
|
303
303
|
const ack = Get(lex, graph)
|
|
304
304
|
const track = utils.text.random(9)
|
|
305
|
-
// Request the whole node in secure mode for verification.
|
|
306
305
|
const request = JSON.stringify({
|
|
307
306
|
"#": dup.track(track),
|
|
308
|
-
get:
|
|
307
|
+
get: lex,
|
|
309
308
|
})
|
|
310
309
|
|
|
311
310
|
if (ack) {
|