mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-17 09:49:55 +02:00
Compare commits
7 Commits
d47449b082
...
540aee3fe2
| Author | SHA1 | Date | |
|---|---|---|---|
| 540aee3fe2 | |||
| b1d52ad1a3 | |||
| ce2fbef805 | |||
| e312b31e02 | |||
| bc156c715d | |||
| 9a4c1f23c6 | |||
| 6921447fab |
@@ -4,19 +4,26 @@ import { eq } from "drizzle-orm";
|
||||
|
||||
type SetServerAdminArgs = {
|
||||
email: string;
|
||||
remove: boolean;
|
||||
};
|
||||
|
||||
export const setServerAdmin: CommandModule<{}, SetServerAdminArgs> = {
|
||||
command: "set-server-admin",
|
||||
describe: "Mark any user as a server admin by email address",
|
||||
describe: "Add or remove server admin by email address",
|
||||
builder: (yargs) => {
|
||||
return yargs.option("email", {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
describe: "User email address"
|
||||
});
|
||||
return yargs
|
||||
.option("email", {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
describe: "User email address"
|
||||
})
|
||||
.option("remove", {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
describe: "Remove server admin status from the user"
|
||||
});
|
||||
},
|
||||
handler: async (argv: { email: string }) => {
|
||||
handler: async (argv: SetServerAdminArgs) => {
|
||||
try {
|
||||
const email = argv.email.trim().toLowerCase();
|
||||
|
||||
@@ -31,6 +38,33 @@ export const setServerAdmin: CommandModule<{}, SetServerAdminArgs> = {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (argv.remove) {
|
||||
if (!user.serverAdmin) {
|
||||
console.log(`User '${email}' is not a server admin`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const serverAdmins = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.serverAdmin, true));
|
||||
|
||||
if (serverAdmins.length <= 1) {
|
||||
console.error(
|
||||
"Cannot remove server admin: at least one server admin must exist"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await db
|
||||
.update(users)
|
||||
.set({ serverAdmin: false })
|
||||
.where(eq(users.userId, user.userId));
|
||||
|
||||
console.log(`Server admin status removed from user '${email}'`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (user.serverAdmin) {
|
||||
console.log(`User '${email}' is already a server admin`);
|
||||
process.exit(0);
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
"resourceErrorDelte": "Error deleting resource",
|
||||
"resourcePoliciesBannerTitle": "Re-use Authentication and Access Rules",
|
||||
"resourcePoliciesBannerDescription": "Shared resource policies let you define authentication methods and access rules once, then attach them to multiple public resources. When you update a policy, every linked resource inherits the change automatically.",
|
||||
"resourcePoliciesBannerButtonText": "Learn More",
|
||||
"resourcePoliciesTitle": "Manage Public Resource Policies",
|
||||
"resourcePoliciesAttachedResourcesColumnTitle": "Resources",
|
||||
"resourcePoliciesAttachedResources": "{count} resource(s)",
|
||||
|
||||
@@ -31,7 +31,7 @@ export enum TierFeature {
|
||||
}
|
||||
|
||||
export const tierMatrix: Record<TierFeature, Tier[]> = {
|
||||
[TierFeature.Labels]: ["tier2", "tier3", "enterprise"],
|
||||
[TierFeature.Labels]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||
[TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||
[TierFeature.LoginPageDomain]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||
[TierFeature.DeviceApprovals]: ["tier1", "tier3", "enterprise"],
|
||||
@@ -71,16 +71,6 @@ export const tierMatrix: Record<TierFeature, Tier[]> = {
|
||||
[TierFeature.WildcardSubdomain]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||
[TierFeature.NewtAutoUpdate]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||
[TierFeature.ResourcePolicies]: ["tier3", "enterprise"],
|
||||
[TierFeature.AdvancedPublicResources]: [
|
||||
"tier1",
|
||||
"tier2",
|
||||
"tier3",
|
||||
"enterprise"
|
||||
],
|
||||
[TierFeature.AdvancedPrivateResources]: [
|
||||
"tier1",
|
||||
"tier2",
|
||||
"tier3",
|
||||
"enterprise"
|
||||
]
|
||||
[TierFeature.AdvancedPublicResources]: ["tier3", "enterprise"],
|
||||
[TierFeature.AdvancedPrivateResources]: ["tier3", "enterprise"]
|
||||
};
|
||||
|
||||
@@ -56,13 +56,18 @@ async function getLatestReleaseInfo(): Promise<ReleaseInfo | null> {
|
||||
return staleReleaseInfo;
|
||||
}
|
||||
|
||||
// Drop drafts, pre-releases, and anything with "rc" in the tag name.
|
||||
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
|
||||
// Drop drafts, pre-releases, anything with "rc" in the tag name,
|
||||
// and releases published less than 1 day ago.
|
||||
releases = releases.filter(
|
||||
(r: any) =>
|
||||
!r.draft &&
|
||||
!r.prerelease &&
|
||||
!r.tag_name.includes("rc") &&
|
||||
!r.tag_name.includes("v")
|
||||
!r.tag_name.includes("v") &&
|
||||
r.published_at &&
|
||||
new Date(r.published_at) <= oneDayAgo
|
||||
);
|
||||
|
||||
// Sort descending by semver to find the true latest stable release.
|
||||
|
||||
@@ -282,7 +282,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
||||
<FormDescription>
|
||||
{t("newtAutoUpdateDescription")}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/sites/configure-site#auto-update"
|
||||
href="https://docs.pangolin.net/manage/sites/auto-update"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
|
||||
@@ -229,7 +229,7 @@ function RdpServerForm({
|
||||
sitesField="selectedSites"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/rdp"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/rdp#site-and-host-configuration"
|
||||
defaultPort={3389}
|
||||
/>
|
||||
</SettingsSectionForm>
|
||||
|
||||
@@ -467,7 +467,7 @@ function SshServerForm({
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("sshDaemonDisclaimer")}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
href="https://docs.pangolin.net/manage/ssh"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
@@ -589,7 +589,7 @@ function SshServerForm({
|
||||
sitesField="selectedSites"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh#site-and-host-configuration"
|
||||
defaultPort={22}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
@@ -602,7 +602,7 @@ function SshServerForm({
|
||||
siteField="selectedSite"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh#site-and-host-configuration"
|
||||
defaultPort={22}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
|
||||
@@ -1097,7 +1097,7 @@ export default function Page() {
|
||||
"sshDaemonDisclaimer"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
href="https://docs.pangolin.net/manage/ssh"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
@@ -1235,7 +1235,7 @@ export default function Page() {
|
||||
sitesField="selectedSites"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh#site-and-host-configuration"
|
||||
defaultPort={22}
|
||||
/>
|
||||
</Form>
|
||||
@@ -1256,7 +1256,7 @@ export default function Page() {
|
||||
siteField="selectedSite"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/ssh#site-and-host-configuration"
|
||||
defaultPort={22}
|
||||
/>
|
||||
</Form>
|
||||
@@ -1306,7 +1306,7 @@ export default function Page() {
|
||||
sitesField="selectedSites"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/rdp"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/rdp#site-and-host-configuration"
|
||||
defaultPort={3389}
|
||||
/>
|
||||
</Form>
|
||||
@@ -1353,7 +1353,7 @@ export default function Page() {
|
||||
sitesField="selectedSites"
|
||||
destinationField="destination"
|
||||
destinationPortField="destinationPort"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/vnc"
|
||||
learnMoreHref="https://docs.pangolin.net/manage/resources/public/vnc#site-and-host-configuration"
|
||||
defaultPort={5900}
|
||||
/>
|
||||
</Form>
|
||||
|
||||
@@ -317,7 +317,7 @@ export default function GeneralPage() {
|
||||
"siteAutoUpdateDescription"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/sites/configure-site#auto-update"
|
||||
href="https://docs.pangolin.net/manage/sites/auto-update"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
|
||||
@@ -526,7 +526,7 @@ export default function Page() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}w
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
|
||||
@@ -596,7 +596,7 @@ export default function SshClient({
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("sshPrivateKeyDisclaimer")}{" "}
|
||||
<Link
|
||||
href="https://docs.pangolin.net/"
|
||||
href="https://docs.pangolin.net/manage/ssh#authentication-method"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
|
||||
@@ -144,6 +144,7 @@ export function BrowserGatewayTargetForm<T extends FieldValues>(
|
||||
[]
|
||||
}
|
||||
onSelectionChange={field.onChange}
|
||||
filterTypes={["newt"]}
|
||||
/>
|
||||
) : (
|
||||
<SitesSelector
|
||||
@@ -155,6 +156,7 @@ export function BrowserGatewayTargetForm<T extends FieldValues>(
|
||||
field.onChange(site);
|
||||
setSiteOpen(false);
|
||||
}}
|
||||
filterTypes={["newt"]}
|
||||
/>
|
||||
)}
|
||||
</PopoverContent>
|
||||
@@ -220,7 +222,7 @@ export function BrowserGatewayTargetForm<T extends FieldValues>(
|
||||
<a
|
||||
href={
|
||||
props.learnMoreHref ??
|
||||
"https://docs.pangolin.net/manage/resources/public/ssh"
|
||||
"https://docs.pangolin.net/manage/resources/private/multi-site-routing"
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
@@ -2079,7 +2079,7 @@ export function PrivateResourceForm({
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("sshDaemonDisclaimer")}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/resources/private/ssh"
|
||||
href="https://docs.pangolin.net/manage/ssh"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Shield } from "lucide-react";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { Shield, ArrowRight } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next/link";
|
||||
import DismissableBanner from "./DismissableBanner";
|
||||
|
||||
export const ResourcePoliciesBanner = () => {
|
||||
@@ -14,7 +16,22 @@ export const ResourcePoliciesBanner = () => {
|
||||
title={t("resourcePoliciesBannerTitle")}
|
||||
titleIcon={<Shield className="w-5 h-5 text-primary" />}
|
||||
description={t("resourcePoliciesBannerDescription")}
|
||||
/>
|
||||
>
|
||||
<Link
|
||||
href="https://docs.pangolin.net/manage/resources/public/resource-policies"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2 hover:bg-primary/10 hover:border-primary/50 transition-colors"
|
||||
>
|
||||
{t("resourcePoliciesBannerButtonText")}
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</DismissableBanner>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user