Skip to content

Commit

Permalink
Merge pull request #22 from kovarike/website-feature
Browse files Browse the repository at this point in the history
set api
  • Loading branch information
kovarike authored Sep 11, 2024
2 parents e09096a + 0939509 commit 700b5a2
Show file tree
Hide file tree
Showing 18 changed files with 800 additions and 102 deletions.
11 changes: 6 additions & 5 deletions apps/algorithms/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const config = {
ignoreBuildErrors: true,
},
images: {
domains: ['img.shields.io', 'github-readme-stats.vercel.app'],
remotePatterns: [
{
protocol: "https",
Expand All @@ -26,11 +27,11 @@ const config = {
},
async redirects() {
return [
// {
// source: "/",
// destination: "/profile",
// permanent: true,
// },
{
source: "/admin",
destination: "/login",
permanent: true,
},
// {
// source: "/admin",
// destination: "/profile",
Expand Down
67 changes: 67 additions & 0 deletions apps/algorithms/src/api/lib/alth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// "use setver"
// import { IncomingMessage } from 'http';
// import { NextApiRequest, NextApiResponse } from 'next';
// import cookies from 'next-cookies';
// import jwt, { JwtPayload } from 'jsonwebtoken';
// import { v4 as uuidv4 } from 'uuid';

// const secret = process.env.JWT_SECRET || uuidv4(); // Gerando UUID se não houver segredo no .env

// interface AuthPayload extends JwtPayload {
// userId: string;
// email: string;
// }


// export const isAuthenticated = (req: IncomingMessage): AuthPayload | null => {
// const allCookies = cookies({ req }); // Usa next-cookies para obter todos os cookies
// const token = allCookies['auth-token']

// if (!token) return null;

// try {
// return jwt.verify(token, secret) as AuthPayload;
// } catch (error) {
// console.error('JWT verification failed:', error);
// return null;
// }
// };




import { NextApiRequest, NextApiResponse } from 'next';
import jwt from 'jsonwebtoken';
import { v4 as uuidv4 } from 'uuid';

const secret = process.env.JWT_SECRET || uuidv4();

interface AuthPayload {
userId: string;
email: string;
}

export const login = async (req: NextApiRequest, res: NextApiResponse) => {
const { email, password } = req.body;

if (email === '[email protected]' && password === 'password123') {
const token = jwt.sign({ email, userId: '1' }, secret, { expiresIn: '1h' });
res.setHeader('Set-Cookie', `auth-token=${token}; Path=/; HttpOnly`);
return res.status(200).json({ success: true });
} else {
return res.status(401).json({ success: false, message: 'Invalid credentials' });
}
};

export const isAuthenticated = (req: NextApiRequest): AuthPayload | null => {
const token = req.cookies['auth-token'];
if (!token) return null;

try {
return jwt.verify(token, secret) as AuthPayload;
} catch (error) {
console.error('Invalid token:', error);
return null;
}
};

26 changes: 26 additions & 0 deletions apps/algorithms/src/api/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
import { v4 as uuidv4 } from 'uuid';

const secret = process.env.JWT_SECRET || uuidv4(); // Gera um UUID se o segredo não for definido

export function middleware(req: NextRequest) {
const token = req.cookies.get('auth-token')?.value;

if (!token) {
return NextResponse.redirect(new URL('/login', req.url));
}

try {
jwt.verify(token, secret);
return NextResponse.next(); // Usuário autenticado, permite continuar
} catch (error) {
return NextResponse.redirect(new URL('/login', req.url)); // Redireciona se o JWT for inválido
}
}

export const config = {
matcher: '/admin/:path*', // Aplica a middleware apenas em rotas que começam com /admin
};
36 changes: 36 additions & 0 deletions apps/algorithms/src/api/routers/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// pages/api/login.ts
import { NextApiRequest, NextApiResponse } from 'next';
import jwt from 'jsonwebtoken';
import cookie from 'cookie';

const secret = process.env.JWT_SECRET || 'seu-segredo-super-seguro';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { id, password } = req.body;

// Validação simples (substitua com sua lógica de autenticação)
if (id === '[email protected]' && password === '123456') {
// Gerar um token JWT
const token = jwt.sign({ id }, secret, { expiresIn: '1h' });

// Configurar o token nos cookies
res.setHeader(
'Set-Cookie',
cookie.serialize('auth-token', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 3600,
sameSite: 'strict',
path: '/',
})
);

return res.status(200).json({ message: 'Login successful' });
}

return res.status(401).json({ message: 'Invalid credentials' });
}

return res.status(405).json({ message: 'Method not allowed' });
}
100 changes: 78 additions & 22 deletions apps/algorithms/src/app/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,86 @@
import { Container } from "@/components/container";
import { ContainerFull } from "@/components/containerfull";
import { Doilog } from "@/components/dailog";
import { Footer } from "@/components/footer";
import { Header } from "@/components/header";
import { Login } from "@/components/login";
// import { GetServerSideProps } from 'next';

// import { Container } from "@/components/container";
// import { ContainerFull } from "@/components/containerfull";
// import { Footer } from "@/components/footer";
// import { Header } from "@/components/header";
// import { isAuthenticated } from '@/api/lib/alth';



// export default function PageAdmin() {
// return (
// <>
// <ContainerFull>
// <Header />
// <Container>
// <h2 className="text-center">Administração</h2>
// <form action="#" className="mx-auto flex items-center flex-col">
// <input className="w-60 p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc]" type="text" name="postTitle" placeholder="Título do Post" required />
// <textarea className="w-full p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc] resize-none" name="postContent" rows={10} placeholder="Conteúdo do Post" required></textarea>
// <button className="w-20 p-2 text-gray-600 bg-algorithms-color/20 hover:bg-algorithms-color/45 rounded-md text-center cursor-pointer" type="submit">Publicar</button>
// </form>

// </Container>
// <Footer />
// </ContainerFull>
// </>
// );
// }

// export const getServerSideProps: GetServerSideProps = async (context) => {
// const user = isAuthenticated(context.req);

// if (!user) {
// return {
// redirect: {
// destination: '/login',
// permanent: false,
// },
// };
// }

// return {
// props: {},
// };
// };


// src/app/admin/page.tsx
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation'; // Para redirecionar no App Router
import cookies from 'js-cookie';
import jwt from 'jsonwebtoken';

export default function PageAdmin() {
const router = useRouter();

useEffect(() => {
const token = String(cookies.get('auth-token'));
const secret = process.env.NEXT_PUBLIC_JWT_SECRET || 'default-secret';

if (!token) {
router.push('/login');
}

try {
jwt.verify(token, secret);
} catch (error) {
console.error('Invalid token, redirecting...');
router.push('/login');
}
}, [router]);

return (
<>
<ContainerFull>
<Header />
<Container>
<h2 className="text-center">Administração</h2>
<form action="#" className="mx-auto flex items-center flex-col">
<input className="w-60 p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc]" type="text" name="postTitle" placeholder="Título do Post" required />
<textarea className="w-full p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc] resize-none" name="postContent" rows={10} placeholder="Conteúdo do Post" required></textarea>
<button className="w-20 p-2 text-gray-600 bg-algorithms-color/20 hover:bg-algorithms-color/45 rounded-md text-center cursor-pointer" type="submit">Publicar</button>
</form>

</Container>
<Doilog>
<Login />
</Doilog>
<Footer />
</ContainerFull>
<h2 className="text-center">Administração</h2>
<form action="#" className="mx-auto flex items-center flex-col">
<input className="w-60 p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc]" type="text" name="postTitle" placeholder="Título do Post" required />
<textarea className="w-full p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc] resize-none" name="postContent" rows={10} placeholder="Conteúdo do Post" required></textarea>
<button className="w-20 p-2 text-gray-600 bg-algorithms-color/20 hover:bg-algorithms-color/45 rounded-md text-center cursor-pointer" type="submit">Publicar</button>
</form>
</>
);
}
11 changes: 11 additions & 0 deletions apps/algorithms/src/app/api/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// pages/api/login.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { login } from '@/api/lib/alth';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
return await login(req, res);
} else {
return res.status(405).json({ message: 'Method not allowed' });
}
}
12 changes: 12 additions & 0 deletions apps/algorithms/src/app/api/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { isAuthenticated } from '@/api/lib/alth';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
const user = isAuthenticated(req);

if (!user) {
return res.status(401).json({ message: 'Unauthorized' });
}

return res.status(200).json({ user });
}
2 changes: 1 addition & 1 deletion apps/algorithms/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default function RootLayout({
<link rel="canonical" href="https://algorithmss.com.br" />
</head>

<body className={`${inter.className} bg-zinc-950`}>{children}</body>
<body className={`${inter.className} bg-zinc-950 h-screen`}>{children}</body>
</html>
);
}
52 changes: 52 additions & 0 deletions apps/algorithms/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client"

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Doilog } from "@/components/dailog";
import { Container } from "@/components/container";

interface DataProps extends FormData {
id: string,
password: string
}


export default function Home() {
const [id, setId] = useState('');
const [password, setPassword] = useState('');
const router = useRouter();

const handleLogin = async (data: DataProps) => {
setId(data.id)
setPassword(data.password)

const response = await fetch('/api/routers/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id, password }),
});

if (response.ok) {
router.push('/admin'); // Redireciona para a página de admin após o login bem-sucedido.
} else {
alert('Invalid credentials');
}
};

return (
<Doilog>
<Container>
<div className="flex flex-col items-center space-y-5 mx-auto" >
<h2 className="text-center font-algorithms-font font-semibold text-lg">Login</h2>
<form action="#" className="mx-auto flex items-center flex-col space-y-5" >
<input className="w-60 p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc]" type="text" name="id" placeholder="Id" required />
<input className="w-60 p-2 my-2 mx-0 rounded-md border-[1px] border-[#ccc]" type="password" name="password" placeholder="Password" required />
<button className="w-20 p-2 text-gray-600 bg-algorithms-color/20 hover:bg-algorithms-color/45 rounded-md text-center cursor-pointer" type="submit">Entrar</button>
</form>
</div>
</Container>
</Doilog>
)
}
4 changes: 2 additions & 2 deletions apps/algorithms/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Toaster } from "sonner";
export default function Home() {
return (
<>
<div className="h-screen w-full px-4 sm:px-6 md:px-8 lg:px-10 xl:px-12 mx-auto max-w-7xl bg-zinc-950 text-white" >
<ContainerFull >
<Header>
<Link href="https://github.com/kovarike" name="GitHub" />
<Link href="https://algorithmss.com.br/profile" name="Portfolio" />
Expand All @@ -38,7 +38,7 @@ export default function Home() {
/>
<Loading layoutId="1" messagem="Carregando..." /> */}
<Footer />
</div>
</ContainerFull>
<Toaster />
</>
);
Expand Down
3 changes: 3 additions & 0 deletions apps/algorithms/src/app/profile/id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use server"
import { v4 as uuidv4 } from "uuid";
export const id = uuidv4();
Loading

0 comments on commit 700b5a2

Please sign in to comment.