Skip to content

Commit

Permalink
fix: update the validate logic
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmyLv committed Mar 3, 2023
1 parent 25f2f50 commit a4c5cfa
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 45 deletions.
51 changes: 12 additions & 39 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,32 @@
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import type { NextFetchEvent, NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { RATE_LIMIT_COUNT } from "./utils/constants";
import { checkLicenseKey } from "./utils/3rd/lemon";
import { checkOpenaiApiKey } from "./utils/3rd/openai";
import { ratelimit } from "./utils/3rd/upstash";
import { isDev } from "./utils/env";

const redis = Redis.fromEnv();

const ratelimit = new Ratelimit({
redis: new Redis({
url: process.env.UPSTASH_RATE_REDIS_REST_URL,
token: process.env.UPSTASH_RATE_REDIS_REST_TOKEN,
}),
// 速率限制算法 https://github.com/upstash/ratelimit#ratelimiting-algorithms
limiter: Ratelimit.fixedWindow(RATE_LIMIT_COUNT, "1 d"),
analytics: true, // <- Enable analytics
});

export async function middleware(req: NextRequest, context: NextFetchEvent) {
if (isDev) {
return NextResponse.next();
}

const { bvId, apiKey } = await req.json();
const { apiKey, bvId, ...rest } = await req.json();
const result = await redis.get<string>(bvId);
if (result) {
if (!isDev && result) {
console.log("hit cache for ", bvId);
return NextResponse.json(result);
}

const response = await fetch(`https://api.lemonsqueezy.com/v1/license-keys`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.LEMON_API_KEY ?? ""}`,
},
});
const keysData = await response.json();
const licenseKeys = keysData.data?.map((i: any) => i.attributes.key);

// licenseKeys
if (
apiKey &&
!apiKey.startsWith(`sk-`) &&
licenseKeys?.includes(apiKey.toLowerCase())
) {
const { remaining } = await ratelimit.limit(apiKey.toLowerCase());
// TODO: log to hit licenseKey
console.log(
`!!!!!!!!! {short-xxxx-licenseKey}, remaining: ${remaining} ========`
);
if (remaining === 0) {
if (apiKey) {
if (checkOpenaiApiKey(apiKey)) {
return NextResponse.next();
}

// 3. something-invalid-sdalkjfasncs-key
if (!(await checkLicenseKey(apiKey))) {
return NextResponse.redirect(new URL("/shop", req.url));
}
}

// TODO: unique to a user (userid, email etc) instead of IP
const identifier = req.ip ?? "127.0.0.5";
const { success, remaining } = await ratelimit.limit(identifier);
Expand Down
Empty file added utils/3rd/bilibili.ts
Empty file.
24 changes: 24 additions & 0 deletions utils/3rd/lemon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ratelimit } from "./upstash";

export async function checkLicenseKey(licenseKey: string) {
const response = await fetch(`https://api.lemonsqueezy.com/v1/license-keys`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.LEMON_API_KEY ?? ""}`,
},
});
const keysData = await response.json();
const licenseKeys = keysData.data?.map((i: any) => i.attributes.key);

if (licenseKeys?.includes(licenseKey.toLowerCase())) {
// TODO: change to supabase after implement user-login
const { remaining } = await ratelimit.limit(licenseKey.toLowerCase());
// TODO: log to hit licenseKey
console.log(
`!!!!!!!!! {short-xxxx-licenseKey}, remaining: ${remaining} ========`
);
return remaining > 0;
}

return false;
}
4 changes: 4 additions & 0 deletions utils/3rd/openai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function checkOpenaiApiKey(str: string) {
var pattern = /^sk-[A-Za-z0-9]{48}$/;
return pattern.test(str);
}
13 changes: 13 additions & 0 deletions utils/3rd/upstash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { RATE_LIMIT_COUNT } from "../constants";

export const ratelimit = new Ratelimit({
redis: new Redis({
url: process.env.UPSTASH_RATE_REDIS_REST_URL,
token: process.env.UPSTASH_RATE_REDIS_REST_TOKEN,
}),
// 速率限制算法 https://github.com/upstash/ratelimit#ratelimiting-algorithms
limiter: Ratelimit.fixedWindow(RATE_LIMIT_COUNT, "1 d"),
analytics: true, // <- Enable analytics
});
11 changes: 5 additions & 6 deletions utils/OpenAIResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ParsedEvent,
ReconnectInterval,
} from "eventsource-parser";
import { checkOpenaiApiKey } from "./3rd/openai";

// TODO: maybe chat with video?
export type ChatGPTAgent = "user" | "system" | "assistant";
Expand All @@ -24,10 +25,6 @@ export interface OpenAIStreamPayload {
n: number;
}

function checkApiKey(str: string) {
var pattern = /^sk-[A-Za-z0-9]{48}$/;
return pattern.test(str);
}
const sample = (arr: any[] = []) => {
const len = arr === null ? 0 : arr.length;
return len ? arr[Math.floor(Math.random() * len)] : undefined;
Expand All @@ -49,11 +46,13 @@ export async function OpenAIResult(
const decoder = new TextDecoder();
const myApiKeyList = process.env.OPENAI_API_KEY;
const luckyApiKey = sample(myApiKeyList?.split(","));
const openai_api_key = apiKey || luckyApiKey || "";
const openai_api_key = checkOpenaiApiKey(apiKey || "") ? apiKey : luckyApiKey || "";

if (!checkApiKey(openai_api_key)) {
/* // don't need to validate anymore, already verified in middleware
if (!checkOpenaiApiKey(openai_api_key)) {
throw new Error("OpenAI API Key Format Error");
}
*/

const res = await fetch("https://api.openai.com/v1/chat/completions", {
headers: {
Expand Down

0 comments on commit a4c5cfa

Please sign in to comment.