@mblaney/holster 1.0.24 → 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/get.js +14 -4
- package/src/ham.js +59 -20
- package/src/holster.js +95 -75
- package/src/sea.js +103 -68
- package/src/store.js +6 -2
- package/src/user.js +49 -36
- package/src/utils.js +15 -8
- package/src/wire.js +7 -2
package/src/user.js
CHANGED
|
@@ -60,8 +60,9 @@ const User = (opt, wire) => {
|
|
|
60
60
|
const update = {
|
|
61
61
|
auth: JSON.stringify({enc: enc, salt: salt}),
|
|
62
62
|
}
|
|
63
|
-
const
|
|
64
|
-
const
|
|
63
|
+
const timestamp = Date.now()
|
|
64
|
+
const sig = await SEA.signTimestamp(timestamp, user.is)
|
|
65
|
+
const graph = utils.graph(pub, update, sig, data.pub, timestamp)
|
|
65
66
|
wire.put(graph, err => {
|
|
66
67
|
if (err) {
|
|
67
68
|
done(`error putting ${update} on ${pub}: ${err}`)
|
|
@@ -72,36 +73,46 @@ const User = (opt, wire) => {
|
|
|
72
73
|
return
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
migrationData,
|
|
93
|
-
propertySignatures,
|
|
94
|
-
data.pub,
|
|
95
|
-
)
|
|
96
|
-
wire.put(graph, err => {
|
|
97
|
-
if (err) {
|
|
98
|
-
// Log migration error but don't fail authentication
|
|
99
|
-
console.log(
|
|
100
|
-
`warning: failed to migrate signatures on login: ${err}`,
|
|
101
|
-
)
|
|
76
|
+
// Migration: broadcast signed data on login if enabled
|
|
77
|
+
// Can be enabled by setting localStorage.setItem("holster_migrate_signatures", "true")
|
|
78
|
+
const migrationEnabled =
|
|
79
|
+
typeof globalThis.localStorage !== "undefined" &&
|
|
80
|
+
globalThis.localStorage.getItem("holster_migrate_signatures") ===
|
|
81
|
+
"true"
|
|
82
|
+
|
|
83
|
+
if (migrationEnabled) {
|
|
84
|
+
const migrationData = {}
|
|
85
|
+
for (const key of Object.keys(data)) {
|
|
86
|
+
if (
|
|
87
|
+
key !== "_" &&
|
|
88
|
+
key !== userPublicKey &&
|
|
89
|
+
key !== userSignature
|
|
90
|
+
) {
|
|
91
|
+
migrationData[key] = data[key]
|
|
92
|
+
}
|
|
102
93
|
}
|
|
94
|
+
// Sign the timestamp for migration
|
|
95
|
+
const timestamp = Date.now()
|
|
96
|
+
const sig = await SEA.signTimestamp(timestamp, user.is)
|
|
97
|
+
const graph = utils.graph(
|
|
98
|
+
pub,
|
|
99
|
+
migrationData,
|
|
100
|
+
sig,
|
|
101
|
+
data.pub,
|
|
102
|
+
timestamp,
|
|
103
|
+
)
|
|
104
|
+
wire.put(graph, err => {
|
|
105
|
+
if (err) {
|
|
106
|
+
// Log migration error but don't fail authentication
|
|
107
|
+
console.log(
|
|
108
|
+
`warning: failed to migrate signatures on login: ${err}`,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
done(null)
|
|
112
|
+
})
|
|
113
|
+
} else {
|
|
103
114
|
done(null)
|
|
104
|
-
}
|
|
115
|
+
}
|
|
105
116
|
},
|
|
106
117
|
{wait: 5000},
|
|
107
118
|
)
|
|
@@ -187,9 +198,10 @@ const User = (opt, wire) => {
|
|
|
187
198
|
}
|
|
188
199
|
|
|
189
200
|
const pub = "~" + pair.pub
|
|
190
|
-
// Sign
|
|
191
|
-
const
|
|
192
|
-
const
|
|
201
|
+
// Sign the timestamp for new account
|
|
202
|
+
const timestamp = Date.now()
|
|
203
|
+
const sig = await SEA.signTimestamp(timestamp, pair)
|
|
204
|
+
const graph = utils.graph(pub, data, sig, pair.pub, timestamp)
|
|
193
205
|
wire.put(graph, err => {
|
|
194
206
|
creating = false
|
|
195
207
|
if (err) {
|
|
@@ -346,10 +358,11 @@ const User = (opt, wire) => {
|
|
|
346
358
|
}
|
|
347
359
|
|
|
348
360
|
const data = {username: null, pub: null, epub: null, auth: null}
|
|
349
|
-
// Sign
|
|
350
|
-
const
|
|
361
|
+
// Sign the timestamp for account deletion
|
|
362
|
+
const timestamp = Date.now()
|
|
363
|
+
const sig = await SEA.signTimestamp(timestamp, user.is)
|
|
351
364
|
const pub = "~" + user.is.pub
|
|
352
|
-
const graph = utils.graph(pub, data,
|
|
365
|
+
const graph = utils.graph(pub, data, sig, user.is.pub, timestamp)
|
|
353
366
|
wire.put(graph, err => {
|
|
354
367
|
if (err) {
|
|
355
368
|
ack(`error putting null on ${pub}: ${err}`)
|
package/src/utils.js
CHANGED
|
@@ -80,22 +80,29 @@ export const userPublicKey = "_holster_user_public_key"
|
|
|
80
80
|
|
|
81
81
|
// graph converts objects to graph format with updated states,
|
|
82
82
|
// with optional meta data to verify signed data.
|
|
83
|
-
export const graph = (soul, data, sig, pub) => {
|
|
84
|
-
const timestamp = Date.now()
|
|
83
|
+
export const graph = (soul, data, sig, pub, timestamp) => {
|
|
85
84
|
const g = {[soul]: {_: {"#": soul, ">": {}}}}
|
|
86
85
|
|
|
87
86
|
for (const [key, value] of Object.entries(data)) {
|
|
88
87
|
if (key !== "_" && key !== userPublicKey && key !== userSignature) {
|
|
89
88
|
g[soul][key] = value
|
|
90
|
-
g[soul]._[">"][key] = timestamp
|
|
89
|
+
g[soul]._[">"][key] = timestamp || Date.now()
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
|
-
// Store
|
|
94
|
-
// sig
|
|
95
|
-
|
|
92
|
+
// Store signatures in node._["s"]
|
|
93
|
+
// sig can be:
|
|
94
|
+
// - object: per-property signatures (legacy format)
|
|
95
|
+
// - string: timestamp signature (new format)
|
|
96
|
+
if (sig && pub && timestamp) {
|
|
96
97
|
g[soul]._["s"] = {}
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if (typeof sig === "string") {
|
|
99
|
+
// Timestamp signature: store with timestamp as key
|
|
100
|
+
g[soul]._["s"][timestamp] = sig
|
|
101
|
+
} else if (typeof sig === "object") {
|
|
102
|
+
// Per-property signatures: store with property names as keys
|
|
103
|
+
for (const [key, signature] of Object.entries(sig)) {
|
|
104
|
+
g[soul]._["s"][key] = signature
|
|
105
|
+
}
|
|
99
106
|
}
|
|
100
107
|
g[soul][userPublicKey] = pub
|
|
101
108
|
g[soul]._[">"][userPublicKey] = timestamp
|
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) {
|
|
@@ -354,6 +353,9 @@ const Wire = opt => {
|
|
|
354
353
|
const api = send => {
|
|
355
354
|
return {
|
|
356
355
|
get: (lex, cb, _opt) => {
|
|
356
|
+
if (lex && typeof lex["."] === "number") {
|
|
357
|
+
lex = {...lex, ".": String(lex["."])}
|
|
358
|
+
}
|
|
357
359
|
// Mark requested soul as something we want to store
|
|
358
360
|
if (lex && lex["#"]) {
|
|
359
361
|
pendingReferences.add(lex["#"])
|
|
@@ -403,6 +405,9 @@ const Wire = opt => {
|
|
|
403
405
|
}
|
|
404
406
|
},
|
|
405
407
|
on: (lex, cb, _get, _opt) => {
|
|
408
|
+
if (lex && typeof lex["."] === "number") {
|
|
409
|
+
lex = {...lex, ".": String(lex["."])}
|
|
410
|
+
}
|
|
406
411
|
const soul = lex && lex["#"]
|
|
407
412
|
if (!soul || !cb) return
|
|
408
413
|
|