This will happen anyway when they follow email verification links. make captchas poll for success so if they are completed elsewhere, electron moves on
171 lines
5.2 KiB
JavaScript
171 lines
5.2 KiB
JavaScript
"use strict";
|
|
var q = require("q");
|
|
|
|
/**
|
|
* An interface class which login types should abide by.
|
|
*/
|
|
class Stage {
|
|
constructor(type, matrixClient, signupInstance) {
|
|
this.type = type;
|
|
this.client = matrixClient;
|
|
this.signupInstance = signupInstance;
|
|
}
|
|
|
|
complete() {
|
|
// Return a promise which is:
|
|
// RESOLVED => With an Object which has an 'auth' key which is the auth dict
|
|
// to submit.
|
|
// REJECTED => With an Error if there was a problem with this stage.
|
|
// Has a "message" string and an "isFatal" flag.
|
|
return q.reject("NOT IMPLEMENTED");
|
|
}
|
|
|
|
onReceiveData() {
|
|
// NOP
|
|
}
|
|
}
|
|
Stage.TYPE = "NOT IMPLEMENTED";
|
|
|
|
|
|
/**
|
|
* This stage requires no auth.
|
|
*/
|
|
class DummyStage extends Stage {
|
|
constructor(matrixClient, signupInstance) {
|
|
super(DummyStage.TYPE, matrixClient, signupInstance);
|
|
}
|
|
|
|
complete() {
|
|
return q({
|
|
auth: {
|
|
type: DummyStage.TYPE
|
|
}
|
|
});
|
|
}
|
|
}
|
|
DummyStage.TYPE = "m.login.dummy";
|
|
|
|
|
|
/**
|
|
* This stage uses Google's Recaptcha to do auth.
|
|
*/
|
|
class RecaptchaStage extends Stage {
|
|
constructor(matrixClient, signupInstance) {
|
|
super(RecaptchaStage.TYPE, matrixClient, signupInstance);
|
|
this.authDict = {
|
|
auth: {
|
|
type: 'm.login.recaptcha',
|
|
// we'll add in the response param if we get one from the local user.
|
|
},
|
|
poll_for_success: true,
|
|
};
|
|
}
|
|
|
|
// called when the recaptcha has been completed.
|
|
onReceiveData(data) {
|
|
if (!data || !data.response) {
|
|
return;
|
|
}
|
|
this.authDict.response = data.response;
|
|
}
|
|
|
|
complete() {
|
|
// we return the authDict with no response, telling Signup to keep polling
|
|
// the server in case the captcha is filled in on another window (e.g. by
|
|
// following a nextlink from an email signup). If the user completes the
|
|
// captcha locally, then we return at the next poll.
|
|
return q(this.authDict);
|
|
}
|
|
}
|
|
RecaptchaStage.TYPE = "m.login.recaptcha";
|
|
|
|
|
|
/**
|
|
* This state uses the IS to verify email addresses.
|
|
*/
|
|
class EmailIdentityStage extends Stage {
|
|
constructor(matrixClient, signupInstance) {
|
|
super(EmailIdentityStage.TYPE, matrixClient, signupInstance);
|
|
}
|
|
|
|
_completeVerify() {
|
|
// pull out the host of the IS URL by creating an anchor element
|
|
var isLocation = document.createElement('a');
|
|
isLocation.href = this.signupInstance.getIdentityServerUrl();
|
|
|
|
var clientSecret = this.clientSecret || this.signupInstance.params.clientSecret;
|
|
var sid = this.sid || this.signupInstance.params.idSid;
|
|
|
|
return q({
|
|
auth: {
|
|
type: 'm.login.email.identity',
|
|
threepid_creds: {
|
|
sid: sid,
|
|
client_secret: clientSecret,
|
|
id_server: isLocation.host
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Complete the email stage.
|
|
*
|
|
* This is called twice under different circumstances:
|
|
* 1) When requesting an email token from the IS
|
|
* 2) When validating query parameters received from the link in the email
|
|
*/
|
|
complete() {
|
|
// TODO: The Registration class shouldn't really know this info.
|
|
if (this.signupInstance.params.hasEmailInfo) {
|
|
return this._completeVerify();
|
|
}
|
|
|
|
this.clientSecret = this.signupInstance.params.clientSecret;
|
|
if (!this.clientSecret) {
|
|
return q.reject(new Error("No client secret specified by Signup class!"));
|
|
}
|
|
|
|
var nextLink = this.signupInstance.params.registrationUrl +
|
|
'?client_secret=' +
|
|
encodeURIComponent(this.clientSecret) +
|
|
"&hs_url=" +
|
|
encodeURIComponent(this.signupInstance.getHomeserverUrl()) +
|
|
"&is_url=" +
|
|
encodeURIComponent(this.signupInstance.getIdentityServerUrl()) +
|
|
"&session_id=" +
|
|
encodeURIComponent(this.signupInstance.getServerData().session);
|
|
|
|
var self = this;
|
|
return this.client.requestRegisterEmailToken(
|
|
this.signupInstance.email,
|
|
this.clientSecret,
|
|
1, // TODO: Multiple send attempts?
|
|
nextLink
|
|
).then(function(response) {
|
|
self.sid = response.sid;
|
|
return self._completeVerify();
|
|
}).then(function(request) {
|
|
request.poll_for_success = true;
|
|
return request;
|
|
}, function(error) {
|
|
console.error(error);
|
|
var e = {
|
|
isFatal: true
|
|
};
|
|
if (error.errcode == 'M_THREEPID_IN_USE') {
|
|
e.message = "This email address is already registered";
|
|
} else {
|
|
e.message = 'Unable to contact the given identity server';
|
|
}
|
|
throw e;
|
|
});
|
|
}
|
|
}
|
|
EmailIdentityStage.TYPE = "m.login.email.identity";
|
|
|
|
module.exports = {
|
|
[DummyStage.TYPE]: DummyStage,
|
|
[RecaptchaStage.TYPE]: RecaptchaStage,
|
|
[EmailIdentityStage.TYPE]: EmailIdentityStage
|
|
};
|