parsav  Diff

Differences From Artifact [2e402a5b93]:

To Artifact [17bd63f8c3]:


    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