parsav  Check-in [e1ff4f301e]

Overview
Comment:get some user admin shit working, general cleanups
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e1ff4f301edd5ee416d023d88a3270904f2b7397c13939ee62c2fcb2232784a4
User & Date: lexi on 2021-01-10 14:26:47
Other Links: manifest | tags
Context
2021-01-10
16:44
add avatar panel check-in: 8398fcda5a user: lexi tags: trunk
14:26
get some user admin shit working, general cleanups check-in: e1ff4f301e user: lexi tags: trunk
11:17
add follow notices check-in: 00a6815988 user: lexi tags: trunk
Changes

Modified mime.t from [2e40a434e4] to [b6a24abaaf].

2
3
4
5
6
7
8



9
10
11
12
13
	['text/csrc'] = {
		ext = 'c', lang = 'c';
	};
	['text/html'] = {
		ext = 'html', lang = 'html';
		unsafe = true;
	};



	['text/markdown'] = {
		formatter = 'smackdown';
		ext = 'md', doc = true;
	};
}







>
>
>





2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	['text/csrc'] = {
		ext = 'c', lang = 'c';
	};
	['text/html'] = {
		ext = 'html', lang = 'html';
		unsafe = true;
	};
	['text/x-lua'] = {
		ext = 'lua', lang = 'lua';
	};
	['text/markdown'] = {
		formatter = 'smackdown';
		ext = 'md', doc = true;
	};
}

Modified render/docpage.t from [8016afcf69] to [9f2f406de7].

85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
	if started then list:lpush('</ol>') end
end

local terra 
render_docpage(co: &lib.srv.convo, pg: pref)
	var nullprivs: lib.store.powerset nullprivs:clear()
	if not pg then -- display index
		var list: lib.str.acc list:compose('<ul>')

		var [pages] = array([allpages])
		for i=0,[pages.type.N] do
			if pages[i].parent == 0 and (pages[i].priv:sz() == 0 or
				(co.aid ~= 0 and (co.who.rights.powers
					and pages[i].priv):sz() > 0)) then
				list:lpush('<li><a href="/doc/'):rpush(pages[i].name):lpush('">')
					:rpush(pages[i].title):lpush('</a>')
................................................................................
					pushbranches(&list, i, nullprivs)
				end
				list:lpush('</li>')
			end
		end
		list:lpush('</ul>')

		var bp = list:finalize()
		co:stdpage(page {
			title = 'documentation';
			body = bp;
			class = P'doc listing';
			cache = false;
		})
		bp:free()
	else showpage(co, pg) end
end

return render_docpage







|
>







 







<


|



<




85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
104
105
106
107
108
109
110

111
112
113
114
115
116

117
118
119
120
	if started then list:lpush('</ol>') end
end

local terra 
render_docpage(co: &lib.srv.convo, pg: pref)
	var nullprivs: lib.store.powerset nullprivs:clear()
	if not pg then -- display index
		var list = co:stra(256)
		list:lpush('<ul>')
		var [pages] = array([allpages])
		for i=0,[pages.type.N] do
			if pages[i].parent == 0 and (pages[i].priv:sz() == 0 or
				(co.aid ~= 0 and (co.who.rights.powers
					and pages[i].priv):sz() > 0)) then
				list:lpush('<li><a href="/doc/'):rpush(pages[i].name):lpush('">')
					:rpush(pages[i].title):lpush('</a>')
................................................................................
					pushbranches(&list, i, nullprivs)
				end
				list:lpush('</li>')
			end
		end
		list:lpush('</ul>')


		co:stdpage(page {
			title = 'documentation';
			body = list:finalize();
			class = P'doc listing';
			cache = false;
		})

	else showpage(co, pg) end
end

return render_docpage

Modified render/media-gallery.t from [5c4e9df122] to [18e4a71c1d].

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
					lib.str.cmp(art(0).mime, 'application/sql') == 0
					-- and so on (we need a mimelib at some point) --
				then
					var view = data.view.media_text(viewerprops)
					var text, mime = co.srv:artifact_load(id) mime:free()
					var san = lib.html.sanitize(&co.srv.pool,pstr{[rawstring](text.ptr),text.ct}, false)
					text:free()
					view.text = lib.str.acc{}:compose('<pre>',san,'</pre>'):finalize()
					san:free()
					var pg = view:tostr()
					view.text:free()
					co:stdpage([lib.srv.convo.page] {
						title = lib.str.plit'media :: text';
						class = lib.str.plit'media viewer text';
						cache = false, body = pg;
					})
					pg:free()
				else co:complain(500,'bad file type','this file type is not supported') end
			elseif path.ct == 4 then
				var act = path(3)
				var curl = lib.str.acc{}:compose(pfx, '/media/a/', path(2)):finalize()
				defer curl:free()
				if act:cmp(lib.str.lit'avi') and lib.str.ncmp(art(0).mime, 'image/', 6) == 0 then
					co:confirm('set avatar', 'are you sure you want this image to be your new avatar?',curl)
				elseif act:cmp(lib.str.lit'del') then
					co:confirm('delete', 'are you sure you want to permanently delete this artifact?',curl)
				else goto e404 end
			end
		else
................................................................................
				folders = pstr{'',0};
				directory = pstr{'',0};
				images = pstr{'',0};
				pfx = pfx;
			}

			if folders.ct > 0 then
				var fa: lib.str.acc fa:pool(&co.srv.pool,128)
				var fldr = co:pgetv('folder')
				for i=0,folders.ct do
					var ule = lib.html.urlenc(&co.srv.pool,folders(i), true) -- defer ule:free()
					var san = lib.html.sanitize(&co.srv.pool,folders(i), true) -- defer san:free()
					fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule)
						:lpush('">'):ppush(san):lpush('</a>')
					lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct})







|
|
|
|





|



|
|







 







|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
					lib.str.cmp(art(0).mime, 'application/sql') == 0
					-- and so on (we need a mimelib at some point) --
				then
					var view = data.view.media_text(viewerprops)
					var text, mime = co.srv:artifact_load(id) mime:free()
					var san = lib.html.sanitize(&co.srv.pool,pstr{[rawstring](text.ptr),text.ct}, false)
					text:free()
					view.text = co:qstr('<pre>',san,'</pre>')
					--san:free()
					var pg = view:poolstr(&co.srv.pool)
					--view.text:free()
					co:stdpage([lib.srv.convo.page] {
						title = lib.str.plit'media :: text';
						class = lib.str.plit'media viewer text';
						cache = false, body = pg;
					})
					--pg:free()
				else co:complain(500,'bad file type','this file type is not supported') end
			elseif path.ct == 4 then
				var act = path(3)
				var curl = co:qstr('/media/a/', path(2))
				-- defer curl:free()
				if act:cmp(lib.str.lit'avi') and lib.str.ncmp(art(0).mime, 'image/', 6) == 0 then
					co:confirm('set avatar', 'are you sure you want this image to be your new avatar?',curl)
				elseif act:cmp(lib.str.lit'del') then
					co:confirm('delete', 'are you sure you want to permanently delete this artifact?',curl)
				else goto e404 end
			end
		else
................................................................................
				folders = pstr{'',0};
				directory = pstr{'',0};
				images = pstr{'',0};
				pfx = pfx;
			}

			if folders.ct > 0 then
				var fa = co:stra(128)
				var fldr = co:pgetv('folder')
				for i=0,folders.ct do
					var ule = lib.html.urlenc(&co.srv.pool,folders(i), true) -- defer ule:free()
					var san = lib.html.sanitize(&co.srv.pool,folders(i), true) -- defer san:free()
					fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule)
						:lpush('">'):ppush(san):lpush('</a>')
					lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct})

Modified render/profile.t from [cdb26ba3d8] to [849244d87f].

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
99
100
101
102
103
104
105
106
107
108
109
110
		var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1))
		var sn_mutuals   = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1))
	var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>'
	if actor.bio ~= nil then
		bio = lib.smackdown.html(&co.srv.pool,cs(actor.bio),false)
	end
	var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free()
	var comments: lib.str.acc comments:pool(&co.srv.pool,64)

	if co.srv.cfg.master == actor.id then
		var foundertxt = lib.str.plit 'founder'
		if co.srv.cfg.ui_cue_founder:ref() then
			if co.srv.cfg.ui_cue_founder.ct == 0 -- empty string, suppress field
				then foundertxt = pstr.null()
				else foundertxt = co.srv.cfg.ui_cue_founder
................................................................................
		auxbtn = auxp;
	}
	if comments.sz > 0 then profile.remarks = comments:finalize() end

	var ret = profile:poolstr(&co.srv.pool)
	-- auxp:free() 
	--if actor.bio ~= nil then bio:free() end
	if comments.sz > 0 then profile.remarks:free() end
	return ret
end

return render_profile







|







 







|




37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
99
100
101
102
103
104
105
106
107
108
109
110
		var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1))
		var sn_mutuals   = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1))
	var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>'
	if actor.bio ~= nil then
		bio = lib.smackdown.html(&co.srv.pool,cs(actor.bio),false)
	end
	var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free()
	var comments = co:stra(64)

	if co.srv.cfg.master == actor.id then
		var foundertxt = lib.str.plit 'founder'
		if co.srv.cfg.ui_cue_founder:ref() then
			if co.srv.cfg.ui_cue_founder.ct == 0 -- empty string, suppress field
				then foundertxt = pstr.null()
				else foundertxt = co.srv.cfg.ui_cue_founder
................................................................................
		auxbtn = auxp;
	}
	if comments.sz > 0 then profile.remarks = comments:finalize() end

	var ret = profile:poolstr(&co.srv.pool)
	-- auxp:free() 
	--if actor.bio ~= nil then bio:free() end
	--if comments.sz > 0 then profile.remarks:free() end
	return ret
end

return render_profile

Modified route.t from [47b3eeec8d] to [efbc5e4a8e].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
...
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
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
...
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
...
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
462
463
464


465



466
467
468
469









470












471




























































472
473
474
475
476
477
478
479
480
481
...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
...
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
...
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
...
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t)
	var rel: lib.store.relationship
	if co.aid ~= 0 then
		rel = co.srv:actor_rel_calc(co.who.id, actor.id)
		if meth == method.post then
			var act = co:ppostv('act')
			if rel.recip.block() then
				if act:cmp(lib.str.plit 'follow') or act:cmp(lib.str.plit 'subscribe') then
					co:complain(403,'blocked','you cannot follow a user you are blocked by') return
				end
			end
			if act:cmp(lib.str.plit 'block') and not rel.rel.block() then
				(rel.rel.block << true) ; (rel.recip.follow << false)
				co.srv:actor_rel_create([lib.store.relation.idvmap.block], co.who.id, actor.id)
				co.srv:actor_rel_destroy([lib.store.relation.idvmap.follow], actor.id, co.who.id)
			else
				[(function()
					local tests = quote co:complain(400,'bad request','the action you have attempted on this user is not meaningful') return end
					for i,v in ipairs(lib.store.relation.members) do
						tests = quote
							if [v ~= 'block'] and act:cmp(lib.str.plit([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
								(rel.rel.[v] << true)
								co.srv:actor_rel_create([lib.store.relation.idvmap[v]], co.who.id, actor.id)
							elseif act:cmp(lib.str.plit(['un'..v])) and rel.rel.[v]() then
								(rel.rel.[v] << false)
								co.srv:actor_rel_destroy([lib.store.relation.idvmap[v]], co.who.id, actor.id)
							else [tests] end
						end
					end
					return tests
				end)()]
................................................................................

	http.actor_profile(co,actor.ptr,meth)
end

terra http.login_form(co: &lib.srv.convo, meth: method.t)
	if meth_get(meth) then
		-- request a username
		lib.render.login(co, nil, nil, lib.str.plit(nil))
	elseif meth == method.post then
		var usn, usnl = co:postv('user')
		var am, aml = co:postv('authmethod')
		var chrs, chrsl = co:postv('response')
		var cs, authok = co.srv:actor_auth_how(co.peer, usn)
		var act = co.srv:actor_fetch_xid([lib.mem.ptr(int8)] {
			ptr = usn, ct = usnl
		})
		if authok == false then
			lib.render.login(co, nil, nil, lib.str.plit'access denied')
			return
		end
		var fakeact = false
		var fakeactor: lib.store.actor
		if act.ptr == nil then
			-- the user is known to us but has not yet claimed an
			-- account on the server. create a template for the
................................................................................
			}
			act.ct = 1
			act.ptr = &fakeactor
			act.ptr.rights = lib.store.rights_default()
		end
		if am == nil then
			-- pick an auth method
			lib.render.login(co, act.ptr, &cs, lib.str.plit(nil))
		else var aid: uint64 = 0
			lib.dbg('authentication attempt beginning')
			-- attempt login with provided method
			if lib.str.ncmp('pw', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
				aid = co.srv:actor_auth_pw(co.peer,
					[lib.mem.ptr(int8)]{ptr=usn,ct=usnl},
					[lib.mem.ptr(int8)]{ptr=chrs,ct=chrsl})
................................................................................
			elseif lib.str.ncmp('otp', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
				lib.dbg('using otp auth')
				-- ··· --
			else lib.dbg('invalid auth method') end

			-- error out
			if aid == 0 then
				lib.render.login(co, nil, nil, lib.str.plit 'authentication failure')
			else
				co:installkey('/',aid)
			end
		end
		if act.ptr ~= nil and fakeact == false then act:free() end
	else
		::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
................................................................................
			end
			return
		elseif path(2):cmp(lib.str.lit 'del') then
			if meth_get(meth) then
				var conf: data.view.confirm
				if post:ref() then
					conf = data.view.confirm {
						title = lib.str.plit 'delete post';
						query = lib.str.plit 'are you sure you want to delete this post?';
						cancel = lnkp
					}
				else
					conf = data.view.confirm {
						title = lib.str.plit 'cancel retweet';
						query = lib.str.plit 'are you sure you want to undo this retweet?';
						cancel = lib.str.plit'/';
					}
				end
				var fr = co.srv.pool:frame()
				var body = conf:poolstr(&co.srv.pool) --defer body:free()
				co:stdpage([lib.srv.convo.page] {
					title = lib.str.plit 'post :: delete';
					class = lib.str.plit 'query';
					body = body; cache = false;
				})
				co.srv.pool:reset(fr)
				return
			elseif meth == method.post then
				var act = co:ppostv('act')
				if act:cmp(lib.str.plit 'confirm') then
					if post:ref() then
						post(0).source:post_destroy(post(0).id)
					elseif rt.kind ~= 0 then
						co.srv:post_act_cancel(pid)
					end
					co:reroute('/') -- TODO maybe return to parent or conversation if possible
					return
................................................................................
			end
		else goto badurl end
	end

	if post:ref() and meth == method.post then
		if co.aid == 0 then goto noauth end
		var act = co:ppostv('act')
		if act:cmp(lib.str.plit 'like') and not co.srv:post_liked_uid(co.who.id,pid) then
			co.srv:post_like(co.who.id, pid, false)
			post.ptr.likes = post.ptr.likes + 1
		elseif act:cmp(lib.str.plit 'dislike') and co.srv:post_liked_uid(co.who.id,pid) then
			co.srv:post_like(co.who.id, pid, true)
			post.ptr.likes = post.ptr.likes - 1
		elseif act:cmp(lib.str.plit 'rt') then
			co.srv:post_retweet(co.who.id, pid, false)
			post.ptr.rts = post.ptr.rts + 1
		elseif act:cmp(lib.str.plit 'post') then
			var replytext = co:ppostv('post')
			var acl = co:ppostv('acl')
			var subj = co:ppostv('subject')
			if not acl then acl = lib.str.plit 'all' end
			if not replytext then goto badop end
			
			var reply = lib.store.post {
				author = co.who.id, parent = pid;
				subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
			}

................................................................................
	::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')
	lib.dbg('showing credentials')
	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('?',co.aid)
		return
	elseif act:cmp(lib.str.plit 'newcred') then
		var cmt = co:ppostv('comment')
		var pw = co:ppostv('newpw')
		var aid: uint64 = 0
		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')
................................................................................
			lib.dbg('setting credential restrictions')
			var privs = [(function()
				local check = quote end
				local me = symbol(lib.store.privset)
				for i,v in ipairs(lib.store.privset.members) do
					check = quote [check]
						var val = co:pgetv(['allow-' .. v])
						if val:ref() and val:cmp(lib.str.plit'on')
							then ([me].[v] << true)
							else ([me].[v] << false)
						end
					end
				end
				return quote
					var [me]
................................................................................
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 >= 2 then
		if not co.who.rights.powers.config() and (
			path(1):cmp(lib.str.lit 'srv')   or
			path(1):cmp(lib.str.lit 'badge') or
			path(1):cmp(lib.str.lit 'emoji')
		) then goto nopriv

		elseif not co.who.rights.powers.rebrand() and (
			path(1):cmp(lib.str.lit 'brand')
		) then goto nopriv

		elseif not co.who.rights.powers.account() and (
			path(1):cmp(lib.str.lit 'profile') or
			path(1):cmp(lib.str.lit 'sec') or
			path(1):cmp(lib.str.lit 'avi') or
			path(1):cmp(lib.str.lit 'ui')
		) then goto nopriv

		elseif not co.who.rights.powers:affect_users() and (
			path(1):cmp(lib.str.lit 'users')
		) then goto nopriv end
	end

................................................................................
			if co.who.bio ~= nil and @co.who.bio == 0 then co.who.bio = nil end
			if co.who.nym ~= nil and @co.who.nym == 0 then co.who.nym = nil end
			co.who.source:actor_save(co.who)

			var act = co:ppostv('act')
			var resethue = false
			if act:ref() then
				resethue = act:cmp(lib.str.plit 'reset-hue')
			end

			if not resethue then
				var shue = co:ppostv('hue')
				var nhue, okhue = lib.math.decparse(shue)
				if okhue and nhue ~= co.ui_hue then
					if nhue == co.srv.cfg.ui_hue
................................................................................
				end
			end
			if resethue then
				co.srv:actor_conf_int_reset(co.who.id, 'ui-accent')
				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



					if path.ct == 4 then
						if path(3):cmp(lib.str.lit 'cred') then
							credsec_for_uid(co, userid)
						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')
................................................................................
					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)
................................................................................
	::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))
			co:reroute('/')
			return
		else goto badop end
	end

	lib.render.notices(co)
................................................................................
	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:poolstr(&co.srv.pool) -- defer pg:free()
			co:stdpage([lib.srv.convo.page] {
				title = lib.str.plit'media :: upload';
				class = lib.str.plit'media upload';
				cache = false; body = pg;
			})
		elseif meth == method.post_file then
			var desc = pstring.null()
			var folder = pstring.null()
			var mime = pstring.null()
			var name = pstring.null()
			var body = binblob.null()
			for i=0, co.uploads.sz do var up = co.uploads.storage.ptr + i
				if up.body.ct > 0 then
					if up.field:cmp(lib.str.plit'desc') then
						desc = up.body
					elseif up.field:cmp(lib.str.plit'folder') then
						folder = up.body
					elseif up.field:cmp(lib.str.plit'file') then
						mime = up.ctype
						body = binblob {ptr = [&uint8](up.body.ptr), ct = up.body.ct}
						name = up.filename
					end
				end
			end
			if not body then goto badop end
................................................................................

			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
................................................................................
	elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
		if not meth_get(meth) then goto wrongmeth end
		if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end
	elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then
		http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5})
	elseif lib.str.ncmp('/file/', uri.ptr, 6) == 0 then
		http.file_serve_raw(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 6, ct = uri.ct - 6})
	elseif uri:cmp(lib.str.plit '/notices') then
		if co.aid == 0 then co:reroute('/login') return end
		http.user_notices(co,meth)
	elseif uri:cmp(lib.str.plit '/compose') then
		if co.aid == 0 then co:reroute('/login') return end
		http.post_compose(co,meth)
	elseif uri:cmp(lib.str.plit '/login') then
		if co.aid == 0
			then http.login_form(co, meth)
			else co:reroute('/')
		end
	elseif uri:cmp(lib.str.plit '/logout') then
		if co.aid == 0
			then goto notfound
			else co:reroute_cookie('/','auth=; Path=/')
		end
	else -- hierarchical routes
		var path = lib.http.hier(&co.srv.pool, uri) --defer path:free()
		if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then







|



|








|


|







 







|









|







 







|







 







|







 







|
|




|
|
|





|
|






|







 







|


|


|


|



|







 







|





|







 







|







 







|
|
|



|



|
|
|
|







 







|







 







|


|

|




|
|
>
>
|
>
>
>




>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


|







 







|







 







|







 







|
|










|

|

|







 







|







 







|


|


|




|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
...
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
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
...
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
...
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
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
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
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t)
	var rel: lib.store.relationship
	if co.aid ~= 0 then
		rel = co.srv:actor_rel_calc(co.who.id, actor.id)
		if meth == method.post then
			var act = co:ppostv('act')
			if rel.recip.block() then
				if act:cmp( 'follow') or act:cmp( 'subscribe') then
					co:complain(403,'blocked','you cannot follow a user you are blocked by') return
				end
			end
			if act:cmp( 'block') and not rel.rel.block() then
				(rel.rel.block << true) ; (rel.recip.follow << false)
				co.srv:actor_rel_create([lib.store.relation.idvmap.block], co.who.id, actor.id)
				co.srv:actor_rel_destroy([lib.store.relation.idvmap.follow], actor.id, co.who.id)
			else
				[(function()
					local tests = quote co:complain(400,'bad request','the action you have attempted on this user is not meaningful') return end
					for i,v in ipairs(lib.store.relation.members) do
						tests = quote
							if [v ~= 'block'] and act:cmp(([v])) and not rel.rel.[v]() then -- rely on dead code elimination :/
								(rel.rel.[v] << true)
								co.srv:actor_rel_create([lib.store.relation.idvmap[v]], co.who.id, actor.id)
							elseif act:cmp((['un'..v])) and rel.rel.[v]() then
								(rel.rel.[v] << false)
								co.srv:actor_rel_destroy([lib.store.relation.idvmap[v]], co.who.id, actor.id)
							else [tests] end
						end
					end
					return tests
				end)()]
................................................................................

	http.actor_profile(co,actor.ptr,meth)
end

terra http.login_form(co: &lib.srv.convo, meth: method.t)
	if meth_get(meth) then
		-- request a username
		lib.render.login(co, nil, nil, pstring.null())
	elseif meth == method.post then
		var usn, usnl = co:postv('user')
		var am, aml = co:postv('authmethod')
		var chrs, chrsl = co:postv('response')
		var cs, authok = co.srv:actor_auth_how(co.peer, usn)
		var act = co.srv:actor_fetch_xid([lib.mem.ptr(int8)] {
			ptr = usn, ct = usnl
		})
		if authok == false then
			lib.render.login(co, nil, nil, 'access denied')
			return
		end
		var fakeact = false
		var fakeactor: lib.store.actor
		if act.ptr == nil then
			-- the user is known to us but has not yet claimed an
			-- account on the server. create a template for the
................................................................................
			}
			act.ct = 1
			act.ptr = &fakeactor
			act.ptr.rights = lib.store.rights_default()
		end
		if am == nil then
			-- pick an auth method
			lib.render.login(co, act.ptr, &cs, pstring.null())
		else var aid: uint64 = 0
			lib.dbg('authentication attempt beginning')
			-- attempt login with provided method
			if lib.str.ncmp('pw', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
				aid = co.srv:actor_auth_pw(co.peer,
					[lib.mem.ptr(int8)]{ptr=usn,ct=usnl},
					[lib.mem.ptr(int8)]{ptr=chrs,ct=chrsl})
................................................................................
			elseif lib.str.ncmp('otp', am, lib.math.biggest(2,aml)) == 0 and chrs ~= nil then
				lib.dbg('using otp auth')
				-- ··· --
			else lib.dbg('invalid auth method') end

			-- error out
			if aid == 0 then
				lib.render.login(co, nil, nil,  'authentication failure')
			else
				co:installkey('/',aid)
			end
		end
		if act.ptr ~= nil and fakeact == false then act:free() end
	else
		::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
................................................................................
			end
			return
		elseif path(2):cmp(lib.str.lit 'del') then
			if meth_get(meth) then
				var conf: data.view.confirm
				if post:ref() then
					conf = data.view.confirm {
						title =  'delete post';
						query =  'are you sure you want to delete this post?';
						cancel = lnkp
					}
				else
					conf = data.view.confirm {
						title =  'cancel retweet';
						query =  'are you sure you want to undo this retweet?';
						cancel = '/';
					}
				end
				var fr = co.srv.pool:frame()
				var body = conf:poolstr(&co.srv.pool) --defer body:free()
				co:stdpage([lib.srv.convo.page] {
					title =  'post :: delete';
					class =  'query';
					body = body; cache = false;
				})
				co.srv.pool:reset(fr)
				return
			elseif meth == method.post then
				var act = co:ppostv('act')
				if act:cmp( 'confirm') then
					if post:ref() then
						post(0).source:post_destroy(post(0).id)
					elseif rt.kind ~= 0 then
						co.srv:post_act_cancel(pid)
					end
					co:reroute('/') -- TODO maybe return to parent or conversation if possible
					return
................................................................................
			end
		else goto badurl end
	end

	if post:ref() and meth == method.post then
		if co.aid == 0 then goto noauth end
		var act = co:ppostv('act')
		if act:cmp( 'like') and not co.srv:post_liked_uid(co.who.id,pid) then
			co.srv:post_like(co.who.id, pid, false)
			post.ptr.likes = post.ptr.likes + 1
		elseif act:cmp( 'dislike') and co.srv:post_liked_uid(co.who.id,pid) then
			co.srv:post_like(co.who.id, pid, true)
			post.ptr.likes = post.ptr.likes - 1
		elseif act:cmp( 'rt') then
			co.srv:post_retweet(co.who.id, pid, false)
			post.ptr.rts = post.ptr.rts + 1
		elseif act:cmp( 'post') then
			var replytext = co:ppostv('post')
			var acl = co:ppostv('acl')
			var subj = co:ppostv('subject')
			if not acl then acl =  'all' end
			if not replytext then goto badop end
			
			var reply = lib.store.post {
				author = co.who.id, parent = pid;
				subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
			}

................................................................................
	::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')
	lib.dbg('showing credentials')
	if act:cmp( '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('?',co.aid)
		return
	elseif act:cmp( 'newcred') then
		var cmt = co:ppostv('comment')
		var pw = co:ppostv('newpw')
		var aid: uint64 = 0
		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')
................................................................................
			lib.dbg('setting credential restrictions')
			var privs = [(function()
				local check = quote end
				local me = symbol(lib.store.privset)
				for i,v in ipairs(lib.store.privset.members) do
					check = quote [check]
						var val = co:pgetv(['allow-' .. v])
						if val:ref() and val:cmp('on')
							then ([me].[v] << true)
							else ([me].[v] << false)
						end
					end
				end
				return quote
					var [me]
................................................................................
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 >= 2 then
		if not co.who.rights.powers.config() and (
			path(1):cmp('srv')   or
			path(1):cmp('badge') or
			path(1):cmp('emoji')
		) then goto nopriv

		elseif not co.who.rights.powers.rebrand() and (
			path(1):cmp('brand')
		) then goto nopriv

		elseif not co.who.rights.powers.account() and (
			path(1):cmp('profile') or
			path(1):cmp('sec') or
			path(1):cmp('avi') or
			path(1):cmp('ui')
		) then goto nopriv

		elseif not co.who.rights.powers:affect_users() and (
			path(1):cmp(lib.str.lit 'users')
		) then goto nopriv end
	end

................................................................................
			if co.who.bio ~= nil and @co.who.bio == 0 then co.who.bio = nil end
			if co.who.nym ~= nil and @co.who.nym == 0 then co.who.nym = nil end
			co.who.source:actor_save(co.who)

			var act = co:ppostv('act')
			var resethue = false
			if act:ref() then
				resethue = act:cmp( 'reset-hue')
			end

			if not resethue then
				var shue = co:ppostv('hue')
				var nhue, okhue = lib.math.decparse(shue)
				if okhue and nhue ~= co.ui_hue then
					if nhue == co.srv.cfg.ui_hue
................................................................................
				end
			end
			if resethue then
				co.srv:actor_conf_int_reset(co.who.id, 'ui-accent')
				co.ui_hue = co.srv.cfg.ui_hue
			end

			msg = 'profile changes saved'
			--user_refresh = true -- not really necessary here, actually

		elseif path(1):cmp('sec') then
			credsec_for_uid(co, co.who.id)
		elseif path(1):cmp('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
							usr:free()
							goto nopriv
						end
					else goto badop end
					defer usr:free()

					if path.ct == 4 then
						if path(3):cmp(lib.str.lit 'cred') then
							credsec_for_uid(co, userid)
						end
					elseif path.ct == 3 then
						var purgestr = co:ppostv("purgestr")
						var purgekey = co:ppostv("purgekey")
						if purgestr:ref() and purgekey:ref() and purgestr(0) ~= 0 then
							if purgestr:cmp(purgekey) then -- destroying account! :O
								co.srv:actor_purge_uid(userid)
								co:reroute('/conf/users')
								return
							else msg = 'purge confirmation failed' end
						end

						var epithet = co:ppostv("epithet")
						var s_rank = co:ppostv("rank")
						var s_invites = co:ppostv("invites")
						var s_quota = co:ppostv("quota")
						var ch_staff = co:ppostv("staff")
						var torank: uint16 = usr(0).rights.rank
						if ch_staff:ref() and ch_staff:cmp('on') then
							if s_rank:ref() then
								var rank, rok = lib.math.decparse(s_rank)
								if rok and rank <= co.srv.cfg.nranks then
									torank = rank
								end
							elseif usr(0).rights.rank == 0 then
								torank = co.who.rights.rank + 1
							end
						else torank = 0 end

						if co.who.id ~= userid and co.who.rights.rank > 0 then
							if (co.who.rights.powers.elevate() and
								 (torank < usr(0).rights.rank or usr(0).rights.rank == 0) and
								  (torank > co.who.rights.rank or co.who.rights.rank == 1))
							or (co.who.rights.powers.demote()  and
								 (torank > usr(0).rights.rank or             torank == 0))
							then usr(0).rights.rank = torank end
						end

						if s_invites:ref() then
							var n_invites, n_invites_ok = lib.math.decparse(s_invites)
							if n_invites_ok and n_invites ~= usr(0).rights.invites then
								if (n_invites > usr(0).rights.invites and
									co.who.rights.powers.elevate() and
									co.who.rights.powers.invite())
								or (n_invites < usr(0).rights.invites and
									co.who.rights.powers.demote())
								then usr(0).rights.invites = n_invites end
							end
						end
						
						if (co.who.id ~= userid or co.who.rights.rank == 1) and s_quota:ref() then
							var n_quota, n_quota_ok = lib.math.decparse(s_quota)
							if n_quota_ok and n_quota ~= usr(0).rights.quota then
								if (co.who.rights.powers.elevate() and 
									((n_quota == 0 and  co.who.rights.quota == 0 or co.who.rights.rank == 1) or
									 (n_quota ~= 0 and (n_quota > usr(0).rights.quota and
										(co.who.rights.quota == 0 or
										 co.who.rights.quota >= n_quota or
										 co.who.rights.rank  == 1)))))
								or (co.who.rights.powers.demote() and n_quota ~= 0 and 
									(n_quota < usr(0).rights.quota or
									 co.who.rights.rank == 1))
								then usr(0).rights.quota = n_quota end
							end
						end

						if co.who.rights.powers.herald() and
						  (co.who.id ~= userid or
						   co.srv.cfg.pol_autoherald or
						   co.who.rights.rank == 1) then 
							if epithet:ref() and epithet(0) ~= 0 then
								usr(0).epithet = epithet.ptr
							else
								usr(0).epithet = nil
							end
						end

						if co.who.id ~= userid then
							-- update powers
						end
						co.srv:actor_save(usr.ptr)
						if not msg then msg = 'user record updated' end
					end
				end
			elseif path.ct == 2 and meth == method.post then
				var act = co:ppostv('act')
				if act:cmp('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')
................................................................................
					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('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)
................................................................................
	::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('clear') then
			co.srv:actor_conf_int_set(co.who.id, 'notice-clear-time', lib.osclock.time(nil))
			co:reroute('/')
			return
		else goto badop end
	end

	lib.render.notices(co)
................................................................................
	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:poolstr(&co.srv.pool) -- defer pg:free()
			co:stdpage([lib.srv.convo.page] {
				title = 'media :: upload';
				class = 'media upload';
				cache = false; body = pg;
			})
		elseif meth == method.post_file then
			var desc = pstring.null()
			var folder = pstring.null()
			var mime = pstring.null()
			var name = pstring.null()
			var body = binblob.null()
			for i=0, co.uploads.sz do var up = co.uploads.storage.ptr + i
				if up.body.ct > 0 then
					if up.field:cmp('desc') then
						desc = up.body
					elseif up.field:cmp('folder') then
						folder = up.body
					elseif up.field:cmp('file') then
						mime = up.ctype
						body = binblob {ptr = [&uint8](up.body.ptr), ct = up.body.ct}
						name = up.filename
					end
				end
			end
			if not body then goto badop end
................................................................................

			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('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
................................................................................
	elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
		if not meth_get(meth) then goto wrongmeth end
		if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end
	elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then
		http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5})
	elseif lib.str.ncmp('/file/', uri.ptr, 6) == 0 then
		http.file_serve_raw(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 6, ct = uri.ct - 6})
	elseif uri:cmp( '/notices') then
		if co.aid == 0 then co:reroute('/login') return end
		http.user_notices(co,meth)
	elseif uri:cmp( '/compose') then
		if co.aid == 0 then co:reroute('/login') return end
		http.post_compose(co,meth)
	elseif uri:cmp( '/login') then
		if co.aid == 0
			then http.login_form(co, meth)
			else co:reroute('/')
		end
	elseif uri:cmp( '/logout') then
		if co.aid == 0
			then goto notfound
			else co:reroute_cookie('/','auth=; Path=/')
		end
	else -- hierarchical routes
		var path = lib.http.hier(&co.srv.pool, uri) --defer path:free()
		if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then

Modified srv.t from [854410a8ca] to [baac561cfe].

3
4
5
6
7
8
9

10
11
12
13
14
15
16
...
324
325
326
327
328
329
330





331
332
333
334
335
336
337
...
950
951
952
953
954
955
956

957
958
959
960
961
962
963
local secmode = lib.enum { 'public', 'private', 'lockdown', 'isolate' }
local pstring = lib.mem.ptr(int8)
local struct srv
local struct cfgcache {
	secret: pstring
	pol_sec: secmode.t
	pol_reg: bool

	credmgd: bool
	maxupsz: intptr
	poolinitsz: intptr
	instance: pstring
	overlord: &srv
	ui_cue_staff: pstring
	ui_cue_founder: pstring
................................................................................
end

terra convo:stra(sz: intptr) -- convenience function
	var s: lib.str.acc
	s:pool(&self.srv.pool,sz)
	return s
end






convo.methods.assertpow = macro(function(self, pow)
	return quote
		var ok = true
		if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then
			ok = false
			self:complain(403,'insufficient privileges',['you lack the <strong>'..pow:asvalue()..'</strong> power and cannot perform this action'])
................................................................................
end

terra cfgcache:load()
	self.instance = self.overlord:conf_get('instance-name')
	self.secret = self.overlord:conf_get('server-secret')

	self.pol_reg = self:cfbool('policy-self-register', false)


	do self.credmgd = false
	var sreg = self.overlord:conf_get('credential-store')
	if sreg:ref() then
		if lib.str.cmp(sreg.ptr, 'managed') == 0
			then self.credmgd = true
			else self.credmgd = false







>







 







>
>
>
>
>







 







>







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
local secmode = lib.enum { 'public', 'private', 'lockdown', 'isolate' }
local pstring = lib.mem.ptr(int8)
local struct srv
local struct cfgcache {
	secret: pstring
	pol_sec: secmode.t
	pol_reg: bool
	pol_autoherald: bool
	credmgd: bool
	maxupsz: intptr
	poolinitsz: intptr
	instance: pstring
	overlord: &srv
	ui_cue_staff: pstring
	ui_cue_founder: pstring
................................................................................
end

terra convo:stra(sz: intptr) -- convenience function
	var s: lib.str.acc
	s:pool(&self.srv.pool,sz)
	return s
end

convo.methods.qstr = macro(function(self, ...) -- convenience string builder
	local exp = {...}
	return `lib.str.acc{}:pcompose(&self.srv.pool, [exp]):finalize()
end)

convo.methods.assertpow = macro(function(self, pow)
	return quote
		var ok = true
		if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then
			ok = false
			self:complain(403,'insufficient privileges',['you lack the <strong>'..pow:asvalue()..'</strong> power and cannot perform this action'])
................................................................................
end

terra cfgcache:load()
	self.instance = self.overlord:conf_get('instance-name')
	self.secret = self.overlord:conf_get('server-secret')

	self.pol_reg = self:cfbool('policy-self-register', false)
	self.pol_autoherald = self:cfbool('policy-self-herald', true)

	do self.credmgd = false
	var sreg = self.overlord:conf_get('credential-store')
	if sreg:ref() then
		if lib.str.cmp(sreg.ptr, 'managed') == 0
			then self.credmgd = true
			else self.credmgd = false

Modified str.t from [89921fa130] to [c8b5d8bfdc].

32
33
34
35
36
37
38

39




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73




74
75
76
77
78
79
80
81
82
83
84
85
86
	return str
end


do local strptr = (lib.mem.ptr(int8))
	local strref = (lib.mem.ref(int8))
	local byteptr = (lib.mem.ptr(uint8))

	strptr.metamethods.__cast = function(from,to,e)




		if from == &int8 then
			return `strptr {ptr = e, ct = m.sz(e)}
		elseif to == &int8 then
			return e.ptr
		end
	end

	terra strptr:cmp(other: strptr)
		if self.ptr == nil and other.ptr == nil then return true end
		if self.ptr == nil or other.ptr == nil then return false end

		var sz = lib.math.biggest(self.ct, other.ct)
		for i = 0, sz do
			if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
			if self.ptr[i] ~= other.ptr[i] then return false end
		end
		return true
	end
	terra strref:cmp(other: strref)
		if self.ptr == nil and other.ptr == nil then return true end
		if self.ptr == nil or other.ptr == nil then return false end

		var sz = lib.math.biggest(self.ct, other.ct)
		for i = 0, sz do
			if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
			if self.ptr[i] ~= other.ptr[i] then return false end
		end
		return true
	end
	terra strptr:ffw()
		var newp = m.ffw(self.ptr,self.ct)
		var newct = self.ct - (newp - self.ptr)
		return strptr { ptr = newp, ct = newct }
	end




	strptr.methods.cmpl = macro(function(self,other)
		return `self:cmp(strptr { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
	end)
	strref.methods.cmpl = macro(function(self,other)
		return `self:cmp(strref { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
	end)

	terra byteptr:cmp(other: byteptr)
		var sz = lib.math.biggest(self.ct, other.ct)
		for i = 0, sz do
			if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
			if self.ptr[i] ~= other.ptr[i] then return false end
		end







>
|
>
>
>
>
|
|
|
|
|
|
<
|
|
|

|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
>
>
>
>
|
|
|
|
|
|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61











62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
	return str
end


do local strptr = (lib.mem.ptr(int8))
	local strref = (lib.mem.ref(int8))
	local byteptr = (lib.mem.ptr(uint8))
	local function install_funcs(ty)
		ty.metamethods.__cast = function(from,to,e)
			local v = e:asvalue()
			if type(v) == 'string' then
				print('hard-coding pstr',v,#v)
				return `ty {ptr = v, ct = [#v]}
			elseif from == &int8 then
				return `ty {ptr = e, ct = m.sz(e)}
			elseif to == &int8 then
				return e.ptr
			end
		end

		terra ty:cmp(other: ty)
			if self.ptr == nil and other.ptr == nil then return true end
			if self.ptr == nil or other.ptr == nil then return false end

			var sz = lib.math.biggest(self.ct, other.ct)
			for i = 0, sz do
				if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
				if self.ptr[i] ~= other.ptr[i] then return false end
			end
			return true
		end











		terra ty:ffw()
			var newp = m.ffw(self.ptr,self.ct)
			var newct = self.ct - (newp - self.ptr)
			return ty { ptr = newp, ct = newct }
		end
	end
	install_funcs(strptr)
	install_funcs(strref)

	--strptr.methods.cmpl = macro(function(self,other)
	--	return `self:cmp(strptr { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
	--end)
	--strref.methods.cmpl = macro(function(self,other)
	--	return `self:cmp(strref { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
	--end)

	terra byteptr:cmp(other: byteptr)
		var sz = lib.math.biggest(self.ct, other.ct)
		for i = 0, sz do
			if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
			if self.ptr[i] ~= other.ptr[i] then return false end
		end