mirror of
https://github.com/umami-software/umami.git
synced 2025-12-08 05:12:36 +01:00
Allow embedding of share page.
This commit is contained in:
parent
9cb6046844
commit
eda2c07ea3
10 changed files with 58 additions and 39 deletions
|
|
@ -3,29 +3,32 @@ require('dotenv').config();
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const pkg = require('./package.json');
|
const pkg = require('./package.json');
|
||||||
|
|
||||||
const contentSecurityPolicy = `
|
const contentSecurityPolicy = [
|
||||||
default-src 'self';
|
`default-src 'self'`,
|
||||||
img-src *;
|
`img-src *`,
|
||||||
script-src 'self' 'unsafe-eval' 'unsafe-inline';
|
`script-src 'self' 'unsafe-eval' 'unsafe-inline'`,
|
||||||
style-src 'self' 'unsafe-inline';
|
`style-src 'self' 'unsafe-inline'`,
|
||||||
connect-src 'self' api.umami.is;
|
`connect-src 'self' api.umami.is`,
|
||||||
frame-ancestors 'self' ${process.env.ALLOWED_FRAME_URLS};
|
];
|
||||||
`;
|
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
{
|
{
|
||||||
key: 'X-DNS-Prefetch-Control',
|
key: 'X-DNS-Prefetch-Control',
|
||||||
value: 'on',
|
value: 'on',
|
||||||
},
|
},
|
||||||
{
|
!process.env.ALLOWED_FRAME_URLS && {
|
||||||
key: 'X-Frame-Options',
|
key: 'X-Frame-Options',
|
||||||
value: 'SAMEORIGIN',
|
value: 'SAMEORIGIN',
|
||||||
},
|
},
|
||||||
{
|
].filter(n => n);
|
||||||
key: 'Content-Security-Policy',
|
|
||||||
value: contentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(),
|
const cspHeader = (values = []) => ({
|
||||||
},
|
key: 'Content-Security-Policy',
|
||||||
];
|
value: [...contentSecurityPolicy, ...values]
|
||||||
|
.join(';')
|
||||||
|
.replace(/\s{2,}/g, ' ')
|
||||||
|
.trim(),
|
||||||
|
});
|
||||||
|
|
||||||
if (process.env.FORCE_SSL) {
|
if (process.env.FORCE_SSL) {
|
||||||
headers.push({
|
headers.push({
|
||||||
|
|
@ -81,14 +84,13 @@ const config = {
|
||||||
reactStrictMode: false,
|
reactStrictMode: false,
|
||||||
env: {
|
env: {
|
||||||
basePath: basePath || '',
|
basePath: basePath || '',
|
||||||
cloudMode: !!process.env.CLOUD_MODE,
|
cloudMode: process.env.CLOUD_MODE || '',
|
||||||
cloudUrl: process.env.CLOUD_URL,
|
cloudUrl: process.env.CLOUD_URL || '',
|
||||||
configUrl: '/config',
|
configUrl: '/config',
|
||||||
currentVersion: pkg.version,
|
currentVersion: pkg.version,
|
||||||
defaultLocale: process.env.DEFAULT_LOCALE,
|
defaultLocale: process.env.DEFAULT_LOCALE || '',
|
||||||
disableLogin: process.env.DISABLE_LOGIN,
|
disableLogin: process.env.DISABLE_LOGIN || '',
|
||||||
disableUI: process.env.DISABLE_UI,
|
disableUI: process.env.DISABLE_UI || '',
|
||||||
isProduction: process.env.NODE_ENV === 'production',
|
|
||||||
},
|
},
|
||||||
basePath,
|
basePath,
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
|
|
@ -125,7 +127,14 @@ const config = {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
source: '/:path*',
|
source: '/:path*',
|
||||||
headers,
|
headers: [
|
||||||
|
...headers,
|
||||||
|
cspHeader([`frame-ancestors 'self' ${process.env.ALLOWED_FRAME_URLS || ''}`]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/share/:path*',
|
||||||
|
headers: [...headers, cspHeader()],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { usePathname } from 'next/navigation';
|
||||||
import UpdateNotice from 'components/common/UpdateNotice';
|
import UpdateNotice from 'components/common/UpdateNotice';
|
||||||
import { useRequireLogin, useConfig } from 'components/hooks';
|
import { useRequireLogin, useConfig } from 'components/hooks';
|
||||||
|
|
||||||
export function Shell({ children }) {
|
export function App({ children }) {
|
||||||
const { user } = useRequireLogin();
|
const { user } = useRequireLogin();
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
@ -24,4 +24,4 @@ export function Shell({ children }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Shell;
|
export default App;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Dashboard from 'app/(main)/dashboard/Dashboard';
|
import Dashboard from 'app/(main)/dashboard/Dashboard';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function DashboardPage() {
|
export default function () {
|
||||||
return <Dashboard />;
|
return <Dashboard />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import Shell from './Shell';
|
import App from './App';
|
||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
import styles from './layout.module.css';
|
import styles from './layout.module.css';
|
||||||
|
|
||||||
export default function AppLayout({ children }) {
|
export default function ({ children }) {
|
||||||
return (
|
return (
|
||||||
<Shell>
|
<App>
|
||||||
<main className={styles.layout}>
|
<main className={styles.layout}>
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
<NavBar />
|
<NavBar />
|
||||||
|
|
@ -14,6 +14,6 @@ export default function AppLayout({ children }) {
|
||||||
<Page>{children}</Page>
|
<Page>{children}</Page>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</Shell>
|
</App>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
import useCache from 'store/cache';
|
import useCache from 'store/cache';
|
||||||
|
|
||||||
export default function ReportsDataTable({ websiteId }) {
|
export default function ReportsDataTable({ websiteId }: { websiteId?: string }) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const modified = useCache(state => state?.reports);
|
const modified = useCache(state => (state as any)?.reports);
|
||||||
const queryResult = useFilterQuery(['reports', { websiteId, modified }], params =>
|
const queryResult = useFilterQuery(['reports', { websiteId, modified }], params =>
|
||||||
get(websiteId ? `/websites/${websiteId}/reports` : `/reports`, params),
|
get(websiteId ? `/websites/${websiteId}/reports` : `/reports`, params),
|
||||||
);
|
);
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import ReportsHeader from './ReportsHeader';
|
import ReportsHeader from './ReportsHeader';
|
||||||
import ReportsDataTable from './ReportsDataTable';
|
import ReportsDataTable from './ReportsDataTable';
|
||||||
|
|
||||||
export default function ReportsPage() {
|
export default function () {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ReportsHeader />
|
<ReportsHeader />
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@ import 'styles/locale.css';
|
||||||
import 'styles/index.css';
|
import 'styles/index.css';
|
||||||
import 'styles/variables.css';
|
import 'styles/variables.css';
|
||||||
|
|
||||||
export default function RootLayout({ children }) {
|
export default function ({ children }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" data-scroll="0">
|
<html lang="en" data-scroll="0">
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" href={`/favicon.ico`} />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href={`/apple-touch-icon.png`} />
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href={`/favicon-32x32.png`} />
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href={`/favicon-16x16.png`} />
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||||
<link rel="manifest" href={`/site.webmanifest`} />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<link rel="mask-icon" href={`/safari-pinned-tab.svg`} color="#5bbad5" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
|
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
|
||||||
<meta name="theme-color" content="#2f2f2f" media="(prefers-color-scheme: dark)" />
|
<meta name="theme-color" content="#2f2f2f" media="(prefers-color-scheme: dark)" />
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import Logout from './Logout';
|
import Logout from './Logout';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return <Logout />;
|
return <Logout />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Logout | umami',
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import Share from './Share';
|
import Share from './Share';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ params: { id } }) {
|
export default function ({ params: { id } }) {
|
||||||
return <Share shareId={id[0]} />;
|
return <Share shareId={id[0]} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'umami',
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
||||||
await useCors(req, res);
|
await useCors(req, res);
|
||||||
|
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) {
|
if (!process.env.DISABLE_BOT_CHECK && isbot(req.headers['user-agent'])) {
|
||||||
return ok(res);
|
return ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue