@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/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 propertySignatures = await SEA.signProperties(update, user.is)
64
- const graph = utils.graph(pub, update, propertySignatures, data.pub)
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
- // TODO: Remove this migration once all peers have updated to the new
76
- // version and have received per-property signatures. This temporarily
77
- // broadcasts signed data on every login to ensure new peers can
78
- // persist it.
79
- const migrationData = {}
80
- for (const key of Object.keys(data)) {
81
- if (key !== "_" && key !== userPublicKey && key !== userSignature) {
82
- migrationData[key] = data[key]
83
- }
84
- }
85
- // Sign each property individually
86
- const propertySignatures = await SEA.signProperties(
87
- migrationData,
88
- user.is,
89
- )
90
- const graph = utils.graph(
91
- pub,
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 each property individually for new account
191
- const propertySignatures = await SEA.signProperties(data, pair)
192
- const graph = utils.graph(pub, data, propertySignatures, pair.pub)
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 each property individually for account deletion
350
- const propertySignatures = await SEA.signProperties(data, user.is)
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, propertySignatures, user.is.pub)
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 per-property signatures in node._["s"]
94
- // sig is an object with per-property signatures
95
- if (sig && pub) {
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
- for (const [key, signature] of Object.entries(sig)) {
98
- g[soul]._["s"][key] = signature
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: opt.secure ? {"#": lex["#"]} : lex,
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