mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-15 00:04:59 +08:00
Add change password flow for anonymous users
This commit is contained in:
parent
d7fd06a250
commit
a7539eb34e
@ -130,8 +130,14 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
const authStore = localStorage.getItem("matrix-auth-store");
|
||||
|
||||
if (authStore) {
|
||||
const { user_id, device_id, access_token, guest, passwordlessUser } =
|
||||
JSON.parse(authStore);
|
||||
const {
|
||||
user_id,
|
||||
device_id,
|
||||
access_token,
|
||||
guest,
|
||||
passwordlessUser,
|
||||
tempPassword,
|
||||
} = JSON.parse(authStore);
|
||||
|
||||
const client = await initClient(
|
||||
{
|
||||
@ -151,6 +157,7 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
access_token,
|
||||
guest,
|
||||
passwordlessUser,
|
||||
tempPassword,
|
||||
})
|
||||
);
|
||||
|
||||
@ -311,10 +318,13 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
deviceId: device_id,
|
||||
});
|
||||
|
||||
localStorage.setItem(
|
||||
"matrix-auth-store",
|
||||
JSON.stringify({ user_id, device_id, access_token, passwordlessUser })
|
||||
);
|
||||
const session = { user_id, device_id, access_token, passwordlessUser };
|
||||
|
||||
if (passwordlessUser) {
|
||||
session.tempPassword = password;
|
||||
}
|
||||
|
||||
localStorage.setItem("matrix-auth-store", JSON.stringify(session));
|
||||
|
||||
setState({
|
||||
client,
|
||||
@ -340,6 +350,45 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const changePassword = useCallback(
|
||||
async (password) => {
|
||||
const { tempPassword, passwordlessUser, ...existingSession } = JSON.parse(
|
||||
localStorage.getItem("matrix-auth-store")
|
||||
);
|
||||
|
||||
await client.setPassword(
|
||||
{
|
||||
type: "m.login.password",
|
||||
identifier: {
|
||||
type: "m.id.user",
|
||||
user: existingSession.user_id,
|
||||
},
|
||||
user: existingSession.user_id,
|
||||
password: tempPassword,
|
||||
},
|
||||
password
|
||||
);
|
||||
|
||||
localStorage.setItem(
|
||||
"matrix-auth-store",
|
||||
JSON.stringify({
|
||||
...existingSession,
|
||||
passwordlessUser: false,
|
||||
})
|
||||
);
|
||||
|
||||
setState({
|
||||
client,
|
||||
loading: false,
|
||||
isGuest: false,
|
||||
isAuthenticated: true,
|
||||
isPasswordlessUser: false,
|
||||
userName: client.getUserIdLocalpart(),
|
||||
});
|
||||
},
|
||||
[client]
|
||||
);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
localStorage.removeItem("matrix-auth-store");
|
||||
window.location = "/";
|
||||
@ -355,6 +404,7 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
login,
|
||||
registerGuest,
|
||||
register,
|
||||
changePassword,
|
||||
logout,
|
||||
userName,
|
||||
}),
|
||||
@ -367,6 +417,7 @@ export function ClientProvider({ homeserverUrl, children }) {
|
||||
login,
|
||||
registerGuest,
|
||||
register,
|
||||
changePassword,
|
||||
logout,
|
||||
userName,
|
||||
]
|
||||
|
@ -22,17 +22,30 @@ export function Field({ children, className, ...rest }) {
|
||||
}
|
||||
|
||||
export const InputField = forwardRef(
|
||||
({ id, label, className, type, checked, prefix, suffix, ...rest }, ref) => {
|
||||
(
|
||||
{ id, label, className, type, checked, prefix, suffix, disabled, ...rest },
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<Field
|
||||
className={classNames(
|
||||
type === "checkbox" ? styles.checkboxField : styles.inputField,
|
||||
{ [styles.prefix]: !!prefix },
|
||||
{
|
||||
[styles.prefix]: !!prefix,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{prefix && <span>{prefix}</span>}
|
||||
<input id={id} {...rest} ref={ref} type={type} checked={checked} />
|
||||
<input
|
||||
id={id}
|
||||
{...rest}
|
||||
ref={ref}
|
||||
type={type}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<label htmlFor={id}>
|
||||
{type === "checkbox" && (
|
||||
<div className={styles.checkbox}>
|
||||
|
@ -33,17 +33,26 @@
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 11px 9px;
|
||||
padding: 12px 9px 10px 9px;
|
||||
color: var(--textColor1);
|
||||
background-color: var(--bgColor1);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.inputField.disabled input,
|
||||
.inputField.disabled span {
|
||||
color: var(--textColor2);
|
||||
}
|
||||
|
||||
.inputField span {
|
||||
padding: 11px 9px;
|
||||
}
|
||||
|
||||
.inputField span:first-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.inputField input::placeholder {
|
||||
transition: color 0.25s ease-in 0s;
|
||||
color: transparent;
|
||||
|
@ -21,14 +21,21 @@ import { Button } from "./button";
|
||||
import { useClient } from "./ConferenceCallManagerHooks";
|
||||
import styles from "./LoginPage.module.css";
|
||||
import { ReactComponent as Logo } from "./icons/LogoLarge.svg";
|
||||
import { LoadingView } from "./FullScreenView";
|
||||
|
||||
export function RegisterPage() {
|
||||
const { register } = useClient();
|
||||
const registerUsernameRef = useRef();
|
||||
const {
|
||||
loading,
|
||||
client,
|
||||
register,
|
||||
changePassword,
|
||||
isAuthenticated,
|
||||
isPasswordlessUser,
|
||||
} = useClient();
|
||||
const confirmPasswordRef = useRef();
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [registering, setRegistering] = useState(false);
|
||||
const [error, setError] = useState();
|
||||
const [password, setPassword] = useState("");
|
||||
const [passwordConfirmation, setPasswordConfirmation] = useState("");
|
||||
@ -36,27 +43,55 @@ export function RegisterPage() {
|
||||
const onSubmitRegisterForm = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
register(
|
||||
registerUsernameRef.current.value,
|
||||
registerPasswordRef.current.value
|
||||
)
|
||||
.then(() => {
|
||||
if (location.state && location.state.from) {
|
||||
history.push(location.state.from);
|
||||
} else {
|
||||
history.push("/");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error);
|
||||
setLoading(false);
|
||||
});
|
||||
const data = new FormData(e.target);
|
||||
const userName = data.get("userName");
|
||||
const password = data.get("password");
|
||||
const passwordConfirmation = data.get("passwordConfirmation");
|
||||
|
||||
if (password !== passwordConfirmation) {
|
||||
return;
|
||||
}
|
||||
|
||||
setRegistering(true);
|
||||
|
||||
console.log(isPasswordlessUser);
|
||||
|
||||
if (isPasswordlessUser) {
|
||||
changePassword(password)
|
||||
.then(() => {
|
||||
if (location.state && location.state.from) {
|
||||
history.push(location.state.from);
|
||||
} else {
|
||||
history.push("/");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error);
|
||||
setRegistering(false);
|
||||
});
|
||||
} else {
|
||||
register(userName, password)
|
||||
.then(() => {
|
||||
if (location.state && location.state.from) {
|
||||
history.push(location.state.from);
|
||||
} else {
|
||||
history.push("/");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error);
|
||||
setRegistering(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
[register, location, history]
|
||||
[register, changePassword, location, history, isPasswordlessUser]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!confirmPasswordRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (password && passwordConfirmation && password !== passwordConfirmation) {
|
||||
confirmPasswordRef.current.setCustomValidity("Passwords must match");
|
||||
} else {
|
||||
@ -64,6 +99,16 @@ export function RegisterPage() {
|
||||
}
|
||||
}, [password, passwordConfirmation]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && isAuthenticated && !isPasswordlessUser) {
|
||||
history.push("/");
|
||||
}
|
||||
}, [history, isAuthenticated, isPasswordlessUser]);
|
||||
|
||||
if (loading) {
|
||||
return <LoadingView />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.container}>
|
||||
@ -75,18 +120,26 @@ export function RegisterPage() {
|
||||
<FieldRow>
|
||||
<InputField
|
||||
type="text"
|
||||
ref={registerUsernameRef}
|
||||
name="userName"
|
||||
placeholder="Username"
|
||||
label="Username"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="none"
|
||||
prefix="@"
|
||||
suffix={`:${window.location.host}`}
|
||||
value={
|
||||
isAuthenticated && isPasswordlessUser
|
||||
? client.getUserIdLocalpart()
|
||||
: undefined
|
||||
}
|
||||
onChange={(e) => setUserName(e.target.value)}
|
||||
disabled={isAuthenticated && isPasswordlessUser}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
required
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
value={password}
|
||||
@ -98,6 +151,7 @@ export function RegisterPage() {
|
||||
<InputField
|
||||
required
|
||||
type="password"
|
||||
name="passwordConfirmation"
|
||||
onChange={(e) => setPasswordConfirmation(e.target.value)}
|
||||
value={passwordConfirmation}
|
||||
placeholder="Confirm Password"
|
||||
@ -111,8 +165,8 @@ export function RegisterPage() {
|
||||
</FieldRow>
|
||||
)}
|
||||
<FieldRow>
|
||||
<Button type="submit" disabled={loading}>
|
||||
{loading ? "Registering..." : "Register"}
|
||||
<Button type="submit" disabled={registering}>
|
||||
{registering ? "Registering..." : "Register"}
|
||||
</Button>
|
||||
</FieldRow>
|
||||
</form>
|
||||
|
33
src/Room.jsx
33
src/Room.jsx
@ -60,8 +60,15 @@ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
export function Room() {
|
||||
const [registeringGuest, setRegisteringGuest] = useState(false);
|
||||
const [registrationError, setRegistrationError] = useState();
|
||||
const { loading, isAuthenticated, error, client, registerGuest, isGuest } =
|
||||
useClient();
|
||||
const {
|
||||
loading,
|
||||
isAuthenticated,
|
||||
error,
|
||||
client,
|
||||
registerGuest,
|
||||
isGuest,
|
||||
isPasswordlessUser,
|
||||
} = useClient();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && !isAuthenticated) {
|
||||
@ -86,10 +93,16 @@ export function Room() {
|
||||
return <ErrorView error={registrationError || error} />;
|
||||
}
|
||||
|
||||
return <GroupCall client={client} isGuest={isGuest} />;
|
||||
return (
|
||||
<GroupCall
|
||||
client={client}
|
||||
isGuest={isGuest}
|
||||
isPasswordlessUser={isPasswordlessUser}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function GroupCall({ client, isGuest }) {
|
||||
export function GroupCall({ client, isGuest, isPasswordlessUser }) {
|
||||
const { roomId: maybeRoomId } = useParams();
|
||||
const { hash, search } = useLocation();
|
||||
const [simpleGrid, viaServers] = useMemo(() => {
|
||||
@ -118,6 +131,7 @@ export function GroupCall({ client, isGuest }) {
|
||||
return (
|
||||
<GroupCallView
|
||||
isGuest={isGuest}
|
||||
isPasswordlessUser={isPasswordlessUser}
|
||||
client={client}
|
||||
roomId={roomId}
|
||||
groupCall={groupCall}
|
||||
@ -129,6 +143,7 @@ export function GroupCall({ client, isGuest }) {
|
||||
export function GroupCallView({
|
||||
client,
|
||||
isGuest,
|
||||
isPasswordlessUser,
|
||||
roomId,
|
||||
groupCall,
|
||||
simpleGrid,
|
||||
@ -184,7 +199,7 @@ export function GroupCallView({
|
||||
const onLeave = useCallback(() => {
|
||||
leave();
|
||||
|
||||
if (!isGuest) {
|
||||
if (!isGuest && !isPasswordlessUser) {
|
||||
history.push("/");
|
||||
} else {
|
||||
setLeft(true);
|
||||
@ -494,18 +509,12 @@ export function CallEndedScreen() {
|
||||
<ul>
|
||||
<li>Easily access all your previous call links</li>
|
||||
<li>Set a username and avatar</li>
|
||||
<li>
|
||||
Get your own Matrix ID so you can log in to{" "}
|
||||
<a href="https://element.io" target="_blank">
|
||||
Element
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<LinkButton
|
||||
className={styles.callEndedButton}
|
||||
size="lg"
|
||||
variant="default"
|
||||
to="/login"
|
||||
to="/register"
|
||||
>
|
||||
Create account
|
||||
</LinkButton>
|
||||
|
Loading…
Reference in New Issue
Block a user