diff --git a/src/js/login.js b/src/js/login.js index 55caa66..4754bef 100644 --- a/src/js/login.js +++ b/src/js/login.js @@ -77,40 +77,16 @@ class Form extends ElemJS { if (!username.isValid()) return this.cancel("Username is not valid.") // Resolve homeserver address - let currentAddress = homeserver.value - let ok = false - while (!ok) { - if (!currentAddress.match(/^https?:\/\//)) { - console.warn(`${currentAddress} doesn't specify the protocol, assuming https`) - currentAddress = "https://" + currentAddress - } - currentAddress = currentAddress.replace(/\/*$/, "") - this.status(`Looking up homeserver... trying ${currentAddress}`) - try { - // check if we found the actual matrix server - try { - const versions = await fetch(`${currentAddress}/_matrix/client/versions`).then(res => res.json()) - if (Array.isArray(versions.versions)) { - ok = true - break - } - } catch (e) {} - // find the next matrix server in the chain - const root = await fetch(`${currentAddress}/.well-known/matrix/client`).then(res => res.json()) - let nextAddress = root["m.homeserver"].base_url - nextAddress = nextAddress.replace(/\/*$/, "") - if (currentAddress === nextAddress) { - ok = true - } - currentAddress = nextAddress - } catch (e) { - return this.cancel(`Failed to look up server ${currentAddress}`) - } + let domain + try { + domain = await this.findHomeserver(homeserver.value) + } catch(e) { + return this.cancel(e.message) } // Request access token this.status("Logging in...") - const root = await fetch(`${currentAddress}/_matrix/client/r0/login`, { + const root = await fetch(`${domain}/_matrix/client/r0/login`, { method: "POST", body: JSON.stringify({ type: "m.login.password", @@ -130,12 +106,52 @@ class Form extends ElemJS { } localStorage.setItem("mx_user_id", root.user_id) - localStorage.setItem("domain", currentAddress) + localStorage.setItem("domain", domain) localStorage.setItem("access_token", root.access_token) location.assign("../") } + async findHomeserver(address, maxDepth = 5) { + + //Protects from servers sending us on a redirect loop + maxDepth-- + if (maxDepth <= 0) throw new Error(`Failed to look up homeserver, maximum search depth reached`) + + //Normalise the address + if (!address.match(/^https?:\/\//)) { + console.warn(`${address} doesn't specify the protocol, assuming https`) + address = "https://" + address + } + address = address.replace(/\/*$/, "") + + this.status(`Looking up homeserver... trying ${address}`) + + // Check if we found the actual matrix server + try { + const versionsReq = await fetch(`${address}/_matrix/client/versions`) + if (versionsReq.ok) { + const versions = await versionsReq.json() + if (Array.isArray(versions.versions)) return address + } + } catch(e) {} + + // Find the next matrix server in the chain + const root = await fetch(`${address}/.well-known/matrix/client`).then(res => res.json()).catch(e => { + console.error(e) + throw new Error(`Failed to look up server ${address}`) + }) + + let nextAddress = root["m.homeserver"].base_url + nextAddress = nextAddress.replace(/\/*$/, "") + + if (address === nextAddress) { + throw new Error(`Failed to look up server ${address}, /.well-known/matrix/client found a redirect loop`); + } + + return this.findHomeserver(nextAddress, maxDepth) + } + status(message) { feedback.setLoading(true) feedback.message(message)