26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
..
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
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
113
114
115
116
...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
...
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
...
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
...
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
....
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
....
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
....
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
|
actor_fetch_uid = {
params = {uint64}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid
from parsav_actors as a
left join parsav_servers as s
on a.origin = s.id
where a.id = $1::bigint
]];
};
................................................................................
actor_fetch_xid = {
params = {pstring}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
coalesce(s.domain,
(select value from parsav_config
where key='domain' limit 1)) as domain
from parsav_actors as a
left join parsav_servers as s
................................................................................
where $1::text = (a.handle || '@' || domain) or
$1::text = ('@' || a.handle || '@' || domain) or
(a.origin is null and
$1::text = a.handle or
$1::text = ('@' || a.handle))
]];
};
actor_save = {
params = {
uint64, --id
rawstring, --nym
rawstring, --handle
rawstring, --bio
rawstring, --epithet
rawstring, --avataruri
uint64, --avatarid
uint16, --rank
uint32 --quota
}, cmd = true, sql = [[
update parsav_actors set
nym = $2::text,
handle = $3::text,
bio = $4::text,
epithet = $5::text,
avataruri = $6::text,
avatarid = $7::bigint,
rank = $8::smallint,
quota = $9::integer
--invites are controlled by their own specialized routines
where id = $1::bigint
]];
};
actor_create = {
params = {
rawstring, rawstring, uint64, lib.store.timepoint,
rawstring, rawstring, lib.mem.ptr(uint8),
rawstring, uint16, uint32
};
sql = [[
insert into parsav_actors (
nym,handle,
origin,knownsince,
bio,avataruri,key,
epithet,rank,quota
) values ($1::text, $2::text,
case when $3::bigint = 0 then null
else $3::bigint end,
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
................................................................................
};
actor_enum_local = {
params = {}, sql = [[
select id, nym, handle, origin, bio,
null::text, rank, quota, key, epithet,
extract(epoch from knownsince)::bigint,
handle ||'@'||
(select value from parsav_config
where key='domain' limit 1) as xid
from parsav_actors where origin is null
]];
};
actor_enum = {
params = {}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid
from parsav_actors a
left join parsav_servers s on s.id = a.origin
]];
};
actor_stats = {
params = {uint64}, sql = ([[
with tweets as (
select from parsav_posts where author = $1::bigint
................................................................................
end
local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor)
var a: lib.mem.ptr(lib.store.actor)
var av: rawstring, avlen: intptr
var nym: rawstring, nymlen: intptr
var bio: rawstring, biolen: intptr
var epi: rawstring, epilen: intptr
if r:null(row,5) then avlen = 0 av = nil else
av = r:string(row,5)
avlen = r:len(row,5)+1
end
if r:null(row,1) then nymlen = 0 nym = nil else
nym = r:string(row,1)
nymlen = r:len(row,1)+1
end
if r:null(row,4) then biolen = 0 bio = nil else
bio = r:string(row,4)
biolen = r:len(row,4)+1
................................................................................
epilen = r:len(row,9)+1
end
a = [ lib.str.encapsulate(lib.store.actor, {
nym = {`nym, `nymlen};
bio = {`bio, `biolen};
epithet = {`epi, `epilen};
avatar = {`av,`avlen};
handle = {`r:string(row, 2); `r:len(row,2) + 1};
xid = {`r:string(row, 11); `r:len(row,11) + 1};
}) ]
a.ptr.id = r:int(uint64, row, 0);
a.ptr.rights = lib.store.rights_default();
a.ptr.rights.rank = r:int(uint16, row, 6);
a.ptr.rights.quota = r:int(uint32, row, 7);
a.ptr.knownsince = r:int(int64,row, 10);
if r:null(row,8) then
a.ptr.key.ct = 0 a.ptr.key.ptr = nil
else
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)
................................................................................
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})
................................................................................
return a
end
end];
actor_enum = [terra(src: &lib.store.source)
var r = queries.actor_enum.exec(src)
if r.sz == 0 then
return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var mem = lib.mem.heapa([&lib.store.actor], r.sz)
for i=0,r.sz do
mem.ptr[i] = row_to_actor(&r, i).ptr
mem.ptr[i].source = src
end
return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_enum_local = [terra(src: &lib.store.source)
var r = queries.actor_enum_local.exec(src)
if r.sz == 0 then
return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var mem = lib.mem.heapa([&lib.store.actor], r.sz)
for i=0,r.sz do
mem.ptr[i] = row_to_actor(&r, i).ptr
mem.ptr[i].source = src
end
return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_auth_how = [terra(
src: &lib.store.source,
ip: lib.store.inet,
username: rawstring
................................................................................
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.acct << r:bool(0,16))
(au.val.privs.upload << r:bool(0,17))
(au.val.privs.censor << 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 }
................................................................................
end];
actor_powers_fetch = getpow;
actor_save = [terra(
src: &lib.store.source,
ac: &lib.store.actor
): {}
queries.actor_save.exec(src,
ac.id, ac.nym, ac.handle,
ac.bio, ac.epithet, ac.avatar,
ac.avatarid, ac.rights.rank, ac.rights.quota)
end];
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_enum_uid = [terra(
src: &lib.store.source,
uid: uint64
): lib.mem.ptr(lib.mem.ptr(lib.store.auth))
var r = queries.auth_enum_uid.exec(src,uid)
if r.sz == 0 then return [lib.mem.ptr(lib.mem.ptr(lib.store.auth))].null() end
var ret = lib.mem.heapa([lib.mem.ptr(lib.store.auth)], r.sz)
|
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
>
|
>
|
|
<
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
|
|
|
>
>
>
>
>
|
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
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
164
165
166
167
168
169
170
...
802
803
804
805
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
...
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
...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
....
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
....
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
....
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
|
actor_fetch_uid = {
params = {uint64}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
a.invites
from parsav_actors as a
left join parsav_servers as s
on a.origin = s.id
where a.id = $1::bigint
]];
};
................................................................................
actor_fetch_xid = {
params = {pstring}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
a.invites,
coalesce(s.domain,
(select value from parsav_config
where key='domain' limit 1)) as domain
from parsav_actors as a
left join parsav_servers as s
................................................................................
where $1::text = (a.handle || '@' || domain) or
$1::text = ('@' || a.handle || '@' || domain) or
(a.origin is null and
$1::text = a.handle or
$1::text = ('@' || a.handle))
]];
};
actor_purge_uid = {
params = {uint64}, cmd = true, sql = [[
with d as ( -- cheating
delete from parsav_sanctions where victim = $1::bigint
)
delete from parsav_actors where id = $1::bigint
]];
};
actor_save = {
params = {
uint64, --id
rawstring, --nym
rawstring, --handle
rawstring, --bio
rawstring, --epithet
rawstring, --avataruri
uint64, --avatarid
uint16, --rank
uint32, --quota
uint32 --invites
}, cmd = true, sql = [[
update parsav_actors set
nym = $2::text,
handle = $3::text,
bio = $4::text,
epithet = $5::text,
avataruri = $6::text,
avatarid = $7::bigint,
rank = $8::smallint,
quota = $9::integer,
invites = $10::integer
where id = $1::bigint
]];
};
actor_create = {
params = {
rawstring, rawstring, uint64, lib.store.timepoint,
rawstring, rawstring, lib.mem.ptr(uint8),
rawstring, uint16, uint32, uint32
};
sql = [[
insert into parsav_actors (
nym,handle,
origin,knownsince,
bio,avataruri,key,
epithet,rank,quota,
invites
) values ($1::text, $2::text,
case when $3::bigint = 0 then null
else $3::bigint end,
to_timestamp($4::bigint),
$5::bigint, $6::bigint, $7::bytea,
$8::text, $9::smallint, $10::integer,
$11::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
................................................................................
};
actor_enum_local = {
params = {}, sql = [[
select id, nym, handle, origin, bio,
null::text, rank, quota, key, epithet,
extract(epoch from knownsince)::bigint,
'@' || handle,
invites
from parsav_actors where origin is null
order by nullif(rank,0) nulls last, handle
]];
};
actor_enum = {
params = {}, sql = [[
select a.id, a.nym, a.handle, a.origin, a.bio,
a.avataruri, a.rank, a.quota, a.key, a.epithet,
extract(epoch from a.knownsince)::bigint,
coalesce(a.handle || '@' || s.domain,
'@' || a.handle) as xid,
invites
from parsav_actors a
left join parsav_servers s on s.id = a.origin
order by nullif(a.rank,0) nulls last, a.handle, a.origin
]];
};
actor_stats = {
params = {uint64}, sql = ([[
with tweets as (
select from parsav_posts where author = $1::bigint
................................................................................
end
local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor)
var a: lib.mem.ptr(lib.store.actor)
var av: rawstring, avlen: intptr
var nym: rawstring, nymlen: intptr
var bio: rawstring, biolen: intptr
var epi: rawstring, epilen: intptr
var origin: uint64 = 0
var handle = r:_string(row, 2)
if not r:null(row,3) then origin = r:int(uint64,row,3) end
var avia = lib.str.acc {buf=nil}
if origin == 0 then
avia:compose('/avi/',handle)
av = avia.buf
avlen = avia.sz+1
elseif r:null(row,5) then
av = r:string(row,5)
avlen = r:len(row,5)+1
else
av = '/s/default-avatar.webp'
avlen = 22
end
if r:null(row,1) then nymlen = 0 nym = nil else
nym = r:string(row,1)
nymlen = r:len(row,1)+1
end
if r:null(row,4) then biolen = 0 bio = nil else
bio = r:string(row,4)
biolen = r:len(row,4)+1
................................................................................
epilen = r:len(row,9)+1
end
a = [ lib.str.encapsulate(lib.store.actor, {
nym = {`nym, `nymlen};
bio = {`bio, `biolen};
epithet = {`epi, `epilen};
avatar = {`av,`avlen};
handle = {`handle.ptr, `handle.ct + 1};
xid = {`r:string(row, 11); `r:len(row,11) + 1};
}) ]
a.ptr.id = r:int(uint64, row, 0);
a.ptr.rights = lib.store.rights_default();
a.ptr.rights.rank = r:int(uint16, row, 6);
a.ptr.rights.quota = r:int(uint32, row, 7);
a.ptr.rights.invites = r:int(uint32, row, 12);
a.ptr.knownsince = r:int(int64,row, 10);
if r:null(row,8) then
a.ptr.key.ct = 0 a.ptr.key.ptr = nil
else
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)
................................................................................
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.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})
................................................................................
return a
end
end];
actor_enum = [terra(src: &lib.store.source)
var r = queries.actor_enum.exec(src)
if r.sz == 0 then
return [lib.mem.lstptr(lib.store.actor)].null()
else defer r:free()
var mem = lib.mem.heapa([lib.mem.ptr(lib.store.actor)], r.sz)
for i=0,r.sz do
mem.ptr[i] = row_to_actor(&r, i)
mem(i).ptr.source = src
end
return [lib.mem.lstptr(lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_enum_local = [terra(src: &lib.store.source)
var r = queries.actor_enum_local.exec(src)
if r.sz == 0 then
return [lib.mem.lstptr(lib.store.actor)].null()
else defer r:free()
var mem = lib.mem.heapa([lib.mem.ptr(lib.store.actor)], r.sz)
for i=0,r.sz do
mem.ptr[i] = row_to_actor(&r, i)
mem(i).ptr.source = src
end
return [lib.mem.lstptr(lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_auth_how = [terra(
src: &lib.store.source,
ip: lib.store.inet,
username: rawstring
................................................................................
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.acct << r:bool(0,17))
(au.val.privs.upload << r:bool(0,18))
(au.val.privs.censor << r:bool(0,19))
(au.val.privs.admin << r:bool(0,20))
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 }
................................................................................
end];
actor_powers_fetch = getpow;
actor_save = [terra(
src: &lib.store.source,
ac: &lib.store.actor
): {}
var avatar = ac.avatar
if ac.origin == 0 then avatar = nil end
queries.actor_save.exec(src,
ac.id, ac.nym, ac.handle,
ac.bio, ac.epithet, avatar,
ac.avatarid, ac.rights.rank, ac.rights.quota, ac.rights.invites)
end];
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,ac.rights.invites)
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];
actor_purge_uid = [terra(
src: &lib.store.source,
uid: uint64
) queries.actor_purge_uid.exec(src,uid) end];
auth_enum_uid = [terra(
src: &lib.store.source,
uid: uint64
): lib.mem.ptr(lib.mem.ptr(lib.store.auth))
var r = queries.auth_enum_uid.exec(src,uid)
if r.sz == 0 then return [lib.mem.ptr(lib.mem.ptr(lib.store.auth))].null() end
var ret = lib.mem.heapa([lib.mem.ptr(lib.store.auth)], r.sz)
|