parsav  Diff

Differences From Artifact [39281cf1cf]:

To Artifact [ee3dfa15a8]:


    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