diff --git a/config/traefik/traefik_config.example.yml b/config/traefik/traefik_config.example.yml index 01d05903..b822f493 100644 --- a/config/traefik/traefik_config.example.yml +++ b/config/traefik/traefik_config.example.yml @@ -4,7 +4,13 @@ api: providers: http: - endpoint: "http://pangolin:{{.INTERNAL_PORT}}/api/v1/traefik-config" + endpoint: "http://pangolin:3001/api/v1/traefik-config/http" + pollInterval: "5s" + udp: + endpoint: "http://pangolin:3001/api/v1/traefik-config/udp" + pollInterval: "5s" + tcp: + endpoint: "http://pangolin:3001/api/v1/traefik-config/tcp" pollInterval: "5s" file: filename: "/etc/traefik/dynamic_config.yml" diff --git a/install/fs/traefik/traefik_config.yml b/install/fs/traefik/traefik_config.yml index 4a68fdd5..b822f493 100644 --- a/install/fs/traefik/traefik_config.yml +++ b/install/fs/traefik/traefik_config.yml @@ -19,7 +19,7 @@ experimental: plugins: badger: moduleName: "github.com/fosrl/badger" - version: "v1.0.0-beta.2" + version: "v1.0.0-beta.3" log: level: "INFO" diff --git a/server/setup/migrations.ts b/server/setup/migrations.ts index 6d2766ee..7d1d7da4 100644 --- a/server/setup/migrations.ts +++ b/server/setup/migrations.ts @@ -31,31 +31,36 @@ const migrations = [ await runMigrations(); export async function runMigrations() { - const appVersion = loadAppVersion(); - if (!appVersion) { - throw new Error("APP_VERSION is not set in the environment"); - } - - if (exists) { - await executeScripts(); - } else { - console.log("Running migrations..."); - try { - migrate(db, { - migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build - }); - console.log("Migrations completed successfully."); - } catch (error) { - console.error("Error running migrations:", error); + try { + const appVersion = loadAppVersion(); + if (!appVersion) { + throw new Error("APP_VERSION is not set in the environment"); } - await db + if (exists) { + await executeScripts(); + } else { + console.log("Running migrations..."); + try { + migrate(db, { + migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build + }); + console.log("Migrations completed successfully."); + } catch (error) { + console.error("Error running migrations:", error); + } + + await db .insert(versionMigrations) .values({ version: appVersion, executedAt: Date.now() }) .execute(); + } + } catch (e) { + console.error("Error running migrations:", e); + await new Promise((resolve) => setTimeout(resolve, 1000 * 60 * 60 * 24 * 1)); } } diff --git a/server/setup/scripts/1.0.0-beta9.ts b/server/setup/scripts/1.0.0-beta9.ts index 32fd8e37..c883bd60 100644 --- a/server/setup/scripts/1.0.0-beta9.ts +++ b/server/setup/scripts/1.0.0-beta9.ts @@ -20,6 +20,25 @@ import { fromZodError } from "zod-validation-error"; export default async function migration() { console.log("Running setup script 1.0.0-beta.9..."); + // make dir config/db/backups + const appPath = APP_PATH; + const dbDir = path.join(appPath, "db"); + + const backupsDir = path.join(dbDir, "backups"); + + // check if the backups directory exists and create it if it doesn't + if (!fs.existsSync(backupsDir)) { + fs.mkdirSync(backupsDir, { recursive: true }); + } + + // copy the db.sqlite file to backups + // add the date to the filename + const date = new Date(); + const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}_${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}`; + const dbPath = path.join(dbDir, "db.sqlite"); + const backupPath = path.join(backupsDir, `db_${dateString}.sqlite`); + fs.copyFileSync(dbPath, backupPath); + await db.transaction(async (trx) => { try { // Determine which config file exists @@ -48,6 +67,12 @@ export default async function migration() { rawConfig.server.session_cookie_name = "p_session_token"; // rename to prevent conflicts delete rawConfig.server.resource_session_cookie_name; + if (!rawConfig.flags) { + rawConfig.flags = {}; + } + + rawConfig.flags.allow_raw_resources = true; + // Write the updated YAML back to the file const updatedYaml = yaml.dump(rawConfig); fs.writeFileSync(filePath, updatedYaml, "utf8"); @@ -97,7 +122,7 @@ export default async function migration() { const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); const traefikConfig = yaml.load(traefikFileContents) as any; - const parsedConfig = schema.safeParse(traefikConfig); + let parsedConfig: any = schema.safeParse(traefikConfig); if (parsedConfig.success) { // Ensure websecure entrypoint exists @@ -116,9 +141,7 @@ export default async function migration() { const updatedTraefikYaml = yaml.dump(traefikConfig); fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); - console.log( - "Updated the version of Badger in your Traefik configuration to v1.0.0-beta.3 and added readTimeout to websecure entrypoint in your Traefik configuration.." - ); + console.log("Updated Badger version in Traefik config."); } else { console.log(fromZodError(parsedConfig.error)); console.log( @@ -133,6 +156,51 @@ export default async function migration() { return; } + try { + const traefikPath = path.join( + APP_PATH, + "traefik", + "dynamic_config.yml" + ); + + const schema = z.object({ + http: z.object({ + middlewares: z.object({ + "redirect-to-https": z.object({ + redirectScheme: z.object({ + scheme: z.string(), + permanent: z.boolean() + }) + }) + }) + }) + }); + + const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); + const traefikConfig = yaml.load(traefikFileContents) as any; + + let parsedConfig: any = schema.safeParse(traefikConfig); + + if (parsedConfig.success) { + // delete permanent from redirect-to-https middleware + delete traefikConfig.http.middlewares["redirect-to-https"].redirectScheme.permanent; + + const updatedTraefikYaml = yaml.dump(traefikConfig); + fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); + + console.log("Deleted permanent from redirect-to-https middleware."); + } else { + console.log(fromZodError(parsedConfig.error)); + console.log( + "We were unable to delete the permanent field from the redirect-to-https middleware in your Traefik configuration. Please delete it manually." + ); + } + } catch (e) { + console.log( + "We were unable to delete the permanent field from the redirect-to-https middleware in your Traefik configuration. Please delete it manually. Note that this is not a critical change but recommended." + ); + } + trx.run(sql`UPDATE ${users} SET email = LOWER(email);`); trx.run( sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);` diff --git a/src/app/[orgId]/settings/resources/CreateResourceForm.tsx b/src/app/[orgId]/settings/resources/CreateResourceForm.tsx index d92a3792..33f5bdfc 100644 --- a/src/app/[orgId]/settings/resources/CreateResourceForm.tsx +++ b/src/app/[orgId]/settings/resources/CreateResourceForm.tsx @@ -162,7 +162,8 @@ export default function CreateResourceForm({ subdomain: data.http ? data.subdomain : undefined, http: data.http, protocol: data.protocol, - proxyPort: data.http ? undefined : data.proxyPort + proxyPort: data.http ? undefined : data.proxyPort, + siteId: data.siteId } ) .catch((e) => { diff --git a/src/app/[orgId]/settings/share-links/CreateShareLinkForm.tsx b/src/app/[orgId]/settings/share-links/CreateShareLinkForm.tsx index 854dfab6..0c36c57e 100644 --- a/src/app/[orgId]/settings/share-links/CreateShareLinkForm.tsx +++ b/src/app/[orgId]/settings/share-links/CreateShareLinkForm.tsx @@ -153,7 +153,9 @@ export default function CreateShareLinkForm({ if (res?.status === 200) { setResources( - res.data.data.resources.map((r) => ({ + res.data.data.resources.filter((r) => { + return r.http; + }).map((r) => ({ resourceId: r.resourceId, name: r.name, resourceUrl: `${r.ssl ? "https://" : "http://"}${r.fullDomain}/`