Parse backend environment, expose more settings

This commit is contained in:
2025-03-28 21:53:03 +01:00
parent 9efe20f69f
commit 0c903e1087
3 changed files with 52 additions and 22 deletions

View File

@@ -2,10 +2,11 @@ import cors from "@elysiajs/cors";
import { staticPlugin } from "@elysiajs/static";
import { swagger } from "@elysiajs/swagger";
import { AttachmentId, PieceId, RepertoireId, RequestId, SessionId, Sha256_Bin, Sha256_Hex } from "common";
import { Effect, Option, pipe } from "effect";
import { Effect, Option, pipe, Redacted } from "effect";
import { Elysia, error, t } from "elysia";
import { sql } from "kysely";
import { CLIENT_ID, EXTERNAL_OAUTH_CONFIGURATION, getUser, INTERNAL_OAUTH_CONFIGURATION, makeAuthorizationUrl, REDIRECT_URI, revalidateTokens } from "./auth";
import { EXTERNAL_OAUTH_CONFIGURATION, getUser, INTERNAL_OAUTH_CONFIGURATION, makeAuthorizationUrl, REDIRECT_URI, revalidateTokens } from "./auth";
import { config } from "./config";
import * as Db from "./database";
import * as Model from "./model";
import { DbFromInstance } from "./services/db";
@@ -30,9 +31,9 @@ const app = new Elysia()
},
}))
.use(cors({ origin: process.env.NODE_ENV === "production" ? false : "localhost:5173" }))
.use(cors({ origin: config.NODE_ENV === "production" ? false : "localhost:5173" }))
.decorate("db", await Db.initDatabase(process.env.DB_PATH))
.decorate("db", await Db.initDatabase(config.DB_PATH))
.resolve(async ({ db, cookie }) => {
await db
@@ -201,12 +202,12 @@ const app = new Elysia()
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
"client_id": CLIENT_ID,
"client_id": config.CLIENT_ID,
"code": code,
"redirect_uri": REDIRECT_URI,
"grant_type": "authorization_code",
"code_verifier": codeVerifier.value,
"client_secret": process.env.CLIENT_SECRET!,
"client_secret": Redacted.value(config.CLIENT_SECRET),
}).toString(),
});
@@ -229,7 +230,7 @@ const app = new Elysia()
.execute();
}
return redirect(process.env.NODE_ENV === "production" ? "https://music.renati.me/" : "http://localhost:5173/", 303) as unknown as void;
return redirect(config.NODE_ENV === "production" ? "https://music.renati.me/" : "http://localhost:5173/", 303) as unknown as void;
}, {
response: {
303: t.Void(),
@@ -859,5 +860,5 @@ const app = new Elysia()
// -------------------------------------------------------------------------
app.listen(process.env.PORT || 3000);
app.listen(config.PORT);
export type App = typeof app;

View File

@@ -1,17 +1,13 @@
import { UserId } from "common";
import { DateTime, Duration, Effect, Option, pipe } from "effect";
import { DateTime, Duration, Effect, Option, pipe, Redacted } from "effect";
import { constant } from "effect/Function";
import { config } from "./config";
import * as Model from "./model";
import { Db } from "./services/db";
import { Session } from "./services/session";
export const TENANT_ID = "0817c403-92e4-4648-a9aa-f688ffc5f97a";
export const TENANT_SUBDOMAIN = "chkvoxastra";
export const CLIENT_ID = "e5948f7d-187b-44f9-80cd-63ffda86f9be";
export const OAUTH_SCOPE = "email offline_access openid profile https://graph.microsoft.com/User.Read.All";
export const REDIRECT_URI = process.env.NODE_ENV === "production" ? "https://music.renati.me/api/v1/login" : "http://localhost:3000/api/v1/login";
export const REDIRECT_URI = config.NODE_ENV === "production" ? "https://music.renati.me/api/v1/login" : "http://localhost:3000/api/v1/login";
export const EXPIRATION_BUFFER = Duration.seconds(10);
@@ -21,13 +17,13 @@ export interface OAuthConfiguration {
}
export const INTERNAL_OAUTH_CONFIGURATION: OAuthConfiguration = Object.freeze<OAuthConfiguration>({
authorizationEndpoint: `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/authorize`,
tokenEndpoint: `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,
authorizationEndpoint: `https://login.microsoftonline.com/${config.TENANT_ID}/oauth2/v2.0/authorize`,
tokenEndpoint: `https://login.microsoftonline.com/${config.TENANT_ID}/oauth2/v2.0/token`,
});
export const EXTERNAL_OAUTH_CONFIGURATION: OAuthConfiguration = Object.freeze<OAuthConfiguration>({
authorizationEndpoint: `https://${TENANT_SUBDOMAIN}.ciamlogin.com/${TENANT_ID}/oauth2/v2.0/authorize`,
tokenEndpoint: `https://${TENANT_SUBDOMAIN}.ciamlogin.com/${TENANT_ID}/oauth2/v2.0/token`,
authorizationEndpoint: `https://${config.TENANT_SUBDOMAIN}.ciamlogin.com/${config.TENANT_ID}/oauth2/v2.0/authorize`,
tokenEndpoint: `https://${config.TENANT_SUBDOMAIN}.ciamlogin.com/${config.TENANT_ID}/oauth2/v2.0/token`,
});
export namespace makeAuthorizationUrl {
@@ -60,7 +56,7 @@ export const makeAuthorizationUrl = Effect.fn("makeAuthorizationUrl")(
const { authorizationEndpoint } = external ? EXTERNAL_OAUTH_CONFIGURATION : INTERNAL_OAUTH_CONFIGURATION;
const url = new URL(authorizationEndpoint);
url.searchParams.set("client_id", CLIENT_ID);
url.searchParams.set("client_id", config.CLIENT_ID);
url.searchParams.set("response_type", "code");
url.searchParams.set("redirect_uri", REDIRECT_URI);
url.searchParams.set("scope", OAUTH_SCOPE);
@@ -132,10 +128,10 @@ export const revalidateTokens = Effect.fn("revaildateTokens")(
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
"client_id": CLIENT_ID,
"client_id": config.CLIENT_ID,
"grant_type": "refresh_token",
"refresh_token": refreshTokenValue,
"client_secret": process.env.CLIENT_SECRET!,
"client_secret": Redacted.value(config.CLIENT_SECRET),
}).toString(),
}));

View File

@@ -0,0 +1,33 @@
import { pipe, Schema } from "effect";
import { constant } from "effect/Function";
/* NOTE I know "effect/Config" exists, but I also don't care. This works for me. */
export const Config = Schema.Struct({
CLIENT_ID: Schema.UUID,
CLIENT_SECRET: pipe(
Schema.String,
Schema.Redacted,
),
DB_PATH: pipe(
Schema.String,
Schema.optional,
),
NODE_ENV: pipe(
Schema.Literal("development", "production"),
Schema.optionalWith({ default: constant("development" as const) }),
),
PORT: pipe(
Schema.NumberFromString,
Schema.optionalWith({ default: constant(3000) }),
),
TENANT_ID: Schema.UUID,
TENANT_SUBDOMAIN: Schema.String,
});
export type Config = typeof Config.Type;
export const config = pipe(
process.env,
Schema.decodeUnknownSync(Config),
);