Differences From
Artifact [325df84c8e]:
93 93 if not go or go(0) ~= @'/' then
94 94 lib.render.user_page(co, actor, &rel)
95 95 else
96 96 co:reroute(go.ptr)
97 97 end
98 98 end
99 99
100 -terra http.actor_profile_xid(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
100 +terra http.actor_dispatch_mime(co: &lib.srv.convo, actor: &lib.store.actor)
101 + if co:matchmime(lib.http.mime.html) then
102 + http.actor_profile(co,actor,co.method)
103 + elseif co:matchmime(lib.http.mime.json) then
104 + lib.api.lp.actor(co, actor)
105 + else co:fail(406) end
106 +end
107 +
108 +terra http.actor_profile_xid(co: &lib.srv.convo, uri: lib.mem.ptr(int8))
101 109 var handle = [lib.mem.ptr(int8)] { ptr = &uri.ptr[2], ct = 0 }
102 110 for i=2,uri.ct do
103 111 if uri.ptr[i] == @'/' or uri.ptr[i] == 0 then handle.ct = i - 2 break end
104 112 end
105 113 if handle.ct == 0 then
106 114 handle.ct = uri.ct - 2
107 115 uri:advance(uri.ct)
................................................................................
114 122 var actor = co.srv:actor_fetch_xid(handle)
115 123 if actor.ptr == nil then
116 124 co:complain(404,'no such user','no such user known to this server')
117 125 return
118 126 end
119 127 defer actor:free()
120 128
121 - http.actor_profile(co,actor.ptr,meth)
129 + http.actor_dispatch_mime(co, actor.ptr)
122 130 end
123 131
124 132 terra http.actor_profile_uid (
125 133 co: &lib.srv.convo,
126 - path: lib.mem.ptr(lib.mem.ref(int8)),
127 - meth: method.t
134 + path: lib.mem.ptr(lib.mem.ref(int8))
128 135 )
129 136 if path.ct < 2 then
130 137 co:complain(404,'bad url','invalid user url')
131 138 return
132 139 end
133 140
134 141 var uid, ok = lib.math.shorthand.parse(path.ptr[1].ptr, path.ptr[1].ct)
................................................................................
140 147 var actor = co.srv:actor_fetch_uid(uid)
141 148 if actor.ptr == nil then
142 149 co:complain(404, 'no such user', 'no user by that ID is known to this instance')
143 150 return
144 151 end
145 152 defer actor:free()
146 153
147 - http.actor_profile(co,actor.ptr,meth)
154 + http.actor_dispatch_mime(co, actor.ptr)
148 155 end
149 156
150 157 terra http.login_form(co: &lib.srv.convo, meth: method.t)
151 158 if meth_get(meth) then
152 159 -- request a username
153 160 lib.render.login(co, nil, nil, pstring.null())
154 161 elseif meth == method.post then
................................................................................
225 232 lib.render.login(co, nil, nil, 'authentication failure')
226 233 else
227 234 co:installkey('/',aid)
228 235 end
229 236 end
230 237 if act.ptr ~= nil and fakeact == false then act:free() end
231 238 else
232 - ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
239 + ::wrongmeth:: co:fail(405) do return end
233 240 end
234 241 return
235 242 end
236 243
237 244 terra http.post_compose(co: &lib.srv.convo, meth: method.t)
238 245 if not co:assertpow('post') then return end
239 246 --if co.who.rights.powers.post() == false then
................................................................................
242 249 if meth_get(meth) then
243 250 lib.render.compose(co, nil, nil)
244 251 elseif meth == method.post then
245 252 var text, textlen = co:postv("post")
246 253 var acl, acllen = co:postv("acl")
247 254 var subj, subjlen = co:postv("subject")
248 255 if text == nil or acl == nil then
249 - co:complain(405, 'invalid post', 'every post must have at least body text and an ACL')
256 + co:complain(400, 'invalid post', 'every post must have at least body text and an ACL')
250 257 return
251 258 end
252 259 if subj == nil then subj = '' end
253 260
254 261 var p = lib.store.post {
255 262 author = co.who.id, acl = acl;
256 263 body = text, subject = subj;
................................................................................
404 411 end
405 412
406 413 if not post then goto badurl end
407 414
408 415 lib.render.tweet_page(co, path, post.ptr)
409 416 do return end
410 417
411 - ::badurl:: do co:complain(404, 'invalid URL', 'this URL does not reference extant content or functionality') return end
412 - ::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
413 - ::noauth:: do co:complain(401, 'unauthorized', 'you have not supplied the necessary credentials to perform this operation') return end
418 + ::noauth:: do co:fail(401) return end
419 + ::badurl:: do co:fail(404) return end
420 + ::badop :: do co:fail(405) return end
414 421 end
415 422
416 423 local terra
417 424 credsec_for_uid(co: &lib.srv.convo, uid: uint64)
418 425 var act = co:ppostv('act')
419 426 if not act then return true end
420 427 lib.dbg('handling credential action')
................................................................................
921 928 do defer data:free() defer mime:free()
922 929 co:bytestream(mime,data)
923 930 return end
924 931
925 932 ::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded to this instance') return end
926 933 end
927 934
928 -local json = {}
929 -
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
961 -end
962 935
963 936 -- entry points
964 -terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
937 +terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8))
965 938 lib.dbg('handling URI of form ', {uri.ptr,uri.ct})
966 939 co.navbar = lib.render.nav(co)
967 940 -- some routes are non-hierarchical, and can be resolved with a simple strcmp
968 941 -- we run through those first before giving up and parsing the URI
942 + var meth = co.method -- TODO unfuck this legacy bat shit
969 943 if uri.ptr == nil or uri.ptr[0] ~= @'/' then
970 944 co:complain(404, 'what the hell', 'how did you do that')
971 945 elseif uri.ct == 1 then -- root
972 946 if (co.srv.cfg.pol_sec == lib.srv.secmode.private or
973 947 co.srv.cfg.pol_sec == lib.srv.secmode.lockdown) and co.aid == 0 then
974 948 http.login_form(co, meth)
975 949 else http.timeline(co, hpath {ptr=nil,ct=0}) end
976 950 elseif uri.ptr[1] == @'@' then
977 - http.actor_profile_xid(co, uri, meth)
951 + http.actor_profile_xid(co, uri)
978 952 elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
979 953 if not meth_get(meth) then goto wrongmeth end
980 954 if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end
981 955 elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then
982 956 http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5})
983 957 elseif lib.str.ncmp('/file/', uri.ptr, 6) == 0 then
984 958 http.file_serve_raw(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 6, ct = uri.ct - 6})
................................................................................
997 971 if co.aid == 0
998 972 then goto notfound
999 973 else co:reroute_cookie('/','auth=; Path=/')
1000 974 end
1001 975 else -- hierarchical routes
1002 976 var path = lib.http.hier(&co.srv.pool, uri) --defer path:free()
1003 977 if path.ct > 1 and path(0):cmp('user') then
1004 - http.actor_profile_uid(co, path, meth)
978 + http.actor_profile_uid(co, path)
1005 979 elseif path.ct > 1 and path(0):cmp('post') then
1006 980 http.tweet_page(co, path, meth)
1007 981 elseif path(0):cmp('tl') then
1008 982 http.timeline(co, path)
1009 983 elseif path(0):cmp('.well-known') then
1010 984 if path(1):cmp('webfinger') then
1011 - json.webfinger(co)
985 + if not co:matchmime(lib.http.mime.json) then goto nacc end
986 + lib.api.webfinger(co)
1012 987 end
988 + elseif path(0):cmp('api') then
989 + if path(1):cmp('parsav') then -- native API
990 + elseif path(1):cmp('v1') then -- mastodon client api :/
991 + elseif path(1):cmp('lp') then -- litepub endpoints
992 + if path(2):cmp('outbox') then
993 + lib.api.lp.outbox(co,uri,path + 3)
994 + elseif path(2):cmp('inbox') then
995 + end
996 + else goto notfound end
1013 997 elseif path(0):cmp('media') then
1014 998 if co.aid == 0 then goto unauth end
1015 999 http.media_manager(co, path, meth, co.who.id)
1016 1000 elseif path(0):cmp('doc') then
1017 1001 if not meth_get(meth) then goto wrongmeth end
1018 1002 http.documentation(co, path)
1019 1003 elseif path(0):cmp('conf') then
1020 1004 if co.aid == 0 then goto unauth end
1021 1005 http.configure(co,path,meth)
1022 1006 else goto notfound end
1023 1007 end
1024 1008 do return end
1025 1009
1026 - ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
1027 - ::notfound:: co:complain(404, 'not found', 'no such resource available') do return end
1028 - ::unauth:: co:complain(401, 'unauthorized', 'this content is not available at your clearance level') do return end
1010 + ::wrongmeth:: co:fail(405) do return end
1011 + ::nacc :: co:fail(406) do return end
1012 + ::notfound :: co:fail(404) do return end
1013 + ::unauth :: co:fail(401) do return end
1029 1014 end