parsav  Diff

Differences From Artifact [881176d2e1]:

To Artifact [b4f49ac3f6]:


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