-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmiddleware.ts
112 lines (100 loc) · 3.7 KB
/
middleware.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { createMiddlewareSupabaseClient } from "@supabase/auth-helpers-nextjs";
import { Redis } from "@upstash/redis";
import type { NextFetchEvent, NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { SummarizeParams } from "~/lib/types";
import { validateLicenseKey } from "./lib/lemon";
import { checkOpenaiApiKeys } from "./lib/openai/checkOpenaiApiKey";
import {
ratelimitForApiKeyIps,
ratelimitForFreeAccounts,
ratelimitForIps,
} from "./lib/upstash";
import { isDev } from "./utils/env";
const redis = Redis.fromEnv();
function redirectAuth() {
// return NextResponse.redirect(new URL("/shop", req.url));
// Respond with JSON indicating an error message
console.error("Authentication Failed");
return new NextResponse(
JSON.stringify({ success: false, message: "Authentication Failed" }),
{ status: 401, headers: { "content-type": "application/json" } }
);
}
function redirectShop(req: NextRequest) {
console.error("Account Limited");
return NextResponse.redirect(new URL("/shop", req.url));
}
export async function middleware(req: NextRequest, context: NextFetchEvent) {
try {
const { userConfig, videoConfig } = (await req.json()) as SummarizeParams;
const { userKey, shouldShowTimestamp } = userConfig || {};
const { videoId: bvId } = videoConfig || {};
const cacheId = shouldShowTimestamp ? `timestamp-${bvId}` : bvId;
const ipIdentifier = req.ip ?? "127.0.0.11";
// licenseKeys
if (userKey) {
if (checkOpenaiApiKeys(userKey)) {
const { success, remaining } = await ratelimitForApiKeyIps.limit(
ipIdentifier
);
console.log(`use user apiKey ${ipIdentifier}, remaining: ${remaining}`);
if (!success) {
return redirectShop(req);
}
return NextResponse.next();
}
// 3. something-invalid-sdalkjfasncs-key
const isValidatedLicense = await validateLicenseKey(userKey, cacheId);
if (!isValidatedLicense) {
return redirectShop(req);
}
}
if (isDev) {
return NextResponse.next();
}
// 👇 below only works for production
if (!userKey) {
const { success, remaining } = await ratelimitForIps.limit(ipIdentifier);
console.log(`ip free user ${ipIdentifier}, remaining: ${remaining}`);
if (!success) {
// We need to create a response and hand it to the supabase client to be able to modify the response headers.
const res = NextResponse.next();
// TODO: unique to a user (userid, email etc) instead of IP
// Create authenticated Supabase Client.
const supabase = createMiddlewareSupabaseClient({ req, res });
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession();
// Check auth condition
const userEmail = session?.user.email;
if (userEmail) {
// Authentication successful, forward request to protected route.
const { success, remaining } = await ratelimitForFreeAccounts.limit(
userEmail
);
// TODO: only reduce the count after summarized successfully
console.log(`login user ${userEmail}, remaining: ${remaining}`);
if (!success) {
return redirectShop(req);
}
return res;
}
// todo: throw error to trigger a modal, rather than redirect a page
return redirectAuth();
}
}
const result = await redis.get<string>(cacheId);
if (result) {
console.log("hit cache for ", cacheId);
return NextResponse.json(result);
}
} catch (e) {
console.error(e);
return redirectAuth();
}
}
export const config = {
matcher: "/api/sumup",
};