refactor: centralize envs and their defaults in modules/config (#464)

* feat(config): centralized env variables and their default values

* fix: fip `corsWildcard` variable check in `corsConfig`

* fix(config): use already declared variables and default some strings to undefined

* fix: check processingPriority against NaN
This commit is contained in:
jsopn 2024-04-29 18:56:05 +07:00 committed by GitHub
parent d780192ada
commit 5fbf35a8d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 68 additions and 42 deletions

View file

@ -6,6 +6,7 @@ import express from "express";
import { Bright, Green, Red } from "./modules/sub/consoleText.js"; import { Bright, Green, Red } from "./modules/sub/consoleText.js";
import { getCurrentBranch, shortCommit } from "./modules/sub/currentCommit.js"; import { getCurrentBranch, shortCommit } from "./modules/sub/currentCommit.js";
import { loadLoc } from "./localization/manager.js"; import { loadLoc } from "./localization/manager.js";
import { mode } from "./modules/config.js"
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
@ -22,13 +23,10 @@ app.disable('x-powered-by');
await loadLoc(); await loadLoc();
const apiMode = process.env.API_URL && !process.env.WEB_URL; if (mode === 'API') {
const webMode = process.env.WEB_URL && process.env.API_URL;
if (apiMode) {
const { runAPI } = await import('./core/api.js'); const { runAPI } = await import('./core/api.js');
runAPI(express, app, gitCommit, gitBranch, __dirname) runAPI(express, app, gitCommit, gitBranch, __dirname)
} else if (webMode) { } else if (mode === 'WEB') {
const { runWeb } = await import('./core/web.js'); const { runWeb } = await import('./core/web.js');
await runWeb(express, app, gitCommit, gitBranch, __dirname) await runWeb(express, app, gitCommit, gitBranch, __dirname)
} else { } else {

View file

@ -4,7 +4,7 @@ import { randomBytes } from "crypto";
const ipSalt = randomBytes(64).toString('hex'); const ipSalt = randomBytes(64).toString('hex');
import { version } from "../modules/config.js"; import { env, version } from "../modules/config.js";
import { getJSON } from "../modules/api.js"; import { getJSON } from "../modules/api.js";
import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js"; import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js";
import { Bright, Cyan } from "../modules/sub/consoleText.js"; import { Bright, Cyan } from "../modules/sub/consoleText.js";
@ -14,8 +14,8 @@ import { generateHmac } from "../modules/sub/crypto.js";
import { verifyStream, getInternalStream } from "../modules/stream/manage.js"; import { verifyStream, getInternalStream } from "../modules/stream/manage.js";
export function runAPI(express, app, gitCommit, gitBranch, __dirname) { export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
const corsConfig = process.env.CORS_WILDCARD === '0' ? { const corsConfig = !env.corsWildcard ? {
origin: process.env.CORS_URL, origin: env.corsURL,
optionsSuccessStatus: 200 optionsSuccessStatus: 200
} : {}; } : {};
@ -163,9 +163,9 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
version: version, version: version,
commit: gitCommit, commit: gitCommit,
branch: gitBranch, branch: gitBranch,
name: process.env.API_NAME || "unknown", name: env.apiName,
url: process.env.API_URL, url: env.apiURL,
cors: process.env?.CORS_WILDCARD === "0" ? 0 : 1, cors: Number(env.corsWildcard),
startTime: `${startTimestamp}` startTime: `${startTimestamp}`
}); });
default: default:
@ -194,12 +194,12 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
res.redirect('/api/json') res.redirect('/api/json')
}); });
app.listen(process.env.API_PORT || 9000, () => { app.listen(env.apiPort, () => {
console.log(`\n` + console.log(`\n` +
`${Cyan("cobalt")} API ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` + `${Cyan("cobalt")} API ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` +
`Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` + `Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` +
`URL: ${Cyan(`${process.env.API_URL}`)}\n` + `URL: ${Cyan(`${env.apiURL}`)}\n` +
`Port: ${process.env.API_PORT || 9000}\n` `Port: ${env.apiPort}\n`
) )
}); });
} }

View file

@ -1,4 +1,4 @@
import { genericUserAgent, version } from "../modules/config.js"; import { genericUserAgent, version, env } from "../modules/config.js";
import { apiJSON, languageCode } from "../modules/sub/utils.js"; import { apiJSON, languageCode } from "../modules/sub/utils.js";
import { Bright, Cyan } from "../modules/sub/consoleText.js"; import { Bright, Cyan } from "../modules/sub/consoleText.js";
@ -76,12 +76,12 @@ export async function runWeb(express, app, gitCommit, gitBranch, __dirname) {
return res.redirect('/') return res.redirect('/')
}); });
app.listen(process.env.WEB_PORT || 9001, () => { app.listen(env.webPort, () => {
console.log(`\n` + console.log(`\n` +
`${Cyan("cobalt")} WEB ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` + `${Cyan("cobalt")} WEB ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` +
`Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` + `Start time: ${Bright(`${startTime.toUTCString()} (${startTimestamp})`)}\n\n` +
`URL: ${Cyan(`${process.env.WEB_URL}`)}\n` + `URL: ${Cyan(`${env.webURL}`)}\n` +
`Port: ${process.env.WEB_PORT || 9001}\n` `Port: ${env.webPort}\n`
) )
}) })
} }

View file

@ -12,6 +12,31 @@ Object.values(servicesConfigJson.config).forEach(service => {
) )
}) })
const
apiURL = process.env.API_URL || '',
// WEB mode related environment variables
webEnvs = {
webPort: process.env.WEB_PORT || 9001,
webURL: process.env.WEB_URL || '',
showSponsors: !!process.env.SHOW_SPONSORS,
isBeta: !!process.env.IS_BETA,
plausibleHostname: process.env.PLAUSIBLE_HOSTNAME,
apiURL
},
// API mode related environment variables
apiEnvs = {
apiPort: process.env.API_PORT || 9000,
apiName: process.env.API_NAME || 'unknown',
corsWildcard: process.env.CORS_WILDCARD !== '0',
corsURL: process.env.CORS_URL,
cookiePath: process.env.COOKIE_PATH,
processingPriority: process.env.PROCESSING_PRIORITY && parseInt(process.env.PROCESSING_PRIORITY),
tiktokDeviceInfo: process.env.TIKTOK_DEVICE_INFO && JSON.parse(process.env.TIKTOK_DEVICE_INFO),
apiURL
}
export const export const
services = servicesConfigJson.config, services = servicesConfigJson.config,
audioIgnore = servicesConfigJson.audioIgnore, audioIgnore = servicesConfigJson.audioIgnore,
@ -26,4 +51,7 @@ export const
supportedAudio = config.supportedAudio, supportedAudio = config.supportedAudio,
celebrations = config.celebrations, celebrations = config.celebrations,
links = config.links, links = config.links,
sponsors = config.sponsors sponsors = config.sponsors,
mode = (apiURL && !webEnvs.webURL) ? 'API' :
(webEnvs.webURL && apiURL) ? 'WEB' : undefined,
env = mode === 'API' ? apiEnvs : webEnvs

View file

@ -1,4 +1,4 @@
import { authorInfo, celebrations, sponsors } from "../config.js"; import { authorInfo, celebrations, sponsors, env } from "../config.js";
import emoji from "../emoji.js"; import emoji from "../emoji.js";
import { loadFile } from "../sub/loadFromFs.js"; import { loadFile } from "../sub/loadFromFs.js";
@ -266,5 +266,5 @@ export function sponsoredList() {
} }
export function betaTag() { export function betaTag() {
return process.env.IS_BETA ? '<span class="logo-sub">β</span>' : '' return env.isBeta ? '<span class="logo-sub">β</span>' : ''
} }

View file

@ -1,5 +1,5 @@
import { checkbox, collapsibleList, explanation, footerButtons, multiPagePopup, popup, popupWithBottomButtons, sep, settingsCategory, switcher, socialLink, socialLinks, urgentNotice, keyboardShortcuts, webLoc, sponsoredList, betaTag, linkSVG } from "./elements.js"; import { checkbox, collapsibleList, explanation, footerButtons, multiPagePopup, popup, popupWithBottomButtons, sep, settingsCategory, switcher, socialLink, socialLinks, urgentNotice, keyboardShortcuts, webLoc, sponsoredList, betaTag, linkSVG } from "./elements.js";
import { services as s, authorInfo, version, repo, donations, supportedAudio, links } from "../config.js"; import { services as s, authorInfo, version, repo, donations, supportedAudio, links, env } from "../config.js";
import { getCommitInfo } from "../sub/currentCommit.js"; import { getCommitInfo } from "../sub/currentCommit.js";
import loc from "../../localization/manager.js"; import loc from "../../localization/manager.js";
import emoji from "../emoji.js"; import emoji from "../emoji.js";
@ -48,10 +48,10 @@ export default function(obj) {
<title>${t("AppTitleCobalt")}</title> <title>${t("AppTitleCobalt")}</title>
<meta property="og:url" content="${process.env.WEB_URL}"> <meta property="og:url" content="${env.webURL}">
<meta property="og:title" content="${t("AppTitleCobalt")}"> <meta property="og:title" content="${t("AppTitleCobalt")}">
<meta property="og:description" content="${t('EmbedBriefDescription')}"> <meta property="og:description" content="${t('EmbedBriefDescription')}">
<meta property="og:image" content="${process.env.WEB_URL}icons/generic.png"> <meta property="og:image" content="${env.webURL}icons/generic.png">
<meta name="title" content="${t("AppTitleCobalt")}"> <meta name="title" content="${t("AppTitleCobalt")}">
<meta name="description" content="${t('AboutSummary')}"> <meta name="description" content="${t('AboutSummary')}">
<meta name="theme-color" content="#000000"> <meta name="theme-color" content="#000000">
@ -75,11 +75,11 @@ export default function(obj) {
<link rel="preload" href="assets/meowbalt/error.png" as="image"> <link rel="preload" href="assets/meowbalt/error.png" as="image">
<link rel="preload" href="assets/meowbalt/question.png" as="image"> <link rel="preload" href="assets/meowbalt/question.png" as="image">
${process.env.PLAUSIBLE_HOSTNAME ? ${env.plausibleHostname ?
`<script `<script
defer defer
data-domain="${new URL(process.env.WEB_URL).hostname}" data-domain="${new URL(env.webURL).hostname}"
src="https://${process.env.PLAUSIBLE_HOSTNAME}/js/script.js" src="https://${env.plausibleHostname}/js/script.js"
></script>` ></script>`
: ''} : ''}
</head> </head>
@ -169,7 +169,7 @@ export default function(obj) {
name: "privacy", name: "privacy",
title: `${emoji("🔒")} ${t("CollapsePrivacy")}`, title: `${emoji("🔒")} ${t("CollapsePrivacy")}`,
body: t("PrivacyPolicy") + `${ body: t("PrivacyPolicy") + `${
process.env.PLAUSIBLE_HOSTNAME ? `<br><br>${t("AnalyticsDescription")}` : '' env.plausibleHostname ? `<br><br>${t("AnalyticsDescription")}` : ''
}` }`
}, { }, {
name: "legal", name: "legal",
@ -177,7 +177,7 @@ export default function(obj) {
body: t("FairUse") body: t("FairUse")
}]) }])
}, },
...(process.env.SHOW_SPONSORS ? ...(env.showSponsors ?
[{ [{
text: t("SponsoredBy"), text: t("SponsoredBy"),
classes: ["sponsored-by-text"], classes: ["sponsored-by-text"],
@ -499,7 +499,7 @@ export default function(obj) {
}]) }])
}) })
+ (() => { + (() => {
if (process.env.PLAUSIBLE_HOSTNAME) { if (env.plausibleHostname) {
return settingsCategory({ return settingsCategory({
name: "privacy", name: "privacy",
title: t('PrivateAnalytics'), title: t('PrivateAnalytics'),
@ -629,7 +629,7 @@ export default function(obj) {
</footer> </footer>
</div> </div>
<script> <script>
let defaultApiUrl = '${process.env.API_URL || ''}'; let defaultApiUrl = '${env.apiURL}';
const loc = ${webLoc(t, const loc = ${webLoc(t,
[ [
'ErrorNoInternet', 'ErrorNoInternet',

View file

@ -1,9 +1,10 @@
import Cookie from './cookie.js'; import Cookie from './cookie.js';
import { readFile, writeFile } from 'fs/promises'; import { readFile, writeFile } from 'fs/promises';
import { parse as parseSetCookie, splitCookiesString } from 'set-cookie-parser'; import { parse as parseSetCookie, splitCookiesString } from 'set-cookie-parser';
import { env } from '../../../modules/config.js'
const WRITE_INTERVAL = 60000, const WRITE_INTERVAL = 60000,
cookiePath = process.env.COOKIE_PATH, cookiePath = env.cookiePath,
COUNTER = Symbol('counter'); COUNTER = Symbol('counter');
let cookies = {}, dirty = false, intervalId; let cookies = {}, dirty = false, intervalId;

View file

@ -1,4 +1,4 @@
import { genericUserAgent } from "../../config.js"; import { genericUserAgent, env } from "../../config.js";
const shortDomain = "https://vt.tiktok.com/"; const shortDomain = "https://vt.tiktok.com/";
const apiPath = "https://api22-normal-c-alisg.tiktokv.com/aweme/v1/feed/?region=US&carrier_region=US"; const apiPath = "https://api22-normal-c-alisg.tiktokv.com/aweme/v1/feed/?region=US&carrier_region=US";
@ -7,7 +7,7 @@ const apiUserAgent = "TikTok/338014 CFNetwork/1410.1 Darwin/22.6.0";
export default async function(obj) { export default async function(obj) {
let postId = obj.postId ? obj.postId : false; let postId = obj.postId ? obj.postId : false;
if (!process.env.TIKTOK_DEVICE_INFO) return { error: 'ErrorCouldntFetch' }; if (!env.tiktokDeviceInfo) return { error: 'ErrorCouldntFetch' };
if (!postId) { if (!postId) {
let html = await fetch(`${shortDomain}${obj.id}`, { let html = await fetch(`${shortDomain}${obj.id}`, {
@ -27,8 +27,7 @@ export default async function(obj) {
} }
if (!postId) return { error: 'ErrorCantGetID' }; if (!postId) return { error: 'ErrorCantGetID' };
let deviceInfo = JSON.parse(process.env.TIKTOK_DEVICE_INFO); let deviceInfo = new URLSearchParams(env.tiktokDeviceInfo).toString();
deviceInfo = new URLSearchParams(deviceInfo).toString();
let apiURL = new URL(apiPath); let apiURL = new URL(apiPath);
apiURL.searchParams.append("aweme_id", postId); apiURL.searchParams.append("aweme_id", postId);

View file

@ -3,7 +3,7 @@ import { randomBytes } from "crypto";
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { decryptStream, encryptStream, generateHmac } from "../sub/crypto.js"; import { decryptStream, encryptStream, generateHmac } from "../sub/crypto.js";
import { streamLifespan } from "../config.js"; import { streamLifespan, env } from "../config.js";
import { strict as assert } from "assert"; import { strict as assert } from "assert";
const M3U_SERVICES = ['dailymotion', 'vimeo', 'rutube']; const M3U_SERVICES = ['dailymotion', 'vimeo', 'rutube'];
@ -54,7 +54,7 @@ export function createStream(obj) {
encryptStream(streamData, iv, secret) encryptStream(streamData, iv, secret)
) )
let streamLink = new URL('/api/stream', process.env.API_URL); let streamLink = new URL('/api/stream', env.apiURL);
const params = { const params = {
't': streamID, 't': streamID,
@ -85,7 +85,7 @@ export function createInternalStream(url, obj = {}) {
controller: new AbortController() controller: new AbortController()
}; };
let streamLink = new URL('/api/istream', `http://127.0.0.1:${process.env.API_PORT || 9000}`); let streamLink = new URL('/api/istream', `http://127.0.0.1:${env.apiPort}`);
streamLink.searchParams.set('t', streamID); streamLink.searchParams.set('t', streamID);
return streamLink.toString(); return streamLink.toString();
} }

View file

@ -5,7 +5,7 @@ import { create as contentDisposition } from "content-disposition-header";
import { metadataManager } from "../sub/utils.js"; import { metadataManager } from "../sub/utils.js";
import { destroyInternalStream } from "./manage.js"; import { destroyInternalStream } from "./manage.js";
import { ffmpegArgs } from "../config.js"; import { env, ffmpegArgs } from "../config.js";
import { getHeaders } from "./shared.js"; import { getHeaders } from "./shared.js";
function toRawHeaders(headers) { function toRawHeaders(headers) {
@ -44,8 +44,8 @@ function pipe(from, to, done) {
} }
function getCommand(args) { function getCommand(args) {
if (process.env.PROCESSING_PRIORITY && process.platform !== "win32") { if (!isNaN(env.processingPriority) && process.platform !== "win32") {
return ['nice', ['-n', process.env.PROCESSING_PRIORITY, ffmpeg, ...args]] return ['nice', ['-n', env.processingPriority.toString(), ffmpeg, ...args]]
} }
return [ffmpeg, args] return [ffmpeg, args]
} }