Overview
| Comment: | continued iteration |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
25e05466d5017e26f9260db3969473dc |
| User & Date: | lexi on 2020-12-21 01:08:01 |
| Other Links: | manifest | tags |
Context
|
2020-12-22
| ||
| 23:01 | milestone check-in: 419d1a1ebe user: lexi tags: trunk | |
|
2020-12-21
| ||
| 01:08 | continued iteration check-in: 25e05466d5 user: lexi tags: trunk | |
|
2020-12-16
| ||
| 08:46 | add nix build file check-in: df4ae251ef user: lexi tags: trunk | |
Changes
Modified backend/pgsql.t from [0360541ecf] to [2e402a5b93].
31 31 where id = $1::bigint 32 32 ]]; 33 33 }; 34 34 35 35 actor_fetch_xid = { 36 36 params = {rawstring}, sql = [[ 37 37 select a.id, a.nym, a.handle, a.origin, 38 - a.bio, a.rank, a.quota, a.key, 38 + a.bio, a.rank, a.quota, a.key, $1::text, 39 39 40 40 coalesce(s.domain, 41 41 (select value from parsav_config 42 42 where key='domain' limit 1)) as domain 43 43 44 44 from parsav_actors as a 45 45 left join parsav_servers as s ................................................................................ 46 46 on a.origin = s.id 47 47 48 48 where $1::text = (a.handle || '@' || domain) or 49 49 $1::text = ('@' || a.handle || '@' || domain) or 50 50 (a.origin is null and $1::text = ('@' || a.handle)) 51 51 ]]; 52 52 }; 53 + 54 + actor_enum_local = { 55 + params = {}, sql = [[ 56 + select id, nym, handle, origin, 57 + bio, rank, quota, key, 58 + handle ||'@'|| 59 + (select value from parsav_config 60 + where key='domain' limit 1) as xid 61 + from parsav_actors where origin is null 62 + ]]; 63 + }; 64 + 65 + actor_enum = { 66 + params = {}, sql = [[ 67 + select a.id, a.nym, a.handle, a.origin, 68 + 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 + from parsav_actors a 74 + left join parsav_servers s on s.id = a.origin 75 + ]]; 76 + }; 53 77 } 54 78 55 79 local struct pqr { 56 80 sz: intptr 57 81 res: &lib.pq.PGresult 58 82 } 59 83 terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end 60 84 terra pqr:null(row: intptr, col: intptr) 61 85 return (lib.pq.PQgetisnull(self.res, row, col) == 1) 62 86 end 63 -terra pqr:string(row: intptr, col: intptr) 87 +terra pqr:len(row: intptr, col: intptr) 88 + return lib.pq.PQgetlength(self.res, row, col) 89 +end 90 +terra pqr:cols() return lib.pq.PQnfields(self.res) end 91 +terra pqr:string(row: intptr, col: intptr) -- not to be exported!! 92 + var v = lib.pq.PQgetvalue(self.res, row, col) 93 +-- var r: lib.mem.ptr(int8) 94 +-- r.ct = lib.str.sz(v) 95 +-- r.ptr = v 96 + return v 97 +end 98 +terra pqr:bin(row: intptr, col: intptr) -- not to be exported!! DO NOT FREE 99 + return [lib.mem.ptr(uint8)] { 100 + ptr = [&uint8](lib.pq.PQgetvalue(self.res, row, col)); 101 + ct = lib.pq.PQgetlength(self.res, row, col); 102 + } 103 +end 104 +terra pqr:String(row: intptr, col: intptr) -- suitable to be exported 105 + var s = [lib.mem.ptr(int8)] { ptr = lib.str.dup(self:string(row,col)) } 106 + s.ct = lib.pq.PQgetlength(self.res, row, col) 107 + return s 108 +end 109 +terra pqr:bool(row: intptr, col: intptr) 110 + var v = lib.pq.PQgetvalue(self.res, row, col) 111 + if @v == 0x01 then return true else return false end 112 +end 113 +terra pqr:cidr(row: intptr, col: intptr) 64 114 var v = lib.pq.PQgetvalue(self.res, row, col) 65 - var r: lib.mem.ptr(int8) 66 - r.ct = lib.str.sz(v) 67 - r.ptr = lib.str.ndup(v, r.ct) 68 - return r 115 + var i: lib.store.inet 116 + if v[0] == 0x02 then i.pv = 4 117 + elseif v[0] == 0x03 then i.pv = 6 118 + else lib.bail('invalid CIDR type in stream') end 119 + i.fixbits = v[1] 120 + if v[2] ~= 0x1 then lib.bail('expected CIDR but got inet from stream') end 121 + if i.pv == 4 and v[3] ~= 0x04 or i.pv == 6 and v[3] ~= 0x10 then 122 + lib.bail('CIDR failed length sanity check') end 123 + 124 + var sz: intptr if i.pv == 4 then sz = 4 else sz = 16 end 125 + for j=0,sz do i.v6[j] = v[4 + j] end -- 😬 126 + return i 69 127 end 70 128 pqr.methods.int = macro(function(self, ty, row, col) 71 129 return quote 72 130 var i: ty:astype() 73 131 var v = lib.pq.PQgetvalue(self.res, row, col) 74 132 lib.math.netswap_ip(ty, v, &i) 75 133 in i end 76 134 end) 135 + 136 +local pqt = { 137 + [lib.store.inet] = function(cidr) 138 + local tycode = cidr and 0x01 or 0x00 139 + return terra(i: lib.store.inet, buf: &uint8) 140 + var sz: intptr 141 + if i.pv == 4 then sz = 4 else sz = 16 end 142 + if buf == nil then buf = [&uint8](lib.mem.heapa_raw(sz + 4)) end 143 + if i.pv == 4 then buf[0] = 0x02 144 + elseif i.pv == 6 then buf[0] = 0x03 end 145 + if cidr then -- our local 'inet' is not quite orthogonal to the 146 + -- postgres inet type; tweak it to match (ignore port) 147 + buf[1] = i.fixbits 148 + elseif i.pv == 6 then buf[1] = 128 149 + else buf[1] = 32 end 150 + buf[2] = tycode 151 + buf[3] = sz 152 + for j=0,sz do buf[4 + j] = i.v6[j] end -- 😬 153 + return buf 154 + end 155 + end; 156 +} 77 157 78 158 local con = symbol(&lib.pq.PGconn) 79 159 local prep = {} 160 +local sqlsquash = function(s) return s:gsub('%s+',' '):gsub('^%s*(.-)%s*$','%1') end 80 161 for k,q in pairs(queries) do 81 - local qt = (q.sql):gsub('%s+',' '):gsub('^%s*(.-)%s*$','%1') 162 + local qt = sqlsquash(q.sql) 82 163 local stmt = 'parsavpg_' .. k 83 164 prep[#prep + 1] = quote 84 165 var res = lib.pq.PQprepare([con], stmt, qt, [#q.params], nil) 85 166 defer lib.pq.PQclear(res) 86 167 if res == nil or lib.pq.PQresultStatus(res) ~= lib.pq.PGRES_COMMAND_OK then 87 168 if res == nil then 88 169 lib.bail('grievous error occurred preparing ',k,' statement') ................................................................................ 105 186 fixers[#fixers + 1] = quote 106 187 --lib.io.fmt('uid=%llu(%llx)\n',[args[i]],[args[i]]) 107 188 [args[i]] = lib.math.netswap(ty, [args[i]]) 108 189 end 109 190 end 110 191 end 111 192 112 - q.exec = terra(src: &lib.store.source, [args]) 193 + terra q.exec(src: &lib.store.source, [args]) 113 194 var params = arrayof([&int8], [casts]) 114 195 var params_sz = arrayof(int, [counters]) 115 196 var params_ft = arrayof(int, [ft]) 116 197 [fixers] 117 198 var res = lib.pq.PQexecPrepared([&lib.pq.PGconn](src.handle), stmt, 118 199 [#args], params, params_sz, params_ft, 1) 119 200 if res == nil then ................................................................................ 129 210 return pqr {0, nil} 130 211 else 131 212 return pqr {ct, res} 132 213 end 133 214 end 134 215 end 135 216 136 -local terra row_to_actor(r: &pqr, row: intptr): lib.store.actor 137 - var a = lib.store.actor { 138 - id = r:int(uint64, row, 0); 139 - nym = r:string(row, 1); 140 - handle = r:string(row, 2); 141 - bio = r:string(row, 4); 142 - key = r:string(row, 7); 143 - rights = lib.store.rights_default(); 144 - } 145 - a.rights.rank = r:int(uint16, 0, 5); 146 - a.rights.quota = r:int(uint32, 0, 6); 147 - if r:null(0,3) then a.origin = 0 148 - else a.origin = r:int(uint64,0,3) end 217 +local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor) 218 + var a: lib.mem.ptr(lib.store.actor) 219 + if r:cols() >= 8 then 220 + a = [ lib.str.encapsulate(lib.store.actor, { 221 + nym = {`r:string(row, 1); `r:len(row,1) + 1}; 222 + handle = {`r:string(row, 2); `r:len(row,2) + 1}; 223 + bio = {`r:string(row, 4); `r:len(row,4) + 1}; 224 + xid = {`r:string(row, 8); `r:len(row,8) + 1}; 225 + }) ] 226 + else 227 + a = [ lib.str.encapsulate(lib.store.actor, { 228 + nym = {`r:string(row, 1); `r:len(row,1) + 1}; 229 + handle = {`r:string(row, 2); `r:len(row,2) + 1}; 230 + bio = {`r:string(row, 4); `r:len(row,4) + 1}; 231 + }) ] 232 + a.ptr.xid = nil 233 + end 234 + a.ptr.id = r:int(uint64, row, 0); 235 + a.ptr.rights = lib.store.rights_default(); 236 + a.ptr.rights.rank = r:int(uint16, row, 5); 237 + a.ptr.rights.quota = r:int(uint32, row, 6); 238 + if r:null(row,7) then 239 + a.ptr.key.ct = 0 a.ptr.key.ptr = nil 240 + else 241 + a.ptr.key = r:bin(row,7) 242 + end 243 + if r:null(row,3) then a.ptr.origin = 0 244 + else a.ptr.origin = r:int(uint64,row,3) end 149 245 return a 150 246 end 247 + 248 +local checksha = function(hnd, query, hash, origin, username, pw) 249 + local inet_buf = symbol(uint8[4 + 16]) 250 + local validate = function(kind, cred, credlen) 251 + return quote 252 + var osz: intptr if origin.pv == 4 then osz = 4 else osz = 16 end 253 + var formats = arrayof([int], 1,1,1,1) 254 + var params = arrayof([&int8], username, kind, 255 + [&int8](&cred), [&int8](&inet_buf)) 256 + var lens = arrayof(int, lib.str.sz(username), [#kind], credlen, osz + 4) 257 + var res = lib.pq.PQexecParams([&lib.pq.PGconn](hnd), query, 4, nil, 258 + params, lens, formats, 1) 259 + if res == nil then 260 + lib.bail('grievous failure checking pwhash') 261 + elseif lib.pq.PQresultStatus(res) ~= lib.pq.PGRES_TUPLES_OK then 262 + lib.warn('pwhash query failed: ', lib.pq.PQresultErrorMessage(res), '\n', query) 263 + else 264 + var r = pqr { 265 + sz = lib.pq.PQntuples(res); 266 + res = res; 267 + } 268 + if r.sz > 0 then -- found a record! stop here 269 + var aid = r:int(uint64, 0,0) 270 + r:free() 271 + return aid 272 + end 273 + end 274 + end 275 + end 276 + 277 + local out = symbol(uint8[64]) 278 + local vdrs = {} 279 + 280 + local alg = lib.md['MBEDTLS_MD_SHA' .. tostring(hash)] 281 + vdrs[#vdrs+1] = quote 282 + if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(alg), 283 + [&uint8](pw), lib.str.sz(pw), out) ~= 0 then 284 + lib.bail('hashing failure!') 285 + end 286 + [ validate(string.format('pw-sha%u', hash), out, hash / 8) ] 287 + end 288 + 289 + return quote 290 + lib.dbg(['searching for hashed password credentials in format SHA' .. tostring(hash)]) 291 + var [inet_buf] 292 + [pqt[lib.store.inet](false)](origin, inet_buf) 293 + var [out] 294 + [vdrs] 295 + lib.dbg(['could not find password hash']) 296 + end 297 +end 151 298 152 299 local b = `lib.store.backend { 153 300 id = "pgsql"; 154 301 open = [terra(src: &lib.store.source): &opaque 155 302 lib.report('connecting to postgres database: ', src.string.ptr) 156 303 var [con] = lib.pq.PQconnectdb(src.string.ptr) 157 304 if lib.pq.PQstatus(con) ~= lib.pq.CONNECTION_OK then ................................................................................ 158 305 lib.warn('postgres backend connection failed') 159 306 lib.pq.PQfinish(con) 160 307 return nil 161 308 end 162 309 var res = lib.pq.PQexec(con, [[ 163 310 select pg_catalog.set_config('search_path', 'public', false) 164 311 ]]) 165 - if res ~= nil then defer lib.pq.PQclear(res) end 166 - if res == nil or lib.pq.PQresultStatus(res) ~= lib.pq.PGRES_TUPLES_OK then 312 + if res == nil then 313 + lib.warn('critical failure to secure postgres connection') 314 + lib.pq.PQfinish(con) 315 + return nil 316 + end 317 + 318 + defer lib.pq.PQclear(res) 319 + if lib.pq.PQresultStatus(res) ~= lib.pq.PGRES_TUPLES_OK then 167 320 lib.warn('failed to secure postgres connection') 168 321 lib.pq.PQfinish(con) 169 322 return nil 170 323 end 171 324 172 325 [prep] 173 326 return con ................................................................................ 174 327 end]; 175 328 close = [terra(src: &lib.store.source) lib.pq.PQfinish([&lib.pq.PGconn](src.handle)) end]; 176 329 177 330 conf_get = [terra(src: &lib.store.source, key: rawstring) 178 331 var r = queries.conf_get.exec(src, key) 179 332 if r.sz == 0 then return [lib.mem.ptr(int8)] { ptr = nil, ct = 0 } else 180 333 defer r:free() 181 - return r:string(0,0) 334 + return r:String(0,0) 182 335 end 183 336 end]; 184 337 conf_set = [terra(src: &lib.store.source, key: rawstring, val: rawstring) 185 338 queries.conf_set.exec(src, key, val):free() end]; 186 339 conf_reset = [terra(src: &lib.store.source, key: rawstring) 187 340 queries.conf_reset.exec(src, key):free() end]; 188 341 189 342 actor_fetch_uid = [terra(src: &lib.store.source, uid: uint64) 190 343 var r = queries.actor_fetch_uid.exec(src, uid) 191 344 if r.sz == 0 then 192 - return [lib.stat(lib.store.actor)] { ok = false, error = 1} 193 - else 194 - defer r:free() 195 - var a = [lib.stat(lib.store.actor)] { ok = true } 196 - a.val = row_to_actor(&r, 0) 197 - a.val.source = src 345 + return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil } 346 + else defer r:free() 347 + var a = row_to_actor(&r, 0) 348 + a.ptr.source = src 198 349 return a 199 350 end 200 351 end]; 352 + 353 + actor_enum = [terra(src: &lib.store.source) 354 + var r = queries.actor_enum.exec(src) 355 + if r.sz == 0 then 356 + return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil } 357 + else defer r:free() 358 + var mem = lib.mem.heapa([&lib.store.actor], r.sz) 359 + for i=0,r.sz do mem.ptr[i] = row_to_actor(&r, i).ptr end 360 + return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr } 361 + end 362 + end]; 363 + 364 + actor_enum_local = [terra(src: &lib.store.source) 365 + var r = queries.actor_enum_local.exec(src) 366 + if r.sz == 0 then 367 + return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil } 368 + else defer r:free() 369 + var mem = lib.mem.heapa([&lib.store.actor], r.sz) 370 + for i=0,r.sz do mem.ptr[i] = row_to_actor(&r, i).ptr end 371 + return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr } 372 + end 373 + end]; 374 + 375 + actor_auth_how = [terra( 376 + src: &lib.store.source, 377 + ip: lib.store.inet, 378 + username: rawstring 379 + ) 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 + 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) } 411 + if r.sz == 0 then return cs end -- just in case 412 + (cs.pw << r:bool(0,0)) 413 + (cs.otp << r:bool(0,1)) 414 + (cs.challenge << r:bool(0,2)) 415 + (cs.trust << r:bool(0,3)) 416 + lib.pq.PQclear(res) 417 + return cs 418 + end]; 419 + 420 + actor_auth_pw = [terra( 421 + src: &lib.store.source, 422 + ip: lib.store.inet, 423 + username: rawstring, 424 + cred: rawstring 425 + ) 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 429 + left join parsav_actors as u on u.id = a.uid 430 + where (a.uid is null or u.handle = $1::text or ( 431 + a.uid = 0 and a.name = $1::text 432 + )) and 433 + (a.kind = 'trust' or (a.kind = $2::text and a.cred = $3::bytea)) and 434 + (a.netmask is null or a.netmask >> $4::inet) 435 + order by blacklist desc limit 1]]]) 436 + 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 441 + 442 + -- TODO: check pbkdf2-hmac 443 + -- TODO: check OTP 444 + return 0 445 + end]; 201 446 } 202 447 203 448 return b
Modified cmdparse.t from [c7f162fae3] to [bad20dd1d0].
5 5 local helpstr = 'usage: parsav [-' .. flags .. '] [<arg>...]\n' 6 6 options.entries = { 7 7 {field = 'arglist', type = lib.mem.ptr(rawstring)} 8 8 } 9 9 local shortcases, longcases, init = {}, {}, {} 10 10 local self = symbol(&options) 11 11 local arg = symbol(rawstring) 12 + local idxo = symbol(uint) 12 13 local skip = label() 14 + local sanitize = function(s) return s:gsub('_','-') end 13 15 for o,desc in pairs(tbl) do 16 + local consume = desc[3] or 0 14 17 options.entries[#options.entries + 1] = { 15 - field = o, type = bool 18 + field = o, type = (consume > 0) and uint or bool 16 19 } 17 20 helpstr = helpstr .. string.format(' -%s --%s: %s\n', 18 - desc[1], o, desc[2]) 21 + desc[1], sanitize(o), desc[2]) 19 22 end 20 23 for o,desc in pairs(tbl) do 21 24 local flag = desc[1] 22 - init[#init + 1] = quote [self].[o] = false end 25 + local consume = desc[3] or 0 26 + init[#init + 1] = quote [self].[o] = [consume > 0 and 0 or false] end 27 + local ch if consume > 0 then ch = quote 28 + [self].[o] = idxo 29 + idxo = idxo + consume 30 + end else ch = quote 31 + [self].[o] = true 32 + end end 23 33 shortcases[#shortcases + 1] = quote 24 - case [int8]([string.byte(flag)]) then [self].[o] = true end 34 + case [int8]([string.byte(flag)]) then [ch] end 25 35 end 26 36 longcases[#longcases + 1] = quote 27 - if lib.str.cmp([arg]+2, o) == 0 then 28 - [self].[o] = true 29 - goto [skip] 30 - end 37 + if lib.str.cmp([arg]+2, [sanitize(o)]) == 0 then [ch] goto [skip] end 31 38 end 32 39 end 40 + terra options:free() self.arglist:free() end 33 41 options.methods.parse = terra([self], argc: int, argv: &rawstring) 34 42 [init] 35 43 var parseopts = true 44 + var [idxo] = 1 36 45 self.arglist = lib.mem.heapa(rawstring, argc) 37 46 var finalargc = 0 38 - for i=0,argc do 47 + for i=1,argc do 39 48 var [arg] = argv[i] 40 49 if arg[0] == ('-')[0] and parseopts then 41 50 if arg[1] == ('-')[0] then -- long option 42 51 if arg[2] == 0 then -- last option 43 52 parseopts = false 44 53 else [longcases] end 45 54 else -- short options
Modified config.lua from [60797f7bc4] to [53779583db].
10 10 end 11 11 end 12 12 local posixes = { 13 13 linux = true; osx = true; 14 14 android = true; haiku = true; 15 15 } 16 16 local default_os = 'linux' 17 +local defaultlist = function(env, ...) 18 + local e = os.getenv(env) 19 + local lst = {} 20 + if e then 21 + for v in e:gmatch('([^:]*)') do lst[#lst + 1] = v end 22 + return lst 23 + else return {...} end 24 +end 17 25 local conf = { 18 26 pkg = {}; 19 27 dist = default('parsav_dist', coalesce( 20 28 os.getenv('NIX_PATH') and 'nixos', 21 29 os.getenv('NIX_STORE') and 'nixos', 22 30 '')); 23 31 tgttrip = default('parsav_arch_triple'); -- target triple, used in xcomp ................................................................................ 26 34 endian = default('parsav_arch_endian', 'little'); 27 35 build = { 28 36 id = u.rndstr(6); 29 37 release = u.ingest('release'); 30 38 when = os.date(); 31 39 }; 32 40 feat = {}; 41 + backends = defaultlist('parsav_backends', 'pgsql'); 42 + braingeniousmode = false; 33 43 } 34 44 if u.ping '.fslckout' or u.ping '_FOSSIL_' then 35 45 if u.ping '_FOSSIL_' then default_os = 'windows' end 36 46 conf.build.branch = u.exec { 'fossil', 'branch', 'current' } 37 47 conf.build.checkout = (u.exec { 'fossil', 'sql', 38 48 [[select value from localdb.vvar where name = 'checkout-hash']] 39 49 }):gsub("^'(.*)'$", '%1')
Modified crypt.t from [340864c560] to [709e2a6426].
10 10 end; 11 11 toobig = -lib.pk.MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; 12 12 } 13 13 const.maxpemsz = math.floor((const.keybits / 8)*6.4) + 128 -- idk why this formula works but it basically seems to 14 14 15 15 local ctx = lib.pk.mbedtls_pk_context 16 16 17 +local struct hashalg { id: uint8 bytes: intptr } 17 18 local m = { 18 19 pemfile = uint8[const.maxpemsz]; 20 + alg = { 21 + sha1 = `hashalg {id = lib.md.MBEDTLS_MD_SHA1; bytes = 160/8}; 22 + sha256 = `hashalg {id = lib.md.MBEDTLS_MD_SHA256; bytes = 256/8}; 23 + sha512 = `hashalg {id = lib.md.MBEDTLS_MD_SHA512; bytes = 512/8}; 24 + sha384 = `hashalg {id = lib.md.MBEDTLS_MD_SHA384; bytes = 384/8}; 25 + sha224 = `hashalg {id = lib.md.MBEDTLS_MD_SHA224; bytes = 224/8}; 26 + -- md5 = {id = lib.md.MBEDTLS_MD_MD5};-- !!! 27 + }; 19 28 } 20 29 local callbacks = {} 21 30 if config.feat.randomizer == 'kern' then 22 31 local rnd = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff); 23 32 terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int 24 33 return rnd(dest, sz, 0) 25 34 end ................................................................................ 132 141 if lib.pk.mbedtls_pk_verify(pk, hk, hash, 0, [&uint8](sig), siglen) == 0 then 133 142 return true, secl 134 143 end 135 144 end 136 145 lib.dbg('all hash algorithms failed') 137 146 return false, 0 138 147 end 148 + 149 +terra m.hmac(alg: hashalg, key: lib.mem.ptr(uint8), txt: lib.mem.ptr(int8), buf: &uint8) 150 + lib.md.mbedtls_md_hmac( 151 + lib.md.mbedtls_md_info_from_type(alg.id), 152 + key.ptr, key.ct, 153 + [&uint8](txt.ptr), txt.ct, 154 + buf) -- sz(buf) >= hash output size 155 +end 156 + 157 +terra m.hmaca(alg: hashalg, key: lib.mem.ptr(uint8), txt: lib.mem.ptr(int8)) 158 + var buf = lib.mem.heapa(uint8, alg.bytes) 159 + m.hmac(alg, key, txt, buf.ptr) 160 + return buf 161 +end 162 + 163 +terra m.hotp(key: &(uint8[10]), counter: uint64) 164 + var hmac: uint8[20] 165 + var ctr = [lib.mem.ptr(int8)]{ptr = [&int8](&counter), ct = 8} 166 + m.hmac(m.alg.sha1, 167 + [lib.mem.ptr(uint8)]{ptr = [&uint8](key), ct = 10}, 168 + ctr, hmac) 169 + 170 + var ofs = hmac[19] and 0x0F 171 + var p: uint8[4] 172 + for i=0,4 do p[i] = hmac[ofs + i] end 173 + 174 + return (@[&uint32](&p)) and 0x7FFFFFFF -- one hopes it's that easy 175 +end 139 176 140 177 return m
Added license.de version [34fb6d78d2].
1 +OPEN-SOURCE-LIZENZ FÜR DIE EUROPÄISCHE UNION v. 1.2 2 +EUPL © Europäische Union 2007, 2016 3 +Diese Open-Source-Lizenz für die Europäische Union („EUPL“) gilt für Werke (im Sinne der nachfolgenden Begriffsbestimmung), die unter EUPL-Bedingungen zur Verfügung gestellt werden. Das Werk darf nur in der durch diese Lizenz gestatteten Form genutzt werden (insoweit eine solche Nutzung dem Urheber vorbehalten ist). 4 +Das Werk wird unter den Bedingungen dieser Lizenz zur Verfügung gestellt, wenn der Lizenzgeber (im Sinne der nachfolgenden Begriffsbestimmung) den folgenden Hinweis unmittelbar hinter dem Urheberrechtshinweis dieses Werks anbringt: 5 + Lizenziert unter der EUPL 6 +oder in einer anderen Form zum Ausdruck bringt, dass er es unter der EUPL lizenzieren möchte. 7 + 8 +1.Begriffsbestimmungen 9 +Für diese Lizenz gelten folgende Begriffsbestimmungen: 10 +— „Lizenz“:diese Lizenz. 11 +— „Originalwerk“:das Werk oder die Software, die vom Lizenzgeber unter dieser Lizenz verbreitet oder zugänglich gemacht wird, und zwar als Quellcode und gegebenenfalls auch als ausführbarer Code. 12 +— „Bearbeitungen“:die Werke oder Software, die der Lizenznehmer auf der Grundlage des Originalwerks oder seiner Bearbeitungen schaffen kann. In dieser Lizenz wird nicht festgelegt, wie umfangreich die Änderung oder wie stark die Abhängigkeit vom Originalwerk für eine Einstufung als Bearbeitung sein muss; dies bestimmt sich nach dem Urheberrecht, das in dem unter Artikel 15 aufgeführten Land anwendbar ist. 13 +— „Werk“:das Originalwerk oder seine Bearbeitungen. 14 +— „Quellcode“:diejenige Form des Werkes, die zur Auffassung durch den Menschen bestimmt ist und die am besten geeignet ist, um vom Menschen verstanden und verändert zu werden. 15 +— „Ausführbarer Code“:die — üblicherweise — kompilierte Form des Werks, die von einem Computer als Programm ausgeführt werden soll. 16 +— „Lizenzgeber“:die natürliche oder juristische Person, die das Werk unter der Lizenz verbreitet oder zugänglich macht. 17 +— „Bearbeiter“:jede natürliche oder juristische Person, die das Werk unter der Lizenz verändert oder auf andere Weise zur Schaffung einer Bearbeitung beiträgt. 18 +— „Lizenznehmer“ („Sie“):jede natürliche oder juristische Person, die das Werk unter den Lizenzbedingungen nutzt. 19 +— „Verbreitung“ oder „Zugänglichmachung“:alle Formen von Verkauf, Überlassung, Verleih, Vermietung, Verbreitung, Weitergabe, Übermittlung oder anderweitiger Online- oder Offline-Bereitstellung von Vervielfältigungen des Werks oder Zugänglichmachung seiner wesentlichen Funktionen für dritte natürliche oder juristische Personen. 20 + 21 +2.Umfang der Lizenzrechte 22 +Der Lizenzgeber erteilt Ihnen hiermit für die Gültigkeitsdauer der am Originalwerk bestehenden Urheberrechte eine weltweite, unentgeltliche, nicht ausschließliche, unterlizenzierbare Lizenz, die Sie berechtigt: 23 +— das Werk uneingeschränkt zu nutzen, 24 +— das Werk zu vervielfältigen, 25 +— das Werk zu verändern und Bearbeitungen auf der Grundlage des Werks zu schaffen, 26 +— das Werk öffentlich zugänglich zu machen, was das Recht einschließt, das Werk oder Vervielfältigungsstücke davon öffentlich bereitzustellen oder wahrnehmbar zu machen oder das Werk, soweit möglich, öffentlich aufzuführen, 27 +— das Werk oder Vervielfältigungen davon zu verbreiten, 28 +— das Werk oder Vervielfältigungen davon zu vermieten oder zu verleihen, 29 +— das Werk oder Vervielfältigungen davon weiter zu lizenzieren. 30 +Für die Wahrnehmung dieser Rechte können beliebige, derzeit bekannte oder künftige Medien, Träger und Formate verwendet werden, soweit das geltende Recht dem nicht entgegensteht. Für die Länder, in denen Urheberpersönlichkeitsrechte an dem Werk bestehen, verzichtet der Lizenzgeber im gesetzlich zulässigen Umfang auf seine Urheberpersönlichkeitsrechte, um die Lizenzierung der oben aufgeführten Verwertungsrechte wirksam durchführen zu können. Der Lizenzgeber erteilt dem Lizenznehmer ein nicht ausschließliches, unentgeltliches Nutzungsrecht an seinen Patenten, sofern dies zur Ausübung der durch die Lizenz erteilten Nutzungsrechte am Werk notwendig ist. 31 + 32 +3.Zugänglichmachung des Quellcodes 33 +Der Lizenzgeber kann das Werk entweder als Quellcode oder als ausführbaren Code zur Verfügung stellen. Stellt er es als ausführbaren Code zur Verfügung, so stellt er darüber hinaus eine maschinenlesbare Kopie des Quellcodes für jedes von ihm verbreitete Vervielfältigungsstück des Werks zur Verfügung, oder er verweist in einem Vermerk im Anschluss an den dem Werk beigefügten Urheberrechtshinweis auf einen Speicherort, an dem problemlos und unentgeltlich auf den Quellcode zugegriffen werden kann, solange der Lizenzgeber das Werk verbreitet oder zugänglich macht. 34 + 35 +4.Einschränkungen des Urheberrechts 36 +Es ist nicht Zweck dieser Lizenz, Ausnahmen oder Schranken der ausschließlichen Rechte des Urhebers am Werk, die dem Lizenznehmer zugutekommen, einzuschränken. Auch die Erschöpfung dieser Rechte bleibt von dieser Lizenz unberührt. 37 + 38 +5.Pflichten des Lizenznehmers 39 +Die Einräumung der oben genannten Rechte ist an mehrere Beschränkungen und Pflichten für den Lizenznehmer gebunden: 40 + 41 +Urheberrechtshinweis, Lizenztext, Nennung des Bearbeiters: Der Lizenznehmer muss alle Urheberrechts-, Patent- oder Markenrechtshinweise und alle Hinweise auf die Lizenz und den Haftungsausschluss unverändert lassen. Jedem von ihm verbreiteten oder zugänglich gemachten Vervielfältigungsstück des Werks muss der Lizenznehmer diese Hinweise sowie diese Lizenz beifügen. Der Lizenznehmer muss auf jedem abgeleiteten Werk deutlich darauf hinweisen, dass das Werk geändert wurde, und das Datum der Bearbeitung angeben. 42 + 43 +„Copyleft“-Klausel: Der Lizenznehmer darf Vervielfältigungen des Originalwerks oder Bearbeitungen nur unter den Bedingungen dieser EUPL oder einer neueren Version dieser Lizenz verbreiten oder zugänglich machen, außer wenn das Originalwerk ausdrücklich nur unter dieser Lizenzversion — z. B. mit der Angabe „Nur EUPL V. 1.2“ — verbreitet werden darf. Der Lizenznehmer (der zum Lizenzgeber wird) darf für das Werk oder die Bearbeitung keine zusätzlichen Bedingungen anbieten oder vorschreiben, die die Bedingungen dieser Lizenz verändern oder einschränken. 44 + 45 +Kompatibilitäts-Klausel: Wenn der Lizenznehmer Bearbeitungen, die auf dem Werk und einem anderen Werk, das unter einer kompatiblen Lizenz lizenziert wurde, basieren, oder die Kopien dieser Bearbeitungen verbreitet oder zugänglich macht, kann dies unter den Bedingungen dieser kompatiblen Lizenz erfolgen. Unter „kompatibler Lizenz“ ist eine im Anhang dieser Lizenz angeführte Lizenz zu verstehen. Sollten die Verpflichtungen des Lizenznehmers aus der kompatiblen Lizenz mit denjenigen aus der vorliegenden Lizenz (EUPL) in Konflikt stehen, werden die Verpflichtungen aus der kompatiblen Lizenz Vorrang haben. 46 + 47 +Bereitstellung des Quellcodes: Wenn der Lizenznehmer Vervielfältigungsstücke des Werks verbreitet oder zugänglich macht, muss er eine maschinenlesbare Fassung des Quellcodes mitliefern oder einen Speicherort angeben, über den problemlos und unentgeltlich so lange auf diesen Quellcode zugegriffen werden kann, wie der Lizenznehmer das Werk verbreitet oder zugänglich macht. 48 + 49 +Rechtsschutz: Diese Lizenz erlaubt nicht die Benutzung von Kennzeichen, Marken oder geschützten Namensrechten des Lizenzgebers, soweit dies nicht für die angemessene und übliche Beschreibung der Herkunft des Werks und der inhaltlichen Wiedergabe des Urheberrechtshinweises erforderlich ist. 50 + 51 +6.Urheber und Bearbeiter 52 +Der ursprüngliche Lizenzgeber gewährleistet, dass er das Urheberrecht am Originalwerk innehat oder dieses an ihn lizenziert wurde und dass er befugt ist, diese Lizenz zu erteilen. 53 +Jeder Bearbeiter gewährleistet, dass er das Urheberrecht an den von ihm vorgenommenen Änderungen des Werks besitzt und befugt ist, diese Lizenz zu erteilen. 54 +Jedes Mal, wenn Sie die Lizenz annehmen, erteilen Ihnen der ursprüngliche Lizenzgeber und alle folgenden Bearbeiter eine Befugnis zur Nutzung ihrer Beiträge zum Werk unter den Bedingungen dieser Lizenz. 55 + 56 +7.Gewährleistungsausschluss 57 +Die Arbeit an diesem Werk wird laufend fortgeführt; es wird durch unzählige Bearbeiter ständig verbessert. Das Werk ist nicht vollendet und kann daher Fehler („bugs“) enthalten, die dieser Art der Entwicklung inhärent sind. 58 +Aus den genannten Gründen wird das Werk unter dieser Lizenz „so, wie es ist“ ohne jegliche Gewährleistung zur Verfügung gestellt. Dies gilt unter anderem — aber nicht ausschließlich — für Marktreife, Verwendbarkeit für einen bestimmten Zweck, Mängelfreiheit, Richtigkeit sowie Nichtverletzung von anderen Immaterialgüterrechten als dem Urheberrecht (vgl. dazu Artikel 6 dieser Lizenz). 59 +Dieser Gewährleistungsausschluss ist wesentlicher Bestandteil der Lizenz und Bedingung für die Einräumung von Rechten an dem Werk. 60 + 61 +8.Haftungsausschluss/Haftungsbeschränkung 62 +Außer in Fällen von Vorsatz oder der Verursachung von Personenschäden haftet der Lizenzgeber nicht für direkte oder indirekte, materielle oder immaterielle Schäden irgendwelcher Art, die aus der Lizenz oder der Benutzung des Werks folgen; dies gilt unter anderem, aber nicht ausschließlich, für Firmenwertverluste, Produktionsausfall, Computerausfall oder Computerfehler, Datenverlust oder wirtschaftliche Schäden, und zwar auch dann, wenn der Lizenzgeber auf die Möglichkeit solcher Schäden hingewiesen wurde. Unabhängig davon haftet der Lizenzgeber im Rahmen der gesetzlichen Produkthaftung, soweit die entsprechenden Regelungen auf das Werk anwendbar sind. 63 + 64 +9.Zusatzvereinbarungen 65 +Wenn Sie das Werk verbreiten, können Sie Zusatzvereinbarungen schließen, in denen Verpflichtungen oder Dienstleistungen festgelegt werden, die mit dieser Lizenz vereinbar sind. Sie dürfen Verpflichtungen indessen nur in Ihrem eigenen Namen und auf Ihre eigene Verantwortung eingehen, nicht jedoch im Namen des ursprünglichen Lizenzgebers oder eines anderen Bearbeiters, und nur, wenn Sie sich gegenüber allen Bearbeitern verpflichten, sie zu entschädigen, zu verteidigen und von der Haftung freizustellen, falls aufgrund der von Ihnen eingegangenen Gewährleistungsverpflichtung oder Haftungsübernahme Forderungen gegen sie geltend gemacht werden oder eine Haftungsverpflichtung entsteht. 66 + 67 +10.Annahme der Lizenz 68 +Sie können den Bestimmungen dieser Lizenz zustimmen, indem Sie das Symbol „Lizenz annehmen“ unter dem Fenster mit dem Lizenztext anklicken oder indem Sie Ihre Zustimmung auf vergleichbare Weise in einer nach anwendbarem Recht zulässigen Form geben. Das Anklicken des Symbols gilt als Anzeichen Ihrer eindeutigen und unwiderruflichen Annahme der Lizenz und der darin enthaltenen Klauseln und Bedingungen. In gleicher Weise gilt als Zeichen der eindeutigen und unwiderruflichen Zustimmung die Ausübung eines Rechtes, das in Artikel 2 dieser Lizenz angeführt ist, wie das Erstellen einer Bearbeitung oder die Verbreitung oder Zugänglichmachung des Werks oder dessen Vervielfältigungen. 69 + 70 +11.Informationspflichten 71 +Wenn Sie das Werk verbreiten oder zugänglich machen (beispielsweise, indem Sie es zum Herunterladen von einer Website anbieten), müssen Sie über den Vertriebskanal oder das benutzte Verbreitungsmedium der Öffentlichkeit zumindest jene Informationen bereitstellen, die nach dem anwendbaren Recht bezüglich der Lizenzgeber, der Lizenz und ihrer Zugänglichkeit, des Abschlusses des Lizenzvertrags sowie darüber, wie die Lizenz durch den Lizenznehmer gespeichert und vervielfältigt werden kann, erforderlich sind. 72 + 73 +12.Beendigung der Lizenz 74 +Die Lizenz und die damit eingeräumten Rechte erlöschen automatisch, wenn der Lizenznehmer gegen die Lizenzbedingungen verstößt. Ein solches Erlöschen der Lizenz führt nicht zum Erlöschen der Lizenzen von Personen, denen das Werk vom Lizenznehmer unter dieser Lizenz zur Verfügung gestellt worden ist, solange diese Personen die Lizenzbedingungen erfüllen. 75 +13.Sonstiges 76 +Unbeschadet des Artikels 9 stellt die Lizenz die vollständige Vereinbarung der Parteien über das Werk dar. Sind einzelne Bestimmungen der Lizenz nach geltendem Recht nichtig oder unwirksam, so berührt dies nicht die Wirksamkeit oder Durchsetzbarkeit der Lizenz an sich. Solche Bestimmungen werden vielmehr so ausgelegt oder modifiziert, dass sie wirksam und durchsetzbar sind. Die Europäische Kommission kann weitere Sprachfassungen oder neue Versionen dieser Lizenz oder aktualisierte Fassungen des Anhangs veröffentlichen, soweit dies notwendig und angemessen ist, ohne den Umfang der Lizenzrechte zu verringern. Neue Versionen werden mit einer eindeutigen Versionsnummer veröffentlicht. Alle von der Europäischen Kommission anerkannten Sprachfassungen dieser Lizenz sind gleichwertig. Die Parteien können sich auf die Sprachfassung ihrer Wahl berufen. 77 + 78 +14.Gerichtsstand 79 +Unbeschadet besonderer Vereinbarungen zwischen den Parteien gilt Folgendes: 80 +— Für alle Streitigkeiten über die Auslegung dieser Lizenz zwischen den Organen, Einrichtungen und sonstigen Stellen der Europäischen Union als Lizenzgeber und einem Lizenznehmer ist der Gerichtshof der Europäischen Union gemäß Artikel 272 des Vertrags über die Arbeitsweise der Europäischen Union zuständig; 81 +— Gerichtsstand für Streitigkeiten zwischen anderen Parteien über die Auslegung dieser Lizenz ist allein der Ort, an dem der Lizenzgeber seinen Wohnsitz oder den wirtschaftlichen Mittelpunkt seiner Tätigkeit hat. 82 + 83 +15.Anwendbares Recht 84 +Unbeschadet besonderer Vereinbarungen zwischen den Parteien gilt Folgendes: 85 +— Diese Lizenz unterliegt dem Recht des Mitgliedstaats der Europäischen Union, in dem der Lizenzgeber seinen Sitz, Wohnsitz oder eingetragenen Sitz hat; 86 +— diese Lizenz unterliegt dem belgischen Recht, wenn der Lizenzgeber keinen Sitz, Wohnsitz oder eingetragenen Sitz in einem Mitgliedstaat der Europäischen Union hat. 87 + 88 +Anlage 89 +„Kompatible Lizenzen“ nach Artikel 5 der EUPL sind: 90 +— GNU General Public License (GPL) v. 2, v. 3 91 +— GNU Affero General Public License (AGPL) v. 3 92 +— Open Software License (OSL) v. 2.1, v. 3.0 93 +— Eclipse Public License (EPL) v. 1.0 94 +— CeCILL v. 2.0, v. 2.1 95 +— Mozilla Public Licence (MPL) v. 2 96 +— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 97 +— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) für andere Werke als Software 98 +— European Union Public Licence (EUPL) v. 1.1, v. 1.2 99 +— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) oder Strong Reciprocity (LiLiQ-R+) 100 +Die Europäische Kommission kann diesen Anhang aktualisieren, um neuere Fassungen der obigen Lizenzen aufzunehmen, ohne hierfür eine neue Fassung der EUPL auszuarbeiten, solange diese Lizenzen die in Artikel 2 gewährten Rechte gewährleisten und den erfassten Quellcode vor ausschließlicher Aneignung schützen. 101 +Alle sonstigen Änderungen oder Ergänzungen dieses Anhangs bedürfen der Ausarbeitung einer neuen Version der EUPL.
Added license.en version [fc940c93f2].
1 + EUROPEAN UNION PUBLIC LICENCE v. 1.2 2 + EUPL © the European Union 2007, 2016 3 + 4 +This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined 5 +below) which is provided under the terms of this Licence. Any use of the Work, 6 +other than as authorised under this Licence is prohibited (to the extent such 7 +use is covered by a right of the copyright holder of the Work). 8 + 9 +The Work is provided under the terms of this Licence when the Licensor (as 10 +defined below) has placed the following notice immediately following the 11 +copyright notice for the Work: 12 + 13 + Licensed under the EUPL 14 + 15 +or has expressed by any other means his willingness to license under the EUPL. 16 + 17 +1. Definitions 18 + 19 +In this Licence, the following terms have the following meaning: 20 + 21 +- ‘The Licence’: this Licence. 22 + 23 +- ‘The Original Work’: the work or software distributed or communicated by the 24 + Licensor under this Licence, available as Source Code and also as Executable 25 + Code as the case may be. 26 + 27 +- ‘Derivative Works’: the works or software that could be created by the 28 + Licensee, based upon the Original Work or modifications thereof. This Licence 29 + does not define the extent of modification or dependence on the Original Work 30 + required in order to classify a work as a Derivative Work; this extent is 31 + determined by copyright law applicable in the country mentioned in Article 15. 32 + 33 +- ‘The Work’: the Original Work or its Derivative Works. 34 + 35 +- ‘The Source Code’: the human-readable form of the Work which is the most 36 + convenient for people to study and modify. 37 + 38 +- ‘The Executable Code’: any code which has generally been compiled and which is 39 + meant to be interpreted by a computer as a program. 40 + 41 +- ‘The Licensor’: the natural or legal person that distributes or communicates 42 + the Work under the Licence. 43 + 44 +- ‘Contributor(s)’: any natural or legal person who modifies the Work under the 45 + Licence, or otherwise contributes to the creation of a Derivative Work. 46 + 47 +- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of 48 + the Work under the terms of the Licence. 49 + 50 +- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, 51 + renting, distributing, communicating, transmitting, or otherwise making 52 + available, online or offline, copies of the Work or providing access to its 53 + essential functionalities at the disposal of any other natural or legal 54 + person. 55 + 56 +2. Scope of the rights granted by the Licence 57 + 58 +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, 59 +sublicensable licence to do the following, for the duration of copyright vested 60 +in the Original Work: 61 + 62 +- use the Work in any circumstance and for all usage, 63 +- reproduce the Work, 64 +- modify the Work, and make Derivative Works based upon the Work, 65 +- communicate to the public, including the right to make available or display 66 + the Work or copies thereof to the public and perform publicly, as the case may 67 + be, the Work, 68 +- distribute the Work or copies thereof, 69 +- lend and rent the Work or copies thereof, 70 +- sublicense rights in the Work or copies thereof. 71 + 72 +Those rights can be exercised on any media, supports and formats, whether now 73 +known or later invented, as far as the applicable law permits so. 74 + 75 +In the countries where moral rights apply, the Licensor waives his right to 76 +exercise his moral right to the extent allowed by law in order to make effective 77 +the licence of the economic rights here above listed. 78 + 79 +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to 80 +any patents held by the Licensor, to the extent necessary to make use of the 81 +rights granted on the Work under this Licence. 82 + 83 +3. Communication of the Source Code 84 + 85 +The Licensor may provide the Work either in its Source Code form, or as 86 +Executable Code. If the Work is provided as Executable Code, the Licensor 87 +provides in addition a machine-readable copy of the Source Code of the Work 88 +along with each copy of the Work that the Licensor distributes or indicates, in 89 +a notice following the copyright notice attached to the Work, a repository where 90 +the Source Code is easily and freely accessible for as long as the Licensor 91 +continues to distribute or communicate the Work. 92 + 93 +4. Limitations on copyright 94 + 95 +Nothing in this Licence is intended to deprive the Licensee of the benefits from 96 +any exception or limitation to the exclusive rights of the rights owners in the 97 +Work, of the exhaustion of those rights or of other applicable limitations 98 +thereto. 99 + 100 +5. Obligations of the Licensee 101 + 102 +The grant of the rights mentioned above is subject to some restrictions and 103 +obligations imposed on the Licensee. Those obligations are the following: 104 + 105 +Attribution right: The Licensee shall keep intact all copyright, patent or 106 +trademarks notices and all notices that refer to the Licence and to the 107 +disclaimer of warranties. The Licensee must include a copy of such notices and a 108 +copy of the Licence with every copy of the Work he/she distributes or 109 +communicates. The Licensee must cause any Derivative Work to carry prominent 110 +notices stating that the Work has been modified and the date of modification. 111 + 112 +Copyleft clause: If the Licensee distributes or communicates copies of the 113 +Original Works or Derivative Works, this Distribution or Communication will be 114 +done under the terms of this Licence or of a later version of this Licence 115 +unless the Original Work is expressly distributed only under this version of the 116 +Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee 117 +(becoming Licensor) cannot offer or impose any additional terms or conditions on 118 +the Work or Derivative Work that alter or restrict the terms of the Licence. 119 + 120 +Compatibility clause: If the Licensee Distributes or Communicates Derivative 121 +Works or copies thereof based upon both the Work and another work licensed under 122 +a Compatible Licence, this Distribution or Communication can be done under the 123 +terms of this Compatible Licence. For the sake of this clause, ‘Compatible 124 +Licence’ refers to the licences listed in the appendix attached to this Licence. 125 +Should the Licensee's obligations under the Compatible Licence conflict with 126 +his/her obligations under this Licence, the obligations of the Compatible 127 +Licence shall prevail. 128 + 129 +Provision of Source Code: When distributing or communicating copies of the Work, 130 +the Licensee will provide a machine-readable copy of the Source Code or indicate 131 +a repository where this Source will be easily and freely available for as long 132 +as the Licensee continues to distribute or communicate the Work. 133 + 134 +Legal Protection: This Licence does not grant permission to use the trade names, 135 +trademarks, service marks, or names of the Licensor, except as required for 136 +reasonable and customary use in describing the origin of the Work and 137 +reproducing the content of the copyright notice. 138 + 139 +6. Chain of Authorship 140 + 141 +The original Licensor warrants that the copyright in the Original Work granted 142 +hereunder is owned by him/her or licensed to him/her and that he/she has the 143 +power and authority to grant the Licence. 144 + 145 +Each Contributor warrants that the copyright in the modifications he/she brings 146 +to the Work are owned by him/her or licensed to him/her and that he/she has the 147 +power and authority to grant the Licence. 148 + 149 +Each time You accept the Licence, the original Licensor and subsequent 150 +Contributors grant You a licence to their contributions to the Work, under the 151 +terms of this Licence. 152 + 153 +7. Disclaimer of Warranty 154 + 155 +The Work is a work in progress, which is continuously improved by numerous 156 +Contributors. It is not a finished work and may therefore contain defects or 157 +‘bugs’ inherent to this type of development. 158 + 159 +For the above reason, the Work is provided under the Licence on an ‘as is’ basis 160 +and without warranties of any kind concerning the Work, including without 161 +limitation merchantability, fitness for a particular purpose, absence of defects 162 +or errors, accuracy, non-infringement of intellectual property rights other than 163 +copyright as stated in Article 6 of this Licence. 164 + 165 +This disclaimer of warranty is an essential part of the Licence and a condition 166 +for the grant of any rights to the Work. 167 + 168 +8. Disclaimer of Liability 169 + 170 +Except in the cases of wilful misconduct or damages directly caused to natural 171 +persons, the Licensor will in no event be liable for any direct or indirect, 172 +material or moral, damages of any kind, arising out of the Licence or of the use 173 +of the Work, including without limitation, damages for loss of goodwill, work 174 +stoppage, computer failure or malfunction, loss of data or any commercial 175 +damage, even if the Licensor has been advised of the possibility of such damage. 176 +However, the Licensor will be liable under statutory product liability laws as 177 +far such laws apply to the Work. 178 + 179 +9. Additional agreements 180 + 181 +While distributing the Work, You may choose to conclude an additional agreement, 182 +defining obligations or services consistent with this Licence. However, if 183 +accepting obligations, You may act only on your own behalf and on your sole 184 +responsibility, not on behalf of the original Licensor or any other Contributor, 185 +and only if You agree to indemnify, defend, and hold each Contributor harmless 186 +for any liability incurred by, or claims asserted against such Contributor by 187 +the fact You have accepted any warranty or additional liability. 188 + 189 +10. Acceptance of the Licence 190 + 191 +The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ 192 +placed under the bottom of a window displaying the text of this Licence or by 193 +affirming consent in any other similar way, in accordance with the rules of 194 +applicable law. Clicking on that icon indicates your clear and irrevocable 195 +acceptance of this Licence and all of its terms and conditions. 196 + 197 +Similarly, you irrevocably accept this Licence and all of its terms and 198 +conditions by exercising any rights granted to You by Article 2 of this Licence, 199 +such as the use of the Work, the creation by You of a Derivative Work or the 200 +Distribution or Communication by You of the Work or copies thereof. 201 + 202 +11. Information to the public 203 + 204 +In case of any Distribution or Communication of the Work by means of electronic 205 +communication by You (for example, by offering to download the Work from a 206 +remote location) the distribution channel or media (for example, a website) must 207 +at least provide to the public the information requested by the applicable law 208 +regarding the Licensor, the Licence and the way it may be accessible, concluded, 209 +stored and reproduced by the Licensee. 210 + 211 +12. Termination of the Licence 212 + 213 +The Licence and the rights granted hereunder will terminate automatically upon 214 +any breach by the Licensee of the terms of the Licence. 215 + 216 +Such a termination will not terminate the licences of any person who has 217 +received the Work from the Licensee under the Licence, provided such persons 218 +remain in full compliance with the Licence. 219 + 220 +13. Miscellaneous 221 + 222 +Without prejudice of Article 9 above, the Licence represents the complete 223 +agreement between the Parties as to the Work. 224 + 225 +If any provision of the Licence is invalid or unenforceable under applicable 226 +law, this will not affect the validity or enforceability of the Licence as a 227 +whole. Such provision will be construed or reformed so as necessary to make it 228 +valid and enforceable. 229 + 230 +The European Commission may publish other linguistic versions or new versions of 231 +this Licence or updated versions of the Appendix, so far this is required and 232 +reasonable, without reducing the scope of the rights granted by the Licence. New 233 +versions of the Licence will be published with a unique version number. 234 + 235 +All linguistic versions of this Licence, approved by the European Commission, 236 +have identical value. Parties can take advantage of the linguistic version of 237 +their choice. 238 + 239 +14. Jurisdiction 240 + 241 +Without prejudice to specific agreement between parties, 242 + 243 +- any litigation resulting from the interpretation of this License, arising 244 + between the European Union institutions, bodies, offices or agencies, as a 245 + Licensor, and any Licensee, will be subject to the jurisdiction of the Court 246 + of Justice of the European Union, as laid down in article 272 of the Treaty on 247 + the Functioning of the European Union, 248 + 249 +- any litigation arising between other parties and resulting from the 250 + interpretation of this License, will be subject to the exclusive jurisdiction 251 + of the competent court where the Licensor resides or conducts its primary 252 + business. 253 + 254 +15. Applicable Law 255 + 256 +Without prejudice to specific agreement between parties, 257 + 258 +- this Licence shall be governed by the law of the European Union Member State 259 + where the Licensor has his seat, resides or has his registered office, 260 + 261 +- this licence shall be governed by Belgian law if the Licensor has no seat, 262 + residence or registered office inside a European Union Member State. 263 + 264 +Appendix 265 + 266 +‘Compatible Licences’ according to Article 5 EUPL are: 267 + 268 +- GNU General Public License (GPL) v. 2, v. 3 269 +- GNU Affero General Public License (AGPL) v. 3 270 +- Open Software License (OSL) v. 2.1, v. 3.0 271 +- Eclipse Public License (EPL) v. 1.0 272 +- CeCILL v. 2.0, v. 2.1 273 +- Mozilla Public Licence (MPL) v. 2 274 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 275 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for 276 + works other than software 277 +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 278 +- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong 279 + Reciprocity (LiLiQ-R+). 280 + 281 +The European Commission may update this Appendix to later versions of the above 282 +licences without producing a new version of the EUPL, as long as they provide 283 +the rights granted in Article 2 of this Licence and protect the covered Source 284 +Code from exclusive appropriation. 285 + 286 +All other changes or additions to this Appendix require the production of a new 287 +EUPL version.
Modified math.t from [fe958b6645] to [f642fd73ba].
78 78 for i = 0, len do 79 79 var v, ok = m.shorthand.cval(s[i]) 80 80 if ok == false then return 0, false end 81 81 val = (val * 64) + v 82 82 end 83 83 return val, true 84 84 end 85 + 86 +terra m.hexdigit(hb: uint8): int8 87 + var a = hb and 0x0F 88 + if a < 10 then return 0x30 + a 89 + else return 0x61 + (a-10) end 90 +end 91 + 92 +terra m.hexbyte(b: uint8): int8[2] 93 + return array(m.hexdigit((b and 0xF0) >> 4), m.hexdigit(b and 0x0F)) 94 +end 95 + 96 +terra m.hexstr(src: &uint8, str: rawstring, sz: intptr) 97 + for i = 0, sz do 98 + var d = m.hexbyte(src[i]) 99 + str[i*2] = d[0] 100 + str[i*2 + 1] = d[1] 101 + end 102 +end 103 + 104 +terra m.b32char(v: uint8): int8 105 + if v <= 25 then return 0x61 + v 106 + elseif v < 31 then return 0x32 + (v-26) 107 + else return 0 end 108 +end 109 + 110 +terra m.b32(v: uint64, buf: rawstring) -- 5 bytes -> 8 chars 111 + while v > 0 do 112 + var val = v % 32 113 + v = v / 32 114 + @buf = m.b32char(val) 115 + buf = buf + 1 116 + end 117 +end 118 + 119 +terra m.b32str(a: lib.mem.ptr(uint64)) 120 + 121 +end 85 122 86 123 return m
Added mem.t version [07d2cb4a7e].
1 +-- vim: ft=terra 2 +local m = { 3 + zero = macro(function(r) 4 + return quote 5 + for i = 0, [r.tree.type.N] do r[i] = 0 end 6 + end 7 + end); 8 + heapa_raw = terralib.externfunction('malloc', intptr -> &opaque); 9 + heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque); 10 + heapf = terralib.externfunction('free', &opaque -> {}); 11 + cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque); 12 +} 13 + 14 +m.heapa = macro(function(ty, sz) 15 + local p = m.ptr(ty:astype()) 16 + return `p { 17 + ptr = [&ty:astype()](m.heapa_raw(sizeof(ty) * sz)); 18 + ct = sz; 19 + } 20 +end) 21 + 22 +m.ptr = terralib.memoize(function(ty) 23 + local t = terralib.types.newstruct(string.format('ptr<%s>', ty)) 24 + t.entries = { 25 + {'ptr', &ty}; 26 + {'ct', intptr}; 27 + } 28 + t.ptr_basetype = ty 29 + local recurse = false 30 + if ty:isstruct() then 31 + if ty.methods.free then recurse = true end 32 + end 33 + t.metamethods.__not = macro(function(self) 34 + return `self.ptr 35 + end) 36 + t.methods = { 37 + free = terra(self: &t): bool 38 + [recurse and quote 39 + self.ptr:free() 40 + end or {}] 41 + if self.ct > 0 then 42 + m.heapf(self.ptr) 43 + self.ct = 0 44 + return true 45 + end 46 + return false 47 + end; 48 + init = terra(self: &t, newct: intptr): bool 49 + var nv = [&ty](m.heapa_raw(sizeof(ty) * newct)) 50 + if nv ~= nil then 51 + self.ptr = nv 52 + self.ct = newct 53 + return true 54 + else return false end 55 + end; 56 + resize = terra(self: &t, newct: intptr): bool 57 + var nv: &ty 58 + if self.ct > 0 59 + then nv = [&ty](m.heapr_raw(self.ptr, sizeof(ty) * newct)) 60 + else nv = [&ty](m.heapa_raw(sizeof(ty) * newct)) 61 + end 62 + if nv ~= nil then 63 + self.ptr = nv 64 + self.ct = newct 65 + return true 66 + else return false end 67 + end; 68 + } 69 + return t 70 +end) 71 + 72 +m.vec = terralib.memoize(function(ty) 73 + local v = terralib.types.newstruct(string.format('vec<%s>', ty.name)) 74 + v.entries = { 75 + {field = 'storage', type = m.ptr(ty)}; 76 + {field = 'sz', type = intptr}; 77 + {field = 'run', type = intptr}; 78 + } 79 + local terra biggest(a: intptr, b: intptr) 80 + if a > b then return a else return b end 81 + end 82 + terra v:assure(n: intptr) 83 + if self.storage.ct < n then 84 + self.storage:resize(biggest(n, self.storage.ct + self.run)) 85 + end 86 + end 87 + v.methods = { 88 + init = terra(self: &v, run: intptr): bool 89 + if not self.storage:init(run) then return false end 90 + self.run = run 91 + self.sz = 0 92 + return true 93 + end; 94 + new = terra(self: &v): &ty 95 + self:assure(self.sz + 1) 96 + self.sz = self.sz + 1 97 + return self.storage.ptr + (self.sz - 1) 98 + end; 99 + push = terra(self: &v, val: ty) 100 + self:assure(self.sz + 1) 101 + self.storage.ptr[self.sz] = val 102 + self.sz = self.sz + 1 103 + end; 104 + free = terra(self: &v) self.storage:free() end; 105 + last = terra(self: &v, idx: intptr): &ty 106 + if self.sz > idx then 107 + return self.storage.ptr + (self.sz - (idx+1)) 108 + else lib.bail('vector underrun!') end 109 + end; 110 + crush = terra(self: &v) 111 + self.storage:resize(self.sz) 112 + return self.storage 113 + end; 114 + } 115 + v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index?? 116 + if self.sz > idx then 117 + return self.storage.ptr + idx 118 + else lib.bail('vector overrun!') end 119 + end 120 + return v 121 +end) 122 + 123 +return m
Modified parsav.md from [d4a5d691bd] to [93a3706cc3].
1 1 # parsav 2 2 3 3 **parsav** is a lightweight fediverse server 4 4 5 +## backends 6 +parsav is designed to be storage-agnostic, and can draw data from multiple backends at a time. backends can be enabled or disabled at compile time to avoid unnecessary dependencies. 7 + 8 +* postgresql 9 + 5 10 ## dependencies 6 11 7 -* libhttp 12 +* mongoose 8 13 * json-c 9 14 * mbedtls 10 -* postgresql-libs 15 +* **postgresql backend:** 16 + * postgresql-libs 11 17 12 18 ## building 13 19 14 -first, either install any missing dependencies as shared libraries, or build them as static libraries as described below: 20 +first, either install any missing dependencies as shared libraries, or build them as static libraries with the command `make dep.$LIBRARY`. as a shortcut, `make dep` will build all dependencies as static libraries. note that if the build system finds a static version of a librari in the `lib/` folder, it will use that instead of any system library. 21 + 22 +postgresql-libs must be installed systemwide, as `parsav` does not currently provide for statically compiling and linking it 23 + 24 +## configuring 25 + 26 +the `parsav` configuration is comprised of two components: the backends list and the config store. the backends list is a simple text file that tells `parsav` which data sources to draw from. the config store is a key-value store which contains the rest of the server's configuration, and is loaded from the backends. the configuration store can be spread across the backends; backends will be checked for configuration keys according to the order in which they are listed. changes to the configuration store affect parsav in real time; you only need to restart the server if you make a change to the backend list. 27 + 28 +eventually, we'll add a command-line tool `parsav-cfg` to enable easy modification of the configuration store from the command line; for now, you'll need to modify the database by hand or use the online administration menu. the schema.sql file contains commands to prompt for various important values like the name of your administrative user. 29 + 30 +by default, parsav looks for a file called `backend.conf` in the current directory when it is launched. you can override this default with the `parsav_backend_file` environment or with the `-b`/`--backend-file` flag. `backend.conf` lists one backend per line, in the form `id type confstring`. for instance, if you had two postgresql databases, you might write a backend file like 31 + 32 + master pgsql host=localhost dbname=parsav 33 + tweets pgsql host=420.69.dread.cloud dbname=content 34 + 35 +the form the configuration string takes depends on the specific backend. 36 + 37 +### postgresql backend 38 + 39 +currently, postgres needs to be configured manually before parsav can make use of it to store data. the first step is to create a database for parsav's use. once you've done that, you need to create the database schema with the command `$ psql (-h $host) -d $database -f schema.sql`. you'll be prompted for some crucial settings to install in the configuration store, such as the name of the relation you want to use for authentication (we'll call it `parsav_auth` from here on out). 40 + 41 +parsav separates the storage of user credentials from the storage of other user data, in order to facilitate centralized user accounting. you don't need to take advantage of this feature, and if you don't want to, you can just create a `parsav_auth` table and have done. however, `parsav_auth` can also be a view, collecting a list of authorized users and their various credentials from whatever source you please. 42 + 43 +`parsav_auth` has the following schema: 44 + 45 + create table parsav_auth ( 46 + aid bigint primary key, 47 + uid bigint, 48 + newname text, 49 + kind text not null, 50 + cred bytea not null, 51 + restrict text[], 52 + netmask cidr, 53 + blacklist bool 54 + ) 55 + 56 +`aid` is a unique value identifying the authentication method. it must be deterministic -- values based on time of creation or a hash of `uid`+`kind`+`cred` are ideal. `uid` is the identifier of the user the row specifies credentials for. `kind` is a string indicating the credential type, and `cred` is the content of that credential.for the meaning of these fields and use of this structure, see **authentication** below. 57 + 58 +## authentication 59 +in the most basic case, an authentication record would be something like `{uid = 123, kind = "pw-sha512", cred = "12bf90…a10e"}`. but `parsav` is not restricted to username-password authentication, and in addition to various hashing styles, it also will support more esoteric forms of authentcation. any individual user can have as many auth rows as she likes. there is also a `restrict` field, which is normally null, but can be specified in order to restrict a particular credential to certain operations, such as posting tweets or updating a bio. `blacklist` indicates that any attempt to authenticate that matches this row will be denied, regardless of whether it matches other rows. if `netmask` is present, this authentication will only succeed if it comes from the specified IP mask. 60 + 61 +`uid` can also be `0` (not null, which matches any user!), indicating that there is not yet a record in `parsav_actors` for this account. if this is the case, `name` must contain the handle of the account to be created when someone attempts to log in with this credential. whether `name` is used in the authentication process depends on whether the authentication method accepts a username. all rows with the same `uid` *must* have the same `name`. 62 + 63 +below is a full list of authentication types we intend to support. a checked box indicates the scheme has been implemented. 64 + 65 +* ☑ pw-sha{512,384,256,224}: an ordinary password, hashed with the appropriate algorithm 66 +* ☐ pw-{sha1,md5,clear} (insecure, must be manually enabled at compile time with the config variable `parsav_let_me_be_a_dumbass="i know what i'm doing"`) 67 +* ☐ pw-pbkdf2-hmac-sha{…}: a password hashed with the Password-Based Key Derivation Function 2 instead of plain SHA2 68 +* ☐ api-digest-sha{…}: a value that can be hashed with the current epoch to derive a temporary access key without logging in. these are used for API calls, sent in the header `X-API-Key`. 69 +* ☐ otp-time-sha1: a TOTP PSK: the first two bytes represent the step, the third byte the OTP length, and the remaining ten bytes the secret key 70 +* ☐ tls-cert-fp: a fingerprint of a client certificate 71 +* ☐ tls-cert-ca: a value of the form `fp/key=value` where a client certificate with the property `key=value` (e.g. `uid=cyberlord19`) signed by a certificate authority matching the given fingerprint `fp` can authenticate the user 72 +* ☐ challenge-rsa-sha256: an RSA public key. the user is presented with a challenge and must sign it with the corresponding private key using SHA256. 73 +* ☐ challenge-ecc-sha256: a Curve25519 public key. the user is presented with a challenge and must sign it with the corresponding private key using SHA256. 74 +* ☐ challenge-ecc448-sha256: a Curve448 public key. the user is presented with a challenge and must sign it with the corresponding private key using SHA256. 75 +* ☑ trust: authentication always succeeds. only use in combination with netmask!!! 76 + 77 +## license 78 + 79 +parsav is released under the terms of the EUPL v1.2. copies of this license are included in the repository. dependencies are produced 80 + 81 +## future direction 15 82 16 -* libhttp: run `$ make lib/libhttp/lib/libhttp.a` 17 -* json-c (deps: `cmake`): run `$ make lib/json-c/libjson-c.a` 18 -* mbedtls: run `$ make lib/mbedtls/lib/mbed{crypto,tls,x509}.a` 83 +parsav needs more storage backends, as it currently supports only postgres. some possibilities, in order of priority, are: 19 84 20 -you can install static libraries for all dependencies with `$ make dep`, but this is recommended only if you have none of the above 85 +* plain text/filesystem storage 86 +* lmdb 87 +* sqlite3 88 +* generic odbc 89 +* lua 90 +* ldap?? possibly just for users 91 +* cdb (for static content, maybe?) 92 +* mariadb/mysql 93 +* the various nosql horrors, e.g. redis, mongo, and so on
Modified parsav.t from [ce122c09dc] to [fcc06cebed].
2 2 3 3 local util = dofile('common.lua') 4 4 local buildopts, buildargs = util.parseargs{...} 5 5 config = dofile('config.lua') 6 6 7 7 lib = { 8 8 init = {}; 9 + load = function(lst) 10 + for _, l in pairs(lst) do 11 + lib[l] = terralib.loadfile(l .. '.t')() 12 + end 13 + end; 9 14 loadlib = function(name,hdr) 10 15 local p = config.pkg[name] 11 16 -- for _,v in pairs(p.dylibs) do 12 17 -- terralib.linklibrary(p.libdir .. '/' .. v) 13 18 -- end 14 19 return terralib.includec(p.incdir .. '/' .. hdr) 15 20 end; ................................................................................ 17 22 return macro(function(v,...) 18 23 for ty,fn in pairs(tbl) do 19 24 if v.tree.type == ty then return fn(v,...) end 20 25 end 21 26 return (tbl[false])(v,...) 22 27 end) 23 28 end; 24 - emit = function(...) 29 + emit_unitary = function(fd,...) 25 30 local code = {} 26 31 for i,v in ipairs{...} do 27 32 if type(v) == 'string' or type(v) == 'number' then 28 33 local str = tostring(v) 29 34 code[#code+1] = `lib.io.send(2, str, [#str]) 35 + elseif type(v) == 'table' and #v == 2 then 36 + code[#code+1] = `lib.io.send(2, [v[1]], [v[2]]) 30 37 elseif v.tree:is 'constant' then 31 38 local str = tostring(v:asvalue()) 32 39 code[#code+1] = `lib.io.send(2, str, [#str]) 33 40 else 34 41 code[#code+1] = quote var n = v in 35 42 lib.io.send(2, n, lib.str.sz(n)) end 36 43 end 37 44 end 38 - code[#code+1] = `lib.io.send(2, '\n', 1) 45 + code[#code+1] = `lib.io.send(fd, '\n', 1) 39 46 return code 40 47 end; 48 + emitv = function(fd,...) 49 + local vec = {} 50 + local defs = {} 51 + for i,v in ipairs{...} do 52 + local str, ct 53 + if type(v) == 'table' and v.tree and not (v.tree:is 'constant') then 54 + if v.tree.type.convertible == 'tuple' then 55 + str = `v._0 56 + ct = `v._1 57 + else 58 + local n = symbol(v.tree.type) 59 + defs[#defs + 1] = quote var [n] = v end 60 + str = n 61 + ct = `lib.str.sz(n) 62 + end 63 + else 64 + if type(v) == 'string' or type(v) == 'number' then 65 + str = tostring(v) 66 + else--if v.tree:is 'constant' then 67 + str = tostring(v:asvalue()) 68 + end 69 + ct = ct or #str 70 + end 71 + vec[#vec + 1] = `[lib.uio.iovec]{iov_base = [&opaque](str), iov_len = ct} 72 + end 73 + vec[#vec + 1] = `[lib.uio.iovec]{iov_base = [&opaque]('\n'), iov_len = 1} 74 + return quote 75 + [defs] 76 + var strs = array( [vec] ) 77 + in lib.uio.writev(fd, strs, [#vec]) end 78 + end; 41 79 trn = macro(function(cond, i, e) 42 80 return quote 43 81 var c: bool = [cond] 44 82 var r: i.tree.type 45 83 if c == true then r = i else r = e end 46 84 in r end 47 85 end); ................................................................................ 52 90 io = { 53 91 send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff); 54 92 recv = terralib.externfunction('read', {int, rawstring, intptr} -> ptrdiff); 55 93 say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end); 56 94 fmt = terralib.externfunction('printf', 57 95 terralib.types.funcpointer({rawstring},{int},true)); 58 96 }; 59 - str = { 60 - sz = terralib.externfunction('strlen', rawstring -> intptr); 61 - cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int); 62 - ncmp = terralib.externfunction('strncmp', {rawstring, rawstring, intptr} -> int); 63 - cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring); 64 - ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring); 65 - ndup = terralib.externfunction('strndup',{rawstring, intptr} -> rawstring); 66 - fmt = terralib.externfunction('asprintf', 67 - terralib.types.funcpointer({&rawstring},{int},true)); 68 - }; 97 + str = { sz = terralib.externfunction('strlen', rawstring -> intptr) }; 69 98 copy = function(tbl) 70 99 local new = {} 71 100 for k,v in pairs(tbl) do new[k] = v end 72 101 setmetatable(new, getmetatable(tbl)) 73 102 return new 74 103 end; 75 - mem = { 76 - zero = macro(function(r) 77 - return quote 78 - for i = 0, [r.tree.type.N] do r[i] = 0 end 79 - end 80 - end); 81 - heapa_raw = terralib.externfunction('malloc', intptr -> &opaque); 82 - heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque); 83 - heapf = terralib.externfunction('free', &opaque -> {}); 84 - cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque); 85 - heapa = macro(function(ty, sz) 86 - local p = lib.mem.ptr(ty:astype()) 87 - return `p { 88 - ptr = [&ty:astype()](lib.mem.heapa_raw(sizeof(ty) * sz)); 89 - ct = sz; 90 - } 91 - end) 92 - }; 93 104 } 105 +if config.posix then 106 + lib.uio = terralib.includec 'sys/uio.h'; 107 + lib.emit = lib.emitv -- use more efficient call where available 108 +else lib.emit = lib.emit_unitary end 94 109 95 110 local noise = global(uint8,1) 96 111 local noise_header = function(code,txt,mod) 97 112 if mod then 98 113 return string.format('\27[%s;1m(parsav::%s %s)\27[m ', code,mod,txt) 99 114 else 100 115 return string.format('\27[%s;1m(parsav %s)\27[m ', code,txt) 101 116 end 102 117 end 103 118 local defrep = function(level,n,code) 104 119 return macro(function(...) 105 - local q = lib.emit(noise_header(code,n), ...) 120 + local q = lib.emit(2, noise_header(code,n), ...) 106 121 return quote 107 122 if noise >= level then [q] end 108 123 end 109 124 end); 110 125 end 111 126 lib.dbg = defrep(3,'debug', '32') 112 127 lib.report = defrep(2,'info', '35') 113 128 lib.warn = defrep(1,'warn', '33') 114 129 lib.bail = macro(function(...) 115 - local q = lib.emit(noise_header('31','fatal'), ...) 130 + local q = lib.emit(2, noise_header('31','fatal'), ...) 116 131 return quote 117 132 [q] 118 133 lib.proc.exit(1) 119 134 end 120 135 end); 121 136 lib.stat = terralib.memoize(function(ty) 122 137 local n = struct { ................................................................................ 137 152 elseif #tbl >= 2^8 then ty = uint16 end 138 153 local o = { t = ty } 139 154 for i, name in ipairs(tbl) do 140 155 o[name] = i 141 156 end 142 157 return o 143 158 end 144 -lib.mem.ptr = terralib.memoize(function(ty) 145 - local t = terralib.types.newstruct(string.format('ptr<%s>', ty)) 146 - t.entries = { 147 - {'ptr', &ty}; 148 - {'ct', intptr}; 149 - } 150 - t.ptr_basetype = ty 151 - local recurse = false 152 - if ty:isstruct() then 153 - if ty.methods.free then recurse = true end 154 - end 155 - t.methods = { 156 - free = terra(self: &t): bool 157 - [recurse and quote 158 - self.ptr:free() 159 - end or {}] 160 - if self.ct > 0 then 161 - lib.mem.heapf(self.ptr) 162 - self.ct = 0 163 - return true 159 +lib.set = function(tbl) 160 + local bytes = math.ceil(#tbl / 8) 161 + local o = {} 162 + for i, name in ipairs(tbl) do o[name] = i end 163 + local struct set { _store: uint8[bytes] } 164 + local struct bit { _v: intptr _set: &set} 165 + terra set:clear() for i=0,bytes do self._store[i] = 0 end end 166 + set.members = tbl 167 + set.name = string.format('set<%s>', table.concat(tbl, '|')) 168 + set.metamethods.__entrymissing = macro(function(val, obj) 169 + if o[val] == nil then error('value ' .. val .. ' not in set') end 170 + return `bit { _v=[o[val] - 1], _set = &obj } 171 + end) 172 + set.methods.dump = macro(function(self) 173 + local q = quote lib.io.say('dumping set:\n') end 174 + for i,v in ipairs(tbl) do 175 + q = quote 176 + [q] 177 + if [bool](self.[v]) 178 + then lib.io.say([' - ' .. v .. ': true\n']) 179 + else lib.io.say([' - ' .. v .. ': false\n']) 180 + end 164 181 end 165 - return false 166 - end; 167 - init = terra(self: &t, newct: intptr): bool 168 - var nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct)) 169 - if nv ~= nil then 170 - self.ptr = nv 171 - self.ct = newct 172 - return true 173 - else return false end 174 - end; 175 - resize = terra(self: &t, newct: intptr): bool 176 - var nv: &ty 177 - if self.ct > 0 178 - then nv = [&ty](lib.mem.heapr_raw(self.ptr, sizeof(ty) * newct)) 179 - else nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct)) 182 + end 183 + return q 184 + end) 185 + set.metamethods.__add = macro(function(self,other) 186 + local new = symbol(set) 187 + local q = quote var [new] new:clear() end 188 + for i = 0, bytes - 1 do 189 + q = quote [q] 190 + new._store[i] = self._store[i] or other._store[i] 180 191 end 181 - if nv ~= nil then 182 - self.ptr = nv 183 - self.ct = newct 184 - return true 185 - else return false end 186 - end; 187 - } 188 - return t 189 -end) 190 -lib.mem.vec = terralib.memoize(function(ty) 191 - local v = terralib.types.newstruct(string.format('vec<%s>', ty.name)) 192 - v.entries = { 193 - {field = 'storage', type = lib.mem.ptr(ty)}; 194 - {field = 'sz', type = intptr}; 195 - {field = 'run', type = intptr}; 196 - } 197 - local terra biggest(a: intptr, b: intptr) 198 - if a > b then return a else return b end 192 + end 193 + return quote [q] in new end 194 + end) 195 + bit.metamethods.__cast = function(from,to,e) 196 + local q = quote var s = e 197 + in (s._set._store[s._v/8] and (1 << s._v % 8)) end 198 + if to == bit then error('casting to bit is not meaningful') 199 + elseif to == bool then return `([q] ~= 0) 200 + elseif to:isintegral() then return q 201 + elseif from == bit then error('cannot cast bit to ' .. tostring(to)) 202 + else return nil end 199 203 end 200 - terra v:assure(n: intptr) 201 - if self.storage.ct < n then 202 - self.storage:resize(biggest(n, self.storage.ct + self.run)) 204 + bit.metamethods.__apply = terra(self: &bit): bool return @self end 205 + bit.metamethods.__lshift = terra(self: &bit, hl: bool) 206 + var byte = self._v / 8 207 + var bit = self._v % 8 208 + if hl then 209 + self._set._store[byte] = self._set._store[byte] or (1 << bit) 210 + else 211 + self._set._store[byte] = self._set._store[byte] and not (1 << bit) 203 212 end 204 213 end 205 - v.methods = { 206 - init = terra(self: &v, run: intptr): bool 207 - if not self.storage:init(run) then return false end 208 - self.run = run 209 - self.sz = 0 210 - return true 211 - end; 212 - new = terra(self: &v): &ty 213 - self:assure(self.sz + 1) 214 - self.sz = self.sz + 1 215 - return self.storage.ptr + (self.sz - 1) 216 - end; 217 - push = terra(self: &v, val: ty) 218 - self:assure(self.sz + 1) 219 - self.storage.ptr[self.sz] = val 220 - self.sz = self.sz + 1 221 - end; 222 - free = terra(self: &v) self.storage:free() end; 223 - last = terra(self: &v, idx: intptr): &ty 224 - if self.sz > idx then 225 - return self.storage.ptr + (self.sz - (idx+1)) 226 - else lib.bail('vector underrun!') end 227 - end; 228 - crush = terra(self: &v) 229 - self.storage:resize(self.sz) 230 - return self.storage 231 - end; 232 - } 233 - v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index?? 234 - if self.sz > idx then 235 - return self.storage.ptr + idx 236 - else lib.bail('vector overrun!') end 237 - end 238 - return v 239 -end) 214 + return set 215 +end 240 216 241 217 lib.err = lib.loadlib('mbedtls','mbedtls/error.h') 242 218 lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h') 243 219 lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h') 244 220 lib.md = lib.loadlib('mbedtls','mbedtls/md.h') 245 221 lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h') 246 222 lib.net = lib.loadlib('mongoose','mongoose.h') 247 223 lib.pq = lib.loadlib('libpq','libpq-fe.h') 248 -lib.file = terralib.loadfile('file.t')() 249 -lib.math = terralib.loadfile('math.t')() 250 -lib.crypt = terralib.loadfile('crypt.t')() 251 -lib.http = terralib.loadfile('http.t')() 252 -lib.tpl = terralib.loadfile('tpl.t')() 253 -lib.string = terralib.loadfile('string.t')() 254 -lib.store = terralib.loadfile('store.t')() 224 + 225 +lib.load { 226 + 'mem', 'str', 'file', 'math', 'crypt'; 227 + 'http', 'tpl', 'store'; 228 +} 255 229 256 230 local be = {} 257 -for _, b in pairs { 'pgsql' } do 231 +for _, b in pairs(config.backends) do 258 232 be[#be+1] = terralib.loadfile('backend/' .. b .. '.t')() 259 233 end 260 234 lib.store.backends = global(`array([be])) 261 235 262 236 lib.cmdparse = terralib.loadfile('cmdparse.t')() 263 237 lib.srv = terralib.loadfile('srv.t')() 264 238 ................................................................................ 279 253 280 254 local pemdump = macro(function(pub, kp) 281 255 local msg = (pub:asvalue() and ' * emitting public key\n') or ' * emitting private key\n' 282 256 return quote 283 257 var buf: lib.crypt.pemfile 284 258 lib.mem.zero(buf) 285 259 lib.crypt.pem(pub, &kp, buf) 286 - lib.io.send(1, msg, [#msg]) 287 - lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf))) 288 - lib.io.send(1, '\n', 1) 260 + lib.emit(msg, buf, '\n') 261 + --lib.io.send(1, msg, [#msg]) 262 + --lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf))) 263 + --lib.io.send(1, '\n', 1) 289 264 end 290 265 end) 291 266 292 267 do 293 268 local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when) 294 269 terra version() lib.io.send(1, p, [#p]) end 295 270 end ................................................................................ 303 278 end 304 279 noise = 1 305 280 end 306 281 307 282 local options = lib.cmdparse { 308 283 version = {'V', 'display information about the binary build and exit'}; 309 284 quiet = {'q', 'do not print to standard out'}; 310 - help = {'h', 'display this list'} 285 + help = {'h', 'display this list'}; 286 + backend_file = {'b', 'init from specified backend file', 1}; 311 287 } 312 288 313 289 terra entry(argc: int, argv: &rawstring): int 290 + if argc < 1 then lib.bail('bad invocation!') end 291 + 314 292 noise_init() 315 293 [lib.init] 316 294 317 295 -- shut mongoose the fuck up 318 296 lib.net.mg_log_set_callback([terra(msg: &opaque, sz: int, u: &opaque) end], nil) 297 + var srv: lib.srv 298 + 299 + do var mode: options 300 + mode:parse(argc,argv) defer mode:free() 301 + if mode.version then version() return 0 end 302 + if mode.help then 303 + lib.io.send(1, [options.helptxt], [#options.helptxt]) 304 + return 0 305 + end 306 + var cnf: rawstring 307 + if mode.backend_file ~= 0 308 + then if mode.arglist.ct >= mode.backend_file 309 + then cnf = mode.arglist.ptr[mode.backend_file - 1] 310 + else lib.bail('bad invocation, backend file not specified') end 311 + else cnf = lib.proc.getenv('parsav_backend_file') 312 + end 313 + if cnf == nil then cnf = "backend.conf" end 319 314 320 - var mode: options 321 - mode:parse(argc,argv) 322 - if mode.version then 323 - version() 324 - return 0 315 + srv:start(cnf) 325 316 end 326 - if mode.help then 327 - lib.io.send(1, [options.helptxt], [#options.helptxt]) 328 - return 0 329 - end 330 - var srv: lib.srv 331 - srv:start('backend.conf') 317 + 332 318 lib.report('listening for requests') 333 319 while true do 334 320 srv:poll() 335 321 end 336 322 srv:shutdown() 337 323 338 324 return 0 ................................................................................ 345 331 end 346 332 347 333 if bflag('dump-config','C') then 348 334 print(util.dump(config)) 349 335 os.exit(0) 350 336 end 351 337 352 -local emit = print 353 -if bflag('quiet','q') then emit = function() end end 354 - 338 +local holler = print 355 339 local out = config.exe and 'parsav' or 'parsav.o' 356 340 local linkargs = {} 341 + 342 +if bflag('quiet','q') then holler = function() end end 343 +if bflag('asan','s') then linkargs[#linkargs+1] = '-fsanitize=address' end 344 +if bflag('lsan','S') then linkargs[#linkargs+1] = '-fsanitize=leak' end 345 + 357 346 if config.posix then 358 347 linkargs[#linkargs+1] = '-pthread' 359 348 end 360 349 for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end 361 -emit('linking with args',util.dump(linkargs)) 350 +holler('linking with args',util.dump(linkargs)) 362 351 terralib.saveobj(out, { 363 352 main = entry 364 353 }, 365 354 linkargs, 366 355 config.tgttrip and terralib.newtarget { 367 356 Triple = config.tgttrip; 368 357 CPU = config.tgtcpu; 369 358 FloatABIHard = config.tgthf; 370 359 } or nil)
Modified schema.sql from [2da83887bf] to [6d12737279].
13 13 value text 14 14 ); 15 15 16 16 insert into parsav_config (key,value) values 17 17 ('bind',:'bind'), 18 18 ('domain',:'domain'), 19 19 ('auth-source',:'auth'), 20 - ('administrator',:'admin'); 20 + ('administrator',:'admin'), 21 + ('server-secret', encode( 22 + digest(int8send((2^63 * (random()*2 - 1))::bigint), 23 + 'sha512'), 'base64')); 21 24 22 25 -- note that valid ids should always > 0, as 0 is reserved for null 23 26 -- on the client side, vastly simplifying code 24 27 drop table if exists parsav_servers cascade; 25 28 create table parsav_servers ( 26 29 id bigint primary key default (1+random()*(2^63-1))::bigint, 27 30 domain text not null,
Modified srv.t from [350801ad24] to [aed7239c9c].
24 24 var fr = lib.file.open(befile, [lib.file.mode.read]) 25 25 if fr.ok == false then 26 26 lib.bail('could not open configuration file ', befile) 27 27 end 28 28 29 29 var f = fr.val 30 30 var c: lib.mem.vec(lib.store.source) c:init(8) 31 - var text: lib.string.acc text:init(64) 31 + var text: lib.str.acc text:init(64) 32 32 do var buf: int8[64] 33 33 while true do 34 34 var ct = f:read(buf, [buf.type.N]) 35 35 if ct == 0 then break end 36 36 text:push(buf, ct) 37 37 end 38 38 end ................................................................................ 92 92 s.sources = c:crush() 93 93 end 94 94 95 95 --srv.methods.conf_set = terra(self: &srv, key: rawstring, val:rawstring) 96 96 -- self.sources.ptr[0]:conf_set(key, val) 97 97 --end 98 98 99 +terra srv:actor_auth_how(ip: lib.store.inet, usn: rawstring) 100 + var cs: lib.store.credset cs:clear() 101 + for i=0,self.sources.ct do 102 + var set: lib.store.credset = self.sources.ptr[i]:actor_auth_how(ip, usn) 103 + cs = cs + set 104 + end 105 + return cs 106 +end 99 107 srv.metamethods.__methodmissing = macro(function(meth, self, ...) 100 - local primary, ptr, stat, simple = 0,1,2,3 108 + local primary, ptr, stat, simple, oid = 0,1,2,3,4 101 109 local tk, rt = primary 102 110 local expr = {...} 103 111 for _,f in pairs(lib.store.backend.entries) do 104 112 local fn = f.field or f[1] 105 113 local ft = f.type or f[2] 106 114 if fn == meth then 107 115 rt = ft.type.returntype 108 116 if rt == bool then tk = simple 117 + elseif rt.type == 'integer' then tk = oid 109 118 elseif rt.stat_basetype then tk = stat 110 119 elseif rt.ptr_basetype then tk = ptr end 111 120 break 112 121 end 113 122 end 114 123 115 124 if tk == primary then ................................................................................ 116 125 return `self.sources.ptr[0]:[meth]([expr]) 117 126 else local ok, empty 118 127 local r = symbol(rt) 119 128 if tk == ptr then 120 129 ok = `r.ptr ~= nil 121 130 empty = `[rt]{ptr=nil,ct=0} 122 131 elseif tk == stat then 123 - ok = `r.ok ~= false 132 + ok = `r.ok == true 124 133 empty = `[rt]{ok=false,error=1} 125 134 elseif tk == simple then 126 135 ok = `r == true 127 136 empty = `false 137 + elseif tk == oid then 138 + ok = `r ~= 0 139 + empty = `0 128 140 end 129 141 return quote 130 142 var [r] = empty 131 143 for i=0,self.sources.ct do var src = self.sources.ptr + i 132 144 if src.handle ~= nil then 133 145 r = src:[meth]([expr]) 134 146 if [ok] then break ................................................................................ 159 171 elseif dbbind.ptr ~= nil then 160 172 bind = dbbind.ptr 161 173 else bind = '[::]:10917' end 162 174 163 175 lib.report('binding to ', bind) 164 176 lib.net.mg_mgr_init(&self.webmgr) 165 177 self.webcon = lib.net.mg_http_listen(&self.webmgr, bind, handle.http, nil) 166 - dbbind:free() 178 + 167 179 180 + if dbbind.ptr ~= nil then dbbind:free() end 168 181 end 169 182 170 183 srv.methods.poll = terra(self: &srv) 171 184 lib.net.mg_mgr_poll(&self.webmgr,1000) 172 185 end 173 186 174 187 srv.methods.shutdown = terra(self: &srv)
Modified store.t from [ed1d490f12] to [2c2e954f5c].
7 7 }; 8 8 notiftype = lib.enum { 9 9 'mention', 'like', 'rt', 'react' 10 10 }; 11 11 relation = lib.enum { 12 12 'follow', 'mute', 'block' 13 13 }; 14 + credset = lib.set { 15 + 'pw', 'otp', 'challenge', 'trust' 16 + }; 14 17 } 15 18 16 -local str = lib.mem.ptr(int8) 17 -str:complete() 19 +local str = rawstring --lib.mem.ptr(int8) 18 20 19 21 struct m.source 20 22 21 23 struct m.rights { 22 24 rank: uint16 -- lower = more powerful except 0 = regular user 23 25 -- creating staff automatically assigns rank immediately below you 24 26 quota: uint32 -- # of allowed tweets per day; 0 = no limit ................................................................................ 54 56 struct m.actor { 55 57 id: uint64 56 58 nym: str 57 59 handle: str 58 60 origin: uint64 59 61 bio: str 60 62 rights: m.rights 61 - key: str 63 + key: lib.mem.ptr(uint8) 64 + 65 + xid: str 62 66 63 67 source: &m.source 64 68 } 65 -terra m.actor:free() 66 - self.nym:free() 67 - self.handle:free() 68 - self.bio:free() 69 - self.key:free() 70 -end 71 69 72 70 struct m.range { 73 71 time: bool 74 72 union { 75 73 from_time: m.timepoint 76 74 from_idx: uint64 77 75 } ................................................................................ 111 109 kind: m.notiftype.t 112 110 when: uint64 113 111 union { 114 112 post: uint64 115 113 reaction: int8[8] 116 114 } 117 115 } 116 + 117 +struct m.inet { 118 + pv: uint8 -- 0 = null, 4 = ipv4, 6 = ipv6 119 + union { 120 + v4: uint8[4] 121 + v6: uint8[16] 122 + } 123 + union { 124 + fixbits: uint8 -- for cidr 125 + port: uint16 -- for origin 126 + } 127 +} 128 + 129 +terra m.inet:cidr_str() 130 + if self.pv == 4 then 131 + var maxsz = 3*4 + 3 + 1 132 + elseif self.pv == 6 then 133 + var bits = 128 134 + var bytes = bits / 8 135 + var hexchs = bytes * 2 136 + var segs = hexchs / 4 137 + var seps = segs - 1 138 + var maxsz = hexchs + seps + 1 139 + else return nil end 140 +end 141 + 142 +struct m.auth { 143 + aid: uint64 144 + uid: uint64 145 + aname: str 146 + netmask: m.inet 147 + restrict: lib.mem.ptr(rawstring) 148 + blacklist: bool 149 +} 150 + 118 151 119 152 -- backends only handle content on the local server 120 153 struct m.backend { id: rawstring 121 154 open: &m.source -> &opaque 122 155 close: &m.source -> {} 123 156 124 157 conf_get: {&m.source, rawstring} -> lib.mem.ptr(int8) 125 158 conf_set: {&m.source, rawstring, rawstring} -> {} 126 159 conf_reset: {&m.source, rawstring} -> {} 127 160 128 161 actor_save: {&m.source, m.actor} -> bool 129 162 actor_create: {&m.source, m.actor} -> bool 130 - actor_fetch_xid: {&m.source, rawstring} -> lib.stat(m.actor) 131 - actor_fetch_uid: {&m.source, uint64} -> lib.stat(m.actor) 163 + actor_fetch_xid: {&m.source, rawstring} -> lib.mem.ptr(m.actor) 164 + actor_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.actor) 132 165 actor_notif_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.notif) 133 - actor_auth: {&m.source, rawstring, rawstring} -> lib.stat(m.actor) 134 - actor_enum: {&m.source} -> lib.mem.ptr(m.actor) 135 - actor_enum_local: {&m.source} -> lib.mem.ptr(m.actor) 166 + actor_enum: {&m.source} -> lib.mem.ptr(&m.actor) 167 + actor_enum_local: {&m.source} -> lib.mem.ptr(&m.actor) 168 + 169 + actor_auth_how: {&m.source, m.inet, rawstring} -> m.credset 170 + -- returns a set of auth method categories that are available for a 171 + -- given user from a certain origin 172 + -- origin: inet 173 + -- handle: rawstring 174 + actor_auth_otp: {&m.source, m.inet, rawstring, rawstring} -> uint64 175 + actor_auth_pw: {&m.source, m.inet, rawstring, rawstring} -> uint64 176 + -- handles password-based logins against hashed passwords 177 + -- origin: inet 178 + -- handle: rawstring 179 + -- token: rawstring 180 + actor_auth_tls: {&m.source, m.inet, rawstring} -> uint64 181 + -- handles implicit authentication performed as part of an TLS connection 182 + -- origin: inet 183 + -- fingerprint: rawstring 184 + actor_auth_api: {&m.source, m.inet, rawstring, rawstring} -> uint64 185 + -- handles API authentication 186 + -- origin: inet 187 + -- handle: rawstring 188 + -- key: rawstring (X-API-Key) 189 + actor_auth_record_fetch: {&m.source, uint64} -> lib.mem.ptr(m.auth) 136 190 137 191 actor_conf_str: cnf(rawstring, lib.mem.ptr(int8)) 138 192 actor_conf_int: cnf(intptr, lib.stat(intptr)) 139 193 140 194 post_save: {&m.source, &m.post} -> bool 141 195 post_create: {&m.source, &m.post} -> bool 142 196 actor_post_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(m.post)
Added str.t version [4b8724b0aa].
1 +-- vim: ft=terra 2 +-- string.t: string classes 3 + 4 +local m = { 5 + sz = terralib.externfunction('strlen', rawstring -> intptr); 6 + cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int); 7 + ncmp = terralib.externfunction('strncmp', {rawstring, rawstring, intptr} -> int); 8 + cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring); 9 + ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring); 10 + dup = terralib.externfunction('strdup',rawstring -> rawstring); 11 + ndup = terralib.externfunction('strndup',{rawstring, intptr} -> rawstring); 12 + fmt = terralib.externfunction('asprintf', 13 + terralib.types.funcpointer({&rawstring,rawstring},{int},true)); 14 + bfmt = terralib.externfunction('sprintf', 15 + terralib.types.funcpointer({rawstring,rawstring},{int},true)); 16 +} 17 + 18 +(lib.mem.ptr(int8)).metamethods.__cast = function(from,to,e) 19 + if from == &int8 then 20 + return `[lib.mem.ptr(int8)]{ptr = e, ct = m.sz(e)} 21 + elseif to == &int8 then 22 + return e.ptr 23 + end 24 +end 25 + 26 +struct m.acc { 27 + buf: rawstring 28 + sz: intptr 29 + run: intptr 30 + space: intptr 31 +} 32 + 33 +local terra biggest(a: intptr, b: intptr) 34 + if a > b then return a else return b end 35 +end 36 + 37 +terra m.acc:init(run: intptr) 38 + lib.dbg('initializing string accumulator') 39 + self.buf = [rawstring](lib.mem.heapa_raw(run)) 40 + self.run = run 41 + self.space = run 42 + self.sz = 0 43 + return self 44 +end; 45 + 46 +terra m.acc:free() 47 + lib.dbg('freeing string accumulator') 48 + if self.buf ~= nil and self.space > 0 then 49 + lib.mem.heapf(self.buf) 50 + end 51 +end; 52 + 53 +terra m.acc:crush() 54 + lib.dbg('crushing string accumulator') 55 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz)) 56 + self.space = self.sz 57 + return self 58 +end; 59 + 60 +terra m.acc:finalize() 61 + lib.dbg('finalizing string accumulator') 62 + self:crush() 63 + var pt: lib.mem.ptr(int8) 64 + pt.ptr = self.buf 65 + pt.ct = self.sz 66 + self.buf = nil 67 + self.sz = 0 68 + return pt 69 +end; 70 + 71 +terra m.acc:push(str: rawstring, len: intptr) 72 + var llen = len 73 + if str == nil then return self end 74 + if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output 75 + lib.dbg('pushing "',{str,llen},'" onto accumulator') 76 + if self.buf == nil then self:init(self.run) end 77 + if len == 0 then len = m.sz(str) end 78 + if len >= self.space - self.sz then 79 + self.space = self.space + biggest(self.run,len + 1) 80 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 81 + end 82 + lib.mem.cpy(self.buf + self.sz, str, len) 83 + self.sz = self.sz + len 84 + self.buf[self.sz] = 0 85 + return self 86 +end; 87 +m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8)) 88 + self:push(str.ptr, str.ct) return self end; 89 +m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8)) 90 + self:push(str.ptr, str.ct) str:free() return self end; 91 +m.acc.methods.compose = macro(function(self, ...) 92 + local minlen = 0 93 + local pstrs = {} 94 + for i,v in ipairs{...} do 95 + if type(v) == 'table' then 96 + local gl = 16 -- guess wildly 97 + if v.tree and v.tree.type.convertible == 'tuple' then 98 + pstrs[#pstrs+1] = {str = `v._0, len = `v._1} 99 + elseif v.asvalue and type(v:asvalue()) == 'string' then 100 + local str = v:asvalue() 101 + pstrs[#pstrs+1] = {str = str, len = #str} 102 + gl = #str + 1 103 + elseif v.tree and v.tree.type.ptr_basetype == int8 then 104 + pstrs[#pstrs+1] = {str = `v.ptr, len = `v.ct} 105 + else pstrs[#pstrs+1] = {str = v, len = 0} end 106 + minlen = minlen + gl 107 + elseif type(v) == 'string' then 108 + pstrs[#pstrs+1] = {str = v, len = #v} 109 + minlen = minlen + #v + 1 110 + else error('invalid type in compose expression') end 111 + end 112 + local call = `self:init(minlen) 113 + for i,v in ipairs(pstrs) do 114 + call = `[call]:push([v.str],[v.len]) 115 + end 116 + return call 117 +end) 118 +m.acc.metamethods.__lshift = terralib.overloadedfunction('(<<)', { 119 + terra(self: &m.acc, str: rawstring) return self: push(str,0) end; 120 + terra(self: &m.acc, str: lib.mem.ptr(int8)) return self:ppush(str ) end; 121 +}) 122 + 123 +m.box = terralib.memoize(function(ty) 124 + local b = struct { 125 + obj: ty 126 + storage: int8[0] 127 + } 128 + b.name = string.format('bytebox<%s>', ty.name) 129 + b.methods.mk = terra(sz: intptr) 130 + return [&b](lib.mem.heapa_raw(sizeof(b) + sz)) 131 + end 132 + terra b:free() lib.mem.heapf(self) end -- enhhhhh 133 + return b 134 +end) 135 + 136 +m.encapsulate = function(ty, vals) 137 + local memreq_const = sizeof(ty) 138 + local ptr = symbol(&int8) 139 + local box = symbol(&m.box(ty)) 140 + local memreq_exp = `0 141 + local copiers = {} 142 + for k,v in pairs(vals) do 143 + local ty = (`box.obj.[k]).tree.type 144 + local kp 145 + if ty.ptr_basetype then 146 + kp = quote [box].obj.[k] = [ty] { [ptr] = [&ty.ptr_basetype]([ptr]) } ; end 147 + else 148 + kp = quote [box].obj.[k] = [ty]([ptr]) ; end 149 + end 150 + 151 + local cpy 152 + if type(v) ~= 'table' or #v ~= 2 then 153 + cpy = quote [kp] ; [ptr] = m.cpy(ptr, v) end 154 + end 155 + if type(v) == 'string' then 156 + memreq_const = memreq_const + #v + 1 157 + elseif type(v) == 'table' and v.tree and (v.tree.type.ptr_basetype == int8 or v.tree.type.ptr_basetype == uint8) then 158 + cpy = quote [kp]; [ptr] = [&int8](lib.mem.cpy([ptr], [v].ptr, [v].ct)) end 159 + if ty.ptr_basetype then 160 + cpy = quote [cpy]; [box].obj.[k].ct = [v].ct end 161 + end 162 + elseif type(v) == 'table' and v.asvalue and type(v:asvalue()) == 'string' then 163 + local str = tostring(v:asvalue()) 164 + memreq_const = memreq_const + #str + 1 165 + elseif type(v) == 'table' and #v == 2 then 166 + local str,sz = v[1],v[2] 167 + if type(sz) == 'number' then 168 + memreq_const = memreq_const + sz 169 + elseif type(sz:asvalue()) == 'number' then 170 + memreq_const = memreq_const + sz:asvalue() 171 + else memreq_exp = `[sz] + [memreq_exp] end 172 + 173 + cpy = quote [kp] ; [ptr] = [&int8](lib.mem.cpy([ptr], str, sz)) end 174 + if ty.ptr_basetype then 175 + cpy = quote [cpy]; [box].obj.[k].ct = sz end 176 + end 177 + else 178 + memreq_exp = `(m.sz(v) + 1) + [memreq_exp] -- make room for NUL 179 + if ty.ptr_basetype then 180 + cpy = quote [cpy]; [box].obj.[k].ct = m.sz(v) end 181 + end 182 + end 183 + copiers[#copiers + 1] = cpy 184 + end 185 + 186 + return quote 187 + var sz: intptr = memreq_const + [memreq_exp] 188 + var [box] = [&m.box(ty)](lib.mem.heapa_raw(sz)) 189 + var [ptr] = [box].storage 190 + [copiers] 191 + in [lib.mem.ptr(ty)] { ct = 1, ptr = &([box].obj) } end 192 +end 193 + 194 +return m
Deleted string.t version [a0d1de486b].
1 --- vim: ft=terra 2 --- string.t: string classes 3 - 4 -local m = {} 5 - 6 -struct m.acc { 7 - buf: rawstring 8 - sz: intptr 9 - run: intptr 10 - space: intptr 11 -} 12 - 13 -local terra biggest(a: intptr, b: intptr) 14 - if a > b then return a else return b end 15 -end 16 - 17 -m.acc.methods = { 18 - init = terra(self: &m.acc, run: intptr) 19 - lib.dbg('initializing string accumulator') 20 - self.buf = [rawstring](lib.mem.heapa_raw(run)) 21 - self.run = run 22 - self.space = run 23 - self.sz = 0 24 - end; 25 - free = terra(self: &m.acc) 26 - lib.dbg('freeing string accumulator') 27 - if self.buf ~= nil and self.space > 0 then 28 - lib.mem.heapf(self.buf) 29 - end 30 - end; 31 - crush = terra(self: &m.acc) 32 - lib.dbg('crushing string accumulator') 33 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz)) 34 - self.space = self.sz 35 - return self 36 - end; 37 -} 38 - 39 -m.acc.methods.finalize = terra(self: &m.acc) 40 - lib.dbg('finalizing string accumulator') 41 - self:crush() 42 - var pt: lib.mem.ptr(int8) 43 - pt.ptr = self.buf 44 - pt.ct = self.sz 45 - self.buf = nil 46 - self.sz = 0 47 - return pt 48 -end; 49 -m.acc.methods.push = terra(self: &m.acc, str: rawstring, len: intptr) 50 - lib.dbg('pushing "',str,'" onto accumulator') 51 - if self.buf == nil then self:init(self.run) end 52 - if len == 0 then len = lib.str.sz(str) end 53 - if len >= self.space - self.sz then 54 - self.space = self.space + biggest(self.run,len + 1) 55 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 56 - end 57 - lib.mem.cpy(self.buf + self.sz, str, len) 58 - self.sz = self.sz + len 59 - self.buf[self.sz] = 0 60 - return self 61 -end; 62 -m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8)) 63 - self:push(str.ptr, str.ct) return self end; 64 -m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8)) 65 - self:push(str.ptr, str.ct) str:free() return self end; 66 - 67 -return m