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:
tecc 2022-08-12 06:24:18 +02:00
parent 36436c2fee
commit 147473ebdb
No known key found for this signature in database
GPG Key ID: 400AAD881FCC028B
3 changed files with 125 additions and 0 deletions

26
config/compatibility.yml Normal file
View 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
View 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;
}

View File

@ -12,6 +12,7 @@ type AllowedEnvs =
| 'DIRECT_RESPONSE_ATTACHMENT'
| 'IS_DEMO'
| 'STORE_PREFIX'
| 'CONFIG_FILE'
export function getEnv<T>(
env: AllowedEnvs,