Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Improve code]: lib/* 手動formatter・Linter対応 #84

Merged
merged 29 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6c056c3
🚨 astro/src/libにESLintのfixオプションを適用
ZEKE320 Apr 6, 2024
a7a4af9
🚨 Astroの環境変数をstring型とみなす記述を追加
ZEKE320 Apr 6, 2024
08cb5fe
🚨 nullish判定を明確化
ZEKE320 Apr 6, 2024
a33a328
💬 コメントの空白を半角に変更
ZEKE320 Apr 6, 2024
e8bc360
🏷️ 変数の型情報を明記
ZEKE320 Apr 6, 2024
6998425
Merge remote-tracking branch 'upstream/develop' into feature/issue_58
ZEKE320 Apr 7, 2024
623f792
🎨 astro/src/libにPrettierを適用
ZEKE320 Apr 7, 2024
e5835ec
✏️ ファイル名getIdの綴りを修正
ZEKE320 Apr 7, 2024
4f51579
✏️ ファイル名変更に伴いimport文を修正
ZEKE320 Apr 7, 2024
c0b67f9
🏷️ Astro API用の型をZodで再定義
ZEKE320 Apr 7, 2024
700b531
🦺 APIレスポンス取得箇所にバリデーションチェックを追加
ZEKE320 Apr 7, 2024
bad010e
🏷️ モジュール外で型の名前が重複しないよう変更
ZEKE320 Apr 7, 2024
3e1565a
🩹 APIレスポンス処理時の型エラーに関する文言を修正
ZEKE320 Apr 7, 2024
b61fddd
🏷️ API呼び出し箇所の型定義更新に伴い、エラー判定箇所を修正
ZEKE320 Apr 7, 2024
dcaed42
🥅 getOgpMetaエラー時のステータス番号を定義
ZEKE320 Apr 7, 2024
ced281e
Merge remote-tracking branch 'origin/feature/issue_58' into preview/i…
ZEKE320 Apr 7, 2024
967b327
✏️ Zodオブジェクトの命名規則を統一
ZEKE320 Apr 10, 2024
4fd4e58
🥅 エラーレスポンスからhtmlを削除
ZEKE320 Apr 10, 2024
ce937a7
🔥 使用されていないレスポンス型定義用のJSONを削除
ZEKE320 Apr 10, 2024
0fc4c2d
🥅 エラー型判定の実装を改善
ZEKE320 Apr 10, 2024
f42fca5
Merge remote-tracking branch 'origin/feature/issue_58' into preview/i…
ZEKE320 Apr 10, 2024
bc2a8e8
🥅 エラー型の判定を`"error" in val`形式で統一
ZEKE320 Apr 11, 2024
9fc9f9c
⚰️ 使用されていない変数を削除
ZEKE320 Apr 11, 2024
16e1065
⚰️ 不要になった行を削除
ZEKE320 Apr 11, 2024
5443727
➕ 依存関係にZodを追加
ZEKE320 Apr 11, 2024
96e9a01
Merge remote-tracking branch 'origin/feature/issue_58' into preview/i…
ZEKE320 Apr 11, 2024
107d954
🥅 エラー型の判定ロジックを変更 & 型アサーション削除
ZEKE320 Apr 11, 2024
aa42a11
🔥 不要になったインポート行を削除
ZEKE320 Apr 11, 2024
62e71ac
Merge remote-tracking branch 'origin/feature/issue_58' into preview/i…
ZEKE320 Apr 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
764 changes: 745 additions & 19 deletions astro/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"tailwind-variants": "^0.1.20",
"tailwindcss": "^3.4.1",
"twitter-text": "^3.1.0",
"typescript": "^5.3.3"
"typescript": "^5.3.3",
"zod": "^3.22.4"
},
"devDependencies": {
"@changesets/cli": "^2.27.1",
Expand Down
2 changes: 1 addition & 1 deletion astro/src/components/Client/bsky/buttons/PostButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ export const Component = ({
accessJwt: session.accessJwt,
uri: createRecordResult.uri,
})
if (typeof createPageResult?.error !== "undefined") {
if ("error" in createPageResult) {
const e: Error = new Error(createPageResult.message)
e.name = createPageResult.error
throw e
Expand Down
5 changes: 2 additions & 3 deletions astro/src/components/Client/pagedb/PageDeleteButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ const Component = ({
did: session.did,
accessJwt: session.accessJwt
})
if (typeof resDeletePage?.error === "undefined" &&
resDeletePage.result === "ok") {
if (!("error" in resDeletePage)) {
setMsgInfo({
isError: false,
msg: "ページを削除しました!"
})
window.location.reload()
} else {
let e: Error = new Error(resDeletePage.message)
const e: Error = new Error(resDeletePage.message)
e.name = "pagedelete.tsx"
throw e
}
Expand Down
9 changes: 5 additions & 4 deletions astro/src/components/Client/pagedb/PageViewForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useContext, useState, ReactNode, Dispatch, SetStateAction } from "react"
import { pagesPrefix } from "@/env/envs"
import getIds from "@/lib/pagedbAPI/geIds"
import getIds from "@/lib/pagedbAPI/getIds"
import { Session_context } from "../common/contexts"
import { load_circle, link } from "../common/tailwindVariants"
import ProfileCard from "./ProfileCard"
Expand Down Expand Up @@ -34,20 +34,21 @@ const Component = ({
const ids = await getIds({
handle: session.handle!
})
if (typeof ids?.error !== "undefined") {
let e: Error = new Error(ids.message)
if ("error" in ids) {
const e: Error = new Error(ids.message)
e.name = ids.error
throw e
}
setMsgInfo({
isError: false,
msg: "投稿一覧を読み込みました!"
})

setList(
<div className="mx-auto">
<div>OGP生成したページ一覧</div>
<div className="grid sm:grid-cols-3 grid-cols-1">
{ids?.ids.map((value) => {
{ids.ids.map((value) => {
return (
<div className=" bg-white rounded-lg px-2 py-1 m-1 border-2">
<a className={link()} target="_blank"
Expand Down
14 changes: 8 additions & 6 deletions astro/src/lib/api/createErrResponse.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { errorResponse } from "./types"

const createErrResponse = ({
statusCode
statusCode,
}: {
statusCode: number
}): errorResponse => {
Expand All @@ -10,31 +10,33 @@ const createErrResponse = ({
case 405:
response = <errorResponse>{
error: "Method Not Allowed",
message: "Invalid method requested. API allow GET only."
message: "Invalid method requested. API allow GET only.",
}
break
case 406:
response = <errorResponse>{
error: "Not Acceptable",
message: "Invalid parameter requested. Check your request."
message: "Invalid parameter requested. Check your request.",
}
break
case 502:
response = <errorResponse>{
error: "Bad Gateway",
message: "Failed to get correct response from gateway. Announce server administrator."
message:
"Failed to get correct response from gateway. Announce server administrator.",
}
break
case 500:
response = <errorResponse>{
error: "Internal Server Error",
message: "Failed to internal process. Announce server administrator."
message:
"Failed to internal process. Announce server administrator.",
}
break
default:
response = <errorResponse>{
error: "Unexpected Error",
message: "Unexpected Error occured."
message: "Unexpected Error occured.",
}
}
response.status = statusCode
Expand Down
41 changes: 24 additions & 17 deletions astro/src/lib/api/types.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
export type ogpMetaData = {
type: "meta"
title: string,
description: string,
image: string,
}
import { z } from "zod"

export const ZodOgpMetaData = z.object({
type: z.literal("meta"),
title: z.string(),
description: z.string(),
image: z.string(),
})
export type ogpMetaData = z.infer<typeof ZodOgpMetaData>

// APIのエラーレスポンスを定義
export type errorResponse = {
type: "error"
error: string,
message: string,
status: number,
}

export type apiRequest = {
type: "api"
decodedUrl: string,
language: string,
}
export const ZodErrorResponse = z.object({
type: z.literal("error"),
error: z.string(),
message: z.string(),
status: z.number(),
})
export type errorResponse = z.infer<typeof ZodErrorResponse>

export const ZodApiRequest = z.object({
type: z.literal("api"),
decodedUrl: z.string(),
language: z.string(),
})
export type apiRequest = z.infer<typeof ZodApiRequest>
37 changes: 18 additions & 19 deletions astro/src/lib/api/validateRequest.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import createErrResponse from "./createErrResponse";
import createErrResponse from "./createErrResponse"
import { isNotProduction } from "@/lib/vars"
import { apiRequest, errorResponse } from "./types";
import { apiRequest, errorResponse } from "./types"

const protocol_validation: RegExp = /(dict|file|ftp|gopher|ldap|smtp|telnet|tftp):\/\//
const protocol_validation: RegExp =
/(dict|file|ftp|gopher|ldap|smtp|telnet|tftp):\/\//
const loopback_validation: RegExp = /localhost/
const ipv4_validation: RegExp = /(?:\d{0,3}\.){3}\d{0,3}/
const ipv6_validation: RegExp = /\[[0-9a-fA-F:]+\]/
Expand All @@ -13,7 +14,7 @@ const ipv6_validation: RegExp = /\[[0-9a-fA-F:]+\]/
* @returns apiResponse または エラーレスポンス
*/
const validateRequestReturnURL = ({
request
request,
}: {
request: Request
}): apiRequest | errorResponse => {
Expand All @@ -24,8 +25,8 @@ const validateRequestReturnURL = ({
})
}

const url = new URL(request.url).searchParams.get("url");
const lang = new URL(request.url).searchParams.get("lang");
const url: string | null = new URL(request.url).searchParams.get("url")
const lang: string | null = new URL(request.url).searchParams.get("lang")
if (url === null) {
return createErrResponse({
statusCode: 406,
Expand All @@ -36,20 +37,18 @@ const validateRequestReturnURL = ({
statusCode: 406,
})
}
const decodedUrl = decodeURIComponent(url)
const decodedUrl: string = decodeURIComponent(url)
// SSRF対策
// Productionではない環境についてはlocalhostの実行を許可
const validation = !isNotProduction ? (
// Productionの場合は厳格なルールを指定
protocol_validation.test(decodedUrl) ||
loopback_validation.test(decodedUrl) ||
ipv4_validation.test(decodedUrl) ||
ipv6_validation.test(decodedUrl)
) : (
// Not Productionの場合は(Cloudflare Zero Trustといった)
// 低レイヤー対策前提でlocalhostを許可
protocol_validation.test(decodedUrl)
)
const validation: boolean = !isNotProduction
? // Productionの場合は厳格なルールを指定
protocol_validation.test(decodedUrl) ||
loopback_validation.test(decodedUrl) ||
ipv4_validation.test(decodedUrl) ||
ipv6_validation.test(decodedUrl)
: // Not Productionの場合は(Cloudflare Zero Trustといった)
// 低レイヤー対策前提でlocalhostを許可
protocol_validation.test(decodedUrl)
if (validation) {
return createErrResponse({
statusCode: 502,
Expand All @@ -59,7 +58,7 @@ const validateRequestReturnURL = ({
return <apiRequest>{
type: "api",
decodedUrl: decodedUrl,
language: lang
language: lang,
}
}
export default validateRequestReturnURL
90 changes: 58 additions & 32 deletions astro/src/lib/getOgp.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,91 @@
import type { ogpMetaData, errorResponse } from "@/lib/api/types";
import type { errorResponse, ogpMetaData } from "@/lib/api/types"
import { ZodErrorResponse, ZodOgpMetaData } from "@/lib/api/types"

// note: エラー規格を型定義として決めた方がいい( error@Component: message とするなど)
// note: エラー規格を型定義として決めた方がいい( error@Component: message とするなど)
export const getOgpMeta = async ({
siteurl,
externalUrl,
languageCode,
}: {
siteurl: string,
externalUrl: string,
languageCode: string,
siteurl: string
externalUrl: string
languageCode: string
}): Promise<ogpMetaData | errorResponse> => {
const apiUrl = new URL("/api/getOgpMeta", siteurl)
apiUrl.searchParams.append("url", encodeURIComponent(externalUrl))
apiUrl.searchParams.append("lang", languageCode)
return await fetch(apiUrl, {
method: 'GET',
method: "GET",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
"Accept-Language": languageCode,
"Cache-Control": "no-cache",
}
}).then(async (response) => {
if (!response?.ok) {
let res: errorResponse = await response.json()
let e: Error = new Error(res.message)
e.name = res.error
throw e
}
return await response.json() as ogpMetaData
}).catch((e: Error) => {
return <errorResponse>{
type: "error",
error: `${e.name}@getOgpMeta`,
message: e.message
}
},
})
.then(async response => {
const jsonResponse: unknown = await response.json()
const responseParsedAsError =
ZodErrorResponse.safeParse(jsonResponse)
const responseParsedAsOgpMetaData =
ZodOgpMetaData.safeParse(jsonResponse)

if (!(response.ok && responseParsedAsOgpMetaData.success)) {
const e: Error = new Error(
responseParsedAsError.success
? responseParsedAsError.data.message
: "Unexpected Response Type@getOgpMeta",
)
e.name = responseParsedAsError.success
? responseParsedAsError.data.error
: "Unexpected Response Type"
throw e
}

return responseParsedAsOgpMetaData.data
})
.catch((e: Error) => {
return {
type: "error",
error: `${e.name}@getOgpMeta`,
message: e.message,
status: 500,
}
})
}
// Blob型はユニオン型として扱うことが難しいため、エラーハンドリングできない
export const getOgpBlob = async ({
siteurl,
externalUrl,
languageCode,
}: {
siteurl: string,
externalUrl: string,
languageCode: string,
siteurl: string
externalUrl: string
languageCode: string
}): Promise<Blob> => {
const apiUrl = new URL("/api/getOgpBlob", siteurl)
apiUrl.searchParams.append("url", encodeURIComponent(externalUrl))
apiUrl.searchParams.append("lang", languageCode)
return await fetch(apiUrl, {
method: 'GET',
method: "GET",
headers: {
"Accept-Language": languageCode,
"Cache-Control": "no-cache",
}
}).then(async (response) => {
if (!response?.ok) {
let res: errorResponse = await response.json()
let e: Error = new Error(res.message)
e.name = `${res.error}@getOgpBlob`
},
}).then(async response => {
if (!response.ok) {
const responseParsedAsError = ZodErrorResponse.safeParse(
response.json(),
)
const e: Error = new Error(
responseParsedAsError.success
? responseParsedAsError.data.message
: "Unexpected Response Type@getOgpBlob",
)
e.name = `${
responseParsedAsError.success
? responseParsedAsError.data.error
: "Unexpected Response Type"
}@getOgpBlob`
throw e
}
return await response.blob()
Expand Down
Loading