@playcademy/sandbox 0.9.0 → 0.9.1-beta.1
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/dist/cli.js +55 -140
- package/dist/server.js +55 -140
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1128,7 +1128,7 @@ var package_default;
|
|
|
1128
1128
|
var init_package = __esm(() => {
|
|
1129
1129
|
package_default = {
|
|
1130
1130
|
name: "@playcademy/sandbox",
|
|
1131
|
-
version: "0.9.
|
|
1131
|
+
version: "0.9.1-beta.1",
|
|
1132
1132
|
description: "Local development server for Playcademy game development",
|
|
1133
1133
|
type: "module",
|
|
1134
1134
|
exports: {
|
|
@@ -110749,10 +110749,10 @@ function createSandboxAuthProvider() {
|
|
|
110749
110749
|
},
|
|
110750
110750
|
async mintGameToken(gameId, userId) {
|
|
110751
110751
|
const header = btoa(JSON.stringify({ alg: "none", typ: "sandbox" }));
|
|
110752
|
-
const exp = Date.now() + 15 * 60
|
|
110752
|
+
const exp = Math.floor(Date.now() / 1000) + 15 * 60;
|
|
110753
110753
|
const payload = btoa(JSON.stringify({ sub: gameId, uid: userId, exp }));
|
|
110754
110754
|
const token = `${header}.${payload}.sandbox`;
|
|
110755
|
-
return { token, exp };
|
|
110755
|
+
return { token, exp: exp * 1000 };
|
|
110756
110756
|
},
|
|
110757
110757
|
async validateGameToken(token) {
|
|
110758
110758
|
try {
|
|
@@ -110760,18 +110760,9 @@ function createSandboxAuthProvider() {
|
|
|
110760
110760
|
if (parts2.length !== 3) {
|
|
110761
110761
|
return null;
|
|
110762
110762
|
}
|
|
110763
|
-
if (parts2[2] === "sandbox") {
|
|
110764
|
-
const payload2 = JSON.parse(atob(parts2[1]));
|
|
110765
|
-
if (payload2.sub && payload2.uid) {
|
|
110766
|
-
if (payload2.exp && payload2.exp < Date.now()) {
|
|
110767
|
-
log.debug("[SandboxAuthProvider] Token expired");
|
|
110768
|
-
return null;
|
|
110769
|
-
}
|
|
110770
|
-
return payload2;
|
|
110771
|
-
}
|
|
110772
|
-
}
|
|
110773
110763
|
const payload = JSON.parse(atob(parts2[1]));
|
|
110774
|
-
|
|
110764
|
+
const nowSeconds = Date.now() / 1000;
|
|
110765
|
+
if (typeof payload?.sub === "string" && payload.sub.length > 0 && typeof payload.uid === "string" && payload.uid.length > 0 && typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > nowSeconds && payload.exp < nowSeconds + MAX_TOKEN_LIFETIME_SECONDS) {
|
|
110775
110766
|
return payload;
|
|
110776
110767
|
}
|
|
110777
110768
|
return null;
|
|
@@ -110869,7 +110860,7 @@ function createSandboxAuthProvider() {
|
|
|
110869
110860
|
}
|
|
110870
110861
|
};
|
|
110871
110862
|
}
|
|
110872
|
-
var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, sandboxAssessmentTokens;
|
|
110863
|
+
var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, MAX_TOKEN_LIFETIME_SECONDS, sandboxAssessmentTokens;
|
|
110873
110864
|
var init_auth_provider = __esm(async () => {
|
|
110874
110865
|
init_src6();
|
|
110875
110866
|
init_constants();
|
|
@@ -110877,6 +110868,7 @@ var init_auth_provider = __esm(async () => {
|
|
|
110877
110868
|
sandboxApiKeys = new Map;
|
|
110878
110869
|
sandboxAssessmentPreparationReceipts = new Map;
|
|
110879
110870
|
ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS = 5 * 60 * 1000;
|
|
110871
|
+
MAX_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60;
|
|
110880
110872
|
sandboxAssessmentTokens = new TimebackCache({
|
|
110881
110873
|
defaultTTL: 2 * 60 * 60 * 1000,
|
|
110882
110874
|
maxSize: 1000
|
|
@@ -112904,56 +112896,13 @@ function extractBearerToken(authHeader) {
|
|
|
112904
112896
|
}
|
|
112905
112897
|
return authHeader.substring(7);
|
|
112906
112898
|
}
|
|
112907
|
-
function
|
|
112908
|
-
try {
|
|
112909
|
-
const parts2 = token.split(".");
|
|
112910
|
-
if (parts2.length !== 3 || parts2[2] !== "sandbox") {
|
|
112911
|
-
return null;
|
|
112912
|
-
}
|
|
112913
|
-
const header = JSON.parse(atob(parts2[0]));
|
|
112914
|
-
if (header.typ !== "sandbox") {
|
|
112915
|
-
return null;
|
|
112916
|
-
}
|
|
112917
|
-
const payload = JSON.parse(atob(parts2[1]));
|
|
112918
|
-
if (!payload.uid || !payload.sub) {
|
|
112919
|
-
return null;
|
|
112920
|
-
}
|
|
112921
|
-
return {
|
|
112922
|
-
userId: payload.uid,
|
|
112923
|
-
gameSlug: payload.sub
|
|
112924
|
-
};
|
|
112925
|
-
} catch {
|
|
112926
|
-
return null;
|
|
112927
|
-
}
|
|
112928
|
-
}
|
|
112929
|
-
function parseJwtClaims(token) {
|
|
112930
|
-
try {
|
|
112931
|
-
const parts2 = token.split(".");
|
|
112932
|
-
if (parts2.length === 3 && parts2[1]) {
|
|
112933
|
-
const payload = JSON.parse(atob(parts2[1]));
|
|
112934
|
-
if (payload.uid) {
|
|
112935
|
-
return {
|
|
112936
|
-
userId: payload.uid,
|
|
112937
|
-
gameId: payload.sub
|
|
112938
|
-
};
|
|
112939
|
-
}
|
|
112940
|
-
}
|
|
112941
|
-
} catch {}
|
|
112942
|
-
return null;
|
|
112943
|
-
}
|
|
112944
|
-
function resolveAuth(token) {
|
|
112899
|
+
async function resolveAuth(token) {
|
|
112945
112900
|
const demoUser = DEMO_TOKENS[token];
|
|
112946
112901
|
if (demoUser) {
|
|
112947
112902
|
return { userId: demoUser.id };
|
|
112948
112903
|
}
|
|
112949
|
-
|
|
112950
|
-
|
|
112951
|
-
if (sandboxClaims) {
|
|
112952
|
-
return sandboxClaims;
|
|
112953
|
-
}
|
|
112954
|
-
return parseJwtClaims(token);
|
|
112955
|
-
}
|
|
112956
|
-
return null;
|
|
112904
|
+
const payload = await sandboxAuth.validateGameToken(token);
|
|
112905
|
+
return payload ? { userId: payload.uid, gameId: payload.sub } : null;
|
|
112957
112906
|
}
|
|
112958
112907
|
async function fetchUserFromDatabase(db2, userId) {
|
|
112959
112908
|
try {
|
|
@@ -112966,18 +112915,6 @@ async function fetchUserFromDatabase(db2, userId) {
|
|
|
112966
112915
|
throw error88;
|
|
112967
112916
|
}
|
|
112968
112917
|
}
|
|
112969
|
-
async function resolveGameIdFromSlug(db2, slug2) {
|
|
112970
|
-
try {
|
|
112971
|
-
const game2 = await db2.query.games.findFirst({
|
|
112972
|
-
where: eq(games.slug, slug2),
|
|
112973
|
-
columns: { id: true }
|
|
112974
|
-
});
|
|
112975
|
-
return game2?.id || null;
|
|
112976
|
-
} catch (error88) {
|
|
112977
|
-
console.error("[Auth] Error looking up game by slug:", error88);
|
|
112978
|
-
return null;
|
|
112979
|
-
}
|
|
112980
|
-
}
|
|
112981
112918
|
function isPublicRoute(path, exceptions) {
|
|
112982
112919
|
return exceptions.some((exception) => {
|
|
112983
112920
|
if (path === exception) {
|
|
@@ -112995,35 +112932,23 @@ async function authenticateRequest(c) {
|
|
|
112995
112932
|
const apiKey = c.req.header("x-api-key");
|
|
112996
112933
|
const token = bearerToken || apiKey;
|
|
112997
112934
|
if (!token) {
|
|
112998
|
-
return {
|
|
112999
|
-
success: false,
|
|
113000
|
-
error: "No authorization token provided",
|
|
113001
|
-
shouldReturn404: true
|
|
113002
|
-
};
|
|
112935
|
+
return { success: false, error: "No authorization token provided" };
|
|
113003
112936
|
}
|
|
113004
|
-
const resolved = resolveAuth(token);
|
|
112937
|
+
const resolved = await resolveAuth(token);
|
|
113005
112938
|
if (!resolved) {
|
|
113006
|
-
return {
|
|
113007
|
-
success: false,
|
|
113008
|
-
error: "Invalid or expired token",
|
|
113009
|
-
shouldReturn404: true
|
|
113010
|
-
};
|
|
112939
|
+
return { success: false, error: "Invalid or expired token" };
|
|
113011
112940
|
}
|
|
113012
112941
|
const claims = resolved;
|
|
113013
112942
|
const db2 = c.get("db");
|
|
113014
112943
|
if (!db2) {
|
|
113015
112944
|
console.error("[Auth] Database not available in context");
|
|
113016
|
-
return { success: false, error: "Internal server error"
|
|
112945
|
+
return { success: false, error: "Internal server error" };
|
|
113017
112946
|
}
|
|
113018
112947
|
const user = await fetchUserFromDatabase(db2, claims.userId);
|
|
113019
112948
|
if (!user) {
|
|
113020
|
-
return { success: false, error: "User not found or token invalid"
|
|
112949
|
+
return { success: false, error: "User not found or token invalid" };
|
|
113021
112950
|
}
|
|
113022
|
-
|
|
113023
|
-
if (!gameId && claims.gameSlug) {
|
|
113024
|
-
gameId = await resolveGameIdFromSlug(db2, claims.gameSlug) ?? undefined;
|
|
113025
|
-
}
|
|
113026
|
-
return { success: true, user, gameId };
|
|
112951
|
+
return { success: true, user, gameId: claims.gameId };
|
|
113027
112952
|
}
|
|
113028
112953
|
function setupAuth(options = {}) {
|
|
113029
112954
|
const { exceptions = [] } = options;
|
|
@@ -113043,20 +112968,19 @@ function setupAuth(options = {}) {
|
|
|
113043
112968
|
}
|
|
113044
112969
|
c.set("authError", result.error);
|
|
113045
112970
|
await next();
|
|
113046
|
-
if (result.shouldReturn404 && c.res.status === 404) {
|
|
113047
|
-
return;
|
|
113048
|
-
}
|
|
113049
|
-
return c.json({ error: "Unauthorized", message: result.error }, 401);
|
|
113050
112971
|
} catch (error88) {
|
|
113051
112972
|
console.error("[Auth] Unexpected error in authentication middleware:", error88);
|
|
113052
112973
|
return c.json({ error: "Internal Server Error", message: "Authentication failed" }, 500);
|
|
113053
112974
|
}
|
|
113054
112975
|
};
|
|
113055
112976
|
}
|
|
113056
|
-
var
|
|
112977
|
+
var sandboxAuth;
|
|
112978
|
+
var init_auth2 = __esm(async () => {
|
|
113057
112979
|
init_drizzle_orm();
|
|
113058
112980
|
init_tables_index();
|
|
113059
112981
|
init_constants();
|
|
112982
|
+
await init_providers();
|
|
112983
|
+
sandboxAuth = createSandboxAuthProvider();
|
|
113060
112984
|
});
|
|
113061
112985
|
|
|
113062
112986
|
// src/server/app.ts
|
|
@@ -113075,11 +112999,11 @@ function createApp(db2, options) {
|
|
|
113075
112999
|
}));
|
|
113076
113000
|
return app;
|
|
113077
113001
|
}
|
|
113078
|
-
var init_app = __esm(() => {
|
|
113002
|
+
var init_app = __esm(async () => {
|
|
113079
113003
|
init_dist7();
|
|
113080
113004
|
init_cors();
|
|
113081
113005
|
init_logger2();
|
|
113082
|
-
init_auth2();
|
|
113006
|
+
await init_auth2();
|
|
113083
113007
|
});
|
|
113084
113008
|
|
|
113085
113009
|
// ../../node_modules/.bun/@electric-sql+pglite@0.3.16/node_modules/@electric-sql/pglite/dist/chunk-QY3QWFKW.js
|
|
@@ -169208,18 +169132,33 @@ var init_sessions = __esm(async () => {
|
|
|
169208
169132
|
});
|
|
169209
169133
|
|
|
169210
169134
|
// src/routes/platform/games/verify.ts
|
|
169211
|
-
|
|
169135
|
+
function toUserInfo(userData) {
|
|
169136
|
+
return {
|
|
169137
|
+
sub: userData.id,
|
|
169138
|
+
email: userData.email || "",
|
|
169139
|
+
name: userData.name || userData.username || "",
|
|
169140
|
+
email_verified: true,
|
|
169141
|
+
given_name: undefined,
|
|
169142
|
+
family_name: undefined,
|
|
169143
|
+
timeback_id: userData.timebackId || undefined
|
|
169144
|
+
};
|
|
169145
|
+
}
|
|
169146
|
+
var gameVerifyRouter, sandboxAuth2;
|
|
169212
169147
|
var init_verify = __esm(async () => {
|
|
169213
169148
|
init_dist7();
|
|
169214
169149
|
init_errors2();
|
|
169215
169150
|
init_constants();
|
|
169216
169151
|
init_error_handler();
|
|
169217
|
-
await
|
|
169152
|
+
await __promiseAll([
|
|
169153
|
+
init_api3(),
|
|
169154
|
+
init_providers()
|
|
169155
|
+
]);
|
|
169218
169156
|
gameVerifyRouter = new Hono2;
|
|
169157
|
+
sandboxAuth2 = createSandboxAuthProvider();
|
|
169219
169158
|
gameVerifyRouter.post("/verify", async (c2) => {
|
|
169220
169159
|
const body2 = await c2.req.json().catch(() => ({}));
|
|
169221
169160
|
const token = body2?.token;
|
|
169222
|
-
if (!token) {
|
|
169161
|
+
if (typeof token !== "string" || !token) {
|
|
169223
169162
|
return c2.json({ error: "Missing token" }, 400);
|
|
169224
169163
|
}
|
|
169225
169164
|
const demoUser = DEMO_TOKENS[token];
|
|
@@ -169232,49 +169171,25 @@ var init_verify = __esm(async () => {
|
|
|
169232
169171
|
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169233
169172
|
}
|
|
169234
169173
|
return c2.json({
|
|
169235
|
-
claims: { sandbox: true },
|
|
169174
|
+
claims: { sandbox: true, exp: Math.floor(Date.now() / 1000) + 15 * 60 },
|
|
169236
169175
|
gameId: MOCK_GAME_ID,
|
|
169237
|
-
user:
|
|
169238
|
-
sub: userData.id,
|
|
169239
|
-
email: userData.email || "",
|
|
169240
|
-
name: userData.name || userData.username || "",
|
|
169241
|
-
email_verified: true,
|
|
169242
|
-
given_name: undefined,
|
|
169243
|
-
family_name: undefined,
|
|
169244
|
-
timeback_id: userData.timebackId || undefined
|
|
169245
|
-
}
|
|
169176
|
+
user: toUserInfo(userData)
|
|
169246
169177
|
});
|
|
169247
169178
|
}
|
|
169248
169179
|
if (token.endsWith(".sandbox")) {
|
|
169180
|
+
const payload = await sandboxAuth2.validateGameToken(token);
|
|
169181
|
+
if (!payload) {
|
|
169182
|
+
return c2.json({ error: "Invalid or expired sandbox token" }, 400);
|
|
169183
|
+
}
|
|
169249
169184
|
try {
|
|
169250
|
-
const
|
|
169251
|
-
|
|
169252
|
-
|
|
169253
|
-
|
|
169254
|
-
|
|
169255
|
-
|
|
169256
|
-
const userData = await db2.query.users.findFirst({
|
|
169257
|
-
where: (users3, { eq: eq3 }) => eq3(users3.id, userId)
|
|
169258
|
-
});
|
|
169259
|
-
if (!userData) {
|
|
169260
|
-
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169261
|
-
}
|
|
169262
|
-
return c2.json({
|
|
169263
|
-
claims: payload,
|
|
169264
|
-
gameId: gameIdOrSlug,
|
|
169265
|
-
user: {
|
|
169266
|
-
sub: userData.id,
|
|
169267
|
-
email: userData.email || "",
|
|
169268
|
-
name: userData.name || userData.username || "",
|
|
169269
|
-
email_verified: true,
|
|
169270
|
-
given_name: undefined,
|
|
169271
|
-
family_name: undefined,
|
|
169272
|
-
timeback_id: userData.timebackId || undefined
|
|
169273
|
-
}
|
|
169274
|
-
});
|
|
169275
|
-
} else {
|
|
169276
|
-
throw new Error("Malformed sandbox token: expected 3 parts");
|
|
169185
|
+
const db2 = c2.get("db");
|
|
169186
|
+
const userData = await db2.query.users.findFirst({
|
|
169187
|
+
where: (users3, { eq: eq3 }) => eq3(users3.id, payload.uid)
|
|
169188
|
+
});
|
|
169189
|
+
if (!userData) {
|
|
169190
|
+
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169277
169191
|
}
|
|
169192
|
+
return c2.json({ claims: payload, gameId: payload.sub, user: toUserInfo(userData) });
|
|
169278
169193
|
} catch {
|
|
169279
169194
|
return c2.json({ error: "Invalid sandbox token" }, 400);
|
|
169280
169195
|
}
|
|
@@ -169782,13 +169697,13 @@ var init_server = __esm(async () => {
|
|
|
169782
169697
|
init_port();
|
|
169783
169698
|
init_package();
|
|
169784
169699
|
init_config();
|
|
169785
|
-
init_app();
|
|
169786
169700
|
init_database2();
|
|
169787
169701
|
init_options();
|
|
169788
169702
|
await __promiseAll([
|
|
169789
169703
|
init_api3(),
|
|
169790
169704
|
init_context(),
|
|
169791
|
-
init_providers()
|
|
169705
|
+
init_providers(),
|
|
169706
|
+
init_app()
|
|
169792
169707
|
]);
|
|
169793
169708
|
version5 = package_default.version;
|
|
169794
169709
|
});
|
package/dist/server.js
CHANGED
|
@@ -1127,7 +1127,7 @@ var package_default;
|
|
|
1127
1127
|
var init_package = __esm(() => {
|
|
1128
1128
|
package_default = {
|
|
1129
1129
|
name: "@playcademy/sandbox",
|
|
1130
|
-
version: "0.9.
|
|
1130
|
+
version: "0.9.1-beta.1",
|
|
1131
1131
|
description: "Local development server for Playcademy game development",
|
|
1132
1132
|
type: "module",
|
|
1133
1133
|
exports: {
|
|
@@ -110748,10 +110748,10 @@ function createSandboxAuthProvider() {
|
|
|
110748
110748
|
},
|
|
110749
110749
|
async mintGameToken(gameId, userId) {
|
|
110750
110750
|
const header = btoa(JSON.stringify({ alg: "none", typ: "sandbox" }));
|
|
110751
|
-
const exp = Date.now() + 15 * 60
|
|
110751
|
+
const exp = Math.floor(Date.now() / 1000) + 15 * 60;
|
|
110752
110752
|
const payload = btoa(JSON.stringify({ sub: gameId, uid: userId, exp }));
|
|
110753
110753
|
const token = `${header}.${payload}.sandbox`;
|
|
110754
|
-
return { token, exp };
|
|
110754
|
+
return { token, exp: exp * 1000 };
|
|
110755
110755
|
},
|
|
110756
110756
|
async validateGameToken(token) {
|
|
110757
110757
|
try {
|
|
@@ -110759,18 +110759,9 @@ function createSandboxAuthProvider() {
|
|
|
110759
110759
|
if (parts2.length !== 3) {
|
|
110760
110760
|
return null;
|
|
110761
110761
|
}
|
|
110762
|
-
if (parts2[2] === "sandbox") {
|
|
110763
|
-
const payload2 = JSON.parse(atob(parts2[1]));
|
|
110764
|
-
if (payload2.sub && payload2.uid) {
|
|
110765
|
-
if (payload2.exp && payload2.exp < Date.now()) {
|
|
110766
|
-
log.debug("[SandboxAuthProvider] Token expired");
|
|
110767
|
-
return null;
|
|
110768
|
-
}
|
|
110769
|
-
return payload2;
|
|
110770
|
-
}
|
|
110771
|
-
}
|
|
110772
110762
|
const payload = JSON.parse(atob(parts2[1]));
|
|
110773
|
-
|
|
110763
|
+
const nowSeconds = Date.now() / 1000;
|
|
110764
|
+
if (typeof payload?.sub === "string" && payload.sub.length > 0 && typeof payload.uid === "string" && payload.uid.length > 0 && typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > nowSeconds && payload.exp < nowSeconds + MAX_TOKEN_LIFETIME_SECONDS) {
|
|
110774
110765
|
return payload;
|
|
110775
110766
|
}
|
|
110776
110767
|
return null;
|
|
@@ -110868,7 +110859,7 @@ function createSandboxAuthProvider() {
|
|
|
110868
110859
|
}
|
|
110869
110860
|
};
|
|
110870
110861
|
}
|
|
110871
|
-
var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, sandboxAssessmentTokens;
|
|
110862
|
+
var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, MAX_TOKEN_LIFETIME_SECONDS, sandboxAssessmentTokens;
|
|
110872
110863
|
var init_auth_provider = __esm(async () => {
|
|
110873
110864
|
init_src6();
|
|
110874
110865
|
init_constants();
|
|
@@ -110876,6 +110867,7 @@ var init_auth_provider = __esm(async () => {
|
|
|
110876
110867
|
sandboxApiKeys = new Map;
|
|
110877
110868
|
sandboxAssessmentPreparationReceipts = new Map;
|
|
110878
110869
|
ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS = 5 * 60 * 1000;
|
|
110870
|
+
MAX_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60;
|
|
110879
110871
|
sandboxAssessmentTokens = new TimebackCache({
|
|
110880
110872
|
defaultTTL: 2 * 60 * 60 * 1000,
|
|
110881
110873
|
maxSize: 1000
|
|
@@ -112903,56 +112895,13 @@ function extractBearerToken(authHeader) {
|
|
|
112903
112895
|
}
|
|
112904
112896
|
return authHeader.substring(7);
|
|
112905
112897
|
}
|
|
112906
|
-
function
|
|
112907
|
-
try {
|
|
112908
|
-
const parts2 = token.split(".");
|
|
112909
|
-
if (parts2.length !== 3 || parts2[2] !== "sandbox") {
|
|
112910
|
-
return null;
|
|
112911
|
-
}
|
|
112912
|
-
const header = JSON.parse(atob(parts2[0]));
|
|
112913
|
-
if (header.typ !== "sandbox") {
|
|
112914
|
-
return null;
|
|
112915
|
-
}
|
|
112916
|
-
const payload = JSON.parse(atob(parts2[1]));
|
|
112917
|
-
if (!payload.uid || !payload.sub) {
|
|
112918
|
-
return null;
|
|
112919
|
-
}
|
|
112920
|
-
return {
|
|
112921
|
-
userId: payload.uid,
|
|
112922
|
-
gameSlug: payload.sub
|
|
112923
|
-
};
|
|
112924
|
-
} catch {
|
|
112925
|
-
return null;
|
|
112926
|
-
}
|
|
112927
|
-
}
|
|
112928
|
-
function parseJwtClaims(token) {
|
|
112929
|
-
try {
|
|
112930
|
-
const parts2 = token.split(".");
|
|
112931
|
-
if (parts2.length === 3 && parts2[1]) {
|
|
112932
|
-
const payload = JSON.parse(atob(parts2[1]));
|
|
112933
|
-
if (payload.uid) {
|
|
112934
|
-
return {
|
|
112935
|
-
userId: payload.uid,
|
|
112936
|
-
gameId: payload.sub
|
|
112937
|
-
};
|
|
112938
|
-
}
|
|
112939
|
-
}
|
|
112940
|
-
} catch {}
|
|
112941
|
-
return null;
|
|
112942
|
-
}
|
|
112943
|
-
function resolveAuth(token) {
|
|
112898
|
+
async function resolveAuth(token) {
|
|
112944
112899
|
const demoUser = DEMO_TOKENS[token];
|
|
112945
112900
|
if (demoUser) {
|
|
112946
112901
|
return { userId: demoUser.id };
|
|
112947
112902
|
}
|
|
112948
|
-
|
|
112949
|
-
|
|
112950
|
-
if (sandboxClaims) {
|
|
112951
|
-
return sandboxClaims;
|
|
112952
|
-
}
|
|
112953
|
-
return parseJwtClaims(token);
|
|
112954
|
-
}
|
|
112955
|
-
return null;
|
|
112903
|
+
const payload = await sandboxAuth.validateGameToken(token);
|
|
112904
|
+
return payload ? { userId: payload.uid, gameId: payload.sub } : null;
|
|
112956
112905
|
}
|
|
112957
112906
|
async function fetchUserFromDatabase(db2, userId) {
|
|
112958
112907
|
try {
|
|
@@ -112965,18 +112914,6 @@ async function fetchUserFromDatabase(db2, userId) {
|
|
|
112965
112914
|
throw error88;
|
|
112966
112915
|
}
|
|
112967
112916
|
}
|
|
112968
|
-
async function resolveGameIdFromSlug(db2, slug2) {
|
|
112969
|
-
try {
|
|
112970
|
-
const game2 = await db2.query.games.findFirst({
|
|
112971
|
-
where: eq(games.slug, slug2),
|
|
112972
|
-
columns: { id: true }
|
|
112973
|
-
});
|
|
112974
|
-
return game2?.id || null;
|
|
112975
|
-
} catch (error88) {
|
|
112976
|
-
console.error("[Auth] Error looking up game by slug:", error88);
|
|
112977
|
-
return null;
|
|
112978
|
-
}
|
|
112979
|
-
}
|
|
112980
112917
|
function isPublicRoute(path, exceptions) {
|
|
112981
112918
|
return exceptions.some((exception) => {
|
|
112982
112919
|
if (path === exception) {
|
|
@@ -112994,35 +112931,23 @@ async function authenticateRequest(c) {
|
|
|
112994
112931
|
const apiKey = c.req.header("x-api-key");
|
|
112995
112932
|
const token = bearerToken || apiKey;
|
|
112996
112933
|
if (!token) {
|
|
112997
|
-
return {
|
|
112998
|
-
success: false,
|
|
112999
|
-
error: "No authorization token provided",
|
|
113000
|
-
shouldReturn404: true
|
|
113001
|
-
};
|
|
112934
|
+
return { success: false, error: "No authorization token provided" };
|
|
113002
112935
|
}
|
|
113003
|
-
const resolved = resolveAuth(token);
|
|
112936
|
+
const resolved = await resolveAuth(token);
|
|
113004
112937
|
if (!resolved) {
|
|
113005
|
-
return {
|
|
113006
|
-
success: false,
|
|
113007
|
-
error: "Invalid or expired token",
|
|
113008
|
-
shouldReturn404: true
|
|
113009
|
-
};
|
|
112938
|
+
return { success: false, error: "Invalid or expired token" };
|
|
113010
112939
|
}
|
|
113011
112940
|
const claims = resolved;
|
|
113012
112941
|
const db2 = c.get("db");
|
|
113013
112942
|
if (!db2) {
|
|
113014
112943
|
console.error("[Auth] Database not available in context");
|
|
113015
|
-
return { success: false, error: "Internal server error"
|
|
112944
|
+
return { success: false, error: "Internal server error" };
|
|
113016
112945
|
}
|
|
113017
112946
|
const user = await fetchUserFromDatabase(db2, claims.userId);
|
|
113018
112947
|
if (!user) {
|
|
113019
|
-
return { success: false, error: "User not found or token invalid"
|
|
112948
|
+
return { success: false, error: "User not found or token invalid" };
|
|
113020
112949
|
}
|
|
113021
|
-
|
|
113022
|
-
if (!gameId && claims.gameSlug) {
|
|
113023
|
-
gameId = await resolveGameIdFromSlug(db2, claims.gameSlug) ?? undefined;
|
|
113024
|
-
}
|
|
113025
|
-
return { success: true, user, gameId };
|
|
112950
|
+
return { success: true, user, gameId: claims.gameId };
|
|
113026
112951
|
}
|
|
113027
112952
|
function setupAuth(options = {}) {
|
|
113028
112953
|
const { exceptions = [] } = options;
|
|
@@ -113042,20 +112967,19 @@ function setupAuth(options = {}) {
|
|
|
113042
112967
|
}
|
|
113043
112968
|
c.set("authError", result.error);
|
|
113044
112969
|
await next();
|
|
113045
|
-
if (result.shouldReturn404 && c.res.status === 404) {
|
|
113046
|
-
return;
|
|
113047
|
-
}
|
|
113048
|
-
return c.json({ error: "Unauthorized", message: result.error }, 401);
|
|
113049
112970
|
} catch (error88) {
|
|
113050
112971
|
console.error("[Auth] Unexpected error in authentication middleware:", error88);
|
|
113051
112972
|
return c.json({ error: "Internal Server Error", message: "Authentication failed" }, 500);
|
|
113052
112973
|
}
|
|
113053
112974
|
};
|
|
113054
112975
|
}
|
|
113055
|
-
var
|
|
112976
|
+
var sandboxAuth;
|
|
112977
|
+
var init_auth2 = __esm(async () => {
|
|
113056
112978
|
init_drizzle_orm();
|
|
113057
112979
|
init_tables_index();
|
|
113058
112980
|
init_constants();
|
|
112981
|
+
await init_providers();
|
|
112982
|
+
sandboxAuth = createSandboxAuthProvider();
|
|
113059
112983
|
});
|
|
113060
112984
|
|
|
113061
112985
|
// src/server/app.ts
|
|
@@ -113074,11 +112998,11 @@ function createApp(db2, options) {
|
|
|
113074
112998
|
}));
|
|
113075
112999
|
return app;
|
|
113076
113000
|
}
|
|
113077
|
-
var init_app = __esm(() => {
|
|
113001
|
+
var init_app = __esm(async () => {
|
|
113078
113002
|
init_dist7();
|
|
113079
113003
|
init_cors();
|
|
113080
113004
|
init_logger2();
|
|
113081
|
-
init_auth2();
|
|
113005
|
+
await init_auth2();
|
|
113082
113006
|
});
|
|
113083
113007
|
|
|
113084
113008
|
// ../../node_modules/.bun/@electric-sql+pglite@0.3.16/node_modules/@electric-sql/pglite/dist/chunk-QY3QWFKW.js
|
|
@@ -169207,18 +169131,33 @@ var init_sessions = __esm(async () => {
|
|
|
169207
169131
|
});
|
|
169208
169132
|
|
|
169209
169133
|
// src/routes/platform/games/verify.ts
|
|
169210
|
-
|
|
169134
|
+
function toUserInfo(userData) {
|
|
169135
|
+
return {
|
|
169136
|
+
sub: userData.id,
|
|
169137
|
+
email: userData.email || "",
|
|
169138
|
+
name: userData.name || userData.username || "",
|
|
169139
|
+
email_verified: true,
|
|
169140
|
+
given_name: undefined,
|
|
169141
|
+
family_name: undefined,
|
|
169142
|
+
timeback_id: userData.timebackId || undefined
|
|
169143
|
+
};
|
|
169144
|
+
}
|
|
169145
|
+
var gameVerifyRouter, sandboxAuth2;
|
|
169211
169146
|
var init_verify = __esm(async () => {
|
|
169212
169147
|
init_dist7();
|
|
169213
169148
|
init_errors2();
|
|
169214
169149
|
init_constants();
|
|
169215
169150
|
init_error_handler();
|
|
169216
|
-
await
|
|
169151
|
+
await __promiseAll([
|
|
169152
|
+
init_api3(),
|
|
169153
|
+
init_providers()
|
|
169154
|
+
]);
|
|
169217
169155
|
gameVerifyRouter = new Hono2;
|
|
169156
|
+
sandboxAuth2 = createSandboxAuthProvider();
|
|
169218
169157
|
gameVerifyRouter.post("/verify", async (c2) => {
|
|
169219
169158
|
const body2 = await c2.req.json().catch(() => ({}));
|
|
169220
169159
|
const token = body2?.token;
|
|
169221
|
-
if (!token) {
|
|
169160
|
+
if (typeof token !== "string" || !token) {
|
|
169222
169161
|
return c2.json({ error: "Missing token" }, 400);
|
|
169223
169162
|
}
|
|
169224
169163
|
const demoUser = DEMO_TOKENS[token];
|
|
@@ -169231,49 +169170,25 @@ var init_verify = __esm(async () => {
|
|
|
169231
169170
|
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169232
169171
|
}
|
|
169233
169172
|
return c2.json({
|
|
169234
|
-
claims: { sandbox: true },
|
|
169173
|
+
claims: { sandbox: true, exp: Math.floor(Date.now() / 1000) + 15 * 60 },
|
|
169235
169174
|
gameId: MOCK_GAME_ID,
|
|
169236
|
-
user:
|
|
169237
|
-
sub: userData.id,
|
|
169238
|
-
email: userData.email || "",
|
|
169239
|
-
name: userData.name || userData.username || "",
|
|
169240
|
-
email_verified: true,
|
|
169241
|
-
given_name: undefined,
|
|
169242
|
-
family_name: undefined,
|
|
169243
|
-
timeback_id: userData.timebackId || undefined
|
|
169244
|
-
}
|
|
169175
|
+
user: toUserInfo(userData)
|
|
169245
169176
|
});
|
|
169246
169177
|
}
|
|
169247
169178
|
if (token.endsWith(".sandbox")) {
|
|
169179
|
+
const payload = await sandboxAuth2.validateGameToken(token);
|
|
169180
|
+
if (!payload) {
|
|
169181
|
+
return c2.json({ error: "Invalid or expired sandbox token" }, 400);
|
|
169182
|
+
}
|
|
169248
169183
|
try {
|
|
169249
|
-
const
|
|
169250
|
-
|
|
169251
|
-
|
|
169252
|
-
|
|
169253
|
-
|
|
169254
|
-
|
|
169255
|
-
const userData = await db2.query.users.findFirst({
|
|
169256
|
-
where: (users3, { eq: eq3 }) => eq3(users3.id, userId)
|
|
169257
|
-
});
|
|
169258
|
-
if (!userData) {
|
|
169259
|
-
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169260
|
-
}
|
|
169261
|
-
return c2.json({
|
|
169262
|
-
claims: payload,
|
|
169263
|
-
gameId: gameIdOrSlug,
|
|
169264
|
-
user: {
|
|
169265
|
-
sub: userData.id,
|
|
169266
|
-
email: userData.email || "",
|
|
169267
|
-
name: userData.name || userData.username || "",
|
|
169268
|
-
email_verified: true,
|
|
169269
|
-
given_name: undefined,
|
|
169270
|
-
family_name: undefined,
|
|
169271
|
-
timeback_id: userData.timebackId || undefined
|
|
169272
|
-
}
|
|
169273
|
-
});
|
|
169274
|
-
} else {
|
|
169275
|
-
throw new Error("Malformed sandbox token: expected 3 parts");
|
|
169184
|
+
const db2 = c2.get("db");
|
|
169185
|
+
const userData = await db2.query.users.findFirst({
|
|
169186
|
+
where: (users3, { eq: eq3 }) => eq3(users3.id, payload.uid)
|
|
169187
|
+
});
|
|
169188
|
+
if (!userData) {
|
|
169189
|
+
return c2.json({ error: "User not found in sandbox" }, 500);
|
|
169276
169190
|
}
|
|
169191
|
+
return c2.json({ claims: payload, gameId: payload.sub, user: toUserInfo(userData) });
|
|
169277
169192
|
} catch {
|
|
169278
169193
|
return c2.json({ error: "Invalid sandbox token" }, 400);
|
|
169279
169194
|
}
|
|
@@ -169781,13 +169696,13 @@ var init_server = __esm(async () => {
|
|
|
169781
169696
|
init_port();
|
|
169782
169697
|
init_package();
|
|
169783
169698
|
init_config();
|
|
169784
|
-
init_app();
|
|
169785
169699
|
init_database2();
|
|
169786
169700
|
init_options();
|
|
169787
169701
|
await __promiseAll([
|
|
169788
169702
|
init_api3(),
|
|
169789
169703
|
init_context(),
|
|
169790
|
-
init_providers()
|
|
169704
|
+
init_providers(),
|
|
169705
|
+
init_app()
|
|
169791
169706
|
]);
|
|
169792
169707
|
version5 = package_default.version;
|
|
169793
169708
|
});
|