Auth context for frontend
This commit is contained in:
parent
9fa2872446
commit
4dfc3129e3
@ -1,13 +1,17 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content=
|
||||||
<title>Vite + React + TS</title>
|
"width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<title>Simponic's Friends</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div><script type="module" src="/src/main.tsx">
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
47
client/package-lock.json
generated
47
client/package-lock.json
generated
@ -8,8 +8,10 @@
|
|||||||
"name": "client",
|
"name": "client",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"chota": "^0.9.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
@ -774,6 +776,14 @@
|
|||||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@remix-run/router": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
"version": "15.7.5",
|
"version": "15.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||||
@ -899,6 +909,11 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chota": {
|
||||||
|
"version": "0.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chota/-/chota-0.9.2.tgz",
|
||||||
|
"integrity": "sha512-DmCHT/R+yMr/aYQuokkJeNIjknSgpMpM9mR0tDlqPu8A+lGo9TS/KFPpze5Q9PPrCWenp/VG7Y10usyNDoIygQ=="
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
@ -1234,6 +1249,36 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "6.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz",
|
||||||
|
"integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "6.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz",
|
||||||
|
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.5.0",
|
||||||
|
"react-router": "6.10.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||||
|
@ -9,8 +9,10 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"chota": "^0.9.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.28",
|
"@types/react": "^18.0.28",
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
#root {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 6em;
|
|
||||||
padding: 1.5em;
|
|
||||||
will-change: filter;
|
|
||||||
transition: filter 300ms;
|
|
||||||
}
|
|
||||||
.logo:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #646cffaa);
|
|
||||||
}
|
|
||||||
.logo.react:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
a:nth-of-type(2) .logo {
|
|
||||||
animation: logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.read-the-docs {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import reactLogo from "./assets/react.svg";
|
|
||||||
import viteLogo from "/vite.svg";
|
|
||||||
import "./App.css";
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
const [count, setCount] = useState(0);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="App">
|
|
||||||
<div>
|
|
||||||
<a href="https://vitejs.dev" target="_blank">
|
|
||||||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
|
||||||
</a>
|
|
||||||
<a href="https://reactjs.org" target="_blank">
|
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h1>Vite + React</h1>
|
|
||||||
<div className="card">
|
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
|
||||||
count is {count}
|
|
||||||
</button>
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.tsx</code> and save to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p className="read-the-docs">
|
|
||||||
Click on the Vite and React logos to learn more
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
104
client/src/context/authContext.tsx
Normal file
104
client/src/context/authContext.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import React, { useContext, useState, createContext, useEffect } from "react";
|
||||||
|
|
||||||
|
interface authContext {
|
||||||
|
signedIn: boolean;
|
||||||
|
setSignedIn: (signedIn: boolean) => void;
|
||||||
|
sessionOver: Date;
|
||||||
|
setSessionOver: (expiry: Date) => void;
|
||||||
|
friendId: number | null;
|
||||||
|
setFriendId: (newFriendId: number | null) => void;
|
||||||
|
friendName: string | null;
|
||||||
|
setFriendName: (newFriendName: string | null) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AuthContext = createContext<authContext>({
|
||||||
|
signedIn: false,
|
||||||
|
setSignedIn: () => null,
|
||||||
|
sessionOver: new Date(),
|
||||||
|
setSessionOver: () => null,
|
||||||
|
friendId: null,
|
||||||
|
setFriendId: () => null,
|
||||||
|
friendName: "",
|
||||||
|
setFriendName: () => null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useAuthContext = () => useContext(AuthContext);
|
||||||
|
|
||||||
|
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const [signedIn, setSignedIn] = useState<boolean>(false);
|
||||||
|
const [sessionOver, setSessionOver] = useState<Date>(new Date());
|
||||||
|
const [friendId, setFriendId] = useState<number | null>(null);
|
||||||
|
const [friendName, setFriendName] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (friendName) {
|
||||||
|
localStorage.setItem("friendName", friendName);
|
||||||
|
}
|
||||||
|
}, [friendName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (friendId) {
|
||||||
|
localStorage.setItem("friendId", friendId);
|
||||||
|
}
|
||||||
|
}, [friendId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let expiry: string | null | Date = localStorage.getItem("expiry");
|
||||||
|
if (expiry) {
|
||||||
|
expiry = new Date(expiry);
|
||||||
|
if (Date.now() < expiry.getTime()) {
|
||||||
|
setSignedIn(true);
|
||||||
|
setSessionOver(expiry);
|
||||||
|
((friendName) => {
|
||||||
|
if (friendName) {
|
||||||
|
setFriendName(friendName);
|
||||||
|
}
|
||||||
|
})(localStorage.getItem("friendName"));
|
||||||
|
|
||||||
|
((id) => {
|
||||||
|
if (id) {
|
||||||
|
setFriendId(parseInt(id, 10));
|
||||||
|
}
|
||||||
|
})(localStorage.getItem("friendId"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem("expiry", sessionOver.toISOString());
|
||||||
|
setTimeout(() => {
|
||||||
|
setSessionOver((sessionOver) => {
|
||||||
|
if (Date.now() >= sessionOver.getTime()) {
|
||||||
|
setSignedIn((signedIn) => {
|
||||||
|
if (signedIn) {
|
||||||
|
alert(
|
||||||
|
"Session expired. Any further privileged requests will fail until signed in again."
|
||||||
|
);
|
||||||
|
["friendId", "friendName"].map((x) => localStorage.removeItem(x));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return signedIn;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return sessionOver;
|
||||||
|
});
|
||||||
|
}, sessionOver.getTime() - Date.now());
|
||||||
|
}, [sessionOver]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider
|
||||||
|
value={{
|
||||||
|
signedIn,
|
||||||
|
setSignedIn,
|
||||||
|
sessionOver,
|
||||||
|
setSessionOver,
|
||||||
|
friendId,
|
||||||
|
setFriendId,
|
||||||
|
friendName,
|
||||||
|
setFriendName,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -1,10 +1,35 @@
|
|||||||
import React from 'react'
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from "react-dom/client";
|
||||||
import App from './App'
|
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||||
import './index.css'
|
import "chota";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
import { AuthProvider } from "./context/authContext";
|
||||||
|
|
||||||
|
import Root from "./routes/root";
|
||||||
|
import NotFound from "./routes/notFound";
|
||||||
|
import Login from "./routes/login";
|
||||||
|
import ProtectedRoute from "./routes/protected.tsx";
|
||||||
|
|
||||||
|
const router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
element: (
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Root />
|
||||||
|
</ProtectedRoute>
|
||||||
|
),
|
||||||
|
errorElement: <NotFound />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/login",
|
||||||
|
element: <Login />,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<AuthProvider>
|
||||||
</React.StrictMode>,
|
<RouterProvider router={router} />
|
||||||
)
|
</AuthProvider>
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
|
112
client/src/routes/login.tsx
Normal file
112
client/src/routes/login.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { useAuthContext } from "../context/authContext";
|
||||||
|
import "../styles/login.css";
|
||||||
|
|
||||||
|
const requestTokenSubmit = async (name) =>
|
||||||
|
fetch(
|
||||||
|
"/api/auth?" +
|
||||||
|
new URLSearchParams({
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
).then((r) => r.json());
|
||||||
|
|
||||||
|
const submitSignedToken = async (signature) =>
|
||||||
|
fetch("/api/auth", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
signature,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
const [token, setToken] = useState("");
|
||||||
|
const [errors, setErrors] = useState([]);
|
||||||
|
|
||||||
|
const { signedIn, setSignedIn, setSessionOver, setFriendId, setFriendName } =
|
||||||
|
useAuthContext();
|
||||||
|
|
||||||
|
const getTokenFormSubmission = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const { error, token } = await requestTokenSubmit(e.target.name.value);
|
||||||
|
if (error) {
|
||||||
|
setErrors([error]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setErrors([]);
|
||||||
|
setToken(token);
|
||||||
|
};
|
||||||
|
|
||||||
|
const signTokenFormSubmission = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const { error, token, expiration, friend } = await submitSignedToken(
|
||||||
|
e.target.signature.value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
setSignedIn(true);
|
||||||
|
setSessionOver(new Date(expiration));
|
||||||
|
setFriendId(friend.id.toString());
|
||||||
|
setFriendName(friend.name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors([error]);
|
||||||
|
};
|
||||||
|
if (signedIn) return <Navigate to="/" />;
|
||||||
|
if (!token)
|
||||||
|
return (
|
||||||
|
<div className="body-centered">
|
||||||
|
<form onSubmit={getTokenFormSubmission} autoComplete="off">
|
||||||
|
<div className="card">
|
||||||
|
<label htmlFor="name">Name</label>
|
||||||
|
<input id="name" name="name" />
|
||||||
|
{errors.length ? (
|
||||||
|
errors.map((error, i) => (
|
||||||
|
<div key={i} className="text-error">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button type="submit">Request Token</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="body-centered">
|
||||||
|
<div className="login card">
|
||||||
|
<div>Please sign the following payload with your PGP key:</div>
|
||||||
|
<code>{token}</code>
|
||||||
|
<hr />
|
||||||
|
<form onSubmit={signTokenFormSubmission}>
|
||||||
|
<textarea
|
||||||
|
id="signature"
|
||||||
|
name="signature"
|
||||||
|
rows="6"
|
||||||
|
placeholder="-----BEGIN PGP SIGNED MESSAGE-----"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{errors.length ? (
|
||||||
|
errors.map((error, i) => (
|
||||||
|
<div key={i} className="text-error">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button type="submit">Log In</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
3
client/src/routes/notFound.tsx
Normal file
3
client/src/routes/notFound.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function NotFound() {
|
||||||
|
return <h1>Not found</h1>;
|
||||||
|
}
|
10
client/src/routes/protected.tsx
Normal file
10
client/src/routes/protected.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { useAuthContext } from "../context/authContext";
|
||||||
|
|
||||||
|
export default function ProtectedRoute({ children }) {
|
||||||
|
const { signedIn } = useAuthContext();
|
||||||
|
|
||||||
|
if (!signedIn) return <Navigate to="/login" />;
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
10
client/src/routes/root.tsx
Normal file
10
client/src/routes/root.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Outlet } from "react-router-dom";
|
||||||
|
|
||||||
|
export default function Root() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Hello</h1>
|
||||||
|
<Outlet />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
15
client/src/styles/login.css
Normal file
15
client/src/styles/login.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.body-centered {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
@ -3,7 +3,7 @@ import {
|
|||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
Body,
|
Body,
|
||||||
Param,
|
Query,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
Res,
|
Res,
|
||||||
@ -20,6 +20,11 @@ export class LoginUserDTO {
|
|||||||
signature: string;
|
signature: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RetrieveTokenDTO {
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Controller('/auth')
|
@Controller('/auth')
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
constructor(private readonly authService: AuthService) {}
|
constructor(private readonly authService: AuthService) {}
|
||||||
@ -34,9 +39,9 @@ export class AuthController {
|
|||||||
return await this.authService.deleteToken(req.token);
|
return await this.authService.deleteToken(req.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('/:name')
|
@Get('/')
|
||||||
async retrieveGodToken(@Param('name') name: string) {
|
async retrieveGodToken(@Query() query: RetrieveTokenDTO) {
|
||||||
const friend = await this.authService.findFriendByName(name);
|
const friend = await this.authService.findFriendByName(query.name);
|
||||||
if (!friend) throw new NotFoundException('Friend not found with that name');
|
if (!friend) throw new NotFoundException('Friend not found with that name');
|
||||||
|
|
||||||
return await this.authService.createTokenForFriend(friend);
|
return await this.authService.createTokenForFriend(friend);
|
||||||
@ -78,7 +83,7 @@ export class AuthController {
|
|||||||
expires: referencedToken.expiration,
|
expires: referencedToken.expiration,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await this.authService.signToken(token);
|
return { ...(await this.authService.signToken(token)), friend };
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
|
Loading…
Reference in New Issue
Block a user