@access-dlsu/leapify 0.260524.3 → 0.260601.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/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { createTurnstileMiddleware, TURNSTILE_VERIFY_PATH, handleTurnstileVerify } from './chunk-AKCERDGP.js';
1
+ import { createTurnstileMiddleware, TURNSTILE_VERIFY_PATH, handleTurnstileVerify } from './chunk-2JEY6TSO.js';
2
2
  import { __export } from './chunk-PZ5AY32C.js';
3
3
  import { Hono } from 'hono';
4
4
  import { cors } from 'hono/cors';
5
+ import { drizzle } from 'drizzle-orm/d1';
6
+ import { sqliteTable, integer, text, index, uniqueIndex } from 'drizzle-orm/sqlite-core';
7
+ import { sql, relations, eq, and, count, lte } from 'drizzle-orm';
5
8
  import { createMiddleware } from 'hono/factory';
6
9
  import { betterAuth } from 'better-auth';
7
10
  import { drizzleAdapter } from 'better-auth/adapters/drizzle';
8
11
  import { bearer } from 'better-auth/plugins';
9
- import { sql, relations, eq, and, count, lte } from 'drizzle-orm';
10
- import { drizzle } from 'drizzle-orm/d1';
11
- import { sqliteTable, integer, text, index, uniqueIndex } from 'drizzle-orm/sqlite-core';
12
12
  import { zValidator } from '@hono/zod-validator';
13
13
  import { z } from 'zod';
14
14
 
@@ -20,6 +20,8 @@ var LeapifyError = class extends Error {
20
20
  this.code = code;
21
21
  this.name = "LeapifyError";
22
22
  }
23
+ statusCode;
24
+ code;
23
25
  };
24
26
  var unauthorized = (message = "Unauthorized") => new LeapifyError(401, "UNAUTHORIZED", message);
25
27
  var domainRestricted = () => new LeapifyError(
@@ -48,58 +50,6 @@ var errorHandler = (err, c) => {
48
50
  500
49
51
  );
50
52
  };
51
- function createCorsMiddleware(allowedOrigins) {
52
- return async (c, next) => {
53
- const origin = c.req.header("origin");
54
- const dynamicOriginsJson = await c.env.KV.get("config:allowed_origins", "json");
55
- const currentAllowedOrigins = dynamicOriginsJson ?? allowedOrigins;
56
- if (c.req.path.startsWith("/api/uploads/images")) {
57
- c.header("Access-Control-Allow-Origin", "*");
58
- c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
59
- if (c.req.method === "OPTIONS") {
60
- return c.body(null, 204);
61
- }
62
- return next();
63
- }
64
- if (!c.req.path.startsWith("/health") && !c.req.path.startsWith("/api/auth") && !c.req.path.startsWith("/internal") && origin && !currentAllowedOrigins.includes("*") && !currentAllowedOrigins.includes(origin)) {
65
- return c.json(
66
- {
67
- error: {
68
- code: "DOMAIN_RESTRICTED",
69
- message: `Origin ${origin} is not allowed`
70
- }
71
- },
72
- 403
73
- );
74
- }
75
- const honoCors = cors({
76
- origin: currentAllowedOrigins,
77
- allowMethods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
78
- allowHeaders: ["Content-Type", "Authorization"],
79
- exposeHeaders: ["ETag", "Last-Modified", "Cache-Control"],
80
- maxAge: 86400,
81
- credentials: true
82
- });
83
- return honoCors(c, next);
84
- };
85
- }
86
- function createRefererGuard(allowedOrigins) {
87
- const MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
88
- const SKIP_PREFIXES = ["/health", "/internal", "/api/auth", "/.well-known"];
89
- return createMiddleware(async (c, next) => {
90
- if (!MUTATION_METHODS.has(c.req.method)) return next();
91
- if (SKIP_PREFIXES.some((p) => c.req.path.startsWith(p))) return next();
92
- const dynamicOriginsJson = await c.env.KV.get("config:allowed_origins", "json");
93
- const currentAllowedOrigins = dynamicOriginsJson ?? allowedOrigins;
94
- if (currentAllowedOrigins.includes("*")) return next();
95
- const referer = c.req.header("referer") ?? "";
96
- const isAllowed = currentAllowedOrigins.some((origin) => referer.startsWith(origin));
97
- if (!isAllowed) {
98
- throw forbidden("Request origin not permitted");
99
- }
100
- return next();
101
- });
102
- }
103
53
 
104
54
  // src/db/schema/index.ts
105
55
  var schema_exports = {};
@@ -332,8 +282,112 @@ var authVerification = sqliteTable(
332
282
  function createDb(d1) {
333
283
  return drizzle(d1, { schema: schema_exports });
334
284
  }
335
-
336
- // src/auth/auth.ts
285
+ async function getOriginsFromDb(env) {
286
+ try {
287
+ const db = createDb(env.DB);
288
+ const row = await db.query.siteConfig.findFirst({
289
+ where: eq(siteConfig.key, "allowed_origins")
290
+ });
291
+ if (row) return JSON.parse(row.value);
292
+ } catch {
293
+ }
294
+ return null;
295
+ }
296
+ function createCorsMiddleware(allowedOrigins) {
297
+ return async (c, next) => {
298
+ const origin = c.req.header("origin");
299
+ const dynamicOriginsJson = await c.env.KV.get(
300
+ "config:allowed_origins",
301
+ "json"
302
+ );
303
+ let currentAllowedOrigins = dynamicOriginsJson ?? allowedOrigins;
304
+ if (!dynamicOriginsJson) {
305
+ const dbOrigins = await getOriginsFromDb(c.env);
306
+ if (dbOrigins) {
307
+ currentAllowedOrigins = dbOrigins;
308
+ await c.env.KV.put(
309
+ "config:allowed_origins",
310
+ JSON.stringify(dbOrigins),
311
+ { expirationTtl: 86400 }
312
+ );
313
+ }
314
+ }
315
+ if (c.req.path.startsWith("/api/uploads/images")) {
316
+ c.header("Access-Control-Allow-Origin", "*");
317
+ c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
318
+ if (c.req.method === "OPTIONS") {
319
+ return c.body(null, 204);
320
+ }
321
+ return next();
322
+ }
323
+ if (!c.req.path.startsWith("/health") && !c.req.path.startsWith("/api/auth") && !c.req.path.startsWith("/internal") && origin && !currentAllowedOrigins.includes("*") && !currentAllowedOrigins.includes(origin) && origin !== new URL(c.req.url).origin) {
324
+ return c.json(
325
+ {
326
+ error: {
327
+ code: "DOMAIN_RESTRICTED",
328
+ message: `Origin ${origin} is not allowed`
329
+ }
330
+ },
331
+ 403
332
+ );
333
+ }
334
+ const honoCors = cors({
335
+ origin: currentAllowedOrigins,
336
+ allowMethods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
337
+ allowHeaders: ["Content-Type", "Authorization"],
338
+ exposeHeaders: ["ETag", "Last-Modified", "Cache-Control"],
339
+ maxAge: 86400,
340
+ credentials: true
341
+ });
342
+ return honoCors(c, next);
343
+ };
344
+ }
345
+ async function getOriginsFromDb2(env) {
346
+ try {
347
+ const db = createDb(env.DB);
348
+ const row = await db.query.siteConfig.findFirst({
349
+ where: eq(siteConfig.key, "allowed_origins")
350
+ });
351
+ if (row) return JSON.parse(row.value);
352
+ } catch {
353
+ }
354
+ return null;
355
+ }
356
+ function createRefererGuard(allowedOrigins) {
357
+ const MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
358
+ const SKIP_PREFIXES = ["/health", "/internal", "/api/auth", "/.well-known"];
359
+ return createMiddleware(async (c, next) => {
360
+ if (!MUTATION_METHODS.has(c.req.method)) return next();
361
+ if (SKIP_PREFIXES.some((p) => c.req.path.startsWith(p))) return next();
362
+ const dynamicOriginsJson = await c.env.KV.get(
363
+ "config:allowed_origins",
364
+ "json"
365
+ );
366
+ let currentAllowedOrigins = dynamicOriginsJson ?? allowedOrigins;
367
+ if (!dynamicOriginsJson) {
368
+ const dbOrigins = await getOriginsFromDb2(c.env);
369
+ if (dbOrigins) {
370
+ currentAllowedOrigins = dbOrigins;
371
+ await c.env.KV.put(
372
+ "config:allowed_origins",
373
+ JSON.stringify(dbOrigins),
374
+ { expirationTtl: 86400 }
375
+ );
376
+ }
377
+ }
378
+ if (currentAllowedOrigins.includes("*")) return next();
379
+ const referer = c.req.header("referer") ?? "";
380
+ const requestOrigin = new URL(c.req.url).origin;
381
+ if (referer.startsWith(requestOrigin)) return next();
382
+ const isAllowed = currentAllowedOrigins.some(
383
+ (origin) => referer.startsWith(origin)
384
+ );
385
+ if (!isAllowed) {
386
+ throw forbidden("Request origin not permitted");
387
+ }
388
+ return next();
389
+ });
390
+ }
337
391
  var DLSU_DOMAIN = "@dlsu.edu.ph";
338
392
  function createAuth(env) {
339
393
  const db = createDb(env.DB);
@@ -629,7 +683,14 @@ healthRoute.get("/", async (c) => {
629
683
  const env = c.env;
630
684
  const hasSes = Boolean(env.SES_REGION) && Boolean(env.SES_ACCESS_KEY_ID) && Boolean(env.SES_SECRET_ACCESS_KEY);
631
685
  const hasResend = Boolean(env.RESEND_API_KEY);
632
- const hasGForms = Boolean(env.GFORMS_SERVICE_ACCOUNT_JSON);
686
+ let hasGForms = false;
687
+ if (env.GFORMS_SERVICE_ACCOUNT_JSON) {
688
+ try {
689
+ const parsed = JSON.parse(env.GFORMS_SERVICE_ACCOUNT_JSON);
690
+ hasGForms = Boolean(parsed.client_email && parsed.private_key);
691
+ } catch {
692
+ }
693
+ }
633
694
  const probes = [];
634
695
  if (hasSes) {
635
696
  probes.push(
@@ -687,6 +748,7 @@ var CacheService = class {
687
748
  constructor(kv) {
688
749
  this.kv = kv;
689
750
  }
751
+ kv;
690
752
  async get(key) {
691
753
  return this.kv.get(key, "json");
692
754
  }
@@ -732,6 +794,8 @@ var SlotsService = class {
732
794
  this.db = db;
733
795
  this.cache = cache;
734
796
  }
797
+ db;
798
+ cache;
735
799
  kvKey(slug) {
736
800
  return `${SLOT_KV_PREFIX}${slug}`;
737
801
  }
@@ -1346,7 +1410,7 @@ siteConfigRoute.patch("/:key", authMiddleware, adminMiddleware, async (c) => {
1346
1410
  set: { value: JSON.stringify(value), updatedAt: now }
1347
1411
  });
1348
1412
  await c.env.KV.put(`config:${key}`, JSON.stringify(value), {
1349
- expirationTtl: 600
1413
+ expirationTtl: 86400
1350
1414
  });
1351
1415
  return c.json({ data: { key, value } });
1352
1416
  });
@@ -1838,6 +1902,7 @@ var SesError = class extends Error {
1838
1902
  this.status = status;
1839
1903
  this.name = "SesError";
1840
1904
  }
1905
+ status;
1841
1906
  /**
1842
1907
  * True for errors that are permanent (not worth retrying via SES again).
1843
1908
  * 400 BadRequest, 403 Forbidden, 404 NotFound → non-retryable.