Always authenticate user by registering temp guest accounts

This commit is contained in:
Robert Long
2021-12-14 18:25:52 -08:00
parent 38eb5e7c2e
commit 34f8023a4e
4 changed files with 130 additions and 213 deletions

View File

@@ -65,6 +65,32 @@ async function initClient(clientOptions, guest) {
return client; return client;
} }
async function registerGuest(homeserverUrl) {
const registrationClient = matrix.createClient(homeserverUrl);
const { user_id, device_id, access_token } =
await registrationClient.registerGuest({});
const client = await initClient(
{
baseUrl: homeserverUrl,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
},
true
);
await client.setDisplayName(`Guest ${client.getUserIdLocalpart()}`);
localStorage.setItem(
"matrix-auth-store",
JSON.stringify({ user_id, device_id, access_token, guest: true })
);
return client;
}
export async function fetchGroupCall( export async function fetchGroupCall(
client, client,
roomIdOrAlias, roomIdOrAlias,
@@ -103,26 +129,15 @@ export async function fetchGroupCall(
export function ClientProvider({ homeserverUrl, children }) { export function ClientProvider({ homeserverUrl, children }) {
const history = useHistory(); const history = useHistory();
const [ const [{ loading, isPasswordlessUser, isGuest, client, userName }, setState] =
{ useState({
loading, loading: true,
isAuthenticated, isPasswordlessUser: false,
isPasswordlessUser, isGuest: false,
isGuest, client: undefined,
client, userName: null,
userName, displayName: null,
displayName, });
},
setState,
] = useState({
loading: true,
isAuthenticated: false,
isPasswordlessUser: false,
isGuest: false,
client: undefined,
userName: null,
displayName: null,
});
useEffect(() => { useEffect(() => {
async function restore() { async function restore() {
@@ -156,8 +171,13 @@ export function ClientProvider({ homeserverUrl, children }) {
return { client, guest, passwordlessUser }; return { client, guest, passwordlessUser };
} }
} catch (err) {
localStorage.removeItem("matrix-auth-store");
}
return { client: undefined, guest: false }; try {
const client = await registerGuest(homeserverUrl);
return { client, guest: true, passwordlessUser: false };
} catch (err) { } catch (err) {
localStorage.removeItem("matrix-auth-store"); localStorage.removeItem("matrix-auth-store");
throw err; throw err;
@@ -169,17 +189,16 @@ export function ClientProvider({ homeserverUrl, children }) {
setState({ setState({
client, client,
loading: false, loading: false,
isAuthenticated: !!client,
isPasswordlessUser: !!passwordlessUser, isPasswordlessUser: !!passwordlessUser,
isGuest: guest, isGuest: guest,
userName: client?.getUserIdLocalpart(), userName: client?.getUserIdLocalpart(),
}); });
}) })
.catch(() => { .catch((error) => {
setState({ setState({
error,
client: undefined, client: undefined,
loading: false, loading: false,
isAuthenticated: false,
isPasswordlessUser: false, isPasswordlessUser: false,
isGuest: false, isGuest: false,
userName: null, userName: null,
@@ -188,156 +207,82 @@ export function ClientProvider({ homeserverUrl, children }) {
}, []); }, []);
const login = useCallback(async (homeserver, username, password) => { const login = useCallback(async (homeserver, username, password) => {
try { let loginHomeserverUrl = homeserver.trim();
let loginHomeserverUrl = homeserver.trim();
if (!loginHomeserverUrl.includes("://")) { if (!loginHomeserverUrl.includes("://")) {
loginHomeserverUrl = "https://" + loginHomeserverUrl; loginHomeserverUrl = "https://" + loginHomeserverUrl;
}
try {
const wellKnownUrl = new URL(
"/.well-known/matrix/client",
window.location
);
const response = await fetch(wellKnownUrl);
const config = await response.json();
if (config["m.homeserver"]) {
loginHomeserverUrl = config["m.homeserver"];
} }
} catch (error) {}
try { const registrationClient = matrix.createClient(loginHomeserverUrl);
const wellKnownUrl = new URL(
"/.well-known/matrix/client",
window.location
);
const response = await fetch(wellKnownUrl);
const config = await response.json();
if (config["m.homeserver"]) { const { user_id, device_id, access_token } =
loginHomeserverUrl = config["m.homeserver"]; await registrationClient.loginWithPassword(username, password);
}
} catch (error) {}
const registrationClient = matrix.createClient(loginHomeserverUrl); const client = await initClient({
baseUrl: loginHomeserverUrl,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
});
const { user_id, device_id, access_token } = localStorage.setItem(
await registrationClient.loginWithPassword(username, password); "matrix-auth-store",
JSON.stringify({ user_id, device_id, access_token })
);
const client = await initClient({ setState({
baseUrl: loginHomeserverUrl, client,
accessToken: access_token, loading: false,
userId: user_id, isPasswordlessUser: false,
deviceId: device_id, isGuest: false,
}); userName: client.getUserIdLocalpart(),
});
localStorage.setItem( return client;
"matrix-auth-store",
JSON.stringify({ user_id, device_id, access_token })
);
setState({
client,
loading: false,
isAuthenticated: true,
isPasswordlessUser: false,
isGuest: false,
userName: client.getUserIdLocalpart(),
});
} catch (err) {
localStorage.removeItem("matrix-auth-store");
setState({
client: undefined,
loading: false,
isAuthenticated: false,
isPasswordlessUser: false,
isGuest: false,
userName: null,
});
throw err;
}
}, []);
const registerGuest = useCallback(async () => {
try {
const registrationClient = matrix.createClient(homeserverUrl);
const { user_id, device_id, access_token } =
await registrationClient.registerGuest({});
const client = await initClient(
{
baseUrl: homeserverUrl,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
},
true
);
await client.setProfileInfo("displayname", {
displayname: `Guest ${client.getUserIdLocalpart()}`,
});
localStorage.setItem(
"matrix-auth-store",
JSON.stringify({ user_id, device_id, access_token, guest: true })
);
setState({
client,
loading: false,
isAuthenticated: true,
isGuest: true,
isPasswordlessUser: false,
userName: client.getUserIdLocalpart(),
});
} catch (err) {
localStorage.removeItem("matrix-auth-store");
setState({
client: undefined,
loading: false,
isAuthenticated: false,
isPasswordlessUser: false,
isGuest: false,
userName: null,
});
throw err;
}
}, []); }, []);
const register = useCallback(async (username, password, passwordlessUser) => { const register = useCallback(async (username, password, passwordlessUser) => {
try { const registrationClient = matrix.createClient(homeserverUrl);
const registrationClient = matrix.createClient(homeserverUrl);
const { user_id, device_id, access_token } = const { user_id, device_id, access_token } =
await registrationClient.register(username, password, null, { await registrationClient.register(username, password, null, {
type: "m.login.dummy", type: "m.login.dummy",
});
const client = await initClient({
baseUrl: homeserverUrl,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
}); });
localStorage.setItem( const client = await initClient({
"matrix-auth-store", baseUrl: homeserverUrl,
JSON.stringify({ user_id, device_id, access_token, passwordlessUser }) accessToken: access_token,
); userId: user_id,
deviceId: device_id,
});
setState({ localStorage.setItem(
client, "matrix-auth-store",
loading: false, JSON.stringify({ user_id, device_id, access_token, passwordlessUser })
isGuest: false, );
isAuthenticated: true,
isPasswordlessUser: passwordlessUser,
userName: client.getUserIdLocalpart(),
});
return client; setState({
} catch (err) { client,
localStorage.removeItem("matrix-auth-store"); loading: false,
setState({ isGuest: false,
client: undefined, isPasswordlessUser: passwordlessUser,
loading: false, userName: client.getUserIdLocalpart(),
isGuest: false, });
isAuthenticated: false,
isPasswordlessUser: false, return client;
userName: null,
});
throw err;
}
}, []); }, []);
const logout = useCallback(() => { const logout = useCallback(() => {
@@ -348,24 +293,20 @@ export function ClientProvider({ homeserverUrl, children }) {
const context = useMemo( const context = useMemo(
() => ({ () => ({
loading, loading,
isAuthenticated,
isPasswordlessUser, isPasswordlessUser,
isGuest, isGuest,
client, client,
login, login,
registerGuest,
register, register,
logout, logout,
userName, userName,
}), }),
[ [
loading, loading,
isAuthenticated,
isPasswordlessUser, isPasswordlessUser,
isGuest, isGuest,
client, client,
login, login,
registerGuest,
register, register,
logout, logout,
userName, userName,

View File

@@ -32,14 +32,7 @@ import classNames from "classnames";
import { ErrorView, LoadingView } from "./FullScreenView"; import { ErrorView, LoadingView } from "./FullScreenView";
export function Home() { export function Home() {
const { const { isGuest, isPasswordlessUser, loading, error, client } = useClient();
isAuthenticated,
isGuest,
isPasswordlessUser,
loading,
error,
client,
} = useClient();
const history = useHistory(); const history = useHistory();
const { createRoomError, creatingRoom, createRoom } = useCreateRoom(); const { createRoomError, creatingRoom, createRoom } = useCreateRoom();
@@ -74,7 +67,7 @@ export function Home() {
return <LoadingView />; return <LoadingView />;
} else if (error || createRoomError) { } else if (error || createRoomError) {
return <ErrorView error={error || createRoomError} />; return <ErrorView error={error || createRoomError} />;
} else if (!isAuthenticated || isGuest) { } else if (isGuest) {
return ( return (
<UnregisteredView <UnregisteredView
onCreateRoom={onCreateRoom} onCreateRoom={onCreateRoom}

View File

@@ -58,32 +58,14 @@ const canScreenshare = "getDisplayMedia" in navigator.mediaDevices;
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
export function Room() { export function Room() {
const [registeringGuest, setRegisteringGuest] = useState(false); const { loading, error, client, isGuest } = useClient();
const [registrationError, setRegistrationError] = useState();
const { loading, isAuthenticated, error, client, registerGuest, isGuest } =
useClient();
useEffect(() => { if (loading) {
if (!loading && !isAuthenticated) {
setRegisteringGuest(true);
registerGuest()
.then(() => {
setRegisteringGuest(false);
})
.catch((error) => {
setRegistrationError(error);
setRegisteringGuest(false);
});
}
}, [loading, isAuthenticated]);
if (loading || registeringGuest) {
return <LoadingView />; return <LoadingView />;
} }
if (registrationError || error) { if (error) {
return <ErrorView error={registrationError || error} />; return <ErrorView error={error} />;
} }
return <GroupCall client={client} isGuest={isGuest} />; return <GroupCall client={client} isGuest={isGuest} />;

View File

@@ -15,7 +15,7 @@ import { ProfileModal } from "./ProfileModal";
export function UserMenu() { export function UserMenu() {
const location = useLocation(); const location = useLocation();
const history = useHistory(); const history = useHistory();
const { isAuthenticated, isGuest, logout, userName, client } = useClient(); const { isGuest, isPasswordlessUser, logout, userName, client } = useClient();
const { displayName } = useDisplayName(client); const { displayName } = useDisplayName(client);
const { modalState, modalProps } = useModalTriggerState(); const { modalState, modalProps } = useModalTriggerState();
@@ -40,30 +40,31 @@ export function UserMenu() {
); );
const items = useMemo(() => { const items = useMemo(() => {
const arr = []; const arr = [
{
if (isAuthenticated) {
arr.push({
key: "user", key: "user",
icon: UserIcon, icon: UserIcon,
label: displayName || userName, label: displayName || userName,
},
];
if (isGuest || isPasswordlessUser) {
arr.push({
key: "login",
label: "Sign In",
icon: LoginIcon,
}); });
} }
if (!isAuthenticated || isGuest) { if (isGuest) {
arr.push( arr.push({
{ key: "register",
key: "login", label: "Register",
label: "Sign In", icon: LoginIcon,
icon: LoginIcon, });
}, }
{
key: "register", if (!isGuest) {
label: "Register",
icon: LoginIcon,
}
);
} else {
arr.push({ arr.push({
key: "logout", key: "logout",
label: "Sign Out", label: "Sign Out",
@@ -72,7 +73,7 @@ export function UserMenu() {
} }
return arr; return arr;
}, [isAuthenticated, isGuest, userName, displayName]); }, [isGuest, isPasswordlessUser, userName, displayName]);
return ( return (
<> <>