parsav  Diff

Differences From Artifact [b4f49ac3f6]:

To Artifact [a8702e1420]:


   197    197   terra http.tweet_page(co: &lib.srv.convo, path: hpath, meth: method.t)
   198    198   	var pid, ok = lib.math.shorthand.parse(path(1).ptr, path(1).ct)
   199    199   	if not ok then
   200    200   		co:complain(400, 'bad post ID', 'that post ID is not valid')
   201    201   		return
   202    202   	end
   203    203   	var post = co.srv:post_fetch(pid)
          204  +	var rt: lib.store.notice
   204    205   	if not post then
   205         -		co:complain(404, 'post not found', 'no such post is known to this server')
   206         -		return
          206  +		rt = co.srv:post_act_fetch_notice(pid)
          207  +		if rt.kind ~= lib.store.noticetype.rt then
          208  +			co:complain(404, 'post not found', 'no such post is known to this server')
          209  +			return
          210  +		elseif rt.who ~= co.who.id then
          211  +			co:complain(403, 'forbidden', 'you cannot cancel other people\'s retweets')
          212  +			return
          213  +		end
   207    214   	end
   208         -	defer post:free()
          215  +	defer post:free() -- NOP on null
   209    216   
   210    217   	if path.ct == 3 then
   211    218   		var lnk: lib.str.acc lnk:compose('/post/', path(1))
   212    219   		var lnkp = lnk:finalize() defer lnkp:free()
   213         -		if post(0).author ~= co.who.id then
          220  +		if post:ref() and post(0).author ~= co.who.id then
   214    221   			co:complain(403, 'forbidden', 'you cannot alter other people\'s posts')
   215    222   			return
   216         -		elseif path(2):cmp(lib.str.lit 'edit') then
          223  +		elseif post:ref() and path(2):cmp(lib.str.lit 'edit') then
          224  +			if not co:assertpow('edit') then return end
   217    225   			if meth_get(meth) then
   218    226   				lib.render.compose(co, post.ptr, nil)
   219    227   				return
   220    228   			elseif meth == method.post then
   221    229   				var newbody = co:postv('post')._0
   222    230   				var newacl = co:postv('acl')._0
   223    231   				var newsubj = co:postv('subject')._0
................................................................................
   226    234   				if newsubj ~= nil then post(0).subject = newsubj end
   227    235   				post(0):save(true)
   228    236   				co:reroute(lnkp.ptr)
   229    237   			end
   230    238   			return
   231    239   		elseif path(2):cmp(lib.str.lit 'del') then
   232    240   			if meth_get(meth) then
   233         -				var conf = data.view.confirm {
   234         -					title = lib.str.plit 'delete post';
   235         -					query = lib.str.plit 'are you sure you want to delete this post?';
   236         -					cancel = lnkp
   237         -				}
          241  +				var conf: data.view.confirm
          242  +				if post:ref() then
          243  +					conf = data.view.confirm {
          244  +						title = lib.str.plit 'delete post';
          245  +						query = lib.str.plit 'are you sure you want to delete this post?';
          246  +						cancel = lnkp
          247  +					}
          248  +				else
          249  +					conf = data.view.confirm {
          250  +						title = lib.str.plit 'cancel retweet';
          251  +						query = lib.str.plit 'are you sure you want to undo this retweet?';
          252  +						cancel = lib.str.plit'/';
          253  +					}
          254  +				end
   238    255   				var body = conf:tostr() defer body:free()
   239    256   				co:stdpage([lib.srv.convo.page] {
   240    257   					title = lib.str.plit 'post :: delete';
   241    258   					class = lib.str.plit 'query';
   242    259   					body = body; cache = false;
   243    260   				})
   244    261   				return
   245    262   			elseif meth == method.post then
   246    263   				var act = co:ppostv('act')
   247    264   				if act:cmp(lib.str.plit 'confirm') then
   248         -					post(0).source:post_destroy(post(0).id)
          265  +					if post:ref() then
          266  +						post(0).source:post_destroy(post(0).id)
          267  +					elseif rt.kind ~= 0 then
          268  +						co.srv:post_act_cancel(pid)
          269  +					end
   249    270   					co:reroute('/') -- TODO maybe return to parent or conversation if possible
   250    271   					return
   251    272   				else goto badop end
   252    273   			end
   253    274   		else goto badurl end
   254    275   	end
   255    276   
   256         -	if meth == method.post then
          277  +	if post:ref() and meth == method.post then
   257    278   		if co.aid == 0 then goto noauth end
   258    279   		var act = co:ppostv('act')
   259    280   		if act:cmp(lib.str.plit 'like') and not co.srv:post_liked_uid(co.who.id,pid) then
   260    281   			co.srv:post_like(co.who.id, pid, false)
   261    282   			post.ptr.likes = post.ptr.likes + 1
   262    283   		elseif act:cmp(lib.str.plit 'dislike') and co.srv:post_liked_uid(co.who.id,pid) then
   263    284   			co.srv:post_like(co.who.id, pid, true)
................................................................................
   276    297   				author = co.who.id, parent = pid;
   277    298   				subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
   278    299   			}
   279    300   
   280    301   			reply:publish(co.srv)
   281    302   		else goto badop end
   282    303   	end
          304  +
          305  +	if not post then goto badurl end
   283    306   
   284    307   	lib.render.tweet_page(co, path, post.ptr)
   285    308   	do return end
   286    309   
   287    310   	::badurl:: do co:complain(404, 'invalid URL', 'this URL does not reference extant content or functionality') return end
   288    311   	::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
   289    312   	::noauth:: do co:complain(401, 'unauthorized', 'you have not supplied the necessary credentials to perform this operation') return end
   290    313   end
   291    314   
   292    315   local terra 
   293    316   credsec_for_uid(co: &lib.srv.convo, uid: uint64)
   294    317   	var act = co:ppostv('act')
          318  +	lib.dbg('showing credentials')
   295    319   	if act:cmp(lib.str.plit 'invalidate') then
   296    320   		lib.dbg('setting user\'s cookie validation time to now')
   297    321   		co.who.source:auth_sigtime_user_alter(uid, lib.osclock.time(nil))
   298    322   		-- the current session has been invalidated as well, so we need to immediately install a new authentication cookie with the same aid so the user doesn't need to log back in all over again
   299    323   		co:installkey('/conf/sec',co.aid)
   300    324   		return
   301    325   	elseif act:cmp(lib.str.plit 'newcred') then
   302    326   		var cmt = co:ppostv('comment')
   303    327   		var pw = co:ppostv('newpw')
          328  +		var aid: uint64 = 0
   304    329   		if pw:ref() then
   305    330   			var cpw = co:ppostv('rptpw')
   306    331   			if not pw:cmp(cpw) then
   307    332   				co:complain(400,'enrollment failure','the passwords you supplied do not match')
   308    333   				return
   309    334   			end
   310         -			co.srv:auth_attach_pw(uid, false, pw, cmt)
   311         -			co:reroute('?')
   312         -			return
          335  +			aid = co.srv:auth_attach_pw(uid, false, pw, cmt)
   313    336   		else
   314    337   			var key = co:ppostv('newkey')
   315    338   			if key:ref() then
   316    339   
   317    340   			end
   318    341   		end
          342  +		if aid ~= 0 then
          343  +			lib.dbg('setting credential restrictions')
          344  +			var privs = [(function()
          345  +				local check = quote end
          346  +				local me = symbol(lib.store.privset)
          347  +				for i,v in ipairs(lib.store.privset.members) do
          348  +					check = quote [check]
          349  +						var val = co:pgetv(['allow-' .. v])
          350  +						if val:ref() and val:cmp(lib.str.plit'on')
          351  +							then ([me].[v] << true)
          352  +							else ([me].[v] << false)
          353  +						end
          354  +					end
          355  +				end
          356  +				return quote
          357  +					var [me]
          358  +					[check]
          359  +				in [me] end
          360  +			end)()]
          361  +			privs:dump()
          362  +			if privs:sz() > 0 then
          363  +				lib.dbg('installing credential restrictions')
          364  +				lib.io.fmt('on priv %llu\n',aid)
          365  +				co.srv:auth_privs_set(aid, privs)
          366  +			end
          367  +		end
          368  +		co:reroute('?')
          369  +		return
   319    370   	end
   320    371   	co:complain(400,'bad request','the operation you have requested is not meaningful in this context')
   321    372   end
   322    373   
   323    374   terra http.configure(co: &lib.srv.convo, path: hpath, meth: method.t)
   324    375   	var msg = pstring.null()
   325    376   	-- first things first, do priv checks
   326         -	if path.ct >= 1 then
          377  +	if path.ct >= 2 then
   327    378   		if not co.who.rights.powers.config() and (
   328    379   			path(1):cmp(lib.str.lit 'srv')   or
   329    380   			path(1):cmp(lib.str.lit 'badge') or
   330    381   			path(1):cmp(lib.str.lit 'emoji')
   331    382   		) then goto nopriv
   332    383   
   333    384   		elseif not co.who.rights.powers.rebrand() and (
   334    385   			path(1):cmp(lib.str.lit 'brand')
   335    386   		) then goto nopriv
   336    387   
   337    388   		elseif not co.who.rights.powers.account() and (
   338    389   			path(1):cmp(lib.str.lit 'profile') or
   339         -			path(1):cmp(lib.str.lit 'acct')
          390  +			path(1):cmp(lib.str.lit 'sec') or
          391  +			path(1):cmp(lib.str.lit 'avi') or
          392  +			path(1):cmp(lib.str.lit 'ui')
   340    393   		) then goto nopriv
   341    394   
   342    395   		elseif not co.who.rights.powers:affect_users() and (
   343    396   			path(1):cmp(lib.str.lit 'users')
   344    397   		) then goto nopriv end
   345    398   	end
   346    399   
................................................................................
   384    437   		elseif path(1):cmp(lib.str.lit 'users') then
   385    438   			if path.ct >= 3 then
   386    439   				var userid, ok = lib.math.shorthand.parse(path(2).ptr, path(2).ct)
   387    440   				if ok then
   388    441   					var usr = co.srv:actor_fetch_uid(userid)
   389    442   					if usr:ref() then defer usr:free()
   390    443   						if not co.who:overpowers(usr.ptr) then goto nopriv end
          444  +					end
          445  +					if path.ct == 4 then
          446  +						if path(3):cmp(lib.str.lit 'cred') then
          447  +							credsec_for_uid(co, userid)
          448  +						end
   391    449   					end
   392    450   				end
   393    451   			elseif path.ct == 2 and meth == method.post then
   394    452   				var act = co:ppostv('act')
   395    453   				if act:cmp(lib.str.plit'create') then
   396    454   					var newname = co:ppostv('handle')
   397    455   					if not newname or not lib.store.actor.handle_validate(newname.ptr) then