rhythia-api 229.0.0 → 231.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/checkQualified.ts +83 -0
- package/api/getBeatmapPage.ts +65 -28
- package/api/getBeatmapPageById.ts +61 -24
- package/api/getUserScores.ts +18 -15
- package/api/{nominateMap.ts → qualifyMap.ts} +86 -82
- package/api/submitScoreInternal.ts +449 -426
- package/api/{approveMap.ts → vetoMap.ts} +94 -78
- package/handleApi.ts +3 -7
- package/index.ts +134 -85
- package/package.json +10 -2
- package/queries/admin_delete_user.sql +39 -0
- package/queries/admin_exclude_user.sql +21 -0
- package/queries/admin_invalidate_ranked_scores.sql +18 -0
- package/queries/admin_log_action.sql +10 -0
- package/queries/admin_profanity_clear.sql +29 -0
- package/queries/admin_remove_all_scores.sql +29 -0
- package/queries/admin_restrict_user.sql +21 -0
- package/queries/admin_search_users.sql +24 -0
- package/queries/admin_silence_user.sql +21 -0
- package/queries/admin_unban_user.sql +21 -0
- package/queries/get_badge_leaderboard.sql +50 -0
- package/queries/get_clan_leaderboard.sql +68 -0
- package/queries/get_collections_v4.sql +109 -0
- package/queries/get_top_scores_for_beatmap.sql +44 -0
- package/queries/get_user_by_email.sql +32 -0
- package/queries/get_user_scores_lastday.sql +47 -0
- package/queries/get_user_scores_reign.sql +31 -0
- package/queries/get_user_scores_top_and_stats.sql +84 -0
- package/queries/grant_special_badges.sql +69 -0
- package/types/database.ts +1224 -1179
- package/utils/getUserBySession.ts +1 -1
- package/utils/requestUtils.ts +127 -88
package/utils/requestUtils.ts
CHANGED
|
@@ -1,88 +1,127 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import {
|
|
3
|
-
import { getUserBySession } from "./getUserBySession";
|
|
4
|
-
import { supabase } from "./supabase";
|
|
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
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { ZodObject } from "zod";
|
|
3
|
+
import { getUserBySession } from "./getUserBySession";
|
|
4
|
+
import { supabase } from "./supabase";
|
|
5
|
+
|
|
6
|
+
const SENSITIVE_LOG_KEYS = new Set([
|
|
7
|
+
"session",
|
|
8
|
+
"replayBytes",
|
|
9
|
+
"token",
|
|
10
|
+
"secret",
|
|
11
|
+
"passkey",
|
|
12
|
+
"passKey",
|
|
13
|
+
]);
|
|
14
|
+
const LONG_LOG_STRING_THRESHOLD = 256;
|
|
15
|
+
|
|
16
|
+
function sanitizeForLog(
|
|
17
|
+
value: unknown,
|
|
18
|
+
key?: string
|
|
19
|
+
):
|
|
20
|
+
| string
|
|
21
|
+
| number
|
|
22
|
+
| boolean
|
|
23
|
+
| null
|
|
24
|
+
| undefined
|
|
25
|
+
| Record<string, unknown>
|
|
26
|
+
| unknown[] {
|
|
27
|
+
const normalizedKey = (key || "").toLowerCase();
|
|
28
|
+
if (
|
|
29
|
+
SENSITIVE_LOG_KEYS.has(key || "") ||
|
|
30
|
+
SENSITIVE_LOG_KEYS.has(normalizedKey)
|
|
31
|
+
) {
|
|
32
|
+
if (value === null || value === undefined) {
|
|
33
|
+
return value as null | undefined;
|
|
34
|
+
}
|
|
35
|
+
return "<Long>";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (typeof value === "string") {
|
|
39
|
+
return value.length > LONG_LOG_STRING_THRESHOLD ? "<Long>" : value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
return value.map((item) => sanitizeForLog(item));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value && typeof value === "object") {
|
|
47
|
+
const sanitizedObject: Record<string, unknown> = {};
|
|
48
|
+
Object.entries(value as Record<string, unknown>).forEach(
|
|
49
|
+
([entryKey, entryValue]) => {
|
|
50
|
+
sanitizedObject[entryKey] = sanitizeForLog(entryValue, entryKey);
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
return sanitizedObject;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return value as string | number | boolean | null | undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface Props<
|
|
60
|
+
K = (...args: any[]) => Promise<NextResponse<any>>,
|
|
61
|
+
T = ZodObject<any>,
|
|
62
|
+
> {
|
|
63
|
+
request: Request;
|
|
64
|
+
schema: { input: T; output: T };
|
|
65
|
+
authorization?: Function;
|
|
66
|
+
activity: K;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function protectedApi({
|
|
70
|
+
request,
|
|
71
|
+
schema,
|
|
72
|
+
authorization,
|
|
73
|
+
activity,
|
|
74
|
+
}: Props) {
|
|
75
|
+
try {
|
|
76
|
+
const toParse = await request.json();
|
|
77
|
+
const data = schema.input.parse(toParse);
|
|
78
|
+
|
|
79
|
+
console.log("Request payload:", sanitizeForLog(data));
|
|
80
|
+
|
|
81
|
+
setActivity(data);
|
|
82
|
+
if (authorization) {
|
|
83
|
+
const authorizationResponse = await authorization(data);
|
|
84
|
+
if (authorizationResponse) {
|
|
85
|
+
return authorizationResponse;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return await activity(data, request);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.log(`Couldn't parse`, error.toString());
|
|
91
|
+
return NextResponse.json({ error: error.toString() }, { status: 400 });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function setActivity(data: Record<string, any>) {
|
|
96
|
+
if (data.session) {
|
|
97
|
+
const user = (await supabase.auth.getUser(data.session)).data.user;
|
|
98
|
+
if (user) {
|
|
99
|
+
await supabase.from("profileActivities").upsert({
|
|
100
|
+
uid: user.id,
|
|
101
|
+
last_activity: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function validUser(data) {
|
|
108
|
+
if (!data.session) {
|
|
109
|
+
return NextResponse.json(
|
|
110
|
+
{
|
|
111
|
+
error: "Session is missing",
|
|
112
|
+
},
|
|
113
|
+
{ status: 501 }
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const user = await getUserBySession(data.session);
|
|
118
|
+
if (!user) {
|
|
119
|
+
console.log("Invalid user session");
|
|
120
|
+
return NextResponse.json(
|
|
121
|
+
{
|
|
122
|
+
error: "Invalid user session",
|
|
123
|
+
},
|
|
124
|
+
{ status: 401 }
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|