diff --git a/.env.example b/.env.example index 7de8cd8..5bddd78 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,6 @@ # FRONTEND CLIENT_PORT=3100 VITE_METABASE_INSTANCE_URL="http://localhost:3000" -VITE_AUTH_PROVIDER_URI="http://localhost:9090/sso/metabase" # BACKEND AUTH_PROVIDER_PORT=9090 diff --git a/client/Dockerfile b/client/Dockerfile index 1b4c515..b9483d6 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -6,9 +6,6 @@ ENV WATCH=${WATCH} ARG VITE_METABASE_INSTANCE_URL ENV VITE_METABASE_INSTANCE_URL=${VITE_METABASE_INSTANCE_URL} -ARG VITE_AUTH_PROVIDER_URI -ENV VITE_AUTH_PROVIDER_URI=${VITE_AUTH_PROVIDER_URI} - WORKDIR /app COPY ./client ./client diff --git a/client/package-lock.json b/client/package-lock.json index 06e29e4..631641a 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,7 +8,7 @@ "name": "client", "version": "0.0.0", "dependencies": { - "@metabase/embedding-sdk-react": "^0.54.11", + "@metabase/embedding-sdk-react": "^0.55.2-nightly", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -1552,9 +1552,9 @@ "license": "MIT" }, "node_modules/@metabase/embedding-sdk-react": { - "version": "0.54.11", - "resolved": "https://registry.npmjs.org/@metabase/embedding-sdk-react/-/embedding-sdk-react-0.54.11.tgz", - "integrity": "sha512-4sWYZp/PBpVMAjh61nAWim3PmKA3lsi0tMSNqf3wAeduIBROChUriDIXYPnJhVl72fDLlsbdCes3zVqCMgV2fA==", + "version": "0.55.2-nightly", + "resolved": "https://registry.npmjs.org/@metabase/embedding-sdk-react/-/embedding-sdk-react-0.55.2-nightly.tgz", + "integrity": "sha512-CIw0eSzhNw2jxUeAaoL9Xlk+fGZgAIlDVOOM4+aBOAFLmJ2s/PMnsDh8seJlDzSYTzwUkQciAOXcFPJRbrjWJA==", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@codemirror/autocomplete": "^6.18.3", @@ -1616,7 +1616,6 @@ "inquirer-toggle": "^1.0.1", "js-cookie": "^2.1.2", "jspdf": "3.0.1", - "jsrsasign": "^11.0.0", "kbar": "^0.1.0-beta.45", "leaflet": "^1.2.0", "leaflet-draw": "^0.4.9", @@ -1654,6 +1653,7 @@ "redux-actions": "^2.0.1", "redux-auth-wrapper": "^2.1.0", "redux-promise": "^0.6.0", + "redux-undo": "^1.1.0", "regenerator-runtime": "^0.14.1", "rehype-external-links": "^2.0.1", "remark-gfm": "1.0.0", @@ -1667,12 +1667,12 @@ "sql-formatter": "^15.1.2", "stream-browserify": "^3.0.0", "tether": "^1.2.0", + "tinykeys": "^3.0.0", "tippy.js": "^6.3.5", "ts-pattern": "^5.1.2", "ttag": "1.7.21", "typescript": "^5.4.5", "underscore": "~1.13.3", - "use-debounce": "^10.0.0", "yup": "^0.32.11" }, "bin": { @@ -6123,14 +6123,6 @@ "html2canvas": "^1.0.0-rc.5" } }, - "node_modules/jsrsasign": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.0.tgz", - "integrity": "sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==", - "funding": { - "url": "https://github.com/kjur/jsrsasign#donations" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -9049,6 +9041,12 @@ "redux": "^5.0.0" } }, + "node_modules/redux-undo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/redux-undo/-/redux-undo-1.1.0.tgz", + "integrity": "sha512-zzLFh2qeF0MTIlzDhDLm9NtkfBqCllQJ3OCuIl5RKlG/ayHw6GUdIFdMhzMS9NnrnWdBX5u//ExMOHpfudGGOg==", + "license": "MIT" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -10263,6 +10261,12 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, + "node_modules/tinykeys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinykeys/-/tinykeys-3.0.0.tgz", + "integrity": "sha512-nazawuGv5zx6MuDfDY0rmfXjuOGhD5XU2z0GLURQ1nzl0RUe9OuCJq+0u8xxJZINHe+mr7nw8PWYYZ9WhMFujw==", + "license": "MIT" + }, "node_modules/tippy.js": { "version": "6.3.7", "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", @@ -10706,17 +10710,6 @@ } } }, - "node_modules/use-debounce": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.4.tgz", - "integrity": "sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==", - "engines": { - "node": ">= 16.0.0" - }, - "peerDependencies": { - "react": "*" - } - }, "node_modules/use-isomorphic-layout-effect": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", diff --git a/client/package.json b/client/package.json index eb09381..7577677 100644 --- a/client/package.json +++ b/client/package.json @@ -11,7 +11,7 @@ "lint": "eslint ." }, "dependencies": { - "@metabase/embedding-sdk-react": "^0.54.11", + "@metabase/embedding-sdk-react": "^0.55.2-nightly", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/client/src/App.jsx b/client/src/App.jsx index cd6748a..ab43b60 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -10,7 +10,6 @@ import { // Configuration const config = defineMetabaseAuthConfig({ metabaseInstanceUrl: import.meta.env.VITE_METABASE_INSTANCE_URL, - authProviderUri: import.meta.env.VITE_AUTH_PROVIDER_URI, }); const questionId = 24; diff --git a/docker-compose.yml b/docker-compose.yml index 19ab51e..035f7f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: MB_JWT_SHARED_SECRET: "${METABASE_JWT_SHARED_SECRET}" MB_SETUP_TOKEN: "${PREMIUM_EMBEDDING_TOKEN}" MB_PREMIUM_EMBEDDING_TOKEN: "${PREMIUM_EMBEDDING_TOKEN}" + MB_JWT_IDENTITY_PROVIDER_URI: "http://localhost:${AUTH_PROVIDER_PORT}/sso/metabase" healthcheck: test: curl --fail -X GET -I "http://localhost:${MB_PORT}/api/health" || exit 1 interval: 15s @@ -30,12 +31,10 @@ services: dockerfile: ./client/Dockerfile args: VITE_METABASE_INSTANCE_URL: "http://localhost:${MB_PORT}" - VITE_AUTH_PROVIDER_URI: "http://localhost:${AUTH_PROVIDER_PORT}/sso/metabase" - WATCH: '${WATCH}' + WATCH: "${WATCH}" environment: CLIENT_PORT: "${CLIENT_PORT}" VITE_METABASE_INSTANCE_URL: "http://localhost:${MB_PORT}" - VITE_AUTH_PROVIDER_URI: "http://localhost:${AUTH_PROVIDER_PORT}/sso/metabase" ports: - "${CLIENT_PORT}:${CLIENT_PORT}" volumes: diff --git a/metabase/Dockerfile b/metabase/Dockerfile index a69fb57..d2250c1 100644 --- a/metabase/Dockerfile +++ b/metabase/Dockerfile @@ -1,4 +1,4 @@ -FROM metabase/metabase-enterprise:v1.54.x +FROM metabase/metabase-enterprise:v1.55.x COPY ./metabase /app/ COPY ./local-dist /app/local-dist diff --git a/server/index.js b/server/index.js index 1c380a6..e943001 100644 --- a/server/index.js +++ b/server/index.js @@ -1,21 +1,20 @@ -const express = require('express'); +const express = require("express"); const app = express(); -const dotenv = require('dotenv').config({ path: '../.env' }); -const cors = require('cors'); +const dotenv = require("dotenv").config({ path: "../.env" }); +const cors = require("cors"); const jwt = require("jsonwebtoken"); -app.get('/', (req, res) => { - res.send('Hello from our server!') -}) +app.get("/", (req, res) => { + res.send("Hello from our server!"); +}); -const AUTH_PROVIDER_PORT = process.env.AUTH_PROVIDER_PORT -const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL -const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET +const AUTH_PROVIDER_PORT = process.env.AUTH_PROVIDER_PORT; +const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL; +const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET; -app.use(cors({ credentials: true, origin:true })); //https://stackoverflow.com/a/66437447 +app.use(cors({ credentials: true, origin: true })); //https://stackoverflow.com/a/66437447 app.get("/sso/metabase", async (req, res) => { - // Usually, you would grab the user from the current session // Here it is hardcoded for demonstration purposes // Example: @@ -24,15 +23,15 @@ app.get("/sso/metabase", async (req, res) => { email: "rene@example.com", firstName: "Rene", lastName: "Descartes", - group: "Customer" - } + group: "Customer", + }; if (!user) { console.log("no user"); return res.status(401).json({ - status: 'error', - message: 'not authenticated', - }) + status: "error", + message: "not authenticated", + }); } const token = jwt.sign( @@ -44,28 +43,36 @@ app.get("/sso/metabase", async (req, res) => { exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration }, // This is the JWT signing secret in your Metabase JWT authentication setting - METABASE_JWT_SHARED_SECRET - ) - const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}` - console.log('Hitting MB SSO endpoint', ssoUrl); + METABASE_JWT_SHARED_SECRET, + ); + + if (req.query.response === "json") { + return res + .status(200) + .set("Content-Type", "application/json") + .send({ jwt: token }); + } + + const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?token=true&jwt=${token}`; + console.log("Hitting MB SSO endpoint", ssoUrl); try { - const response = await fetch(ssoUrl, { method: 'GET' }) - const session = await response.text() + const response = await fetch(ssoUrl, { method: "GET" }); + const session = await response.text(); - console.log("Received session", session) - return res.status(200).set("Content-Type", "application/json").end(session) + console.log("Received session", session); + return res.status(200).set("Content-Type", "application/json").end(session); } catch (error) { if (error instanceof Error) { res.status(401).json({ - status: 'error', - message: 'authentication failed', + status: "error", + message: "authentication failed", error: error.message, - }) + }); } } -}) +}); app.listen(AUTH_PROVIDER_PORT, () => { - console.log(`server listening on port ${AUTH_PROVIDER_PORT}`) -}) + console.log(`server listening on port ${AUTH_PROVIDER_PORT}`); +});