|
|
|
@ -4,6 +4,8 @@ const create = require('create-react-class');
|
|
|
|
|
const Promise = require('bluebird');
|
|
|
|
|
const urllib = require('url');
|
|
|
|
|
|
|
|
|
|
const createApiRequester = require("../lib/api-request");
|
|
|
|
|
|
|
|
|
|
let login = create({
|
|
|
|
|
displayName: "Login",
|
|
|
|
|
|
|
|
|
@ -24,67 +26,82 @@ let login = create({
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
login: function() {
|
|
|
|
|
this.setState({error: ""});
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
this.setState({error: ""});
|
|
|
|
|
|
|
|
|
|
if (this.state.hs.valid) {
|
|
|
|
|
return this.doLogin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let parts = this.state.formState.user.split(':');
|
|
|
|
|
if (parts.length != 2) {
|
|
|
|
|
return this.setState({error: "Please enter a full mxid, like username:homeserver.tld"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let hostname = urllib.parse("https://" + parts[1]);
|
|
|
|
|
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
return getApiServer(hostname);
|
|
|
|
|
}).then((homeserverUrl) => {
|
|
|
|
|
console.log("Using API server", homeserverUrl);
|
|
|
|
|
|
|
|
|
|
if (this.state.hs.valid) {
|
|
|
|
|
return this.doLogin();
|
|
|
|
|
}
|
|
|
|
|
this.setState({
|
|
|
|
|
apiUrl: homeserverUrl,
|
|
|
|
|
apiRequest: createApiRequester(homeserverUrl),
|
|
|
|
|
formState: Object.assign(this.state.formState, {
|
|
|
|
|
user: parts[0],
|
|
|
|
|
hs: homeserverUrl
|
|
|
|
|
}),
|
|
|
|
|
hs: Object.assign(this.state.hs, {
|
|
|
|
|
valid: true
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let parts = this.state.formState.user.split(':');
|
|
|
|
|
if (parts.length != 2) {
|
|
|
|
|
return this.setState({error: "Please enter a full mxid, like username:homeserver.tld"});
|
|
|
|
|
}
|
|
|
|
|
return this.doLogin();
|
|
|
|
|
}).catch((error) => {
|
|
|
|
|
/* FIXME: Error filtering */
|
|
|
|
|
console.log("ERROR fetching homeserver url", error);
|
|
|
|
|
|
|
|
|
|
let hostname = urllib.parse("https://" + parts[1]);
|
|
|
|
|
getApiServer(hostname).then((hs) => {
|
|
|
|
|
console.log("Using API server", hs);
|
|
|
|
|
let formState = this.state.formState;
|
|
|
|
|
formState.user = parts[0];
|
|
|
|
|
formState.hs = hs;
|
|
|
|
|
let hsState = Object.assign(this.state.hs, {valid: true});
|
|
|
|
|
this.setState({apiUrl: hs, formState: formState, hs: hsState});
|
|
|
|
|
this.doLogin();
|
|
|
|
|
}).catch((error) => {
|
|
|
|
|
console.log("ERROR fetching homeserver url", error);
|
|
|
|
|
let hsState = Object.assign(this.state.hs, {error: error, valid: false, prompt: true});
|
|
|
|
|
this.setState({hs: hsState});
|
|
|
|
|
this.setState({
|
|
|
|
|
hs: Object.assign(this.state.hs, {
|
|
|
|
|
error: error,
|
|
|
|
|
valid: false,
|
|
|
|
|
prompt: true
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
doLogin: function() {
|
|
|
|
|
console.log("Logging in");
|
|
|
|
|
let user = this.state.formState.user.replace('@', '');
|
|
|
|
|
let password = this.state.formState.pass;
|
|
|
|
|
let hs = this.state.apiUrl;
|
|
|
|
|
|
|
|
|
|
let data = {
|
|
|
|
|
user: user,
|
|
|
|
|
password: password,
|
|
|
|
|
type: "m.login.password",
|
|
|
|
|
initial_device_display_name: "Neo v4",
|
|
|
|
|
};
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
console.log("Logging in");
|
|
|
|
|
let user = this.state.formState.user.replace('@', '');
|
|
|
|
|
let password = this.state.formState.pass;
|
|
|
|
|
let homeserverUrl = this.state.apiUrl;
|
|
|
|
|
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
return this.state.apiRequest("/_matrix/client/r0/login", {
|
|
|
|
|
user: user,
|
|
|
|
|
password: password,
|
|
|
|
|
type: "m.login.password",
|
|
|
|
|
initial_device_display_name: "Neo v4",
|
|
|
|
|
});
|
|
|
|
|
}).then((responseJson) => {
|
|
|
|
|
console.log("got access token", responseJson);
|
|
|
|
|
|
|
|
|
|
let url = hs + "/_matrix/client/r0/login";
|
|
|
|
|
this.setState({ json: responseJson });
|
|
|
|
|
|
|
|
|
|
fetch(url, {
|
|
|
|
|
body: JSON.stringify(data),
|
|
|
|
|
headers: {
|
|
|
|
|
'content-type': 'application/json'
|
|
|
|
|
},
|
|
|
|
|
method: 'POST',
|
|
|
|
|
}).then((response) => response.json())
|
|
|
|
|
.then((responseJson) => {
|
|
|
|
|
console.log("got access token", responseJson);
|
|
|
|
|
this.setState({json: responseJson});
|
|
|
|
|
if(responseJson.access_token != undefined) {
|
|
|
|
|
this.props.callback(responseJson.user_id, responseJson.access_token, hs);
|
|
|
|
|
this.props.callback(responseJson.user_id, responseJson.access_token, homeserverUrl);
|
|
|
|
|
} else {
|
|
|
|
|
this.setState({error: responseJson.error});
|
|
|
|
|
this.setState({ error: responseJson.error });
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
console.error(url, error);
|
|
|
|
|
}).catch((error) => {
|
|
|
|
|
/* FIXME: Why are errors being swallowed here? */
|
|
|
|
|
console.error(error);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleUserChange: function(e) {
|
|
|
|
@ -106,7 +123,7 @@ let login = create({
|
|
|
|
|
this.setState({formState: formState});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleHsChange: function(e) {
|
|
|
|
|
handleHomeserverChange: function(e) {
|
|
|
|
|
let formState = this.state.formState;
|
|
|
|
|
formState.hs = e.target.value;
|
|
|
|
|
this.setState({formState: formState});
|
|
|
|
@ -138,9 +155,9 @@ let login = create({
|
|
|
|
|
|
|
|
|
|
<label htmlFor="hs" className={hsState}>Homeserver: </label>
|
|
|
|
|
{this.state.hs.prompt ? (
|
|
|
|
|
<>
|
|
|
|
|
<input type="text" id="hs" value={this.state.formState["hs"]} onChange={this.handleHsChange}/>
|
|
|
|
|
</>
|
|
|
|
|
<>
|
|
|
|
|
<input type="text" id="hs" value={this.state.formState["hs"]} onChange={this.handleHomeserverChange}/>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<span id="hs">{this.state.formState["hs"]}</span>
|
|
|
|
|
)}
|
|
|
|
@ -152,39 +169,44 @@ let login = create({
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function getApiServer(hostname) {
|
|
|
|
|
/* FIXME: Promise.try */
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
console.log("Checking for api server from mxid", urllib.format(hostname));
|
|
|
|
|
checkApi(hostname).then(() => {
|
|
|
|
|
// Hostname is a valid api server
|
|
|
|
|
hostname.pathname = "";
|
|
|
|
|
resolve(urllib.format(hostname));
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
console.log("trying .well-known");
|
|
|
|
|
tryWellKnown(hostname).then((hostname) => {
|
|
|
|
|
console.log("got .well-known host", hostname);
|
|
|
|
|
resolve(hostname);
|
|
|
|
|
}).catch((_err) => {
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
reject(new Error("Fatal error trying to get API host"));
|
|
|
|
|
});
|
|
|
|
|
function getApiServer(parsedUrl) {
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
console.log("Checking for api server from mxid", urllib.format(parsedUrl));
|
|
|
|
|
|
|
|
|
|
return checkApi(parsedUrl);
|
|
|
|
|
}).then(() => {
|
|
|
|
|
// Hostname is a valid api server
|
|
|
|
|
return buildUrl(parsedUrl, "");
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
/* FIXME: Error filtering */
|
|
|
|
|
console.log("trying .well-known");
|
|
|
|
|
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
return tryWellKnown(parsedUrl);
|
|
|
|
|
}).then((hostname) => {
|
|
|
|
|
console.log("got .well-known host", hostname);
|
|
|
|
|
|
|
|
|
|
return hostname;
|
|
|
|
|
}).catch((_err) => {
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
throw new Error("Fatal error trying to get API host");
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkApi(host) {
|
|
|
|
|
let versionUrl = buildUrl(host, "/_matrix/client/versions");
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
fetch(versionUrl).then((response) => {
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
let versionUrl = buildUrl(host, "/_matrix/client/versions");
|
|
|
|
|
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
return fetch(versionUrl);
|
|
|
|
|
}).then((response) => {
|
|
|
|
|
if (response.status != 200) {
|
|
|
|
|
console.log("Invalid homeserver url", versionUrl);
|
|
|
|
|
|
|
|
|
|
/* FIXME: Error types */
|
|
|
|
|
return reject(new Error("Invalid homeserver URL"));
|
|
|
|
|
throw new Error("Invalid homeserver URL");
|
|
|
|
|
}
|
|
|
|
|
resolve();
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -193,36 +215,43 @@ function tryWellKnown(host) {
|
|
|
|
|
let wellKnownUrl = urllib.format(Object.assign(host, {
|
|
|
|
|
pathname: "/.well-known/matrix/client"
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
console.log("Trying", wellKnownUrl, "for .well-known");
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
return fetch(wellKnownUrl)
|
|
|
|
|
.then((response) => {
|
|
|
|
|
if (response.status != 200) {
|
|
|
|
|
console.log("no well-known in use");
|
|
|
|
|
reject(new Error("No homeserver found"));
|
|
|
|
|
}
|
|
|
|
|
return response;
|
|
|
|
|
}).catch((_error) => {
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
reject(new Error("can't fetch .well-known"));
|
|
|
|
|
})
|
|
|
|
|
.then((response) => response.json())
|
|
|
|
|
.then((json) => {
|
|
|
|
|
console.log("Parsed json", json);
|
|
|
|
|
if (json['m.homeserver'] != undefined && json['m.homeserver'].base_url != undefined) {
|
|
|
|
|
resolve(json['m.homeserver'].base_url);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
console.log("Error in json", err);
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
reject(new Error("Error while parsing .well-known"));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Promise.try(() => {
|
|
|
|
|
return fetch(wellKnownUrl);
|
|
|
|
|
}).tap((response) => {
|
|
|
|
|
if (response.status != 200) {
|
|
|
|
|
console.log("no well-known in use");
|
|
|
|
|
|
|
|
|
|
/* FIXME: Error type */
|
|
|
|
|
throw new Error("No homeserver found");
|
|
|
|
|
}
|
|
|
|
|
}).catch((_error) => {
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
throw new Error("can't fetch .well-known");
|
|
|
|
|
}).then((response) => {
|
|
|
|
|
return response.json();
|
|
|
|
|
}).then((json) => {
|
|
|
|
|
console.log("Parsed json", json);
|
|
|
|
|
|
|
|
|
|
if (json['m.homeserver'] != null && json['m.homeserver'].base_url != null) {
|
|
|
|
|
return json['m.homeserver'].base_url;
|
|
|
|
|
} else {
|
|
|
|
|
/* FIXME: Error type */
|
|
|
|
|
throw new Error("No homeserver specified in .well-known");
|
|
|
|
|
}
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
/* FIXME: Error filtering? */
|
|
|
|
|
console.log("Error in json", err);
|
|
|
|
|
|
|
|
|
|
/* FIXME: Error chaining */
|
|
|
|
|
throw new Error("Error while parsing .well-known");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildUrl(host, path) {
|
|
|
|
|
return urllib.format(Object.assign(host, {
|
|
|
|
|
function buildUrl(parsedUrl, path) {
|
|
|
|
|
return urllib.format(Object.assign(parsedUrl, {
|
|
|
|
|
pathname: path
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|