@mblaney/holster 2.0.2 → 2.1.1

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/ts/src/user.ts CHANGED
@@ -6,37 +6,57 @@
6
6
  import * as utils from "./utils.ts"
7
7
  import Wire from "./wire.ts"
8
8
  import SEA from "./sea.ts"
9
- import type { UserIdentity, HolsterOptions, LexFilter, WireOptions } from "./schemas.ts"
10
- import type { HolsterAPI } from "./holster.ts"
9
+ import type {
10
+ UserIdentity,
11
+ HolsterOptions,
12
+ LexFilter,
13
+ WireOptions,
14
+ } from "./schemas.ts"
15
+ import type {HolsterAPI} from "./holster.ts"
11
16
 
12
17
  type WireInterface = ReturnType<typeof Wire>
13
18
 
14
19
  export interface UserInterface {
15
20
  is?: UserIdentity | null
16
- create: (username: string, password: string, cb?: (err?: string | null) => void) => void
17
- auth: (username: string, password: string, cb?: (err?: string | null) => void) => void
21
+ create: (
22
+ username: string,
23
+ password: string,
24
+ cb?: (err?: string | null) => void,
25
+ ) => void
26
+ auth: (
27
+ username: string,
28
+ password: string,
29
+ cb?: (err?: string | null) => void,
30
+ ) => void
18
31
  change: (
19
32
  username: string,
20
33
  password: string,
21
34
  newPassword: string,
22
- cb?: (err?: string | null) => void
35
+ cb?: (err?: string | null) => void,
23
36
  ) => void
24
37
  store: (localStorage?: boolean) => void
25
38
  recall: () => void
26
39
  leave: () => void
27
- delete: (username: string, password: string, cb?: (err?: string | null) => void) => void
40
+ delete: (
41
+ username: string,
42
+ password: string,
43
+ cb?: (err?: string | null) => void,
44
+ ) => void
28
45
  get?(
29
46
  keys: string | string[],
30
47
  lex?: LexFilter | ((data: unknown) => void),
31
48
  cb?: ((data: unknown) => void) | WireOptions,
32
- _opt?: WireOptions
49
+ _opt?: WireOptions,
33
50
  ): HolsterAPI
34
51
  }
35
52
 
36
53
  /**
37
54
  * Create User management interface
38
55
  */
39
- const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterface => {
56
+ const User = (
57
+ opt: HolsterOptions | undefined,
58
+ wire?: WireInterface,
59
+ ): UserInterface => {
40
60
  if (!wire) wire = Wire(opt as HolsterOptions)
41
61
  let pubs: string[] = []
42
62
  let creating = false
@@ -47,7 +67,7 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
47
67
  username: string,
48
68
  password: string,
49
69
  newPassword: string,
50
- ack: (err?: string | null) => void
70
+ ack: (err?: string | null) => void,
51
71
  ): void => {
52
72
  const retry = (username: string): void => {
53
73
  retries++
@@ -66,57 +86,61 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
66
86
  }
67
87
 
68
88
  const pub = pubs.shift()!
69
- wire.get(
70
- { "#": pub, ".": ["auth", "pub", "epub"] },
71
- async msg => {
72
- if (msg.err) {
73
- done(`error getting ${pub}: ${msg.err}`)
74
- return
75
- }
89
+ wire.get({"#": pub, ".": ["auth", "pub", "epub"]}, async msg => {
90
+ if (msg.err) {
91
+ done(`error getting ${pub}: ${msg.err}`)
92
+ return
93
+ }
76
94
 
77
- const data = msg.put && msg.put[pub]
78
- if (!data || !data.auth) return next()
95
+ const data = msg.put && msg.put[pub]
96
+ if (!data || !data.auth) return next()
79
97
 
80
- const authData = JSON.parse(data.auth as string) as {
81
- enc: { ct: string; iv: string; s: string }
82
- salt: string
83
- }
84
- const work = await SEA.work(password, authData.salt)
85
- const dec = (await SEA.decrypt(authData.enc, work)) as
86
- | { priv: string; epriv: string }
87
- | null
88
- if (!dec) return next()
89
-
90
- user.is = {
91
- username: username,
92
- pub: data.pub as string,
93
- epub: data.epub as string,
94
- priv: dec.priv,
95
- epriv: dec.epriv,
98
+ const authData = JSON.parse(data.auth as string) as {
99
+ enc: {ct: string; iv: string; s: string}
100
+ salt: string
101
+ }
102
+ const work = await SEA.work(password, authData.salt)
103
+ const dec = (await SEA.decrypt(authData.enc, work)) as {
104
+ priv: string
105
+ epriv: string
106
+ } | null
107
+ if (!dec) return next()
108
+
109
+ user.is = {
110
+ username: username,
111
+ pub: data.pub as string,
112
+ epub: data.epub as string,
113
+ priv: dec.priv,
114
+ epriv: dec.epriv,
115
+ }
116
+ if (newPassword !== "") {
117
+ const salt = utils.text.random(64)
118
+ const newWork = await SEA.work(newPassword, salt)
119
+ const enc = await SEA.encrypt(dec, newWork)
120
+ const update = {
121
+ auth: JSON.stringify({enc: enc, salt: salt}),
96
122
  }
97
- if (newPassword !== "") {
98
- const salt = utils.text.random(64)
99
- const newWork = await SEA.work(newPassword, salt)
100
- const enc = await SEA.encrypt(dec, newWork)
101
- const update = {
102
- auth: JSON.stringify({ enc: enc, salt: salt }),
123
+ const timestamp = Date.now()
124
+ const sig = await SEA.signTimestamp(timestamp, user.is)
125
+ const graph = utils.graph(
126
+ pub,
127
+ update,
128
+ sig!,
129
+ data.pub as string,
130
+ timestamp,
131
+ )
132
+ wire.put(graph, err => {
133
+ if (err) {
134
+ done(`error putting ${JSON.stringify(update)} on ${pub}: ${err}`)
135
+ } else {
136
+ done(null)
103
137
  }
104
- const timestamp = Date.now()
105
- const sig = await SEA.signTimestamp(timestamp, user.is)
106
- const graph = utils.graph(pub, update, sig!, data.pub as string, timestamp)
107
- wire.put(graph, err => {
108
- if (err) {
109
- done(`error putting ${JSON.stringify(update)} on ${pub}: ${err}`)
110
- } else {
111
- done(null)
112
- }
113
- })
114
- return
115
- }
138
+ })
139
+ return
140
+ }
116
141
 
117
- done(null)
118
- },
119
- )
142
+ done(null)
143
+ })
120
144
  }
121
145
 
122
146
  if (retries > 9) {
@@ -125,22 +149,19 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
125
149
  }
126
150
 
127
151
  const soul = "~@" + username
128
- wire.get(
129
- { "#": soul },
130
- async msg => {
131
- if (msg.err) {
132
- done(`error getting ${soul}: ${msg.err}`)
133
- return
134
- }
152
+ wire.get({"#": soul}, async msg => {
153
+ if (msg.err) {
154
+ done(`error getting ${soul}: ${msg.err}`)
155
+ return
156
+ }
135
157
 
136
- const data = msg.put && msg.put[soul]
137
- if (!data) return retry(username)
158
+ const data = msg.put && msg.put[soul]
159
+ if (!data) return retry(username)
138
160
 
139
- delete (data as { _?: unknown })._
140
- pubs = Object.keys(data)
141
- next()
142
- },
143
- )
161
+ delete (data as {_?: unknown})._
162
+ pubs = Object.keys(data)
163
+ next()
164
+ })
144
165
  }
145
166
 
146
167
  const user: UserInterface = {
@@ -169,56 +190,53 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
169
190
  creating = true
170
191
 
171
192
  const soul = "~@" + username
172
- wire.get(
173
- { "#": soul },
174
- async msg => {
175
- if (msg.err) {
176
- creating = false
177
- ack(`error getting ${soul}: ${msg.err}`)
178
- return
179
- }
193
+ wire.get({"#": soul}, async msg => {
194
+ if (msg.err) {
195
+ creating = false
196
+ ack(`error getting ${soul}: ${msg.err}`)
197
+ return
198
+ }
180
199
 
181
- if (msg.put && msg.put[soul]) {
182
- creating = false
183
- ack("Username already exists")
184
- return
185
- }
200
+ if (msg.put && msg.put[soul]) {
201
+ creating = false
202
+ ack("Username already exists")
203
+ return
204
+ }
186
205
 
187
- const salt = utils.text.random(64)
188
- const work = await SEA.work(password, salt)
189
- const pair = await SEA.pair()
190
- const priv = { priv: pair.priv, epriv: pair.epriv }
191
- const enc = await SEA.encrypt(priv, work)
192
- const data = {
193
- username: username,
194
- pub: pair.pub,
195
- epub: pair.epub,
196
- auth: JSON.stringify({ enc: enc, salt: salt }),
206
+ const salt = utils.text.random(64)
207
+ const work = await SEA.work(password, salt)
208
+ const pair = await SEA.pair()
209
+ const priv = {priv: pair.priv, epriv: pair.epriv}
210
+ const enc = await SEA.encrypt(priv, work)
211
+ const data = {
212
+ username: username,
213
+ pub: pair.pub,
214
+ epub: pair.epub,
215
+ auth: JSON.stringify({enc: enc, salt: salt}),
216
+ }
217
+
218
+ const pub = "~" + pair.pub
219
+ const timestamp = Date.now()
220
+ const sig = await SEA.signTimestamp(timestamp, pair)
221
+ const graph = utils.graph(pub, data, sig!, pair.pub, timestamp)
222
+ wire.put(graph, err => {
223
+ creating = false
224
+ if (err) {
225
+ ack(`error putting ${JSON.stringify(data)} on ${pub}: ${err}`)
226
+ return
197
227
  }
198
228
 
199
- const pub = "~" + pair.pub
200
- const timestamp = Date.now()
201
- const sig = await SEA.signTimestamp(timestamp, pair)
202
- const graph = utils.graph(pub, data, sig!, pair.pub, timestamp)
203
- wire.put(graph, err => {
204
- creating = false
229
+ const rel = {[pub]: {"#": pub}}
230
+ wire.put(utils.graph(soul, rel as never), err => {
205
231
  if (err) {
206
- ack(`error putting ${JSON.stringify(data)} on ${pub}: ${err}`)
232
+ ack(`error putting ${JSON.stringify(rel)} on ${soul}: ${err}`)
207
233
  return
208
234
  }
209
235
 
210
- const rel = { [pub]: { "#": pub } }
211
- wire.put(utils.graph(soul, rel as never), err => {
212
- if (err) {
213
- ack(`error putting ${JSON.stringify(rel)} on ${soul}: ${err}`)
214
- return
215
- }
216
-
217
- if (cb) cb(null)
218
- })
236
+ if (cb) cb(null)
219
237
  })
220
- },
221
- )
238
+ })
239
+ })
222
240
  },
223
241
  auth: (username, password, cb) => {
224
242
  const ack = (err?: string | null): void => {
@@ -353,11 +371,17 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
353
371
  return
354
372
  }
355
373
 
356
- const data = { username: null, pub: null, epub: null, auth: null }
374
+ const data = {username: null, pub: null, epub: null, auth: null}
357
375
  const timestamp = Date.now()
358
376
  const sig = await SEA.signTimestamp(timestamp, user.is!)
359
377
  const pub = "~" + user.is!.pub
360
- const graph = utils.graph(pub, data as never, sig!, user.is!.pub, timestamp)
378
+ const graph = utils.graph(
379
+ pub,
380
+ data as never,
381
+ sig!,
382
+ user.is!.pub,
383
+ timestamp,
384
+ )
361
385
  wire.put(graph, err => {
362
386
  if (err) {
363
387
  ack(`error putting null on ${pub}: ${err}`)
@@ -374,4 +398,3 @@ const User = (opt: HolsterOptions | undefined, wire?: WireInterface): UserInterf
374
398
  }
375
399
 
376
400
  export default User
377
-
package/ts/src/utils.ts CHANGED
@@ -3,7 +3,14 @@
3
3
  * Provides helpers for type checking, graph manipulation, and pattern matching
4
4
  */
5
5
 
6
- import type { Soul, Relation, Graph, GraphNode, LexFilter, GraphValue } from "./schemas.ts"
6
+ import type {
7
+ Soul,
8
+ Relation,
9
+ Graph,
10
+ GraphNode,
11
+ LexFilter,
12
+ GraphValue,
13
+ } from "./schemas.ts"
7
14
 
8
15
  // ============================================================================
9
16
  // Number Utilities
@@ -50,7 +57,7 @@ export const obj = {
50
57
  map: <T, R>(
51
58
  list: Record<string, T>,
52
59
  cb: (value: T, key: string, o?: Record<string, unknown>) => R | undefined,
53
- o?: Record<string, unknown>
60
+ o?: Record<string, unknown>,
54
61
  ): R | undefined => {
55
62
  const keys = Object.keys(list)
56
63
  for (let i = 0; i < keys.length; i++) {
@@ -64,7 +71,11 @@ export const obj = {
64
71
  /**
65
72
  * Set a property on an object
66
73
  */
67
- put: (o: Record<string, unknown> | undefined, key: string, value: unknown): Record<string, unknown> => {
74
+ put: (
75
+ o: Record<string, unknown> | undefined,
76
+ key: string,
77
+ value: unknown,
78
+ ): Record<string, unknown> => {
68
79
  const target = o || {}
69
80
  target[key] = value
70
81
  return target
@@ -73,7 +84,10 @@ export const obj = {
73
84
  /**
74
85
  * Delete a property from an object
75
86
  */
76
- del: <T>(o: Record<string, T> | undefined, key: string): Record<string, T> | undefined => {
87
+ del: <T>(
88
+ o: Record<string, T> | undefined,
89
+ key: string,
90
+ ): Record<string, T> | undefined => {
77
91
  if (!o) return undefined
78
92
  o[key] = null as T
79
93
  delete o[key]
@@ -85,7 +99,11 @@ export const obj = {
85
99
  // Relation Utilities
86
100
  // ============================================================================
87
101
 
88
- const map_soul = (soul: unknown, key: string, o: { id: string | false }): void => {
102
+ const map_soul = (
103
+ soul: unknown,
104
+ key: string,
105
+ o: {id: string | false},
106
+ ): void => {
89
107
  // If id is already defined AND we're still looping through the object,
90
108
  // then it is considered invalid
91
109
  if (o.id) {
@@ -115,8 +133,16 @@ export const rel = {
115
133
  !("_" in value) &&
116
134
  obj.is(value)
117
135
  ) {
118
- const o: { id: string | false } = { id: "" }
119
- obj.map(value as Record<string, unknown>, map_soul as (value: unknown, key: string, o?: Record<string, unknown>) => void, o)
136
+ const o: {id: string | false} = {id: ""}
137
+ obj.map(
138
+ value as Record<string, unknown>,
139
+ map_soul as (
140
+ value: unknown,
141
+ key: string,
142
+ o?: Record<string, unknown>,
143
+ ) => void,
144
+ o,
145
+ )
120
146
  if (o.id) return o.id
121
147
  }
122
148
  return false
@@ -147,12 +173,12 @@ export const graph = (
147
173
  data: Record<string, GraphValue>,
148
174
  sig?: string,
149
175
  pub?: string,
150
- timestamp?: number
176
+ timestamp?: number,
151
177
  ): Graph => {
152
178
  const ts = timestamp || Date.now()
153
179
  const stateVector: Record<string, number> = {}
154
180
  const node: GraphNode = {
155
- _: { "#": soul, ">": stateVector },
181
+ _: {"#": soul, ">": stateVector},
156
182
  }
157
183
 
158
184
  for (const [key, value] of Object.entries(data)) {
@@ -171,7 +197,7 @@ export const graph = (
171
197
  stateVector[userPublicKey] = timestamp
172
198
  }
173
199
 
174
- return { [soul]: node }
200
+ return {[soul]: node}
175
201
  }
176
202
 
177
203
  // ============================================================================
@@ -229,4 +255,3 @@ export const text = {
229
255
  return s
230
256
  },
231
257
  }
232
-