This commit is contained in:
parent
4656df7fca
commit
434536d1f2
149
package-lock.json
generated
149
package-lock.json
generated
@ -13,10 +13,9 @@
|
|||||||
"argon2": "^0.41.1",
|
"argon2": "^0.41.1",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"jose": "^6.0.10",
|
|
||||||
"lucide-react": "^0.485.0",
|
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"next": "15.2.4",
|
"next": "15.2.4",
|
||||||
|
"next-auth": "^5.0.0-beta.25",
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
@ -38,6 +37,46 @@
|
|||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@auth/core": {
|
||||||
|
"version": "0.37.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@auth/core/-/core-0.37.2.tgz",
|
||||||
|
"integrity": "sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@panva/hkdf": "^1.2.1",
|
||||||
|
"@types/cookie": "0.6.0",
|
||||||
|
"cookie": "0.7.1",
|
||||||
|
"jose": "^5.9.3",
|
||||||
|
"oauth4webapi": "^3.0.0",
|
||||||
|
"preact": "10.11.3",
|
||||||
|
"preact-render-to-string": "5.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@simplewebauthn/browser": "^9.0.1",
|
||||||
|
"@simplewebauthn/server": "^9.0.2",
|
||||||
|
"nodemailer": "^6.8.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@simplewebauthn/browser": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@simplewebauthn/server": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"nodemailer": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@auth/core/node_modules/jose": {
|
||||||
|
"version": "5.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
|
||||||
|
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.27.0",
|
"version": "7.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||||
@ -862,6 +901,15 @@
|
|||||||
"node": ">=12.4.0"
|
"node": ">=12.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@panva/hkdf": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@phc/format": {
|
"node_modules/@phc/format": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
|
||||||
@ -933,6 +981,12 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/cookie": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||||
@ -2028,6 +2082,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/cookie": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@ -3875,15 +3938,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jose": {
|
|
||||||
"version": "6.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.0.10.tgz",
|
|
||||||
"integrity": "sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/panva"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -4041,15 +4095,6 @@
|
|||||||
"loose-envify": "cli.js"
|
"loose-envify": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lucide-react": {
|
|
||||||
"version": "0.485.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.485.0.tgz",
|
|
||||||
"integrity": "sha512-NvyQJ0LKyyCxL23nPKESlr/jmz8r7fJO1bkuptSNYSy0s8VVj4ojhX0YAgmE1e0ewfxUZjIlZpvH+otfTnla8Q==",
|
|
||||||
"license": "ISC",
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/markdown-it": {
|
"node_modules/markdown-it": {
|
||||||
"version": "14.1.0",
|
"version": "14.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||||
@ -4216,6 +4261,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/next-auth": {
|
||||||
|
"version": "5.0.0-beta.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.25.tgz",
|
||||||
|
"integrity": "sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@auth/core": "0.37.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@simplewebauthn/browser": "^9.0.1",
|
||||||
|
"@simplewebauthn/server": "^9.0.2",
|
||||||
|
"next": "^14.0.0-0 || ^15.0.0-0",
|
||||||
|
"nodemailer": "^6.6.5",
|
||||||
|
"react": "^18.2.0 || ^19.0.0-0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@simplewebauthn/browser": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@simplewebauthn/server": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"nodemailer": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-addon-api": {
|
"node_modules/node-addon-api": {
|
||||||
"version": "8.3.1",
|
"version": "8.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
|
||||||
@ -4257,6 +4329,15 @@
|
|||||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/oauth4webapi": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-5lcbectYuzQHvh0Ni7Epvc13sMVq7BxWUlHEYHaNko64OA1hcats0Huq30vZjqCZULcVE/PZxAGGPansfRAWKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-assign": {
|
"node_modules/object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
@ -4581,6 +4662,28 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/preact": {
|
||||||
|
"version": "10.11.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
|
||||||
|
"integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/preact-render-to-string": {
|
||||||
|
"version": "5.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz",
|
||||||
|
"integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pretty-format": "^3.8.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"preact": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@ -4591,6 +4694,12 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pretty-format": {
|
||||||
|
"version": "3.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||||
|
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/prop-types": {
|
"node_modules/prop-types": {
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
"argon2": "^0.41.1",
|
"argon2": "^0.41.1",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"jose": "^6.0.10",
|
|
||||||
"lucide-react": "^0.485.0",
|
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"next": "15.2.4",
|
"next": "15.2.4",
|
||||||
|
"next-auth": "^5.0.0-beta.25",
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
2
src/app/api/auth/[...nextauth]/route.ts
Normal file
2
src/app/api/auth/[...nextauth]/route.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import { handlers } from "@/auth";
|
||||||
|
export const { GET, POST } = handlers;
|
@ -7,8 +7,8 @@ import React from "react";
|
|||||||
import PostSummary from "./PostSummary";
|
import PostSummary from "./PostSummary";
|
||||||
import Pagination from "./Pagination";
|
import Pagination from "./Pagination";
|
||||||
import TagOverview from "./TagOverview";
|
import TagOverview from "./TagOverview";
|
||||||
import { isLoggedIn } from "@/components/auth";
|
|
||||||
import ActionButtons from "./ActionButtons";
|
import ActionButtons from "./ActionButtons";
|
||||||
|
import { auth } from "@/auth";
|
||||||
|
|
||||||
export default async function Blog({
|
export default async function Blog({
|
||||||
params,
|
params,
|
||||||
@ -31,7 +31,7 @@ export default async function Blog({
|
|||||||
if (pageNumber > numberOfPages) {
|
if (pageNumber > numberOfPages) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
const loggedIn = await isLoggedIn();
|
const loggedIn = (await auth()) != null;
|
||||||
const tags = await getTags(loggedIn);
|
const tags = await getTags(loggedIn);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Form from "next/form";
|
|
||||||
import { handleLogin } from "./action";
|
|
||||||
|
|
||||||
export default function FormComponent() {
|
|
||||||
return (
|
|
||||||
<Form action={handleLogin}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "1rem",
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
Username:
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
style={{
|
|
||||||
height: "2rem",
|
|
||||||
backgroundColor: "#333",
|
|
||||||
borderStyle: "none",
|
|
||||||
color: "#eee",
|
|
||||||
fontSize: 16,
|
|
||||||
padding: "0.5rem 1rem",
|
|
||||||
}}
|
|
||||||
name="username"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
Password:
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
style={{
|
|
||||||
height: "2rem",
|
|
||||||
backgroundColor: "#333",
|
|
||||||
borderStyle: "none",
|
|
||||||
color: "#eee",
|
|
||||||
fontSize: 16,
|
|
||||||
padding: "0.5rem 1rem",
|
|
||||||
}}
|
|
||||||
name="password"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#333",
|
|
||||||
borderStyle: "none",
|
|
||||||
color: "#eee",
|
|
||||||
fontSize: "1rem",
|
|
||||||
padding: "0.5rem 1rem",
|
|
||||||
transition: "background-color 0.3s linear",
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
|
||||||
onMouseOver={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = "#444";
|
|
||||||
}}
|
|
||||||
onMouseOut={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = "#333";
|
|
||||||
}}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
import { PrismaClient } from "@prisma/client";
|
|
||||||
import argon2 from "argon2";
|
|
||||||
import { setSession } from "@/components/auth";
|
|
||||||
import { redirect, RedirectType } from "next/navigation";
|
|
||||||
|
|
||||||
export async function handleLogin(data: FormData) {
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
const username = data.get("username")?.toString();
|
|
||||||
const password = data.get("password")?.toString();
|
|
||||||
if (!username || !password) {
|
|
||||||
throw new Error("Missing username or password");
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await prisma.user.findUnique({ where: { username } });
|
|
||||||
if (!user) {
|
|
||||||
redirect("/blog/login?error=Invalid%20credentials", RedirectType.replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await argon2.verify(user.password, password)) {
|
|
||||||
setSession();
|
|
||||||
redirect("/blog/write", RedirectType.replace);
|
|
||||||
} else {
|
|
||||||
redirect("/blog/login?error=Invalid%20credentials", RedirectType.replace);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
import { isLoggedIn } from "@/components/auth";
|
|
||||||
import FormComponent from "./Form";
|
|
||||||
|
|
||||||
export default async function Login() {
|
|
||||||
if (await isLoggedIn()) {
|
|
||||||
redirect("/blog/write");
|
|
||||||
}
|
|
||||||
return <FormComponent />;
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getPost } from "../../action";
|
import { getPost } from "../../action";
|
||||||
import PostDisplay from "./PostDisplay";
|
import PostDisplay from "./PostDisplay";
|
||||||
import { isLoggedIn } from "@/components/auth";
|
import { auth } from "@/auth";
|
||||||
|
|
||||||
export default async function Post({
|
export default async function Post({
|
||||||
params,
|
params,
|
||||||
@ -13,7 +13,7 @@ export default async function Post({
|
|||||||
if (!post) {
|
if (!post) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
const loggedIn = await isLoggedIn();
|
const loggedIn = (await auth()) != null;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PostDisplay post={post} loggedIn={loggedIn} />
|
<PostDisplay post={post} loggedIn={loggedIn} />
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Post } from "../../types";
|
import { Post } from "../../types";
|
||||||
import Write from "../Write";
|
import Write from "../Write";
|
||||||
import { isLoggedIn } from "@/components/auth";
|
|
||||||
import { PrismaClient } from "@prisma/client";
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
import { auth, signIn } from "@/auth";
|
||||||
|
|
||||||
export default async function WritePage({
|
export default async function WritePage({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: Promise<{ slug: string[] | undefined }>;
|
params: Promise<{ slug: string[] | undefined }>;
|
||||||
}) {
|
}) {
|
||||||
if (!(await isLoggedIn())) {
|
if (!(await auth())) {
|
||||||
redirect("/blog/login");
|
signIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
const slug = (await params).slug?.[0];
|
const slug = (await params).slug?.[0];
|
||||||
|
@ -5,6 +5,7 @@ import MarkdownIt from "markdown-it";
|
|||||||
import hljs from "highlight.js";
|
import hljs from "highlight.js";
|
||||||
import * as cheerio from "cheerio";
|
import * as cheerio from "cheerio";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
import { auth } from "@/auth";
|
||||||
|
|
||||||
export async function savePostServer(
|
export async function savePostServer(
|
||||||
title: string,
|
title: string,
|
||||||
@ -13,6 +14,10 @@ export async function savePostServer(
|
|||||||
is_draft: boolean,
|
is_draft: boolean,
|
||||||
existingSlug?: string
|
existingSlug?: string
|
||||||
) {
|
) {
|
||||||
|
if (!(await auth())) {
|
||||||
|
throw new Error("Not authenticated");
|
||||||
|
}
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
const md = new MarkdownIt({
|
const md = new MarkdownIt({
|
||||||
|
6
src/auth.ts
Normal file
6
src/auth.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import NextAuth from "next-auth";
|
||||||
|
import Authentik from "next-auth/providers/authentik";
|
||||||
|
|
||||||
|
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||||
|
providers: [Authentik],
|
||||||
|
});
|
@ -1,49 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
import { jwtVerify, SignJWT } from "jose";
|
|
||||||
import { cookies } from "next/headers";
|
|
||||||
const SECRET_KEY = process.env.SESSION_SECRET;
|
|
||||||
const encodedKey = new TextEncoder().encode(SECRET_KEY);
|
|
||||||
|
|
||||||
export type SessionPayload = { admin: true };
|
|
||||||
|
|
||||||
export async function encrypt(payload: SessionPayload) {
|
|
||||||
return new SignJWT(payload)
|
|
||||||
.setProtectedHeader({ alg: "HS256" })
|
|
||||||
.setIssuedAt()
|
|
||||||
.setExpirationTime("7d")
|
|
||||||
.sign(encodedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function decrypt(
|
|
||||||
token: string | undefined = ""
|
|
||||||
): Promise<SessionPayload | null> {
|
|
||||||
try {
|
|
||||||
const { payload } = await jwtVerify(token, encodedKey, {
|
|
||||||
algorithms: ["HS256"],
|
|
||||||
});
|
|
||||||
return payload as SessionPayload;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function isLoggedIn(): Promise<boolean> {
|
|
||||||
const cookieStore = (await cookies()).get("session")?.value;
|
|
||||||
const session = await decrypt(cookieStore);
|
|
||||||
if (session != null && session.admin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function setSession(): Promise<void> {
|
|
||||||
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
|
||||||
(await cookies()).set("session", await encrypt({ admin: true }), {
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
expires: expiresAt,
|
|
||||||
sameSite: "lax",
|
|
||||||
path: "/",
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user