mirror of
https://github.com/notea-org/notea.git
synced 2024-10-04 10:27:35 +03:00
feat(config): Add yaml configuration support
+ Notea now accepts a CONFIG_FILE environment variable, which supports all the options that the previous environment configuration provided. The equivalent of each option can be found in config/compatibility.yml.
This commit is contained in:
parent
36436c2fee
commit
147473ebdb
26
config/compatibility.yml
Normal file
26
config/compatibility.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Notea Configuration File (Compatibility version)
|
||||||
|
# ------------------------------------------------
|
||||||
|
# NOTE: Environment variables override file configuration values in most cases
|
||||||
|
|
||||||
|
# Authentication configuration
|
||||||
|
auth:
|
||||||
|
# Type of configuration
|
||||||
|
# none: No authentication, anyone can view/edit (same as DISABLE_PASSWORD)
|
||||||
|
# basic: Basic authentication; a password.
|
||||||
|
type: basic
|
||||||
|
# PLANNED: Multiple users and usernames
|
||||||
|
password: 123
|
||||||
|
|
||||||
|
# Store configuration
|
||||||
|
store:
|
||||||
|
# type is unused for now
|
||||||
|
type: s3
|
||||||
|
# endpoint is the same as STORE_END_POINT; must be specified if env doesn't
|
||||||
|
endpoint: http://localhost:9000
|
||||||
|
# accessKey is the same as STORE_ACCESS_KEY; must be specified if env doesn't
|
||||||
|
accessKey: YOUR_ACCESS_KEY
|
||||||
|
# secretKey is the same as STORE_SECRET_KEY; must be specified if env doesn't
|
||||||
|
secretKey: YOUR_SECRET_KEY
|
||||||
|
# forcePathStyle is the same as STORE_FORCE_PATH_STYLE; defaults to false
|
||||||
|
|
||||||
|
baseUrl:
|
98
libs/server/config.ts
Normal file
98
libs/server/config.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import yaml from 'js-yaml';
|
||||||
|
import { getEnv } from "libs/shared/env";
|
||||||
|
import { existsSync, readFileSync } from "fs";
|
||||||
|
|
||||||
|
export type BasicUser = { username: string; password: string };
|
||||||
|
export type BasicAuthConfiguration =
|
||||||
|
{ type: 'basic' }
|
||||||
|
& (Omit<BasicUser, "username"> | BasicUser | { users: BasicUser[] })
|
||||||
|
export type AuthConfiguration = { type: 'none' } | BasicAuthConfiguration;
|
||||||
|
|
||||||
|
export interface S3StoreConfiguration {
|
||||||
|
accessKey: string;
|
||||||
|
secretKey: string;
|
||||||
|
bucket: string;
|
||||||
|
endpoint: string;
|
||||||
|
region: string;
|
||||||
|
forcePathStyle: boolean;
|
||||||
|
prefix: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StoreConfiguration = S3StoreConfiguration;
|
||||||
|
|
||||||
|
export interface Configuration {
|
||||||
|
auth: AuthConfiguration;
|
||||||
|
store: StoreConfiguration;
|
||||||
|
baseUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
let loaded: Configuration | undefined = undefined;
|
||||||
|
|
||||||
|
export function loadConfig() {
|
||||||
|
const configFile = String(getEnv('CONFIG_FILE', './notea.yml'));
|
||||||
|
|
||||||
|
let baseConfig: Configuration = {} as Configuration;
|
||||||
|
if (existsSync(configFile)) {
|
||||||
|
const data = readFileSync(configFile, 'utf-8');
|
||||||
|
baseConfig = yaml.load(data) as Configuration;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const disablePassword = getEnv<boolean>("DISABLE_PASSWORD", undefined);
|
||||||
|
|
||||||
|
let auth: AuthConfiguration;
|
||||||
|
if (disablePassword === undefined || !disablePassword) {
|
||||||
|
const envPassword = getEnv<string>("PASSWORD", undefined, false);
|
||||||
|
if (baseConfig.auth === undefined) {
|
||||||
|
if (envPassword === undefined) {
|
||||||
|
throw new Error("Authentication undefined");
|
||||||
|
} else {
|
||||||
|
auth = {
|
||||||
|
type: 'basic',
|
||||||
|
password: envPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auth = baseConfig.auth;
|
||||||
|
if (envPassword !== undefined) {
|
||||||
|
throw new Error("Cannot specify PASSWORD when auth config section is present")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
auth = { type: 'none' };
|
||||||
|
}
|
||||||
|
|
||||||
|
let store: StoreConfiguration;
|
||||||
|
|
||||||
|
if (!baseConfig.store) {
|
||||||
|
store = {} as StoreConfiguration;
|
||||||
|
} else {
|
||||||
|
store = baseConfig.store;
|
||||||
|
}
|
||||||
|
// for now, this works
|
||||||
|
{
|
||||||
|
store.accessKey = getEnv<string>("STORE_ACCESS_KEY", store.accessKey, !store.accessKey).toString();
|
||||||
|
store.secretKey = getEnv<string>("STORE_SECRET_KEY", store.secretKey, !store.secretKey).toString();
|
||||||
|
store.bucket = getEnv<string>("STORE_BUCKET", store.bucket ?? "notea", false).toString();
|
||||||
|
store.forcePathStyle = getEnv<boolean>("STORE_FORCE_PATH_STYLE", store.forcePathStyle ?? false, !store.forcePathStyle);
|
||||||
|
store.endpoint = getEnv<string>("STORE_END_POINT", store.endpoint, !store.endpoint);
|
||||||
|
store.region = getEnv<string>("STORE_REGION", store.region ?? 'us-east-1', false).toString();
|
||||||
|
store.prefix = getEnv<string>("STORE_PREFIX", store.prefix ?? '', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded = {
|
||||||
|
auth,
|
||||||
|
store,
|
||||||
|
baseUrl: getEnv<string>("BASE_URL")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function config(): Configuration {
|
||||||
|
if (!loaded) {
|
||||||
|
loadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
return loaded as Configuration;
|
||||||
|
}
|
@ -12,6 +12,7 @@ type AllowedEnvs =
|
|||||||
| 'DIRECT_RESPONSE_ATTACHMENT'
|
| 'DIRECT_RESPONSE_ATTACHMENT'
|
||||||
| 'IS_DEMO'
|
| 'IS_DEMO'
|
||||||
| 'STORE_PREFIX'
|
| 'STORE_PREFIX'
|
||||||
|
| 'CONFIG_FILE'
|
||||||
|
|
||||||
export function getEnv<T>(
|
export function getEnv<T>(
|
||||||
env: AllowedEnvs,
|
env: AllowedEnvs,
|
||||||
|
Loading…
Reference in New Issue
Block a user