Opensearch wrapper WIP

This commit is contained in:
Darren Clarke 2025-02-17 10:53:08 +01:00
parent 5ff5eb4213
commit 6e8d3e171e
11 changed files with 58 additions and 71 deletions

View file

@ -23,13 +23,11 @@ import { useSearchParams } from "next/navigation";
type LoginProps = { type LoginProps = {
session: any; session: any;
baseURL: string;
}; };
export const Login: FC<LoginProps> = ({ session }) => { export const Login: FC<LoginProps> = ({ session, baseURL }) => {
const origin = const origin = baseURL;
typeof window !== "undefined" && window.location.origin
? window.location.origin
: "";
const callbackUrl = `${origin}/setup`; const callbackUrl = `${origin}/setup`;
const [provider, setProvider] = useState(undefined); const [provider, setProvider] = useState(undefined);
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");

View file

@ -9,10 +9,11 @@ export const metadata: Metadata = {
export default async function Page() { export default async function Page() {
const session = await getSession(); const session = await getSession();
const baseURL = process.env.LINK_URL;
return ( return (
<Suspense fallback={<div>Loading...</div>}> <Suspense fallback={<div>Loading...</div>}>
<Login session={session} /> <Login session={session} baseURL={baseURL} />
</Suspense> </Suspense>
); );
} }

View file

@ -136,11 +136,11 @@ export const authOptions: NextAuthOptions = {
return roles.includes("admin") || roles.includes("agent"); return roles.includes("admin") || roles.includes("agent");
}, },
session: async ({ session, token }) => { session: async ({ session, token }) => {
const redis = new Redis(process.env.REDIS_URL); // const redis = new Redis(process.env.REDIS_URL);
const isInvalidated = await redis.get(`invalidated:${token.sub}`); // const isInvalidated = await redis.get(`invalidated:${token.sub}`);
if (isInvalidated) { // if (isInvalidated) {
return null; // return null;
} // }
// @ts-ignore // @ts-ignore
session.user.roles = token.roles ?? []; session.user.roles = token.roles ?? [];
// @ts-ignore // @ts-ignore

View file

@ -7,6 +7,8 @@ const rewriteURL = (
destinationBaseURL: string, destinationBaseURL: string,
headers: any = {}, headers: any = {},
) => { ) => {
console.log("Rewriting URL");
console.log({ request, originBaseURL, destinationBaseURL, headers });
let path = request.url.replace(originBaseURL, ""); let path = request.url.replace(originBaseURL, "");
if (path.startsWith("/")) { if (path.startsWith("/")) {
path = path.slice(1); path = path.slice(1);
@ -30,20 +32,11 @@ const rewriteURL = (
const checkRewrites = async (request: NextRequestWithAuth) => { const checkRewrites = async (request: NextRequestWithAuth) => {
const linkBaseURL = process.env.LINK_URL ?? "http://localhost:3000"; const linkBaseURL = process.env.LINK_URL ?? "http://localhost:3000";
const zammadURL = process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080"; console.log({ linkBaseURL });
const opensearchBaseURL = const opensearchBaseURL =
process.env.OPENSEARCH_DASHBOARDS_URL ?? process.env.OPENSEARCH_DASHBOARDS_URL ??
"http://opensearch-dashboards:5601"; "http://opensearch-dashboards:5601";
const zammadPaths = [
"/zammad",
"/auth/sso",
"/assets",
"/mobile",
"/graphql",
"/cable",
];
const isSetupMode = process.env.SETUP_MODE === "true";
const { token } = request.nextauth; const { token } = request.nextauth;
const email = token?.email?.toLowerCase() ?? "unknown"; const email = token?.email?.toLowerCase() ?? "unknown";
const roles = (token?.roles as string[]) ?? []; const roles = (token?.roles as string[]) ?? [];
@ -59,16 +52,6 @@ const checkRewrites = async (request: NextRequestWithAuth) => {
opensearchBaseURL, opensearchBaseURL,
headers, headers,
); );
} else if (request.nextUrl.pathname.startsWith("/zammad")) {
return rewriteURL(request, `${linkBaseURL}/zammad`, zammadURL, headers);
} else if (zammadPaths.some((p) => request.nextUrl.pathname.startsWith(p))) {
return rewriteURL(request, linkBaseURL, zammadURL, headers);
} else if (request.nextUrl.pathname.startsWith("/api/v1")) {
if ((email && email !== "unknown") || isSetupMode) {
return NextResponse.next();
} else {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
} else { } else {
const isDev = process.env.NODE_ENV === "development"; const isDev = process.env.NODE_ENV === "development";
const nonce = Buffer.from(crypto.randomUUID()).toString("base64"); const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
@ -86,30 +69,30 @@ const checkRewrites = async (request: NextRequestWithAuth) => {
frame-ancestors 'self'; frame-ancestors 'self';
upgrade-insecure-requests; upgrade-insecure-requests;
`; `;
const contentSecurityPolicyHeaderValue = cspHeader const contentSecurityPolicyHeaderValue = cspHeader
.replace(/\s{2,}/g, " ") .replace(/\s{2,}/g, " ")
.trim(); .trim();
const requestHeaders = new Headers(request.headers); const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-nonce", nonce); requestHeaders.set("x-nonce", nonce);
requestHeaders.set( requestHeaders.set(
"Content-Security-Policy", "Content-Security-Policy",
contentSecurityPolicyHeaderValue, contentSecurityPolicyHeaderValue,
); );
const response = NextResponse.next({ const response = NextResponse.next({
request: { request: {
headers: requestHeaders, headers: requestHeaders,
}, },
}); });
response.headers.set( response.headers.set(
"Content-Security-Policy", "Content-Security-Policy",
contentSecurityPolicyHeaderValue, contentSecurityPolicyHeaderValue,
); );
return response; return response;
}; };
} }
export default withAuth(checkRewrites, { export default withAuth(checkRewrites, {

View file

@ -3,7 +3,7 @@
"version": "2.4.0b1", "version": "2.4.0b1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev -H 0.0.0.0",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"export": "next export", "export": "next export",

View file

@ -15,6 +15,10 @@ x-zammad-vars: &common-zammad-variables
ELASTICSEARCH_SSL_VERIFY: "false" # this doesn't set es_ssl_verify as expected, but ideally it would ELASTICSEARCH_SSL_VERIFY: "false" # this doesn't set es_ssl_verify as expected, but ideally it would
ELASTICSEARCH_SCHEMA: "https" ELASTICSEARCH_SCHEMA: "https"
x-zammad-args: &common-zammad-args
EMBEDDED: "true"
LINK_HOST: ${LINK_HOST}
services: services:
zammad-init: zammad-init:
container_name: zammad-init container_name: zammad-init
@ -28,7 +32,7 @@ services:
build: build:
context: ../zammad context: ../zammad
args: args:
EMBEDDED: "true" <<: *common-zammad-args
image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION} image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION}
restart: on-failure restart: on-failure
user: 0:0 user: 0:0
@ -57,7 +61,7 @@ services:
build: build:
context: ../zammad context: ../zammad
args: args:
EMBEDDED: "true" <<: *common-zammad-args
image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION} image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION}
restart: ${RESTART} restart: ${RESTART}
environment: environment:
@ -81,7 +85,7 @@ services:
build: build:
context: ../zammad context: ../zammad
args: args:
EMBEDDED: "true" <<: *common-zammad-args
image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION} image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION}
restart: ${RESTART} restart: ${RESTART}
volumes: volumes:
@ -110,7 +114,7 @@ services:
build: build:
context: ../zammad context: ../zammad
args: args:
EMBEDDED: "true" <<: *common-zammad-args
image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION} image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION}
restart: ${RESTART} restart: ${RESTART}
volumes: volumes:
@ -129,7 +133,7 @@ services:
build: build:
context: ../zammad context: ../zammad
args: args:
EMBEDDED: "true" <<: *common-zammad-args
image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION} image: registry.gitlab.com/digiresilience/link/link-stack/zammad:${LINK_STACK_VERSION}
restart: ${RESTART} restart: ${RESTART}
volumes: volumes:

View file

@ -20,5 +20,5 @@ opensearch_security.multitenancy.tenants.preferred: [Private, Global]
# opensearch_security.readonly_mode.roles: [kibana_read_only] # opensearch_security.readonly_mode.roles: [kibana_read_only]
opensearch_security.cookie.secure: false opensearch_security.cookie.secure: false
server.host: "0.0.0.0" server.host: "0.0.0.0"
server.basePath: "/dashboards" server.basePath: "/link/dashboards"
server.rewriteBasePath: false server.rewriteBasePath: false

View file

@ -22,15 +22,16 @@ RUN sed -i '/touch db\/schema.rb/a ZAMMAD_SAFE_MODE=1 DATABASE_URL=postgresql:\/
RUN cat contrib/docker/setup.sh RUN cat contrib/docker/setup.sh
RUN contrib/docker/setup.sh builder RUN contrib/docker/setup.sh builder
ARG EMBEDDED=false ARG EMBEDDED=false
RUN if [ "$EMBEDDED" = "true" ] ; then sed -i '/location \/ {/i \ ARG LINK_HOST=http://link:3000
\ \n\ RUN if [ "$EMBEDDED" = "true" ] ; then sed -i "/location \/ {/i\
\ location /link {\n\ location /link {\n\
\ proxy_pass http://link:3000;\n\ proxy_pass ${LINK_HOST};\n\
\ proxy_set_header Host $host;\n\ proxy_set_header Host \$host;\n\
\ proxy_set_header X-Real-IP $remote_addr;\n\ proxy_set_header X-Real-IP \$remote_addr;\n\
\ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\n\
\ proxy_set_header X-Forwarded-Proto https;\n\ proxy_set_header X-Forwarded-Proto https;\n\
\ }\n' ${ZAMMAD_DIR}/contrib/nginx/zammad.conf; fi }\n\
" ${ZAMMAD_DIR}/contrib/nginx/zammad.conf; fi
RUN sed -i '/^[[:space:]]*# es config/a\ RUN sed -i '/^[[:space:]]*# es config/a\
echo "about to reinstall..."\n\ echo "about to reinstall..."\n\
bundle exec rails runner /opt/zammad/contrib/link/setup.rb\n\ bundle exec rails runner /opt/zammad/contrib/link/setup.rb\n\

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "@link-stack", "name": "@link-stack",
"version": "2.4.0b1", "version": "2.5.0b1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@link-stack", "name": "@link-stack",
"version": "2.4.0b1", "version": "2.5.0b1",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"workspaces": [ "workspaces": [
"apps/*", "apps/*",

View file

@ -1,6 +1,6 @@
{ {
"name": "@link-stack", "name": "@link-stack",
"version": "2.4.0b1", "version": "2.5.0b1",
"description": "Link from the Center for Digital Resilience", "description": "Link from the Center for Digital Resilience",
"scripts": { "scripts": {
"dev": "dotenv -- turbo dev", "dev": "dotenv -- turbo dev",

View file

@ -34,7 +34,7 @@ export const OpenSearchWrapper: FC<OpenSearchWrapperProps> = ({
> >
<Iframe <Iframe
id="opensearch" id="opensearch"
url={`/dashboards/${url}`} url={`/link/dashboards/${url}`}
// url={`/dashboards/${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`} // url={`/dashboards/${url}&_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)%2Ctime%3A(from%3Anow-3y%2Cto%3Anow))`}
width="100%" width="100%"
height="100%" height="100%"