Overview
| Comment: | add privilege control verbs |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
a64461061f49614172eea9ab72b4f428 |
| User & Date: | lexi on 2020-12-29 00:57:00 |
| Other Links: | manifest | tags |
Context
|
2020-12-29
| ||
| 14:35 | add ipc backbone check-in: 87731d4007 user: lexi tags: trunk | |
| 00:57 | add privilege control verbs check-in: a64461061f user: lexi tags: trunk | |
|
2020-12-28
| ||
| 23:42 | vastly improve the setup process check-in: d228cd7fcb user: lexi tags: trunk | |
Changes
Modified backend/pgsql.t from [0fdc39456b] to [f0f9593494].
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 ... 198 199 200 201 202 203 204 205 206 207 208 209 210 211 ... 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 ... 568 569 570 571 572 573 574 575 576 577 578 579 580 581 ... 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 ... 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 |
to_timestamp($4::bigint),
$5::bigint, $6::bigint, $7::bytea,
$8::text, $9::smallint, $10::integer
) returning id
]];
};
actor_auth_pw = {
params = {pstring,rawstring,pstring,lib.store.inet}, sql = [[
select a.aid, a.uid, a.name from parsav_auth as a
left join parsav_actors as u on u.id = a.uid
where (a.uid is null or u.handle = $1::text or (
a.uid = 0 and a.name = $1::text
)) and
................................................................................
actor_power_insert = {
params = {uint64,lib.mem.ptr(int8),uint16}, cmd = true, sql = [[
insert into parsav_rights (actor, key, allow) values (
$1::bigint, $2::text, ($3::smallint)::integer::bool
)
]]
};
auth_create_pw = {
params = {uint64, lib.mem.ptr(uint8)}, cmd = true, sql = [[
insert into parsav_auth (uid, name, kind, cred) values (
$1::bigint,
(select handle from parsav_actors where id = $1::bigint),
'pw-sha256', $2::bytea
................................................................................
a.ptr.key = r:bin(row,8)
end
if r:null(row,3) then a.ptr.origin = 0
else a.ptr.origin = r:int(uint64,row,3) end
return a
end
local privmap = {}
do local struct pt { name:pstring, priv:lib.store.powerset }
for k,v in pairs(lib.store.powerset.members) do
privmap[#privmap + 1] = quote
var ps: lib.store.powerset ps:clear()
(ps.[v] << true)
in pt {name = lib.str.plit(v), priv = ps} end
end end
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,
................................................................................
[vdrs]
lib.dbg(['could not find password hash'])
end
end
local schema = sqlsquash(lib.util.ingest('backend/schema/pgsql.sql'))
local obliterator = sqlsquash(lib.util.ingest('backend/schema/pgsql-drop.sql'))
local b = `lib.store.backend {
id = "pgsql";
open = [terra(src: &lib.store.source): &opaque
lib.report('connecting to postgres database: ', src.string.ptr)
var [con] = lib.pq.PQconnectdb(src.string.ptr)
if lib.pq.PQstatus(con) ~= lib.pq.CONNECTION_OK then
................................................................................
actor_fetch_uid = [terra(src: &lib.store.source, uid: uint64)
var r = queries.actor_fetch_uid.exec(src, uid)
if r.sz == 0 then
return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var a = row_to_actor(&r, 0)
a.ptr.source = src
return a
end
end];
actor_fetch_xid = [terra(src: &lib.store.source, xid: lib.mem.ptr(int8))
var r = queries.actor_fetch_xid.exec(src, xid)
if r.sz == 0 then
return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var a = row_to_actor(&r, 0)
a.ptr.source = src
return a
end
end];
actor_enum = [terra(src: &lib.store.source)
var r = queries.actor_enum.exec(src)
................................................................................
var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL
return ret
end];
actor_powers_fetch = [terra(
src: &lib.store.source,
uid: uint64
): lib.store.powerset
var powers = lib.store.rights_default().powers
var map = array([privmap])
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];
actor_create = [terra(
src: &lib.store.source,
ac: &lib.store.actor
): uint64
var r = queries.actor_create.exec(src,ac.nym, ac.handle, ac.origin, ac.knownsince, ac.bio, ac.avatar, ac.key, ac.epithet, ac.rights.rank, ac.rights.quota)
if r.sz == 0 then lib.bail('failed to create actor!') end
var uid = r:int(uint64,0,0)
-- check against default rights, insert records for wherever powers differ
lib.dbg('created new actor, establishing powers')
var pdef = lib.store.rights_default().powers
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
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, uid, 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, uid, map[i].name, 1)
end
end
lib.dbg('powers established')
return uid
end];
auth_create_pw = [terra(
src: &lib.store.source,
uid: uint64,
reset: bool,
pw: lib.mem.ptr(int8)
|
< > > > > > > > > | < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < | |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 ... 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 ... 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 ... 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 ... 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 ... 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
to_timestamp($4::bigint),
$5::bigint, $6::bigint, $7::bytea,
$8::text, $9::smallint, $10::integer
) returning id
]];
};
actor_auth_pw = {
params = {pstring,rawstring,pstring,lib.store.inet}, sql = [[
select a.aid, a.uid, a.name from parsav_auth as a
left join parsav_actors as u on u.id = a.uid
where (a.uid is null or u.handle = $1::text or (
a.uid = 0 and a.name = $1::text
)) and
................................................................................
actor_power_insert = {
params = {uint64,lib.mem.ptr(int8),uint16}, cmd = true, sql = [[
insert into parsav_rights (actor, key, allow) values (
$1::bigint, $2::text, ($3::smallint)::integer::bool
)
]]
};
actor_power_delete = {
params = {uint64,lib.mem.ptr(int8)}, cmd = true, sql = [[
delete from parsav_rights where
actor = $1::bigint and
key = $2::text
]]
};
auth_create_pw = {
params = {uint64, lib.mem.ptr(uint8)}, cmd = true, sql = [[
insert into parsav_auth (uid, name, kind, cred) values (
$1::bigint,
(select handle from parsav_actors where id = $1::bigint),
'pw-sha256', $2::bytea
................................................................................
a.ptr.key = r:bin(row,8)
end
if r:null(row,3) then a.ptr.origin = 0
else a.ptr.origin = r:int(uint64,row,3) 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,
................................................................................
[vdrs]
lib.dbg(['could not find password hash'])
end
end
local schema = sqlsquash(lib.util.ingest('backend/schema/pgsql.sql'))
local obliterator = sqlsquash(lib.util.ingest('backend/schema/pgsql-drop.sql'))
local privupdate = terra(
src: &lib.store.source,
ac: &lib.store.actor
): {}
var pdef = lib.store.rights_default().powers
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)
end
end
end
local getpow = terra(
src: &lib.store.source,
uid: uint64
): lib.store.powerset
var powers = lib.store.rights_default().powers
var map = array([privmap])
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
local b = `lib.store.backend {
id = "pgsql";
open = [terra(src: &lib.store.source): &opaque
lib.report('connecting to postgres database: ', src.string.ptr)
var [con] = lib.pq.PQconnectdb(src.string.ptr)
if lib.pq.PQstatus(con) ~= lib.pq.CONNECTION_OK then
................................................................................
actor_fetch_uid = [terra(src: &lib.store.source, uid: uint64)
var r = queries.actor_fetch_uid.exec(src, uid)
if r.sz == 0 then
return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var a = row_to_actor(&r, 0)
a.ptr.rights.powers = getpow(src, uid)
a.ptr.source = src
return a
end
end];
actor_fetch_xid = [terra(src: &lib.store.source, xid: lib.mem.ptr(int8))
var r = queries.actor_fetch_xid.exec(src, xid)
if r.sz == 0 then
return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var a = row_to_actor(&r, 0)
a.ptr.rights.powers = getpow(src, a.ptr.id)
a.ptr.source = src
return a
end
end];
actor_enum = [terra(src: &lib.store.source)
var r = queries.actor_enum.exec(src)
................................................................................
var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL
return ret
end];
actor_powers_fetch = getpow;
actor_save_privs = privupdate;
actor_create = [terra(
src: &lib.store.source,
ac: &lib.store.actor
): uint64
var r = queries.actor_create.exec(src,ac.nym, ac.handle, ac.origin, ac.knownsince, ac.bio, ac.avatar, ac.key, ac.epithet, ac.rights.rank, ac.rights.quota)
if r.sz == 0 then lib.bail('failed to create actor!') end
ac.id = r:int(uint64,0,0)
-- check against default rights, insert records for wherever powers differ
lib.dbg('created new actor, establishing powers')
privupdate(src,ac)
lib.dbg('powers established')
return ac.id
end];
auth_create_pw = [terra(
src: &lib.store.source,
uid: uint64,
reset: bool,
pw: lib.mem.ptr(int8)
|
Modified mgtool.t from [293667feb7] to [54eca1a845].
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 .. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 ... 219 220 221 222 223 224 225 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 |
{ 'db extract (<artifact>|<post>/<attachment number>)', 'extracts an attachment artifact from the database and prints it to standard out' };
{ 'db excise <artifact>', 'extracts an attachment artifact from the database and prints it to standard out' };
{ 'db obliterate', 'completely purge all parsav-related content and structure from the database, destroying all user content (requires confirmation)' };
{ 'db insert', 'reads a file from standard in and inserts it into the attachment database, printing the resulting ID' };
{ 'mkroot <handle>', 'establish a new root user with the given handle' };
{ 'user <handle> auth <type> new', '(where applicable, managed auth only) create a new authentication token of the given type for a user' };
{ 'user <handle> auth <type> reset', '(where applicable, managed auth only) delete all of a user\'s authentication tokens of the given type and issue a new one' };
{ 'user <handle> auth purge-credentials [<type>]', 'delete all credentials that would allow this user to log in (where possible)' };
{ 'user <handle> (grant|revoke) (<priv>|all)', 'grant or revoke a specific power to or from a user' };
{ 'user <handle> emasculate', 'strip all administrative powers from a user' };
{ 'user <handle> suspend [<timespec>]', '(e.g. \27[1muser jokester suspend 5d 6h 7m 3s\27[m to suspend "jokester" for five days, six hours, seven minutes, and three seconds) suspend a user'};
{ 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth purge-credentials\27[m to prevent a user from accessing the instance)' };
{ 'actor <xid> create', 'instantiate a new actor' };
{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
{ 'conf set <setting> <value>', 'add or a change a server configuration parameter to the database' };
{ 'conf get <setting>', 'report the value of a server setting' };
{ 'conf reset <setting>', 'reset a server setting to its default value' };
{ 'conf refresh', 'instruct an instance to refresh its configuration cache' };
{ 'conf chsec', 'reset the server secret, invalidating all authentication cookies' };
................................................................................
local terra gensec(sdest: rawstring)
var dest = [&uint8](sdest)
lib.crypt.spray(dest,64)
for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
dest[64] = 0
end
local terra entry_mgtool(argc: int, argv: &rawstring): int
if argc < 1 then lib.bail('bad invocation!') end
lib.noise_init(2)
[lib.init]
................................................................................
root.epithet = epithets[lib.crypt.random(intptr,0,[epithets.type.N])]
root.rights.powers:fill() -- grant omnipotence
root.rights.rank = 1
var ruid = dlg:actor_create(&root)
dlg:conf_set('master',root.handle)
lib.report('created new administrator')
if mg then
lib.dbg('generating temporary password')
var tmppw: uint8[33]
lib.crypt.spray(&tmppw[0],32) tmppw[32] = 0
for i=0,32 do
tmppw[i] = tmppw[i] % (10 + 26*2)
if tmppw[i] >= 36 then
tmppw[i] = tmppw[i] + (0x61 - 36)
elseif tmppw[i] >= 10 then
tmppw[i] = tmppw[i] + (0x41 - 10)
else tmppw[i] = tmppw[i] + 0x30 end
end
lib.dbg('assigning temporary password')
dlg:auth_create_pw(ruid, false, pstr {
ptr = [rawstring](&tmppw[0]), ct = 32
})
lib.report('temporary root pw: ', {[rawstring](&tmppw[0]), 32})
end
else goto cmderr end
elseif lib.str.cmp(mode.arglist(0),'user') == 0 then
elseif lib.str.cmp(mode.arglist(0),'actor') == 0 then
elseif lib.str.cmp(mode.arglist(0),'tl') == 0 then
elseif lib.str.cmp(mode.arglist(0),'serv') == 0 then
else goto cmderr end
end
end
do return 0 end
::cmderr:: lib.bail('invalid command') return 2
end
return entry_mgtool
|
| | > > > > > > > > > > > > > > > > > > < | > | < > | | | | | | | | | | | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > > | |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 .. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 ... 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 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 |
{ 'db extract (<artifact>|<post>/<attachment number>)', 'extracts an attachment artifact from the database and prints it to standard out' };
{ 'db excise <artifact>', 'extracts an attachment artifact from the database and prints it to standard out' };
{ 'db obliterate', 'completely purge all parsav-related content and structure from the database, destroying all user content (requires confirmation)' };
{ 'db insert', 'reads a file from standard in and inserts it into the attachment database, printing the resulting ID' };
{ 'mkroot <handle>', 'establish a new root user with the given handle' };
{ 'user <handle> auth <type> new', '(where applicable, managed auth only) create a new authentication token of the given type for a user' };
{ 'user <handle> auth <type> reset', '(where applicable, managed auth only) delete all of a user\'s authentication tokens of the given type and issue a new one' };
{ 'user <handle> auth (<type>|all) purge', 'delete all credentials that would allow this user to log in (where possible)' };
{ 'user <handle> (grant|revoke) (<priv>|all)', 'grant or revoke a specific power to or from a user' };
{ 'user <handle> emasculate', 'strip all administrative powers from a user' };
{ 'user <handle> suspend [<timespec>]', '(e.g. \27[1muser jokester suspend 5d 6h 7m 3s\27[m to suspend "jokester" for five days, six hours, seven minutes, and three seconds) suspend a user'};
{ 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' };
{ 'actor <xid> create', 'instantiate a new actor' };
{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
{ 'conf set <setting> <value>', 'add or a change a server configuration parameter to the database' };
{ 'conf get <setting>', 'report the value of a server setting' };
{ 'conf reset <setting>', 'reset a server setting to its default value' };
{ 'conf refresh', 'instruct an instance to refresh its configuration cache' };
{ 'conf chsec', 'reset the server secret, invalidating all authentication cookies' };
................................................................................
local terra gensec(sdest: rawstring)
var dest = [&uint8](sdest)
lib.crypt.spray(dest,64)
for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
dest[64] = 0
end
local terra pwset(dlg: idelegate, buf: &(int8[33]), uid: uint64, reset: bool)
lib.dbg('generating temporary password')
var tmppw = [&uint8](&(buf[0]))
lib.crypt.spray(tmppw,32) tmppw[32] = 0
for i=0,32 do
tmppw[i] = tmppw[i] % (10 + 26*2)
if tmppw[i] >= 36 then
tmppw[i] = tmppw[i] + (0x61 - 36)
elseif tmppw[i] >= 10 then
tmppw[i] = tmppw[i] + (0x41 - 10)
else tmppw[i] = tmppw[i] + 0x30 end
end
lib.dbg('assigning temporary password')
dlg:auth_create_pw(uid, reset, pstr {
ptr = [rawstring](tmppw), ct = 32
})
end
local terra entry_mgtool(argc: int, argv: &rawstring): int
if argc < 1 then lib.bail('bad invocation!') end
lib.noise_init(2)
[lib.init]
................................................................................
root.epithet = epithets[lib.crypt.random(intptr,0,[epithets.type.N])]
root.rights.powers:fill() -- grant omnipotence
root.rights.rank = 1
var ruid = dlg:actor_create(&root)
dlg:conf_set('master',root.handle)
lib.report('created new administrator')
if mg then
var tmppw: int8[33]
pwset(dlg, &tmppw, ruid, false)
lib.report('temporary root pw: ', {&tmppw[0], 32})
end
else goto cmderr end
elseif lib.str.cmp(mode.arglist(0),'user') == 0 then
var umode: pbasic umode:parse(mode.arglist.ct, &mode.arglist(0))
if umode.help then
[ lib.emit(false, 1, 'usage: ', `argv[0], ' user ', umode.type.helptxt.flags, ' <handle> <cmd> [<args>…]', umode.type.helptxt.opts) ]
return 1
end
if umode.arglist.ct >= 3 then
var grant = lib.str.cmp(umode.arglist(1),'grant') == 0
var handle = umode.arglist(0)
var usr = dlg:actor_fetch_xid(pstr {ptr=handle, ct=lib.str.sz(handle)})
if not usr then lib.bail('unknown handle') 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
usr.ptr.rights.powers = newprivs
dlg:actor_save_privs(usr.ptr)
elseif lib.str.cmp(umode.arglist(1),'auth') == 0 and umode.arglist.ct == 4 then
var reset = lib.str.cmp(umode.arglist(3),'reset') == 0
if reset or lib.str.cmp(umode.arglist(3),'new') == 0 then
if lib.str.cmp(umode.arglist(2),'pw') == 0 then
var tmppw: int8[33]
pwset(dlg, &tmppw, usr.ptr.id, reset)
lib.report('new temporary password for ',usr.ptr.handle,': ', {&tmppw[0], 32})
else lib.bail('unknown credential type') end
elseif lib.str.cmp(umode.arglist(3),'purge') == 0 then
else goto cmderr end
else goto cmderr end
else goto cmderr end
elseif lib.str.cmp(mode.arglist(0),'actor') == 0 then
elseif lib.str.cmp(mode.arglist(0),'tl') == 0 then
elseif lib.str.cmp(mode.arglist(0),'serv') == 0 then
else goto cmderr end
end
end
do return 0 end
::cmderr:: lib.bail('invalid command')
end
return entry_mgtool
|
Modified parsav.md from [4b27db126a] to [409d9b6b60].
49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
master pgsql host=localhost dbname=parsav
tweets pgsql host=420.69.dread.cloud dbname=content
the form the configuration string takes depends on the specific backend.
once you've set up a backend and confirmed parsav can connect succesfully to it, you can initialize the database with the command `parsav db init <domain>`, where `<domain>` is the name of the domain name you will be hosting `parsav` from. this will install all necessary structures and functions in the target and create all necessary files. it will not, however, create any users. you can create an initial administrative user with the `parsav mkroot <handle>` command, where `<handle>` is the handle you want to use on the server. this will also assign a temporary password for the user if possible. you should now be able to log in and administer the server.
by default, parsav binds to [::1]:10917. if you want to change this (to run it on a different port, or make it directly accessible to other servers on the network), you can use the command `parsav conf set bind <address>`, where `address` is a binding specification like `0.0.0.0:80`. it is recommended, however, that `parsavd` be kept accessible only from localhost, and that connections be forwarded to it from nginx, haproxy, or a similar reverse proxy. (this can also be changed with the online configuration UI)
### postgresql backend
a database will need to be created for `parsav`'s use before `parsav db init` will work. this can be accomplished with a command like `$ createdb parsav`. you'll also of course need to set up some way for `parsavd` to authenticate itself to `postgres`. peer auth is the most secure option, and this is what you should use if postgres and `parsavd` are running on the same box. specify the database name to the backend the usual way, with a clause like `dbname=parsav` in your connection string.
|
> > |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
master pgsql host=localhost dbname=parsav
tweets pgsql host=420.69.dread.cloud dbname=content
the form the configuration string takes depends on the specific backend.
once you've set up a backend and confirmed parsav can connect succesfully to it, you can initialize the database with the command `parsav db init <domain>`, where `<domain>` is the name of the domain name you will be hosting `parsav` from. this will install all necessary structures and functions in the target and create all necessary files. it will not, however, create any users. you can create an initial administrative user with the `parsav mkroot <handle>` command, where `<handle>` is the handle you want to use on the server. this will also assign a temporary password for the user if possible. you should now be able to log in and administer the server.
if something goes awry with your administrative account, don't fret! you can get your powers themselves back with the command `parsav user <handle> grant all`, and if you're having difficulties logging in, the command `parsav user <handle> auth pw reset` will give you a fresh password. if all else fails, you can always run `mkroot` again to create a new root account, and try to repair the damage from there.
by default, parsav binds to [::1]:10917. if you want to change this (to run it on a different port, or make it directly accessible to other servers on the network), you can use the command `parsav conf set bind <address>`, where `address` is a binding specification like `0.0.0.0:80`. it is recommended, however, that `parsavd` be kept accessible only from localhost, and that connections be forwarded to it from nginx, haproxy, or a similar reverse proxy. (this can also be changed with the online configuration UI)
### postgresql backend
a database will need to be created for `parsav`'s use before `parsav db init` will work. this can be accomplished with a command like `$ createdb parsav`. you'll also of course need to set up some way for `parsavd` to authenticate itself to `postgres`. peer auth is the most secure option, and this is what you should use if postgres and `parsavd` are running on the same box. specify the database name to the backend the usual way, with a clause like `dbname=parsav` in your connection string.
|
Modified route.t from [4fbd6ed0a5] to [4ebb6db558].
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
else ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end end return end terra http.post_compose(co: &lib.srv.convo, meth: method.t) if meth == method.get then lib.render.compose(co, nil) elseif meth == method.post then if co.who.rights.powers.post() == false then co:complain(401,'insufficient privileges','you lack the <strong>post</strong> power and cannot perform this action') return end var text, textlen = co:postv("post") var acl, acllen = co:postv("acl") var subj, subjlen = co:postv("subject") if text == nil or acl == nil then co:complain(405, 'invalid post', 'every post must have at least body text and an ACL') return end |
> > > > < < < |
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
else ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end end return end terra http.post_compose(co: &lib.srv.convo, meth: method.t) if not co:assertpow('post') then return end --if co.who.rights.powers.post() == false then --co:complain(403,'insufficient privileges','you lack the <strong>post</strong> power and cannot perform this action') if meth == method.get then lib.render.compose(co, nil) elseif meth == method.post then var text, textlen = co:postv("post") var acl, acllen = co:postv("acl") var subj, subjlen = co:postv("subject") if text == nil or acl == nil then co:complain(405, 'invalid post', 'every post must have at least body text and an ACL') return end |
Modified srv.t from [7234d58b59] to [7c204f248d].
179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
body:send(self.con, code, [lib.mem.ptr(lib.http.header)] {
ptr = &hdrs[0], ct = [hdrs.type.N]
})
body.title:free()
body.body:free()
end
struct convo.page {
title: pstring
body: pstring
class: pstring
}
|
> > > > > > > > > > |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
body:send(self.con, code, [lib.mem.ptr(lib.http.header)] {
ptr = &hdrs[0], ct = [hdrs.type.N]
})
body.title:free()
body.body:free()
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
in ok end
end)
struct convo.page {
title: pstring
body: pstring
class: pstring
}
|
Modified store.t from [71684bc451] to [3a79c99b1d].
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
'cred', 'elevate', 'demote', 'rebrand', -- modify site's brand identity
'herald' -- grant serverwide epithets
};
prepmode = lib.enum {
'full','conf','admin'
}
}
terra m.powerset:affect_users()
return self.purge() or self.censor() or self.suspend() or
self.elevate() or self.demote() or self.cred()
end
local str = rawstring
................................................................................
conprep: {&m.source, m.prepmode.t} -> {} -- prepares queries and similar tasks that require the schema to already be in place
obliterate_everything: &m.source -> bool -- wipes everything parsav-related out of the database
conf_get: {&m.source, rawstring} -> lib.mem.ptr(int8)
conf_set: {&m.source, rawstring, rawstring} -> {}
conf_reset: {&m.source, rawstring} -> {}
actor_save: {&m.source, &m.actor} -> bool
actor_create: {&m.source, &m.actor} -> uint64
actor_fetch_xid: {&m.source, lib.mem.ptr(int8)} -> lib.mem.ptr(m.actor)
actor_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.actor)
actor_notif_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.notif)
actor_enum: {&m.source} -> lib.mem.ptr(&m.actor)
actor_enum_local: {&m.source} -> lib.mem.ptr(&m.actor)
actor_stats: {&m.source, uint64} -> m.actor_stats
|
>
>
>
>
>
>
>
>
>
|
|
|
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
'cred', 'elevate', 'demote', 'rebrand', -- modify site's brand identity
'herald' -- grant serverwide epithets
};
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.censor() or self.suspend() or
self.elevate() or self.demote() or self.cred()
end
local str = rawstring
................................................................................
conprep: {&m.source, m.prepmode.t} -> {} -- prepares queries and similar tasks that require the schema to already be in place
obliterate_everything: &m.source -> bool -- wipes everything parsav-related out of the database
conf_get: {&m.source, rawstring} -> lib.mem.ptr(int8)
conf_set: {&m.source, rawstring, rawstring} -> {}
conf_reset: {&m.source, rawstring} -> {}
actor_create: {&m.source, &m.actor} -> uint64
actor_save_privs: {&m.source, &m.actor} -> {}
actor_fetch_xid: {&m.source, lib.mem.ptr(int8)} -> lib.mem.ptr(m.actor)
actor_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.actor)
actor_notif_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.notif)
actor_enum: {&m.source} -> lib.mem.ptr(&m.actor)
actor_enum_local: {&m.source} -> lib.mem.ptr(&m.actor)
actor_stats: {&m.source, uint64} -> m.actor_stats
|