rhythia-api 151.0.0 → 153.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/approveMap.ts +3 -1
- package/api/createBeatmap.ts +3 -1
- package/api/createBeatmapPage.ts +4 -2
- package/api/deleteBeatmapPage.ts +3 -1
- package/api/editAboutMe.ts +3 -1
- package/api/editProfile.ts +3 -1
- package/api/getAvatarUploadUrl.ts +3 -1
- package/api/getBadgedUsers.ts +1 -1
- package/api/getLeaderboard.ts +5 -3
- package/api/getMapUploadUrl.ts +3 -1
- package/api/getPassToken.ts +55 -0
- package/api/getProfile.ts +3 -1
- package/api/nominateMap.ts +3 -1
- package/api/postBeatmapComment.ts +3 -1
- package/api/rankMapsArchive.ts +3 -1
- package/api/setPasskey.ts +59 -0
- package/api/submitScore.ts +27 -10
- package/api/updateBeatmapPage.ts +3 -1
- package/index.ts +38 -1
- package/package.json +2 -1
- package/types/database.ts +26 -0
- package/utils/getUserBySession.ts +48 -0
- package/utils/requestUtils.ts +3 -15
- package/utils/security.ts +20 -0
- package/utils/star-calc/index.ts +0 -2
package/api/approveMap.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -23,7 +25,7 @@ export async function POST(request: Request) {
|
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
26
|
-
const user = (await
|
|
28
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
27
29
|
let { data: queryUserData, error: userError } = await supabase
|
|
28
30
|
.from("profiles")
|
|
29
31
|
.select("*")
|
package/api/createBeatmap.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { SSPMParser } from "../utils/star-calc/sspmParser";
|
|
|
5
5
|
import { supabase } from "../utils/supabase";
|
|
6
6
|
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
7
7
|
import { rateMap } from "../utils/star-calc";
|
|
8
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
9
|
+
import { User } from "@supabase/supabase-js";
|
|
8
10
|
const s3Client = new S3Client({
|
|
9
11
|
region: "auto",
|
|
10
12
|
endpoint: "https://s3.eu-central-003.backblazeb2.com",
|
|
@@ -52,7 +54,7 @@ export async function handler({
|
|
|
52
54
|
const parsedData = parser.parse();
|
|
53
55
|
const digested = parsedData.strings.mapID;
|
|
54
56
|
|
|
55
|
-
const user = (await
|
|
57
|
+
const user = (await getUserBySession(session)) as User;
|
|
56
58
|
let { data: userData, error: userError } = await supabase
|
|
57
59
|
.from("profiles")
|
|
58
60
|
.select("*")
|
package/api/createBeatmapPage.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -27,7 +29,7 @@ export async function handler({
|
|
|
27
29
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
28
30
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
29
31
|
> {
|
|
30
|
-
const user = (await
|
|
32
|
+
const user = (await getUserBySession(session)) as User;
|
|
31
33
|
let { data: userData, error: userError } = await supabase
|
|
32
34
|
.from("profiles")
|
|
33
35
|
.select("*")
|
|
@@ -49,7 +51,7 @@ export async function handler({
|
|
|
49
51
|
{ status: 404 }
|
|
50
52
|
);
|
|
51
53
|
}
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
const upserted = await supabase
|
|
54
56
|
.from("beatmapPages")
|
|
55
57
|
.upsert({
|
package/api/deleteBeatmapPage.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -28,7 +30,7 @@ export async function handler({
|
|
|
28
30
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
29
31
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
30
32
|
> {
|
|
31
|
-
const user = (await
|
|
33
|
+
const user = (await getUserBySession(session)) as User;
|
|
32
34
|
let { data: userData, error: userError } = await supabase
|
|
33
35
|
.from("profiles")
|
|
34
36
|
.select("*")
|
package/api/editAboutMe.ts
CHANGED
|
@@ -3,6 +3,8 @@ import z from "zod";
|
|
|
3
3
|
import { Database } from "../types/database";
|
|
4
4
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
5
5
|
import { supabase } from "../utils/supabase";
|
|
6
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
7
|
+
import { User } from "@supabase/supabase-js";
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
8
10
|
session: z.string(),
|
|
@@ -45,7 +47,7 @@ export async function handler(
|
|
|
45
47
|
);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
const user = (await
|
|
50
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
49
51
|
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
50
52
|
|
|
51
53
|
// Find user's entry
|
package/api/editProfile.ts
CHANGED
|
@@ -3,6 +3,8 @@ import z from "zod";
|
|
|
3
3
|
import { Database } from "../types/database";
|
|
4
4
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
5
5
|
import { supabase } from "../utils/supabase";
|
|
6
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
7
|
+
import { User } from "@supabase/supabase-js";
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
8
10
|
session: z.string(),
|
|
@@ -46,7 +48,7 @@ export async function handler(
|
|
|
46
48
|
);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
const user = (await
|
|
51
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
50
52
|
|
|
51
53
|
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
52
54
|
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "@aws-sdk/client-s3";
|
|
11
11
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
12
12
|
import { validateIntrinsicToken } from "../utils/validateToken";
|
|
13
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
14
|
+
import { User } from "@supabase/supabase-js";
|
|
13
15
|
|
|
14
16
|
const s3Client = new S3Client({
|
|
15
17
|
region: "auto",
|
|
@@ -51,7 +53,7 @@ export async function handler({
|
|
|
51
53
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
52
54
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
53
55
|
> {
|
|
54
|
-
const user = (await
|
|
56
|
+
const user = (await getUserBySession(session)) as User;
|
|
55
57
|
|
|
56
58
|
if (!validateIntrinsicToken(intrinsicToken)) {
|
|
57
59
|
return NextResponse.json({
|
package/api/getBadgedUsers.ts
CHANGED
package/api/getLeaderboard.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import z from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { protectedApi } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -48,7 +50,7 @@ export async function handler(
|
|
|
48
50
|
const VIEW_PER_PAGE = 50;
|
|
49
51
|
|
|
50
52
|
export async function getLeaderboard(page = 1, session: string) {
|
|
51
|
-
const getUserData = await
|
|
53
|
+
const getUserData = (await getUserBySession(session)) as User;
|
|
52
54
|
|
|
53
55
|
let leaderPosition = 0;
|
|
54
56
|
|
|
@@ -56,7 +58,7 @@ export async function getLeaderboard(page = 1, session: string) {
|
|
|
56
58
|
let { data: queryData, error } = await supabase
|
|
57
59
|
.from("profiles")
|
|
58
60
|
.select("*")
|
|
59
|
-
.eq("uid", getUserData.
|
|
61
|
+
.eq("uid", getUserData.id)
|
|
60
62
|
.single();
|
|
61
63
|
|
|
62
64
|
if (queryData) {
|
package/api/getMapUploadUrl.ts
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "@aws-sdk/client-s3";
|
|
11
11
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
12
12
|
import { validateIntrinsicToken } from "../utils/validateToken";
|
|
13
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
14
|
+
import { User } from "@supabase/supabase-js";
|
|
13
15
|
|
|
14
16
|
const s3Client = new S3Client({
|
|
15
17
|
region: "auto",
|
|
@@ -53,7 +55,7 @@ export async function handler({
|
|
|
53
55
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
54
56
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
55
57
|
> {
|
|
56
|
-
const user = (await
|
|
58
|
+
const user = (await getUserBySession(session)) as User;
|
|
57
59
|
|
|
58
60
|
if (!validateIntrinsicToken(intrinsicToken)) {
|
|
59
61
|
return NextResponse.json({
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { Database } from "../types/database";
|
|
4
|
+
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
5
|
+
import { supabase } from "../utils/supabase";
|
|
6
|
+
import { encryptString } from "../utils/security";
|
|
7
|
+
export const Schema = {
|
|
8
|
+
input: z.strictObject({
|
|
9
|
+
data: z.object({
|
|
10
|
+
email: z.string(),
|
|
11
|
+
passkey: z.string(),
|
|
12
|
+
computerName: z.string(),
|
|
13
|
+
}),
|
|
14
|
+
}),
|
|
15
|
+
output: z.object({
|
|
16
|
+
token: z.string().optional(),
|
|
17
|
+
error: z.string().optional(),
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export async function POST(request: Request): Promise<NextResponse> {
|
|
22
|
+
return protectedApi({
|
|
23
|
+
request,
|
|
24
|
+
schema: Schema,
|
|
25
|
+
authorization: () => {},
|
|
26
|
+
activity: handler,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function handler(
|
|
31
|
+
data: (typeof Schema)["input"]["_type"]
|
|
32
|
+
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
33
|
+
let { data: queryPasskey, error } = await supabase
|
|
34
|
+
.from("passkeys")
|
|
35
|
+
.select("*")
|
|
36
|
+
.eq("email", data.data.email)
|
|
37
|
+
.eq("passkey", data.data.passkey)
|
|
38
|
+
.single();
|
|
39
|
+
|
|
40
|
+
if (!queryPasskey) {
|
|
41
|
+
return NextResponse.json({
|
|
42
|
+
error: "Wrong combination",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return NextResponse.json({
|
|
46
|
+
token: encryptString(
|
|
47
|
+
JSON.stringify({
|
|
48
|
+
userId: queryPasskey.id,
|
|
49
|
+
email: queryPasskey.email,
|
|
50
|
+
passKey: queryPasskey.passkey,
|
|
51
|
+
computerName: data.data.computerName,
|
|
52
|
+
})
|
|
53
|
+
),
|
|
54
|
+
});
|
|
55
|
+
}
|
package/api/getProfile.ts
CHANGED
|
@@ -4,6 +4,8 @@ import z from "zod";
|
|
|
4
4
|
import { Database } from "../types/database";
|
|
5
5
|
import { protectedApi } from "../utils/requestUtils";
|
|
6
6
|
import { supabase } from "../utils/supabase";
|
|
7
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
8
|
+
import { User } from "@supabase/supabase-js";
|
|
7
9
|
|
|
8
10
|
export const Schema = {
|
|
9
11
|
input: z.strictObject({
|
|
@@ -71,7 +73,7 @@ export async function handler(
|
|
|
71
73
|
profiles = queryData;
|
|
72
74
|
} else {
|
|
73
75
|
// Fetch by session id
|
|
74
|
-
const user = (await
|
|
76
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
75
77
|
|
|
76
78
|
if (user) {
|
|
77
79
|
let { data: queryData, error } = await supabase
|
package/api/nominateMap.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -23,7 +25,7 @@ export async function POST(request: Request) {
|
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
26
|
-
const user = (await
|
|
28
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
27
29
|
let { data: queryUserData, error: userError } = await supabase
|
|
28
30
|
.from("profiles")
|
|
29
31
|
.select("*")
|
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { User } from "@supabase/supabase-js";
|
|
6
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -30,7 +32,7 @@ export async function handler({
|
|
|
30
32
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
31
33
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
32
34
|
> {
|
|
33
|
-
const user = (await
|
|
35
|
+
const user = (await getUserBySession(session)) as User;
|
|
34
36
|
let { data: userData, error: userError } = await supabase
|
|
35
37
|
.from("profiles")
|
|
36
38
|
.select("*")
|
package/api/rankMapsArchive.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -23,7 +25,7 @@ export async function POST(request: Request) {
|
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
26
|
-
const user = (await
|
|
28
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
27
29
|
let { data: queryUserData, error: userError } = await supabase
|
|
28
30
|
.from("profiles")
|
|
29
31
|
.select("*")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { Database } from "../types/database";
|
|
4
|
+
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
5
|
+
import { supabase } from "../utils/supabase";
|
|
6
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
7
|
+
import { User } from "@supabase/supabase-js";
|
|
8
|
+
export const Schema = {
|
|
9
|
+
input: z.strictObject({
|
|
10
|
+
session: z.string(),
|
|
11
|
+
data: z.object({
|
|
12
|
+
passkey: z.string(),
|
|
13
|
+
}),
|
|
14
|
+
}),
|
|
15
|
+
output: z.object({
|
|
16
|
+
error: z.string().optional(),
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export async function POST(request: Request): Promise<NextResponse> {
|
|
21
|
+
return protectedApi({
|
|
22
|
+
request,
|
|
23
|
+
schema: Schema,
|
|
24
|
+
authorization: () => {},
|
|
25
|
+
activity: handler,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function handler(
|
|
30
|
+
data: (typeof Schema)["input"]["_type"]
|
|
31
|
+
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
32
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
33
|
+
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
34
|
+
// Find user's entry
|
|
35
|
+
{
|
|
36
|
+
let { data: queryUserData, error } = await supabase
|
|
37
|
+
.from("profiles")
|
|
38
|
+
.select("*")
|
|
39
|
+
.eq("uid", user.id);
|
|
40
|
+
|
|
41
|
+
if (!queryUserData?.length) {
|
|
42
|
+
return NextResponse.json(
|
|
43
|
+
{
|
|
44
|
+
error: "User cannot be retrieved from session",
|
|
45
|
+
},
|
|
46
|
+
{ status: 404 }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
userData = queryUserData[0];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await supabase.from("passkeys").upsert({
|
|
53
|
+
id: userData.id!,
|
|
54
|
+
email: user.email!,
|
|
55
|
+
passkey: data.data.passkey,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return NextResponse.json({});
|
|
59
|
+
}
|
package/api/submitScore.ts
CHANGED
|
@@ -2,6 +2,10 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { decryptString } from "../utils/security";
|
|
6
|
+
import { isEqual } from "lodash";
|
|
7
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
8
|
+
import { User } from "@supabase/supabase-js";
|
|
5
9
|
|
|
6
10
|
export const Schema = {
|
|
7
11
|
input: z.strictObject({
|
|
@@ -13,7 +17,6 @@ export const Schema = {
|
|
|
13
17
|
misses: z.number(),
|
|
14
18
|
hits: z.number(),
|
|
15
19
|
mapHash: z.string(),
|
|
16
|
-
mapNoteCount: z.number(),
|
|
17
20
|
speed: z.number(),
|
|
18
21
|
}),
|
|
19
22
|
}),
|
|
@@ -50,13 +53,26 @@ export async function handler({
|
|
|
50
53
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
51
54
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
52
55
|
> {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
const tokenContents = JSON.parse(decryptString(data.token));
|
|
57
|
+
if (
|
|
58
|
+
!isEqual(tokenContents, {
|
|
59
|
+
relayHwid: data.relayHwid,
|
|
60
|
+
songId: data.songId,
|
|
61
|
+
misses: data.misses,
|
|
62
|
+
hits: data.hits,
|
|
63
|
+
mapHash: data.mapHash,
|
|
64
|
+
speed: data.speed,
|
|
65
|
+
})
|
|
66
|
+
) {
|
|
67
|
+
return NextResponse.json(
|
|
68
|
+
{
|
|
69
|
+
error: "Token miscalculation",
|
|
70
|
+
},
|
|
71
|
+
{ status: 500 }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const user = (await getUserBySession(session)) as User;
|
|
60
76
|
|
|
61
77
|
let { data: userData, error: userError } = await supabase
|
|
62
78
|
.from("profiles")
|
|
@@ -103,7 +119,8 @@ export async function handler({
|
|
|
103
119
|
);
|
|
104
120
|
}
|
|
105
121
|
|
|
106
|
-
|
|
122
|
+
const noteCount = data.misses + data.hits;
|
|
123
|
+
if (noteCount !== beatmaps.noteCount) {
|
|
107
124
|
return NextResponse.json(
|
|
108
125
|
{
|
|
109
126
|
error: "Wrong map",
|
|
@@ -124,7 +141,7 @@ export async function handler({
|
|
|
124
141
|
passed = false;
|
|
125
142
|
}
|
|
126
143
|
|
|
127
|
-
const accurracy = data.hits /
|
|
144
|
+
const accurracy = data.hits / noteCount;
|
|
128
145
|
let awarded_sp = 0;
|
|
129
146
|
|
|
130
147
|
console.log(
|
package/api/updateBeatmapPage.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
4
|
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
5
7
|
|
|
6
8
|
export const Schema = {
|
|
7
9
|
input: z.strictObject({
|
|
@@ -34,7 +36,7 @@ export async function handler({
|
|
|
34
36
|
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
35
37
|
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
36
38
|
> {
|
|
37
|
-
const user = (await
|
|
39
|
+
const user = (await getUserBySession(session)) as User;
|
|
38
40
|
let { data: userData, error: userError } = await supabase
|
|
39
41
|
.from("profiles")
|
|
40
42
|
.select("*")
|
package/index.ts
CHANGED
|
@@ -353,6 +353,26 @@ import { Schema as GetMapUploadUrl } from "./api/getMapUploadUrl"
|
|
|
353
353
|
export { Schema as SchemaGetMapUploadUrl } from "./api/getMapUploadUrl"
|
|
354
354
|
export const getMapUploadUrl = handleApi({url:"/api/getMapUploadUrl",...GetMapUploadUrl})
|
|
355
355
|
|
|
356
|
+
// ./api/getPassToken.ts API
|
|
357
|
+
|
|
358
|
+
/*
|
|
359
|
+
export const Schema = {
|
|
360
|
+
input: z.strictObject({
|
|
361
|
+
data: z.object({
|
|
362
|
+
email: z.string(),
|
|
363
|
+
passkey: z.string(),
|
|
364
|
+
computerName: z.string(),
|
|
365
|
+
}),
|
|
366
|
+
}),
|
|
367
|
+
output: z.object({
|
|
368
|
+
token: z.string().optional(),
|
|
369
|
+
error: z.string().optional(),
|
|
370
|
+
}),
|
|
371
|
+
};*/
|
|
372
|
+
import { Schema as GetPassToken } from "./api/getPassToken"
|
|
373
|
+
export { Schema as SchemaGetPassToken } from "./api/getPassToken"
|
|
374
|
+
export const getPassToken = handleApi({url:"/api/getPassToken",...GetPassToken})
|
|
375
|
+
|
|
356
376
|
// ./api/getProfile.ts API
|
|
357
377
|
|
|
358
378
|
/*
|
|
@@ -562,6 +582,24 @@ import { Schema as SearchUsers } from "./api/searchUsers"
|
|
|
562
582
|
export { Schema as SchemaSearchUsers } from "./api/searchUsers"
|
|
563
583
|
export const searchUsers = handleApi({url:"/api/searchUsers",...SearchUsers})
|
|
564
584
|
|
|
585
|
+
// ./api/setPasskey.ts API
|
|
586
|
+
|
|
587
|
+
/*
|
|
588
|
+
export const Schema = {
|
|
589
|
+
input: z.strictObject({
|
|
590
|
+
session: z.string(),
|
|
591
|
+
data: z.object({
|
|
592
|
+
passkey: z.string(),
|
|
593
|
+
}),
|
|
594
|
+
}),
|
|
595
|
+
output: z.object({
|
|
596
|
+
error: z.string().optional(),
|
|
597
|
+
}),
|
|
598
|
+
};*/
|
|
599
|
+
import { Schema as SetPasskey } from "./api/setPasskey"
|
|
600
|
+
export { Schema as SchemaSetPasskey } from "./api/setPasskey"
|
|
601
|
+
export const setPasskey = handleApi({url:"/api/setPasskey",...SetPasskey})
|
|
602
|
+
|
|
565
603
|
// ./api/submitScore.ts API
|
|
566
604
|
|
|
567
605
|
/*
|
|
@@ -575,7 +613,6 @@ export const Schema = {
|
|
|
575
613
|
misses: z.number(),
|
|
576
614
|
hits: z.number(),
|
|
577
615
|
mapHash: z.string(),
|
|
578
|
-
mapNoteCount: z.number(),
|
|
579
616
|
speed: z.number(),
|
|
580
617
|
}),
|
|
581
618
|
}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rhythia-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "153.0.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"update": "bun ./scripts/update.ts",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"@aws-sdk/client-s3": "^3.637.0",
|
|
17
17
|
"@aws-sdk/s3-request-presigner": "^3.637.0",
|
|
18
18
|
"@netlify/zip-it-and-ship-it": "^9.37.9",
|
|
19
|
+
"@noble/ciphers": "^1.0.0",
|
|
19
20
|
"@supabase/supabase-js": "^2.45.1",
|
|
20
21
|
"@types/aws-lambda": "^8.10.143",
|
|
21
22
|
"@types/bun": "^1.1.6",
|
package/types/database.ts
CHANGED
|
@@ -147,6 +147,32 @@ export type Database = {
|
|
|
147
147
|
}
|
|
148
148
|
Relationships: []
|
|
149
149
|
}
|
|
150
|
+
passkeys: {
|
|
151
|
+
Row: {
|
|
152
|
+
email: string
|
|
153
|
+
id: number
|
|
154
|
+
passkey: string
|
|
155
|
+
}
|
|
156
|
+
Insert: {
|
|
157
|
+
email: string
|
|
158
|
+
id: number
|
|
159
|
+
passkey: string
|
|
160
|
+
}
|
|
161
|
+
Update: {
|
|
162
|
+
email?: string
|
|
163
|
+
id?: number
|
|
164
|
+
passkey?: string
|
|
165
|
+
}
|
|
166
|
+
Relationships: [
|
|
167
|
+
{
|
|
168
|
+
foreignKeyName: "passkeys_id_fkey"
|
|
169
|
+
columns: ["id"]
|
|
170
|
+
isOneToOne: true
|
|
171
|
+
referencedRelation: "profiles"
|
|
172
|
+
referencedColumns: ["id"]
|
|
173
|
+
},
|
|
174
|
+
]
|
|
175
|
+
}
|
|
150
176
|
profiles: {
|
|
151
177
|
Row: {
|
|
152
178
|
about_me: string | null
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { User } from "@supabase/supabase-js";
|
|
2
|
+
import { decryptString } from "./security";
|
|
3
|
+
import { supabase } from "./supabase";
|
|
4
|
+
|
|
5
|
+
export async function getUserBySession(session: string): Promise<User | null> {
|
|
6
|
+
const user = (await supabase.auth.getUser(session)).data.user;
|
|
7
|
+
|
|
8
|
+
if (user) {
|
|
9
|
+
return user;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
console.log("trying legacy token");
|
|
14
|
+
const decryptedToken = JSON.parse(decryptString(session)) as {
|
|
15
|
+
userId: number;
|
|
16
|
+
email: string;
|
|
17
|
+
passKey: string;
|
|
18
|
+
computerName: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
for (const key of Object.keys(decryptedToken)) {
|
|
22
|
+
if (decryptedToken[key] === undefined || decryptedToken[key] === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(decryptedToken);
|
|
28
|
+
|
|
29
|
+
let { data: queryPasskey, error } = await supabase
|
|
30
|
+
.from("passkeys")
|
|
31
|
+
.select("*,profiles(uid)")
|
|
32
|
+
.eq("id", decryptedToken.userId)
|
|
33
|
+
.eq("email", decryptedToken.email)
|
|
34
|
+
.eq("passkey", decryptedToken.passKey)
|
|
35
|
+
.single();
|
|
36
|
+
|
|
37
|
+
console.log(queryPasskey);
|
|
38
|
+
|
|
39
|
+
if (!queryPasskey) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (await supabase.auth.admin.getUserById(queryPasskey.profiles?.uid!))
|
|
44
|
+
.data.user;
|
|
45
|
+
} catch (error) {}
|
|
46
|
+
|
|
47
|
+
return null;
|
|
48
|
+
}
|
package/utils/requestUtils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
|
-
import { supabase } from "./supabase";
|
|
3
2
|
import { ZodObject } from "zod";
|
|
3
|
+
import { getUserBySession } from "./getUserBySession";
|
|
4
4
|
|
|
5
5
|
interface Props<
|
|
6
6
|
K = (...args: any[]) => Promise<NextResponse<any>>,
|
|
@@ -43,8 +43,8 @@ export async function validUser(data) {
|
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const user = await
|
|
47
|
-
if (
|
|
46
|
+
const user = await getUserBySession(data.session);
|
|
47
|
+
if (!user) {
|
|
48
48
|
return NextResponse.json(
|
|
49
49
|
{
|
|
50
50
|
error: "Invalid user session",
|
|
@@ -53,15 +53,3 @@ export async function validUser(data) {
|
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
export async function getUser(data) {
|
|
58
|
-
if (!data.session) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const user = await supabase.auth.getUser(data.session);
|
|
63
|
-
if (user.error || !user.data.user) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
return user;
|
|
67
|
-
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { xchacha20poly1305 } from "@noble/ciphers/chacha";
|
|
2
|
+
import { managedNonce } from "@noble/ciphers/webcrypto";
|
|
3
|
+
import {
|
|
4
|
+
bytesToHex,
|
|
5
|
+
bytesToUtf8,
|
|
6
|
+
hexToBytes,
|
|
7
|
+
utf8ToBytes,
|
|
8
|
+
} from "@noble/ciphers/utils";
|
|
9
|
+
const key = hexToBytes(process.env.TOKEN_SECRET || "");
|
|
10
|
+
const chacha = managedNonce(xchacha20poly1305)(key); // manages nonces for you
|
|
11
|
+
|
|
12
|
+
export function encryptString(str: string) {
|
|
13
|
+
const data = utf8ToBytes(str);
|
|
14
|
+
return bytesToHex(chacha.encrypt(data));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function decryptString(str: string) {
|
|
18
|
+
const data = hexToBytes(str);
|
|
19
|
+
return bytesToUtf8(chacha.decrypt(data));
|
|
20
|
+
}
|
package/utils/star-calc/index.ts
CHANGED
|
@@ -48,7 +48,6 @@ export function rate(
|
|
|
48
48
|
) {
|
|
49
49
|
notes = notes.sort((a, b) => a.time - b.time);
|
|
50
50
|
const decoder = new BeatmapDecoder();
|
|
51
|
-
const encoder = new BeatmapEncoder();
|
|
52
51
|
const beatmap1 = decoder.decodeFromString(sampleMap);
|
|
53
52
|
let i = 0;
|
|
54
53
|
while (i < notes.length - 1) {
|
|
@@ -70,7 +69,6 @@ export function rate(
|
|
|
70
69
|
const mods = ruleset.createModCombination("RX");
|
|
71
70
|
const difficultyCalculator = ruleset.createDifficultyCalculator(beatmap1);
|
|
72
71
|
const difficultyAttributes = difficultyCalculator.calculateWithMods(mods);
|
|
73
|
-
encoder.encodeToPath("./map.osu", beatmap1);
|
|
74
72
|
return difficultyAttributes.starRating;
|
|
75
73
|
}
|
|
76
74
|
|