mirror of
https://github.com/fosrl/pangolin.git
synced 2025-05-13 05:40:38 +01:00
optionally generate traefik files, set cors in config, and set trust proxy in config
This commit is contained in:
parent
cb87463a69
commit
1aec431c36
13 changed files with 300 additions and 49 deletions
|
@ -27,6 +27,8 @@ COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=builder /app/init ./dist/init
|
COPY --from=builder /app/init ./dist/init
|
||||||
|
|
||||||
COPY config/config.example.yml ./dist/config.example.yml
|
COPY config/config.example.yml ./dist/config.example.yml
|
||||||
|
COPY config/traefik/traefik_config.example.yml ./dist/traefik_config.example.yml
|
||||||
|
COPY config/traefik/dynamic_config.example.yml ./dist/dynamic_config.example.yml
|
||||||
COPY server/db/names.json ./dist/names.json
|
COPY server/db/names.json ./dist/names.json
|
||||||
|
|
||||||
COPY public ./public
|
COPY public ./public
|
||||||
|
|
|
@ -38,6 +38,6 @@ users:
|
||||||
password: Password123!
|
password: Password123!
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
require_email_verification: true
|
require_email_verification: false
|
||||||
disable_signup_without_invite: true
|
disable_signup_without_invite: true
|
||||||
disable_user_create_org: true
|
disable_user_create_org: true
|
||||||
|
|
54
config/traefik/dynamic_config.example.yml
Normal file
54
config/traefik/dynamic_config.example.yml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
redirect-to-https:
|
||||||
|
redirectScheme:
|
||||||
|
scheme: https
|
||||||
|
permanent: true
|
||||||
|
|
||||||
|
routers:
|
||||||
|
# HTTP to HTTPS redirect router
|
||||||
|
main-app-router-redirect:
|
||||||
|
rule: "Host(`{{.DashboardDomain}}`)"
|
||||||
|
service: next-service
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
middlewares:
|
||||||
|
- redirect-to-https
|
||||||
|
|
||||||
|
# Next.js router (handles everything except API and WebSocket paths)
|
||||||
|
next-router:
|
||||||
|
rule: "Host(`{{.DashboardDomain}}`) && !PathPrefix(`/api/v1`)"
|
||||||
|
service: next-service
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
# API router (handles /api/v1 paths)
|
||||||
|
api-router:
|
||||||
|
rule: "Host(`{{.DashboardDomain}}`) && PathPrefix(`/api/v1`)"
|
||||||
|
service: api-service
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
# WebSocket router
|
||||||
|
ws-router:
|
||||||
|
rule: "Host(`{{.DashboardDomain}}`)"
|
||||||
|
service: api-service
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
services:
|
||||||
|
next-service:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://pangolin:3002" # Next.js server
|
||||||
|
|
||||||
|
api-service:
|
||||||
|
loadBalancer:
|
||||||
|
servers:
|
||||||
|
- url: "http://pangolin:3000" # API/WebSocket server
|
41
config/traefik/traefik_config.example.yml
Normal file
41
config/traefik/traefik_config.example.yml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
api:
|
||||||
|
insecure: true
|
||||||
|
dashboard: true
|
||||||
|
|
||||||
|
providers:
|
||||||
|
http:
|
||||||
|
endpoint: "http://pangolin:3001/api/v1/traefik-config"
|
||||||
|
pollInterval: "5s"
|
||||||
|
file:
|
||||||
|
filename: "/etc/traefik/dynamic_config.yml"
|
||||||
|
|
||||||
|
experimental:
|
||||||
|
plugins:
|
||||||
|
badger:
|
||||||
|
moduleName: "github.com/fosrl/badger"
|
||||||
|
version: "v1.0.0-beta.2"
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: "INFO"
|
||||||
|
format: "common"
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
acme:
|
||||||
|
httpChallenge:
|
||||||
|
entryPoint: web
|
||||||
|
email: "{{.LetsEncryptEmail}}"
|
||||||
|
storage: "/letsencrypt/acme.json"
|
||||||
|
caServer: "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: ":80"
|
||||||
|
websecure:
|
||||||
|
address: ":443"
|
||||||
|
http:
|
||||||
|
tls:
|
||||||
|
certResolver: "letsencrypt"
|
||||||
|
|
||||||
|
serversTransport:
|
||||||
|
insecureSkipVerify: true
|
|
@ -13,6 +13,11 @@ server:
|
||||||
session_cookie_name: p_session
|
session_cookie_name: p_session
|
||||||
resource_session_cookie_name: p_resource_session
|
resource_session_cookie_name: p_resource_session
|
||||||
resource_access_token_param: p_token
|
resource_access_token_param: p_token
|
||||||
|
cors:
|
||||||
|
origins: ["https://{{.DashboardDomain}}"]
|
||||||
|
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
||||||
|
headers: ["X-CSRF-Token", "Content-Type"]
|
||||||
|
credentials: false
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
cert_resolver: letsencrypt
|
cert_resolver: letsencrypt
|
||||||
|
|
|
@ -4,21 +4,6 @@ http:
|
||||||
redirectScheme:
|
redirectScheme:
|
||||||
scheme: https
|
scheme: https
|
||||||
permanent: true
|
permanent: true
|
||||||
cors:
|
|
||||||
headers:
|
|
||||||
accessControlAllowMethods:
|
|
||||||
- GET
|
|
||||||
- PUT
|
|
||||||
- POST
|
|
||||||
- DELETE
|
|
||||||
- PATCH
|
|
||||||
accessControlAllowHeaders:
|
|
||||||
- Content-Type
|
|
||||||
- X-CSRF-Token
|
|
||||||
accessControlAllowOriginList:
|
|
||||||
- https://{{.DashboardDomain}}
|
|
||||||
accessControlAllowCredentials: false
|
|
||||||
|
|
||||||
|
|
||||||
routers:
|
routers:
|
||||||
# HTTP to HTTPS redirect router
|
# HTTP to HTTPS redirect router
|
||||||
|
@ -29,7 +14,6 @@ http:
|
||||||
- web
|
- web
|
||||||
middlewares:
|
middlewares:
|
||||||
- redirect-to-https
|
- redirect-to-https
|
||||||
- cors
|
|
||||||
|
|
||||||
# Next.js router (handles everything except API and WebSocket paths)
|
# Next.js router (handles everything except API and WebSocket paths)
|
||||||
next-router:
|
next-router:
|
||||||
|
@ -37,8 +21,6 @@ http:
|
||||||
service: next-service
|
service: next-service
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
middlewares:
|
|
||||||
- cors
|
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
@ -48,8 +30,6 @@ http:
|
||||||
service: api-service
|
service: api-service
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
middlewares:
|
|
||||||
- cors
|
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
@ -59,8 +39,6 @@ http:
|
||||||
service: api-service
|
service: api-service
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
middlewares:
|
|
||||||
- cors
|
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
|
|
||||||
|
@ -68,9 +46,9 @@ http:
|
||||||
next-service:
|
next-service:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
servers:
|
servers:
|
||||||
- url: "http://pangolin:3002" # Next.js server
|
- url: "http://pangolin:{{.NEXT_PORT}}" # Next.js server
|
||||||
|
|
||||||
api-service:
|
api-service:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
servers:
|
servers:
|
||||||
- url: "http://pangolin:3000" # API/WebSocket server
|
- url: "http://pangolin:{{.EXTERNAL_PORT}}" # API/WebSocket server
|
||||||
|
|
|
@ -4,7 +4,7 @@ api:
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
http:
|
http:
|
||||||
endpoint: "http://pangolin:3001/api/v1/traefik-config"
|
endpoint: "http://pangolin:{{.INTERNAL_PORT}}/api/v1/traefik-config"
|
||||||
pollInterval: "5s"
|
pollInterval: "5s"
|
||||||
file:
|
file:
|
||||||
filename: "/etc/traefik/dynamic_config.yml"
|
filename: "/etc/traefik/dynamic_config.yml"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@fosrl/pangolin",
|
"name": "@fosrl/pangolin",
|
||||||
"version": "1.0.0-beta.5",
|
"version": "1.0.0-beta.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Tunneled Reverse Proxy Management Server with Identity and Access Control and Dashboard UI",
|
"description": "Tunneled Reverse Proxy Management Server with Identity and Access Control and Dashboard UI",
|
||||||
|
|
|
@ -20,7 +20,9 @@ const externalPort = config.getRawConfig().server.external_port;
|
||||||
export function createApiServer() {
|
export function createApiServer() {
|
||||||
const apiServer = express();
|
const apiServer = express();
|
||||||
|
|
||||||
apiServer.set("trust proxy", 1);
|
if (config.getRawConfig().server.trust_proxy) {
|
||||||
|
apiServer.set("trust proxy", 1);
|
||||||
|
}
|
||||||
|
|
||||||
const corsConfig = config.getRawConfig().server.cors;
|
const corsConfig = config.getRawConfig().server.cors;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
} from "@server/lib/consts";
|
} from "@server/lib/consts";
|
||||||
import { loadAppVersion } from "@server/lib/loadAppVersion";
|
import { loadAppVersion } from "@server/lib/loadAppVersion";
|
||||||
import { passwordSchema } from "@server/auth/passwordSchema";
|
import { passwordSchema } from "@server/auth/passwordSchema";
|
||||||
|
import stoi from "./stoi";
|
||||||
|
|
||||||
const portSchema = z.number().positive().gt(0).lte(65535);
|
const portSchema = z.number().positive().gt(0).lte(65535);
|
||||||
const hostnameSchema = z
|
const hostnameSchema = z
|
||||||
|
@ -20,31 +21,56 @@ const hostnameSchema = z
|
||||||
)
|
)
|
||||||
.or(z.literal("localhost"));
|
.or(z.literal("localhost"));
|
||||||
|
|
||||||
const environmentSchema = z.object({
|
const getEnvOrYaml = (envVar: string) => (valFromYaml: any) => {
|
||||||
|
return process.env[envVar] ?? valFromYaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
const configSchema = z.object({
|
||||||
app: z.object({
|
app: z.object({
|
||||||
dashboard_url: z
|
dashboard_url: z
|
||||||
.string()
|
.string()
|
||||||
.url()
|
.url()
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("APP_DASHBOARDURL"))
|
||||||
|
.pipe(z.string().url())
|
||||||
.transform((url) => url.toLowerCase()),
|
.transform((url) => url.toLowerCase()),
|
||||||
base_domain: hostnameSchema,
|
base_domain: hostnameSchema
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("APP_BASEDOMAIN"))
|
||||||
|
.pipe(hostnameSchema),
|
||||||
log_level: z.enum(["debug", "info", "warn", "error"]),
|
log_level: z.enum(["debug", "info", "warn", "error"]),
|
||||||
save_logs: z.boolean()
|
save_logs: z.boolean()
|
||||||
}),
|
}),
|
||||||
server: z.object({
|
server: z.object({
|
||||||
external_port: portSchema,
|
external_port: portSchema
|
||||||
internal_port: portSchema,
|
.optional()
|
||||||
next_port: portSchema,
|
.transform(getEnvOrYaml("SERVER_EXTERNALPORT"))
|
||||||
|
.transform(stoi)
|
||||||
|
.pipe(portSchema),
|
||||||
|
internal_port: portSchema
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("SERVER_INTERNALPORT"))
|
||||||
|
.transform(stoi)
|
||||||
|
.pipe(portSchema),
|
||||||
|
next_port: portSchema
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("SERVER_NEXTPORT"))
|
||||||
|
.transform(stoi)
|
||||||
|
.pipe(portSchema),
|
||||||
internal_hostname: z.string().transform((url) => url.toLowerCase()),
|
internal_hostname: z.string().transform((url) => url.toLowerCase()),
|
||||||
secure_cookies: z.boolean(),
|
secure_cookies: z.boolean(),
|
||||||
session_cookie_name: z.string(),
|
session_cookie_name: z.string(),
|
||||||
resource_session_cookie_name: z.string(),
|
resource_session_cookie_name: z.string(),
|
||||||
resource_access_token_param: z.string(),
|
resource_access_token_param: z.string(),
|
||||||
cors: z.object({
|
cors: z
|
||||||
origins: z.array(z.string()).optional(),
|
.object({
|
||||||
methods: z.array(z.string()).optional(),
|
origins: z.array(z.string()).optional(),
|
||||||
allowed_headers: z.array(z.string()).optional(),
|
methods: z.array(z.string()).optional(),
|
||||||
credentials: z.boolean().optional(),
|
allowed_headers: z.array(z.string()).optional(),
|
||||||
}).optional()
|
credentials: z.boolean().optional()
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
trust_proxy: z.boolean().optional().default(true)
|
||||||
}),
|
}),
|
||||||
traefik: z.object({
|
traefik: z.object({
|
||||||
http_entrypoint: z.string(),
|
http_entrypoint: z.string(),
|
||||||
|
@ -53,8 +79,17 @@ const environmentSchema = z.object({
|
||||||
prefer_wildcard_cert: z.boolean().optional()
|
prefer_wildcard_cert: z.boolean().optional()
|
||||||
}),
|
}),
|
||||||
gerbil: z.object({
|
gerbil: z.object({
|
||||||
start_port: portSchema,
|
start_port: portSchema
|
||||||
base_endpoint: z.string().transform((url) => url.toLowerCase()),
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("GERBIL_STARTPORT"))
|
||||||
|
.transform(stoi)
|
||||||
|
.pipe(portSchema),
|
||||||
|
base_endpoint: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("GERBIL_BASEENDPOINT"))
|
||||||
|
.pipe(z.string())
|
||||||
|
.transform((url) => url.toLowerCase()),
|
||||||
use_subdomain: z.boolean(),
|
use_subdomain: z.boolean(),
|
||||||
subnet_group: z.string(),
|
subnet_group: z.string(),
|
||||||
block_size: z.number().positive().gt(0),
|
block_size: z.number().positive().gt(0),
|
||||||
|
@ -83,8 +118,16 @@ const environmentSchema = z.object({
|
||||||
.optional(),
|
.optional(),
|
||||||
users: z.object({
|
users: z.object({
|
||||||
server_admin: z.object({
|
server_admin: z.object({
|
||||||
email: z.string().email(),
|
email: z
|
||||||
|
.string()
|
||||||
|
.email()
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("USERS_SERVERADMIN_EMAIL"))
|
||||||
|
.pipe(z.string().email()),
|
||||||
password: passwordSchema
|
password: passwordSchema
|
||||||
|
.optional()
|
||||||
|
.transform(getEnvOrYaml("USERS_SERVERADMIN_PASSWORD"))
|
||||||
|
.pipe(passwordSchema)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
flags: z
|
flags: z
|
||||||
|
@ -97,12 +140,18 @@ const environmentSchema = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
export class Config {
|
export class Config {
|
||||||
private rawConfig!: z.infer<typeof environmentSchema>;
|
private rawConfig!: z.infer<typeof configSchema>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.loadConfig();
|
this.loadConfig();
|
||||||
|
|
||||||
|
if (process.env.GENERATE_TRAEFIK_CONFIG === "true") {
|
||||||
|
this.createTraefikConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public loadEnvironment() {}
|
||||||
|
|
||||||
public loadConfig() {
|
public loadConfig() {
|
||||||
const loadConfig = (configPath: string) => {
|
const loadConfig = (configPath: string) => {
|
||||||
try {
|
try {
|
||||||
|
@ -166,7 +215,7 @@ export class Config {
|
||||||
throw new Error("No configuration file found");
|
throw new Error("No configuration file found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedConfig = environmentSchema.safeParse(environment);
|
const parsedConfig = configSchema.safeParse(environment);
|
||||||
|
|
||||||
if (!parsedConfig.success) {
|
if (!parsedConfig.success) {
|
||||||
const errors = fromError(parsedConfig.error);
|
const errors = fromError(parsedConfig.error);
|
||||||
|
@ -214,6 +263,72 @@ export class Config {
|
||||||
public getBaseDomain(): string {
|
public getBaseDomain(): string {
|
||||||
return this.rawConfig.app.base_domain;
|
return this.rawConfig.app.base_domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createTraefikConfig() {
|
||||||
|
try {
|
||||||
|
// check if traefik_config.yml and dynamic_config.yml exists in APP_PATH/traefik
|
||||||
|
const defaultTraefikConfigPath = path.join(
|
||||||
|
__DIRNAME,
|
||||||
|
"traefik_config.example.yml"
|
||||||
|
);
|
||||||
|
const defaultDynamicConfigPath = path.join(
|
||||||
|
__DIRNAME,
|
||||||
|
"dynamic_config.example.yml"
|
||||||
|
);
|
||||||
|
|
||||||
|
const traefikPath = path.join(APP_PATH, "traefik");
|
||||||
|
if (!fs.existsSync(traefikPath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load default configs
|
||||||
|
let traefikConfig = fs.readFileSync(
|
||||||
|
defaultTraefikConfigPath,
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
let dynamicConfig = fs.readFileSync(
|
||||||
|
defaultDynamicConfigPath,
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
traefikConfig = traefikConfig
|
||||||
|
.split("{{.LetsEncryptEmail}}")
|
||||||
|
.join(this.rawConfig.users.server_admin.email);
|
||||||
|
traefikConfig = traefikConfig
|
||||||
|
.split("{{.INTERNAL_PORT}}")
|
||||||
|
.join(this.rawConfig.server.internal_port.toString());
|
||||||
|
|
||||||
|
dynamicConfig = dynamicConfig
|
||||||
|
.split("{{.DashboardDomain}}")
|
||||||
|
.join(new URL(this.rawConfig.app.dashboard_url).hostname);
|
||||||
|
dynamicConfig = dynamicConfig
|
||||||
|
.split("{{.NEXT_PORT}}")
|
||||||
|
.join(this.rawConfig.server.next_port.toString());
|
||||||
|
dynamicConfig = dynamicConfig
|
||||||
|
.split("{{.EXTERNAL_PORT}}")
|
||||||
|
.join(this.rawConfig.server.external_port.toString());
|
||||||
|
|
||||||
|
// write thiese to the traefik directory
|
||||||
|
const traefikConfigPath = path.join(
|
||||||
|
traefikPath,
|
||||||
|
"traefik_config.yml"
|
||||||
|
);
|
||||||
|
const dynamicConfigPath = path.join(
|
||||||
|
traefikPath,
|
||||||
|
"dynamic_config.yml"
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.writeFileSync(traefikConfigPath, traefikConfig, "utf8");
|
||||||
|
fs.writeFileSync(dynamicConfigPath, dynamicConfig, "utf8");
|
||||||
|
|
||||||
|
console.log("Traefik configuration files created");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(
|
||||||
|
"Failed to generate the Traefik configuration files. Please create them manually."
|
||||||
|
);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const config = new Config();
|
export const config = new Config();
|
||||||
|
|
|
@ -10,6 +10,7 @@ import m1 from "./scripts/1.0.0-beta1";
|
||||||
import m2 from "./scripts/1.0.0-beta2";
|
import m2 from "./scripts/1.0.0-beta2";
|
||||||
import m3 from "./scripts/1.0.0-beta3";
|
import m3 from "./scripts/1.0.0-beta3";
|
||||||
import m4 from "./scripts/1.0.0-beta5";
|
import m4 from "./scripts/1.0.0-beta5";
|
||||||
|
import m5 from "./scripts/1.0.0-beta6";
|
||||||
import { existsSync, mkdirSync } from "fs";
|
import { existsSync, mkdirSync } from "fs";
|
||||||
|
|
||||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||||
|
@ -20,7 +21,8 @@ const migrations = [
|
||||||
{ version: "1.0.0-beta.1", run: m1 },
|
{ version: "1.0.0-beta.1", run: m1 },
|
||||||
{ version: "1.0.0-beta.2", run: m2 },
|
{ version: "1.0.0-beta.2", run: m2 },
|
||||||
{ version: "1.0.0-beta.3", run: m3 },
|
{ version: "1.0.0-beta.3", run: m3 },
|
||||||
{ version: "1.0.0-beta.5", run: m4 }
|
{ version: "1.0.0-beta.5", run: m4 },
|
||||||
|
{ version: "1.0.0-beta.6", run: m5 }
|
||||||
// Add new migrations here as they are created
|
// Add new migrations here as they are created
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|
52
server/setup/scripts/1.0.0-beta6.ts
Normal file
52
server/setup/scripts/1.0.0-beta6.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||||
|
import fs from "fs";
|
||||||
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
|
export default async function migration() {
|
||||||
|
console.log("Running setup script 1.0.0-beta.6...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Determine which config file exists
|
||||||
|
const filePaths = [configFilePath1, configFilePath2];
|
||||||
|
let filePath = "";
|
||||||
|
for (const path of filePaths) {
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
filePath = path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
throw new Error(
|
||||||
|
`No config file found (expected config.yml or config.yaml).`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and parse the YAML file
|
||||||
|
let rawConfig: any;
|
||||||
|
const fileContents = fs.readFileSync(filePath, "utf8");
|
||||||
|
rawConfig = yaml.load(fileContents);
|
||||||
|
|
||||||
|
// Validate the structure
|
||||||
|
if (!rawConfig.server) {
|
||||||
|
throw new Error(`Invalid config file: server is missing.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the config
|
||||||
|
rawConfig.server.cors = {
|
||||||
|
origins: [rawConfig.app.dashboard_url],
|
||||||
|
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
|
||||||
|
headers: ["X-CSRF-Token", "Content-Type"],
|
||||||
|
credentials: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the updated YAML back to the file
|
||||||
|
const updatedYaml = yaml.dump(rawConfig);
|
||||||
|
fs.writeFileSync(filePath, updatedYaml, "utf8");
|
||||||
|
} catch (error) {
|
||||||
|
console.log("We were unable to add CORS to your config file. Please add it manually.")
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Done.");
|
||||||
|
}
|
|
@ -235,10 +235,10 @@ PersistentKeepalive = 5`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
// am I at http or https?
|
// am I at http or https?
|
||||||
let proto = "http:";
|
let proto = "https:";
|
||||||
if (typeof window !== "undefined") {
|
// if (typeof window !== "undefined") {
|
||||||
proto = window.location.protocol;
|
// proto = window.location.protocol;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const newtConfig = `newt --id ${siteDefaults?.newtId} --secret ${siteDefaults?.newtSecret} --endpoint ${proto}//${siteDefaults?.endpoint}`;
|
const newtConfig = `newt --id ${siteDefaults?.newtId} --secret ${siteDefaults?.newtSecret} --endpoint ${proto}//${siteDefaults?.endpoint}`;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue