statebus 7.0.3 → 7.0.4
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/clients.js +64 -165
- package/extras/tests.js +52 -48
- package/package.json +1 -1
- package/servers.js +225 -166
- package/statebus.js +55 -19
package/servers.js
CHANGED
|
@@ -37,7 +37,7 @@ function set_options (bus, options) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function import_server (bus, options)
|
|
40
|
+
function import_server (bus, make_statebus, options)
|
|
41
41
|
{ var extra_methods = {
|
|
42
42
|
|
|
43
43
|
serve: function serve (options) {
|
|
@@ -76,23 +76,6 @@ function import_server (bus, options)
|
|
|
76
76
|
try { bus.http.use(require('compression')())
|
|
77
77
|
console.log('Enabled http compression!') } catch (e) {}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
// Initialize new clients with an id. We put the client id on
|
|
81
|
-
// req.client, and also in a cookie for the browser to see.
|
|
82
|
-
if (bus.options.client)
|
|
83
|
-
bus.express.use(function (req, res, next) {
|
|
84
|
-
req.client = require('cookie').parse(req.headers.cookie || '').client
|
|
85
|
-
if (!req.client) {
|
|
86
|
-
req.client = (Math.random().toString(36).substring(2)
|
|
87
|
-
+ Math.random().toString(36).substring(2)
|
|
88
|
-
+ Math.random().toString(36).substring(2))
|
|
89
|
-
|
|
90
|
-
res.setHeader('Set-Cookie', 'client=' + req.client
|
|
91
|
-
+ '; Expires=21 Oct 2025 00:0:00 GMT;')
|
|
92
|
-
}
|
|
93
|
-
next()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
79
|
// Initialize file sync
|
|
97
80
|
; (bus.options.sync_files || []).forEach( x => {
|
|
98
81
|
if (require('fs').existsSync(x.fs_path || x.state_path))
|
|
@@ -165,20 +148,34 @@ function import_server (bus, options)
|
|
|
165
148
|
|| req.method === 'OPTIONS')
|
|
166
149
|
free_the_cors(req, res)
|
|
167
150
|
|
|
151
|
+
// Initialize new clients with an id. We put the client id on
|
|
152
|
+
// req.client, and also in a cookie for the browser to see.
|
|
153
|
+
req.peer = //req.headers.peer ||
|
|
154
|
+
require('cookie').parse(req.headers.cookie || '').peer
|
|
155
|
+
if (!req.peer) {
|
|
156
|
+
req.peer = (Math.random().toString(36).substring(2)
|
|
157
|
+
+ Math.random().toString(36).substring(2)
|
|
158
|
+
+ Math.random().toString(36).substring(2))
|
|
159
|
+
|
|
160
|
+
res.setHeader('Set-Cookie', 'peer=' + req.peer
|
|
161
|
+
+ '; Expires=21 Oct 2055 00:0:00 GMT;')
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Handle the GET or PUT request!
|
|
168
165
|
if (req.method === 'GET') {
|
|
169
166
|
|
|
170
167
|
// Make a temporary client bus
|
|
171
168
|
var cbus = bus.bus_for_http_client(req, res)
|
|
172
169
|
var cb
|
|
173
|
-
function
|
|
170
|
+
function end_subscription () {
|
|
174
171
|
cbus.forget(key, cb)
|
|
175
|
-
cbus.delete_bus()
|
|
176
172
|
res.end()
|
|
173
|
+
cbus.http_unsubscribe(req)
|
|
177
174
|
}
|
|
178
175
|
|
|
179
176
|
braidify(req, res)
|
|
180
177
|
if (req.subscribe)
|
|
181
|
-
res.startSubscription({ onClose:
|
|
178
|
+
res.startSubscription({ onClose: end_subscription })
|
|
182
179
|
else
|
|
183
180
|
res.statusCode = 200
|
|
184
181
|
|
|
@@ -188,7 +185,9 @@ function import_server (bus, options)
|
|
|
188
185
|
// Do the get
|
|
189
186
|
// cbus.honk = 'statelog'
|
|
190
187
|
var key = req.path.substr(1)
|
|
188
|
+
// console.log('http_in: doing cbus.get(', key, ')')
|
|
191
189
|
cbus.get(key, cb = (o) => {
|
|
190
|
+
// console.trace('http_in: Sending update of', key)
|
|
192
191
|
var body = to_http_body(o)
|
|
193
192
|
|
|
194
193
|
// If we're braiding, send via subscription
|
|
@@ -200,14 +199,11 @@ function import_server (bus, options)
|
|
|
200
199
|
|
|
201
200
|
// And shut down the connection if there's no subscription
|
|
202
201
|
if (!req.subscribe)
|
|
203
|
-
|
|
202
|
+
end_subscription()
|
|
204
203
|
})
|
|
205
204
|
}
|
|
206
205
|
|
|
207
206
|
else if (req.method === 'PUT') {
|
|
208
|
-
// Make a temporary client bus
|
|
209
|
-
var cbus = bus.bus_for_http_client(req, res)
|
|
210
|
-
|
|
211
207
|
// Maybe the new state is expressed in patches
|
|
212
208
|
if (req.headers.patches) {
|
|
213
209
|
console.error("We don't actually handle PUT patches yet")
|
|
@@ -234,9 +230,14 @@ function import_server (bus, options)
|
|
|
234
230
|
res.end()
|
|
235
231
|
return
|
|
236
232
|
}
|
|
237
|
-
|
|
233
|
+
|
|
234
|
+
// Make a temporary client bus
|
|
235
|
+
var cbus = bus.bus_for_http_client(req, res)
|
|
236
|
+
cbus.set(obj) // And use it
|
|
237
|
+
|
|
238
238
|
res.statusCode = 200
|
|
239
239
|
res.end()
|
|
240
|
+
cbus.http_unsubscribe(req)
|
|
240
241
|
})
|
|
241
242
|
}
|
|
242
243
|
}
|
|
@@ -246,16 +247,39 @@ function import_server (bus, options)
|
|
|
246
247
|
|
|
247
248
|
bus_for_http_client: function (req, res) {
|
|
248
249
|
var bus = this
|
|
249
|
-
if (!bus.bus_for_http_client.counter)
|
|
250
|
+
if (!bus.bus_for_http_client.counter) {
|
|
250
251
|
bus.bus_for_http_client.counter = 0
|
|
251
|
-
|
|
252
|
+
bus.bus_for_http_client.busses = {}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// If this client has a peer ID, and we've got a bus for that peer,
|
|
256
|
+
// then re-use it!
|
|
257
|
+
if (req.peer && bus.bus_for_http_client.busses[req.peer]) {
|
|
258
|
+
var cbus = bus.bus_for_http_client.busses[req.peer]
|
|
259
|
+
cbus.client_ip = req.connection.remoteAddress
|
|
260
|
+
cbus.num_subscriptions++
|
|
261
|
+
return cbus
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Otherwise, create a new bus
|
|
265
|
+
var cbus = make_statebus()
|
|
252
266
|
cbus.label = 'client_http' + bus.bus_for_http_client.counter++
|
|
253
267
|
cbus.master = bus
|
|
268
|
+
cbus.num_subscriptions = 1
|
|
269
|
+
cbus.http_unsubscribe = (req) => {
|
|
270
|
+
cbus.num_subscriptions--
|
|
271
|
+
if (cbus.num_subscriptions === 0) {
|
|
272
|
+
// log('Last subscription! Killing client bus!')
|
|
273
|
+
cbus.delete_bus()
|
|
274
|
+
delete bus.bus_for_http_client.busses[req.peer]
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
bus.bus_for_http_client.busses[req.peer] = cbus
|
|
254
278
|
|
|
255
|
-
//
|
|
279
|
+
// And log into it as the client
|
|
256
280
|
cbus.serves_auth({remoteAddress: req.connection.remoteAddress}, bus)
|
|
257
281
|
bus.options.client(cbus)
|
|
258
|
-
cbus.set({key: 'current_user', client: req.
|
|
282
|
+
cbus.set({key: 'current_user', val: {client: req.peer}})
|
|
259
283
|
return cbus
|
|
260
284
|
},
|
|
261
285
|
|
|
@@ -358,7 +382,7 @@ function import_server (bus, options)
|
|
|
358
382
|
// var client_busses = {} // XXX work in progress
|
|
359
383
|
var log = master.log
|
|
360
384
|
if (client_bus_func) {
|
|
361
|
-
master.set({key: 'connections'}) // Clean out old sessions
|
|
385
|
+
master.set({key: 'connections', val: {}}) // Clean out old sessions
|
|
362
386
|
var connections = master.get('connections')
|
|
363
387
|
}
|
|
364
388
|
var s = require('sockjs').createServer({
|
|
@@ -376,11 +400,11 @@ function import_server (bus, options)
|
|
|
376
400
|
// - When disconnecting, decrement the number, and if it gets
|
|
377
401
|
// to zero, delete the client bus.
|
|
378
402
|
|
|
379
|
-
connections[conn.id] = {client: conn.id, // client is deprecated
|
|
380
|
-
|
|
403
|
+
connections.val[conn.id] = {client: conn.id, // client is deprecated
|
|
404
|
+
id: conn.id}
|
|
381
405
|
master.set(connections)
|
|
382
406
|
|
|
383
|
-
var client =
|
|
407
|
+
var client = make_statebus()
|
|
384
408
|
client.label = 'client' + client_num++
|
|
385
409
|
master.label = master.label || 'master'
|
|
386
410
|
client.master = master
|
|
@@ -489,7 +513,7 @@ function import_server (bus, options)
|
|
|
489
513
|
for (var key in our_gets_in)
|
|
490
514
|
client.forget(key, sockjs_pubber)
|
|
491
515
|
if (client_bus_func) {
|
|
492
|
-
delete connections[conn.id]; master.set(connections)
|
|
516
|
+
delete connections.val[conn.id]; master.set(connections)
|
|
493
517
|
master.delete('connection/' + conn.id)
|
|
494
518
|
client.delete_bus()
|
|
495
519
|
}
|
|
@@ -537,12 +561,12 @@ function import_server (bus, options)
|
|
|
537
561
|
client('connections').to_set = function noop (t) {t.abort()}
|
|
538
562
|
client('connections').to_get = function () {
|
|
539
563
|
var result = []
|
|
540
|
-
var conns = master.get('connections')
|
|
564
|
+
var conns = master.get('connections').val
|
|
541
565
|
for (var connid in conns)
|
|
542
566
|
if (connid !== 'key')
|
|
543
567
|
result.push(client.get('connection/' + connid))
|
|
544
568
|
|
|
545
|
-
return {
|
|
569
|
+
return {val: result}
|
|
546
570
|
}
|
|
547
571
|
}
|
|
548
572
|
})
|
|
@@ -558,13 +582,6 @@ function import_server (bus, options)
|
|
|
558
582
|
WebSocket = require('websocket').w3cwebsocket
|
|
559
583
|
return new WebSocket(url + '/' + bus.options.websocket_path + '/websocket')
|
|
560
584
|
},
|
|
561
|
-
client_creds: function client_creds (server_url) {
|
|
562
|
-
// Right now the server just creates a different random id each time
|
|
563
|
-
// it connects.
|
|
564
|
-
return {clientid: (Math.random().toString(36).substring(2)
|
|
565
|
-
+ Math.random().toString(36).substring(2)
|
|
566
|
-
+ Math.random().toString(36).substring(2))}
|
|
567
|
-
},
|
|
568
585
|
|
|
569
586
|
file_store: (function () {
|
|
570
587
|
// Make a database
|
|
@@ -1310,23 +1327,24 @@ function import_server (bus, options)
|
|
|
1310
1327
|
}
|
|
1311
1328
|
|
|
1312
1329
|
function user_addy (u) {
|
|
1330
|
+
console.error('fix this! not ported to v7 links')
|
|
1313
1331
|
return u.name + '@' + opts.domain
|
|
1314
1332
|
}
|
|
1315
1333
|
function current_addy () {
|
|
1316
1334
|
var c = client.get('current_user')
|
|
1317
|
-
|
|
1335
|
+
console.error('fix this! not ported to v7 links')
|
|
1336
|
+
return c.val.logged_in ? user_addy(c.val.user) : 'public'
|
|
1318
1337
|
}
|
|
1319
1338
|
function is_author (post) {
|
|
1320
1339
|
var from = post._.from
|
|
1321
|
-
var c = client.get('current_user')
|
|
1322
1340
|
return from.includes(current_addy())
|
|
1323
1341
|
}
|
|
1324
1342
|
function can_see (post) {
|
|
1325
|
-
|
|
1343
|
+
console.error('fix this! not ported to v7')
|
|
1326
1344
|
var allowed = post._.to.concat(post._.cc).concat(post._.from)
|
|
1327
1345
|
return allowed.includes(current_addy()) || allowed.includes('public')
|
|
1328
1346
|
}
|
|
1329
|
-
var drtbus = master//
|
|
1347
|
+
var drtbus = master//make_statebus()
|
|
1330
1348
|
function dirty (key) { drtbus.set({key: 'dirty-'+key, n: Math.random()}) }
|
|
1331
1349
|
function watch_for_dirt (key) { drtbus.get('dirty-'+key) }
|
|
1332
1350
|
|
|
@@ -1337,7 +1355,6 @@ function import_server (bus, options)
|
|
|
1337
1355
|
// Define state on client
|
|
1338
1356
|
client('posts*').to_get = (k, rest) => {
|
|
1339
1357
|
var args = bus.parse(rest.substr(1))
|
|
1340
|
-
var c = client.get('current_user')
|
|
1341
1358
|
args.for = current_addy()
|
|
1342
1359
|
var e = master.get('posts_for/' + JSON.stringify(args))
|
|
1343
1360
|
return {_: master.clone(e._).map(x=>client.get(x.key))}
|
|
@@ -1415,7 +1432,7 @@ function import_server (bus, options)
|
|
|
1415
1432
|
}
|
|
1416
1433
|
|
|
1417
1434
|
client('friends').to_get = t => {
|
|
1418
|
-
return {_: (master.get('users').
|
|
1435
|
+
return {_: (master.get('users').val||[])
|
|
1419
1436
|
.map(u=>client.get('email/' + user_addy(u)))
|
|
1420
1437
|
.concat([client.get('email/public')])
|
|
1421
1438
|
}
|
|
@@ -1643,42 +1660,55 @@ function import_server (bus, options)
|
|
|
1643
1660
|
|
|
1644
1661
|
serves_auth: function serves_auth (conn, master) {
|
|
1645
1662
|
var client = this // to keep me straight while programming
|
|
1646
|
-
|
|
1647
|
-
function logout (key) {
|
|
1663
|
+
function logout (user_key) {
|
|
1648
1664
|
var clients = master.get('logged_in_clients')
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1665
|
+
clients.val = clients.val || {}
|
|
1666
|
+
|
|
1667
|
+
for (var k in clients.val) {
|
|
1668
|
+
// We used to encounter stray deleted accounts that hadn't
|
|
1669
|
+
// gotten properly garbage collected, and I added some code
|
|
1670
|
+
// here to remove them.
|
|
1671
|
+
//
|
|
1672
|
+
// However, it was a bit kludgy, and I'm rewriting the code
|
|
1673
|
+
// now, and not sure if this problem still occurs. Will watch
|
|
1674
|
+
// and see. Meanwhile, I'm commenting the code out.
|
|
1675
|
+
//
|
|
1676
|
+
// if (Object.keys(clients.val[k]).length === 0) {
|
|
1677
|
+
// client.log('Found a deleted user. Removing.', k, clients.val[k])
|
|
1678
|
+
// delete clients.val[k]
|
|
1679
|
+
// master.set(clients)
|
|
1680
|
+
// }
|
|
1681
|
+
if (clients.val[k].link === user_key) {
|
|
1682
|
+
client.log('Logging out!', k, clients.val[k])
|
|
1683
|
+
delete clients.val[k]
|
|
1684
|
+
master.set(clients)
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1660
1687
|
}
|
|
1661
1688
|
|
|
1662
1689
|
// Initialize master
|
|
1663
1690
|
if (!master.auth_initialized) {
|
|
1691
|
+
|
|
1692
|
+
// A hash for fast lookup of a user's password
|
|
1664
1693
|
master('users/passwords').to_get = function (k) {
|
|
1694
|
+
// We compute it from the 'users' state
|
|
1665
1695
|
master.log('users/passwords.to_get: Computing!')
|
|
1666
|
-
var result = {key: 'users/passwords'}
|
|
1696
|
+
var result = {key: 'users/passwords', val: {}}
|
|
1667
1697
|
var users = master.get('users')
|
|
1668
|
-
users.
|
|
1669
|
-
for (var i=0; i<users.
|
|
1670
|
-
var u = master.get(users.
|
|
1671
|
-
if (!(u.login || u.name)) {
|
|
1672
|
-
console.error('upass: this user has bogus name/login', u.key, u.name, u.login)
|
|
1698
|
+
users.val = users.val || []
|
|
1699
|
+
for (var i=0; i<users.val.length; i++) {
|
|
1700
|
+
var u = master.get(users.val[i].link)
|
|
1701
|
+
if (!(u.val.login || u.val.name)) {
|
|
1702
|
+
console.error('upass: this user has bogus name/login', u.key, u.val.name, u.val.login)
|
|
1673
1703
|
continue
|
|
1674
1704
|
}
|
|
1675
|
-
var login = (u.login || u.name).toLowerCase()
|
|
1705
|
+
var login = (u.val.login || u.val.name).toLowerCase()
|
|
1676
1706
|
console.assert(login, 'Missing login for user', u)
|
|
1677
|
-
if (result.hasOwnProperty(login)) {
|
|
1707
|
+
if (result.val.hasOwnProperty(login)) {
|
|
1678
1708
|
console.error("upass: this user's name is bogus, dude.", u.key)
|
|
1679
1709
|
continue
|
|
1680
1710
|
}
|
|
1681
|
-
result[login] = {user: u.key, pass: u.pass}
|
|
1711
|
+
result.val[login] = {user: u.key, pass: u.val.pass}
|
|
1682
1712
|
}
|
|
1683
1713
|
return result
|
|
1684
1714
|
}
|
|
@@ -1689,26 +1719,25 @@ function import_server (bus, options)
|
|
|
1689
1719
|
master.log('Deleteinggg!!!', key)
|
|
1690
1720
|
// Remove from users.all
|
|
1691
1721
|
var users = master.get('users')
|
|
1692
|
-
users.
|
|
1722
|
+
users.val = users.val.filter(u => u.link && u.link !== key)
|
|
1693
1723
|
master.set(users)
|
|
1694
1724
|
|
|
1695
1725
|
// Log out
|
|
1696
1726
|
master.log('Logging out', key)
|
|
1697
1727
|
logout(key)
|
|
1698
1728
|
|
|
1699
|
-
// Remove connection
|
|
1700
|
-
master.log('Removing connections for', key)
|
|
1701
|
-
var conns = master.get('connections')
|
|
1702
|
-
for (var k in conns) {
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
}
|
|
1729
|
+
// // Remove connection
|
|
1730
|
+
// master.log('Removing connections for', key)
|
|
1731
|
+
// var conns = master.get('connections')
|
|
1732
|
+
// for (var k in conns.val) {
|
|
1733
|
+
// console.log('Trying key', k)
|
|
1734
|
+
// if (conns.val[k].user && !conns.val[k].user.key) {
|
|
1735
|
+
// console.log('Cleaning keyless user', conss.val[k].user)
|
|
1736
|
+
// delete conns.val[k].user
|
|
1737
|
+
// master.set(conns)
|
|
1738
|
+
// continue
|
|
1739
|
+
// }
|
|
1740
|
+
// }
|
|
1712
1741
|
|
|
1713
1742
|
master.log('Dirtying users/passwords for', key)
|
|
1714
1743
|
master.dirty('users/passwords')
|
|
@@ -1720,9 +1749,9 @@ function import_server (bus, options)
|
|
|
1720
1749
|
|
|
1721
1750
|
// Authentication functions
|
|
1722
1751
|
function authenticate (login, pass) {
|
|
1723
|
-
var userpass = master.get('users/passwords')[login.toLowerCase()]
|
|
1752
|
+
var userpass = master.get('users/passwords').val[login.toLowerCase()]
|
|
1724
1753
|
master.log('authenticate: we see', {
|
|
1725
|
-
passwords: master.get('users/passwords'),
|
|
1754
|
+
passwords: master.get('users/passwords').val,
|
|
1726
1755
|
hash_to_match: userpass && userpass.pass,
|
|
1727
1756
|
password_guess: pass
|
|
1728
1757
|
})
|
|
@@ -1733,7 +1762,7 @@ function import_server (bus, options)
|
|
|
1733
1762
|
|
|
1734
1763
|
// console.log('comparing passwords', pass, userpass.pass)
|
|
1735
1764
|
if (require('bcrypt-nodejs').compareSync(pass, userpass.pass))
|
|
1736
|
-
return
|
|
1765
|
+
return userpass.user
|
|
1737
1766
|
}
|
|
1738
1767
|
function create_account (params) {
|
|
1739
1768
|
if (typeof (params.login || params.name) !== 'string')
|
|
@@ -1746,7 +1775,7 @@ function import_server (bus, options)
|
|
|
1746
1775
|
throw 'invalid name, login, pass, or email'
|
|
1747
1776
|
|
|
1748
1777
|
var passes = master.get('users/passwords')
|
|
1749
|
-
if (passes.hasOwnProperty(login))
|
|
1778
|
+
if (passes.val.hasOwnProperty(login))
|
|
1750
1779
|
throw 'there is already a user with that login or name'
|
|
1751
1780
|
|
|
1752
1781
|
// Hash password
|
|
@@ -1766,60 +1795,81 @@ function import_server (bus, options)
|
|
|
1766
1795
|
key = 'user/' + Math.random().toString(36).substring(7,13)
|
|
1767
1796
|
|
|
1768
1797
|
// Make account object
|
|
1769
|
-
var new_account = {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1798
|
+
var new_account = {
|
|
1799
|
+
key: key, val: {
|
|
1800
|
+
name: params.name,
|
|
1801
|
+
login: params.login,
|
|
1802
|
+
pass: params.pass,
|
|
1803
|
+
email: params.email
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
for (var k in new_account.val) // Clean out falsy fields
|
|
1807
|
+
if (!new_account.val[k])
|
|
1808
|
+
delete new_account.val[k]
|
|
1775
1809
|
master.set(new_account)
|
|
1776
1810
|
|
|
1777
1811
|
var users = master.get('users')
|
|
1778
|
-
users.
|
|
1779
|
-
users.
|
|
1780
|
-
passes[login] = {user: new_account.key, pass: new_account.pass}
|
|
1812
|
+
users.val = users.val || []
|
|
1813
|
+
users.val.push({link: new_account.key})
|
|
1814
|
+
passes.val[login] = {user: new_account.key, pass: new_account.val.pass}
|
|
1781
1815
|
master.set(users)
|
|
1782
1816
|
master.set(passes)
|
|
1783
1817
|
}
|
|
1784
1818
|
|
|
1785
1819
|
// Current User
|
|
1786
1820
|
client('current_user').to_get = function (k) {
|
|
1787
|
-
client
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
u =
|
|
1791
|
-
|
|
1821
|
+
if (!conn.client)
|
|
1822
|
+
return {val: {error: 'no client'}}
|
|
1823
|
+
|
|
1824
|
+
var u = (master.get('logged_in_clients').val || {})[conn.client]
|
|
1825
|
+
var result = {val: {user: u || null, logged_in: !!u}}
|
|
1826
|
+
return result
|
|
1792
1827
|
}
|
|
1793
1828
|
|
|
1794
1829
|
client('current_user').to_set = function (o, t) {
|
|
1830
|
+
var val = o.val
|
|
1831
|
+
if (typeof val !== 'object') {
|
|
1832
|
+
console.error('current_user: set to something not an object:', val)
|
|
1833
|
+
t.abort()
|
|
1834
|
+
return
|
|
1835
|
+
}
|
|
1795
1836
|
function error (msg) {
|
|
1837
|
+
console.error(msg)
|
|
1796
1838
|
client.set.abort(o)
|
|
1797
1839
|
var c = client.get('current_user')
|
|
1798
|
-
c.error = msg
|
|
1840
|
+
c.val.error = msg
|
|
1799
1841
|
client.set.fire(c)
|
|
1800
1842
|
}
|
|
1801
1843
|
|
|
1802
1844
|
client.log('* saving: current_user!')
|
|
1803
|
-
if (
|
|
1845
|
+
if (val.client && !conn.client) {
|
|
1804
1846
|
// Set the client
|
|
1805
|
-
|
|
1806
|
-
|
|
1847
|
+
//
|
|
1848
|
+
// Note: Should this code be moved upstream, when creating a
|
|
1849
|
+
// client bus?
|
|
1850
|
+
conn.client = val.client
|
|
1851
|
+
client.client_id = val.client
|
|
1807
1852
|
client.client_ip = conn.remoteAddress
|
|
1808
1853
|
|
|
1809
|
-
if (conn.id) {
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1854
|
+
// if (conn.id) {
|
|
1855
|
+
// var connections = master.get('connections')
|
|
1856
|
+
// var logged_in_user =
|
|
1857
|
+
// (master.get('logged_in_clients').val || {})[conn.client]
|
|
1858
|
+
|
|
1859
|
+
// if (logged_in_user) {
|
|
1860
|
+
// connections.val[conn.id].user = {link: user.link}
|
|
1861
|
+
// master.set(connections)
|
|
1862
|
+
// }
|
|
1863
|
+
// }
|
|
1814
1864
|
}
|
|
1815
1865
|
else {
|
|
1816
|
-
if (
|
|
1866
|
+
if (val.create_account) {
|
|
1817
1867
|
client.log('current_user: creating account')
|
|
1818
1868
|
try {
|
|
1819
|
-
create_account(
|
|
1869
|
+
create_account(val.create_account)
|
|
1820
1870
|
client.log('Success creating account!')
|
|
1821
1871
|
var cu = client.get('current_user')
|
|
1822
|
-
cu.create_account = null
|
|
1872
|
+
cu.val.create_account = null
|
|
1823
1873
|
client.set.fire(cu)
|
|
1824
1874
|
} catch (e) {
|
|
1825
1875
|
error('Cannot create that account because ' + e)
|
|
@@ -1827,29 +1877,29 @@ function import_server (bus, options)
|
|
|
1827
1877
|
}
|
|
1828
1878
|
}
|
|
1829
1879
|
|
|
1830
|
-
if (
|
|
1880
|
+
if (val.login_as) {
|
|
1831
1881
|
// Then client is trying to log in
|
|
1832
|
-
|
|
1833
|
-
var creds = o.login_as
|
|
1882
|
+
var creds = val.login_as
|
|
1834
1883
|
var login = creds.login || creds.name
|
|
1835
1884
|
if (login && creds.pass) {
|
|
1836
1885
|
// With a username and password
|
|
1837
|
-
var
|
|
1886
|
+
var user_key = authenticate(login, creds.pass)
|
|
1838
1887
|
|
|
1839
|
-
client.log('auth said:',
|
|
1840
|
-
if (
|
|
1888
|
+
client.log('auth said:', user_key)
|
|
1889
|
+
if (user_key) {
|
|
1841
1890
|
// Success!
|
|
1842
1891
|
// Associate this user with this session
|
|
1843
1892
|
// user.log('Logging the user in!', u)
|
|
1844
1893
|
|
|
1845
1894
|
var clients = master.get('logged_in_clients')
|
|
1846
|
-
var connections = master.get('connections')
|
|
1895
|
+
// var connections = master.get('connections')
|
|
1847
1896
|
|
|
1848
|
-
clients
|
|
1849
|
-
|
|
1897
|
+
clients.val = clients.val || {}
|
|
1898
|
+
clients.val[conn.client] = {link: user_key}
|
|
1899
|
+
// connections.val[conn.id].user = {link: user_key}
|
|
1850
1900
|
|
|
1851
1901
|
master.set(clients)
|
|
1852
|
-
master.set(connections)
|
|
1902
|
+
// master.set(connections)
|
|
1853
1903
|
|
|
1854
1904
|
client.log('current_user: success logging in!')
|
|
1855
1905
|
}
|
|
@@ -1864,16 +1914,17 @@ function import_server (bus, options)
|
|
|
1864
1914
|
}
|
|
1865
1915
|
}
|
|
1866
1916
|
|
|
1867
|
-
else if (
|
|
1917
|
+
else if (val.logout) {
|
|
1868
1918
|
client.log('current_user: logging out')
|
|
1869
1919
|
var clients = master.get('logged_in_clients')
|
|
1870
|
-
var connections = master.get('connections')
|
|
1920
|
+
// var connections = master.get('connections')
|
|
1871
1921
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1922
|
+
clients.val = clients.val || {}
|
|
1923
|
+
delete clients.val[conn.client]
|
|
1924
|
+
// connections.val[conn.id].user = null
|
|
1874
1925
|
|
|
1875
1926
|
master.set(clients)
|
|
1876
|
-
master.set(connections)
|
|
1927
|
+
// master.set(connections)
|
|
1877
1928
|
}
|
|
1878
1929
|
}
|
|
1879
1930
|
|
|
@@ -1891,11 +1942,13 @@ function import_server (bus, options)
|
|
|
1891
1942
|
var user_key = o.key.match(/^user\/([^\/]+)/)
|
|
1892
1943
|
user_key = user_key && ('user/' + user_key[1])
|
|
1893
1944
|
|
|
1894
|
-
// Only the current user can touch
|
|
1895
|
-
if (!c.logged_in || c.user.
|
|
1896
|
-
client.log('Only the current user can touch
|
|
1897
|
-
|
|
1898
|
-
|
|
1945
|
+
// Only the current user can touch himself.
|
|
1946
|
+
if (!c.val.logged_in || c.val.user.link !== user_key) {
|
|
1947
|
+
client.log('Only the current user can touch himself.', {
|
|
1948
|
+
logged_in: c.val.logged_in,
|
|
1949
|
+
as: c.val.user && c.val.user.link,
|
|
1950
|
+
touching: user_key
|
|
1951
|
+
})
|
|
1899
1952
|
client.set.abort(o)
|
|
1900
1953
|
return
|
|
1901
1954
|
}
|
|
@@ -1911,9 +1964,14 @@ function import_server (bus, options)
|
|
|
1911
1964
|
console.assert(o.key.match(/^user\/[^\/]+$/))
|
|
1912
1965
|
|
|
1913
1966
|
// Validate types
|
|
1914
|
-
if (!client.validate(o, {key: 'string',
|
|
1915
|
-
|
|
1916
|
-
|
|
1967
|
+
if (!client.validate(o, {key: 'string',
|
|
1968
|
+
val: {
|
|
1969
|
+
'?login': 'string',
|
|
1970
|
+
'?name': 'string',
|
|
1971
|
+
'?pass': 'string',
|
|
1972
|
+
'?email': 'string',
|
|
1973
|
+
/*'?pic': 'string',*/
|
|
1974
|
+
'*':'*'}})) {
|
|
1917
1975
|
client.log('This user change fails validation.')
|
|
1918
1976
|
client.set.abort(o)
|
|
1919
1977
|
return
|
|
@@ -1924,7 +1982,7 @@ function import_server (bus, options)
|
|
|
1924
1982
|
// • That resulting login must be unique across all users
|
|
1925
1983
|
|
|
1926
1984
|
// There must be at least a login or a name
|
|
1927
|
-
var login = o.login || o.name
|
|
1985
|
+
var login = o.val.login || o.val.name
|
|
1928
1986
|
if (!login) {
|
|
1929
1987
|
client.log('User must have a login or a name')
|
|
1930
1988
|
client.set.abort(o)
|
|
@@ -1935,26 +1993,26 @@ function import_server (bus, options)
|
|
|
1935
1993
|
var userpass = master.get('users/passwords')
|
|
1936
1994
|
|
|
1937
1995
|
// Validate that the login/name is not changed to something clobberish
|
|
1938
|
-
var old_login = u.login || u.name
|
|
1996
|
+
var old_login = u.val.login || u.val.name
|
|
1939
1997
|
if (old_login.toLowerCase() !== login.toLowerCase()
|
|
1940
1998
|
&& userpass.hasOwnProperty(login)) {
|
|
1941
1999
|
client.log('The login', login, 'is already taken. Aborting.')
|
|
1942
2000
|
client.set.abort(o) // Abort
|
|
1943
2001
|
|
|
1944
2002
|
o = client.get(o.key) // Add error message
|
|
1945
|
-
o.error = 'The login "' + login + '" is already taken'
|
|
2003
|
+
o.val.error = 'The login "' + login + '" is already taken'
|
|
1946
2004
|
client.set.fire(o)
|
|
1947
2005
|
|
|
1948
2006
|
return // And exit
|
|
1949
2007
|
}
|
|
1950
2008
|
|
|
1951
2009
|
// Now we can update login and name
|
|
1952
|
-
u.login = o.login
|
|
1953
|
-
u.name = o.name
|
|
2010
|
+
u.val.login = o.val.login
|
|
2011
|
+
u.val.name = o.val.name
|
|
1954
2012
|
|
|
1955
2013
|
// Hash password
|
|
1956
|
-
o.pass = o.pass && require('bcrypt-nodejs').hashSync(o.pass)
|
|
1957
|
-
u.pass = o.pass || u.pass
|
|
2014
|
+
o.val.pass = o.val.pass && require('bcrypt-nodejs').hashSync(o.val.pass)
|
|
2015
|
+
u.val.pass = o.val.pass || u.val.pass
|
|
1958
2016
|
|
|
1959
2017
|
// // Users can have pictures (remove this soon)
|
|
1960
2018
|
// // Bug: if user changes name, this picture's url doesn't change.
|
|
@@ -1973,24 +2031,24 @@ function import_server (bus, options)
|
|
|
1973
2031
|
|
|
1974
2032
|
// For anything else, go ahead and add it to the user object
|
|
1975
2033
|
var protected = {key:1, name:1, /*pic:1,*/ pass:1}
|
|
1976
|
-
for (var k in o)
|
|
2034
|
+
for (var k in o.val)
|
|
1977
2035
|
if (!protected.hasOwnProperty(k))
|
|
1978
|
-
u[k] = o[k]
|
|
1979
|
-
for (var k in u)
|
|
1980
|
-
if (!protected.hasOwnProperty(k) && !o.hasOwnProperty(k))
|
|
1981
|
-
delete u[k]
|
|
2036
|
+
u.val[k] = o.val[k]
|
|
2037
|
+
for (var k in u.val)
|
|
2038
|
+
if (!protected.hasOwnProperty(k) && !o.val.hasOwnProperty(k))
|
|
2039
|
+
delete u.val[k]
|
|
1982
2040
|
|
|
1983
2041
|
master.set(u)
|
|
1984
2042
|
}
|
|
1985
2043
|
client('user/*').to_get = function user_getter (k) {
|
|
1986
2044
|
var c = client.get('current_user')
|
|
1987
|
-
client.log('* getting:', k, 'as', c.user)
|
|
2045
|
+
client.log('* getting:', k, 'as', c.val.user)
|
|
1988
2046
|
|
|
1989
2047
|
// Users have closet space at /user/<name>/*
|
|
1990
2048
|
if (k.match(closet_space_key)) {
|
|
1991
2049
|
var obj_user = k.match(closet_space_key)[1]
|
|
1992
2050
|
if (k.match(private_closet_space_key)
|
|
1993
|
-
&& (!c.user || obj_user !== c.user.
|
|
2051
|
+
&& (!c.val.user || obj_user !== c.val.user.link)) {
|
|
1994
2052
|
client.log('hiding private closet data')
|
|
1995
2053
|
return {}
|
|
1996
2054
|
}
|
|
@@ -1999,16 +2057,17 @@ function import_server (bus, options)
|
|
|
1999
2057
|
}
|
|
2000
2058
|
|
|
2001
2059
|
// Otherwise return the actual user
|
|
2002
|
-
return user_obj(k, c.logged_in && c.user.
|
|
2060
|
+
return user_obj(k, c.val.logged_in && c.val.user.link === k)
|
|
2003
2061
|
}
|
|
2004
2062
|
client('user/*').to_delete = function () {}
|
|
2005
2063
|
function user_obj (k, logged_in) {
|
|
2006
2064
|
var o = master.clone(master.get(k))
|
|
2007
2065
|
if (k.match(/^user\/([^\/]+)\/private\/(.*)$/))
|
|
2008
2066
|
return logged_in ? o : {key: k}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2067
|
+
|
|
2068
|
+
o.val = o.val || {}
|
|
2069
|
+
delete o.val.pass
|
|
2070
|
+
if (!logged_in) {delete o.val.email; delete o.val.login}
|
|
2012
2071
|
return o
|
|
2013
2072
|
}
|
|
2014
2073
|
|
|
@@ -2027,14 +2086,14 @@ function import_server (bus, options)
|
|
|
2027
2086
|
var was_logged_in = undefined
|
|
2028
2087
|
|
|
2029
2088
|
function client_prefix (current_user) {
|
|
2030
|
-
return 'client/' + (current_user.logged_in
|
|
2031
|
-
? current_user.user.
|
|
2089
|
+
return 'client/' + (current_user.val.logged_in
|
|
2090
|
+
? current_user.val.user.link.substr('user/'.length)
|
|
2032
2091
|
: client.client_id) + '/'
|
|
2033
2092
|
}
|
|
2034
2093
|
|
|
2035
|
-
function copy_client_to_user(client,
|
|
2094
|
+
function copy_client_to_user(client, user_key) {
|
|
2036
2095
|
var old_prefix = 'client/' + client.client_id
|
|
2037
|
-
var new_prefix = 'client/' +
|
|
2096
|
+
var new_prefix = 'client/' + user_key.substr('user/'.length)
|
|
2038
2097
|
|
|
2039
2098
|
var keys = client.master.get('persisted_keys/' + client.client_id)
|
|
2040
2099
|
if (!keys.val) return
|
|
@@ -2080,10 +2139,10 @@ function import_server (bus, options)
|
|
|
2080
2139
|
client(_=>{
|
|
2081
2140
|
var c = client.get('current_user')
|
|
2082
2141
|
if (client.loading()) return
|
|
2083
|
-
if (was_logged_in == false && c.logged_in)
|
|
2142
|
+
if (was_logged_in == false && c.val.logged_in)
|
|
2084
2143
|
// User just logged in! Let's copy his stuff over
|
|
2085
|
-
copy_client_to_user(client, c.user)
|
|
2086
|
-
was_logged_in = c.logged_in
|
|
2144
|
+
copy_client_to_user(client, c.val.user.link)
|
|
2145
|
+
was_logged_in = c.val.logged_in
|
|
2087
2146
|
})
|
|
2088
2147
|
|
|
2089
2148
|
client(prefix_to_sync).to_get = function (key) {
|
|
@@ -2141,7 +2200,7 @@ function import_server (bus, options)
|
|
|
2141
2200
|
}
|
|
2142
2201
|
|
|
2143
2202
|
function client_persisted_keys () {
|
|
2144
|
-
if (client.get('current_user').logged_in) return
|
|
2203
|
+
if (client.get('current_user').val.logged_in) return
|
|
2145
2204
|
var result = client.master.get('persisted_keys/' + client.client_id)
|
|
2146
2205
|
if (result && !result.val) result.val = {}
|
|
2147
2206
|
return result
|
|
@@ -2274,7 +2333,7 @@ function import_server (bus, options)
|
|
|
2274
2333
|
// Installs a GET handler at route that gets state from a getter function
|
|
2275
2334
|
// Note: Makes too many textbusses. Should re-use one.
|
|
2276
2335
|
http_serve: function http_serve (route, getter) {
|
|
2277
|
-
var textbus =
|
|
2336
|
+
var textbus = make_statebus()
|
|
2278
2337
|
textbus.label = 'textbus'
|
|
2279
2338
|
var watched = new Set()
|
|
2280
2339
|
textbus('*').to_get = (filename, old) => {
|