From 1d017f60b43808741dc21a2d7bf3ff827288aa16 Mon Sep 17 00:00:00 2001 From: Pallavi Kumari Date: Fri, 17 Oct 2025 19:51:32 +0530 Subject: [PATCH 1/7] make priority optional in schema --- server/db/pg/schema/schema.ts | 2 +- server/db/sqlite/schema/schema.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/db/pg/schema/schema.ts b/server/db/pg/schema/schema.ts index 2e307c5f..4bed23f8 100644 --- a/server/db/pg/schema/schema.ts +++ b/server/db/pg/schema/schema.ts @@ -126,7 +126,7 @@ export const targets = pgTable("targets", { pathMatchType: text("pathMatchType"), // exact, prefix, regex rewritePath: text("rewritePath"), // if set, rewrites the path to this value before sending to the target rewritePathType: text("rewritePathType"), // exact, prefix, regex, stripPrefix - priority: integer("priority").notNull().default(100) + priority: integer("priority").default(100) }); export const targetHealthCheck = pgTable("targetHealthCheck", { diff --git a/server/db/sqlite/schema/schema.ts b/server/db/sqlite/schema/schema.ts index 2c19a1c7..3d6c6b0d 100644 --- a/server/db/sqlite/schema/schema.ts +++ b/server/db/sqlite/schema/schema.ts @@ -138,7 +138,7 @@ export const targets = sqliteTable("targets", { pathMatchType: text("pathMatchType"), // exact, prefix, regex rewritePath: text("rewritePath"), // if set, rewrites the path to this value before sending to the target rewritePathType: text("rewritePathType"), // exact, prefix, regex, stripPrefix - priority: integer("priority").notNull().default(100) + priority: integer("priority").default(100) }); export const targetHealthCheck = sqliteTable("targetHealthCheck", { From d241dcfb27069667af49798b160a7ed61d4a8be5 Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 16 Oct 2025 14:43:11 -0700 Subject: [PATCH 2/7] Fix typo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 277fa336..c90bd180 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ major_tag := $(shell echo $(tag) | cut -d. -f1) minor_tag := $(shell echo $(tag) | cut -d. -f1,2) -build-release-arm: +build-release: @if [ -z "$(tag)" ]; then \ echo "Error: tag is required. Usage: make build-release tag="; \ exit 1; \ From 59a334ce24d9c9bb9208c802905367c7dd99e3c9 Mon Sep 17 00:00:00 2001 From: Milo Schwartz Date: Thu, 16 Oct 2025 17:45:11 -0400 Subject: [PATCH 3/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1ae6e5f..885a83bf 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Check out the [quick install guide](https://docs.digpangolin.com/self-host/quick | | Description | |-----------------|--------------| -| **Self-Host: Community Edition** | Free, open source, and AGPL-3 compliant. | +| **Self-Host: Community Edition** | Free, open source, and licensed under AGPL-3. | | **Self-Host: Enterprise Edition** | Licensed under Fossorial Commercial License. Free for personal and hobbyist use, and for businesses earning under \$100K USD annually. | | **Pangolin Cloud** | Fully managed service with instant setup and pay-as-you-go pricing — no infrastructure required. Or, self-host your own [remote node](https://docs.digpangolin.com/manage/remote-node/nodes) and connect to our control plane. | From bb6e093ac6ba65b1e450989ad41f353310774895 Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 16 Oct 2025 14:51:42 -0700 Subject: [PATCH 4/7] Priority needs to be def --- server/routers/target/createTarget.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/routers/target/createTarget.ts b/server/routers/target/createTarget.ts index 3d9cf2de..1aef3251 100644 --- a/server/routers/target/createTarget.ts +++ b/server/routers/target/createTarget.ts @@ -179,7 +179,8 @@ export async function createTarget( .insert(targets) .values({ resourceId, - ...targetData + ...targetData, + priority: targetData.priority || 100 }) .returning(); } else { From e5a436593fd8955d26f0a06f297f68cc9eea9659 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 17 Oct 2025 11:56:19 -0700 Subject: [PATCH 5/7] Delete all before migrating --- server/setup/scriptsPg/1.11.0.ts | 11 +++++------ server/setup/scriptsSqlite/1.11.0.ts | 7 ++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/server/setup/scriptsPg/1.11.0.ts b/server/setup/scriptsPg/1.11.0.ts index 13186b4f..4804d7e2 100644 --- a/server/setup/scriptsPg/1.11.0.ts +++ b/server/setup/scriptsPg/1.11.0.ts @@ -313,6 +313,11 @@ export default async function migration() { dateCreated: string; }[]; + // Delete the old record + await db.execute(sql` + DELETE FROM "webauthnCredentials"; + `); + for (const webauthnCredential of webauthnCredentials) { const newCredentialId = isoBase64URL.fromBuffer( new Uint8Array( @@ -325,12 +330,6 @@ export default async function migration() { ) ); - // Delete the old record - await db.execute(sql` - DELETE FROM "webauthnCredentials" - WHERE "credentialId" = ${webauthnCredential.credentialId} - `); - // Insert the updated record with converted values await db.execute(sql` INSERT INTO "webauthnCredentials" ("credentialId", "publicKey", "userId", "signCount", "transports", "name", "lastUsed", "dateCreated") diff --git a/server/setup/scriptsSqlite/1.11.0.ts b/server/setup/scriptsSqlite/1.11.0.ts index 1247eee9..c79cfdb4 100644 --- a/server/setup/scriptsSqlite/1.11.0.ts +++ b/server/setup/scriptsSqlite/1.11.0.ts @@ -269,6 +269,8 @@ export default async function migration() { dateCreated: string; }[]; + db.prepare(`DELETE FROM 'webauthnCredentials';`).run(); + for (const webauthnCredential of webauthnCredentials) { const newCredentialId = isoBase64URL.fromBuffer( new Uint8Array( @@ -281,11 +283,6 @@ export default async function migration() { ) ); - // Delete the old record - db.prepare( - `DELETE FROM 'webauthnCredentials' WHERE 'credentialId' = ?` - ).run(webauthnCredential.credentialId); - // Insert the updated record with converted values db.prepare( `INSERT INTO 'webauthnCredentials' (credentialId, publicKey, userId, signCount, transports, name, lastUsed, dateCreated) VALUES (?, ?, ?, ?, ?, ?, ?, ?)` From c07abf8ff991abc29cb5756f2ce897f647a2502d Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 17 Oct 2025 14:04:49 -0700 Subject: [PATCH 6/7] Pass through transaction --- server/lib/billing/usageService.ts | 27 +++++++++++++---------- server/lib/exitNodes/exitNodes.ts | 8 +++++-- server/private/lib/exitNodes/exitNodes.ts | 7 +++--- server/routers/gerbil/receiveBandwidth.ts | 6 +++-- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/server/lib/billing/usageService.ts b/server/lib/billing/usageService.ts index 0b2b095f..999d5b63 100644 --- a/server/lib/billing/usageService.ts +++ b/server/lib/billing/usageService.ts @@ -612,7 +612,8 @@ export class UsageService { public async getUsage( orgId: string, - featureId: FeatureId + featureId: FeatureId, + trx: Transaction | typeof db = db ): Promise { if (noop()) { return null; @@ -621,7 +622,7 @@ export class UsageService { const usageId = `${orgId}-${featureId}`; try { - const [result] = await db + const [result] = await trx .select() .from(usage) .where(eq(usage.usageId, usageId)) @@ -635,7 +636,7 @@ export class UsageService { const meterId = getFeatureMeterId(featureId); try { - const [newUsage] = await db + const [newUsage] = await trx .insert(usage) .values({ usageId, @@ -652,7 +653,7 @@ export class UsageService { return newUsage; } else { // Record was created by another process, fetch it - const [existingUsage] = await db + const [existingUsage] = await trx .select() .from(usage) .where(eq(usage.usageId, usageId)) @@ -665,7 +666,7 @@ export class UsageService { `Insert failed for ${orgId}/${featureId}, attempting to fetch existing record:`, insertError ); - const [existingUsage] = await db + const [existingUsage] = await trx .select() .from(usage) .where(eq(usage.usageId, usageId)) @@ -812,7 +813,8 @@ export class UsageService { orgId: string, kickSites = false, featureId?: FeatureId, - usage?: Usage + usage?: Usage, + trx: Transaction | typeof db = db ): Promise { if (noop()) { return false; @@ -825,7 +827,7 @@ export class UsageService { let orgLimits: Limit[] = []; if (featureId) { // Get all limits set for this organization - orgLimits = await db + orgLimits = await trx .select() .from(limits) .where( @@ -836,7 +838,7 @@ export class UsageService { ); } else { // Get all limits set for this organization - orgLimits = await db + orgLimits = await trx .select() .from(limits) .where(eq(limits.orgId, orgId)); @@ -855,7 +857,8 @@ export class UsageService { } else { currentUsage = await this.getUsage( orgId, - limit.featureId as FeatureId + limit.featureId as FeatureId, + trx ); } @@ -890,7 +893,7 @@ export class UsageService { ); // Get all sites for this organization - const orgSites = await db + const orgSites = await trx .select() .from(sites) .where(eq(sites.orgId, orgId)); @@ -902,7 +905,7 @@ export class UsageService { // Send termination messages to newt sites for (const site of orgSites) { if (site.type === "newt") { - const [newt] = await db + const [newt] = await trx .select() .from(newts) .where(eq(newts.siteId, site.siteId)) @@ -917,7 +920,7 @@ export class UsageService { }; // Don't await to prevent blocking - sendToClient(newt.newtId, payload).catch( + await sendToClient(newt.newtId, payload).catch( (error: any) => { logger.error( `Failed to send termination message to newt ${newt.newtId}:`, diff --git a/server/lib/exitNodes/exitNodes.ts b/server/lib/exitNodes/exitNodes.ts index bb269710..fb32f4f7 100644 --- a/server/lib/exitNodes/exitNodes.ts +++ b/server/lib/exitNodes/exitNodes.ts @@ -1,4 +1,4 @@ -import { db, exitNodes } from "@server/db"; +import { db, exitNodes, Transaction } from "@server/db"; import logger from "@server/logger"; import { ExitNodePingResult } from "@server/routers/newt"; import { eq } from "drizzle-orm"; @@ -59,7 +59,11 @@ export function selectBestExitNode( return pingResults[0]; } -export async function checkExitNodeOrg(exitNodeId: number, orgId: string) { +export async function checkExitNodeOrg( + exitNodeId: number, + orgId: string, + trx?: Transaction | typeof db +): Promise { return false; } diff --git a/server/private/lib/exitNodes/exitNodes.ts b/server/private/lib/exitNodes/exitNodes.ts index 0dad7714..10418d5a 100644 --- a/server/private/lib/exitNodes/exitNodes.ts +++ b/server/private/lib/exitNodes/exitNodes.ts @@ -18,7 +18,8 @@ import { resources, targets, sites, - targetHealthCheck + targetHealthCheck, + Transaction } from "@server/db"; import logger from "@server/logger"; import { ExitNodePingResult } from "@server/routers/newt"; @@ -333,8 +334,8 @@ export function selectBestExitNode( return fallbackNode; } -export async function checkExitNodeOrg(exitNodeId: number, orgId: string) { - const [exitNodeOrg] = await db +export async function checkExitNodeOrg(exitNodeId: number, orgId: string, trx: Transaction | typeof db = db) { + const [exitNodeOrg] = await trx .select() .from(exitNodeOrgs) .where( diff --git a/server/routers/gerbil/receiveBandwidth.ts b/server/routers/gerbil/receiveBandwidth.ts index 3661dedd..d9279852 100644 --- a/server/routers/gerbil/receiveBandwidth.ts +++ b/server/routers/gerbil/receiveBandwidth.ts @@ -98,7 +98,8 @@ export async function updateSiteBandwidth( if ( await checkExitNodeOrg( exitNodeId, - updatedSite.orgId + updatedSite.orgId, + trx ) ) { // not allowed @@ -242,7 +243,8 @@ export async function updateSiteBandwidth( if ( await checkExitNodeOrg( exitNodeId, - updatedSite.orgId + updatedSite.orgId, + trx ) ) { // not allowed From 240c5b005bb06f1aacc778c3dded255c10d6fe78 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 17 Oct 2025 16:22:43 -0700 Subject: [PATCH 7/7] Add more transactions support --- server/lib/billing/usageService.ts | 2 +- server/private/lib/traefik/getTraefikConfig.ts | 2 +- server/routers/gerbil/receiveBandwidth.ts | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/lib/billing/usageService.ts b/server/lib/billing/usageService.ts index 999d5b63..3c501526 100644 --- a/server/lib/billing/usageService.ts +++ b/server/lib/billing/usageService.ts @@ -920,7 +920,7 @@ export class UsageService { }; // Don't await to prevent blocking - await sendToClient(newt.newtId, payload).catch( + sendToClient(newt.newtId, payload).catch( (error: any) => { logger.error( `Failed to send termination message to newt ${newt.newtId}:`, diff --git a/server/private/lib/traefik/getTraefikConfig.ts b/server/private/lib/traefik/getTraefikConfig.ts index 9408dbfd..c7b0f681 100644 --- a/server/private/lib/traefik/getTraefikConfig.ts +++ b/server/private/lib/traefik/getTraefikConfig.ts @@ -238,7 +238,7 @@ export async function getTraefikConfig( } // get the valid certs for these domains validCerts = await getValidCertificatesForDomains(domains, true); // we are caching here because this is called often - logger.debug(`Valid certs for domains: ${JSON.stringify(validCerts)}`); + // logger.debug(`Valid certs for domains: ${JSON.stringify(validCerts)}`); } const config_output: any = { diff --git a/server/routers/gerbil/receiveBandwidth.ts b/server/routers/gerbil/receiveBandwidth.ts index d9279852..ffbd05c1 100644 --- a/server/routers/gerbil/receiveBandwidth.ts +++ b/server/routers/gerbil/receiveBandwidth.ts @@ -149,7 +149,8 @@ export async function updateSiteBandwidth( orgId, true, FeatureId.EGRESS_DATA_MB, - bandwidthUsage + bandwidthUsage, + trx ) .catch((error: any) => { logger.error( @@ -175,7 +176,8 @@ export async function updateSiteBandwidth( orgId, true, FeatureId.SITE_UPTIME, - uptimeUsage + uptimeUsage, + trx ) .catch((error: any) => { logger.error(