mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-19 00:40:40 +02:00
fix minor auth issues and set NODE_ENV to solve react email bug
This commit is contained in:
parent
8178dd1525
commit
c2cbd7e1a1
10 changed files with 75 additions and 90 deletions
|
@ -1,14 +1,15 @@
|
||||||
app:
|
app:
|
||||||
base_url: http://localhost:3000
|
base_url: https://fossorial.io
|
||||||
log_level: debug
|
log_level: debug
|
||||||
save_logs: false
|
save_logs: false
|
||||||
|
|
||||||
server:
|
server:
|
||||||
external_port: 3000
|
external_port: 3000
|
||||||
internal_port: 3001
|
internal_port: 3001
|
||||||
internal_hostname: localhost
|
internal_hostname: pangolin
|
||||||
secure_cookies: false
|
secure_cookies: false
|
||||||
session_cookie_name: session
|
session_cookie_name: session
|
||||||
|
resource_session_cookie_name: resource_session
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
cert_resolver: letsencrypt
|
cert_resolver: letsencrypt
|
||||||
|
@ -16,16 +17,12 @@ traefik:
|
||||||
https_entrypoint: websecure
|
https_entrypoint: websecure
|
||||||
prefer_wildcard_cert: true
|
prefer_wildcard_cert: true
|
||||||
|
|
||||||
badger:
|
|
||||||
session_query_parameter: __pang_sess
|
|
||||||
resource_session_cookie_name: resource_session
|
|
||||||
|
|
||||||
gerbil:
|
gerbil:
|
||||||
start_port: 51820
|
start_port: 51820
|
||||||
base_endpoint: localhost
|
base_endpoint: fossorial.io
|
||||||
|
use_subdomain: false
|
||||||
block_size: 16
|
block_size: 16
|
||||||
subnet_group: 10.0.0.0/8
|
subnet_group: 10.0.0.0/8
|
||||||
use_subdomain: true
|
|
||||||
|
|
||||||
rate_limit:
|
rate_limit:
|
||||||
window_minutes: 1
|
window_minutes: 1
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio",
|
||||||
"build": "mkdir -p dist && next build && node scripts/esbuild.mjs -e server/index.ts -o dist/server.mjs",
|
"build": "mkdir -p dist && next build && node scripts/esbuild.mjs -e server/index.ts -o dist/server.mjs",
|
||||||
"start": "ENVIRONMENT=prod node dist/server.mjs",
|
"start": "NODE_ENV=development ENVIRONMENT=prod node dist/server.mjs",
|
||||||
"email": "email dev --dir server/emails/templates --port 3002"
|
"email": "email dev --dir server/emails/templates --port 3002"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -25,9 +25,6 @@ const environmentSchema = z.object({
|
||||||
secure_cookies: z.boolean(),
|
secure_cookies: z.boolean(),
|
||||||
signup_secret: z.string().optional(),
|
signup_secret: z.string().optional(),
|
||||||
session_cookie_name: z.string(),
|
session_cookie_name: z.string(),
|
||||||
}),
|
|
||||||
badger: z.object({
|
|
||||||
session_query_parameter: z.string(),
|
|
||||||
resource_session_cookie_name: z.string(),
|
resource_session_cookie_name: z.string(),
|
||||||
}),
|
}),
|
||||||
traefik: z.object({
|
traefik: z.object({
|
||||||
|
@ -136,8 +133,6 @@ process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED = parsedConfig.data.flags
|
||||||
: "false";
|
: "false";
|
||||||
process.env.SESSION_COOKIE_NAME = parsedConfig.data.server.session_cookie_name;
|
process.env.SESSION_COOKIE_NAME = parsedConfig.data.server.session_cookie_name;
|
||||||
process.env.RESOURCE_SESSION_COOKIE_NAME =
|
process.env.RESOURCE_SESSION_COOKIE_NAME =
|
||||||
parsedConfig.data.badger.resource_session_cookie_name;
|
parsedConfig.data.server.resource_session_cookie_name;
|
||||||
process.env.RESOURCE_SESSION_QUERY_PARAM_NAME =
|
|
||||||
parsedConfig.data.badger.session_query_parameter;
|
|
||||||
|
|
||||||
export default parsedConfig.data;
|
export default parsedConfig.data;
|
||||||
|
|
|
@ -121,7 +121,7 @@ export async function verifyResourceSession(
|
||||||
|
|
||||||
const resourceSessionToken =
|
const resourceSessionToken =
|
||||||
sessions[
|
sessions[
|
||||||
`${config.badger.resource_session_cookie_name}_${resource.resourceId}`
|
`${config.server.resource_session_cookie_name}_${resource.resourceId}`
|
||||||
];
|
];
|
||||||
|
|
||||||
if ((pincode || password) && resourceSessionToken) {
|
if ((pincode || password) && resourceSessionToken) {
|
||||||
|
|
|
@ -132,7 +132,7 @@ export async function authWithPassword(
|
||||||
token,
|
token,
|
||||||
passwordId: definedPassword.passwordId,
|
passwordId: definedPassword.passwordId,
|
||||||
});
|
});
|
||||||
const cookieName = `${config.badger.resource_session_cookie_name}_${resource.resourceId}`;
|
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
|
||||||
const cookie = serializeResourceSessionCookie(
|
const cookie = serializeResourceSessionCookie(
|
||||||
cookieName,
|
cookieName,
|
||||||
token,
|
token,
|
||||||
|
|
|
@ -128,7 +128,7 @@ export async function authWithPincode(
|
||||||
token,
|
token,
|
||||||
pincodeId: definedPincode.pincodeId,
|
pincodeId: definedPincode.pincodeId,
|
||||||
});
|
});
|
||||||
const cookieName = `${config.badger.resource_session_cookie_name}_${resource.resourceId}`;
|
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
|
||||||
const cookie = serializeResourceSessionCookie(
|
const cookie = serializeResourceSessionCookie(
|
||||||
cookieName,
|
cookieName,
|
||||||
token,
|
token,
|
||||||
|
|
|
@ -55,11 +55,9 @@ export async function traefikConfigProvider(
|
||||||
`http://${config.server.internal_hostname}:${config.server.internal_port}`,
|
`http://${config.server.internal_hostname}:${config.server.internal_port}`,
|
||||||
).href,
|
).href,
|
||||||
resourceSessionCookieName:
|
resourceSessionCookieName:
|
||||||
config.badger.resource_session_cookie_name,
|
config.server.resource_session_cookie_name,
|
||||||
userSessionCookieName:
|
userSessionCookieName:
|
||||||
config.server.session_cookie_name,
|
config.server.session_cookie_name,
|
||||||
sessionQueryParameter:
|
|
||||||
config.badger.session_query_parameter,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -233,6 +233,24 @@ export default function ReverseProxyTargets(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: ColumnDef<LocalTarget>[] = [
|
const columns: ColumnDef<LocalTarget>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "method",
|
||||||
|
header: "Method",
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Select
|
||||||
|
defaultValue={row.original.method}
|
||||||
|
onValueChange={(value) =>
|
||||||
|
updateTarget(row.original.targetId, { method: value })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger>{row.original.method}</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="http">http</SelectItem>
|
||||||
|
<SelectItem value="https">https</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "ip",
|
accessorKey: "ip",
|
||||||
header: "IP Address",
|
header: "IP Address",
|
||||||
|
@ -262,24 +280,6 @@ export default function ReverseProxyTargets(props: {
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessorKey: "method",
|
|
||||||
header: "Method",
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<Select
|
|
||||||
defaultValue={row.original.method}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
updateTarget(row.original.targetId, { method: value })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger>{row.original.method}</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="http">http</SelectItem>
|
|
||||||
<SelectItem value="https">https</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
// {
|
// {
|
||||||
// accessorKey: "protocol",
|
// accessorKey: "protocol",
|
||||||
// header: "Protocol",
|
// header: "Protocol",
|
||||||
|
@ -368,7 +368,7 @@ export default function ReverseProxyTargets(props: {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr className="lg:max-w-2xl"/>
|
<hr className="lg:max-w-2xl" />
|
||||||
|
|
||||||
<section className="space-y-8">
|
<section className="space-y-8">
|
||||||
<SettingsSectionTitle
|
<SettingsSectionTitle
|
||||||
|
@ -386,25 +386,6 @@ export default function ReverseProxyTargets(props: {
|
||||||
className="space-y-8"
|
className="space-y-8"
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||||
<FormField
|
|
||||||
control={addTargetForm.control}
|
|
||||||
name="ip"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>
|
|
||||||
IP Address
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input id="ip" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription>
|
|
||||||
Enter the IP address of the
|
|
||||||
target.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={addTargetForm.control}
|
control={addTargetForm.control}
|
||||||
name="method"
|
name="method"
|
||||||
|
@ -444,6 +425,25 @@ export default function ReverseProxyTargets(props: {
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={addTargetForm.control}
|
||||||
|
name="ip"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
IP Address
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input id="ip" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
Enter the IP address of the
|
||||||
|
target.
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={addTargetForm.control}
|
control={addTargetForm.control}
|
||||||
name="port"
|
name="port"
|
||||||
|
|
|
@ -165,14 +165,14 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleSSOAuth() {
|
async function handleSSOAuth() {
|
||||||
console.log("SSO authentication");
|
try {
|
||||||
|
await api.get(`/resource/${props.resource.id}`);
|
||||||
await api.get(`/resource/${props.resource.id}`).catch((e) => {
|
} catch (e) {
|
||||||
setAccessDenied(true);
|
setAccessDenied(true);
|
||||||
});
|
}
|
||||||
|
|
||||||
if (!accessDenied) {
|
if (!accessDenied) {
|
||||||
window.location.href = props.redirect;
|
window.location.href = constructRedirect(props.redirect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,7 @@ export default async function ResourceAuthPage(props: {
|
||||||
if (res && res.data.data.valid) {
|
if (res && res.data.data.valid) {
|
||||||
doRedirect = true;
|
doRedirect = true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doRedirect) {
|
if (doRedirect) {
|
||||||
redirect(redirectUrl);
|
redirect(redirectUrl);
|
||||||
|
@ -91,7 +89,6 @@ export default async function ResourceAuthPage(props: {
|
||||||
console.log(res.data);
|
console.log(res.data);
|
||||||
doRedirect = true;
|
doRedirect = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
|
||||||
userIsUnauthorized = true;
|
userIsUnauthorized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,30 +97,28 @@ export default async function ResourceAuthPage(props: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userIsUnauthorized && isSSOOnly) {
|
|
||||||
return (
|
|
||||||
<div className="w-full max-w-md">
|
|
||||||
<ResourceAccessDenied />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full max-w-md">
|
{userIsUnauthorized && isSSOOnly ? (
|
||||||
<ResourceAuthPortal
|
<div className="w-full max-w-md">
|
||||||
methods={{
|
<ResourceAccessDenied />
|
||||||
password: authInfo.password,
|
</div>
|
||||||
pincode: authInfo.pincode,
|
) : (
|
||||||
sso: authInfo.sso && !userIsUnauthorized,
|
<div className="w-full max-w-md">
|
||||||
}}
|
<ResourceAuthPortal
|
||||||
resource={{
|
methods={{
|
||||||
name: authInfo.resourceName,
|
password: authInfo.password,
|
||||||
id: authInfo.resourceId,
|
pincode: authInfo.pincode,
|
||||||
}}
|
sso: authInfo.sso && !userIsUnauthorized,
|
||||||
redirect={redirectUrl}
|
}}
|
||||||
/>
|
resource={{
|
||||||
</div>
|
name: authInfo.resourceName,
|
||||||
|
id: authInfo.resourceId,
|
||||||
|
}}
|
||||||
|
redirect={redirectUrl}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue