diff --git a/+layout.svelte b/+layout.svelte new file mode 100644 index 0000000..5e0c69d --- /dev/null +++ b/+layout.svelte @@ -0,0 +1,445 @@ + + + +{#if navigator.userAgent.indexOf("Firefox") === -1} +
+ +
+{/if} + +
+
+ +
+
+ +
+
+ +
+
+
+ + {#each navItems as item, i} + toggleDropdown()} + > +

{item.name}

+
+ {/each} +
+
+ + {#key data.url} +
+ +
+ {/key} +
diff --git a/+page.svelte b/+page.svelte new file mode 100644 index 0000000..81ea910 --- /dev/null +++ b/+page.svelte @@ -0,0 +1,279 @@ + + + + {metadata.title} + + + + + + + + + + + + + + +
+ + + + +

+ suyu is a fully open-source + Switch emulator +

+

+ suyu is a familiar C++ based Switch emulator with a focus on compatibility. Completely free + and open-source, forever. +

+ +
+ +
+
+

By the numbers

+ + + + +
+
+
+
+ +
+
+
+
+ +
+

+ Built by and for the community +

+

+ The future of suyu is shaped by you. New features are always being added, and our community + continually shapes the direction of the project. +

+
+ + + +
+

+ we’re passionate about preserving games. +

+

+ We’re developing suyu as a tool to prevent Switch games from becoming lost media, so we’re + taking care to prevent dissolution from outside influences. +

+
+
+ + + +

suyu is community-run.

+
+
+ + + +

suyu is completely free. There’s no option to monetarily support the project.

+
+
+ + + +

suyu exists solely as an effort of hardware preservation and research.

+
+
+ + + +

suyu does not condone nor facilitate piracy or intellectual property theft.

+
+
+
+ +
diff --git a/src/lib/server/util/index.ts b/src/lib/server/util/index.ts index fb4030d..104afea 100644 --- a/src/lib/server/util/index.ts +++ b/src/lib/server/util/index.ts @@ -1,6 +1,6 @@ import type { IJwtData } from "$types/auth"; import type { Role } from "$types/db"; -import { PUBLIC_KEY } from "../secrets/secrets.json"; +import { PUB_KEY } from "$env/static/private"; import jwt from "jsonwebtoken"; export function json(body: T, status?: number): Response { @@ -14,7 +14,7 @@ export function json(body: T, status?: number): Response { export async function getJwtData(token: string): Promise { return new Promise((resolve, reject) => { - jwt.verify(token, PUBLIC_KEY, { algorithms: ["RS256"] }, (err, data) => { + jwt.verify(token, PUB_KEY, { algorithms: ["RS256"] }, (err, data) => { if (err) reject(err); else resolve(data as IJwtData); }); diff --git a/src/lib/util/api/index.ts b/src/lib/util/api/index.ts index b5c24e4..dbedfb6 100644 --- a/src/lib/util/api/index.ts +++ b/src/lib/util/api/index.ts @@ -1,6 +1,6 @@ import { userRepo } from "$lib/server/repo"; import type { SuyuUser } from "$lib/server/schema"; -import { PUBLIC_KEY } from "$lib/server/secrets/secrets.json"; +import { PUB_KEY } from "$env/static/private"; import type { IJwtData } from "$types/auth"; import cookie from "cookie"; import jwt from "jsonwebtoken"; @@ -18,7 +18,7 @@ export async function useAuth( } if (apiKey.startsWith("Bearer ")) { const token = apiKey.replace("Bearer ", ""); - const decoded: IJwtData = jwt.verify(token, Buffer.from(PUBLIC_KEY), { + const decoded: IJwtData = jwt.verify(token, Buffer.from(PUB_KEY), { algorithms: ["RS256"], }) as IJwtData; let user = await userRepo.findOne({ diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 281a8d6..bc384a7 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -6,6 +6,7 @@ let starCount = 0; let roleMembers = { "1214817156420862012": 50, }; +let gitCommits = 0; async function fetchServerSideData() { console.log("Fetching member count"); @@ -22,16 +23,17 @@ async function fetchServerSideData() { fetch("https://git.suyu.dev/api/v1/repos/suyu/suyu"), ]; - const [res, roles, gitlabRes] = await Promise.all(promises); + const [res, roles, gitlabRes, suyuGitRes] = await Promise.all(promises); const jsonPromises = [res.json(), roles.json(), gitlabRes.json()]; const [resJson, rolesJson, gitResJson] = await Promise.all(jsonPromises); + memberCount = resJson.approximate_member_count; - starCount = gitResJson.stars_count; + gitCommits = parseInt(suyuGitRes?.headers?.get('x-total'), 10) || 0; if (DISCORD_USER_TOKEN) roleMembers = rolesJson; console.log("Member count:", memberCount); - console.log("Stars count:", starCount); + console.log('Git commit count', gitCommits); } if (!building) { @@ -46,5 +48,6 @@ export async function load({ cookies }) { memberCount, starCount, roleMembers, + gitCommits }; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index fbdcb5a..8070ff2 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -8,8 +8,9 @@ export let data: PageData; $: memberCount = parseFloat(data.memberCount?.toPrecision(2)); - $: contributors = parseFloat(data.roleMembers["1214817156420862012"]?.toPrecision(2)); + $: contributors = parseFloat(data.roleMembers?.["1214817156420862012"]?.toPrecision(2)); $: starCount = parseFloat(data.starCount?.toPrecision(2)); + $: gitCommits = parseFloat(data.gitCommits?.toPrecision(2)); let metadata = { url: "https://suyu.dev", title: "suyu - Open-source, non-profit Switch emulator", @@ -70,12 +71,8 @@ and open-source, forever.

@@ -187,8 +183,8 @@ >

Git

- Our Git instance is where all the magic of suyu happens. We're always looking for new contributors - to help us out, so feel free to check out our code. + Our Git instance is where all the magic of suyu happens. We're always looking for new + contributors to help us out, so feel free to check out our code.

(".navbar"); if (navBars.length !== 1) navBars.forEach((bar) => { @@ -52,6 +52,7 @@ const bounds = target.getBoundingClientRect(); const navBounds = navBar.getBoundingClientRect(); const pillBounds = indicator.getBoundingClientRect(); + if (ignoreAnimation) return; indicator.style.transform = `translateX(${bounds.left - navBounds.left}px)`; indicator.style.width = `${bounds.width}px`; if ( @@ -190,7 +191,7 @@ navClick(e, true)} class={`navitem flex flex-grow basis-[0] items-center justify-center whitespace-nowrap rounded-full px-4 py-2 text-sm font-bold ${ selected === i ? " text-[#a9a9a9] opacity-100" : "opacity-50" }`} diff --git a/src/routes/jwt/external/[audience]/+server.ts b/src/routes/jwt/external/[audience]/+server.ts new file mode 100644 index 0000000..9551a48 --- /dev/null +++ b/src/routes/jwt/external/[audience]/+server.ts @@ -0,0 +1,24 @@ +import { PRIVATE_KEY } from "$env/static/private"; +import { userRepo } from "$lib/server/repo/index.js"; +import { getJwtData } from "$lib/server/util/index.js"; +import { useAuth } from "$lib/util/api/index.js"; +import type { IJwtData } from "$types/auth.js"; +import jwt from "jsonwebtoken"; + +export async function POST({ request }) { + const jwtData = await getJwtData(request.headers.get("authorization")?.split(" ")[1] || ""); + const user = await userRepo.findOne({ + where: { + apiKey: jwtData.apiKey, + }, + }); + const token = jwt.sign({ ...user }, Buffer.from(PRIVATE_KEY), { + algorithm: "RS256", + }); + return new Response(token, { + status: 200, + headers: { + "content-type": "text/html", + }, + }); +} diff --git a/src/routes/jwt/external/key.pem/+server.ts b/src/routes/jwt/external/key.pem/+server.ts index ef8c292..a5815f2 100644 --- a/src/routes/jwt/external/key.pem/+server.ts +++ b/src/routes/jwt/external/key.pem/+server.ts @@ -1,45 +1,11 @@ -import { json } from "$lib/server/util/index.js"; +import { PUB_KEY } from "$env/static/private"; export function GET({ request }) { - return new Response( - `-----BEGIN CERTIFICATE----- -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== ------END CERTIFICATE-----`, - { - headers: { - "content-type": "text/plain", - }, + return new Response(PUB_KEY, { + headers: { + "content-type": "text/plain", }, - ); + }); } export function POST({ request }) { diff --git a/src/routes/jwt/internal/+server.ts b/src/routes/jwt/internal/+server.ts index ba144e7..a880dce 100644 --- a/src/routes/jwt/internal/+server.ts +++ b/src/routes/jwt/internal/+server.ts @@ -1,4 +1,4 @@ -import { PRIVATE_KEY } from "$lib/server/secrets/secrets.json"; +import { PRIVATE_KEY } from "$env/static/private"; import { useAuth } from "$lib/util/api/index.js"; import jwt from "jsonwebtoken"; diff --git a/src/routes/lobby/+server.ts b/src/routes/lobby/+server.ts index bb80a7d..650989a 100644 --- a/src/routes/lobby/+server.ts +++ b/src/routes/lobby/+server.ts @@ -1,7 +1,6 @@ import { Room, RoomManager } from "$lib/server/class/Room"; import { userRepo } from "$lib/server/repo/index.js"; import { SuyuUser } from "$lib/server/schema"; -import { PUBLIC_KEY } from "$lib/server/secrets/secrets.json"; import { json } from "$lib/server/util"; import { useAuth } from "$lib/util/api/index.js"; import type { IJwtData } from "$types/auth.js"; @@ -65,12 +64,5 @@ export async function POST({ request, getClientAddress }) { host: user, hasPassword: body.hasPassword || false, }); - console.log("Room added:", JSON.stringify(room, null, 2)); - // push every room to the top which starts with `[SUYU OFFICIAL]` and was created with username "suyu" - const suyuRoom = RoomManager.rooms.find((r) => r.roomInfo.name.startsWith("[SUYU OFFICIAL]")); - if (suyuRoom && suyuRoom.host.username === "suyu") { - RoomManager.rooms.splice(RoomManager.rooms.indexOf(suyuRoom), 1); - RoomManager.rooms.unshift(suyuRoom); - } return json(room.toJSON()); }