DodoTransfer/config.js
2026-11-05 10:28:10 +09:00

153 lines
6.2 KiB
JavaScript

const path = require('path');
const fs = require('fs');
const fsp = require('fs-promise');
// Default Config
// Do not edit this, generate a config.<ENV>.js for your NODE_ENV
// or use ENV-VARS like PSITRANSFER_PORT=8000
const config = {
"uploadDir": path.resolve(__dirname + '/data'),
// admin settings (name, logo, ...) are stored here, default: <uploadDir>/.settings
"settingsDir": '',
// set to serve the app from a sub-path
"baseUrl": '/',
// use to set custom upload url (subfolder to baseUrl)
"uploadAppPath": '/',
"iface": '0.0.0.0',
// set to false to disable HTTP
"port": 3000,
// HTTPS, set all 3 values to enable
"sslPort": 8443,
"sslKeyFile": false,
"sslCertFile": false,
// Force redirect to https
// can be true or a specific url like https://example.com:8443
// keep empty to disable
"forceHttps": '',
// Use trust proxy to show real IP on logs when reverse proxy are used
// see https://expressjs.com/en/guide/behind-proxies.html for options
"trustProxy": '',
// retention options in seconds:label
"retentions": {
"one-time": "one time download",
"3600": "1 Hour",
"21600": "6 Hours",
"86400": "1 Day",
"259200": "3 Days",
"432000": "5 Days",
"604800": "7 Days",
"1209600": "2 Weeks",
"2419200": "4 Weeks",
"4838400": "8 Weeks"
},
// retentions shown as buttons, all others are offered in a list box
"quickRetentions": ['one-time', '86400', '259200', '432000', '604800'],
// admin password, set to false to disable /admin page
// to enable /admin page set your password like this:
// "adminPass": "YourSecurePassword",
"adminPass": false,
// upload password, set to false to disable
"uploadPass": false,
// lifetime of the login token issued after a successful upload login (seconds)
// the token is renewed on every use
"tokenTtl": 60 * 60 * 24 * 7,
// secret to sign login tokens. When empty it is derived from uploadPass and adminPass,
// so changing one of the passwords invalidates all issued tokens
"tokenSecret": '',
// a bucket-password is mandatory, except for one-time downloads
"requireBucketPassword": true,
"defaultRetention": "604800",
// expire every file after maxAge (eg never downloaded one-time files)
"maxAge": 3600 * 24 * 75, // 75 days
// maximum file-size for text previews in byte
"maxPreviewSize": Math.pow(2, 20) * 2, // 2MB
"mailTemplate": 'mailto:?subject=파일 전달&body=다운로드 링크: %%URL%%',
// see https://github.com/expressjs/morgan
// set to false to disable logging
"accessLog": ':date[iso] :method :url :status :response-time :remote-addr',
// event webhooks
// invokes an HTTP POST to a url whenever a file is downloaded
// for more info, see the webhooks section of docs/configuration.md
"fileDownloadedWebhook": null,
"fileUploadedWebhook": null,
// Fallback language
"defaultLanguage": "ko",
// Limit upload size
"maxFileSize": null, // Math.pow(2, 30) * 2, // 2GB
"maxBucketSize": null, // Math.pow(2, 30) * 2, // 10GB
"plugins": ['file-downloaded-webhook', 'file-uploaded-webhook'],
// Disable the QR code button for download url sharing, set to true to disable
"disableQrCode": false,
// Defaults for the branding, each of them can be changed on the admin settings page
"appName": 'Dodo Transfer',
"appOwner": '아진산업(주) 전장선행개발팀',
"appFromYear": 2026,
};
// Load NODE_ENV specific config
const envConfFile = path.resolve(__dirname, `config.${ process.env.NODE_ENV }.js`);
if (process.env.NODE_ENV && fsp.existsSync(envConfFile)) {
Object.assign(config, require(envConfFile));
}
// Load config from ENV VARS
const BOOLEAN_KEYS = ['requireBucketPassword', 'disableQrCode'];
let envName;
for (let k in config) {
envName = 'PSITRANSFER_' + k.replace(/([A-Z])/g, $1 => "_" + $1).toUpperCase();
if (process.env[envName]) {
const raw = process.env[envName];
if (typeof config[k] === 'number') {
config[k] = parseInt(raw, 10);
} else if (BOOLEAN_KEYS.includes(k)) {
// other keys that default to false (passwords, ssl files, ...) take a string
config[k] = ['true', '1', 'yes', 'on'].includes(raw.trim().toLowerCase());
} else if (Array.isArray(config[k])) {
config[k] = raw.split(',').map(s => s.trim()).filter(Boolean);
} else if (config[k] === null) {
// null defaults are numbers (limits) or strings (urls)
try { config[k] = JSON.parse(raw); } catch (e) { config[k] = raw; }
} else if (typeof config[k] === 'object') {
config[k] = JSON.parse(raw);
} else {
config[k] = raw;
}
}
}
if (!config.baseUrl.endsWith('/')) config.baseUrl = config.baseUrl + '/';
if (!config.uploadAppPath.endsWith('/')) config.uploadAppPath = config.uploadAppPath + '/';
config.uploadAppPath = config.baseUrl.substr(0, config.baseUrl.length - 1) + config.uploadAppPath;
config.uploadDir = path.resolve(config.uploadDir);
if (!config.settingsDir) config.settingsDir = path.join(config.uploadDir, '.settings');
// Retention sanity: ignore unknown keys instead of showing broken buttons
config.quickRetentions = config.quickRetentions.filter(key => {
const known = Object.prototype.hasOwnProperty.call(config.retentions, key);
if (!known) console.warn(`config: quickRetentions entry "${ key }" is not in retentions, ignored`);
return known;
});
if (!Object.prototype.hasOwnProperty.call(config.retentions, String(config.defaultRetention))) {
const fallback = Object.keys(config.retentions).find(k => k !== 'one-time');
console.warn(`config: defaultRetention "${ config.defaultRetention }" is not in retentions, using "${ fallback }"`);
config.defaultRetention = fallback;
}
// Load language files: English is the base, every other language overrides it
const langDir = path.resolve(__dirname, 'lang');
const base = require('./lang/en');
config.languages = {};
fs.readdirSync(langDir).forEach(file => {
if (!file.endsWith('.js')) return;
const code = file.replace(/\.js$/, '');
config.languages[code] = code === 'en' ? base : { ...base, ...require(`./lang/${ code }`) };
});
if (!config.languages[config.defaultLanguage]) {
console.warn(`config: defaultLanguage "${ config.defaultLanguage }" not found, using "en"`);
config.defaultLanguage = 'en';
}
module.exports = config;