Overview
| Comment: | enable webfinger |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
64ae6724c26d73c349c71d534d955bb9 |
| User & Date: | lexi on 2021-01-24 23:18:29 |
| Other Links: | manifest | tags |
Context
|
2021-01-25
| ||
| 12:40 | first steps towards litepub support check-in: 26937ca853 user: lexi tags: trunk | |
|
2021-01-24
| ||
| 23:18 | enable webfinger check-in: 64ae6724c2 user: lexi tags: trunk | |
|
2021-01-22
| ||
| 17:22 | improve compose icon check-in: db0e155b9d user: lexi tags: trunk | |
Changes
Modified common.lua from [c868f8cd22] to [31fe76fcd7].
20 20 if val then return os.execute(cmd) else 21 21 local fd = io.popen(cmd,'r') 22 22 local t = fd:read('*a') 23 23 return chomp(t), fd:close() 24 24 end 25 25 end 26 26 27 -local function dump(v,pfx,cyc) 27 +local function copy(a) 28 + local new = {} 29 + for k,v in pairs(a) do new[k] = v end 30 + return new 31 +end 32 + 33 +local function cat(a,b) 34 + a = copy(a) 35 + local ofs = #a 36 + for k,v in pairs(b) do 37 + if type(k) == 'number' then 38 + a[k+ofs] = v 39 + else a[k] = v end 40 + end 41 + return a 42 +end 43 + 44 +local function search(tbl,pred,lst,path) 45 + lst = lst or {} path = path or {} 46 + if type(pred) ~= 'function' then 47 + local val = pred 48 + pred = function(a,k) 49 + if type(a) == 'table' and a ~= val then return end 50 + return a == val 51 + end 52 + end 53 + for k,v in pairs(tbl) do 54 + local res = pred(v,k) 55 + local np = cat(path, {tbl}) 56 + if res == true then 57 + table.insert(lst, { 58 + key = k; 59 + value = v; 60 + parent = tbl; 61 + path = np; 62 + }) 63 + elseif res == nil then 64 + search(v,pred,lst,np) 65 + end 66 + end 67 + return lst 68 +end 69 + 70 +local function dump(v,pfx,cyc,ismeta) 28 71 pfx = pfx or '' 29 72 cyc = cyc or {} 30 73 local np = pfx .. ' ' 31 74 32 75 if type(v) == 'table' then 33 76 if cyc[v] then return '<...>' else cyc[v] = true end 34 77 end ................................................................................ 37 80 return string.format('%q', v) 38 81 elseif type(v) == 'table' then 39 82 local str = '' 40 83 for k,v in pairs(v) do 41 84 local tkey, tval = dump(k,np,cyc), dump(v,np,cyc) 42 85 str = str .. string.format('%s[%s] = %s\n', np, tkey,tval) 43 86 end 44 - return '{\n' .. str .. pfx .. '}\n' 87 + local meta = '' 88 + if getmetatable(v) then 89 + meta = dump(getmetatable(v),pfx,cyc,true) .. '::' 90 + end 91 + if ismeta then 92 + return string.format('%s<|\n%s%s|>',meta,str,pfx) 93 + else 94 + return meta..'{\n' .. str .. pfx .. '}\n' 95 + end 45 96 else 46 97 return string.format('%s', v) 47 98 end 48 99 end 100 + 49 101 local ping = function(path) 50 102 local f = io.open(path) 51 103 if f then f:close() return true end 52 104 return false 53 105 end 54 106 local tobool = function(s) 55 107 if s == true then return true ................................................................................ 68 120 local seed = 1 for i = 1, 8 do 69 121 seed = seed * string.byte(string.sub(ent,i,i)) 70 122 end 71 123 math.randomseed(seed) 72 124 else math.randomseed(os.time()) end 73 125 74 126 return { 75 - exec = exec; 76 127 dump = dump; 77 - ping = ping; 78 - chomp = chomp; 79 - map = map; 80 - tobool = tobool; 128 + exec = exec, ping = ping; 129 + map = map, copy = copy, cat = cat, search = search; 130 + chomp = chomp, tobool = tobool; 81 131 find = function(lst,pred) 82 132 for k,v in pairs(lst) do 83 133 local test = pred(v,k) 84 134 if test then return test end 85 135 end 86 136 return nil 87 137 end; ................................................................................ 94 144 s = s .. string.char(ofs) 95 145 end 96 146 return s 97 147 end; 98 148 append = function(a,b) 99 149 for _, v in pairs(b) do a[#a+1] = v end 100 150 end; 101 - has = function(haystack,needle,eq) 102 - eq = eq or function(a,b) return a == b end 151 + has = function(haystack,pred) 152 + if type(pred) ~= 'function' then 153 + local val = pred 154 + pred = function(a) return a == val end 155 + end 103 156 for k,v in pairs(haystack) do 104 - if eq(needle,v) then return k end 157 + if pred(v,k) then return k,v end 105 158 end 106 159 end; 107 160 keys = function(ary) 108 161 local kt = {} 109 162 for k,v in pairs(ary) do kt[#kt+1] = k end 110 163 return kt 111 164 end;
Modified mem.t from [8c252399a5] to [d10508934e].
106 106 self.ct = self.ct - n 107 107 return self.ptr 108 108 end 109 109 terra t.methods.null(): t return t { ptr = nil, ct = 0 } end -- maybe should be a macro? 110 110 terra t:ref() return self.ptr ~= nil end 111 111 t.metamethods.__not = macro(function(self) return `not self:ref() end) 112 112 t.metamethods.__apply = macro(function(self,idx) return `self.ptr[ [idx or 0] ] end) 113 + t.metamethods.__add = terra(self: &t, sz: intptr): t 114 + var n = @self n:advance(sz) return n 115 + end 113 116 t.metamethods.__update = macro(function(self,idx,rhs) 114 117 return quote self.ptr[idx] = rhs end end) 115 118 t.metamethods.__cast = function(from,to,exp) 116 119 if to == t then 117 120 if from == niltype then return `t.null() 118 121 elseif from == &ty then return `t {ptr = exp, ct = 1} 119 122 elseif from == ty then return `t {ptr = &exp, ct = 1}
Modified route.t from [8f0d6bf9b0] to [325df84c8e].
923 923 return end 924 924 925 925 ::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded to this instance') return end 926 926 end 927 927 928 928 local json = {} 929 929 930 -terra json.webfinger(co: &lib.srv.convo) 931 - 930 +do wftpl = lib.tpl.mk [[{ 931 + "subject": @$subj, 932 + "links": [ 933 + { "rel": "self", "type": "application/ld+json", "href": @$href } 934 + ] 935 + }]] 936 + terra json.webfinger(co: &lib.srv.convo) 937 + var res = co:pgetv('resource') 938 + if (not res) or not res:startswith 'acct:' then goto err end 939 + 940 + -- technically we should look this user up in the database to make sure 941 + -- they actually exist, buuut that's costly and i doubt that's actually 942 + -- necessary for webfinger to do its job. so we cheat and just do string 943 + -- munging so lookups are as cheap as possible. TODO make sure this works 944 + -- in practice and doesn't cause any weird security problems 945 + var acct = res + 5 946 + var svp = lib.str.find(acct, '@') 947 + if svp:ref() then 948 + acct.ct = (svp.ptr - acct.ptr) 949 + svp:advance(1) 950 + if not svp:cmp(co.srv.cfg.domain) then goto err end 951 + end 952 + var tp = wftpl { 953 + subj = res; 954 + href = co:qstr('https://', co.srv.cfg.domain, '/@', acct); 955 + } 956 + co:json(tp:poolstr(&co.srv.pool)) 957 + 958 + do return end -- error conditions 959 + ::err:: do co:json('{}') return end 960 + end 932 961 end 933 962 934 963 -- entry points 935 964 terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t) 936 965 lib.dbg('handling URI of form ', {uri.ptr,uri.ct}) 937 966 co.navbar = lib.render.nav(co) 938 967 -- some routes are non-hierarchical, and can be resolved with a simple strcmp
Modified srv.t from [c8974a3f52] to [557555fd0b].
8 8 pol_sec: secmode.t 9 9 pol_reg: bool 10 10 pol_autoherald: bool 11 11 credmgd: bool 12 12 maxupsz: intptr 13 13 poolinitsz: intptr 14 14 instance: pstring 15 + domain: pstring 15 16 overlord: &srv 16 17 ui_cue_staff: pstring 17 18 ui_cue_founder: pstring 18 19 ui_hue: uint16 19 20 nranks: uint16 20 21 maxinvites: uint16 21 22 master: uint64 ................................................................................ 28 29 webmgr: lib.net.mg_mgr 29 30 webcon: &lib.net.mg_connection 30 31 cfg: cfgcache 31 32 id: rawstring 32 33 pool: lib.mem.pool 33 34 } 34 35 35 -terra cfgcache:free() -- :/ 36 +terra cfgcache:free() -- :/ TODO replace with pool 36 37 self.secret:free() 37 38 self.instance:free() 39 + self.domain:free() 38 40 self.ui_cue_staff:free() 39 41 self.ui_cue_founder:free() 40 42 self.usrdef_pol_follow:free() 41 43 self.usrdef_pol_follow_req:free() 42 44 end 43 45 44 46 terra srv:post_enum_author_uid(uid: uint64, r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post)) ................................................................................ 507 509 508 510 local route = {} -- these are defined in route.t, as they need access to renderers 509 511 terra route.dispatch_http :: {&convo, lib.mem.ptr(int8), lib.http.method.t} -> {} 510 512 511 513 local mimetypes = { 512 514 {'html', 'text/html'}; 513 515 {'json', 'application/json'}; 516 + {'json', 'application/ld+json'}; 517 + {'json', 'application/activity+json'}; 514 518 {'mkdown', 'text/markdown'}; 515 519 {'text', 'text/plain'}; 516 520 {'ansi', 'text/x-ansi'}; 517 521 } 518 522 519 523 local mimevar = symbol(lib.mem.ref(int8)) 520 524 local mimeneg = `lib.http.mime.none ................................................................................ 529 533 in ret end 530 534 end 531 535 532 536 local handle = { 533 537 http = terra(con: &lib.net.mg_connection, event_kind: int, event: &opaque, userdata: &opaque) 534 538 var server = [&srv](userdata) 535 539 var mgpeer = getpeer(con) 536 - var peer = lib.store.inet { port = mgpeer.port; } 537 - if mgpeer.is_ip6 then peer.pv = 6 else peer.pv = 4 end 538 - if peer.pv == 6 then 539 - for i = 0, 16 do peer.v6[i] = mgpeer.ip6[i] end 540 - else -- v4 541 - @[&uint32](&peer.v4) = mgpeer.ip 542 - end 540 + -- var pbuf: int8[128] 541 + 543 542 -- the peer property is currently broken and there is precious 544 543 -- little i can do about this -- it always reports a peer v4 IP 545 - -- of 0.0.0.0, altho the port seems to come through correctly. 546 - -- for now i'm leaving it as is, but note that netmask restrictions 547 - -- WILL NOT WORK until upstream gets its shit together. FIXME 544 + -- of 0.0.0.0 for v6 connections, altho the port seems to come 545 + -- through correctly. -- for now i'm leaving it as is, but note 546 + -- that netmask restrictions WILL NOT WORK until upstream gets 547 + -- its shit together. FIXME 548 548 549 549 -- needs to check for an X-Forwarded-For header from nginx and 550 550 -- use that instead of the peer iff peer is ::1/127.1 FIXME 551 551 -- maybe also haproxy support? 552 552 553 553 switch event_kind do 554 554 case lib.net.MG_EV_HTTP_MSG then 555 + -- lib.net.mg_ntoa(&mgpeer,&pbuf[0],127) 556 + -- lib.dbg('got connection from client ',&pbuf[0]) 557 + var peer = lib.store.inet { port = mgpeer.port; } 558 + if mgpeer.is_ip6 then peer.pv = 6 else peer.pv = 4 end 559 + if peer.pv == 6 then 560 + for i = 0, 16 do peer.v6[i] = mgpeer.ip6[i] end 561 + else -- v4 562 + @[&uint32](&peer.v4) = mgpeer.ip 563 + end 564 + 555 565 lib.dbg('routing HTTP request') 556 566 var msg = [&lib.net.mg_http_message](event) 557 567 var co = convo { 558 568 con = con, srv = server, msg = msg; 559 569 aid = 0, aid_issue = 0, who = nil; 560 570 reqtype = lib.http.mime.none; 561 571 peer = peer, live_last = 0; ................................................................................ 1110 1120 str:free() 1111 1121 end 1112 1122 return default 1113 1123 end 1114 1124 1115 1125 terra cfgcache:load() 1116 1126 self.instance = self.overlord:conf_get('instance-name') 1127 + self.domain = self.overlord:conf_get('domain') 1117 1128 self.secret = self.overlord:conf_get('server-secret') 1118 1129 1119 1130 self.pol_reg = self:cfbool('policy-self-register', false) 1120 1131 self.pol_autoherald = self:cfbool('policy-self-herald', true) 1121 1132 1122 1133 do self.credmgd = false 1123 1134 var sreg = self.overlord:conf_get('credential-store')
Modified str.t from [0c9ba1d780] to [6c699847d5].
59 59 60 60 var sz = lib.math.biggest(self.ct, other.ct) 61 61 for i = 0, sz do 62 62 if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end 63 63 if self.ptr[i] ~= other.ptr[i] then return false end 64 64 end 65 65 return true 66 + end 67 + terra ty:startswith(other: ty) 68 + for i=0, other.ct do 69 + if other(i) == 0 then return true end 70 + if other(i) ~= self(i) then return false end 71 + end 72 + return true 66 73 end 67 74 terra ty:ffw() 68 75 var newp = m.ffw(self.ptr,self.ct) 69 76 var newct = self.ct - (newp - self.ptr) 70 77 return ty { ptr = newp, ct = newct } 71 78 end 72 79 terra ty:blob() ................................................................................ 559 566 var cur = str while cur.ct > 0 do 560 567 var add, cont = disemvowel_codepoint(cur) 561 568 if add:ref() then acc:ppush(add) end 562 569 cur = cont 563 570 end 564 571 return acc:finalize() 565 572 end 573 + 574 +terra m.qesc(pool: &lib.mem.pool, str: m.t): m.t 575 + -- escape double-quotes 576 + var a: m.acc a:pool(pool, str.ct + str.ct/2) 577 + a:lpush '"' 578 + for i=0, str.ct do 579 + if str(i) == @'"' then a:lpush '\\"' 580 + elseif str(i) == @'\\' then a:lpush '\\\\' 581 + elseif str(i) < 0x20 then -- for json 582 + var hex = lib.math.hexbyte(str(i)) 583 + a:lpush('\\u00'):push(&hex[0], 2) 584 + else a:push(str.ptr + i,1) end 585 + end 586 + a:lpush '"' 587 + return a:finalize() 588 +end 566 589 567 590 return m
Modified tpl.t from [7216746946] to [ce74a1083d].
34 34 str = str:gsub('%s+[\n$]','') 35 35 str = str:gsub('\n','') 36 36 str = str:gsub('</a><a ','</a> <a ') -- keep nav links from getting smooshed 37 37 str = str:gsub(tplchar .. '%?([-%w]+)', function(file) 38 38 if not docs[file] then docs[file] = data.doc[file] end 39 39 return string.format('<a href="#help-%s" class="help">?</a>', file) 40 40 end) 41 - for start, mode, key, stop in string.gmatch(str,'()'..tplchar..'([:!]?)([-a-zA-Z0-9_]+)()') do 41 + for start, mode, key, stop in string.gmatch(str,'()'..tplchar..'([:!$]?)([-a-zA-Z0-9_]+)()') do 42 42 if string.sub(str,start-1,start-1) ~= '\\' then 43 43 segs[#segs+1] = string.sub(str,last,start-1) 44 44 fields[#segs] = { key = key:gsub('-','_'), mode = (mode ~= '' and mode or nil) } 45 45 last = stop 46 46 end 47 47 end 48 48 segs[#segs+1] = string.sub(str,last) ................................................................................ 73 73 if not kfac[fld.key] then 74 74 rec.entries[#rec.entries + 1] = { 75 75 field = fld.key; 76 76 type = lib.mem.ptr(int8); 77 77 } 78 78 end 79 79 kfac[fld.key] = (kfac[fld.key] or 0) + 1 80 - sanmode[fld.key] = fld.mode == ':' and 6 or fld.mode == '!' and 5 or 1 80 + sanmode[fld.key] = fld.mode == ':' and 6 81 + or fld.mode == '!' and 5 82 + or fld.mode == '$' and 2 or 1 81 83 end 82 84 for key, fac in pairs(kfac) do 83 85 local sanfac = sanmode[key] 84 86 85 87 tallyup[#tallyup + 1] = quote 86 88 [runningtally] = [runningtally] + ([symself].[key].ct)*fac*sanfac 87 89 end ................................................................................ 99 101 for idx, seg in ipairs(segs) do 100 102 copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end 101 103 senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end 102 104 appenders[#appenders+1] = quote [accumulator]:push([seg], [#seg]) end 103 105 if fields[idx] and fields[idx].mode then 104 106 local f = fields[idx] 105 107 local fp = `symself.[f.key] 108 + local sanexp 109 + if f.mode == '$' then 110 + sanexp = `lib.str.qesc(pool, fp) 111 + else 112 + sanexp = `lib.html.sanitize(pool, fp, [f.mode == ':']) 113 + end 106 114 copiers[#copiers+1] = quote 107 115 if fp.ct > 0 then 108 - var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 116 + var san = sanexp 109 117 [cpypos] = lib.mem.cpy([cpypos], [&opaque](san.ptr), san.ct) 110 118 --san:free() 111 119 end 112 120 end 113 121 senders[#senders+1] = quote 114 122 if fp.ct > 0 then 115 - var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 123 + var san = sanexp 116 124 lib.net.mg_send([destcon], san.ptr, san.ct) 117 125 --san:free() 118 126 end 119 127 end 120 128 appenders[#appenders+1] = quote 121 129 if fp.ct > 0 then 122 - var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 130 + var san = sanexp 123 131 [accumulator]:ppush(san) 124 132 --san:free() 125 133 end 126 134 end 127 135 elseif fields[idx] then 128 136 local f = fields[idx] 129 137 local fp = `symself.[f.key]