diff options
| author | 2023-04-18 03:02:17 +0800 | |
|---|---|---|
| committer | 2023-04-18 03:02:17 +0800 | |
| commit | 4919f028c884a041da7ff098abb02389b4eac598 (patch) | |
| tree | b0f482568c4b8c8a680ce6e2e70a7b7ca87dc190 /pages/api/v1/secret | |
| parent | b135aac8531c1e1488147ad8c6f98eddbdbe0c99 (diff) | |
| download | HydroRoll-4919f028c884a041da7ff098abb02389b4eac598.tar.gz HydroRoll-4919f028c884a041da7ff098abb02389b4eac598.zip | |
✨add envshare docs
Diffstat (limited to 'pages/api/v1/secret')
| -rw-r--r-- | pages/api/v1/secret/[id].ts | 58 | ||||
| -rw-r--r-- | pages/api/v1/secret/index.ts | 96 |
2 files changed, 0 insertions, 154 deletions
diff --git a/pages/api/v1/secret/[id].ts b/pages/api/v1/secret/[id].ts deleted file mode 100644 index 8b5f082..0000000 --- a/pages/api/v1/secret/[id].ts +++ /dev/null @@ -1,58 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { Redis } from "@upstash/redis"; -import { z } from "zod"; - -const responseValidation = z.union([ - z.object({ - data: z.object({ - remainingReads: z.number().int().optional(), - secret: z.string(), - }), - }), - z.object({ - error: z.string(), - }), -]); - -const redis = Redis.fromEnv(); -export default async function handler(req: NextRequest): Promise<NextResponse> { - try { - if (req.method !== "GET") { - return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 }); - } - const id = new URL(req.url).searchParams.get("id"); - if (!id) { - return NextResponse.json({ error: "Missing `id` parameter" }, { status: 400 }); - } - - const redisKey = ["envshare", id].join(":"); - - const [data, _] = await Promise.all([ - await redis.hgetall<{ secret: string; remainingReads: number | null }>(redisKey), - await redis.incr("envshare:metrics:reads"), - ]); - - if (!data) { - return NextResponse.json({ error: "Not Found" }, { status: 404 }); - } - if (data.remainingReads !== null && data.remainingReads < 1) { - await redis.del(redisKey); - return NextResponse.json({ error: "Not Found" }, { status: 404 }); - } - - let remainingReads: number | null = null; - if (data.remainingReads !== null) { - // Decrement the number of reads and return the remaining reads - remainingReads = await redis.hincrby(redisKey, "remainingReads", -1); - } - - return NextResponse.json({ data: { secret: data.secret, remainingReads: remainingReads ?? undefined } }); - } catch (e) { - console.error(e); - return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); - } -} - -export const config = { - runtime: "edge", -}; diff --git a/pages/api/v1/secret/index.ts b/pages/api/v1/secret/index.ts deleted file mode 100644 index 423e7a0..0000000 --- a/pages/api/v1/secret/index.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { Redis } from "@upstash/redis"; -import { generateId } from "pkg/id"; -import { z } from "zod"; - -export const requestValidation = z.object({ - // ttl in seconds - // defaults to 30 days - // not more than 1 year - // 0 means no expiration - ttl: z - .string() - .nullable() - .transform((v) => (v ? parseInt(v, 10) : 43260)) - .refine((v) => v >= 0 && v <= 30758400, "ttl must be between 0 and 30758400 seconds"), - - // number of reads before deletion - // defaults to null (no limit) - reads: z - .string() - .nullable() - .transform((v) => (v ? parseInt(v, 10) : null)) - .refine((v) => v === null || v > 0, "reads must be greater than 0"), - secret: z.string().min(1), -}); -export const responseValidation = z.union([ - z.object({ - data: z.object({ - id: z.string(), - ttl: z.number().optional(), - reads: z.number().optional(), - expiresAt: z.string(), - url: z.string().url(), - }), - }), - z.object({ - error: z.string(), - }), -]); - -const redis = Redis.fromEnv(); - -export default async function handler(req: NextRequest): Promise<NextResponse> { - try { - if (req.method !== "POST") { - return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 }); - } - - const parsed = requestValidation.safeParse({ - ttl: req.headers.get("envshare-ttl"), - reads: req.headers.get("envshare-reads"), - secret: await req.text(), - }); - if (!parsed.success) { - return NextResponse.json({ error: JSON.parse(parsed.error.message) }, { status: 400 }); - } - const { ttl, reads, secret } = parsed.data; - - const id = generateId(); - const rediskey = ["envshare", id].join(":"); - - const tx = redis.multi(); - - tx.hset(rediskey, { - remainingReads: reads ?? null, - secret, - }); - tx.incr("envshare:metrics:writes"); - if (ttl > 0) { - tx.expire(rediskey, ttl); - } - - await tx.exec(); - const url = new URL(req.url); - url.pathname = `/api/v1/secret/${id}`; - - return NextResponse.json( - responseValidation.parse({ - data: { - id, - ttl: ttl > 0 ? ttl : undefined, - reads: reads ?? undefined, - expiresAt: ttl > 0 ? new Date(Date.now() + ttl * 1000).toISOString() : undefined, - url: url.toString(), - }, - }), - ); - } catch (e) { - console.error(e); - return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); - } -} - -export const config = { - runtime: "edge", -}; |
