Remind the user who they are on the frontend
Diff
chartered-frontend/src/useAuth.tsx | 48 +++++++++++++++++++++++++++++++++++++-----------
chartered-frontend/src/pages/Login.tsx | 4 ----
chartered-frontend/src/pages/crate/Members.tsx | 7 +++++--
chartered-web/src/endpoints/web_api/auth/mod.rs | 3 +++
4 files changed, 41 insertions(+), 21 deletions(-)
@@ -8,12 +8,20 @@
providers: string[];
}
interface LoginResponse {
user_uuid: string;
key: string;
expires: number;
error?: string;
}
export interface AuthContext {
login: (username: string, password: string) => Promise<void>;
oauthLogin: (provider: string) => Promise<void>;
logout: () => Promise<void>;
getAuthKey: () => Promise<string | null>;
setAuth: ([string, string]) => any;
getUserUuid: () => Promise<string>;
handleLoginResponse: (json: LoginResponse) => any;
}
const authContext = createContext<AuthContext | null>(null);
@@ -32,12 +40,8 @@
try {
let result = await fetch(unauthenticatedEndpoint(`login/oauth/complete${location.search}`));
let json = await result.json();
if (json.error) {
throw new Error(json.error);
}
auth.setAuth([json.key, new Date(json.expires)]);
auth.handleLoginResponse(json);
} catch (err) {
setResult(
<Redirect to={{
@@ -58,15 +62,23 @@
function useProvideAuth(): AuthContext {
const [auth, setAuth] = useState(() => {
let authStorage = getAuthStorage();
return [authStorage.authKey, authStorage.expires];
return [authStorage.userUuid, authStorage.authKey, authStorage.expires];
});
useEffect(() => {
localStorage.setItem(
"charteredAuthentication",
JSON.stringify({ authKey: auth?.[0], expires: auth?.[1] })
JSON.stringify({ userUuid: auth?.[0], authKey: auth?.[1], expires: auth?.[2] })
);
}, [auth]);
const handleLoginResponse = (response: LoginResponse) => {
if (response.error) {
throw new Error(response.error);
}
setAuth([response.user_uuid, response.key, new Date(response.expires)]);
}
const login = async (username: string, password: string) => {
let res = await fetch(unauthenticatedEndpoint("login/password"), {
@@ -79,11 +91,7 @@
});
let json = await res.json();
if (json.error) {
throw new Error(json.error);
}
setAuth([json.key, new Date(json.expires)]);
handleLoginResponse(json);
};
const oauthLogin = async (provider: string) => {
@@ -109,7 +117,15 @@
};
const getAuthKey = () => {
if (auth?.[1] > new Date()) {
if (auth?.[2] > new Date()) {
return auth[1];
} else if (auth) {
return null;
}
};
const getUserUuid = () => {
if (auth?.[2] > new Date()) {
return auth[0];
} else if (auth) {
return null;
@@ -120,8 +136,9 @@
login,
logout,
getAuthKey,
getUserUuid,
oauthLogin,
setAuth,
handleLoginResponse,
};
}
@@ -129,6 +146,7 @@
const saved = localStorage.getItem("charteredAuthentication");
const initial = JSON.parse(saved);
return {
userUuid: initial?.userUuid || null,
authKey: initial?.authKey || null,
expires: initial?.expires ? new Date(initial.expires) : null,
};
@@ -55,10 +55,6 @@
await auth.oauthLogin(provider);
} catch (e) {
setError(e.message);
} finally {
if (isMountedRef.current) {
setLoading(null);
}
}
}
@@ -121,6 +121,7 @@
const [selectedPermissions, setSelectedPermissions] = useState(
member.permissions
);
const auth = useAuth();
const [deleting, setDeleting] = useState(false);
const [saving, setSaving] = useState(false);
const [error, setError] = useState(null);
@@ -218,8 +219,10 @@
<td className="align-middle">
<strong>{member.username}</strong>
{/*<br />
<em>(that's you!)</em>*/}
{auth.getUserUuid() === member.uuid ? <>
<br />
<em>(that's you!)</em>
</> : <></>}
</td>
{possiblePermissions && member.permissions ? (
@@ -8,6 +8,7 @@
use chartered_db::{
users::{User, UserSession},
ConnectionPool,
uuid::Uuid,
};
use futures::future::Future;
use serde::Serialize;
@@ -34,6 +35,7 @@
#[derive(Serialize)]
pub struct LoginResponse {
user_uuid: Uuid,
key: String,
expires: chrono::DateTime<chrono::Utc>,
}
@@ -62,6 +64,7 @@
.await?;
Ok(LoginResponse {
user_uuid: user.uuid.0,
key: key.session_key,
expires,
})