Skip to content

Commit

Permalink
feat(server): backend exec on post with deno
Browse files Browse the repository at this point in the history
Signed-off-by: John Andersen <johnandersen777@protonmail.com>
  • Loading branch information
johnandersen777 committed Dec 3, 2024
1 parent 5f1e920 commit 322e4fe
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 6 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ python -m pip install -e .
ATPROTO_BASE_URL=https://atproto.chadig.com ATPROTO_HANDLE=publicdomainrelay.atproto.chadig.com ATPROTO_PASSWORD=$(python -m keyring get publicdomainrelay@protonmail.com password.publicdomainrelay.atproto.chadig.com) python -m atprotobin
```

- Features
- mimetype Content-Type blob resolution
- text/javascript backend exec sandboxed with `deno --allow-net`
- TODO
- Receive webhook from VCS, get OIDC token, get secret using OIDC, trigger
push and pull for federated repo.
- References
- https://bsky.app/profile/johnandersen777.bsky.social/post/3lc47yvadu22i

[![asciicast](https://asciinema.org/a/693007.svg)](https://asciinema.org/a/693007)

- TODO
- Receive webhook from VCS, get OIDC token, get secret using OIDC, trigger
push and pull for federated repo.
14 changes: 14 additions & 0 deletions examples/mimetypes/javascript/backend_github_query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
let text = "";
const decoder = new TextDecoder();
for await (const chunk of Deno.stdin.readable) {
text += decoder.decode(chunk);
}
const input = JSON.parse(text);

const resp = await fetch("https://api.github.com/users/" + input["user"], {
headers: {
accept: "application/json",
},
});

console.log(JSON.stringify(await resp.json()));
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "atprotobin"
version = "1.0.0"
version = "1.1.0"
description = "ATProto based pastebin"
readme = {file = "README.md", content-type = "text/markdown"}
authors = [
Expand Down
47 changes: 46 additions & 1 deletion src/atprotobin/server.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import json
import asyncio
import hashlib
import pathlib
Expand All @@ -11,7 +12,7 @@
import markdown2
from pydantic import BaseModel
from atproto import AsyncClient, models
from fastapi import FastAPI, File, UploadFile, Request, Response
from fastapi import FastAPI, File, UploadFile, Request, Response, HTTPException
from fastapi.responses import HTMLResponse

from .zip_image import encode, decode
Expand Down Expand Up @@ -124,6 +125,50 @@ async def get(post_id: str):
blob = await load_and_decode(post_id)
return Response(content=blob.contents, media_type=blob.mimetype)

RUNABLE_MIMETYPES = [
"text/javascript",
"application/javascript",
]

# TODO https://www.thc.org/segfault/ hot pool
@app.post("/{post_id}")
async def exec(post_id: str, request: Request):
global RUNABLE_MIMETYPES
blob = await load_and_decode(post_id)
if blob.mimetype not in RUNABLE_MIMETYPES:
raise HTTPException(
status_code=415,
detail=f"Invalid file mimetype: {blob.mimetype!r}) runnable: {RUNABLE_MIMETYPES!r}",
)
with tempfile.TemporaryDirectory() as tempdir:
file_path = pathlib.Path(tempdir, "script.js")
file_path.write_bytes(blob.contents)
cmd = [
"deno",
"--allow-net",
file_path.name,
]
proc = await asyncio.create_subprocess_exec(
*cmd,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=tempdir,
)
stdout, stderr = await proc.communicate(input=await request.body())
try:
stdout_string = stdout.decode()
return json.loads(stdout_string)
except:
return {
"error": {
"detail": {
"stdout": stdout_string,
"stderr": stderr.decode(),
},
},
}

@app.get("/", response_class=HTMLResponse)
async def root():
return markdown_html_content_by_file["README.md"]

0 comments on commit 322e4fe

Please sign in to comment.