enzostvs HF Staff commited on
Commit
3d6f13d
·
1 Parent(s): c3a6273

UI for not authorized domain

Browse files
Files changed (2) hide show
  1. app/layout.tsx +2 -16
  2. components/not-authorized.tsx +124 -26
app/layout.tsx CHANGED
@@ -2,7 +2,6 @@ import type { Metadata, Viewport } from "next";
2
  import { Geist, Geist_Mono } from "next/font/google";
3
  import { NextStepProvider } from "nextstepjs";
4
  import Script from "next/script";
5
- import { headers } from "next/headers";
6
 
7
  import "@/app/globals.css";
8
  import { ThemeProvider } from "@/components/providers/theme";
@@ -10,7 +9,6 @@ import { AuthProvider } from "@/components/providers/session";
10
  import { Toaster } from "@/components/ui/sonner";
11
  import { ReactQueryProvider } from "@/components/providers/react-query";
12
  import { generateSEO, generateStructuredData } from "@/lib/seo";
13
- import { ALLOWED_DOMAINS } from "@/lib/utils";
14
  import { NotAuthorizedDomain } from "@/components/not-authorized";
15
 
16
  const geistSans = Geist({
@@ -56,13 +54,6 @@ export default async function RootLayout({
56
  }: Readonly<{
57
  children: React.ReactNode;
58
  }>) {
59
- const headersList = await headers();
60
- const hostname = (
61
- headersList.get("x-forwarded-host") ??
62
- headersList.get("host") ??
63
- ""
64
- ).split(":")[0];
65
-
66
  const structuredData = generateStructuredData("WebApplication", {
67
  name: "DeepSite",
68
  description: "Build websites with AI, no code required",
@@ -73,8 +64,6 @@ export default async function RootLayout({
73
  url: "https://huggingface.co/deepsite",
74
  });
75
 
76
- const isAllowedDomain = ALLOWED_DOMAINS.includes(hostname);
77
-
78
  return (
79
  <html lang="en" suppressHydrationWarning>
80
  <body
@@ -107,11 +96,8 @@ export default async function RootLayout({
107
  disableTransitionOnChange
108
  >
109
  <NextStepProvider>
110
- {isAllowedDomain ? (
111
- children
112
- ) : (
113
- <NotAuthorizedDomain hostname={hostname} />
114
- )}
115
  </NextStepProvider>
116
  </ThemeProvider>
117
  </ReactQueryProvider>
 
2
  import { Geist, Geist_Mono } from "next/font/google";
3
  import { NextStepProvider } from "nextstepjs";
4
  import Script from "next/script";
 
5
 
6
  import "@/app/globals.css";
7
  import { ThemeProvider } from "@/components/providers/theme";
 
9
  import { Toaster } from "@/components/ui/sonner";
10
  import { ReactQueryProvider } from "@/components/providers/react-query";
11
  import { generateSEO, generateStructuredData } from "@/lib/seo";
 
12
  import { NotAuthorizedDomain } from "@/components/not-authorized";
13
 
14
  const geistSans = Geist({
 
54
  }: Readonly<{
55
  children: React.ReactNode;
56
  }>) {
 
 
 
 
 
 
 
57
  const structuredData = generateStructuredData("WebApplication", {
58
  name: "DeepSite",
59
  description: "Build websites with AI, no code required",
 
64
  url: "https://huggingface.co/deepsite",
65
  });
66
 
 
 
67
  return (
68
  <html lang="en" suppressHydrationWarning>
69
  <body
 
96
  disableTransitionOnChange
97
  >
98
  <NextStepProvider>
99
+ {children}
100
+ <NotAuthorizedDomain />
 
 
 
101
  </NextStepProvider>
102
  </ThemeProvider>
103
  </ReactQueryProvider>
components/not-authorized.tsx CHANGED
@@ -1,33 +1,131 @@
 
 
1
  import Image from "next/image";
2
  import { Button } from "./ui/button";
3
  import Link from "next/link";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- export const NotAuthorizedDomain = ({ hostname }: { hostname: string }) => {
6
  return (
7
- <section className="h-screen w-full flex items-center justify-center">
8
- <div className="max-w-md text-center p-6">
9
- <Image
10
- src="/logo.svg"
11
- alt="DeepSite"
12
- width={48}
13
- height={48}
14
- className="mb-6 mx-auto"
15
- />
16
- <h1 className="text-3xl font-bold mb-4">Access Denied</h1>
17
- <p className="text-lg text-muted-foreground mb-6">
18
- Unfortunately, you don&apos;t have access to DeepSite from this
19
- domain:{" "}
20
- <span className="font-mono font-semibold bg-indigo-500/10 border-2 border-indigo-500/10 text-indigo-500 text-base px-2 py-1 rounded-md">
21
- {hostname}
22
- </span>
23
- .
24
- </p>
25
- <Link href="https://huggingface.co/deepsite" target="_blank">
26
- <Button size="lg" className="text-base!">
27
- Go to DeepSite
28
- </Button>
29
- </Link>
30
- </div>
31
- </section>
 
 
 
 
 
 
32
  );
33
  };
 
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
  import Image from "next/image";
4
  import { Button } from "./ui/button";
5
  import Link from "next/link";
6
+ import { useMount } from "react-use";
7
+
8
+ import { Dialog, DialogContent, DialogTitle } from "./ui/dialog";
9
+
10
+ export const NotAuthorizedDomain = () => {
11
+ const [open, setOpen] = useState(false);
12
+
13
+ useMount(() => {
14
+ const isAllowedDomain = (hostname: string) => {
15
+ const host = hostname.toLowerCase();
16
+ return (
17
+ host.endsWith(".huggingface.co") ||
18
+ host.endsWith(".hf.co") ||
19
+ host === "huggingface.co" ||
20
+ host === "hf.co" ||
21
+ host === "enzostvs-deepsite.hf.space" ||
22
+ host === "huggingface.co/deepsite"
23
+ );
24
+ };
25
+
26
+ const isInIframe = () => {
27
+ try {
28
+ return window.self !== window.top;
29
+ } catch {
30
+ return true;
31
+ }
32
+ };
33
+
34
+ const isEmbedded = () => {
35
+ try {
36
+ return window.location !== window.parent.location;
37
+ } catch {
38
+ return true;
39
+ }
40
+ };
41
+
42
+ const addCanonicalUrl = () => {
43
+ const existingCanonical = document.querySelector('link[rel="canonical"]');
44
+ if (existingCanonical) {
45
+ existingCanonical.remove();
46
+ }
47
+
48
+ const canonical = document.createElement("link");
49
+ canonical.rel = "canonical";
50
+ canonical.href = window.location.href;
51
+ document.head.appendChild(canonical);
52
+
53
+ if (isInIframe() || isEmbedded()) {
54
+ try {
55
+ const parentHostname = document.referrer
56
+ ? new URL(document.referrer).hostname
57
+ : null;
58
+ if (parentHostname && !isAllowedDomain(parentHostname)) {
59
+ const noIndexMeta = document.createElement("meta");
60
+ noIndexMeta.name = "robots";
61
+ noIndexMeta.content = "noindex, nofollow";
62
+ document.head.appendChild(noIndexMeta);
63
+ }
64
+ } catch (error) {
65
+ console.debug(
66
+ "SEO: Could not determine parent domain for iframe indexing rules"
67
+ );
68
+ }
69
+ }
70
+ };
71
+
72
+ const shouldShowWarning = () => {
73
+ if (!isInIframe() && !isEmbedded()) {
74
+ return false; // Not in an iframe
75
+ }
76
+
77
+ try {
78
+ const parentHostname = window.parent.location.hostname;
79
+ return !isAllowedDomain(parentHostname);
80
+ } catch {
81
+ try {
82
+ if (document.referrer) {
83
+ const referrerUrl = new URL(document.referrer);
84
+ return !isAllowedDomain(referrerUrl.hostname);
85
+ }
86
+ } catch {}
87
+ return true;
88
+ }
89
+ };
90
+
91
+ addCanonicalUrl();
92
+
93
+ if (shouldShowWarning()) {
94
+ setOpen(true);
95
+ }
96
+ });
97
 
 
98
  return (
99
+ <Dialog open={open}>
100
+ <DialogContent
101
+ showCloseButton={false}
102
+ className="lg:min-w-4xl w-full rounded-3xl! p-0! overflow-hidden"
103
+ >
104
+ <DialogTitle className="hidden" />
105
+ <div className="max-w-md mx-auto text-center px-6 py-12">
106
+ <Image
107
+ src="/logo.svg"
108
+ alt="DeepSite"
109
+ width={48}
110
+ height={48}
111
+ className="mb-6 mx-auto"
112
+ />
113
+ <h1 className="text-3xl font-bold mb-4">Access Denied</h1>
114
+ <p className="text-lg text-muted-foreground mb-6">
115
+ Unfortunately, you don&apos;t have access to DeepSite from this
116
+ domain:{" "}
117
+ <span className="font-mono font-semibold bg-indigo-500/10 border-2 border-indigo-500/10 text-indigo-500 text-base px-2 py-1 rounded-md">
118
+ {window.location.hostname}
119
+ </span>
120
+ .
121
+ </p>
122
+ <Link href="https://huggingface.co/deepsite" target="_blank">
123
+ <Button size="lg" className="text-base!">
124
+ Go to DeepSite
125
+ </Button>
126
+ </Link>
127
+ </div>
128
+ </DialogContent>
129
+ </Dialog>
130
  );
131
  };