mirror of https://github.com/xwiki-labs/cryptpad
TOTP: recovery by secret key
This commit is contained in:
parent
be152fdaae
commit
e893613b43
|
@ -0,0 +1,128 @@
|
|||
define([
|
||||
'/api/config',
|
||||
'jquery',
|
||||
'/common/hyperscript.js',
|
||||
'/common/common-interface.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/pages.js'
|
||||
], function (Config, $, h, UI, Msg, Pages) {
|
||||
return function () {
|
||||
document.title = Msg.register_header;
|
||||
|
||||
var tos = $(UI.createCheckbox('accept-terms')).find('.cp-checkmark-label').append(Msg.register_acceptTerms).parent()[0];
|
||||
|
||||
var termsLink = Pages.customURLs.terms;
|
||||
$(tos).find('a').attr({
|
||||
href: termsLink,
|
||||
target: '_blank',
|
||||
tabindex: '-1',
|
||||
});
|
||||
|
||||
Msg.recovery_header = "Recover account"; // XXX
|
||||
Msg.recovery_totp = "Disable TOTP on your account"; // XXX
|
||||
Msg.recovery_totp_description = "If you've locked yourselves out of your CryptPad account because of a TOTP (Time based One Time Password) multi-factor authentication, you can use this form to disable this protection.";
|
||||
Msg.recovery_totp_beta = 'The TOTP multi-factor authentication has just been released. To avoid accidentaly locking accounts, the support team will temporarily agree to disable the protection even if you forgot your secret recovery key. <strong>If you forgot your recovery key, please copy the proof of ownership and send it to <a href="mailto:{0}">{0}</a></strong>';
|
||||
Msg.recovery_totp_login = "Please enter your login credentials";
|
||||
Msg.recovery_totp_secret = "Please enter your secret recovery key";
|
||||
Msg.recovery_totp_secret_ph = "Secret recovery key";
|
||||
Msg.recovery_totp_proof = "Proof of ownership";
|
||||
Msg.recovery_totp_continue = "Continue";
|
||||
Msg.recovery_totp_disable = "Disable TOTP";
|
||||
|
||||
Msg.recovery_totp_method_email = "Manual recovery by email";
|
||||
Msg.recovery_totp_method_secret = "Automatic recovery by secret key";
|
||||
|
||||
Msg.recovery_totp_wrong = "Invalid username or password";
|
||||
Msg.recovery_totp_error = "Unknown error. Please reload and try again.";
|
||||
Msg.recovery_totp_disabled = "Multi-factor authentication is already disabled for this account.";
|
||||
|
||||
var frame = function (content) {
|
||||
return [
|
||||
h('div#cp-main', [
|
||||
Pages.infopageTopbar(),
|
||||
h('div.container.cp-container', [
|
||||
h('div.row.cp-page-title', h('h1', Msg.recovery_header)),
|
||||
].concat(content)),
|
||||
Pages.infopageFooter(),
|
||||
]),
|
||||
];
|
||||
};
|
||||
|
||||
if (Config.restrictRegistration) {
|
||||
return frame([
|
||||
h('div.cp-restricted-registration', [
|
||||
h('p', Msg.register_registrationIsClosed),
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
var termsCheck;
|
||||
if (termsLink) {
|
||||
termsCheck = h('div.checkbox-container', tos);
|
||||
}
|
||||
|
||||
return frame([
|
||||
h('div.row.cp-recovery-det', [
|
||||
h('div#userForm.form-group.hidden.col-md-12', [
|
||||
h('h2', Msg.recovery_totp),
|
||||
h('div.cp-recovery-desc', [
|
||||
Msg._getKey('recovery_totp_description', [ Pages.Instance.name ]),
|
||||
]),
|
||||
h('div.cp-recovery-step.step1', [
|
||||
h('div.alert.alert-danger.wrong-cred.cp-hidden', Msg.recovery_totp_wrong),
|
||||
h('label', Msg.recovery_totp_login),
|
||||
h('input.form-control#username', {
|
||||
type: 'text',
|
||||
autocomplete: 'off',
|
||||
autocorrect: 'off',
|
||||
autocapitalize: 'off',
|
||||
spellcheck: false,
|
||||
placeholder: Msg.login_username,
|
||||
autofocus: true,
|
||||
}),
|
||||
h('input.form-control#password', {
|
||||
type: 'password',
|
||||
placeholder: Msg.login_password,
|
||||
}),
|
||||
h('div.cp-recover-button',
|
||||
h('button.btn.btn-primary#cp-recover-login', Msg.recovery_totp_continue)
|
||||
)
|
||||
]),
|
||||
h('div.cp-recovery-step.step2', { style: 'display: none;' }, [
|
||||
h('div.cp-recovery-method', [
|
||||
h('h3', Msg.recovery_totp_method_secret),
|
||||
h('label', Msg.recovery_totp_secret),
|
||||
h('input.form-control#totprecovery', {
|
||||
type: 'text',
|
||||
autocomplete: 'off',
|
||||
autocorrect: 'off',
|
||||
autocapitalize: 'off',
|
||||
spellcheck: false,
|
||||
placeholder: Msg.recovery_totp_secret_ph,
|
||||
autofocus: true,
|
||||
}),
|
||||
h('div.cp-recover-button',
|
||||
h('button.btn.btn-primary#cp-recover', Msg.recovery_totp_disable)
|
||||
)
|
||||
]),
|
||||
h('div.cp-recovery-desc', Msg.settings_kanbanTagsOr),
|
||||
h('div.cp-recovery-method', [
|
||||
h('h3', Msg.recovery_totp_method_email),
|
||||
Config.adminEmail ? UI.setHTML(h('div.alert.alert-warning'),
|
||||
Msg._getKey('recovery_totp_beta', [Config.adminEmail])) : undefined,
|
||||
h('label', Msg.recovery_totp_proof),
|
||||
h('textarea.cp-recover-email', {readonly: 'readonly'}),
|
||||
h('button.btn.btn-secondary', Msg.copyToClipboard),
|
||||
]),
|
||||
]),
|
||||
h('div.cp-recovery-step.step-info', { style: 'display: none;' }, [
|
||||
h('div.alert.alert-info.cp-hidden.disabled', Msg.recovery_totp_disabled),
|
||||
h('div.alert.alert-danger.cp-hidden.unknown-error', Msg.recovery_totp_error),
|
||||
]),
|
||||
])
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -20,6 +20,11 @@
|
|||
.infopages_main () {
|
||||
--LessLoader_require: LessLoader_currentFile();
|
||||
}
|
||||
|
||||
.cp-loading-noscroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.html {
|
||||
.font_main();
|
||||
@infopages_infobar-height: 64px;
|
||||
|
@ -105,7 +110,7 @@ body.html {
|
|||
filter: @cp_static-img-invert-filter;
|
||||
}
|
||||
|
||||
button {
|
||||
button:not(.btn) {
|
||||
outline: none;
|
||||
background-color: @cp_buttons-primary;
|
||||
color: @cp_buttons-primary-text;
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
@import (reference) "../include/infopages.less";
|
||||
@import (reference) "../include/colortheme-all.less";
|
||||
@import (reference) "../include/alertify.less";
|
||||
@import (reference) "../include/checkmark.less";
|
||||
@import (reference) "../include/forms.less";
|
||||
|
||||
&.cp-page-recovery {
|
||||
.infopages_main();
|
||||
.forms_main();
|
||||
|
||||
.alertify_main();
|
||||
.checkmark_main(20px);
|
||||
|
||||
.cp-container {
|
||||
.alert {
|
||||
font-size: @colortheme_app-font-size;
|
||||
}
|
||||
.form-group {
|
||||
.cp-recovery-desc {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cp-recovery-desc, .cp-recovery-step {
|
||||
width: 100%;
|
||||
}
|
||||
#register {
|
||||
&.btn {
|
||||
padding: .5rem .5rem;
|
||||
}
|
||||
margin-top: 16px;
|
||||
font-size: 1.25em;
|
||||
min-width: 30%;
|
||||
}
|
||||
}
|
||||
padding-bottom: 3em;
|
||||
min-height: 5vh;
|
||||
.cp-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.alertify {
|
||||
// workaround for alertify making empty p
|
||||
p:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
nav .btn-danger {
|
||||
line-height: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.cp-recovery-det {
|
||||
.cp-recover-button {
|
||||
text-align: center;
|
||||
}
|
||||
.cp-recovery-method {
|
||||
padding: 5px;
|
||||
border: 1px solid white;
|
||||
border-radius: 5px;
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
.cp-recover-email {
|
||||
height: 164px;
|
||||
}
|
||||
#userForm {
|
||||
padding: 15px;
|
||||
background-color: @cp_static-card-bg;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-bottom: 100px;
|
||||
border-radius: @infopages-radius-L;
|
||||
.cp-shadow();
|
||||
.form-control {
|
||||
border-radius: @infopages-radius;
|
||||
color: @cryptpad_text_col;
|
||||
background-color: @cp_forms-bg;
|
||||
margin-bottom: 10px;
|
||||
&:focus {
|
||||
border-color: @cryptpad_color_brand;
|
||||
}
|
||||
.tools_placeholder-color();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,8 @@ $(function () {
|
|||
require([ '/register/main.js' ], function () {});
|
||||
} else if (/^\/install\//.test(pathname)) {
|
||||
require([ '/install/main.js' ], function () {});
|
||||
} else if (/^\/recovery\//.test(pathname)) {
|
||||
require([ '/recovery/main.js' ], function () {});
|
||||
} else if (/^\/login\//.test(pathname)) {
|
||||
require([ '/login/main.js' ], function () {});
|
||||
} else if (/^\/($|^\/index\.html$)/.test(pathname)) {
|
||||
|
|
|
@ -23,6 +23,16 @@ var isValidOTP = otp => {
|
|||
!/\D/.test(otp);
|
||||
};
|
||||
|
||||
// basic definition of what we'll accept as a recovery key
|
||||
// 24 bytes encoded as b64 ==> 32 characters
|
||||
var isValidRecoveryKey = otp => {
|
||||
return isString(otp) &&
|
||||
// in the future this could be updated to support 8 digits
|
||||
otp.length === 32 &&
|
||||
// \D is non-digit characters, so this tests that it is exclusively numeric
|
||||
/[A-Za-z0-9+\/]{32}/.test(otp);
|
||||
};
|
||||
|
||||
// we'll only allow users to set up multi-factor auth
|
||||
// for keypairs they control which already have blocks
|
||||
// this check doesn't confirm that their id is valid base64
|
||||
|
@ -349,15 +359,15 @@ So, we should:
|
|||
// 3. They can produce a valid OTP for that block's TOTP secret
|
||||
// 4. They can sign for the block's public key
|
||||
const revoke = Commands.TOTP_REVOKE = function (Env, body, cb) {
|
||||
var { publicKey, code } = body;
|
||||
var { publicKey, code, recoveryKey } = body;
|
||||
|
||||
// they must provide a valid OTP code
|
||||
if (!isValidOTP(code)) { return void cb('E_INVALID'); }
|
||||
if (!isValidOTP(code) && !isValidRecoveryKey(recoveryKey)) { return void cb('E_INVALID'); }
|
||||
|
||||
// they must provide a valid block public key
|
||||
if (!isValidBlockId(publicKey)) { return void cb("INVALID_KEY"); }
|
||||
|
||||
var secret;
|
||||
var secret, recoveryStored;
|
||||
nThen(function (w) {
|
||||
// check that there is an MFA configuration for the given account
|
||||
MFA.read(Env, publicKey, w(function (err, content) {
|
||||
|
@ -378,7 +388,19 @@ const revoke = Commands.TOTP_REVOKE = function (Env, body, cb) {
|
|||
}
|
||||
|
||||
secret = parsed.secret;
|
||||
recoveryStored = parsed.contact;
|
||||
}));
|
||||
}).nThen(function (w) {
|
||||
if (!recoveryKey) { return; }
|
||||
w.abort();
|
||||
if (!/^secret:/.test(recoveryStored)) {
|
||||
return void cb("E_NO_RECOVERY_KEY");
|
||||
}
|
||||
recoveryStored = recoveryStored.slice(7);
|
||||
if (recoveryKey !== recoveryStored) {
|
||||
return void cb("E_WRONG_RECOVERY_KEY");
|
||||
}
|
||||
cb();
|
||||
}).nThen(function () {
|
||||
let decoded = decode32(secret);
|
||||
if (!decoded) {
|
||||
|
|
|
@ -985,6 +985,7 @@ define([
|
|||
todo();
|
||||
}
|
||||
|
||||
$('html').toggleClass('cp-loading-noscroll', true);
|
||||
// Remove the inner placeholder (iframe)
|
||||
$('#placeholder').remove();
|
||||
};
|
||||
|
@ -1004,6 +1005,7 @@ define([
|
|||
$loading.find('.cp-loading-progress').remove(); // Remove the progress list
|
||||
setTimeout(cb, 750);
|
||||
$('head > link[href^="/customize/src/pre-loading.css"]').remove();
|
||||
$('html').toggleClass('cp-loading-noscroll', false);
|
||||
};
|
||||
UI.errorLoadingScreen = function (error, transparent, exitable) {
|
||||
if (error === 'Error: XDR encoding failure') {
|
||||
|
@ -1044,6 +1046,7 @@ define([
|
|||
$(window).keydown(function (e) { // XXX what if they don't have a keyboard?
|
||||
if (e.which === 27) {
|
||||
$loading.hide();
|
||||
$('html').toggleClass('cp-loading-noscroll', false);
|
||||
if (typeof(exitable) === "function") { exitable(); }
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||
<head>
|
||||
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||
<script src="/customize/pre-loading.js?ver=1.1"></script>
|
||||
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
|
||||
<script async data-bootload="/customize/template.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
</head>
|
||||
<body class="html">
|
||||
<noscript></noscript>
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
define([
|
||||
'jquery',
|
||||
'json.sortify',
|
||||
'/customize/login.js',
|
||||
'/common/cryptpad-common.js',
|
||||
//'/common/test.js',
|
||||
'/common/common-credential.js',
|
||||
'/common/common-interface.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/common-constants.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/outer/local-store.js',
|
||||
'/common/outer/login-block.js',
|
||||
'/common/outer/http-command.js',
|
||||
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
], function ($, Sortify, Login, Cryptpad, /*Test,*/ Cred, UI, Util, Realtime, Constants, Feedback,
|
||||
LocalStore, Block, ServerCommand) {
|
||||
if (window.top !== window) { return; }
|
||||
|
||||
var Messages = Cryptpad.Messages;
|
||||
var Nacl = window.nacl;
|
||||
|
||||
$(function () {
|
||||
if (LocalStore.isLoggedIn()) {
|
||||
// already logged in, redirect to drive
|
||||
document.location.href = '/drive/';
|
||||
return;
|
||||
}
|
||||
|
||||
// text and password input fields
|
||||
var $uname = $('#username');
|
||||
var $passwd = $('#password');
|
||||
var $recoveryKey = $('#totprecovery');
|
||||
|
||||
var $step1 = $('.cp-recovery-step.step1');
|
||||
var $step2 = $('.cp-recovery-step.step2');
|
||||
var $stepInfo = $('.cp-recovery-step.step-info');
|
||||
var $totpProof = $('textarea.cp-recover-email');
|
||||
|
||||
[ $uname, $passwd]
|
||||
.some(function ($el) { if (!$el.val()) { $el.focus(); return true; } });
|
||||
|
||||
var totpStep2 = function () {
|
||||
$step1.hide();
|
||||
$step2.show();
|
||||
};
|
||||
var totpStepInfo = function (cls) {
|
||||
$step1.hide();
|
||||
$step2.hide();
|
||||
$stepInfo.find('.alert').toggleClass('cp-hidden', true);
|
||||
$stepInfo.find(cls).toggleClass('cp-hidden', false);
|
||||
$stepInfo.show();
|
||||
};
|
||||
|
||||
$step2.show(); // XXX debug
|
||||
|
||||
var addProof = function (blockKeys) {
|
||||
var pub = blockKeys.sign.publicKey;
|
||||
var sec = blockKeys.sign.secretKey;
|
||||
var toSign = {
|
||||
intent: 'Disable TOTP',
|
||||
date: new Date().toISOString(),
|
||||
blockId: Nacl.util.encodeBase64(pub),
|
||||
};
|
||||
var proof = Nacl.sign.detached(Nacl.util.decodeUTF8(Sortify(toSign)), sec);
|
||||
toSign.proof = Nacl.util.encodeBase64(proof);
|
||||
$totpProof.html(JSON.stringify(toSign, 0, 2));
|
||||
};
|
||||
|
||||
var revokeTOTP = function (blockKeys) {
|
||||
var recoveryKey = $recoveryKey.val().trim();
|
||||
if (!recoveryKey || recoveryKey.length !== 32) {
|
||||
return void UI.warn(Messages.error); // XXX error message?
|
||||
}
|
||||
ServerCommand(blockKeys.sign, {
|
||||
command: 'TOTP_REVOKE',
|
||||
recoveryKey: recoveryKey
|
||||
}, function (err, response) {
|
||||
var success = !err && response && response.success;
|
||||
if (!success) {
|
||||
console.error(err, response);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
// XXX redirect to login?
|
||||
return void UI.log(Messages.ui_success);
|
||||
});
|
||||
};
|
||||
|
||||
var $recoverLogin = $('button#cp-recover-login');
|
||||
var $recoverConfirm = $('button#cp-recover');
|
||||
var blockKeys;
|
||||
$recoverLogin.click(function () {
|
||||
UI.addLoadingScreen({
|
||||
loadingText: Messages.login_hashing
|
||||
});
|
||||
var name = $uname.val();
|
||||
var pw = $passwd.val();
|
||||
setTimeout(function () {
|
||||
Login.Cred.deriveFromPassphrase(name, pw, Login.requiredBytes, function (bytes) {
|
||||
var result = Login.allocateBytes(bytes);
|
||||
var blockHash = result.blockHash;
|
||||
var parsed = Block.parseBlockHash(blockHash);
|
||||
addProof(result.blockKeys);
|
||||
blockKeys = result.blockKeys;
|
||||
Util.getBlock(parsed.href, {}, function (err, v) {
|
||||
UI.removeLoadingScreen();
|
||||
if (v && !err) {
|
||||
return totpStepInfo('.disabled');
|
||||
}
|
||||
if (err === 401) {
|
||||
return totpStep2(result.blockKeys);
|
||||
}
|
||||
if (err === 404) {
|
||||
return $step1.find('.wrong-cred').toggleClass('cp-hidden', false);
|
||||
}
|
||||
totpStepInfo('.unknown-error');
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
|
||||
UI.confirmButton($recoverConfirm[0], {
|
||||
multiple: true
|
||||
}, function () {
|
||||
if (!blockKeys) { return; }
|
||||
// XXX disable TOTP automatically
|
||||
revokeTOTP(blockKeys);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -60,6 +60,9 @@ define([
|
|||
Messages.settings_totp_tuto = "Scan this QR code with a authenticator application. Obtain a valid authentication code and confirm before it expires."; // XXX
|
||||
Messages.settings_totp_confirm = "Enable TOTP with this secret"; // XXX
|
||||
|
||||
Messages.settings_totp_recovery_header = "Recovery code";
|
||||
Messages.settings_totp_recovery = "If you lose access to your authenticator app, you may lock yourselves out of your CryptPad account. <strong>To prevent this, please store the following recovery secret key.</strong> You'll be able to use it to disable the multi-factor authentication. Do not share this key.";
|
||||
|
||||
var categories = {
|
||||
'account': [ // Msg.settings_cat_account
|
||||
'cp-settings-own-drive',
|
||||
|
@ -864,17 +867,15 @@ define([
|
|||
var button = h('button.btn.btn-primary', Messages.settings_totp_enable);
|
||||
$(button).click(function () {
|
||||
$content.empty();
|
||||
var Base32, Block, QRCode, Nacl;
|
||||
var Base32, QRCode, Nacl;
|
||||
var blockKeys;
|
||||
nThen(function (waitFor) {
|
||||
require([
|
||||
'/auth/base32.js',
|
||||
'/common/outer/login-block.js',
|
||||
'/lib/qrcode.min.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
], waitFor(function (_Base32, _Login, _Block) {
|
||||
], waitFor(function (_Base32) {
|
||||
Base32 = _Base32;
|
||||
Block = _Block;
|
||||
QRCode = window.QRCode;
|
||||
Nacl = window.nacl;
|
||||
}));
|
||||
|
@ -943,6 +944,7 @@ define([
|
|||
var updateURI = function (secret) {
|
||||
$container.empty();
|
||||
|
||||
var recoverySecret = Nacl.util.encodeBase64(Nacl.randomBytes(24));
|
||||
var username = privateData.accountName;
|
||||
var hostname = new URL(privateData.origin).hostname;
|
||||
var label = "CryptPad";
|
||||
|
@ -972,13 +974,16 @@ define([
|
|||
$confirmBtn.attr('disabled', 'disabled');
|
||||
lock = true;
|
||||
|
||||
var data = {
|
||||
command: 'TOTP_SETUP',
|
||||
secret: secret,
|
||||
contact: "secret:" + recoverySecret, // XXX add other recovery options
|
||||
code: code,
|
||||
};
|
||||
|
||||
sframeChan.query("Q_SETTINGS_TOTP_SETUP", {
|
||||
key: blockKeys.sign,
|
||||
data: {
|
||||
command: 'TOTP_SETUP',
|
||||
secret: secret,
|
||||
code: code,
|
||||
}
|
||||
data: data
|
||||
}, function (err, obj) {
|
||||
lock = false;
|
||||
$OTPEntry.val("");
|
||||
|
@ -992,11 +997,18 @@ define([
|
|||
|
||||
});
|
||||
|
||||
var recoveryBlock = h('div.alert.alert-danger', [
|
||||
h('h3', Messages.settings_totp_recovery_header),
|
||||
UI.setHTML(h('p'), Messages.settings_totp_recovery),
|
||||
UI.dialog.selectable(recoverySecret)
|
||||
]);
|
||||
|
||||
$container.append([
|
||||
uriInput,
|
||||
qr,
|
||||
h('br'),
|
||||
description,
|
||||
recoveryBlock,
|
||||
OTPEntry,
|
||||
confirmOTP
|
||||
]);
|
||||
|
|
|
@ -79,7 +79,6 @@ define([
|
|||
], function (ServerCommand) {
|
||||
ServerCommand(obj.key, obj.data, function (err, response) {
|
||||
cb({ success: Boolean(!err && response && response.bearer) });
|
||||
console.log(response);
|
||||
if (response && response.bearer) {
|
||||
Utils.LocalStore.setSessionToken(response.bearer);
|
||||
}
|
||||
|
@ -92,7 +91,6 @@ define([
|
|||
], function (ServerCommand) {
|
||||
ServerCommand(obj.key, obj.data, function (err, response) {
|
||||
cb({ success: Boolean(!err && response && response.success) });
|
||||
console.error(response);
|
||||
if (response && response.success) {
|
||||
Utils.LocalStore.setSessionToken('');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue