Merge branch 'main' into nexy7574/render-tombstone

This commit is contained in:
Tulir Asokan 2025-03-28 12:50:56 +02:00
commit 4176cc38ed
6 changed files with 25 additions and 6 deletions

View file

@ -60,6 +60,7 @@ type HiClient struct {
syncLock sync.Mutex syncLock sync.Mutex
stopSync atomic.Pointer[context.CancelFunc] stopSync atomic.Pointer[context.CancelFunc]
encryptLock sync.Mutex encryptLock sync.Mutex
loginLock sync.Mutex
requestQueueWakeup chan struct{} requestQueueWakeup chan struct{}

View file

@ -36,6 +36,12 @@ func (h *HiClient) LoginPassword(ctx context.Context, homeserverURL, username, p
} }
func (h *HiClient) Login(ctx context.Context, req *mautrix.ReqLogin) error { func (h *HiClient) Login(ctx context.Context, req *mautrix.ReqLogin) error {
h.loginLock.Lock()
defer h.loginLock.Unlock()
if h.IsLoggedIn() {
return fmt.Errorf("already logged in")
}
err := h.CheckServerVersions(ctx) err := h.CheckServerVersions(ctx)
if err != nil { if err != nil {
return err return err

View file

@ -101,6 +101,8 @@ func (h *HiClient) processGetRoomState(ctx context.Context, roomID id.RoomID, fe
room, err := h.DB.Room.Get(ctx, roomID) room, err := h.DB.Room.Get(ctx, roomID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get room from database: %w", err) return fmt.Errorf("failed to get room from database: %w", err)
} else if room == nil {
return fmt.Errorf("room not found")
} }
updatedRoom := &database.Room{ updatedRoom := &database.Room{
ID: room.ID, ID: room.ID,

View file

@ -126,15 +126,16 @@ func (h *HiClient) maybeDiscardOutboundSession(ctx context.Context, newMembershi
prevMembership = event.Membership(gjson.GetBytes(evt.Unsigned.PrevContent.VeryRaw, "membership").Str) prevMembership = event.Membership(gjson.GetBytes(evt.Unsigned.PrevContent.VeryRaw, "membership").Str)
} }
if prevMembership == "unknown" || prevMembership == "" { if prevMembership == "unknown" || prevMembership == "" {
cs, err := h.DB.CurrentState.Get(ctx, evt.RoomID, event.StateMember, h.Account.UserID.String()) cs, err := h.DB.CurrentState.Get(ctx, evt.RoomID, event.StateMember, evt.GetStateKey())
if err != nil { if err != nil {
zerolog.Ctx(ctx).Warn().Err(err). zerolog.Ctx(ctx).Warn().Err(err).
Stringer("room_id", evt.RoomID). Stringer("room_id", evt.RoomID).
Str("user_id", evt.GetStateKey()). Str("user_id", evt.GetStateKey()).
Msg("Failed to get previous membership") Msg("Failed to get previous membership")
return false return false
} else if cs != nil {
prevMembership = event.Membership(gjson.GetBytes(cs.Content, "membership").Str)
} }
prevMembership = event.Membership(gjson.GetBytes(cs.Content, "membership").Str)
} }
if prevMembership == newMembership || if prevMembership == newMembership ||
(prevMembership == event.MembershipInvite && newMembership == event.MembershipJoin && h.shouldShareKeysToInvitedUsers(ctx, evt.RoomID)) || (prevMembership == event.MembershipInvite && newMembership == event.MembershipJoin && h.shouldShareKeysToInvitedUsers(ctx, evt.RoomID)) ||

View file

@ -26,6 +26,7 @@ const BeeperLogin = ({ domain, client }: BeeperLoginProps) => {
const [email, setEmail] = useState("") const [email, setEmail] = useState("")
const [requestID, setRequestID] = useState("") const [requestID, setRequestID] = useState("")
const [code, setCode] = useState("") const [code, setCode] = useState("")
const [loading, setLoading] = useState(false)
const [error, setError] = useState("") const [error, setError] = useState("")
const onChangeEmail = (evt: React.ChangeEvent<HTMLInputElement>) => { const onChangeEmail = (evt: React.ChangeEvent<HTMLInputElement>) => {
@ -41,16 +42,18 @@ const BeeperLogin = ({ domain, client }: BeeperLoginProps) => {
const requestCode = (evt: React.FormEvent) => { const requestCode = (evt: React.FormEvent) => {
evt.preventDefault() evt.preventDefault()
setLoading(true)
beeper.doStartLogin(domain).then( beeper.doStartLogin(domain).then(
request => beeper.doRequestCode(domain, request, email).then( request => beeper.doRequestCode(domain, request, email).then(
() => setRequestID(request), () => setRequestID(request),
err => setError(`Failed to request code: ${err}`), err => setError(`Failed to request code: ${err}`),
), ),
err => setError(`Failed to start login: ${err}`), err => setError(`Failed to start login: ${err}`),
) ).finally(() => setLoading(false))
} }
const submitCode = (evt: React.FormEvent) => { const submitCode = (evt: React.FormEvent) => {
evt.preventDefault() evt.preventDefault()
setLoading(true)
beeper.doSubmitCode(domain, requestID, code).then( beeper.doSubmitCode(domain, requestID, code).then(
token => { token => {
client.rpc.loginCustom(`https://matrix.${domain}`, { client.rpc.loginCustom(`https://matrix.${domain}`, {
@ -59,7 +62,7 @@ const BeeperLogin = ({ domain, client }: BeeperLoginProps) => {
}).catch(err => setError(`Failed to login with token: ${err}`)) }).catch(err => setError(`Failed to login with token: ${err}`))
}, },
err => setError(`Failed to submit code: ${err}`), err => setError(`Failed to submit code: ${err}`),
) ).finally(() => setLoading(false))
} }
return <form onSubmit={requestID ? submitCode : requestCode} className="beeper-login"> return <form onSubmit={requestID ? submitCode : requestCode} className="beeper-login">
@ -83,6 +86,7 @@ const BeeperLogin = ({ domain, client }: BeeperLoginProps) => {
<button <button
className="beeper-login-button primary-color-button" className="beeper-login-button primary-color-button"
type="submit" type="submit"
disabled={loading}
>{requestID ? "Submit Code" : "Request Code"}</button> >{requestID ? "Submit Code" : "Request Code"}</button>
{error && <div className="error"> {error && <div className="error">
{error} {error}

View file

@ -31,9 +31,11 @@ export const LoginScreen = ({ client }: LoginScreenProps) => {
const [password, setPassword] = useState("") const [password, setPassword] = useState("")
const [homeserverURL, setHomeserverURL] = useState("") const [homeserverURL, setHomeserverURL] = useState("")
const [loginFlows, setLoginFlows] = useState<string[] | null>(null) const [loginFlows, setLoginFlows] = useState<string[] | null>(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState("") const [error, setError] = useState("")
const loginSSO = () => { const loginSSO = () => {
setLoading(true)
fetch("_gomuks/sso", { fetch("_gomuks/sso", {
method: "POST", method: "POST",
body: JSON.stringify({ homeserver_url: homeserverURL }), body: JSON.stringify({ homeserver_url: homeserverURL }),
@ -51,7 +53,7 @@ export const LoginScreen = ({ client }: LoginScreenProps) => {
window.location.href = `${homeserverURL}/_matrix/client/v3/login/sso/redirect?redirectUrl=${redir}` window.location.href = `${homeserverURL}/_matrix/client/v3/login/sso/redirect?redirectUrl=${redir}`
}, },
err => setError(`Failed to start SSO login: ${err}`), err => setError(`Failed to start SSO login: ${err}`),
) ).finally(() => setLoading(false))
} }
const login = (evt: React.FormEvent) => { const login = (evt: React.FormEvent) => {
@ -61,10 +63,11 @@ export const LoginScreen = ({ client }: LoginScreenProps) => {
} else if (!loginFlows.includes("m.login.password")) { } else if (!loginFlows.includes("m.login.password")) {
loginSSO() loginSSO()
} else { } else {
setLoading(true)
client.rpc.login(homeserverURL, username, password).then( client.rpc.login(homeserverURL, username, password).then(
() => {}, () => {},
err => setError(err.toString()), err => setError(err.toString()),
) ).finally(() => setLoading(false))
} }
} }
@ -143,11 +146,13 @@ export const LoginScreen = ({ client }: LoginScreenProps) => {
{supportsSSO && <button {supportsSSO && <button
className="mx-login-button primary-color-button" className="mx-login-button primary-color-button"
type={supportsPassword ? "button" : "submit"} type={supportsPassword ? "button" : "submit"}
disabled={loading}
onClick={supportsPassword ? loginSSO : undefined} onClick={supportsPassword ? loginSSO : undefined}
>Login with SSO</button>} >Login with SSO</button>}
{supportsPassword && <button {supportsPassword && <button
className="mx-login-button primary-color-button" className="mx-login-button primary-color-button"
type="submit" type="submit"
disabled={loading}
>Login{supportsSSO || beeperDomain ? " with password" : ""}</button>} >Login{supportsSSO || beeperDomain ? " with password" : ""}</button>}
</div> </div>
{error && <div className="error"> {error && <div className="error">