diff --git a/deno.json b/deno.json
index 8b2a01d5..3b9ab95f 100644
--- a/deno.json
+++ b/deno.json
@@ -6,7 +6,8 @@
"test": "deno test"
},
"imports": {
- "@/": "./src/"
+ "@/": "./src/",
+ "react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime"
},
"lint": {
"include": ["src/"],
@@ -23,5 +24,9 @@
"semiColons": true,
"singleQuote": true,
"proseWrap": "preserve"
+ },
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "jsxImportSource": "react"
}
}
\ No newline at end of file
diff --git a/src/controllers/api/oauth.ts b/src/controllers/api/oauth.ts
index fae3e883..9e557d0b 100644
--- a/src/controllers/api/oauth.ts
+++ b/src/controllers/api/oauth.ts
@@ -1,5 +1,7 @@
import { z } from '@/deps.ts';
import { AppController } from '@/app.ts';
+import OAuthPage from '@/pages/oauth.tsx';
+import { renderPage } from '@/pages/mod.tsx';
import { parseBody } from '@/utils.ts';
const passwordGrantSchema = z.object({
@@ -48,31 +50,10 @@ const oauthController: AppController = (c) => {
const redirectUri = decodeURIComponent(encodedUri);
- // Poor man's XSS check.
- // TODO: Render form with JSX.
- try {
- new URL(redirectUri);
- } catch (_e) {
- return c.text('Invalid `redirect_uri`.', 422);
- }
-
c.res.headers.set('content-security-policy', 'default-src \'self\'');
// TODO: Login with `window.nostr` (NIP-07).
- return c.html(`
-
-
- Log in with Ditto
-
-
-
-
-
- `);
+ return c.html(renderPage(OAuthPage({ redirectUri })));
};
const oauthAuthorizeController: AppController = async (c) => {
diff --git a/src/deps.ts b/src/deps.ts
index 14a6adc6..0f629f6c 100644
--- a/src/deps.ts
+++ b/src/deps.ts
@@ -32,3 +32,7 @@ import 'npm:linkify-plugin-hashtag@^4.1.0';
export { default as mime } from 'npm:mime@^3.0.0';
export { unfurl } from 'npm:unfurl.js@^6.3.1';
export { default as TTLCache } from 'npm:@isaacs/ttlcache@^1.4.0';
+// @deno-types="npm:@types/react@18.2.6"
+export { default as React } from 'npm:react@^18.2.0';
+// @deno-types="npm:@types/react-dom@18.2.4/server"
+export { renderToString } from 'npm:react-dom@^18.2.0/server';
diff --git a/src/pages/layout.tsx b/src/pages/layout.tsx
new file mode 100644
index 00000000..0514825d
--- /dev/null
+++ b/src/pages/layout.tsx
@@ -0,0 +1,22 @@
+import { React } from '@/deps.ts';
+
+interface ILayout {
+ title: string;
+ children: React.ReactNode;
+}
+
+const Layout: React.FC = ({ children, title }) => {
+ return (
+
+
+ {title}
+
+
+
+ {children}
+
+
+ );
+};
+
+export default Layout;
diff --git a/src/pages/mod.tsx b/src/pages/mod.tsx
new file mode 100644
index 00000000..ad40cac8
--- /dev/null
+++ b/src/pages/mod.tsx
@@ -0,0 +1,7 @@
+import { React, renderToString } from '@/deps.ts';
+
+function renderPage(page: React.ReactNode): string {
+ return '' + renderToString(<>{page}>);
+}
+
+export { renderPage };
diff --git a/src/pages/oauth.tsx b/src/pages/oauth.tsx
new file mode 100644
index 00000000..e4ec52c3
--- /dev/null
+++ b/src/pages/oauth.tsx
@@ -0,0 +1,20 @@
+import { React } from '@/deps.ts';
+import Layout from './layout.tsx';
+
+interface IOAuthPage {
+ redirectUri: string;
+}
+
+const OAuthPage: React.FC = ({ redirectUri }) => {
+ return (
+
+
+
+ );
+};
+
+export default OAuthPage;