statebus 7.0.1 → 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 +228 -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,27 +148,46 @@ 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
|
|
|
182
|
+
// We only return JSON
|
|
183
|
+
res.setHeader('Content-Type', 'application/json')
|
|
184
|
+
|
|
185
185
|
// Do the get
|
|
186
186
|
// cbus.honk = 'statelog'
|
|
187
187
|
var key = req.path.substr(1)
|
|
188
|
+
// console.log('http_in: doing cbus.get(', key, ')')
|
|
188
189
|
cbus.get(key, cb = (o) => {
|
|
190
|
+
// console.trace('http_in: Sending update of', key)
|
|
189
191
|
var body = to_http_body(o)
|
|
190
192
|
|
|
191
193
|
// If we're braiding, send via subscription
|
|
@@ -197,14 +199,11 @@ function import_server (bus, options)
|
|
|
197
199
|
|
|
198
200
|
// And shut down the connection if there's no subscription
|
|
199
201
|
if (!req.subscribe)
|
|
200
|
-
|
|
202
|
+
end_subscription()
|
|
201
203
|
})
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
else if (req.method === 'PUT') {
|
|
205
|
-
// Make a temporary client bus
|
|
206
|
-
var cbus = bus.bus_for_http_client(req, res)
|
|
207
|
-
|
|
208
207
|
// Maybe the new state is expressed in patches
|
|
209
208
|
if (req.headers.patches) {
|
|
210
209
|
console.error("We don't actually handle PUT patches yet")
|
|
@@ -231,9 +230,14 @@ function import_server (bus, options)
|
|
|
231
230
|
res.end()
|
|
232
231
|
return
|
|
233
232
|
}
|
|
234
|
-
|
|
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
|
+
|
|
235
238
|
res.statusCode = 200
|
|
236
239
|
res.end()
|
|
240
|
+
cbus.http_unsubscribe(req)
|
|
237
241
|
})
|
|
238
242
|
}
|
|
239
243
|
}
|
|
@@ -243,16 +247,39 @@ function import_server (bus, options)
|
|
|
243
247
|
|
|
244
248
|
bus_for_http_client: function (req, res) {
|
|
245
249
|
var bus = this
|
|
246
|
-
if (!bus.bus_for_http_client.counter)
|
|
250
|
+
if (!bus.bus_for_http_client.counter) {
|
|
247
251
|
bus.bus_for_http_client.counter = 0
|
|
248
|
-
|
|
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()
|
|
249
266
|
cbus.label = 'client_http' + bus.bus_for_http_client.counter++
|
|
250
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
|
|
251
278
|
|
|
252
|
-
//
|
|
279
|
+
// And log into it as the client
|
|
253
280
|
cbus.serves_auth({remoteAddress: req.connection.remoteAddress}, bus)
|
|
254
281
|
bus.options.client(cbus)
|
|
255
|
-
cbus.set({key: 'current_user', client: req.
|
|
282
|
+
cbus.set({key: 'current_user', val: {client: req.peer}})
|
|
256
283
|
return cbus
|
|
257
284
|
},
|
|
258
285
|
|
|
@@ -355,7 +382,7 @@ function import_server (bus, options)
|
|
|
355
382
|
// var client_busses = {} // XXX work in progress
|
|
356
383
|
var log = master.log
|
|
357
384
|
if (client_bus_func) {
|
|
358
|
-
master.set({key: 'connections'}) // Clean out old sessions
|
|
385
|
+
master.set({key: 'connections', val: {}}) // Clean out old sessions
|
|
359
386
|
var connections = master.get('connections')
|
|
360
387
|
}
|
|
361
388
|
var s = require('sockjs').createServer({
|
|
@@ -373,11 +400,11 @@ function import_server (bus, options)
|
|
|
373
400
|
// - When disconnecting, decrement the number, and if it gets
|
|
374
401
|
// to zero, delete the client bus.
|
|
375
402
|
|
|
376
|
-
connections[conn.id] = {client: conn.id, // client is deprecated
|
|
377
|
-
|
|
403
|
+
connections.val[conn.id] = {client: conn.id, // client is deprecated
|
|
404
|
+
id: conn.id}
|
|
378
405
|
master.set(connections)
|
|
379
406
|
|
|
380
|
-
var client =
|
|
407
|
+
var client = make_statebus()
|
|
381
408
|
client.label = 'client' + client_num++
|
|
382
409
|
master.label = master.label || 'master'
|
|
383
410
|
client.master = master
|
|
@@ -486,7 +513,7 @@ function import_server (bus, options)
|
|
|
486
513
|
for (var key in our_gets_in)
|
|
487
514
|
client.forget(key, sockjs_pubber)
|
|
488
515
|
if (client_bus_func) {
|
|
489
|
-
delete connections[conn.id]; master.set(connections)
|
|
516
|
+
delete connections.val[conn.id]; master.set(connections)
|
|
490
517
|
master.delete('connection/' + conn.id)
|
|
491
518
|
client.delete_bus()
|
|
492
519
|
}
|
|
@@ -534,12 +561,12 @@ function import_server (bus, options)
|
|
|
534
561
|
client('connections').to_set = function noop (t) {t.abort()}
|
|
535
562
|
client('connections').to_get = function () {
|
|
536
563
|
var result = []
|
|
537
|
-
var conns = master.get('connections')
|
|
564
|
+
var conns = master.get('connections').val
|
|
538
565
|
for (var connid in conns)
|
|
539
566
|
if (connid !== 'key')
|
|
540
567
|
result.push(client.get('connection/' + connid))
|
|
541
568
|
|
|
542
|
-
return {
|
|
569
|
+
return {val: result}
|
|
543
570
|
}
|
|
544
571
|
}
|
|
545
572
|
})
|
|
@@ -555,13 +582,6 @@ function import_server (bus, options)
|
|
|
555
582
|
WebSocket = require('websocket').w3cwebsocket
|
|
556
583
|
return new WebSocket(url + '/' + bus.options.websocket_path + '/websocket')
|
|
557
584
|
},
|
|
558
|
-
client_creds: function client_creds (server_url) {
|
|
559
|
-
// Right now the server just creates a different random id each time
|
|
560
|
-
// it connects.
|
|
561
|
-
return {clientid: (Math.random().toString(36).substring(2)
|
|
562
|
-
+ Math.random().toString(36).substring(2)
|
|
563
|
-
+ Math.random().toString(36).substring(2))}
|
|
564
|
-
},
|
|
565
585
|
|
|
566
586
|
file_store: (function () {
|
|
567
587
|
// Make a database
|
|
@@ -1307,23 +1327,24 @@ function import_server (bus, options)
|
|
|
1307
1327
|
}
|
|
1308
1328
|
|
|
1309
1329
|
function user_addy (u) {
|
|
1330
|
+
console.error('fix this! not ported to v7 links')
|
|
1310
1331
|
return u.name + '@' + opts.domain
|
|
1311
1332
|
}
|
|
1312
1333
|
function current_addy () {
|
|
1313
1334
|
var c = client.get('current_user')
|
|
1314
|
-
|
|
1335
|
+
console.error('fix this! not ported to v7 links')
|
|
1336
|
+
return c.val.logged_in ? user_addy(c.val.user) : 'public'
|
|
1315
1337
|
}
|
|
1316
1338
|
function is_author (post) {
|
|
1317
1339
|
var from = post._.from
|
|
1318
|
-
var c = client.get('current_user')
|
|
1319
1340
|
return from.includes(current_addy())
|
|
1320
1341
|
}
|
|
1321
1342
|
function can_see (post) {
|
|
1322
|
-
|
|
1343
|
+
console.error('fix this! not ported to v7')
|
|
1323
1344
|
var allowed = post._.to.concat(post._.cc).concat(post._.from)
|
|
1324
1345
|
return allowed.includes(current_addy()) || allowed.includes('public')
|
|
1325
1346
|
}
|
|
1326
|
-
var drtbus = master//
|
|
1347
|
+
var drtbus = master//make_statebus()
|
|
1327
1348
|
function dirty (key) { drtbus.set({key: 'dirty-'+key, n: Math.random()}) }
|
|
1328
1349
|
function watch_for_dirt (key) { drtbus.get('dirty-'+key) }
|
|
1329
1350
|
|
|
@@ -1334,7 +1355,6 @@ function import_server (bus, options)
|
|
|
1334
1355
|
// Define state on client
|
|
1335
1356
|
client('posts*').to_get = (k, rest) => {
|
|
1336
1357
|
var args = bus.parse(rest.substr(1))
|
|
1337
|
-
var c = client.get('current_user')
|
|
1338
1358
|
args.for = current_addy()
|
|
1339
1359
|
var e = master.get('posts_for/' + JSON.stringify(args))
|
|
1340
1360
|
return {_: master.clone(e._).map(x=>client.get(x.key))}
|
|
@@ -1412,7 +1432,7 @@ function import_server (bus, options)
|
|
|
1412
1432
|
}
|
|
1413
1433
|
|
|
1414
1434
|
client('friends').to_get = t => {
|
|
1415
|
-
return {_: (master.get('users').
|
|
1435
|
+
return {_: (master.get('users').val||[])
|
|
1416
1436
|
.map(u=>client.get('email/' + user_addy(u)))
|
|
1417
1437
|
.concat([client.get('email/public')])
|
|
1418
1438
|
}
|
|
@@ -1640,42 +1660,55 @@ function import_server (bus, options)
|
|
|
1640
1660
|
|
|
1641
1661
|
serves_auth: function serves_auth (conn, master) {
|
|
1642
1662
|
var client = this // to keep me straight while programming
|
|
1643
|
-
|
|
1644
|
-
function logout (key) {
|
|
1663
|
+
function logout (user_key) {
|
|
1645
1664
|
var clients = master.get('logged_in_clients')
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
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
|
+
}
|
|
1657
1687
|
}
|
|
1658
1688
|
|
|
1659
1689
|
// Initialize master
|
|
1660
1690
|
if (!master.auth_initialized) {
|
|
1691
|
+
|
|
1692
|
+
// A hash for fast lookup of a user's password
|
|
1661
1693
|
master('users/passwords').to_get = function (k) {
|
|
1694
|
+
// We compute it from the 'users' state
|
|
1662
1695
|
master.log('users/passwords.to_get: Computing!')
|
|
1663
|
-
var result = {key: 'users/passwords'}
|
|
1696
|
+
var result = {key: 'users/passwords', val: {}}
|
|
1664
1697
|
var users = master.get('users')
|
|
1665
|
-
users.
|
|
1666
|
-
for (var i=0; i<users.
|
|
1667
|
-
var u = master.get(users.
|
|
1668
|
-
if (!(u.login || u.name)) {
|
|
1669
|
-
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)
|
|
1670
1703
|
continue
|
|
1671
1704
|
}
|
|
1672
|
-
var login = (u.login || u.name).toLowerCase()
|
|
1705
|
+
var login = (u.val.login || u.val.name).toLowerCase()
|
|
1673
1706
|
console.assert(login, 'Missing login for user', u)
|
|
1674
|
-
if (result.hasOwnProperty(login)) {
|
|
1707
|
+
if (result.val.hasOwnProperty(login)) {
|
|
1675
1708
|
console.error("upass: this user's name is bogus, dude.", u.key)
|
|
1676
1709
|
continue
|
|
1677
1710
|
}
|
|
1678
|
-
result[login] = {user: u.key, pass: u.pass}
|
|
1711
|
+
result.val[login] = {user: u.key, pass: u.val.pass}
|
|
1679
1712
|
}
|
|
1680
1713
|
return result
|
|
1681
1714
|
}
|
|
@@ -1686,26 +1719,25 @@ function import_server (bus, options)
|
|
|
1686
1719
|
master.log('Deleteinggg!!!', key)
|
|
1687
1720
|
// Remove from users.all
|
|
1688
1721
|
var users = master.get('users')
|
|
1689
|
-
users.
|
|
1722
|
+
users.val = users.val.filter(u => u.link && u.link !== key)
|
|
1690
1723
|
master.set(users)
|
|
1691
1724
|
|
|
1692
1725
|
// Log out
|
|
1693
1726
|
master.log('Logging out', key)
|
|
1694
1727
|
logout(key)
|
|
1695
1728
|
|
|
1696
|
-
// Remove connection
|
|
1697
|
-
master.log('Removing connections for', key)
|
|
1698
|
-
var conns = master.get('connections')
|
|
1699
|
-
for (var k in conns) {
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
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
|
+
// }
|
|
1709
1741
|
|
|
1710
1742
|
master.log('Dirtying users/passwords for', key)
|
|
1711
1743
|
master.dirty('users/passwords')
|
|
@@ -1717,9 +1749,9 @@ function import_server (bus, options)
|
|
|
1717
1749
|
|
|
1718
1750
|
// Authentication functions
|
|
1719
1751
|
function authenticate (login, pass) {
|
|
1720
|
-
var userpass = master.get('users/passwords')[login.toLowerCase()]
|
|
1752
|
+
var userpass = master.get('users/passwords').val[login.toLowerCase()]
|
|
1721
1753
|
master.log('authenticate: we see', {
|
|
1722
|
-
passwords: master.get('users/passwords'),
|
|
1754
|
+
passwords: master.get('users/passwords').val,
|
|
1723
1755
|
hash_to_match: userpass && userpass.pass,
|
|
1724
1756
|
password_guess: pass
|
|
1725
1757
|
})
|
|
@@ -1730,7 +1762,7 @@ function import_server (bus, options)
|
|
|
1730
1762
|
|
|
1731
1763
|
// console.log('comparing passwords', pass, userpass.pass)
|
|
1732
1764
|
if (require('bcrypt-nodejs').compareSync(pass, userpass.pass))
|
|
1733
|
-
return
|
|
1765
|
+
return userpass.user
|
|
1734
1766
|
}
|
|
1735
1767
|
function create_account (params) {
|
|
1736
1768
|
if (typeof (params.login || params.name) !== 'string')
|
|
@@ -1743,7 +1775,7 @@ function import_server (bus, options)
|
|
|
1743
1775
|
throw 'invalid name, login, pass, or email'
|
|
1744
1776
|
|
|
1745
1777
|
var passes = master.get('users/passwords')
|
|
1746
|
-
if (passes.hasOwnProperty(login))
|
|
1778
|
+
if (passes.val.hasOwnProperty(login))
|
|
1747
1779
|
throw 'there is already a user with that login or name'
|
|
1748
1780
|
|
|
1749
1781
|
// Hash password
|
|
@@ -1763,60 +1795,81 @@ function import_server (bus, options)
|
|
|
1763
1795
|
key = 'user/' + Math.random().toString(36).substring(7,13)
|
|
1764
1796
|
|
|
1765
1797
|
// Make account object
|
|
1766
|
-
var new_account = {
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
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]
|
|
1772
1809
|
master.set(new_account)
|
|
1773
1810
|
|
|
1774
1811
|
var users = master.get('users')
|
|
1775
|
-
users.
|
|
1776
|
-
users.
|
|
1777
|
-
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}
|
|
1778
1815
|
master.set(users)
|
|
1779
1816
|
master.set(passes)
|
|
1780
1817
|
}
|
|
1781
1818
|
|
|
1782
1819
|
// Current User
|
|
1783
1820
|
client('current_user').to_get = function (k) {
|
|
1784
|
-
client
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
u =
|
|
1788
|
-
|
|
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
|
|
1789
1827
|
}
|
|
1790
1828
|
|
|
1791
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
|
+
}
|
|
1792
1836
|
function error (msg) {
|
|
1837
|
+
console.error(msg)
|
|
1793
1838
|
client.set.abort(o)
|
|
1794
1839
|
var c = client.get('current_user')
|
|
1795
|
-
c.error = msg
|
|
1840
|
+
c.val.error = msg
|
|
1796
1841
|
client.set.fire(c)
|
|
1797
1842
|
}
|
|
1798
1843
|
|
|
1799
1844
|
client.log('* saving: current_user!')
|
|
1800
|
-
if (
|
|
1845
|
+
if (val.client && !conn.client) {
|
|
1801
1846
|
// Set the client
|
|
1802
|
-
|
|
1803
|
-
|
|
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
|
|
1804
1852
|
client.client_ip = conn.remoteAddress
|
|
1805
1853
|
|
|
1806
|
-
if (conn.id) {
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
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
|
+
// }
|
|
1811
1864
|
}
|
|
1812
1865
|
else {
|
|
1813
|
-
if (
|
|
1866
|
+
if (val.create_account) {
|
|
1814
1867
|
client.log('current_user: creating account')
|
|
1815
1868
|
try {
|
|
1816
|
-
create_account(
|
|
1869
|
+
create_account(val.create_account)
|
|
1817
1870
|
client.log('Success creating account!')
|
|
1818
1871
|
var cu = client.get('current_user')
|
|
1819
|
-
cu.create_account = null
|
|
1872
|
+
cu.val.create_account = null
|
|
1820
1873
|
client.set.fire(cu)
|
|
1821
1874
|
} catch (e) {
|
|
1822
1875
|
error('Cannot create that account because ' + e)
|
|
@@ -1824,29 +1877,29 @@ function import_server (bus, options)
|
|
|
1824
1877
|
}
|
|
1825
1878
|
}
|
|
1826
1879
|
|
|
1827
|
-
if (
|
|
1880
|
+
if (val.login_as) {
|
|
1828
1881
|
// Then client is trying to log in
|
|
1829
|
-
|
|
1830
|
-
var creds = o.login_as
|
|
1882
|
+
var creds = val.login_as
|
|
1831
1883
|
var login = creds.login || creds.name
|
|
1832
1884
|
if (login && creds.pass) {
|
|
1833
1885
|
// With a username and password
|
|
1834
|
-
var
|
|
1886
|
+
var user_key = authenticate(login, creds.pass)
|
|
1835
1887
|
|
|
1836
|
-
client.log('auth said:',
|
|
1837
|
-
if (
|
|
1888
|
+
client.log('auth said:', user_key)
|
|
1889
|
+
if (user_key) {
|
|
1838
1890
|
// Success!
|
|
1839
1891
|
// Associate this user with this session
|
|
1840
1892
|
// user.log('Logging the user in!', u)
|
|
1841
1893
|
|
|
1842
1894
|
var clients = master.get('logged_in_clients')
|
|
1843
|
-
var connections = master.get('connections')
|
|
1895
|
+
// var connections = master.get('connections')
|
|
1844
1896
|
|
|
1845
|
-
clients
|
|
1846
|
-
|
|
1897
|
+
clients.val = clients.val || {}
|
|
1898
|
+
clients.val[conn.client] = {link: user_key}
|
|
1899
|
+
// connections.val[conn.id].user = {link: user_key}
|
|
1847
1900
|
|
|
1848
1901
|
master.set(clients)
|
|
1849
|
-
master.set(connections)
|
|
1902
|
+
// master.set(connections)
|
|
1850
1903
|
|
|
1851
1904
|
client.log('current_user: success logging in!')
|
|
1852
1905
|
}
|
|
@@ -1861,16 +1914,17 @@ function import_server (bus, options)
|
|
|
1861
1914
|
}
|
|
1862
1915
|
}
|
|
1863
1916
|
|
|
1864
|
-
else if (
|
|
1917
|
+
else if (val.logout) {
|
|
1865
1918
|
client.log('current_user: logging out')
|
|
1866
1919
|
var clients = master.get('logged_in_clients')
|
|
1867
|
-
var connections = master.get('connections')
|
|
1920
|
+
// var connections = master.get('connections')
|
|
1868
1921
|
|
|
1869
|
-
|
|
1870
|
-
|
|
1922
|
+
clients.val = clients.val || {}
|
|
1923
|
+
delete clients.val[conn.client]
|
|
1924
|
+
// connections.val[conn.id].user = null
|
|
1871
1925
|
|
|
1872
1926
|
master.set(clients)
|
|
1873
|
-
master.set(connections)
|
|
1927
|
+
// master.set(connections)
|
|
1874
1928
|
}
|
|
1875
1929
|
}
|
|
1876
1930
|
|
|
@@ -1888,11 +1942,13 @@ function import_server (bus, options)
|
|
|
1888
1942
|
var user_key = o.key.match(/^user\/([^\/]+)/)
|
|
1889
1943
|
user_key = user_key && ('user/' + user_key[1])
|
|
1890
1944
|
|
|
1891
|
-
// Only the current user can touch
|
|
1892
|
-
if (!c.logged_in || c.user.
|
|
1893
|
-
client.log('Only the current user can touch
|
|
1894
|
-
|
|
1895
|
-
|
|
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
|
+
})
|
|
1896
1952
|
client.set.abort(o)
|
|
1897
1953
|
return
|
|
1898
1954
|
}
|
|
@@ -1908,9 +1964,14 @@ function import_server (bus, options)
|
|
|
1908
1964
|
console.assert(o.key.match(/^user\/[^\/]+$/))
|
|
1909
1965
|
|
|
1910
1966
|
// Validate types
|
|
1911
|
-
if (!client.validate(o, {key: 'string',
|
|
1912
|
-
|
|
1913
|
-
|
|
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
|
+
'*':'*'}})) {
|
|
1914
1975
|
client.log('This user change fails validation.')
|
|
1915
1976
|
client.set.abort(o)
|
|
1916
1977
|
return
|
|
@@ -1921,7 +1982,7 @@ function import_server (bus, options)
|
|
|
1921
1982
|
// • That resulting login must be unique across all users
|
|
1922
1983
|
|
|
1923
1984
|
// There must be at least a login or a name
|
|
1924
|
-
var login = o.login || o.name
|
|
1985
|
+
var login = o.val.login || o.val.name
|
|
1925
1986
|
if (!login) {
|
|
1926
1987
|
client.log('User must have a login or a name')
|
|
1927
1988
|
client.set.abort(o)
|
|
@@ -1932,26 +1993,26 @@ function import_server (bus, options)
|
|
|
1932
1993
|
var userpass = master.get('users/passwords')
|
|
1933
1994
|
|
|
1934
1995
|
// Validate that the login/name is not changed to something clobberish
|
|
1935
|
-
var old_login = u.login || u.name
|
|
1996
|
+
var old_login = u.val.login || u.val.name
|
|
1936
1997
|
if (old_login.toLowerCase() !== login.toLowerCase()
|
|
1937
1998
|
&& userpass.hasOwnProperty(login)) {
|
|
1938
1999
|
client.log('The login', login, 'is already taken. Aborting.')
|
|
1939
2000
|
client.set.abort(o) // Abort
|
|
1940
2001
|
|
|
1941
2002
|
o = client.get(o.key) // Add error message
|
|
1942
|
-
o.error = 'The login "' + login + '" is already taken'
|
|
2003
|
+
o.val.error = 'The login "' + login + '" is already taken'
|
|
1943
2004
|
client.set.fire(o)
|
|
1944
2005
|
|
|
1945
2006
|
return // And exit
|
|
1946
2007
|
}
|
|
1947
2008
|
|
|
1948
2009
|
// Now we can update login and name
|
|
1949
|
-
u.login = o.login
|
|
1950
|
-
u.name = o.name
|
|
2010
|
+
u.val.login = o.val.login
|
|
2011
|
+
u.val.name = o.val.name
|
|
1951
2012
|
|
|
1952
2013
|
// Hash password
|
|
1953
|
-
o.pass = o.pass && require('bcrypt-nodejs').hashSync(o.pass)
|
|
1954
|
-
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
|
|
1955
2016
|
|
|
1956
2017
|
// // Users can have pictures (remove this soon)
|
|
1957
2018
|
// // Bug: if user changes name, this picture's url doesn't change.
|
|
@@ -1970,24 +2031,24 @@ function import_server (bus, options)
|
|
|
1970
2031
|
|
|
1971
2032
|
// For anything else, go ahead and add it to the user object
|
|
1972
2033
|
var protected = {key:1, name:1, /*pic:1,*/ pass:1}
|
|
1973
|
-
for (var k in o)
|
|
2034
|
+
for (var k in o.val)
|
|
1974
2035
|
if (!protected.hasOwnProperty(k))
|
|
1975
|
-
u[k] = o[k]
|
|
1976
|
-
for (var k in u)
|
|
1977
|
-
if (!protected.hasOwnProperty(k) && !o.hasOwnProperty(k))
|
|
1978
|
-
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]
|
|
1979
2040
|
|
|
1980
2041
|
master.set(u)
|
|
1981
2042
|
}
|
|
1982
2043
|
client('user/*').to_get = function user_getter (k) {
|
|
1983
2044
|
var c = client.get('current_user')
|
|
1984
|
-
client.log('* getting:', k, 'as', c.user)
|
|
2045
|
+
client.log('* getting:', k, 'as', c.val.user)
|
|
1985
2046
|
|
|
1986
2047
|
// Users have closet space at /user/<name>/*
|
|
1987
2048
|
if (k.match(closet_space_key)) {
|
|
1988
2049
|
var obj_user = k.match(closet_space_key)[1]
|
|
1989
2050
|
if (k.match(private_closet_space_key)
|
|
1990
|
-
&& (!c.user || obj_user !== c.user.
|
|
2051
|
+
&& (!c.val.user || obj_user !== c.val.user.link)) {
|
|
1991
2052
|
client.log('hiding private closet data')
|
|
1992
2053
|
return {}
|
|
1993
2054
|
}
|
|
@@ -1996,16 +2057,17 @@ function import_server (bus, options)
|
|
|
1996
2057
|
}
|
|
1997
2058
|
|
|
1998
2059
|
// Otherwise return the actual user
|
|
1999
|
-
return user_obj(k, c.logged_in && c.user.
|
|
2060
|
+
return user_obj(k, c.val.logged_in && c.val.user.link === k)
|
|
2000
2061
|
}
|
|
2001
2062
|
client('user/*').to_delete = function () {}
|
|
2002
2063
|
function user_obj (k, logged_in) {
|
|
2003
2064
|
var o = master.clone(master.get(k))
|
|
2004
2065
|
if (k.match(/^user\/([^\/]+)\/private\/(.*)$/))
|
|
2005
2066
|
return logged_in ? o : {key: k}
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2067
|
+
|
|
2068
|
+
o.val = o.val || {}
|
|
2069
|
+
delete o.val.pass
|
|
2070
|
+
if (!logged_in) {delete o.val.email; delete o.val.login}
|
|
2009
2071
|
return o
|
|
2010
2072
|
}
|
|
2011
2073
|
|
|
@@ -2024,14 +2086,14 @@ function import_server (bus, options)
|
|
|
2024
2086
|
var was_logged_in = undefined
|
|
2025
2087
|
|
|
2026
2088
|
function client_prefix (current_user) {
|
|
2027
|
-
return 'client/' + (current_user.logged_in
|
|
2028
|
-
? current_user.user.
|
|
2089
|
+
return 'client/' + (current_user.val.logged_in
|
|
2090
|
+
? current_user.val.user.link.substr('user/'.length)
|
|
2029
2091
|
: client.client_id) + '/'
|
|
2030
2092
|
}
|
|
2031
2093
|
|
|
2032
|
-
function copy_client_to_user(client,
|
|
2094
|
+
function copy_client_to_user(client, user_key) {
|
|
2033
2095
|
var old_prefix = 'client/' + client.client_id
|
|
2034
|
-
var new_prefix = 'client/' +
|
|
2096
|
+
var new_prefix = 'client/' + user_key.substr('user/'.length)
|
|
2035
2097
|
|
|
2036
2098
|
var keys = client.master.get('persisted_keys/' + client.client_id)
|
|
2037
2099
|
if (!keys.val) return
|
|
@@ -2077,10 +2139,10 @@ function import_server (bus, options)
|
|
|
2077
2139
|
client(_=>{
|
|
2078
2140
|
var c = client.get('current_user')
|
|
2079
2141
|
if (client.loading()) return
|
|
2080
|
-
if (was_logged_in == false && c.logged_in)
|
|
2142
|
+
if (was_logged_in == false && c.val.logged_in)
|
|
2081
2143
|
// User just logged in! Let's copy his stuff over
|
|
2082
|
-
copy_client_to_user(client, c.user)
|
|
2083
|
-
was_logged_in = c.logged_in
|
|
2144
|
+
copy_client_to_user(client, c.val.user.link)
|
|
2145
|
+
was_logged_in = c.val.logged_in
|
|
2084
2146
|
})
|
|
2085
2147
|
|
|
2086
2148
|
client(prefix_to_sync).to_get = function (key) {
|
|
@@ -2138,7 +2200,7 @@ function import_server (bus, options)
|
|
|
2138
2200
|
}
|
|
2139
2201
|
|
|
2140
2202
|
function client_persisted_keys () {
|
|
2141
|
-
if (client.get('current_user').logged_in) return
|
|
2203
|
+
if (client.get('current_user').val.logged_in) return
|
|
2142
2204
|
var result = client.master.get('persisted_keys/' + client.client_id)
|
|
2143
2205
|
if (result && !result.val) result.val = {}
|
|
2144
2206
|
return result
|
|
@@ -2271,7 +2333,7 @@ function import_server (bus, options)
|
|
|
2271
2333
|
// Installs a GET handler at route that gets state from a getter function
|
|
2272
2334
|
// Note: Makes too many textbusses. Should re-use one.
|
|
2273
2335
|
http_serve: function http_serve (route, getter) {
|
|
2274
|
-
var textbus =
|
|
2336
|
+
var textbus = make_statebus()
|
|
2275
2337
|
textbus.label = 'textbus'
|
|
2276
2338
|
var watched = new Set()
|
|
2277
2339
|
textbus('*').to_get = (filename, old) => {
|