mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-29 16:55:55 +02:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f47c94d05b | |||
| 9a9ae649ef | |||
| aa6dc67015 |
@@ -1,7 +1,5 @@
|
||||
import {
|
||||
db,
|
||||
idp,
|
||||
idpOrg,
|
||||
resourcePolicies,
|
||||
resourcePolicyHeaderAuth,
|
||||
resourcePolicyPassword,
|
||||
@@ -20,6 +18,7 @@ import { Config, ResourcePolicyData } from "./types";
|
||||
import logger from "@server/logger";
|
||||
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||
import { hashPassword } from "@server/auth/password";
|
||||
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||
import { tierMatrix } from "../billing/tierMatrix";
|
||||
@@ -71,19 +70,13 @@ export async function updateResourcePolicies(
|
||||
|
||||
// Validate auto-login-idp if provided
|
||||
if (policyData["auto-login-idp"]) {
|
||||
const [provider] = await trx
|
||||
.select()
|
||||
.from(idp)
|
||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||
.where(
|
||||
and(
|
||||
eq(idp.idpId, policyData["auto-login-idp"]),
|
||||
eq(idpOrg.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
const providerExists = await idpExistsForOrg(
|
||||
policyData["auto-login-idp"],
|
||||
orgId,
|
||||
trx
|
||||
);
|
||||
|
||||
if (!provider) {
|
||||
if (!providerExists) {
|
||||
throw new Error(
|
||||
`Identity provider not found for policy '${policyNiceId}' in this organization`
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@ export const TargetHealthCheckSchema = z.object({
|
||||
hostname: z.string(),
|
||||
port: z.int().min(1).max(65535),
|
||||
enabled: z.boolean().optional().default(true),
|
||||
path: z.string().optional(),
|
||||
path: z.string().optional().default("/"),
|
||||
scheme: z.string().optional(),
|
||||
mode: z.string().default("http"),
|
||||
interval: z.int().default(30),
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { db, idp, idpOrg, Transaction } from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
export function isOrgIdentityProviderMode(): boolean {
|
||||
return process.env.IDENTITY_PROVIDER_MODE === "org";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an identity provider can be used for the given org.
|
||||
* In org IdP mode, the provider must be linked via idpOrg.
|
||||
* In global IdP mode, the provider only needs to exist.
|
||||
*/
|
||||
export async function idpExistsForOrg(
|
||||
idpId: number,
|
||||
orgId: string,
|
||||
dbOrTrx: typeof db | Transaction = db
|
||||
): Promise<boolean> {
|
||||
if (isOrgIdentityProviderMode()) {
|
||||
const [provider] = await dbOrTrx
|
||||
.select({ idpId: idp.idpId })
|
||||
.from(idp)
|
||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||
.where(and(eq(idp.idpId, idpId), eq(idpOrg.orgId, orgId)))
|
||||
.limit(1);
|
||||
|
||||
return !!provider;
|
||||
}
|
||||
|
||||
const [provider] = await dbOrTrx
|
||||
.select({ idpId: idp.idpId })
|
||||
.from(idp)
|
||||
.where(eq(idp.idpId, idpId))
|
||||
.limit(1);
|
||||
|
||||
return !!provider;
|
||||
}
|
||||
@@ -14,8 +14,6 @@
|
||||
import { hashPassword } from "@server/auth/password";
|
||||
import {
|
||||
db,
|
||||
idp,
|
||||
idpOrg,
|
||||
orgs,
|
||||
resourcePolicies,
|
||||
resourcePolicyHeaderAuth,
|
||||
@@ -31,6 +29,7 @@ import {
|
||||
type ResourcePolicy
|
||||
} from "@server/db";
|
||||
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||
import response from "@server/lib/response";
|
||||
import {
|
||||
getResourceRuleValueValidationError,
|
||||
@@ -204,14 +203,9 @@ export async function createResourcePolicy(
|
||||
|
||||
// Check if Identity provider in `skipToIdpId` exists
|
||||
if (skipToIdpId) {
|
||||
const [provider] = await db
|
||||
.select()
|
||||
.from(idp)
|
||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||
.where(and(eq(idp.idpId, skipToIdpId), eq(idpOrg.orgId, orgId)))
|
||||
.limit(1);
|
||||
const providerExists = await idpExistsForOrg(skipToIdpId, orgId);
|
||||
|
||||
if (!provider) {
|
||||
if (!providerExists) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
|
||||
@@ -2,8 +2,6 @@ import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
db,
|
||||
idp,
|
||||
idpOrg,
|
||||
resourcePolicies,
|
||||
rolePolicies,
|
||||
roles,
|
||||
@@ -18,6 +16,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { and, eq, inArray, ne } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||
|
||||
const setResourcePolicyAcccessControlBodySchema = z.strictObject({
|
||||
sso: z.boolean(),
|
||||
@@ -27,7 +26,7 @@ const setResourcePolicyAcccessControlBodySchema = z.strictObject({
|
||||
}),
|
||||
skipToIdpId: z.int().positive().optional().nullable().openapi({
|
||||
type: "integer",
|
||||
description: "Page number to retrieve"
|
||||
description: "Default identity provider ID to skip to on login"
|
||||
})
|
||||
});
|
||||
|
||||
@@ -36,8 +35,8 @@ const setResourcePolicyAccessControlParamsSchema = z.strictObject({
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/resource-policy/{resourceId}/access-control",
|
||||
method: "put",
|
||||
path: "/resource-policy/{resourcePolicyId}/access-control",
|
||||
description:
|
||||
"Set access control users for a resource policy, including SSO, users, roles, Identity provider.",
|
||||
tags: [OpenAPITags.PublicResourcePolicyLegacy],
|
||||
@@ -163,16 +162,9 @@ export async function setResourcePolicyAccessControl(
|
||||
|
||||
// Check if Identity provider in `skipToIdpId` exists
|
||||
if (idpId) {
|
||||
const [provider] = await db
|
||||
.select()
|
||||
.from(idp)
|
||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||
.where(
|
||||
and(eq(idp.idpId, idpId), eq(idpOrg.orgId, policy.orgId))
|
||||
)
|
||||
.limit(1);
|
||||
const providerExists = await idpExistsForOrg(idpId, policy.orgId);
|
||||
|
||||
if (!provider) {
|
||||
if (!providerExists) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
|
||||
@@ -40,6 +40,8 @@ import { NewtSiteInstallCommands } from "@app/components/newt-install-commands";
|
||||
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { productUpdatesQueries } from "@app/lib/queries";
|
||||
|
||||
export default function CredentialsPage() {
|
||||
const { env } = useEnvContext();
|
||||
@@ -67,6 +69,12 @@ export default function CredentialsPage() {
|
||||
|
||||
const { isPaidUser } = usePaidStatus();
|
||||
|
||||
const { data: latestVersions } = useQuery(
|
||||
productUpdatesQueries.latestVersion(true)
|
||||
);
|
||||
const newtVersion =
|
||||
latestVersions?.data?.newt?.latestVersion ?? "latest";
|
||||
|
||||
// Fetch site defaults for wireguard sites to show in obfuscated config
|
||||
useEffect(() => {
|
||||
const fetchSiteDefaults = async () => {
|
||||
@@ -302,6 +310,7 @@ export default function CredentialsPage() {
|
||||
id={displayNewtId ?? "**********"}
|
||||
secret={displaySecret ?? "**************"}
|
||||
endpoint={env.app.dashboardUrl}
|
||||
version={newtVersion}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -56,6 +56,8 @@ import { QRCodeCanvas } from "qrcode.react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { build } from "@server/build";
|
||||
import { NewtSiteInstallCommands } from "@app/components/newt-install-commands";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { productUpdatesQueries } from "@app/lib/queries";
|
||||
|
||||
type SiteType = "newt" | "wireguard" | "local";
|
||||
|
||||
@@ -189,9 +191,14 @@ export default function Page() {
|
||||
const [wgConfig, setWgConfig] = useState("");
|
||||
|
||||
const [createLoading, setCreateLoading] = useState(false);
|
||||
const [newtVersion, setNewtVersion] = useState("latest");
|
||||
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
||||
|
||||
const { data: latestVersions } = useQuery(
|
||||
productUpdatesQueries.latestVersion(true)
|
||||
);
|
||||
const newtVersion =
|
||||
latestVersions?.data?.newt?.latestVersion ?? "latest";
|
||||
|
||||
const [siteDefaults, setSiteDefaults] =
|
||||
useState<PickSiteDefaultsResponse | null>(null);
|
||||
|
||||
@@ -302,45 +309,6 @@ export default function Page() {
|
||||
const load = async () => {
|
||||
setLoadingPage(true);
|
||||
|
||||
let currentNewtVersion = "latest";
|
||||
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
||||
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/fosrl/newt/releases/latest`,
|
||||
{ signal: controller.signal }
|
||||
);
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
t("newtErrorFetchReleases", {
|
||||
err: response.statusText
|
||||
})
|
||||
);
|
||||
}
|
||||
const data = await response.json();
|
||||
const latestVersion = data.tag_name;
|
||||
currentNewtVersion = latestVersion;
|
||||
setNewtVersion(latestVersion);
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.name === "AbortError") {
|
||||
console.error(t("newtErrorFetchTimeout"));
|
||||
} else {
|
||||
console.error(
|
||||
t("newtErrorFetchLatest", {
|
||||
err:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: String(error)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const generatedKeypair = generateKeypair();
|
||||
|
||||
const privateKey = generatedKeypair.privateKey;
|
||||
|
||||
Reference in New Issue
Block a user