Differences From
Artifact [b4f49ac3f6]:
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