From c28d5f68b59c3e314d8ed6030687737caf3ebaa3 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 01:33:21 +0900 Subject: [PATCH 1/7] feat(web): support multi-tenant login --- web/src/App.tsx | 1 + web/src/auth/AuthProvider.tsx | 15 ++++--- web/src/aws-config.ts | 30 -------------- web/src/config/authInfo.ts | 56 ++++++++++++++++++++++++++ web/src/config/aws.ts | 31 ++++++++++++++ web/src/{config.ts => config/index.ts} | 26 +++++++++--- web/src/main.tsx | 1 - 7 files changed, 118 insertions(+), 42 deletions(-) delete mode 100644 web/src/aws-config.ts create mode 100644 web/src/config/authInfo.ts create mode 100644 web/src/config/aws.ts rename web/src/{config.ts => config/index.ts} (83%) diff --git a/web/src/App.tsx b/web/src/App.tsx index 35aa6c5ced..88f8d60451 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -34,6 +34,7 @@ const router = createBrowserRouter( createRoutesFromElements( <> } /> + } /> }> } /> } /> diff --git a/web/src/auth/AuthProvider.tsx b/web/src/auth/AuthProvider.tsx index 5096719338..fd6ce58dd2 100644 --- a/web/src/auth/AuthProvider.tsx +++ b/web/src/auth/AuthProvider.tsx @@ -1,6 +1,8 @@ import { Auth0Provider } from "@auth0/auth0-react"; import React, { createContext, ReactNode } from "react"; +import { getAuthInfo, getSignInCallbackUrl } from "@reearth-cms/config"; + import { useAuth0Auth } from "./Auth0Auth"; import AuthHook from "./AuthHook"; import { useCognitoAuth } from "./CognitoAuth"; @@ -18,12 +20,13 @@ const CognitoWrapper = ({ children }: { children: ReactNode }) => { }; export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const authProvider = window.REEARTH_CONFIG?.authProvider; + const authInfo = getAuthInfo(); + const authProvider = authInfo?.authProvider; if (authProvider === "auth0") { - const domain = window.REEARTH_CONFIG?.auth0Domain; - const clientId = window.REEARTH_CONFIG?.auth0ClientId; - const audience = window.REEARTH_CONFIG?.auth0Audience; + const domain = authInfo?.auth0Domain; + const clientId = authInfo?.auth0ClientId; + const audience = authInfo?.auth0Audience; return domain && clientId ? ( = ({ children useRefreshTokens scope="openid profile email" cacheLocation="localstorage" - redirectUri={window.location.origin}> + redirectUri={getSignInCallbackUrl()}> {children} ) : null; @@ -44,5 +47,5 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children return {children}; } - return <>{children}; // or some default fallback + return null; }; diff --git a/web/src/aws-config.ts b/web/src/aws-config.ts deleted file mode 100644 index 568db987ea..0000000000 --- a/web/src/aws-config.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Amplify } from "aws-amplify"; - -const authProvider = window.REEARTH_CONFIG?.authProvider; -if (authProvider === "cognito") { - const cognitoRegion = window.REEARTH_CONFIG?.cognitoRegion; - const cognitoUserPoolId = window.REEARTH_CONFIG?.cognitoUserPoolId; - const cognitoUserPoolWebClientId = window.REEARTH_CONFIG?.cognitoUserPoolWebClientId; - const cognitoOauthScope = window.REEARTH_CONFIG?.cognitoOauthScope?.split(", "); - const cognitoOauthDomain = window.REEARTH_CONFIG?.cognitoOauthDomain; - const cognitoOauthRedirectSignIn = window.REEARTH_CONFIG?.cognitoOauthRedirectSignIn; - const cognitoOauthRedirectSignOut = window.REEARTH_CONFIG?.cognitoOauthRedirectSignOut; - const cognitoOauthResponseType = window.REEARTH_CONFIG?.cognitoOauthResponseType; - - const config = { - Auth: { - region: cognitoRegion, - userPoolId: cognitoUserPoolId, - userPoolWebClientId: cognitoUserPoolWebClientId, - oauth: { - scope: cognitoOauthScope, - domain: cognitoOauthDomain, - redirectSignIn: cognitoOauthRedirectSignIn, - redirectSignOut: cognitoOauthRedirectSignOut, - responseType: cognitoOauthResponseType, - }, - }, - }; - - Amplify.configure(config); -} diff --git a/web/src/config/authInfo.ts b/web/src/config/authInfo.ts new file mode 100644 index 0000000000..4f6732d726 --- /dev/null +++ b/web/src/config/authInfo.ts @@ -0,0 +1,56 @@ +import { config, type CognitoParams } from "."; + +export type AuthInfo = { + auth0ClientId?: string; + auth0Domain?: string; + auth0Audience?: string; + authProvider?: string; + cognito?: CognitoParams; +}; + +export function getAuthInfo(conf = config()): AuthInfo | undefined { + return getMultitenantAuthInfo(conf) || defaultAuthInfo(conf); +} + +export function defaultAuthInfo(conf = config()): AuthInfo | undefined { + if (!conf) return; + return { + auth0Audience: conf.auth0Audience, + auth0ClientId: conf.auth0ClientId, + auth0Domain: conf.auth0Domain, + authProvider: conf.authProvider || "auth0", + cognito: conf.cognito, + }; +} + +export function getMultitenantAuthInfo(conf = config()): AuthInfo | undefined { + if (!conf?.multitenant) return; + const name = getTenantName(); + if (name) { + const tenant = conf.multitenant[name]; + if (tenant && !tenant.authProvider) { + tenant.authProvider = "auth0"; + } + return tenant; + } + return; +} + +export function getTenantName(): string | undefined { + const path = window.location.pathname; + if (path.startsWith("/auth/")) { + // e.g. /auth/tennant-name?code=xxx&state=xxx + const name = path.split("/")[2]; + return name; + } + return; +} + +export function getSignInCallbackUrl() { + const tenantName = getTenantName(); + if (tenantName) { + // multi-tenant + return `${window.location.origin}/auth/${tenantName}`; + } + return window.location.origin; +} diff --git a/web/src/config/aws.ts b/web/src/config/aws.ts new file mode 100644 index 0000000000..066140b079 --- /dev/null +++ b/web/src/config/aws.ts @@ -0,0 +1,31 @@ +import { Amplify } from "aws-amplify"; + +import { CognitoParams } from "."; + +export function configureCognito(cognito: CognitoParams) { + const cognitoRegion = cognito.cognitoRegion; + const cognitoUserPoolId = cognito.cognitoUserPoolId; + const cognitoUserPoolWebClientId = cognito.cognitoUserPoolWebClientId; + const cognitoOauthScope = cognito.cognitoOauthScope?.split(", "); + const cognitoOauthDomain = cognito.cognitoOauthDomain; + const cognitoOauthRedirectSignIn = cognito.cognitoOauthRedirectSignIn; + const cognitoOauthRedirectSignOut = cognito.cognitoOauthRedirectSignOut; + const cognitoOauthResponseType = cognito.cognitoOauthResponseType; + + const config = { + Auth: { + region: cognitoRegion, + userPoolId: cognitoUserPoolId, + userPoolWebClientId: cognitoUserPoolWebClientId, + oauth: { + scope: cognitoOauthScope, + domain: cognitoOauthDomain, + redirectSignIn: cognitoOauthRedirectSignIn, + redirectSignOut: cognitoOauthRedirectSignOut, + responseType: cognitoOauthResponseType, + }, + }, + }; + + Amplify.configure(config); +} diff --git a/web/src/config.ts b/web/src/config/index.ts similarity index 83% rename from web/src/config.ts rename to web/src/config/index.ts index 9799fecb11..14110de4fd 100644 --- a/web/src/config.ts +++ b/web/src/config/index.ts @@ -1,8 +1,26 @@ +import { getAuthInfo } from "./authInfo"; +import { configureCognito } from "./aws"; + +export { getAuthInfo, getSignInCallbackUrl } from "./authInfo"; + export type Config = { api: string; + logoUrl?: string; + coverImageUrl?: string; + cesiumIonAccessToken?: string; + editorUrl: string; + multitenant?: Record; +} & AuthInfo; + +export type AuthInfo = { auth0ClientId?: string; auth0Domain?: string; auth0Audience?: string; + authProvider?: string; + cognito?: CognitoParams; +} & CognitoParams; + +export type CognitoParams = { cognitoRegion?: string; cognitoUserPoolId?: string; cognitoUserPoolWebClientId?: string; @@ -11,11 +29,6 @@ export type Config = { cognitoOauthRedirectSignIn?: string; cognitoOauthRedirectSignOut?: string; cognitoOauthResponseType?: string; - authProvider?: string; - logoUrl?: string; - coverImageUrl?: string; - cesiumIonAccessToken?: string; - editorUrl: string; }; const env = import.meta.env; @@ -39,6 +52,9 @@ export default async function loadConfig() { ...defaultConfig, ...(await (await fetch("/reearth_config.json")).json()), }; + + const authInfo = getAuthInfo(window.REEARTH_CONFIG); + if (authInfo?.cognito) configureCognito(authInfo.cognito); } export function config(): Config | undefined { diff --git a/web/src/main.tsx b/web/src/main.tsx index cf558bf250..865e6e292c 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -11,7 +11,6 @@ import "./index.css"; try { await loadConfig(); } finally { - await import("./aws-config"); const element = document.getElementById("root"); if (element) { const root = ReactDOM.createRoot(element); From 4e7b18c20f97b28e788995b492755f4277a38900 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 01:35:50 +0900 Subject: [PATCH 2/7] memoize --- web/src/auth/AuthProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/auth/AuthProvider.tsx b/web/src/auth/AuthProvider.tsx index fd6ce58dd2..b2c419fa61 100644 --- a/web/src/auth/AuthProvider.tsx +++ b/web/src/auth/AuthProvider.tsx @@ -1,5 +1,5 @@ import { Auth0Provider } from "@auth0/auth0-react"; -import React, { createContext, ReactNode } from "react"; +import React, { createContext, ReactNode, useState } from "react"; import { getAuthInfo, getSignInCallbackUrl } from "@reearth-cms/config"; @@ -20,7 +20,7 @@ const CognitoWrapper = ({ children }: { children: ReactNode }) => { }; export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const authInfo = getAuthInfo(); + const [authInfo] = useState(() => getAuthInfo()); const authProvider = authInfo?.authProvider; if (authProvider === "auth0") { From a3b09137897e7a910064a1d579720603dac9d072 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 01:39:32 +0900 Subject: [PATCH 3/7] refactor type --- web/src/config/authInfo.ts | 6 ++++-- web/src/config/aws.ts | 11 ++++++++++- web/src/config/index.ts | 21 +-------------------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/web/src/config/authInfo.ts b/web/src/config/authInfo.ts index 4f6732d726..d3e95a5c09 100644 --- a/web/src/config/authInfo.ts +++ b/web/src/config/authInfo.ts @@ -1,4 +1,6 @@ -import { config, type CognitoParams } from "."; +import { type CognitoParams } from "./aws"; + +import { config } from "."; export type AuthInfo = { auth0ClientId?: string; @@ -6,7 +8,7 @@ export type AuthInfo = { auth0Audience?: string; authProvider?: string; cognito?: CognitoParams; -}; +} & CognitoParams; export function getAuthInfo(conf = config()): AuthInfo | undefined { return getMultitenantAuthInfo(conf) || defaultAuthInfo(conf); diff --git a/web/src/config/aws.ts b/web/src/config/aws.ts index 066140b079..a8baff7a55 100644 --- a/web/src/config/aws.ts +++ b/web/src/config/aws.ts @@ -1,6 +1,15 @@ import { Amplify } from "aws-amplify"; -import { CognitoParams } from "."; +export type CognitoParams = { + cognitoRegion?: string; + cognitoUserPoolId?: string; + cognitoUserPoolWebClientId?: string; + cognitoOauthScope?: string; + cognitoOauthDomain?: string; + cognitoOauthRedirectSignIn?: string; + cognitoOauthRedirectSignOut?: string; + cognitoOauthResponseType?: string; +}; export function configureCognito(cognito: CognitoParams) { const cognitoRegion = cognito.cognitoRegion; diff --git a/web/src/config/index.ts b/web/src/config/index.ts index 14110de4fd..eaab420b8e 100644 --- a/web/src/config/index.ts +++ b/web/src/config/index.ts @@ -1,4 +1,4 @@ -import { getAuthInfo } from "./authInfo"; +import { type AuthInfo, getAuthInfo } from "./authInfo"; import { configureCognito } from "./aws"; export { getAuthInfo, getSignInCallbackUrl } from "./authInfo"; @@ -12,25 +12,6 @@ export type Config = { multitenant?: Record; } & AuthInfo; -export type AuthInfo = { - auth0ClientId?: string; - auth0Domain?: string; - auth0Audience?: string; - authProvider?: string; - cognito?: CognitoParams; -} & CognitoParams; - -export type CognitoParams = { - cognitoRegion?: string; - cognitoUserPoolId?: string; - cognitoUserPoolWebClientId?: string; - cognitoOauthScope?: string; - cognitoOauthDomain?: string; - cognitoOauthRedirectSignIn?: string; - cognitoOauthRedirectSignOut?: string; - cognitoOauthResponseType?: string; -}; - const env = import.meta.env; export const defaultConfig: Config = { From 095687614b750c09e0cdbfc23e54ccc4d5d2c4ea Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 01:41:39 +0900 Subject: [PATCH 4/7] fix cognito --- web/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/config/index.ts b/web/src/config/index.ts index eaab420b8e..e6361256de 100644 --- a/web/src/config/index.ts +++ b/web/src/config/index.ts @@ -35,7 +35,7 @@ export default async function loadConfig() { }; const authInfo = getAuthInfo(window.REEARTH_CONFIG); - if (authInfo?.cognito) configureCognito(authInfo.cognito); + if (authInfo?.authProvider === "cognito") configureCognito(authInfo.cognito ?? authInfo); } export function config(): Config | undefined { From 1584620b491cd30ea3adcc5899043471da28fdb2 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 14:00:03 +0900 Subject: [PATCH 5/7] fix bugs --- web/.gitignore | 2 + web/src/App.tsx | 1 + web/src/auth/Auth0Auth.ts | 15 ++++-- web/src/auth/AuthProvider.tsx | 7 ++- web/src/auth/CognitoAuth.ts | 4 ++ web/src/components/pages/RootPage/index.tsx | 4 +- web/src/config/authInfo.ts | 55 ++++++++++++++------- web/src/config/index.ts | 24 ++------- web/vite.config.ts | 10 ++++ 9 files changed, 76 insertions(+), 46 deletions(-) diff --git a/web/.gitignore b/web/.gitignore index af242f0d5c..2b6ad9731d 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -25,6 +25,8 @@ dist-ssr /storybook-static /coverage +/reearth-config.json +.env* #amplify-do-not-edit-begin amplify/\#current-cloud-backend diff --git a/web/src/App.tsx b/web/src/App.tsx index 88f8d60451..60ffcb933b 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -36,6 +36,7 @@ const router = createBrowserRouter( } /> } /> }> + } /> } /> } /> } /> diff --git a/web/src/auth/Auth0Auth.ts b/web/src/auth/Auth0Auth.ts index 56dabff473..2abc6323aa 100644 --- a/web/src/auth/Auth0Auth.ts +++ b/web/src/auth/Auth0Auth.ts @@ -1,5 +1,7 @@ import { useAuth0 } from "@auth0/auth0-react"; +import { logOutFromTenant } from "@reearth-cms/config"; + import AuthHook from "./AuthHook"; export const errorKey = "reeartherror"; @@ -21,12 +23,17 @@ export const useAuth0Auth = (): AuthHook => { isLoading, error: error?.message ?? null, getAccessToken: () => getAccessTokenSilently(), - login: () => loginWithRedirect(), - logout: () => - logout({ + login: () => { + logOutFromTenant(); + return loginWithRedirect(); + }, + logout: () => { + logOutFromTenant(); + return logout({ returnTo: error ? `${window.location.origin}?${errorKey}=${encodeURIComponent(error?.message)}` : window.location.origin, - }), + }); + }, }; }; diff --git a/web/src/auth/AuthProvider.tsx b/web/src/auth/AuthProvider.tsx index b2c419fa61..56d8c9b1c2 100644 --- a/web/src/auth/AuthProvider.tsx +++ b/web/src/auth/AuthProvider.tsx @@ -1,7 +1,7 @@ import { Auth0Provider } from "@auth0/auth0-react"; import React, { createContext, ReactNode, useState } from "react"; -import { getAuthInfo, getSignInCallbackUrl } from "@reearth-cms/config"; +import { getAuthInfo, getSignInCallbackUrl, logInToTenant } from "@reearth-cms/config"; import { useAuth0Auth } from "./Auth0Auth"; import AuthHook from "./AuthHook"; @@ -20,7 +20,10 @@ const CognitoWrapper = ({ children }: { children: ReactNode }) => { }; export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const [authInfo] = useState(() => getAuthInfo()); + const [authInfo] = useState(() => { + logInToTenant(); // note that it includes side effect + return getAuthInfo(); + }); const authProvider = authInfo?.authProvider; if (authProvider === "auth0") { diff --git a/web/src/auth/CognitoAuth.ts b/web/src/auth/CognitoAuth.ts index bcfe763b46..fbd81a7989 100644 --- a/web/src/auth/CognitoAuth.ts +++ b/web/src/auth/CognitoAuth.ts @@ -1,6 +1,8 @@ import { Auth } from "@aws-amplify/auth"; import { useState, useEffect } from "react"; +import { logOutFromTenant } from "@reearth-cms/config"; + import AuthHook from "./AuthHook"; export const useCognitoAuth = (): AuthHook => { @@ -32,10 +34,12 @@ export const useCognitoAuth = (): AuthHook => { }; const login = () => { + logOutFromTenant(); Auth.federatedSignIn(); }; const logout = async () => { + logOutFromTenant(); try { await Auth.signOut(); setUser(null); diff --git a/web/src/components/pages/RootPage/index.tsx b/web/src/components/pages/RootPage/index.tsx index 1a493628b8..72aa3e9a08 100644 --- a/web/src/components/pages/RootPage/index.tsx +++ b/web/src/components/pages/RootPage/index.tsx @@ -18,10 +18,10 @@ const RootPage: React.FC = () => { if (isAuthenticated) { if (data?.me?.id) { if (currentWorkspaceId && currentUserId === data.me.id) { - navigate(`workspace/${currentWorkspaceId}`); + navigate(`/workspace/${currentWorkspaceId || ""}`); } else { setCurrentWorkspaceId(undefined); - navigate("workspace"); + navigate("/workspace"); } } } diff --git a/web/src/config/authInfo.ts b/web/src/config/authInfo.ts index d3e95a5c09..220415941c 100644 --- a/web/src/config/authInfo.ts +++ b/web/src/config/authInfo.ts @@ -2,6 +2,8 @@ import { type CognitoParams } from "./aws"; import { config } from "."; +const tenantKey = "reearth_tennant"; + export type AuthInfo = { auth0ClientId?: string; auth0Domain?: string; @@ -14,7 +16,27 @@ export function getAuthInfo(conf = config()): AuthInfo | undefined { return getMultitenantAuthInfo(conf) || defaultAuthInfo(conf); } -export function defaultAuthInfo(conf = config()): AuthInfo | undefined { +export function getSignInCallbackUrl() { + const tenantName = getTenantName(); + if (tenantName) { + // multi-tenant + return `${window.location.origin}/auth/${tenantName}`; + } + return window.location.origin; +} + +export function logInToTenant() { + const tenantName = getLogginInTenantName(); + if (tenantName) { + window.localStorage.setItem(tenantKey, tenantName); + } +} + +export function logOutFromTenant() { + window.localStorage.removeItem(tenantKey); +} + +function defaultAuthInfo(conf = config()): AuthInfo | undefined { if (!conf) return; return { auth0Audience: conf.auth0Audience, @@ -25,11 +47,11 @@ export function defaultAuthInfo(conf = config()): AuthInfo | undefined { }; } -export function getMultitenantAuthInfo(conf = config()): AuthInfo | undefined { - if (!conf?.multitenant) return; +function getMultitenantAuthInfo(conf = config()): AuthInfo | undefined { + if (!conf?.multiTenant) return; const name = getTenantName(); if (name) { - const tenant = conf.multitenant[name]; + const tenant = conf.multiTenant[name]; if (tenant && !tenant.authProvider) { tenant.authProvider = "auth0"; } @@ -38,21 +60,20 @@ export function getMultitenantAuthInfo(conf = config()): AuthInfo | undefined { return; } -export function getTenantName(): string | undefined { - const path = window.location.pathname; - if (path.startsWith("/auth/")) { - // e.g. /auth/tennant-name?code=xxx&state=xxx - const name = path.split("/")[2]; - return name; +function getTenantName(): string | null { + const loggingInTenantName = getLogginInTenantName(); + if (loggingInTenantName) { + return loggingInTenantName; } - return; + return window.localStorage.getItem(tenantKey); } -export function getSignInCallbackUrl() { - const tenantName = getTenantName(); - if (tenantName) { - // multi-tenant - return `${window.location.origin}/auth/${tenantName}`; +function getLogginInTenantName(): string | null { + const path = window.location.pathname; + // /auth/ + if (path.startsWith("/auth/")) { + const name = path.split("/")[2]; + return name || null; } - return window.location.origin; + return null; } diff --git a/web/src/config/index.ts b/web/src/config/index.ts index e6361256de..5867f6f97b 100644 --- a/web/src/config/index.ts +++ b/web/src/config/index.ts @@ -1,7 +1,7 @@ import { type AuthInfo, getAuthInfo } from "./authInfo"; import { configureCognito } from "./aws"; -export { getAuthInfo, getSignInCallbackUrl } from "./authInfo"; +export { getAuthInfo, getSignInCallbackUrl, logInToTenant, logOutFromTenant } from "./authInfo"; export type Config = { api: string; @@ -9,7 +9,7 @@ export type Config = { coverImageUrl?: string; cesiumIonAccessToken?: string; editorUrl: string; - multitenant?: Record; + multiTenant?: Record; } & AuthInfo; const env = import.meta.env; @@ -48,25 +48,7 @@ export function e2eAccessToken(): string | undefined { declare global { interface Window { - REEARTH_CONFIG?: { - api: string; - auth0ClientId?: string; - auth0Domain?: string; - auth0Audience?: string; - cognitoRegion?: string; - cognitoUserPoolId?: string; - cognitoUserPoolWebClientId?: string; - cognitoOauthScope?: string; - cognitoOauthDomain?: string; - cognitoOauthRedirectSignIn?: string; - cognitoOauthRedirectSignOut?: string; - cognitoOauthResponseType?: string; - authProvider?: string; - logoUrl?: string; - coverImageUrl?: string; - cesiumIonAccessToken?: string; - editorUrl: string; - }; + REEARTH_CONFIG?: Config; REEARTH_E2E_ACCESS_TOKEN?: string; } } diff --git a/web/vite.config.ts b/web/vite.config.ts index 10a18989d4..91f3b30266 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -70,8 +70,18 @@ function config(): Plugin { return { name: "reearth-config", async configureServer(server) { + const envs = loadEnv( + server.config.mode, + server.config.envDir ?? process.cwd(), + server.config.envPrefix, + ); + const remoteReearthConfig = envs.REEARTH_WEB_CONFIG_URL + ? await (await fetch(envs.REEARTH_WEB_CONFIG_URL)).json() + : {}; const configRes = JSON.stringify( { + ...remoteReearthConfig, + api: "http://localhost:8080/api", ...readEnv("REEARTH_CMS", { source: loadEnv( server.config.mode, From 30ae360dbece03a5549af5024a7d42627ab2b83b Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 14:16:06 +0900 Subject: [PATCH 6/7] pretty print config, mask db url --- server/go.mod | 1 + server/go.sum | 2 + server/internal/app/config.go | 150 +++++++++++-------- server/internal/infrastructure/gcp/config.go | 10 +- 4 files changed, 92 insertions(+), 71 deletions(-) diff --git a/server/go.mod b/server/go.mod index 4f4666764d..8a01cad7d8 100644 --- a/server/go.mod +++ b/server/go.mod @@ -104,6 +104,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/opts v1.2.3 // indirect + github.com/k0kubun/pp/v3 v3.2.0 // indirect github.com/klauspost/compress v1.17.5 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/server/go.sum b/server/go.sum index 4e772bb001..89fe8e9046 100644 --- a/server/go.sum +++ b/server/go.sum @@ -243,6 +243,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/jpillora/opts v1.2.3 h1:Q0YuOM7y0BlunHJ7laR1TUxkUA7xW8A2rciuZ70xs8g= github.com/jpillora/opts v1.2.3/go.mod h1:7p7X/vlpKZmtaDFYKs956EujFqA6aCrOkcCaS6UBcR4= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= +github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs= +github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= diff --git a/server/internal/app/config.go b/server/internal/app/config.go index e72f4e5945..4a8284ef85 100644 --- a/server/internal/app/config.go +++ b/server/internal/app/config.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/joho/godotenv" + "github.com/k0kubun/pp/v3" "github.com/kelseyhightower/envconfig" "github.com/reearth/reearth-cms/server/internal/infrastructure/aws" "github.com/reearth/reearth-cms/server/internal/infrastructure/gcp" @@ -17,51 +18,55 @@ import ( const configPrefix = "REEARTH_CMS" +func init() { + pp.Default.SetColoringEnabled(false) +} + type Config struct { - Port string `default:"8080" envconfig:"PORT"` - ServerHost string - Host string `default:"http://localhost:8080"` - Dev bool - Host_Web string - GraphQL GraphQLConfig - Origins []string - DB string `default:"mongodb://localhost"` - Mailer string - SMTP SMTPConfig - SendGrid SendGridConfig - SignupSecret string - GCS GCSConfig - S3 S3Config - Task gcp.TaskConfig - AWSTask aws.TaskConfig - AssetBaseURL string - Web map[string]string - Web_Config JSON - Web_Disabled bool + Port string `default:"8080" envconfig:"PORT"` + ServerHost string `pp:",omitempty"` + Host string `default:"http://localhost:8080"` + Dev bool `pp:",omitempty"` + Host_Web string `pp:",omitempty"` + GraphQL GraphQLConfig `pp:",omitempty"` + Origins []string `pp:",omitempty"` + DB string `default:"mongodb://localhost"` + Mailer string `pp:",omitempty"` + SMTP SMTPConfig `pp:",omitempty"` + SendGrid SendGridConfig `pp:",omitempty"` + SignupSecret string `pp:",omitempty"` + GCS GCSConfig `pp:",omitempty"` + S3 S3Config `pp:",omitempty"` + Task gcp.TaskConfig `pp:",omitempty"` + AWSTask aws.TaskConfig `pp:",omitempty"` + AssetBaseURL string `pp:",omitempty"` + Web map[string]string `pp:",omitempty"` + Web_Config JSON `pp:",omitempty"` + Web_Disabled bool `pp:",omitempty"` // auth - Auth AuthConfigs - Auth0 Auth0Config - Cognito CognitoConfig - Auth_ISS string - Auth_AUD string - Auth_ALG *string - Auth_TTL *int - Auth_ClientID *string - Auth_JWKSURI *string + Auth AuthConfigs `pp:",omitempty"` + Auth0 Auth0Config `pp:",omitempty"` + Cognito CognitoConfig `pp:",omitempty"` + Auth_ISS string `pp:",omitempty"` + Auth_AUD string `pp:",omitempty"` + Auth_ALG *string `pp:",omitempty"` + Auth_TTL *int `pp:",omitempty"` + Auth_ClientID *string `pp:",omitempty"` + Auth_JWKSURI *string `pp:",omitempty"` // auth for m2m - AuthM2M AuthM2MConfig + AuthM2M AuthM2MConfig `pp:",omitempty"` - DB_Account string - DB_Users []appx.NamedURI + DB_Account string `pp:",omitempty"` + DB_Users []appx.NamedURI `pp:",omitempty"` } type AuthConfig struct { - ISS string - AUD []string - ALG *string - TTL *int - ClientID *string - JWKSURI *string + ISS string `pp:",omitempty"` + AUD []string `pp:",omitempty"` + ALG *string `pp:",omitempty"` + TTL *int `pp:",omitempty"` + ClientID *string `pp:",omitempty"` + JWKSURI *string `pp:",omitempty"` } type GraphQLConfig struct { @@ -71,50 +76,50 @@ type GraphQLConfig struct { type AuthConfigs []AuthConfig type Auth0Config struct { - Domain string - Audience string - ClientID string - ClientSecret string - WebClientID string + Domain string `pp:",omitempty"` + Audience string `pp:",omitempty"` + ClientID string `pp:",omitempty"` + ClientSecret string `pp:",omitempty"` + WebClientID string `pp:",omitempty"` } type CognitoConfig struct { - UserPoolID string - Region string - ClientID string + UserPoolID string `pp:",omitempty"` + Region string `pp:",omitempty"` + ClientID string `pp:",omitempty"` } type SendGridConfig struct { - Email string - Name string - API string + Email string `pp:",omitempty"` + Name string `pp:",omitempty"` + API string `pp:",omitempty"` } type SMTPConfig struct { - Host string - Port string - SMTPUsername string - Email string - Password string + Host string `pp:",omitempty"` + Port string `pp:",omitempty"` + SMTPUsername string `pp:",omitempty"` + Email string `pp:",omitempty"` + Password string `pp:",omitempty"` } type GCSConfig struct { - BucketName string - PublicationCacheControl string + BucketName string `pp:",omitempty"` + PublicationCacheControl string `pp:",omitempty"` } type S3Config struct { - BucketName string - PublicationCacheControl string + BucketName string `pp:",omitempty"` + PublicationCacheControl string `pp:",omitempty"` } type AuthM2MConfig struct { - ISS string - AUD []string - ALG *string - TTL *int - Email string - JWKSURI *string + ISS string `pp:",omitempty"` + AUD []string `pp:",omitempty"` + ALG *string `pp:",omitempty"` + TTL *int `pp:",omitempty"` + Email string `pp:",omitempty"` + JWKSURI *string `pp:",omitempty"` } func (c *Config) Auths() (res AuthConfigs) { @@ -290,13 +295,26 @@ func ReadConfig(debug bool) (*Config, error) { } func (c *Config) Print() string { - s := fmt.Sprintf("%+v", c) - for _, secret := range []string{c.DB, c.Auth0.ClientSecret} { + s := pp.Sprint(c) + + for _, secret := range c.secrets() { if secret == "" { continue } s = strings.ReplaceAll(s, secret, "***") } + + return s +} + +func (c *Config) secrets() []string { + s := []string{ + c.DB, + c.Auth0.ClientSecret, + } + for _, d := range c.DB_Users { + s = append(s, d.URI) + } return s } diff --git a/server/internal/infrastructure/gcp/config.go b/server/internal/infrastructure/gcp/config.go index c4552c70df..09c246f883 100644 --- a/server/internal/infrastructure/gcp/config.go +++ b/server/internal/infrastructure/gcp/config.go @@ -1,11 +1,11 @@ package gcp type TaskConfig struct { - GCPProject string - GCPRegion string - Topic string - GCSHost string - GCSBucket string + GCPProject string `pp:",omitempty"` + GCPRegion string `pp:",omitempty"` + Topic string `pp:",omitempty"` + GCSHost string `pp:",omitempty"` + GCSBucket string `pp:",omitempty"` DecompressorImage string `default:"reearth/reearth-cms-decompressor"` DecompressorTopic string `default:"decompress"` DecompressorGzipExt string `default:"gml"` From bc8b8022546f959bdfaf2f8f92c3ce4d4a5133fa Mon Sep 17 00:00:00 2001 From: rot1024 Date: Mon, 18 Mar 2024 18:05:22 +0900 Subject: [PATCH 7/7] fix --- server/go.mod | 2 +- web/src/App.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/go.mod b/server/go.mod index 8a01cad7d8..850e8e9236 100644 --- a/server/go.mod +++ b/server/go.mod @@ -21,6 +21,7 @@ require ( github.com/hallazzang/echo-compose v1.0.1 github.com/jarcoal/httpmock v1.3.1 github.com/joho/godotenv v1.5.1 + github.com/k0kubun/pp/v3 v3.2.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/labstack/echo/v4 v4.11.4 github.com/oapi-codegen/runtime v1.1.1 @@ -104,7 +105,6 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/opts v1.2.3 // indirect - github.com/k0kubun/pp/v3 v3.2.0 // indirect github.com/klauspost/compress v1.17.5 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/web/src/App.tsx b/web/src/App.tsx index 60ffcb933b..77855b64f4 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -33,8 +33,8 @@ import { Provider as I18nProvider } from "@reearth-cms/i18n"; const router = createBrowserRouter( createRoutesFromElements( <> - } /> - } /> + } /> + } /> }> } /> } />