Differences From
Artifact [39281cf1cf]:
21 21
22 22 local ctlcmds = {
23 23 { 'start', 'start a new instance of the server' };
24 24 { 'stop', 'stop a running instance' };
25 25 { 'ls', 'list all running instances' };
26 26 { 'attach', 'capture log output from a running instance' };
27 27 { 'db', 'set up and manage the database' };
28 - { 'user', 'manage users, privileges, and credentials'};
28 + { 'user', 'create and manage users, privileges, and credentials'};
29 + { 'actor', 'manage and purge actors, epithets, and ranks'};
29 30 { 'mkroot <handle>', 'establish a new root user with the given handle' };
30 - { 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' };
31 - { 'actor <xid> create', 'instantiate a new actor' };
32 - { 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
33 31 { 'conf', 'manage the server configuration'};
32 + { 'grow <count> [<acl>]', 'grant a new round of invites to all users, or those who match the given ACL' };
34 33 { 'serv dl', 'initiate an update cycle over foreign actors' };
35 34 { 'tl', 'print the current local timeline to standard out' };
36 35 { 'be pgsql setup-auth (managed|unmanaged)', '(PGSQL backends) select the authentication strategy to use' };
37 36 }
38 37
39 38 local cmdhelp = function(tbl)
40 39 local str = '\ncommands:\n'
................................................................................
130 129 if acks(i).success then
131 130 lib.report('instance #',num,' reports successful ',rep)
132 131 else
133 132 lib.report('instance #',num,' reports failed ',rep)
134 133 end
135 134 end
136 135 end
136 +
137 +local terra gen_cfstr(cfmstr: rawstring, seed: intptr)
138 + var confirmstrs = array(
139 + 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa',
140 + 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst'
141 + )
142 + var tdx = lib.osclock.time(nil) / 60
143 + cfmstr[0] = 0
144 + for i=0,3 do
145 + if i ~= 0 then lib.str.cat(cfmstr, '-') end
146 + lib.str.cat(cfmstr, confirmstrs[(seed ^ tdx ^ (173*i)) % [confirmstrs.type.N]])
147 + end
148 +end
137 149
138 150 local emp = lib.ipc.global_emperor
139 151 local terra entry_mgtool(argc: int, argv: &rawstring): int
140 152 if argc < 1 then lib.bail('bad invocation!') end
141 153
142 154 lib.noise.init(2)
143 155 [lib.init]
................................................................................
272 284 return 1
273 285 end
274 286 if dbmode.arglist.ct < 1 then goto cmderr end
275 287
276 288 srv:setup(cnf)
277 289 if lib.str.cmp(dbmode.arglist(0),'init') == 0 and dbmode.arglist.ct == 2 then
278 290 lib.report('initializing new database structure for domain ', dbmode.arglist(1))
291 + dlg:tx_enter()
279 292 if dlg:dbsetup() then
280 293 srv:conprep(lib.store.prepmode.conf)
281 294 dlg:conf_set('instance-name', dbmode.arglist(1))
295 + dlg:conf_set('domain', dbmode.arglist(1))
282 296 do var sec: int8[65] gensec(&sec[0])
297 + dlg:conf_set('server-secret', &sec[0])
283 298 dlg:conf_set('server-secret', &sec[0])
284 299 end
285 300 lib.report('database setup complete; use mkroot to create an administrative user')
286 301 else lib.bail('initialization process interrupted') end
302 + dlg:tx_complete()
287 303 elseif lib.str.cmp(dbmode.arglist(0),'obliterate') == 0 then
288 - var confirmstrs = array(
289 - 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa',
290 - 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst'
291 - )
292 - var cfmstr: int8[64] cfmstr[0] = 0
293 - var tdx = lib.osclock.time(nil) / 60
294 - for i=0,3 do
295 - if i ~= 0 then lib.str.cat(&cfmstr[0], '-') end
296 - lib.str.cat(&cfmstr[0], confirmstrs[(tdx ^ (173*i)) % [confirmstrs.type.N]])
297 - end
304 + var cfmstr: int8[64] gen_cfstr(&cfmstr[0],0)
298 305
299 306 if dbmode.arglist.ct == 1 then
300 307 lib.bail('you are attempting to completely obliterate all data! make sure you have selected your target correctly. if you really want to do this, pass the confirmation string ', &cfmstr[0])
301 308 elseif dbmode.arglist.ct == 2 then
302 309 if lib.str.cmp(dbmode.arglist(1), cfmstr) == 0 then
303 310 lib.warn('completely obliterating all data!')
304 311 dlg:obliterate_everything()
................................................................................
392 399 dlg:conf_set('master',root.handle)
393 400 lib.report('created new administrator')
394 401 if mg then
395 402 var tmppw: int8[33]
396 403 pwset(dlg, &tmppw, ruid, false)
397 404 lib.report('temporary root pw: ', {&tmppw[0], 32})
398 405 end
406 + else goto cmderr end
407 + elseif lib.str.cmp(mode.arglist(0),'actor') == 0 then
408 + var umode: pbasic umode:parse(mode.arglist.ct, &mode.arglist(0))
409 + if umode.help then
410 + [ lib.emit(false, 1, 'usage: ', `argv[0], ' actor ', umode.type.helptxt.flags, ' <xid> <cmd> [<args>…]', umode.type.helptxt.opts, cmdhelp {
411 + { 'actor <xid> rank <value>', 'set an actor\'s rank to <value> (remote actors cannot exercise rank-related powers, but benefit from rank immunities)' };
412 + { 'actor <xid> degrade', 'alias for `actor <xid> rank 0`' };
413 + { 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
414 + { 'actor <xid> instantiate', 'instantiate a remote actor, retrieving their profile and posts even if no one follows them' };
415 + { 'actor <xid> proscribe', 'globally ban an actor from interacting with your server' };
416 + { 'actor <xid> rehabilitate', 'lift a proscription on an actor' };
417 + { 'actor <xid> purge-all <confirm-str>', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' };
418 + }) ]
419 + return 1
420 + end
421 + if umode.arglist.ct >= 2 then
422 + var degrade = lib.str.cmp(umode.arglist(1),'degrade') == 0
423 + var xid = umode.arglist(0)
424 + var usr = dlg:actor_fetch_xid(pstr {ptr=xid, ct=lib.str.sz(xid)})
425 + if not usr then lib.bail('no such actor') end
426 + if degrade or lib.str.cmp(umode.arglist(1),'rank') == 0 then
427 + var rank: uint16
428 + if degrade and umode.arglist.ct == 2 then
429 + rank = 0
430 + elseif (not degrade) and umode.arglist.ct == 3 then
431 + var r, ok = lib.math.decparse(pstr {
432 + ptr = umode.arglist(2);
433 + ct = lib.str.sz(umode.arglist(2));
434 + })
435 + if not ok then goto cmderr end
436 + rank = r
437 + else goto cmderr end
438 + usr.ptr.rights.rank = rank
439 + dlg:actor_save(usr.ptr)
440 + lib.report('set user rank')
441 + elseif umode.arglist.ct == 3 and lib.str.cmp(umode.arglist(1),'bestow') == 0 then
442 + if umode.arglist(2)[0] == 0
443 + then usr.ptr.epithet = nil
444 + else usr.ptr.epithet = umode.arglist(2)
445 + end
446 + dlg:actor_save(usr.ptr)
447 + lib.report('bestowed a new epithet on ', usr.ptr.xid)
448 + elseif lib.str.cmp(umode.arglist(1),'purge-all') == 0 then
449 + var cfmstr: int8[64] gen_cfstr(&cfmstr[0],usr.ptr.id)
450 + if umode.arglist.ct == 2 then
451 + lib.bail('you are attempting to completely purge the actor ', usr.ptr.xid, ' and all related content from the database! if you really want to do this, pass the confirmation string ', &cfmstr[0])
452 + elseif umode.arglist.ct == 3 then
453 + if lib.str.ncmp(&cfmstr[0],umode.arglist(2),64) ~= 0 then
454 + lib.bail('you have supplied an invalid confirmation string; if you really want to purge this actor, pass ', &cfmstr[0])
455 + end
456 + lib.warn('completely purging actor ', usr.ptr.xid, ' and all related content from database')
457 + dlg:actor_purge_uid(usr.ptr.id)
458 + lib.report('actor purged')
459 + else goto cmderr end
460 + else goto cmderr end
399 461 else goto cmderr end
400 462 elseif lib.str.cmp(mode.arglist(0),'user') == 0 then
401 463 var umode: pbasic umode:parse(mode.arglist.ct, &mode.arglist(0))
402 464 if umode.help then
403 465 [ lib.emit(false, 1, 'usage: ', `argv[0], ' user ', umode.type.helptxt.flags, ' <handle> <cmd> [<args>…]', umode.type.helptxt.opts, cmdhelp {
466 + { 'user <handle> create', 'add a new user' };
404 467 { 'user <handle> auth <type> new', '(where applicable, managed auth only) create a new authentication token of the given type for a user' };
405 468 { 'user <handle> auth <type> reset', '(where applicable, managed auth only) delete all of a user\'s authentication tokens of the given type and issue a new one' };
406 469 { 'user <handle> auth (<type>|all) purge', 'delete all credentials that would allow this user to log in (where possible)' };
407 470 { 'user <handle> (grant|revoke) (<priv>|all)', 'grant or revoke a specific power to or from a user' };
408 - { 'user <handle> emasculate', 'strip all administrative powers from a user' };
471 + { 'user <handle> emasculate', 'strip all administrative powers and rank from a user' };
409 472 { 'user <handle> forgive', 'restore all default powers to a user' };
410 473 { 'user <handle> suspend [<timespec>]', '(e.g. \27[1muser jokester suspend 5d 6h 7m 3s\27[m to suspend "jokester" for five days, six hours, seven minutes, and three seconds) suspend a user'};
411 474 }) ]
412 475 return 1
413 476 end
414 - if umode.arglist.ct >= 3 then
477 + var handle = umode.arglist(0)
478 + var usr = dlg:actor_fetch_xid(pstr {ptr=handle, ct=lib.str.sz(handle)})
479 + if umode.arglist.ct == 2 and lib.str.cmp(umode.arglist(1),'create')==0 then
480 + if usr:ref() then lib.bail('that user already exists') end
481 + if not lib.store.actor.handle_validate(handle) then
482 + lib.bail('invalid user handle') end
483 + var kbuf: uint8[lib.crypt.const.maxdersz]
484 + var na = lib.store.actor.mk(&kbuf[0])
485 + na.handle = handle
486 + dlg:actor_create(&na)
487 + lib.report('created new user @',na.handle,'; assign credentials to enable login')
488 + elseif umode.arglist.ct >= 3 then
415 489 var grant = lib.str.cmp(umode.arglist(1),'grant') == 0
416 - var handle = umode.arglist(0)
417 - var usr = dlg:actor_fetch_xid(pstr {ptr=handle, ct=lib.str.sz(handle)})
490 + if not usr then lib.bail('no such user') end
418 491 if grant or lib.str.cmp(umode.arglist(1),'revoke') == 0 then
419 - if not usr then lib.bail('unknown handle') end
420 492 var newprivs = usr.ptr.rights.powers
421 493 var map = array([lib.store.privmap])
422 494 if umode.arglist.ct == 3 and lib.str.cmp(umode.arglist(2),'all') == 0 then
423 495 if grant
424 496 then newprivs:fill()
425 497 else newprivs:clear()
426 498 end