284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
|
lib.render.tweet_page(co, path, post.ptr)
do return end
::badurl:: do co:complain(404, 'invalid URL', 'this URL does not reference extant content or functionality') return end
::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
::noauth:: do co:complain(401, 'unauthorized', 'you have not supplied the necessary credentials to perform this operation') return end
end
terra http.configure(co: &lib.srv.convo, path: hpath, meth: method.t)
var msg = pstring.null()
-- first things first, do priv checks
if path.ct >= 1 then
if not co.who.rights.powers.config() and (
path(1):cmp(lib.str.lit 'srv') or
................................................................................
co.ui_hue = co.srv.cfg.ui_hue
end
msg = lib.str.plit 'profile changes saved'
--user_refresh = true -- not really necessary here, actually
elseif path(1):cmp(lib.str.lit 'sec') then
var act = co:ppostv('act')
if act:cmp(lib.str.plit 'invalidate') then
lib.dbg('setting user\'s cookie validation time to now')
co.who.source:auth_sigtime_user_alter(co.who.id, lib.osclock.time(nil))
-- 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
co:installkey('/conf/sec',co.aid)
return
end
elseif path(1):cmp(lib.str.lit 'users') then
if path.ct >= 3 then
var userid, ok = lib.math.shorthand.parse(path(2).ptr, path(2).ct)
if ok then
var usr = co.srv:actor_fetch_uid(userid)
if usr:ref() then defer usr:free()
if not co.who:overpowers(usr.ptr) then goto nopriv end
end
end
elseif path.ct == 2 then
end
end
if user_refresh then -- refresh the user info for the renderer
var usr = co.srv:actor_fetch_uid(co.who.id)
lib.mem.heapf(co.who)
co.who = usr.ptr
................................................................................
co:reroute(go)
return
end
end
lib.render.conf(co,path,msg)
do return end
::nopriv:: co:complain(403,'insufficient privileges','you do not have the necessary powers to perform this action')
end
terra http.user_notices(co: &lib.srv.convo, meth: method.t)
if meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit'clear') then
co.srv:actor_conf_int_set(co.who.id, 'notice-clear-time', lib.osclock.time(nil))
................................................................................
lib.render.notices(co)
do return end
::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
end
terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t)
if meth == method.post then
goto badop
end
if path.ct == 2 and path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then
if meth == method.get then
var view = data.view.media_upload {
folders = ''
}
var pg = view:tostr() defer pg:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit'media :: upload';
................................................................................
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(id,&idbuf[0])
var url = lib.str.acc{}:compose('/media/a/',pstring{&idbuf[0],idlen}):finalize()
co:reroute(url.ptr)
url:free()
else goto badop end
else
if meth == method.post then goto badop end
lib.render.media_gallery(co,path,co.who.id,nil)
end
do return end
::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded by this user') return end
end
................................................................................
::[send]:: page:send(co.con) return true
end
end
terra http.local_avatar(co: &lib.srv.convo, handle: lib.mem.ptr(int8))
-- TODO retrieve user avatars
co:reroute('/s/default-avatar.webp')
end
terra http.file_serve_raw(co: &lib.srv.convo, id: lib.mem.ptr(int8))
var id, idok = lib.math.shorthand.parse(id.ptr, id.ct)
if not idok then goto e404 end
var data, mime = co.srv:artifact_load(id)
if not data then goto e404 end
do defer data:free() defer mime:free()
var safemime = mime
-- TODO this is not a satisfactory solution; it's a bandaid on a gaping
-- chest wound. ultimately we need to compile a whitelist of safe mime
-- types as part of mimelib, but that is no small task. for now, this
-- will keep the patient from immediately bleeding out
if mime:cmp(lib.str.plit'text/html') or
mime:cmp(lib.str.plit'text/xml') or
mime:cmp(lib.str.plit'application/xhtml+xml') or
mime:cmp(lib.str.plit'application/vnd.wap.xhtml+xml')
then -- danger will robinson
safemime = lib.str.plit'text/plain'
elseif mime:cmp(lib.str.plit'application/x-shockwave-flash') then
safemime = lib.str.plit'application/octet-stream'
end
lib.net.mg_printf(co.con, "HTTP/1.1 200 OK\r\nContent-Type: %.*s\r\nContent-Length: %llu\r\nContent-Security-Policy: sandbox; default-src 'none'; form-action 'none'; navigate-to 'none';\r\nX-Content-Options: nosniff\r\n\r\n", safemime.ct, safemime.ptr, data.ct + 2)
lib.net.mg_send(co.con, data.ptr, data.ct)
lib.net.mg_send(co.con, '\r\n', 2)
return end
::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded to this instance') return end
end
-- entry points
terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
................................................................................
http.actor_profile_uid(co, path, meth)
elseif path.ct > 1 and path(0):cmp(lib.str.lit('post')) then
http.tweet_page(co, path, meth)
elseif path(0):cmp(lib.str.lit('tl')) then
http.timeline(co, path)
elseif path(0):cmp(lib.str.lit('media')) then
if co.aid == 0 then goto unauth end
http.media_manager(co, path, meth)
elseif path(0):cmp(lib.str.lit('doc')) then
if not meth_get(meth) then goto wrongmeth end
http.documentation(co, path)
elseif path(0):cmp(lib.str.lit('conf')) then
if co.aid == 0 then goto unauth end
http.configure(co,path,meth)
else goto notfound end
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
<
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
...
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
|
lib.render.tweet_page(co, path, post.ptr)
do return end
::badurl:: do co:complain(404, 'invalid URL', 'this URL does not reference extant content or functionality') return end
::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
::noauth:: do co:complain(401, 'unauthorized', 'you have not supplied the necessary credentials to perform this operation') return end
end
local terra
credsec_for_uid(co: &lib.srv.convo, uid: uint64)
var act = co:ppostv('act')
if act:cmp(lib.str.plit 'invalidate') then
lib.dbg('setting user\'s cookie validation time to now')
co.who.source:auth_sigtime_user_alter(uid, lib.osclock.time(nil))
-- 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
co:installkey('/conf/sec',co.aid)
return
elseif act:cmp(lib.str.plit 'newcred') then
var cmt = co:ppostv('comment')
var pw = co:ppostv('newpw')
if pw:ref() then
var cpw = co:ppostv('rptpw')
if not pw:cmp(cpw) then
co:complain(400,'enrollment failure','the passwords you supplied do not match')
return
end
co.srv:auth_attach_pw(uid, false, pw, cmt)
co:reroute('?')
return
else
var key = co:ppostv('newkey')
if key:ref() then
end
end
end
co:complain(400,'bad request','the operation you have requested is not meaningful in this context')
end
terra http.configure(co: &lib.srv.convo, path: hpath, meth: method.t)
var msg = pstring.null()
-- first things first, do priv checks
if path.ct >= 1 then
if not co.who.rights.powers.config() and (
path(1):cmp(lib.str.lit 'srv') or
................................................................................
co.ui_hue = co.srv.cfg.ui_hue
end
msg = lib.str.plit 'profile changes saved'
--user_refresh = true -- not really necessary here, actually
elseif path(1):cmp(lib.str.lit 'sec') then
credsec_for_uid(co, co.who.id)
elseif path(1):cmp(lib.str.lit 'users') then
if path.ct >= 3 then
var userid, ok = lib.math.shorthand.parse(path(2).ptr, path(2).ct)
if ok then
var usr = co.srv:actor_fetch_uid(userid)
if usr:ref() then defer usr:free()
if not co.who:overpowers(usr.ptr) then goto nopriv end
end
end
elseif path.ct == 2 and meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit'create') then
var newname = co:ppostv('handle')
if not newname or not lib.store.actor.handle_validate(newname.ptr) then
co:complain(400,'invalid handle','the handle you have requested is not valid')
end
var tu = co.srv:actor_fetch_xid(newname)
if tu:ref() then tu:free()
co:complain(409,'handle clash','that handle conflicts with one that already exists')
return
end
var kbuf: uint8[lib.crypt.const.maxdersz]
var na = lib.store.actor.mk(&kbuf[0])
na.handle = newname.ptr
var newuid = co.srv:actor_create(&na)
var shid: int8[lib.math.shorthand.maxlen]
var shidlen = lib.math.shorthand.gen(newuid, &shid[0])
var url = lib.str.acc{}:compose('/conf/users/',pstring{&shid[0],shidlen}):finalize() defer url:free()
co:reroute(url.ptr)
return
elseif act:cmp(lib.str.plit'inst') then
else goto badop end
end
end
if user_refresh then -- refresh the user info for the renderer
var usr = co.srv:actor_fetch_uid(co.who.id)
lib.mem.heapf(co.who)
co.who = usr.ptr
................................................................................
co:reroute(go)
return
end
end
lib.render.conf(co,path,msg)
do return end
::nopriv:: do co:complain(403,'insufficient privileges','you do not have the necessary powers to perform this action') return end
::badop:: do co:complain(400,'bad request','the operation you have requested is not meaningful in this context') return end
end
terra http.user_notices(co: &lib.srv.convo, meth: method.t)
if meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit'clear') then
co.srv:actor_conf_int_set(co.who.id, 'notice-clear-time', lib.osclock.time(nil))
................................................................................
lib.render.notices(co)
do return end
::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
end
terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t, uid: uint64)
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
if meth == method.get then
var view = data.view.media_upload {
folders = ''
}
var pg = view:tostr() defer pg:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit'media :: upload';
................................................................................
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(id,&idbuf[0])
var url = lib.str.acc{}:compose('/media/a/',pstring{&idbuf[0],idlen}):finalize()
co:reroute(url.ptr)
url:free()
else goto badop end
elseif co.aid ~= 0 and path.ct == 4 and path(1):cmp(lib.str.lit'a') and meth==method.post then
var act = co:ppostv('act')
if not act or not act:cmp(lib.str.plit'confirm') then goto badop end
var artid, aok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
if not aok then goto e404 end
var art = co.srv:artifact_fetch(uid,artid)
if not art then goto e404 end
defer art:free()
if path(3):cmp(lib.str.lit'avi') then
-- user wants to set avatar
co.who.avatarid = artid
co.srv:actor_save(co.who)
co:reroute('/conf/avi')
elseif path(3):cmp(lib.str.lit'del') then
co.srv:artifact_disclaim(co.who.id, artid)
co:reroute('/media')
else goto badop end
else
if meth == method.post then goto badop end
lib.render.media_gallery(co,path,uid,nil)
end
do return end
::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded by this user') return end
end
................................................................................
::[send]:: page:send(co.con) return true
end
end
terra http.local_avatar(co: &lib.srv.convo, handle: lib.mem.ptr(int8))
-- TODO retrieve user avatars
var usr = co.srv:actor_fetch_xid(handle)
if not usr then
goto default end
if usr(0).origin == 0 then
if usr(0).avatarid == 0 then goto default end
var avi, mime = co.srv:artifact_load(usr(0).avatarid)
if not avi then goto default end
defer avi:free() defer mime:free()
co:bytestream(mime,avi)
else
co:reroute(usr(0).avatar)
end
do return end
::default:: co:reroute('/s/default-avatar.webp')
end
terra http.file_serve_raw(co: &lib.srv.convo, id: lib.mem.ptr(int8))
var id, idok = lib.math.shorthand.parse(id.ptr, id.ct)
if not idok then goto e404 end
var data, mime = co.srv:artifact_load(id)
if not data then goto e404 end
do defer data:free() defer mime:free()
co:bytestream(mime,data)
return end
::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded to this instance') return end
end
-- entry points
terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
................................................................................
http.actor_profile_uid(co, path, meth)
elseif path.ct > 1 and path(0):cmp(lib.str.lit('post')) then
http.tweet_page(co, path, meth)
elseif path(0):cmp(lib.str.lit('tl')) then
http.timeline(co, path)
elseif path(0):cmp(lib.str.lit('media')) then
if co.aid == 0 then goto unauth end
http.media_manager(co, path, meth, co.who.id)
elseif path(0):cmp(lib.str.lit('doc')) then
if not meth_get(meth) then goto wrongmeth end
http.documentation(co, path)
elseif path(0):cmp(lib.str.lit('conf')) then
if co.aid == 0 then goto unauth end
http.configure(co,path,meth)
else goto notfound end
|