Differences From
Artifact [47b3eeec8d]:
12 12 terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t)
13 13 var rel: lib.store.relationship
14 14 if co.aid ~= 0 then
15 15 rel = co.srv:actor_rel_calc(co.who.id, actor.id)
16 16 if meth == method.post then
17 17 var act = co:ppostv('act')
18 18 if rel.recip.block() then
19 - if act:cmp(lib.str.plit 'follow') or act:cmp(lib.str.plit 'subscribe') then
19 + if act:cmp( 'follow') or act:cmp( 'subscribe') then
20 20 co:complain(403,'blocked','you cannot follow a user you are blocked by') return
21 21 end
22 22 end
23 - if act:cmp(lib.str.plit 'block') and not rel.rel.block() then
23 + if act:cmp( 'block') and not rel.rel.block() then
24 24 (rel.rel.block << true) ; (rel.recip.follow << false)
25 25 co.srv:actor_rel_create([lib.store.relation.idvmap.block], co.who.id, actor.id)
26 26 co.srv:actor_rel_destroy([lib.store.relation.idvmap.follow], actor.id, co.who.id)
27 27 else
28 28 [(function()
29 29 local tests = quote co:complain(400,'bad request','the action you have attempted on this user is not meaningful') return end
30 30 for i,v in ipairs(lib.store.relation.members) do
31 31 tests = quote
32 - if [v ~= 'block'] and act:cmp(lib.str.plit([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
32 + if [v ~= 'block'] and act:cmp(([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
33 33 (rel.rel.[v] << true)
34 34 co.srv:actor_rel_create([lib.store.relation.idvmap[v]], co.who.id, actor.id)
35 - elseif act:cmp(lib.str.plit(['un'..v])) and rel.rel.[v]() then
35 + elseif act:cmp((['un'..v])) and rel.rel.[v]() then
36 36 (rel.rel.[v] << false)
37 37 co.srv:actor_rel_destroy([lib.store.relation.idvmap[v]], co.who.id, actor.id)
38 38 else [tests] end
39 39 end
40 40 end
41 41 return tests
42 42 end)()]
................................................................................
102 102
103 103 http.actor_profile(co,actor.ptr,meth)
104 104 end
105 105
106 106 terra http.login_form(co: &lib.srv.convo, meth: method.t)
107 107 if meth_get(meth) then
108 108 -- request a username
109 - lib.render.login(co, nil, nil, lib.str.plit(nil))
109 + lib.render.login(co, nil, nil, pstring.null())
110 110 elseif meth == method.post then
111 111 var usn, usnl = co:postv('user')
112 112 var am, aml = co:postv('authmethod')
113 113 var chrs, chrsl = co:postv('response')
114 114 var cs, authok = co.srv:actor_auth_how(co.peer, usn)
115 115 var act = co.srv:actor_fetch_xid([lib.mem.ptr(int8)] {
116 116 ptr = usn, ct = usnl
117 117 })
118 118 if authok == false then
119 - lib.render.login(co, nil, nil, lib.str.plit'access denied')
119 + lib.render.login(co, nil, nil, 'access denied')
120 120 return
121 121 end
122 122 var fakeact = false
123 123 var fakeactor: lib.store.actor
124 124 if act.ptr == nil then
125 125 -- the user is known to us but has not yet claimed an
126 126 -- account on the server. create a template for the
................................................................................
134 134 }
135 135 act.ct = 1
136 136 act.ptr = &fakeactor
137 137 act.ptr.rights = lib.store.rights_default()
138 138 end
139 139 if am == nil then
140 140 -- pick an auth method
141 - lib.render.login(co, act.ptr, &cs, lib.str.plit(nil))
141 + lib.render.login(co, act.ptr, &cs, pstring.null())
142 142 else var aid: uint64 = 0
143 143 lib.dbg('authentication attempt beginning')
144 144 -- attempt login with provided method
145 145 if lib.str.ncmp('pw', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
146 146 aid = co.srv:actor_auth_pw(co.peer,
147 147 [lib.mem.ptr(int8)]{ptr=usn,ct=usnl},
148 148 [lib.mem.ptr(int8)]{ptr=chrs,ct=chrsl})
................................................................................
149 149 elseif lib.str.ncmp('otp', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
150 150 lib.dbg('using otp auth')
151 151 -- ยทยทยท --
152 152 else lib.dbg('invalid auth method') end
153 153
154 154 -- error out
155 155 if aid == 0 then
156 - lib.render.login(co, nil, nil, lib.str.plit 'authentication failure')
156 + lib.render.login(co, nil, nil, 'authentication failure')
157 157 else
158 158 co:installkey('/',aid)
159 159 end
160 160 end
161 161 if act.ptr ~= nil and fakeact == false then act:free() end
162 162 else
163 163 ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
................................................................................
253 253 end
254 254 return
255 255 elseif path(2):cmp(lib.str.lit 'del') then
256 256 if meth_get(meth) then
257 257 var conf: data.view.confirm
258 258 if post:ref() then
259 259 conf = data.view.confirm {
260 - title = lib.str.plit 'delete post';
261 - query = lib.str.plit 'are you sure you want to delete this post?';
260 + title = 'delete post';
261 + query = 'are you sure you want to delete this post?';
262 262 cancel = lnkp
263 263 }
264 264 else
265 265 conf = data.view.confirm {
266 - title = lib.str.plit 'cancel retweet';
267 - query = lib.str.plit 'are you sure you want to undo this retweet?';
268 - cancel = lib.str.plit'/';
266 + title = 'cancel retweet';
267 + query = 'are you sure you want to undo this retweet?';
268 + cancel = '/';
269 269 }
270 270 end
271 271 var fr = co.srv.pool:frame()
272 272 var body = conf:poolstr(&co.srv.pool) --defer body:free()
273 273 co:stdpage([lib.srv.convo.page] {
274 - title = lib.str.plit 'post :: delete';
275 - class = lib.str.plit 'query';
274 + title = 'post :: delete';
275 + class = 'query';
276 276 body = body; cache = false;
277 277 })
278 278 co.srv.pool:reset(fr)
279 279 return
280 280 elseif meth == method.post then
281 281 var act = co:ppostv('act')
282 - if act:cmp(lib.str.plit 'confirm') then
282 + if act:cmp( 'confirm') then
283 283 if post:ref() then
284 284 post(0).source:post_destroy(post(0).id)
285 285 elseif rt.kind ~= 0 then
286 286 co.srv:post_act_cancel(pid)
287 287 end
288 288 co:reroute('/') -- TODO maybe return to parent or conversation if possible
289 289 return
................................................................................
291 291 end
292 292 else goto badurl end
293 293 end
294 294
295 295 if post:ref() and meth == method.post then
296 296 if co.aid == 0 then goto noauth end
297 297 var act = co:ppostv('act')
298 - if act:cmp(lib.str.plit 'like') and not co.srv:post_liked_uid(co.who.id,pid) then
298 + if act:cmp( 'like') and not co.srv:post_liked_uid(co.who.id,pid) then
299 299 co.srv:post_like(co.who.id, pid, false)
300 300 post.ptr.likes = post.ptr.likes + 1
301 - elseif act:cmp(lib.str.plit 'dislike') and co.srv:post_liked_uid(co.who.id,pid) then
301 + elseif act:cmp( 'dislike') and co.srv:post_liked_uid(co.who.id,pid) then
302 302 co.srv:post_like(co.who.id, pid, true)
303 303 post.ptr.likes = post.ptr.likes - 1
304 - elseif act:cmp(lib.str.plit 'rt') then
304 + elseif act:cmp( 'rt') then
305 305 co.srv:post_retweet(co.who.id, pid, false)
306 306 post.ptr.rts = post.ptr.rts + 1
307 - elseif act:cmp(lib.str.plit 'post') then
307 + elseif act:cmp( 'post') then
308 308 var replytext = co:ppostv('post')
309 309 var acl = co:ppostv('acl')
310 310 var subj = co:ppostv('subject')
311 - if not acl then acl = lib.str.plit 'all' end
311 + if not acl then acl = 'all' end
312 312 if not replytext then goto badop end
313 313
314 314 var reply = lib.store.post {
315 315 author = co.who.id, parent = pid;
316 316 subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
317 317 }
318 318
................................................................................
330 330 ::noauth:: do co:complain(401, 'unauthorized', 'you have not supplied the necessary credentials to perform this operation') return end
331 331 end
332 332
333 333 local terra
334 334 credsec_for_uid(co: &lib.srv.convo, uid: uint64)
335 335 var act = co:ppostv('act')
336 336 lib.dbg('showing credentials')
337 - if act:cmp(lib.str.plit 'invalidate') then
337 + if act:cmp( 'invalidate') then
338 338 lib.dbg('setting user\'s cookie validation time to now')
339 339 co.who.source:auth_sigtime_user_alter(uid, lib.osclock.time(nil))
340 340 -- 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
341 341 co:installkey('?',co.aid)
342 342 return
343 - elseif act:cmp(lib.str.plit 'newcred') then
343 + elseif act:cmp( 'newcred') then
344 344 var cmt = co:ppostv('comment')
345 345 var pw = co:ppostv('newpw')
346 346 var aid: uint64 = 0
347 347 if pw:ref() then
348 348 var cpw = co:ppostv('rptpw')
349 349 if not pw:cmp(cpw) then
350 350 co:complain(400,'enrollment failure','the passwords you supplied do not match')
................................................................................
361 361 lib.dbg('setting credential restrictions')
362 362 var privs = [(function()
363 363 local check = quote end
364 364 local me = symbol(lib.store.privset)
365 365 for i,v in ipairs(lib.store.privset.members) do
366 366 check = quote [check]
367 367 var val = co:pgetv(['allow-' .. v])
368 - if val:ref() and val:cmp(lib.str.plit'on')
368 + if val:ref() and val:cmp('on')
369 369 then ([me].[v] << true)
370 370 else ([me].[v] << false)
371 371 end
372 372 end
373 373 end
374 374 return quote
375 375 var [me]
................................................................................
393 393 end
394 394
395 395 terra http.configure(co: &lib.srv.convo, path: hpath, meth: method.t)
396 396 var msg = pstring.null()
397 397 -- first things first, do priv checks
398 398 if path.ct >= 2 then
399 399 if not co.who.rights.powers.config() and (
400 - path(1):cmp(lib.str.lit 'srv') or
401 - path(1):cmp(lib.str.lit 'badge') or
402 - path(1):cmp(lib.str.lit 'emoji')
400 + path(1):cmp('srv') or
401 + path(1):cmp('badge') or
402 + path(1):cmp('emoji')
403 403 ) then goto nopriv
404 404
405 405 elseif not co.who.rights.powers.rebrand() and (
406 - path(1):cmp(lib.str.lit 'brand')
406 + path(1):cmp('brand')
407 407 ) then goto nopriv
408 408
409 409 elseif not co.who.rights.powers.account() and (
410 - path(1):cmp(lib.str.lit 'profile') or
411 - path(1):cmp(lib.str.lit 'sec') or
412 - path(1):cmp(lib.str.lit 'avi') or
413 - path(1):cmp(lib.str.lit 'ui')
410 + path(1):cmp('profile') or
411 + path(1):cmp('sec') or
412 + path(1):cmp('avi') or
413 + path(1):cmp('ui')
414 414 ) then goto nopriv
415 415
416 416 elseif not co.who.rights.powers:affect_users() and (
417 417 path(1):cmp(lib.str.lit 'users')
418 418 ) then goto nopriv end
419 419 end
420 420
................................................................................
427 427 if co.who.bio ~= nil and @co.who.bio == 0 then co.who.bio = nil end
428 428 if co.who.nym ~= nil and @co.who.nym == 0 then co.who.nym = nil end
429 429 co.who.source:actor_save(co.who)
430 430
431 431 var act = co:ppostv('act')
432 432 var resethue = false
433 433 if act:ref() then
434 - resethue = act:cmp(lib.str.plit 'reset-hue')
434 + resethue = act:cmp( 'reset-hue')
435 435 end
436 436
437 437 if not resethue then
438 438 var shue = co:ppostv('hue')
439 439 var nhue, okhue = lib.math.decparse(shue)
440 440 if okhue and nhue ~= co.ui_hue then
441 441 if nhue == co.srv.cfg.ui_hue
................................................................................
446 446 end
447 447 end
448 448 if resethue then
449 449 co.srv:actor_conf_int_reset(co.who.id, 'ui-accent')
450 450 co.ui_hue = co.srv.cfg.ui_hue
451 451 end
452 452
453 - msg = lib.str.plit 'profile changes saved'
453 + msg = 'profile changes saved'
454 454 --user_refresh = true -- not really necessary here, actually
455 455
456 - elseif path(1):cmp(lib.str.lit 'sec') then
456 + elseif path(1):cmp('sec') then
457 457 credsec_for_uid(co, co.who.id)
458 - elseif path(1):cmp(lib.str.lit 'users') then
458 + elseif path(1):cmp('users') then
459 459 if path.ct >= 3 then
460 460 var userid, ok = lib.math.shorthand.parse(path(2).ptr, path(2).ct)
461 461 if ok then
462 462 var usr = co.srv:actor_fetch_uid(userid)
463 - if usr:ref() then defer usr:free()
464 - if not co.who:overpowers(usr.ptr) then goto nopriv end
465 - end
463 + if usr:ref() then --defer usr:free()
464 + if not co.who:overpowers(usr.ptr) then
465 + usr:free()
466 + goto nopriv
467 + end
468 + else goto badop end
469 + defer usr:free()
470 +
466 471 if path.ct == 4 then
467 472 if path(3):cmp(lib.str.lit 'cred') then
468 473 credsec_for_uid(co, userid)
469 474 end
475 + elseif path.ct == 3 then
476 + var purgestr = co:ppostv("purgestr")
477 + var purgekey = co:ppostv("purgekey")
478 + if purgestr:ref() and purgekey:ref() and purgestr(0) ~= 0 then
479 + if purgestr:cmp(purgekey) then -- destroying account! :O
480 + co.srv:actor_purge_uid(userid)
481 + co:reroute('/conf/users')
482 + return
483 + else msg = 'purge confirmation failed' end
484 + end
485 +
486 + var epithet = co:ppostv("epithet")
487 + var s_rank = co:ppostv("rank")
488 + var s_invites = co:ppostv("invites")
489 + var s_quota = co:ppostv("quota")
490 + var ch_staff = co:ppostv("staff")
491 + var torank: uint16 = usr(0).rights.rank
492 + if ch_staff:ref() and ch_staff:cmp('on') then
493 + if s_rank:ref() then
494 + var rank, rok = lib.math.decparse(s_rank)
495 + if rok and rank <= co.srv.cfg.nranks then
496 + torank = rank
497 + end
498 + elseif usr(0).rights.rank == 0 then
499 + torank = co.who.rights.rank + 1
500 + end
501 + else torank = 0 end
502 +
503 + if co.who.id ~= userid and co.who.rights.rank > 0 then
504 + if (co.who.rights.powers.elevate() and
505 + (torank < usr(0).rights.rank or usr(0).rights.rank == 0) and
506 + (torank > co.who.rights.rank or co.who.rights.rank == 1))
507 + or (co.who.rights.powers.demote() and
508 + (torank > usr(0).rights.rank or torank == 0))
509 + then usr(0).rights.rank = torank end
510 + end
511 +
512 + if s_invites:ref() then
513 + var n_invites, n_invites_ok = lib.math.decparse(s_invites)
514 + if n_invites_ok and n_invites ~= usr(0).rights.invites then
515 + if (n_invites > usr(0).rights.invites and
516 + co.who.rights.powers.elevate() and
517 + co.who.rights.powers.invite())
518 + or (n_invites < usr(0).rights.invites and
519 + co.who.rights.powers.demote())
520 + then usr(0).rights.invites = n_invites end
521 + end
522 + end
523 +
524 + if (co.who.id ~= userid or co.who.rights.rank == 1) and s_quota:ref() then
525 + var n_quota, n_quota_ok = lib.math.decparse(s_quota)
526 + if n_quota_ok and n_quota ~= usr(0).rights.quota then
527 + if (co.who.rights.powers.elevate() and
528 + ((n_quota == 0 and co.who.rights.quota == 0 or co.who.rights.rank == 1) or
529 + (n_quota ~= 0 and (n_quota > usr(0).rights.quota and
530 + (co.who.rights.quota == 0 or
531 + co.who.rights.quota >= n_quota or
532 + co.who.rights.rank == 1)))))
533 + or (co.who.rights.powers.demote() and n_quota ~= 0 and
534 + (n_quota < usr(0).rights.quota or
535 + co.who.rights.rank == 1))
536 + then usr(0).rights.quota = n_quota end
537 + end
538 + end
539 +
540 + if co.who.rights.powers.herald() and
541 + (co.who.id ~= userid or
542 + co.srv.cfg.pol_autoherald or
543 + co.who.rights.rank == 1) then
544 + if epithet:ref() and epithet(0) ~= 0 then
545 + usr(0).epithet = epithet.ptr
546 + else
547 + usr(0).epithet = nil
548 + end
549 + end
550 +
551 + if co.who.id ~= userid then
552 + -- update powers
553 + end
554 + co.srv:actor_save(usr.ptr)
555 + if not msg then msg = 'user record updated' end
470 556 end
471 557 end
472 558 elseif path.ct == 2 and meth == method.post then
473 559 var act = co:ppostv('act')
474 - if act:cmp(lib.str.plit'create') then
560 + if act:cmp('create') then
475 561 var newname = co:ppostv('handle')
476 562 if not newname or not lib.store.actor.handle_validate(newname.ptr) then
477 563 co:complain(400,'invalid handle','the handle you have requested is not valid')
478 564 end
479 565 var tu = co.srv:actor_fetch_xid(newname)
480 566 if tu:ref() then tu:free()
481 567 co:complain(409,'handle clash','that handle conflicts with one that already exists')
................................................................................
486 572 na.handle = newname.ptr
487 573 var newuid = co.srv:actor_create(&na)
488 574 var shid: int8[lib.math.shorthand.maxlen]
489 575 var shidlen = lib.math.shorthand.gen(newuid, &shid[0])
490 576 var url = lib.str.acc{}:compose('/conf/users/',pstring{&shid[0],shidlen}):finalize() defer url:free()
491 577 co:reroute(url.ptr)
492 578 return
493 - elseif act:cmp(lib.str.plit'inst') then
579 + elseif act:cmp('inst') then
494 580 else goto badop end
495 581 end
496 582 end
497 583
498 584 if user_refresh then -- refresh the user info for the renderer
499 585 var usr = co.srv:actor_fetch_uid(co.who.id)
500 586 lib.mem.heapf(co.who)
................................................................................
512 598 ::nopriv:: do co:complain(403,'insufficient privileges','you do not have the necessary powers to perform this action') return end
513 599 ::badop:: do co:complain(400,'bad request','the operation you have requested is not meaningful in this context') return end
514 600 end
515 601
516 602 terra http.user_notices(co: &lib.srv.convo, meth: method.t)
517 603 if meth == method.post then
518 604 var act = co:ppostv('act')
519 - if act:cmp(lib.str.plit'clear') then
605 + if act:cmp('clear') then
520 606 co.srv:actor_conf_int_set(co.who.id, 'notice-clear-time', lib.osclock.time(nil))
521 607 co:reroute('/')
522 608 return
523 609 else goto badop end
524 610 end
525 611
526 612 lib.render.notices(co)
................................................................................
533 619 if co.aid ~= 0 and co.who.id == uid and path.ct == 2 and path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then
534 620 if meth == method.get then
535 621 var view = data.view.media_upload {
536 622 folders = ''
537 623 }
538 624 var pg = view:poolstr(&co.srv.pool) -- defer pg:free()
539 625 co:stdpage([lib.srv.convo.page] {
540 - title = lib.str.plit'media :: upload';
541 - class = lib.str.plit'media upload';
626 + title = 'media :: upload';
627 + class = 'media upload';
542 628 cache = false; body = pg;
543 629 })
544 630 elseif meth == method.post_file then
545 631 var desc = pstring.null()
546 632 var folder = pstring.null()
547 633 var mime = pstring.null()
548 634 var name = pstring.null()
549 635 var body = binblob.null()
550 636 for i=0, co.uploads.sz do var up = co.uploads.storage.ptr + i
551 637 if up.body.ct > 0 then
552 - if up.field:cmp(lib.str.plit'desc') then
638 + if up.field:cmp('desc') then
553 639 desc = up.body
554 - elseif up.field:cmp(lib.str.plit'folder') then
640 + elseif up.field:cmp('folder') then
555 641 folder = up.body
556 - elseif up.field:cmp(lib.str.plit'file') then
642 + elseif up.field:cmp('file') then
557 643 mime = up.ctype
558 644 body = binblob {ptr = [&uint8](up.body.ptr), ct = up.body.ct}
559 645 name = up.filename
560 646 end
561 647 end
562 648 end
563 649 if not body then goto badop end
................................................................................
577 663
578 664 var url = lib.str.acc{}:compose('/media/a/',pstring{&idbuf[0],idlen}):finalize()
579 665 co:reroute(url.ptr)
580 666 url:free()
581 667 else goto badop end
582 668 elseif co.aid ~= 0 and path.ct == 4 and path(1):cmp(lib.str.lit'a') and meth==method.post then
583 669 var act = co:ppostv('act')
584 - if not act or not act:cmp(lib.str.plit'confirm') then goto badop end
670 + if not act or not act:cmp('confirm') then goto badop end
585 671 var artid, aok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
586 672 if not aok then goto e404 end
587 673 var art = co.srv:artifact_fetch(uid,artid)
588 674 if not art then goto e404 end
589 675 defer art:free()
590 676
591 677 if path(3):cmp(lib.str.lit'avi') then
................................................................................
691 777 elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
692 778 if not meth_get(meth) then goto wrongmeth end
693 779 if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end
694 780 elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then
695 781 http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5})
696 782 elseif lib.str.ncmp('/file/', uri.ptr, 6) == 0 then
697 783 http.file_serve_raw(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 6, ct = uri.ct - 6})
698 - elseif uri:cmp(lib.str.plit '/notices') then
784 + elseif uri:cmp( '/notices') then
699 785 if co.aid == 0 then co:reroute('/login') return end
700 786 http.user_notices(co,meth)
701 - elseif uri:cmp(lib.str.plit '/compose') then
787 + elseif uri:cmp( '/compose') then
702 788 if co.aid == 0 then co:reroute('/login') return end
703 789 http.post_compose(co,meth)
704 - elseif uri:cmp(lib.str.plit '/login') then
790 + elseif uri:cmp( '/login') then
705 791 if co.aid == 0
706 792 then http.login_form(co, meth)
707 793 else co:reroute('/')
708 794 end
709 - elseif uri:cmp(lib.str.plit '/logout') then
795 + elseif uri:cmp( '/logout') then
710 796 if co.aid == 0
711 797 then goto notfound
712 798 else co:reroute_cookie('/','auth=; Path=/')
713 799 end
714 800 else -- hierarchical routes
715 801 var path = lib.http.hier(&co.srv.pool, uri) --defer path:free()
716 802 if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then