website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


08782d0pyrossh 2026-07-07T12:15:52+05:30
fix: add HX-Request guard, error handling, and issue ID validation
packages/workers/repos/issues/detail/src/index.tsx CHANGED
@@ -91,30 +91,60 @@ export default {
91
91
  const repoId = parts[1];
92
92
  const issueId = parts[3];
93
93
 
94
+ if (!/^[a-f0-9]{16}$/.test(issueId)) {
95
+ return Response.redirect(`${url.origin}/repos/${repoId}/issues`, 302);
96
+ }
97
+
94
98
  const repo = getRepo(repoId);
95
99
  if (!repo) return Response.redirect(`${url.origin}/404`, 302);
96
100
 
97
- const issue = await getGitBugIssue(env.REPOS, repo.id, issueId ?? "");
101
+ const issue = await getGitBugIssue(env.REPOS, repo.id, issueId);
98
102
  if (!issue) return Response.redirect(`${url.origin}/repos/${repo.id}/issues`, 302);
99
103
 
100
104
  if (request.method === "POST") {
105
+ if (!request.headers.get("HX-Request")) {
106
+ return Response.redirect(request.url, 303);
107
+ }
108
+
101
109
  const formData = await request.formData();
102
110
  const body = formData.get("body") as string;
103
111
  const author = formData.get("author") as string;
112
+
113
+ try {
104
- const updated = await addGitBugIssueComment(env.REPOS, repo.id, issueId, { body, author });
114
+ const updated = await addGitBugIssueComment(env.REPOS, repo.id, issueId, { body, author });
105
- return new Response("<!---->" + CommentsSection(repo.id, updated).toString(), {
115
+ return new Response("<!---->" + CommentsSection(repo.id, updated).toString(), {
106
- headers: { "Content-Type": "text/html" },
116
+ headers: { "Content-Type": "text/html" },
107
- });
117
+ });
118
+ } catch (err) {
119
+ const message = err instanceof Error ? err.message : "Unknown error";
120
+ return new Response(
121
+ `<div class="error" style="color:red;padding:0.5rem">${message}</div>`,
122
+ { headers: { "content-type": "text/html" } },
123
+ );
124
+ }
108
125
  }
109
126
 
110
127
  if (request.method === "PUT") {
128
+ if (!request.headers.get("HX-Request")) {
129
+ return Response.redirect(request.url, 303);
130
+ }
131
+
111
132
  const formData = await request.formData();
112
133
  const state = formData.get("state") as "open" | "closed";
113
134
  const author = formData.get("author") as string;
135
+
136
+ try {
114
- const updated = await setGitBugIssueState(env.REPOS, repo.id, issueId, state, author);
137
+ const updated = await setGitBugIssueState(env.REPOS, repo.id, issueId, state, author);
115
- return new Response(StateBadge(updated).toString(), {
138
+ return new Response(StateBadge(updated).toString(), {
116
- headers: { "Content-Type": "text/html" },
139
+ headers: { "Content-Type": "text/html" },
117
- });
140
+ });
141
+ } catch (err) {
142
+ const message = err instanceof Error ? err.message : "Unknown error";
143
+ return new Response(
144
+ `<div class="error" style="color:red;padding:0.5rem">${message}</div>`,
145
+ { headers: { "content-type": "text/html" } },
146
+ );
147
+ }
118
148
  }
119
149
 
120
150
  return new Response(
packages/workers/repos/issues/index/src/index.tsx CHANGED
@@ -11,6 +11,10 @@ export default {
11
11
  if (!repo) return Response.redirect(`${url.origin}/404`, 302);
12
12
 
13
13
  if (request.method === "POST") {
14
+ if (!request.headers.get("HX-Request")) {
15
+ return Response.redirect(request.url, 303);
16
+ }
17
+
14
18
  const formData = await request.formData();
15
19
  const title = formData.get("title") as string;
16
20
  const body = formData.get("body") as string;
@@ -23,14 +27,22 @@ export default {
23
27
  .filter(Boolean)
24
28
  : undefined;
25
29
 
30
+ try {
26
- const issue = await createGitBugIssue(env.REPOS, repo.id, { title, body, author, labels });
31
+ await createGitBugIssue(env.REPOS, repo.id, { title, body, author, labels });
27
32
 
28
- const { issues } = await getGitBugIssues(env.REPOS, repo.id);
33
+ const { issues } = await getGitBugIssues(env.REPOS, repo.id);
29
- const html = issues.map((i) => <IssueCard repoId={repo.id} issue={i} />).join("");
34
+ const html = issues.map((i) => <IssueCard repoId={repo.id} issue={i} />).join("");
30
35
 
31
- return new Response(html, {
36
+ return new Response(html, {
32
- headers: { "Content-Type": "text/html" },
37
+ headers: { "Content-Type": "text/html" },
33
- });
38
+ });
39
+ } catch (err) {
40
+ const message = err instanceof Error ? err.message : "Unknown error";
41
+ return new Response(
42
+ `<div class="error" style="color:red;padding:0.5rem">${message}</div>`,
43
+ { headers: { "content-type": "text/html" } },
44
+ );
45
+ }
34
46
  }
35
47
 
36
48
  const { issues, isAvailable } = await getGitBugIssues(env.REPOS, repo.id);