Differences From
Artifact [2e402a5b93]:
29 29 bio, rank, quota, key
30 30 from parsav_actors
31 31 where id = $1::bigint
32 32 ]];
33 33 };
34 34
35 35 actor_fetch_xid = {
36 - params = {rawstring}, sql = [[
36 + params = {lib.mem.ptr(int8)}, sql = [[
37 37 select a.id, a.nym, a.handle, a.origin,
38 - a.bio, a.rank, a.quota, a.key, $1::text,
38 + a.bio, a.rank, a.quota, a.key,
39 + coalesce(a.handle || '@' || s.domain,
40 + '@' || a.handle) as xid,
39 41
40 42 coalesce(s.domain,
41 43 (select value from parsav_config
42 44 where key='domain' limit 1)) as domain
43 45
44 46 from parsav_actors as a
45 47 left join parsav_servers as s
46 48 on a.origin = s.id
47 49
48 50 where $1::text = (a.handle || '@' || domain) or
49 51 $1::text = ('@' || a.handle || '@' || domain) or
50 - (a.origin is null and $1::text = ('@' || a.handle))
52 + (a.origin is null and
53 + $1::text = a.handle or
54 + $1::text = ('@' || a.handle))
51 55 ]];
52 56 };
53 57
54 58 actor_enum_local = {
55 59 params = {}, sql = [[
56 60 select id, nym, handle, origin,
57 61 bio, rank, quota, key,
................................................................................
62 66 ]];
63 67 };
64 68
65 69 actor_enum = {
66 70 params = {}, sql = [[
67 71 select a.id, a.nym, a.handle, a.origin,
68 72 a.bio, a.rank, a.quota, a.key,
69 - a.handle ||'@'||
70 - coalesce(s.domain,
71 - (select value from parsav_config
72 - where key='domain' limit 1)) as xid
73 + coalesce(a.handle || '@' || s.domain,
74 + '@' || a.handle) as xid
73 75 from parsav_actors a
74 76 left join parsav_servers s on s.id = a.origin
75 77 ]];
76 78 };
79 +
80 + actor_auth_how = {
81 + params = {rawstring, lib.store.inet}, sql = [[
82 + with mts as (select a.kind from parsav_auth as a
83 + left join parsav_actors as u on u.id = a.uid
84 + where (a.uid is null or u.handle = $1::text or (
85 + a.uid = 0 and a.name = $1::text
86 + )) and
87 + (a.netmask is null or a.netmask >> $2::inet) and
88 + blacklist = false)
89 +
90 + select
91 + (select count(*) from mts where kind like 'pw-%') > 0,
92 + (select count(*) from mts where kind like 'otp-%') > 0,
93 + (select count(*) from mts where kind like 'challenge-%') > 0,
94 + (select count(*) from mts where kind = 'trust') > 0
95 + ]]; -- cheat
96 + };
97 +
98 + actor_session_fetch = {
99 + params = {uint64, lib.store.inet}, sql = [[
100 + select a.id, a.nym, a.handle, a.origin,
101 + a.bio, a.rank, a.quota, a.key,
102 + coalesce(a.handle || '@' || s.domain,
103 + '@' || a.handle) as xid,
104 +
105 + au.restrict,
106 + array['post' ] <@ au.restrict as can_post,
107 + array['edit' ] <@ au.restrict as can_edit,
108 + array['acct' ] <@ au.restrict as can_acct,
109 + array['upload'] <@ au.restrict as can_upload,
110 + array['censor'] <@ au.restrict as can_censor,
111 + array['admin' ] <@ au.restrict as can_admin
112 +
113 + from parsav_auth au
114 + left join parsav_actors a on au.uid = a.id
115 + left join parsav_servers s on a.origin = s.id
116 +
117 + where au.aid = $1::bigint and au.blacklist = false and
118 + (au.netmask is null or au.netmask >> $2::inet)
119 + ]];
120 + };
77 121 }
78 122
79 123 local struct pqr {
80 124 sz: intptr
81 125 res: &lib.pq.PGresult
82 126 }
83 127 terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end
................................................................................
85 129 return (lib.pq.PQgetisnull(self.res, row, col) == 1)
86 130 end
87 131 terra pqr:len(row: intptr, col: intptr)
88 132 return lib.pq.PQgetlength(self.res, row, col)
89 133 end
90 134 terra pqr:cols() return lib.pq.PQnfields(self.res) end
91 135 terra pqr:string(row: intptr, col: intptr) -- not to be exported!!
136 + if self:null(row,col) then return nil end
92 137 var v = lib.pq.PQgetvalue(self.res, row, col)
93 138 -- var r: lib.mem.ptr(int8)
94 139 -- r.ct = lib.str.sz(v)
95 140 -- r.ptr = v
96 141 return v
97 142 end
98 143 terra pqr:bin(row: intptr, col: intptr) -- not to be exported!! DO NOT FREE
99 144 return [lib.mem.ptr(uint8)] {
100 145 ptr = [&uint8](lib.pq.PQgetvalue(self.res, row, col));
101 146 ct = lib.pq.PQgetlength(self.res, row, col);
102 147 }
103 148 end
104 149 terra pqr:String(row: intptr, col: intptr) -- suitable to be exported
150 + if self:null(row,col) then return [lib.mem.ptr(int8)] {ptr=nil,ct=0} end
105 151 var s = [lib.mem.ptr(int8)] { ptr = lib.str.dup(self:string(row,col)) }
106 152 s.ct = lib.pq.PQgetlength(self.res, row, col)
107 153 return s
108 154 end
109 155 terra pqr:bool(row: intptr, col: intptr)
110 156 var v = lib.pq.PQgetvalue(self.res, row, col)
111 157 if @v == 0x01 then return true else return false end
................................................................................
176 222 local args, casts, counters, fixers, ft, yield = {}, {}, {}, {}, {}, {}
177 223 for i, ty in ipairs(q.params) do
178 224 args[i] = symbol(ty)
179 225 ft[i] = `1
180 226 if ty == rawstring then
181 227 counters[i] = `lib.trn([args[i]] == nil, 0, lib.str.sz([args[i]]))
182 228 casts[i] = `[&int8]([args[i]])
229 + elseif ty == lib.store.inet then -- assume not CIDR
230 + counters[i] = `lib.trn([args[i]].pv == 4,4,16)+4
231 + casts[i] = quote
232 + var ipbuf: int8[20]
233 + ;[pqt[lib.store.inet](false)]([args[i]], [&uint8](&ipbuf))
234 + in &ipbuf[0] end
235 + elseif ty.ptr_basetype == int8 or ty.ptr_basetype == uint8 then
236 + counters[i] = `[args[i]].ct
237 + casts[i] = `[&int8]([args[i]].ptr)
183 238 elseif ty:isintegral() then
184 239 counters[i] = ty.bytes
185 240 casts[i] = `[&int8](&[args[i]])
186 241 fixers[#fixers + 1] = quote
187 242 --lib.io.fmt('uid=%llu(%llx)\n',[args[i]],[args[i]])
188 243 [args[i]] = lib.math.netswap(ty, [args[i]])
189 244 end
................................................................................
212 267 return pqr {ct, res}
213 268 end
214 269 end
215 270 end
216 271
217 272 local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor)
218 273 var a: lib.mem.ptr(lib.store.actor)
274 +
219 275 if r:cols() >= 8 then
220 276 a = [ lib.str.encapsulate(lib.store.actor, {
221 - nym = {`r:string(row, 1); `r:len(row,1) + 1};
277 + nym = {`r:string(row,1), `r:len(row,1)+1};
278 + bio = {`r:string(row,4), `r:len(row,4)+1};
222 279 handle = {`r:string(row, 2); `r:len(row,2) + 1};
223 - bio = {`r:string(row, 4); `r:len(row,4) + 1};
224 280 xid = {`r:string(row, 8); `r:len(row,8) + 1};
225 281 }) ]
226 282 else
227 283 a = [ lib.str.encapsulate(lib.store.actor, {
228 - nym = {`r:string(row, 1); `r:len(row,1) + 1};
284 + nym = {`r:string(row,1), `r:len(row,1)+1};
285 + bio = {`r:string(row,4), `r:len(row,4)+1};
229 286 handle = {`r:string(row, 2); `r:len(row,2) + 1};
230 - bio = {`r:string(row, 4); `r:len(row,4) + 1};
231 287 }) ]
232 288 a.ptr.xid = nil
233 289 end
234 290 a.ptr.id = r:int(uint64, row, 0);
235 291 a.ptr.rights = lib.store.rights_default();
236 292 a.ptr.rights.rank = r:int(uint16, row, 5);
237 293 a.ptr.rights.quota = r:int(uint32, row, 6);
................................................................................
345 401 return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
346 402 else defer r:free()
347 403 var a = row_to_actor(&r, 0)
348 404 a.ptr.source = src
349 405 return a
350 406 end
351 407 end];
408 +
409 + actor_fetch_xid = [terra(src: &lib.store.source, xid: lib.mem.ptr(int8))
410 + var r = queries.actor_fetch_xid.exec(src, xid)
411 + if r.sz == 0 then
412 + return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
413 + else defer r:free()
414 + var a = row_to_actor(&r, 0)
415 + a.ptr.source = src
416 + return a
417 + end
418 + end];
352 419
353 420 actor_enum = [terra(src: &lib.store.source)
354 421 var r = queries.actor_enum.exec(src)
355 422 if r.sz == 0 then
356 423 return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil }
357 424 else defer r:free()
358 425 var mem = lib.mem.heapa([&lib.store.actor], r.sz)
................................................................................
373 440 end];
374 441
375 442 actor_auth_how = [terra(
376 443 src: &lib.store.source,
377 444 ip: lib.store.inet,
378 445 username: rawstring
379 446 )
380 - var authview = src:conf_get('auth-source') defer authview:free()
381 - var a: lib.str.acc defer a:free()
382 - a:compose('with mts as (select a.kind from ',authview,[' ' .. sqlsquash [[as a
383 - left join parsav_actors as u on u.id = a.uid
384 - where (a.uid is null or u.handle = $1::text or (
385 - a.uid = 0 and a.name = $1::text
386 - )) and
387 - (a.netmask is null or a.netmask >> $2::inet) and
388 - blacklist = false)
389 -
390 - select
391 - (select count(*) from mts where kind like 'pw-%') > 0,
392 - (select count(*) from mts where kind like 'otp-%') > 0,
393 - (select count(*) from mts where kind like 'challenge-%') > 0,
394 - (select count(*) from mts where kind = 'trust') > 0 ]]]) -- cheat
395 447 var cs: lib.store.credset cs:clear();
396 - var ipbuf: int8[20]
397 - ;[pqt[lib.store.inet](false)](ip, [&uint8](&ipbuf))
398 - var ipbl: intptr if ip.pv == 4 then ipbl = 8 else ipbl = 20 end
399 - var params = arrayof(rawstring, username, [&int8](&ipbuf))
400 - var params_sz = arrayof(int, lib.str.sz(username), ipbl)
401 - var params_ft = arrayof(int, 1, 1)
402 - var res = lib.pq.PQexecParams([&lib.pq.PGconn](src.handle), a.buf, 2, nil,
403 - params, params_sz, params_ft, 1)
404 - if res == nil or lib.pq.PQresultStatus(res) ~= lib.pq.PGRES_TUPLES_OK then
405 - if res == nil then
406 - lib.bail('grievous error occurred checking for auth methods')
407 - end
408 - lib.bail('could not get auth methods for user ',username,':\n',lib.pq.PQresultErrorMessage(res))
409 - end
410 - var r = pqr { res = res, sz = lib.pq.PQntuples(res) }
448 + var r = queries.actor_auth_how.exec(src, username, ip)
411 449 if r.sz == 0 then return cs end -- just in case
450 + defer r:free()
412 451 (cs.pw << r:bool(0,0))
413 452 (cs.otp << r:bool(0,1))
414 453 (cs.challenge << r:bool(0,2))
415 454 (cs.trust << r:bool(0,3))
416 - lib.pq.PQclear(res)
417 455 return cs
418 456 end];
419 457
420 458 actor_auth_pw = [terra(
421 459 src: &lib.store.source,
422 460 ip: lib.store.inet,
423 461 username: rawstring,
424 462 cred: rawstring
425 463 )
426 - var authview = src:conf_get('auth-source') defer authview:free()
427 - var a: lib.str.acc defer a:free()
428 - a:compose('select a.aid from ',authview,[' ' .. sqlsquash [[as a
464 + var q = [[select a.aid from parsav_auth as a
429 465 left join parsav_actors as u on u.id = a.uid
430 466 where (a.uid is null or u.handle = $1::text or (
431 467 a.uid = 0 and a.name = $1::text
432 468 )) and
433 469 (a.kind = 'trust' or (a.kind = $2::text and a.cred = $3::bytea)) and
434 470 (a.netmask is null or a.netmask >> $4::inet)
435 - order by blacklist desc limit 1]]])
471 + order by blacklist desc limit 1]]
436 472
437 - [ checksha(`src.handle, `a.buf, 256, ip, username, cred) ] -- most common
438 - [ checksha(`src.handle, `a.buf, 512, ip, username, cred) ] -- most secure
439 - [ checksha(`src.handle, `a.buf, 384, ip, username, cred) ] -- weird
440 - [ checksha(`src.handle, `a.buf, 224, ip, username, cred) ] -- weirdest
473 + [ checksha(`src.handle, q, 256, ip, username, cred) ] -- most common
474 + [ checksha(`src.handle, q, 512, ip, username, cred) ] -- most secure
475 + [ checksha(`src.handle, q, 384, ip, username, cred) ] -- weird
476 + [ checksha(`src.handle, q, 224, ip, username, cred) ] -- weirdest
441 477
442 478 -- TODO: check pbkdf2-hmac
443 479 -- TODO: check OTP
444 480 return 0
445 481 end];
482 +
483 + actor_session_fetch = [terra(
484 + src: &lib.store.source,
485 + aid: uint64,
486 + ip : lib.store.inet
487 + ): { lib.stat(lib.store.auth), lib.mem.ptr(lib.store.actor) }
488 + var r = queries.actor_session_fetch.exec(src, aid, ip)
489 + if r.sz == 0 then goto fail end
490 + do defer r:free()
491 +
492 + if r:null(0,0) then goto fail end
493 +
494 + var a = row_to_actor(&r, 0)
495 + a.ptr.source = src
496 +
497 + var au = [lib.stat(lib.store.auth)] { ok = true }
498 + au.val.aid = aid
499 + au.val.uid = a.ptr.id
500 + if not r:null(0,10) then -- restricted?
501 + au.val.privs:clear()
502 + (au.val.privs.post << r:bool(0,11))
503 + (au.val.privs.edit << r:bool(0,12))
504 + (au.val.privs.acct << r:bool(0,13))
505 + (au.val.privs.upload << r:bool(0,14))
506 + (au.val.privs.censor << r:bool(0,15))
507 + (au.val.privs.admin << r:bool(0,16))
508 + else au.val.privs:fill() end
509 +
510 + return au, a
511 + end
512 +
513 + ::fail:: return [lib.stat (lib.store.auth) ] { ok = false },
514 + [lib.mem.ptr(lib.store.actor)] { ptr = nil, ct = 0 }
515 + end];
446 516 }
447 517
448 518 return b