Overview
| Comment: | user mgmt and rt improvements |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
05af79b909dfb0c5ac50472976eed863 |
| User & Date: | lexi on 2021-01-09 07:15:21 |
| Other Links: | manifest | tags |
Context
|
2021-01-10
| ||
| 03:54 | add memory pool impl, handle various little details, add beginnings of mimelib check-in: 8d35307a7f user: lexi tags: trunk | |
|
2021-01-09
| ||
| 07:15 | user mgmt and rt improvements check-in: 05af79b909 user: lexi tags: trunk | |
|
2021-01-08
| ||
| 05:58 | enable passwords check-in: d6024624c6 user: lexi tags: trunk | |
Changes
Modified backend/pgsql.t from [9c53eed84d] to [175b022aff].
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 ... 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 ... 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 ... 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 .... 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 .... 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 .... 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 .... 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 .... 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 .... 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 |
select (pg_temp.parsavpg_translate_actor(a)).*, au.restrict, array['post' ] <@ au.restrict, array['edit' ] <@ au.restrict, array['account' ] <@ au.restrict, array['upload' ] <@ au.restrict, array['moderate'] <@ au.restrict, array['admin' ] <@ au.restrict from parsav_auth au left join parsav_actors a on au.uid = a.id where au.aid = $1::bigint and au.blacklist = false and (au.netmask is null or au.netmask >> $2::inet) and ($3::bigint = 0 or --slightly abusing the epoch time fmt here, but ................................................................................ update parsav_actors set authtime = $2::bigint where id = $1::bigint ]]; }; auth_create_pw = { params = {uint64, binblob, int64, pstring}, cmd = true, sql = [[ insert into parsav_auth (uid, name, kind, cred, valperiod, comment) values ( $1::bigint, (select handle from parsav_actors where id = $1::bigint), 'pw-sha256', $2::bytea, $3::bigint, $4::text ) ]] }; auth_purge_type = { params = {rawstring, uint64, rawstring}, cmd = true, sql = [[ delete from parsav_auth where ((uid = 0 and name = $1::text) or uid = $2::bigint) and kind like $3::text ]] }; auth_enum_uid = { params = {uint64}, sql = [[ select aid, kind, comment, netmask, blacklist from parsav_auth where uid = $1::bigint ]]; }; ................................................................................ params = {uint64, uint64, pstring}, cmd = true, sql = [[ delete from parsav_acts where actor = $1::bigint and subject = $2::bigint and kind = $3::text ]]; }; post_reacts_fetch_uid = { params = {uint64, uint64, pstring}, sql = [[ select id, actor, subject, kind, body, time from parsav_acts where ($1::bigint = 0 or actor = $1::bigint) and ($2::bigint = 0 or subject = $2::bigint) and ($3::text is null or kind = $3::text ) ]] }; post_enum_author_uid = { params = {uint64,uint64,uint64,uint64, uint64}, sql = [[ select (c.post).* from pg_temp.parsavpg_known_content as c ................................................................................ a.ptr.key = r:bin(row,8) end a.ptr.origin = origin if avia.buf ~= nil then avia:free() end return a end local privmap = lib.store.privmap local checksha = function(src, hash, origin, username, pw) local validate = function(kind, cred, credlen) return quote var r = queries.actor_auth_pw.exec( [&lib.store.source](src), username, ................................................................................ local privupdate = terra( src: &lib.store.source, ac: &lib.store.actor ): {} var pdef: lib.store.powerset pdef:clear() var map = array([privmap]) for i=0, [map.type.N] do var d = pdef and map[i].priv var u = ac.rights.powers and map[i].priv queries.actor_power_delete.exec(src, ac.id, map[i].name) if d:sz() > 0 and u:sz() == 0 then lib.dbg('blocking power ', {map[i].name.ptr, map[i].name.ct}) queries.actor_power_insert.exec(src, ac.id, map[i].name, 0) elseif d:sz() == 0 and u:sz() > 0 then lib.dbg('granting power ', {map[i].name.ptr, map[i].name.ct}) queries.actor_power_insert.exec(src, ac.id, map[i].name, 1) ................................................................................ var r = queries.actor_powers_fetch.exec(src, uid) for i=0, r.sz do for j=0, [map.type.N] do var pn = r:_string(i,0) if map[j].name:cmp(pn) then if r:bool(i,1) then powers = powers + map[j].priv else powers = powers - map[j].priv end end end end return powers end ................................................................................ var a = row_to_actor(&r, 0) a.ptr.source = src var au = [lib.stat(lib.store.auth)] { ok = true } au.val.aid = aid au.val.uid = a.ptr.id if not r:null(0,13) then -- restricted? au.val.privs:clear() (au.val.privs.post << r:bool(0,14)) (au.val.privs.edit << r:bool(0,15)) (au.val.privs.account << r:bool(0,16)) (au.val.privs.upload << r:bool(0,17)) (au.val.privs.moderate<< r:bool(0,18)) (au.val.privs.admin << r:bool(0,19)) else au.val.privs:fill() end return au, a end ::fail:: return [lib.stat (lib.store.auth) ] { ok = false }, [lib.mem.ptr(lib.store.actor)] { ptr = nil, ct = 0 } ................................................................................ var r = queries.post_fetch.exec(src, post) if r.sz == 0 then return [lib.mem.ptr(lib.store.post)].null() end var p = row_to_post(&r, 0) p.ptr.source = src return p end]; post_retweet = [terra( src: &lib.store.source, uid: uint64, post: uint64, undo: bool ): {} var time = lib.osclock.time(nil) if not undo then queries.post_react_simple.exec(src,uid,post,"rt",time) else queries.post_react_cancel.exec(src,uid,post,"rt") end end]; post_like = [terra( src: &lib.store.source, ................................................................................ auth_attach_pw = [terra( src: &lib.store.source, uid: uint64, reset: bool, pw: pstring, comment: pstring ): {} var hash: uint8[lib.crypt.algsz.sha256] if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(lib.crypt.alg.sha256.id), [&uint8](pw.ptr), pw.ct, &hash[0]) ~= 0 then lib.bail('cannot hash password') end if reset then queries.auth_purge_type.exec(src, nil, uid, 'pw-%') end queries.auth_create_pw.exec(src, uid, binblob {ptr = &hash[0], ct = [hash.type.N]}, lib.osclock.time(nil), comment) end]; auth_purge_pw = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} queries.auth_purge_type.exec(src, handle, uid, 'pw-%') end]; auth_purge_otp = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} ................................................................................ post.id, post.chgcount, post.edited, post.subject, post.acl, post.body) end]; post_enum_parent = [terra( src: &lib.store.source, post: uint64 ): lib.mem.ptr(lib.mem.ptr(lib.store.post)) var r = queries.post_enum_parent.exec(src,post) if r.sz == 0 then return [lib.mem.ptr(lib.mem.ptr(lib.store.post))].null() end defer r:free() var lst = lib.mem.heapa([lib.mem.ptr(lib.store.post)], r.sz) for i=0, r.sz do lst.ptr[i] = row_to_post(&r, i) end return lst end]; thread_latest_arrival_calc = [terra( src: &lib.store.source, post: uint64 ): lib.store.timepoint var r = queries.thread_latest_arrival_calc.exec(src,post) if r.sz == 0 or r:null(0,0) then return 0 end |
> | > | > > > | > > > | > > > > > > > > > > > > > > > > > > | > > > > > > > > | | | | | | | | | | > | | > > > > > > < > | | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 ... 273 274 275 276 277 278 279 280 281 282 283 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 ... 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 ... 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 .... 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 .... 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 .... 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 .... 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 .... 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 .... 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 |
select (pg_temp.parsavpg_translate_actor(a)).*, au.restrict, array['post' ] <@ au.restrict, array['edit' ] <@ au.restrict, array['account' ] <@ au.restrict, array['upload' ] <@ au.restrict, array['artifact'] <@ au.restrict, array['moderate'] <@ au.restrict, array['admin' ] <@ au.restrict, array['invite' ] <@ au.restrict from parsav_auth au left join parsav_actors a on au.uid = a.id where au.aid = $1::bigint and au.blacklist = false and (au.netmask is null or au.netmask >> $2::inet) and ($3::bigint = 0 or --slightly abusing the epoch time fmt here, but ................................................................................ update parsav_actors set authtime = $2::bigint where id = $1::bigint ]]; }; auth_create_pw = { params = {uint64, binblob, int64, pstring}, sql = [[ insert into parsav_auth (uid, name, kind, cred, valperiod, comment) values ( $1::bigint, (select handle from parsav_actors where id = $1::bigint), 'pw-sha256', $2::bytea, $3::bigint, $4::text ) on conflict (name,kind,cred) do update set comment = $4::text returning aid ]] }; auth_privs_clear = { params = {uint64}, cmd = true, sql = [[ update parsav_auth set restrict = array[]::text[] where aid = $1::bigint ]]; }; auth_priv_install = { params = {uint64,pstring}, cmd = true, sql = [[ update parsav_auth set restrict = restrict || $2::text where aid = $1::bigint ]]; }; auth_purge_type = { params = {rawstring, uint64, rawstring}, cmd = true, sql = [[ delete from parsav_auth where ((uid = 0 and name = $1::text) or uid = $2::bigint) and kind like $3::text ]] }; auth_purge_aid = { params = {uint64}, cmd = true, sql = [[ delete from parsav_auth where aid = $1::bigint ]] }; auth_enum_uid = { params = {uint64}, sql = [[ select aid, kind, comment, netmask, blacklist from parsav_auth where uid = $1::bigint ]]; }; ................................................................................ params = {uint64, uint64, pstring}, cmd = true, sql = [[ delete from parsav_acts where actor = $1::bigint and subject = $2::bigint and kind = $3::text ]]; }; post_react_delete = { params = {uint64}, cmd = true, sql = [[ delete from parsav_acts where id = $1::bigint ]]; }; post_reacts_fetch_uid = { params = {uint64, uint64, pstring}, sql = [[ select id, actor, subject, kind, body, time from parsav_acts where ($1::bigint = 0 or actor = $1::bigint) and ($2::bigint = 0 or subject = $2::bigint) and ($3::text is null or kind = $3::text ) ]]; }; post_act_fetch_notice = { params = {uint64}, sql = [[ select (pg_temp.parsavpg_translate_act(a)).* from parsav_acts as a where id = $1::bigint ]]; }; post_enum_author_uid = { params = {uint64,uint64,uint64,uint64, uint64}, sql = [[ select (c.post).* from pg_temp.parsavpg_known_content as c ................................................................................ a.ptr.key = r:bin(row,8) end a.ptr.origin = origin if avia.buf ~= nil then avia:free() end return a end local privmap = lib.store.powmap local checksha = function(src, hash, origin, username, pw) local validate = function(kind, cred, credlen) return quote var r = queries.actor_auth_pw.exec( [&lib.store.source](src), username, ................................................................................ local privupdate = terra( src: &lib.store.source, ac: &lib.store.actor ): {} var pdef: lib.store.powerset pdef:clear() var map = array([privmap]) for i=0, [map.type.N] do var d = pdef and map[i].val var u = ac.rights.powers and map[i].val queries.actor_power_delete.exec(src, ac.id, map[i].name) if d:sz() > 0 and u:sz() == 0 then lib.dbg('blocking power ', {map[i].name.ptr, map[i].name.ct}) queries.actor_power_insert.exec(src, ac.id, map[i].name, 0) elseif d:sz() == 0 and u:sz() > 0 then lib.dbg('granting power ', {map[i].name.ptr, map[i].name.ct}) queries.actor_power_insert.exec(src, ac.id, map[i].name, 1) ................................................................................ var r = queries.actor_powers_fetch.exec(src, uid) for i=0, r.sz do for j=0, [map.type.N] do var pn = r:_string(i,0) if map[j].name:cmp(pn) then if r:bool(i,1) then powers = powers + map[j].val else powers = powers - map[j].val end end end end return powers end ................................................................................ var a = row_to_actor(&r, 0) a.ptr.source = src var au = [lib.stat(lib.store.auth)] { ok = true } au.val.aid = aid au.val.uid = a.ptr.id if not r:null(0,14) then -- restricted? au.val.privs:clear() (au.val.privs.post << r:bool(0,15)) (au.val.privs.edit << r:bool(0,16)) (au.val.privs.account << r:bool(0,17)) (au.val.privs.upload << r:bool(0,18)) (au.val.privs.artifact<< r:bool(0,19)) (au.val.privs.moderate<< r:bool(0,20)) (au.val.privs.admin << r:bool(0,21)) (au.val.privs.invite << r:bool(0,22)) else au.val.privs:fill() end return au, a end ::fail:: return [lib.stat (lib.store.auth) ] { ok = false }, [lib.mem.ptr(lib.store.actor)] { ptr = nil, ct = 0 } ................................................................................ var r = queries.post_fetch.exec(src, post) if r.sz == 0 then return [lib.mem.ptr(lib.store.post)].null() end var p = row_to_post(&r, 0) p.ptr.source = src return p end]; post_act_cancel = [terra( src: &lib.store.source, act: uint64 ): {} queries.post_react_delete.exec(src, act) end]; post_retweet = [terra( src: &lib.store.source, uid: uint64, post: uint64, undo: bool ): {} if not undo then var time = lib.osclock.time(nil) queries.post_react_simple.exec(src,uid,post,"rt",time) else queries.post_react_cancel.exec(src,uid,post,"rt") end end]; post_like = [terra( src: &lib.store.source, ................................................................................ auth_attach_pw = [terra( src: &lib.store.source, uid: uint64, reset: bool, pw: pstring, comment: pstring ): uint64 var hash: uint8[lib.crypt.algsz.sha256] if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(lib.crypt.alg.sha256.id), [&uint8](pw.ptr), pw.ct, &hash[0]) ~= 0 then lib.bail('cannot hash password') end if reset then queries.auth_purge_type.exec(src, nil, uid, 'pw-%') end var r = queries.auth_create_pw.exec(src, uid, binblob {ptr = &hash[0], ct = [hash.type.N]}, lib.osclock.time(nil), comment) if r.sz == 0 then return 0 end var aid = r:int(uint64,0,0) r:free() return aid end]; auth_privs_set = [terra( src: &lib.store.source, aid: uint64, set: lib.store.privset ): {} var map = array([lib.store.privmap]) queries.auth_privs_clear.exec(src,aid) if set:sz() == 0 then return end for i=0, [map.type.N] do if (set and map[i].val):sz() > 0 then queries.auth_priv_install.exec(src,aid,map[i].name) end end end]; auth_purge_pw = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} queries.auth_purge_type.exec(src, handle, uid, 'pw-%') end]; auth_purge_otp = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} ................................................................................ post.id, post.chgcount, post.edited, post.subject, post.acl, post.body) end]; post_enum_parent = [terra( src: &lib.store.source, post: uint64 ): lib.mem.lstptr(lib.store.post) var r = queries.post_enum_parent.exec(src,post) if r.sz == 0 then return [lib.mem.ptr(lib.mem.ptr(lib.store.post))].null() end defer r:free() var lst = lib.mem.heapa([lib.mem.ptr(lib.store.post)], r.sz) for i=0, r.sz do lst.ptr[i] = row_to_post(&r, i) end return lst end]; post_act_fetch_notice = [terra( src: &lib.store.source, act: uint64 ): lib.store.notice var r = queries.post_act_fetch_notice.exec(src,act) if r.sz == 0 then return lib.store.notice { kind = lib.store.noticetype.none } end defer r:free() var n: lib.store.notice n.kind = r:int(uint16,0,0) n.when = r:int(int64,0,1) n.who = r:int(int64,0,2) n.what = r:int(uint64,0,3) if n.kind == lib.store.noticetype.react then var react = r:_string(0,5) lib.str.ncpy(n.reaction, react.ptr, lib.math.smallest(react.ct,[(`n.reaction).tree.type.N])) end return n end]; thread_latest_arrival_calc = [terra( src: &lib.store.source, post: uint64 ): lib.store.timepoint var r = queries.thread_latest_arrival_calc.exec(src,post) if r.sz == 0 or r:null(0,0) then return 0 end |
Modified backend/schema/pgsql-views.sql from [25f9d405bc] to [c997d2f5ad].
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
kind smallint, "when" bigint, who bigint, what bigint, reply bigint, reaction text ); create type pg_temp.parsavpg_intern_actor as ( id bigint, nym text, handle text, origin bigint, bio text, ................................................................................ --); create temp view parsavpg_notices as ( -- TODO add mentions with ntimes as ( select uid, value as when from parsav_actor_conf_ints where key = 'notice-clear-time' ), acts as ( select row( kmap.kind::smallint, a.time, a.actor, a.subject, null::bigint, null::text )::pg_temp.parsavpg_intern_notice as notice, p.author as rcpt from parsav_acts as a inner join parsav_posts as p on a.subject = p.id inner join (values ('rt', <notice:rt> ), ('like', <notice:like> ), ('react', <notice:react>) ) as kmap(kstr,kind) on kmap.kstr = a.kind left join ntimes as nt on nt.uid = p.author where a.time >= coalesce(nt.when,0) ), replies as ( select row( <notice:reply>::smallint, coalesce(p.posted,p.discovered), p.author, |
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
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
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
kind smallint, "when" bigint, who bigint, what bigint, reply bigint, reaction text ); create or replace function pg_temp.parsavpg_translate_act(parsav_acts) returns pg_temp.parsavpg_intern_notice as $$ select row( kmap.kind::smallint, ($1).time, ($1).actor, ($1).subject, null::bigint, ($1).body )::pg_temp.parsavpg_intern_notice as notice from (values ('rt', <notice:rt> ), ('like', <notice:like> ), ('react', <notice:react>) ) as kmap(kstr,kind) where kmap.kstr = ($1).kind $$ language sql; create type pg_temp.parsavpg_intern_actor as ( id bigint, nym text, handle text, origin bigint, bio text, ................................................................................ --); create temp view parsavpg_notices as ( -- TODO add mentions with ntimes as ( select uid, value as when from parsav_actor_conf_ints where key = 'notice-clear-time' ), acts as ( select pg_temp.parsavpg_translate_act(a) as notice, -- row( -- kmap.kind::smallint, -- a.time, -- a.actor, -- a.subject, -- null::bigint, -- null::text -- )::pg_temp.parsavpg_intern_notice as notice, p.author as rcpt from parsav_acts as a inner join parsav_posts as p on a.subject = p.id -- inner join (values -- ('rt', <notice:rt> ), -- ('like', <notice:like> ), -- ('react', <notice:react>) -- ) as kmap(kstr,kind) on kmap.kstr = a.kind left join ntimes as nt on nt.uid = p.author where a.time >= coalesce(nt.when,0) ), replies as ( select row( <notice:reply>::smallint, coalesce(p.posted,p.discovered), p.author, |
Modified mgtool.t from [4f69a41277] to [b1a646e421].
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 |
dlg:actor_create(&na)
lib.report('created new user @',na.handle,'; assign credentials to enable login')
elseif umode.arglist.ct >= 3 then
var grant = lib.str.cmp(umode.arglist(1),'grant') == 0
if not usr then lib.bail('no such user') end
if grant or lib.str.cmp(umode.arglist(1),'revoke') == 0 then
var newprivs = usr.ptr.rights.powers
var map = array([lib.store.privmap])
if umode.arglist.ct == 3 and lib.str.cmp(umode.arglist(2),'all') == 0 then
if grant
then newprivs:fill()
else newprivs:clear()
end
else
for i=2,umode.arglist.ct do
var priv = umode.arglist(i)
for j=0,[map.type.N] do
var p = map[j]
if p.name:cmp_raw(priv) then
if grant then
lib.dbg('enabling power ', {p.name.ptr,p.name.ct})
newprivs = newprivs + p.priv
else
lib.dbg('disabling power ', {p.name.ptr,p.name.ct})
newprivs = newprivs - p.priv
end
break
end
end
end
end
|
| | | |
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 |
dlg:actor_create(&na)
lib.report('created new user @',na.handle,'; assign credentials to enable login')
elseif umode.arglist.ct >= 3 then
var grant = lib.str.cmp(umode.arglist(1),'grant') == 0
if not usr then lib.bail('no such user') end
if grant or lib.str.cmp(umode.arglist(1),'revoke') == 0 then
var newprivs = usr.ptr.rights.powers
var map = array([lib.store.powmap])
if umode.arglist.ct == 3 and lib.str.cmp(umode.arglist(2),'all') == 0 then
if grant
then newprivs:fill()
else newprivs:clear()
end
else
for i=2,umode.arglist.ct do
var priv = umode.arglist(i)
for j=0,[map.type.N] do
var p = map[j]
if p.name:cmp_raw(priv) then
if grant then
lib.dbg('enabling power ', {p.name.ptr,p.name.ct})
newprivs = newprivs + p.val
else
lib.dbg('disabling power ', {p.name.ptr,p.name.ct})
newprivs = newprivs - p.val
end
break
end
end
end
end
|
Modified render/conf/sec.t from [7f83a40056] to [f6e2d18341].
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
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
|
lib.osclock.ctime_r(&time, &tstr[0])
var body = data.view.conf_sec {
lastreset = pstr {
ptr = &tstr[0], ct = lib.str.sz(&tstr[0])
}
}
if co.srv.cfg.credmgd then
var new = co:pgetv('new')
var a: lib.str.acc a:init(768)
if not new then
body:append(&a)
var credmgr = data.view.conf_sec_credmg {
credlist = pstr{'',0};
}
var creds = co.srv:auth_enum_uid(uid)
if creds.ct > 0 then defer creds:free()
................................................................................
cl:lpush('</option>')
end
end
credmgr.credlist = cl:finalize()
end
credmgr:append(&a)
if credmgr.credlist.ct > 0 then credmgr.credlist:free() end
elseif new:cmp(lib.str.plit'pw') then
var d: data.view.conf_sec_pwnew
var time = lib.osclock.time(nil)
var timestr: int8[26] lib.osclock.ctime_r(&time, ×tr[0])
var cmt: lib.str.acc
cmt:init(48):lpush('enrolled over http on '):push(×tr[0],0)
d.comment = cmt:finalize()
var st = d:tostr()
d.comment:free()
return st
elseif new:cmp(lib.str.plit'challenge') then
-- we're going to break the rules a bit and do database munging from
-- the rendering code, because doing otherwise in this case would be
-- genuinely nightmarish
elseif new:cmp(lib.str.plit'otp') then
elseif new:cmp(lib.str.plit'api') then
else return pstr.null() end
return a:finalize()
else return body:tostr() end
end
terra lib.render.conf.sec_overlay
(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
-- render the credential panel for the current user, allowing
-- it to be reused in the administration UI
return render_conf_sec(co,co.who.id)
end
return render_conf_sec
|
>
>
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
<
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
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
|
lib.osclock.ctime_r(&time, &tstr[0])
var body = data.view.conf_sec {
lastreset = pstr {
ptr = &tstr[0], ct = lib.str.sz(&tstr[0])
}
}
var a: lib.str.acc a:init(768) defer a:free()
if co.srv.cfg.credmgd then
var new = co:pgetv('new')
if not new then
body:append(&a)
var credmgr = data.view.conf_sec_credmg {
credlist = pstr{'',0};
}
var creds = co.srv:auth_enum_uid(uid)
if creds.ct > 0 then defer creds:free()
................................................................................
cl:lpush('</option>')
end
end
credmgr.credlist = cl:finalize()
end
credmgr:append(&a)
if credmgr.credlist.ct > 0 then credmgr.credlist:free() end
else
if new:cmp(lib.str.plit'pw') then
var d: data.view.conf_sec_pwnew
var time = lib.osclock.time(nil)
var timestr: int8[26] lib.osclock.ctime_r(&time, ×tr[0])
var cmt: lib.str.acc
cmt:init(48):lpush('enrolled over http on '):push(×tr[0],0)
d.comment = cmt:finalize()
var st = d:tostr()
d.comment:free()
return st
elseif new:cmp(lib.str.plit'challenge') then
-- we're going to break the rules a bit and do database munging from
-- the rendering code, because doing otherwise in this case would be
-- genuinely nightmarish
elseif new:cmp(lib.str.plit'otp') then
elseif new:cmp(lib.str.plit'api') then
else return pstr.null() end
end
else body:append(&a) end
return a:finalize()
end
terra lib.render.conf.sec_overlay
(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
-- render the credential panel for the current user, allowing
-- it to be reused in the administration UI
return render_conf_sec(co,co.who.id)
end
return render_conf_sec
|
Modified render/conf/users.t from [41f55e0682] to [59cb9f4fac].
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
push_checkbox(&cinp, 'staff', pstr.null(), 'site staff member', user.ptr.rights.rank > 0, true, pstr.null())
end
cinp:lpush('</div></div>')
if (co.who.rights.powers.elevate() or
co.who.rights.powers.demote()) and user.ptr.id ~= co.who.id then
var map = array([lib.store.privmap])
cinp:lpush('<details><summary>powers</summary><div class="pick-list">')
for i=0, [map.type.N] do
if (co.who.rights.powers and map[i].priv):sz() > 0 then
var on = (user.ptr.rights.powers and map[i].priv):sz() > 0
var enabled = ( on and co.who.rights.powers.demote() ) or
((not on) and co.who.rights.powers.elevate())
var namea: lib.str.acc namea:compose('power-', map[i].name)
var name = namea:finalize()
push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null())
name:free()
end
|
| | | |
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
push_checkbox(&cinp, 'staff', pstr.null(), 'site staff member', user.ptr.rights.rank > 0, true, pstr.null())
end
cinp:lpush('</div></div>')
if (co.who.rights.powers.elevate() or
co.who.rights.powers.demote()) and user.ptr.id ~= co.who.id then
var map = array([lib.store.powmap])
cinp:lpush('<details><summary>powers</summary><div class="pick-list">')
for i=0, [map.type.N] do
if (co.who.rights.powers and map[i].val):sz() > 0 then
var on = (user.ptr.rights.powers and map[i].val):sz() > 0
var enabled = ( on and co.who.rights.powers.demote() ) or
((not on) and co.who.rights.powers.elevate())
var namea: lib.str.acc namea:compose('power-', map[i].name)
var name = namea:finalize()
push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null())
name:free()
end
|
Modified render/tweet-page.t from [57c7b287c5] to [c0b864229b].
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
pg:lpush('<form class="action-bar" method="post">')
if not co.srv:post_liked_uid(co.who.id, p.id)
then pg:lpush('<button class="pos" name="act" accesskey="l" value="like">like</button>')
else pg:lpush('<button class="neg" name="act" accesskey="l" value="dislike">dislike</button>')
end
pg:lpush('<button class="pos" name="act" accesskey="r" value="rt">retweet</button>')
if p.author == co.who.id then
pg:lpush('<a class="button" accesskey="e" href="/post/'):rpush(path(1)):lpush('/edit">edit</a><a class="neg button" accesskey="d" href="/post/'):rpush(path(1)):lpush('/del">delete</a>')
end
-- TODO list user's chosen reaction emoji
pg:lpush('</form>')
end
pg:lpush('<div id="convo" data-live="10">')
render_tweet_replies(co, &pg, p.id)
|
> | > > > > |
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
pg:lpush('<form class="action-bar" method="post">')
if not co.srv:post_liked_uid(co.who.id, p.id)
then pg:lpush('<button class="pos" name="act" accesskey="l" value="like">like</button>')
else pg:lpush('<button class="neg" name="act" accesskey="l" value="dislike">dislike</button>')
end
pg:lpush('<button class="pos" name="act" accesskey="r" value="rt">retweet</button>')
if p.author == co.who.id then
if co.who.rights.powers.edit() then
pg:lpush('<a class="button" accesskey="e" href="/post/'):rpush(path(1)):lpush('/edit">edit</a>')
end
pg:lpush('<a class="neg button" accesskey="d" href="/post/'):rpush(path(1)):lpush('/del">delete</a>')
elseif co.who.rights.powers.snitch() then
pg:lpush('<a class="neg button" accesskey="s" href="/post/'):rpush(path(1)):lpush('/report">report</a>')
end
-- TODO list user's chosen reaction emoji
pg:lpush('</form>')
end
pg:lpush('<div id="convo" data-live="10">')
render_tweet_replies(co, &pg, p.id)
|
Modified route.t from [b4f49ac3f6] to [a8702e1420].
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 ... 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 ... 276 277 278 279 280 281 282 283 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 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 ... 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
terra http.tweet_page(co: &lib.srv.convo, path: hpath, meth: method.t)
var pid, ok = lib.math.shorthand.parse(path(1).ptr, path(1).ct)
if not ok then
co:complain(400, 'bad post ID', 'that post ID is not valid')
return
end
var post = co.srv:post_fetch(pid)
if not post then
co:complain(404, 'post not found', 'no such post is known to this server')
return
end
defer post:free()
if path.ct == 3 then
var lnk: lib.str.acc lnk:compose('/post/', path(1))
var lnkp = lnk:finalize() defer lnkp:free()
if post(0).author ~= co.who.id then
co:complain(403, 'forbidden', 'you cannot alter other people\'s posts')
return
elseif path(2):cmp(lib.str.lit 'edit') then
if meth_get(meth) then
lib.render.compose(co, post.ptr, nil)
return
elseif meth == method.post then
var newbody = co:postv('post')._0
var newacl = co:postv('acl')._0
var newsubj = co:postv('subject')._0
................................................................................
if newsubj ~= nil then post(0).subject = newsubj end
post(0):save(true)
co:reroute(lnkp.ptr)
end
return
elseif path(2):cmp(lib.str.lit 'del') then
if meth_get(meth) then
var 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
}
var body = conf:tostr() defer body:free()
co:stdpage([lib.srv.convo.page] {
title = lib.str.plit 'post :: delete';
class = lib.str.plit 'query';
body = body; cache = false;
})
return
elseif meth == method.post then
var act = co:ppostv('act')
if act:cmp(lib.str.plit 'confirm') then
post(0).source:post_destroy(post(0).id)
co:reroute('/') -- TODO maybe return to parent or conversation if possible
return
else goto badop end
end
else goto badurl end
end
if 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)
................................................................................
author = co.who.id, parent = pid;
subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
}
reply:publish(co.srv)
else goto badop end
end
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
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 'acct')
) then goto nopriv
elseif not co.who.rights.powers:affect_users() and (
path(1):cmp(lib.str.lit 'users')
) then goto nopriv end
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 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
|
> > > | | > > > | > | | | > > > | | | | | > > > > > > > > | > > > | > > > > | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > |
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 ... 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 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 ... 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 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 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 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 ... 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
terra http.tweet_page(co: &lib.srv.convo, path: hpath, meth: method.t) var pid, ok = lib.math.shorthand.parse(path(1).ptr, path(1).ct) if not ok then co:complain(400, 'bad post ID', 'that post ID is not valid') return end var post = co.srv:post_fetch(pid) var rt: lib.store.notice if not post then rt = co.srv:post_act_fetch_notice(pid) if rt.kind ~= lib.store.noticetype.rt then co:complain(404, 'post not found', 'no such post is known to this server') return elseif rt.who ~= co.who.id then co:complain(403, 'forbidden', 'you cannot cancel other people\'s retweets') return end end defer post:free() -- NOP on null if path.ct == 3 then var lnk: lib.str.acc lnk:compose('/post/', path(1)) var lnkp = lnk:finalize() defer lnkp:free() if post:ref() and post(0).author ~= co.who.id then co:complain(403, 'forbidden', 'you cannot alter other people\'s posts') return elseif post:ref() and path(2):cmp(lib.str.lit 'edit') then if not co:assertpow('edit') then return end if meth_get(meth) then lib.render.compose(co, post.ptr, nil) return elseif meth == method.post then var newbody = co:postv('post')._0 var newacl = co:postv('acl')._0 var newsubj = co:postv('subject')._0 ................................................................................ if newsubj ~= nil then post(0).subject = newsubj end post(0):save(true) co:reroute(lnkp.ptr) 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 body = conf:tostr() defer body:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit 'post :: delete'; class = lib.str.plit 'query'; body = body; cache = false; }) 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 else goto badop end 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) ................................................................................ author = co.who.id, parent = pid; subject = subj.ptr, acl = acl.ptr, body = replytext.ptr; } reply:publish(co.srv) else goto badop end end if not post then goto badurl end 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') 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('/conf/sec',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') return end aid = co.srv:auth_attach_pw(uid, false, pw, cmt) else var key = co:ppostv('newkey') if key:ref() then end end if aid ~= 0 then 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] [check] in [me] end end)()] privs:dump() if privs:sz() > 0 then lib.dbg('installing credential restrictions') lib.io.fmt('on priv %llu\n',aid) co.srv:auth_privs_set(aid, privs) end end co:reroute('?') return 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 >= 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 ................................................................................ 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 |
Modified srv.t from [56e1fe84a6] to [80adbc5ad3].
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
end ::nocookie::;
end
if co.aid ~= 0 then
var sess, usr = co.srv:actor_session_fetch(co.aid, peer, co.aid_issue)
if sess.ok == false then co.aid = 0 co.aid_issue = 0 else
co.who = usr.ptr
co.who.rights.powers = server:actor_powers_fetch(co.who.id)
var userhue, hueok = server:actor_conf_int_get(co.who.id, 'ui-accent')
if hueok then co.ui_hue = userhue end
end
end
var livelast_p = lib.http.findheader(msg, 'X-Live-Last-Arrival')
if livelast_p ~= nil and livelast_p.ptr ~= nil then
|
| > > > > > > > > > > > > > > > > > > > > > > |
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 |
end ::nocookie::; end if co.aid ~= 0 then var sess, usr = co.srv:actor_session_fetch(co.aid, peer, co.aid_issue) if sess.ok == false then co.aid = 0 co.aid_issue = 0 else co.who = usr.ptr var pows = server:actor_powers_fetch(co.who.id) var privs = sess.val.privs if not privs.post() then (pows.post << false) end if not privs.edit() then (pows.edit << false) end if not privs.account() then (pows.account << false) end if not privs.artifact() then (pows.artifact << false) end if not privs.invite() then (pows.invite << false) end if not privs.moderate() then (pows.censor << false) (pows.discipline << false) (pows.vacate << false) (pows.crier << false) end if not privs.admin() then (pows.cred << false) (pows.elevate << false) (pows.demote << false) (pows.rebrand << false) (pows.herald << false) (pows.config << false) (pows.purge << false) end co.who.rights.powers = pows var userhue, hueok = server:actor_conf_int_get(co.who.id, 'ui-accent') if hueok then co.ui_hue = userhue end end end var livelast_p = lib.http.findheader(msg, 'X-Live-Last-Arrival') if livelast_p ~= nil and livelast_p.ptr ~= nil then |
Modified static/live.js from [76c21b64a1] to [c1f304b23e].
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
if (event.key == 'f') { // fave
postReq(root, 'like', post.querySelector('.stats>.like'))
} else if (event.key == 'r') { // rt
postReq(root, 'rt', post.querySelector('.stats>.rt'))
} else if (event.key == 'Enter') { // nav
window.location = root;
return;
} else if (post.attributes.getNamedItem('data-own')) {
if (event.key == 'd') { window.location = root + '/del'; }
else if (event.key == 'e') { window.location = root + '/edit'; }
else if (event.key == 'u' && root != cururl) { window.location = cururl; } // detweet
}
}
if (nexturl != null) {
if (cururl != null) {
let cur = window._liveTweetMap.map.get(cururl);
cur.me.classList.remove('live-selected')
}
|
> > < |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
if (event.key == 'f') { // fave
postReq(root, 'like', post.querySelector('.stats>.like'))
} else if (event.key == 'r') { // rt
postReq(root, 'rt', post.querySelector('.stats>.rt'))
} else if (event.key == 'Enter') { // nav
window.location = root;
return;
} else if (event.key == 'u' && root != cururl) {
window.location = cururl; // detweet TODO don't try to delete other's retweets
} else if (post.attributes.getNamedItem('data-own')) {
if (event.key == 'd') { window.location = root + '/del'; }
else if (event.key == 'e') { window.location = root + '/edit'; }
}
}
if (nexturl != null) {
if (cururl != null) {
let cur = window._liveTweetMap.map.get(cururl);
cur.me.classList.remove('live-selected')
}
|
Modified store.t from [b8bbc4e0ec] to [0ebd27b207].
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 .. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 ... 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 ... 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
'avoid', -- posts will be kept out of the timeline but will show on users' posts and in conversations
'exclude', -- own posts will not be visible to this user
};
credset = lib.set {
'pw', 'otp', 'challenge', 'trust'
};
privset = lib.set {
'post', 'edit', 'account', 'upload', 'moderate', 'admin', 'invite'
};
powerset = lib.set {
-- user powers -- default on
'login', -- not locked out
'visible', -- account & posts can be seen by others
'post', -- can do poasts
'shout', -- posts show up on local timeline
................................................................................
'invite' -- *unlimited* invites
};
prepmode = lib.enum {
'full','conf','admin'
}
}
m.privmap = {}
do local struct pt { name:lib.mem.ptr(int8), priv:m.powerset }
for k,v in pairs(m.powerset.members) do
m.privmap[#m.privmap + 1] = quote
var ps: m.powerset ps:clear()
(ps.[v] << true)
in pt {name = lib.str.plit(v), priv = ps} end
end end
terra m.powerset:affect_users()
return self.purge() or self.discipline() or self.herald() or
self.elevate() or self.demote() or self.cred()
end
local str = rawstring
................................................................................
actor_notice_enum: {&m.source, uint64} -> lib.mem.ptr(m.notice)
actor_rel_create: {&m.source, uint16, uint64, uint64} -> {}
actor_rel_destroy: {&m.source, uint16, uint64, uint64} -> {}
actor_rel_calc: {&m.source, uint64, uint64} -> m.relationship
auth_enum_uid: {&m.source, uint64} -> lib.mem.lstptr(m.auth)
auth_enum_handle: {&m.source, rawstring} -> lib.mem.lstptr(m.auth)
auth_attach_pw: {&m.source, uint64, bool, pstr, pstr} -> {}
auth_attach_key: {&m.source, uint64, bool, pstr, pstr} -> {}
-- uid: uint64
-- reset: bool (delete other passwords?)
-- pw: pstring
-- comment: pstring
auth_purge_pw: {&m.source, uint64, rawstring} -> {}
auth_purge_otp: {&m.source, uint64, rawstring} -> {}
auth_purge_trust: {&m.source, uint64, rawstring} -> {}
auth_sigtime_user_fetch: {&m.source, uint64} -> m.timepoint
-- authentication tokens and accounts have a property that controls
-- whether auth cookies dated to a certain point are valid. cookies
-- that are generated before the timepoint are considered invalid.
................................................................................
-- artifact id: uint64
-- detach: bool
post_retweet: {&m.source, uint64, uint64, bool} -> {}
post_like: {&m.source, uint64, uint64, bool} -> {}
-- undo: bool
post_react: {&m.source, uint64, uint64, pstring} -> {}
-- emoji: pstring (null to delete previous reaction, otherwise adds/changes)
post_liked_uid: {&m.source, uint64, uint64} -> bool
post_reacted_uid: {&m.source, uint64, uint64} -> bool
thread_latest_arrival_calc: {&m.source, uint64} -> m.timepoint
artifact_instantiate: {&m.source, lib.mem.ptr(uint8), lib.mem.ptr(int8)} -> uint64
-- instantiate an artifact in the database, either installing a new
-- artifact or returning the id of an existing artifact with the same hash
-- artifact: bytea
|
| > | | | | | | | | > > > > | > > > |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 .. 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 ... 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 ... 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
'avoid', -- posts will be kept out of the timeline but will show on users' posts and in conversations
'exclude', -- own posts will not be visible to this user
};
credset = lib.set {
'pw', 'otp', 'challenge', 'trust'
};
privset = lib.set {
'post', 'edit', 'account', 'upload', 'artifact', 'moderate', 'admin', 'invite'
};
powerset = lib.set {
-- user powers -- default on
'login', -- not locked out
'visible', -- account & posts can be seen by others
'post', -- can do poasts
'shout', -- posts show up on local timeline
................................................................................
'invite' -- *unlimited* invites
};
prepmode = lib.enum {
'full','conf','admin'
}
}
local function setmap(set)
local map = {}
local struct pt { name:lib.mem.ptr(int8), val:set }
for k,v in pairs(set.members) do
map[#map + 1] = quote
var ps: set ps:clear()
(ps.[v] << true)
in pt {name = lib.str.plit(v), val = ps} end
end
return map
end
m.powmap = setmap(m.powerset)
m.privmap = setmap(m.privset)
terra m.powerset:affect_users()
return self.purge() or self.discipline() or self.herald() or
self.elevate() or self.demote() or self.cred()
end
local str = rawstring
................................................................................
actor_notice_enum: {&m.source, uint64} -> lib.mem.ptr(m.notice)
actor_rel_create: {&m.source, uint16, uint64, uint64} -> {}
actor_rel_destroy: {&m.source, uint16, uint64, uint64} -> {}
actor_rel_calc: {&m.source, uint64, uint64} -> m.relationship
auth_enum_uid: {&m.source, uint64} -> lib.mem.lstptr(m.auth)
auth_enum_handle: {&m.source, rawstring} -> lib.mem.lstptr(m.auth)
auth_attach_pw: {&m.source, uint64, bool, pstr, pstr} -> uint64
auth_attach_key: {&m.source, uint64, bool, pstr, pstr} -> {}
-- uid: uint64
-- reset: bool (delete other passwords?)
-- pw: pstring
-- comment: pstring
auth_privs_set: {&m.source, uint64, m.privset} -> {}
auth_purge_pw: {&m.source, uint64, rawstring} -> {}
auth_purge_otp: {&m.source, uint64, rawstring} -> {}
auth_purge_trust: {&m.source, uint64, rawstring} -> {}
auth_sigtime_user_fetch: {&m.source, uint64} -> m.timepoint
-- authentication tokens and accounts have a property that controls
-- whether auth cookies dated to a certain point are valid. cookies
-- that are generated before the timepoint are considered invalid.
................................................................................
-- artifact id: uint64
-- detach: bool
post_retweet: {&m.source, uint64, uint64, bool} -> {}
post_like: {&m.source, uint64, uint64, bool} -> {}
-- undo: bool
post_react: {&m.source, uint64, uint64, pstring} -> {}
-- emoji: pstring (null to delete previous reaction, otherwise adds/changes)
post_act_cancel: {&m.source, uint64} -> {}
post_liked_uid: {&m.source, uint64, uint64} -> bool
post_reacted_uid: {&m.source, uint64, uint64} -> bool
post_act_fetch_notice: {&m.source, uint64} -> m.notice
thread_latest_arrival_calc: {&m.source, uint64} -> m.timepoint
artifact_instantiate: {&m.source, lib.mem.ptr(uint8), lib.mem.ptr(int8)} -> uint64
-- instantiate an artifact in the database, either installing a new
-- artifact or returning the id of an existing artifact with the same hash
-- artifact: bytea
|
Modified view/conf-sec-credmg.tpl from [6f4f9fa693] to [c30c9309b5].
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
</form>
<hr>
<form method="get">
<p>you can associate extra credentials with this account. you can also limit how much of this account’s authority these credentials can be used to exercise — for instance, it might be useful to create API keys that can read the account timeline, but not post as the account owner or access any of his administrative powers. if you don't select a capability set, the credential will be able to wield the full scope of the associated account‘s powers.</p>
<div class="check-panel">
<label><input type="checkbox" name="allow-post"> post</label>
<label><input type="checkbox" name="allow-edit"> edit</label>
<label><input type="checkbox" name="allow-acct"> manage account</label>
<label><input type="checkbox" name="allow-upload"> upload artifacts</label>
<label><input type="checkbox" name="allow-censor"> moderation</label>
<label><input type="checkbox" name="allow-admin"> other admin powers</label>
<label><input type="checkbox" name="allow-invite"> invite</label>
</div>
<p>you can also specify an IP address range in CIDR format to associate with this credential. if you do so, this credential will only be usable when connecting from an IP address in that range. otherwise, it will be valid when connecting from anywhere on the internet.</p>
<div class="elem">
<label for="netmask">netmask</label>
<input type="text" name="netmask" id="netmask" placeholder="10.0.0.0/8">
|
| > | |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
</form> <hr> <form method="get"> <p>you can associate extra credentials with this account. you can also limit how much of this account’s authority these credentials can be used to exercise — for instance, it might be useful to create API keys that can read the account timeline, but not post as the account owner or access any of his administrative powers. if you don't select a capability set, the credential will be able to wield the full scope of the associated account‘s powers.</p> <div class="check-panel"> <label><input type="checkbox" name="allow-post"> post</label> <label><input type="checkbox" name="allow-edit"> edit</label> <label><input type="checkbox" name="allow-account"> manage account settings</label> <label><input type="checkbox" name="allow-upload"> upload artifacts</label> <label><input type="checkbox" name="allow-artifact"> edit and delete artifacts</label> <label><input type="checkbox" name="allow-moderate"> moderation</label> <label><input type="checkbox" name="allow-admin"> other admin powers</label> <label><input type="checkbox" name="allow-invite"> invite</label> </div> <p>you can also specify an IP address range in CIDR format to associate with this credential. if you do so, this credential will only be usable when connecting from an IP address in that range. otherwise, it will be valid when connecting from anywhere on the internet.</p> <div class="elem"> <label for="netmask">netmask</label> <input type="text" name="netmask" id="netmask" placeholder="10.0.0.0/8"> |