Supported 2-step verifications
Disabled webpage attachment
This commit is contained in:
parent
8047209ba5
commit
8464acdfdc
@ -30,7 +30,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
LayoutSwitchService.start();
|
||||
})
|
||||
|
||||
.controller('AppLoginController', function ($scope, $rootScope, $location, $timeout, $modal, $modalStack, MtpApiManager, ErrorService, NotificationsManager, ChangelogNotifyService, IdleManager, LayoutSwitchService, TelegramMeWebService, _) {
|
||||
.controller('AppLoginController', function ($scope, $rootScope, $location, $timeout, $modal, $modalStack, MtpApiManager, ErrorService, NotificationsManager, PasswordManager, ChangelogNotifyService, IdleManager, LayoutSwitchService, TelegramMeWebService, _) {
|
||||
|
||||
$modalStack.dismissAll();
|
||||
IdleManager.start();
|
||||
@ -156,6 +156,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
|
||||
var callTimeout;
|
||||
var updatePasswordTimeout = false;
|
||||
|
||||
function saveAuth (result) {
|
||||
MtpApiManager.setUserAuth(options.dcID, {
|
||||
@ -204,7 +205,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
phone_number: $scope.credentials.phone_full,
|
||||
// sms_type: 5,
|
||||
api_id: Config.App.id,
|
||||
api_hash: Config.App.hash
|
||||
api_hash: Config.App.hash,
|
||||
lang_code: navigator.language || 'en'
|
||||
}, options).then(function (sentCode) {
|
||||
$scope.progress.enabled = false;
|
||||
|
||||
@ -290,6 +292,16 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
} else if (error.code == 400 && error.type == 'PHONE_NUMBER_OCCUPIED') {
|
||||
error.handled = true;
|
||||
return $scope.logIn(false);
|
||||
} else if (error.code == 401 && error.type == 'SESSION_PASSWORD_NEEDED') {
|
||||
$scope.progress.enabled = true;
|
||||
updatePasswordState().then(function () {
|
||||
$scope.progress.enabled = false;
|
||||
$scope.credentials.phone_code_valid = true;
|
||||
$scope.credentials.password_needed = true;
|
||||
$scope.about = {};
|
||||
});
|
||||
error.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -312,6 +324,82 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
};
|
||||
|
||||
$scope.checkPassword = function () {
|
||||
return PasswordManager.check($scope.password, $scope.credentials.password, options).then(saveAuth, function (error) {
|
||||
switch (error.type) {
|
||||
case 'PASSWORD_HASH_INVALID':
|
||||
$scope.error = {field: 'password'};
|
||||
error.handled = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.forgotPassword = function (event) {
|
||||
PasswordManager.requestRecovery($scope.password, options).then(function (emailRecovery) {
|
||||
|
||||
var scope = $rootScope.$new();
|
||||
scope.recovery = emailRecovery;
|
||||
scope.options = options;
|
||||
var modal = $modal.open({
|
||||
scope: scope,
|
||||
templateUrl: templateUrl('password_recovery_modal'),
|
||||
controller: 'PasswordRecoveryModalController',
|
||||
windowClass: 'md_simple_modal_window mobile_modal'
|
||||
});
|
||||
|
||||
modal.result.then(function (result) {
|
||||
if (result && result.user) {
|
||||
saveAuth(result);
|
||||
} else {
|
||||
$scope.canReset = true;
|
||||
}
|
||||
});
|
||||
|
||||
}, function (error) {
|
||||
switch (error.type) {
|
||||
case 'PASSWORD_EMPTY':
|
||||
$scope.logIn();
|
||||
break;
|
||||
case 'PASSWORD_RECOVERY_NA':
|
||||
$timeout(function () {
|
||||
$scope.canReset = true;
|
||||
}, 1000);
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
return cancelEvent(event);
|
||||
};
|
||||
|
||||
$scope.resetAccount = function () {
|
||||
ErrorService.confirm({
|
||||
type: 'RESET_ACCOUNT'
|
||||
}).then(function () {
|
||||
$scope.progress.enabled = true;
|
||||
MtpApiManager.invokeApi('account.deleteAccount', {
|
||||
reason: 'Forgot password'
|
||||
}, options).then(function () {
|
||||
delete $scope.progress.enabled;
|
||||
delete $scope.credentials.password_needed;
|
||||
$scope.credentials.phone_unoccupied = true;
|
||||
}, function () {
|
||||
delete $scope.progress.enabled;
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
function updatePasswordState () {
|
||||
// $timeout.cancel(updatePasswordTimeout);
|
||||
// updatePasswordTimeout = false;
|
||||
return PasswordManager.getState(options).then(function (result) {
|
||||
return $scope.password = result;
|
||||
// if (result._ == 'account.noPassword' && result.email_unconfirmed_pattern) {
|
||||
// updatePasswordTimeout = $timeout(updatePasswordState, 5000);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
ChangelogNotifyService.checkUpdate();
|
||||
LayoutSwitchService.start();
|
||||
})
|
||||
@ -364,6 +452,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
};
|
||||
|
||||
// setTimeout($scope.openSettings, 1000);
|
||||
|
||||
$scope.openFaq = function () {
|
||||
var url = 'https://telegram.org/faq';
|
||||
switch (Config.I18n.locale) {
|
||||
@ -2535,10 +2625,17 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
$scope.password = {_: 'account.noPassword'};
|
||||
updatePasswordState();
|
||||
var updatePasswordTimeout = false;
|
||||
|
||||
$scope.changePassword = function (options) {
|
||||
options = options || {};
|
||||
if (options.action == 'cancel_email') {
|
||||
return ErrorService.confirm({type: 'PASSWORD_ABORT_SETUP'}).then(function () {
|
||||
PasswordManager.updateSettings($scope.password, {email: ''}).then(updatePasswordState);
|
||||
});
|
||||
}
|
||||
var scope = $rootScope.$new();
|
||||
scope.password = $scope.password;
|
||||
angular.extend(scope, options);
|
||||
var modal = $modal.open({
|
||||
scope: scope,
|
||||
@ -2550,9 +2647,14 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
modal.result['finally'](updatePasswordState);
|
||||
};
|
||||
|
||||
function updatePasswordState (argument) {
|
||||
PasswordManager.getPasswordState().then(function (result) {
|
||||
function updatePasswordState () {
|
||||
$timeout.cancel(updatePasswordTimeout);
|
||||
updatePasswordTimeout = false;
|
||||
PasswordManager.getState().then(function (result) {
|
||||
$scope.password = result;
|
||||
if (result._ == 'account.noPassword' && result.email_unconfirmed_pattern) {
|
||||
updatePasswordTimeout = $timeout(updatePasswordState, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -2882,7 +2984,141 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
})
|
||||
})
|
||||
|
||||
.controller('PasswordUpdateModalController', function ($scope, PasswordManager, MtpApiManager) {
|
||||
.controller('PasswordUpdateModalController', function ($scope, $q, _, PasswordManager, MtpApiManager, ErrorService, $modalInstance) {
|
||||
|
||||
$scope.passwordSettings = {};
|
||||
|
||||
$scope.updatePassword = function () {
|
||||
delete $scope.passwordSettings.error_field;
|
||||
|
||||
var confirmPromise;
|
||||
if ($scope.action == 'disable') {
|
||||
confirmPromise = $q.when();
|
||||
}
|
||||
else {
|
||||
if (!$scope.passwordSettings.new_password) {
|
||||
$scope.passwordSettings.error_field = 'new_password';
|
||||
$scope.$broadcast('new_password_focus');
|
||||
return false;
|
||||
}
|
||||
if ($scope.passwordSettings.new_password != $scope.passwordSettings.confirm_password) {
|
||||
$scope.passwordSettings.error_field = 'confirm_password';
|
||||
$scope.$broadcast('confirm_password_focus');
|
||||
return false;
|
||||
}
|
||||
confirmPromise = $scope.passwordSettings.email
|
||||
? $q.when()
|
||||
: ErrorService.confirm({type: 'RECOVERY_EMAIL_EMPTY'});
|
||||
}
|
||||
|
||||
$scope.passwordSettings.loading = true;
|
||||
|
||||
confirmPromise.then(function () {
|
||||
PasswordManager.updateSettings($scope.password, {
|
||||
cur_password: $scope.passwordSettings.cur_password || '',
|
||||
new_password: $scope.passwordSettings.new_password,
|
||||
email: $scope.passwordSettings.email,
|
||||
hint: $scope.passwordSettings.hint
|
||||
}).then(function (result) {
|
||||
delete $scope.passwordSettings.loading;
|
||||
$modalInstance.close(true);
|
||||
if ($scope.action == 'disable') {
|
||||
ErrorService.alert(
|
||||
_('error_modal_password_disabled_title'),
|
||||
_('error_modal_password_disabled_descripion')
|
||||
);
|
||||
} else {
|
||||
ErrorService.alert(
|
||||
_('error_modal_password_success_title'),
|
||||
_('error_modal_password_success_descripion')
|
||||
);
|
||||
}
|
||||
}, function (error) {
|
||||
switch (error.type) {
|
||||
case 'PASSWORD_HASH_INVALID':
|
||||
case 'NEW_PASSWORD_BAD':
|
||||
$scope.passwordSettings.error_field = 'cur_password';
|
||||
error.handled = true;
|
||||
$scope.$broadcast('cur_password_focus');
|
||||
break;
|
||||
case 'NEW_PASSWORD_BAD':
|
||||
$scope.passwordSettings.error_field = 'new_password';
|
||||
error.handled = true;
|
||||
break;
|
||||
case 'EMAIL_INVALID':
|
||||
$scope.passwordSettings.error_field = 'email';
|
||||
error.handled = true;
|
||||
break;
|
||||
case 'EMAIL_UNCONFIRMED':
|
||||
ErrorService.alert(
|
||||
_('error_modal_email_unconfirmed_title'),
|
||||
_('error_modal_email_unconfirmed_descripion')
|
||||
);
|
||||
$modalInstance.close(true);
|
||||
error.handled = true;
|
||||
break;
|
||||
}
|
||||
delete $scope.passwordSettings.loading;
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
switch ($scope.action) {
|
||||
case 'disable':
|
||||
$scope.passwordSettings.new_password = '';
|
||||
break;
|
||||
case 'create':
|
||||
onContentLoaded(function () {
|
||||
$scope.$broadcast('new_password_focus');
|
||||
});
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$scope.$watch('passwordSettings.new_password', function (newValue) {
|
||||
var len = newValue && newValue.length || 0;
|
||||
if (!len) {
|
||||
$scope.passwordSettings.hint = '';
|
||||
}
|
||||
else if (len <= 3) {
|
||||
$scope.passwordSettings.hint = '***';
|
||||
}
|
||||
else {
|
||||
$scope.passwordSettings.hint = newValue.charAt(0) + (new Array(len - 1)).join('*') + newValue.charAt(len - 1);
|
||||
}
|
||||
$scope.$broadcast('value_updated');
|
||||
})
|
||||
})
|
||||
|
||||
.controller('PasswordRecoveryModalController', function ($scope, $q, _, PasswordManager, MtpApiManager, ErrorService, $modalInstance) {
|
||||
|
||||
$scope.checkCode = function () {
|
||||
$scope.recovery.updating = true;
|
||||
|
||||
PasswordManager.recover($scope.recovery.code, $scope.options).then(function (result) {
|
||||
ErrorService.alert(
|
||||
_('error_modal_password_disabled_title'),
|
||||
_('error_modal_password_disabled_descripion')
|
||||
);
|
||||
$modalInstance.close(result);
|
||||
}, function (error) {
|
||||
delete $scope.recovery.updating;
|
||||
switch (error.type) {
|
||||
case 'CODE_EMPTY':
|
||||
case 'CODE_INVALID':
|
||||
$scope.recovery.error_field = 'code';
|
||||
error.handled = true;
|
||||
break;
|
||||
|
||||
case 'PASSWORD_EMPTY':
|
||||
case 'PASSWORD_RECOVERY_NA':
|
||||
case 'PASSWORD_RECOVERY_EXPIRED':
|
||||
$modalInstance.dismiss();
|
||||
error.handled = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
|
@ -2840,7 +2840,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
});
|
||||
}
|
||||
|
||||
$scope.$on('value_updated', function (event, args) {
|
||||
$scope.$on('value_updated', function () {
|
||||
setZeroTimeout(function () {
|
||||
updateHasValueClass();
|
||||
});
|
||||
@ -2858,6 +2858,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
element.on('keydown', function (event) {
|
||||
if (event.keyCode == 13) {
|
||||
element.trigger('submit');
|
||||
return cancelEvent(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -651,7 +651,7 @@ angular.module('izhukov.utils', [])
|
||||
awaiting = {},
|
||||
webCrypto = Config.Modes.webcrypto && window.crypto && (window.crypto.subtle || window.crypto.webkitSubtle)/* || window.msCrypto && window.msCrypto.subtle*/,
|
||||
useSha1Crypto = webCrypto && webCrypto.digest !== undefined,
|
||||
useSha2Crypto = webCrypto && webCrypto.digest !== undefined,
|
||||
useSha256Crypto = webCrypto && webCrypto.digest !== undefined,
|
||||
finalizeTask = function (taskID, result) {
|
||||
var deferred = awaiting[taskID];
|
||||
if (deferred !== undefined) {
|
||||
@ -729,8 +729,8 @@ angular.module('izhukov.utils', [])
|
||||
return sha1HashSync(bytes);
|
||||
});
|
||||
},
|
||||
sha2Hash: function (bytes) {
|
||||
if (useSha2Crypto) {
|
||||
sha256Hash: function (bytes) {
|
||||
if (useSha256Crypto) {
|
||||
var deferred = $q.defer(),
|
||||
bytesTyped = Array.isArray(bytes) ? convertToUint8Array(bytes) : bytes;
|
||||
// console.log(dT(), 'Native sha1 start');
|
||||
@ -739,7 +739,7 @@ angular.module('izhukov.utils', [])
|
||||
deferred.resolve(digest);
|
||||
}, function (e) {
|
||||
console.error('Crypto digest error', e);
|
||||
useSha2Crypto = false;
|
||||
useSha256Crypto = false;
|
||||
deferred.resolve(sha256HashSync(bytes));
|
||||
});
|
||||
|
||||
|
@ -122,6 +122,9 @@ TLSerialization.prototype.storeDouble = function (f) {
|
||||
TLSerialization.prototype.storeString = function (s, field) {
|
||||
this.debug && console.log('>>>', s, (field || '') + ':string');
|
||||
|
||||
if (s === undefined) {
|
||||
s = '';
|
||||
}
|
||||
var sUTF8 = unescape(encodeURIComponent(s));
|
||||
|
||||
this.checkLength(sUTF8.length + 8);
|
||||
@ -151,6 +154,9 @@ TLSerialization.prototype.storeBytes = function (bytes, field) {
|
||||
if (bytes instanceof ArrayBuffer) {
|
||||
bytes = new Uint8Array(bytes);
|
||||
}
|
||||
else if (bytes === undefined) {
|
||||
bytes = [];
|
||||
}
|
||||
this.debug && console.log('>>>', bytesToHex(bytes), (field || '') + ':bytes');
|
||||
|
||||
var len = bytes.byteLength || bytes.length;
|
||||
|
@ -54,6 +54,26 @@
|
||||
"settings_modal_follow_us_twitter": "Follow us on Twitter!",
|
||||
"settings_modal_recent_updates": "Recent updates (ver. {version})",
|
||||
|
||||
"settings_modal_set_password": "Set Additional Password",
|
||||
"settings_modal_change_password": "Change password",
|
||||
"settings_modal_disable_password": "Turn off",
|
||||
"settings_modal_password_email_pending": "Click the link in {email} to complete Two-Step Verification setup.",
|
||||
"settings_modal_password_email_pending_cancel": "Abort",
|
||||
|
||||
"password_delete_title": "Turn Password Off",
|
||||
"password_change_title": "Two-Step Verification",
|
||||
"password_current_placeholder": "Enter current password",
|
||||
"password_create_placeholder": "Enter a password",
|
||||
"password_new_placeholder": "Enter new password",
|
||||
"password_confirm_placeholder": "Re-enter new password",
|
||||
"password_hint_placeholder": "Enter password hint",
|
||||
"password_email_placeholder": "Enter recovery e-mail",
|
||||
"password_create_description": "This password will be required when you log in on a new device in addition to the pin code.",
|
||||
"password_create_active": "Saving...",
|
||||
"password_create_submit": "Save",
|
||||
"password_delete_active": "Deleting...",
|
||||
"password_delete_submit": "Delete password",
|
||||
|
||||
"page_title_pluralize_notifications": "{'0': 'No notifications', 'one': '1 notification', 'other': '{} notifications'}",
|
||||
|
||||
"profile_edit_modal_title": "Edit profile",
|
||||
@ -147,6 +167,9 @@
|
||||
"confirm_modal_migrate_to_https_md": "Telegram Web now supports additional SSL encryption. Would you like to switch to HTTPS?\nThe HTTP version will be disabled soon.",
|
||||
"confirm_modal_resize_desktop_md": "Would you like to switch to desktop version?",
|
||||
"confirm_modal_resize_mobile_md": "Would you like to switch to mobile version?",
|
||||
"confirm_modal_recovery_email_empty_md": "Warning! Are you sure you don't want to add a password recovery e-mail?\n\nIf you forget your password, you will lose access to your Telegram account",
|
||||
"confirm_modal_abort_password_setup": "Abort two-step verification setup?",
|
||||
"confirm_modal_reset_account_md": "Are you sure?\nThis action can not be undone.\n\nYou will lose all your chats and messages, along with any media and files you shared, if you proceed with resetting your account.",
|
||||
"confirm_modal_are_u_sure": "Are you sure?",
|
||||
|
||||
"confirm_modal_logout_submit": "Log Out",
|
||||
@ -161,6 +184,7 @@
|
||||
"confirm_modal_share_video_submit": "Forward video",
|
||||
"confirm_modal_share_contact_submit": "Send contact",
|
||||
"confirm_modal_share_file_submit": "Share file",
|
||||
"confirm_modal_reset_account_submit": "Reset my account",
|
||||
|
||||
"contacts_modal_edit_list": "Edit",
|
||||
"contacts_modal_edit_cancel": "Cancel",
|
||||
@ -232,7 +256,12 @@
|
||||
"error_modal_flood_title": "Too fast",
|
||||
"error_modal_internal_title": "Server error",
|
||||
"error_modal_alert": "Alert",
|
||||
"error_modal_email_unconfirmed_title": "Almost there!",
|
||||
"error_modal_email_unconfirmed_descripion": "Please check your e-mail (don't forget the spam folder) to complete Two-Step Verification setup.",
|
||||
"error_modal_password_success_title": "Success!",
|
||||
"error_modal_password_disabled_title": "Password deactivated",
|
||||
"error_modal_media_not_supported_title": "Unsupported media",
|
||||
"error_modal_recovery_na_title": "Sorry",
|
||||
|
||||
"error_modal_network_description": "Please check your internet connection.",
|
||||
"error_modal_firstname_invali_description": "The first name you entered is invalid.",
|
||||
@ -258,6 +287,9 @@
|
||||
"error_modal_internal_description": "Internal server error occured. Please try again later.",
|
||||
"error_modal_tech_details": "Technical details here",
|
||||
"error_modal_multiple_open_tabs": "Please close other Telegram app tabs.",
|
||||
"error_modal_recovery_na_description": "Since you haven't provided a recovery e-mail when setting up your password, your remaining options are either to remember your password or to reset your account.",
|
||||
"error_modal_password_success_descripion": "Your password for Two-Step Verification is now active.",
|
||||
"error_modal_password_disabled_descripion": "You have disabled Two-Step Verification.",
|
||||
|
||||
|
||||
"head_telegram": "Telegram",
|
||||
@ -367,6 +399,21 @@
|
||||
"login_about_desc3_md": "Our {source-link: source code} is open, so everyone can make a contribution.",
|
||||
"login_about_intro": "Welcome to the official Telegram web-client.",
|
||||
"login_about_learn": "Learn more",
|
||||
"login_password_title": "Password",
|
||||
"login_password_label": "You have enabled Two-Step Verification, so your account is protected with an additional password.",
|
||||
"login_password_forgot_link": "Forgot password?",
|
||||
"login_account_reset": "Reset account",
|
||||
"login_password": "Your Password",
|
||||
"login_incorrect_password": "Incorrect password",
|
||||
"login_checking_password": "Checking",
|
||||
"login_recovery_title": "Forgot password?",
|
||||
"login_code_placeholder": "Code",
|
||||
"login_code_incorrect": "Incorrect code",
|
||||
"login_recovery_description_md": "We have sent a recovery code to the e-mail you provided:\n\n{email}\n\nPlease check your e-mail and enter the 6-digit code we have sent here.",
|
||||
|
||||
"password_recover_active": "Checking...",
|
||||
"password_recover_submit": "Submit",
|
||||
|
||||
|
||||
"login_controller_unknown_country": "Unknown",
|
||||
|
||||
|
@ -4537,18 +4537,104 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
|
||||
})
|
||||
|
||||
.service('PasswordManager', function ($timeout, $rootScope, MtpApiManager) {
|
||||
.service('PasswordManager', function ($timeout, $q, $rootScope, MtpApiManager, CryptoWorker, MtpSecureRandom) {
|
||||
|
||||
return {
|
||||
getPasswordState: getPasswordState
|
||||
check: check,
|
||||
getState: getState,
|
||||
requestRecovery: requestRecovery,
|
||||
recover: recover,
|
||||
updateSettings: updateSettings
|
||||
};
|
||||
|
||||
function getPasswordState () {
|
||||
return MtpApiManager.invokeApi('account.getPassword').then(function (result) {
|
||||
function getState (options) {
|
||||
return MtpApiManager.invokeApi('account.getPassword', {}, options).then(function (result) {
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function updateSettings (state, settings) {
|
||||
var currentHashPromise;
|
||||
var newHashPromise;
|
||||
var params = {
|
||||
new_settings: {
|
||||
_: 'account.passwordInputSettings',
|
||||
flags: 0,
|
||||
hint: settings.hint || ''
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof settings.cur_password === 'string' &&
|
||||
settings.cur_password.length > 0) {
|
||||
currentHashPromise = makePasswordHash(state.current_salt, settings.cur_password);
|
||||
} else {
|
||||
currentHashPromise = $q.when([]);
|
||||
}
|
||||
|
||||
if (typeof settings.new_password === 'string' &&
|
||||
settings.new_password.length > 0) {
|
||||
var saltRandom = new Array(8);
|
||||
var newSalt = bufferConcat(state.new_salt, saltRandom);
|
||||
MtpSecureRandom.nextBytes(saltRandom);
|
||||
newHashPromise = makePasswordHash(newSalt, settings.new_password);
|
||||
params.new_settings.new_salt = newSalt;
|
||||
params.new_settings.flags |= 1;
|
||||
} else {
|
||||
if (typeof settings.new_password === 'string') {
|
||||
params.new_settings.flags |= 1;
|
||||
params.new_settings.new_salt = [];
|
||||
}
|
||||
newHashPromise = $q.when([]);
|
||||
}
|
||||
|
||||
if (typeof settings.email === 'string') {
|
||||
params.new_settings.flags |= 2;
|
||||
params.new_settings.email = settings.email || '';
|
||||
}
|
||||
|
||||
return $q.all([currentHashPromise, newHashPromise]).then(function (hashes) {
|
||||
params.current_password_hash = hashes[0];
|
||||
params.new_settings.new_password_hash = hashes[1];
|
||||
|
||||
return MtpApiManager.invokeApi('account.updatePasswordSettings', params);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function check (state, password, options) {
|
||||
return makePasswordHash(state.current_salt, password).then(function (passwordHash) {
|
||||
return MtpApiManager.invokeApi('auth.checkPassword', {
|
||||
password_hash: passwordHash
|
||||
}, options);
|
||||
});
|
||||
}
|
||||
|
||||
function requestRecovery (state, options) {
|
||||
return MtpApiManager.invokeApi('auth.requestPasswordRecovery', {}, options);
|
||||
}
|
||||
|
||||
function recover (code, options) {
|
||||
return MtpApiManager.invokeApi('auth.recoverPassword', {
|
||||
code: code
|
||||
}, options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function makePasswordHash (salt, password) {
|
||||
var passwordUTF8 = unescape(encodeURIComponent(password));
|
||||
|
||||
var buffer = new ArrayBuffer(passwordUTF8.length);
|
||||
var byteView = new Uint8Array(buffer);
|
||||
for (var i = 0, len = passwordUTF8.length; i < len; i++) {
|
||||
byteView[i] = passwordUTF8.charCodeAt(i);
|
||||
}
|
||||
|
||||
buffer = bufferConcat(bufferConcat(salt, byteView), salt);
|
||||
|
||||
return CryptoWorker.sha256Hash(buffer);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
@ -242,6 +242,9 @@ input[type="number"] {
|
||||
padding: 0;
|
||||
margin: 0 0 22px;
|
||||
}
|
||||
.md-input-grouped {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.md-input-label {
|
||||
font-weight: normal;
|
||||
@ -974,6 +977,12 @@ a.tg_radio_on:hover i.icon-radio {
|
||||
font-size: 13px;
|
||||
line-height: 160%;
|
||||
}
|
||||
.login_form_hint {
|
||||
color: #999;
|
||||
margin: 0 0 20px;
|
||||
font-size: 13px;
|
||||
line-height: 160%;
|
||||
}
|
||||
.login_form_messaging {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
@ -1002,6 +1011,15 @@ a.tg_radio_on:hover i.icon-radio {
|
||||
}
|
||||
}
|
||||
|
||||
.login_forgot_button {
|
||||
text-align: center;
|
||||
margin: 30px 0 10px;
|
||||
}
|
||||
.login_reset_button {
|
||||
text-align: center;
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
|
||||
/* IM page start */
|
||||
|
||||
/* Dialogs list */
|
||||
@ -3363,6 +3381,15 @@ a.countries_modal_search_clear {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
&.pull-right {
|
||||
color: #3a6d99;
|
||||
}
|
||||
}
|
||||
|
||||
&_text {
|
||||
display: block;
|
||||
padding: 4px 0;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
&_version {
|
||||
|
@ -43,6 +43,9 @@
|
||||
<div ng-switch-when="MIGRATE_TO_HTTPS" my-i18n="confirm_modal_migrate_to_https_md"></div>
|
||||
<div ng-switch-when="SWITCH_DESKTOP_VERSION" my-i18n="confirm_modal_resize_desktop_md"></div>
|
||||
<div ng-switch-when="SWITCH_MOBILE_VERSION" my-i18n="confirm_modal_resize_mobile_md"></div>
|
||||
<div ng-switch-when="RECOVERY_EMAIL_EMPTY" my-i18n="confirm_modal_recovery_email_empty_md"></div>
|
||||
<div ng-switch-when="PASSWORD_ABORT_SETUP" my-i18n="confirm_modal_abort_password_setup"></div>
|
||||
<div ng-switch-when="RESET_ACCOUNT" my-i18n="confirm_modal_reset_account_md"></div>
|
||||
<span ng-switch-default ng-switch="message.length > 0">
|
||||
<span ng-switch-when="true" ng-bind="message"></span>
|
||||
<span ng-switch-default my-i18n="confirm_modal_are_u_sure"></span>
|
||||
@ -55,7 +58,7 @@
|
||||
<button class="btn btn-md" ng-click="$dismiss()">
|
||||
<span my-i18n="modal_cancel"></span>
|
||||
</button>
|
||||
<button class="btn btn-md btn-md-primary" ng-switch="type" ng-click="$close()" my-focused >
|
||||
<button class="btn btn-md btn-md-primary" ng-switch="type" ng-click="$close()" ng-class="{'btn-md-danger': type == 'RESET_ACCOUNT'}" my-focused >
|
||||
<span ng-switch-when="LOGOUT" my-i18n="confirm_modal_logout_submit"></span>
|
||||
<span ng-switch-when="HISTORY_FLUSH" my-i18n="confirm_modal_history_flush_submit"></span>
|
||||
<span ng-switch-when="FILES_CLIPBOARD_PASTE" my-i18n="confirm_modal_clipboard_files_send_submit"></span>
|
||||
@ -68,6 +71,7 @@
|
||||
<span ng-switch-when="VIDEO_SHARE_PEER" my-i18n="confirm_modal_share_video_submit"></span>
|
||||
<span ng-switch-when="SHARE_CONTACT_PEER" my-i18n="confirm_modal_share_contact_submit"></span>
|
||||
<span ng-switch-when="EXT_SHARE_PEER" my-i18n="confirm_modal_share_file_submit"></span>
|
||||
<span ng-switch-when="RESET_ACCOUNT" my-i18n="confirm_modal_reset_account_submit"></span>
|
||||
<span ng-switch-default my-i18n="modal_ok"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<h4 ng-if="error" class="md_simple_header" ng-switch="error.type">
|
||||
<span ng-switch-when="MEDIA_TYPE_NOT_SUPPORTED" my-i18n="error_modal_media_not_supported_title"></span>
|
||||
<span ng-switch-when="USERNAME_NOT_OCCUPIED" my-i18n="error_modal_not_found_title"></span>
|
||||
<span ng-switch-when="PASSWORD_RECOVERY_NA" my-i18n="error_modal_recovery_na_title"></span>
|
||||
<span ng-switch-default ng-switch="error.code">
|
||||
<span ng-switch-when="400" my-i18n="error_modal_bad_request_title"></span>
|
||||
<span ng-switch-when="401" my-i18n="error_modal_unauthorized_title"></span>
|
||||
@ -37,6 +38,7 @@
|
||||
<span ng-switch-when="USERNAME_OCCUPIED" my-i18n="error_modal_username_occupied_description"></span>
|
||||
<span ng-switch-when="MEDIA_TYPE_NOT_SUPPORTED" my-i18n="error_modal_media_not_supported_description"></span>
|
||||
<span ng-switch-when="USERNAME_NOT_OCCUPIED" my-i18n="error_modal_username_not_found_description"></span>
|
||||
<span ng-switch-when="PASSWORD_RECOVERY_NA" my-i18n="error_modal_recovery_na_description"></span>
|
||||
|
||||
|
||||
<div ng-switch-default ng-switch="error.code">
|
||||
@ -66,7 +68,7 @@ Stack: {{error.originalError.stack || error.stack}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="md_simple_modal_footer">
|
||||
<button class="btn btn-md btn-md-primary" ng-click="$dismiss()">
|
||||
<button class="btn btn-md btn-md-primary" ng-click="$dismiss()" my-focused>
|
||||
<span my-i18n="modal_ok"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="login_page">
|
||||
<div class="login_head_wrap clearfix" ng-switch="progress.enabled">
|
||||
<div ng-switch-when="true" class="login_head_submit_progress">
|
||||
<my-i18n ng-if="!credentials.phone_code_hash" msgid="login_generating_key"></my-i18n><my-i18n ng-if="credentials.phone_code_hash && !credentials.phone_code_valid" msgid="login_checking_code"></my-i18n><my-i18n ng-if="credentials.phone_code_valid && credentials.phone_unoccupied" msgid="login_signing_up"></my-i18n><span my-loading-dots></span>
|
||||
<my-i18n ng-if="!credentials.phone_code_hash" msgid="login_generating_key"></my-i18n><my-i18n ng-if="credentials.phone_code_hash && !credentials.phone_code_valid" msgid="login_checking_code"></my-i18n><my-i18n ng-if="credentials.phone_code_valid && credentials.phone_unoccupied" msgid="login_signing_up"></my-i18n><my-i18n ng-if="credentials.phone_code_valid && credentials.password_needed" msgid="login_checking_password"></my-i18n><span my-loading-dots></span>
|
||||
</div>
|
||||
<div ng-switch-default class="login_head_submit_wrap">
|
||||
<a class="login_head_submit_btn" ng-if="!credentials.phone_code_hash" ng-click="sendCode()">
|
||||
@ -15,6 +15,9 @@
|
||||
<a class="login_head_submit_btn" ng-if="credentials.phone_code_valid && credentials.phone_unoccupied" ng-click="logIn(true)">
|
||||
<my-i18n msgid="modal_next"></my-i18n><i class="icon icon-next-submit"></i>
|
||||
</a>
|
||||
<a class="login_head_submit_btn" ng-if="credentials.phone_code_valid && credentials.password_needed" ng-click="checkPassword()">
|
||||
<my-i18n msgid="modal_next"></my-i18n><i class="icon icon-next-submit"></i>
|
||||
</a>
|
||||
</div>
|
||||
<a class="login_head_logo_link" href="https://telegram.org" target="_blank">
|
||||
<i class="icon icon-tg-logo"></i><i class="icon icon-tg-title"></i>
|
||||
@ -98,6 +101,28 @@
|
||||
|
||||
</form>
|
||||
|
||||
<form name="myPasswordForm" ng-if="credentials.phone_code_valid && credentials.password_needed" ng-submit="checkPassword()">
|
||||
<h3 class="login_form_head" my-i18n="login_password_title"></h3>
|
||||
<p class="login_form_lead" my-i18n="login_password_label"></p>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': error.field == 'password'}" my-labeled-input ng-switch="error.field == 'password'">
|
||||
<label ng-switch-when="true" class="md-input-label" my-i18n="login_incorrect_password"></label>
|
||||
<label ng-switch-default class="md-input-label" my-i18n="login_password"></label>
|
||||
<input autocomplete="off" class="md-input" my-focused name="password" type="password" ng-model="credentials.password" my-submit-on-enter required />
|
||||
</div>
|
||||
|
||||
<p ng-if="password.hint.length > 0" class="login_form_hint" ng-bind="password.hint"></p>
|
||||
|
||||
<div class="login_forgot_button">
|
||||
<button class="btn btn-md" ng-click="forgotPassword($event)" my-i18n="login_password_forgot_link"></button>
|
||||
</div>
|
||||
|
||||
<div ng-if="canReset" class="login_reset_button">
|
||||
<button class="btn btn-md btn-md-danger" ng-click="resetAccount($event)" my-i18n="login_account_reset"></button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-switch="about.shown">
|
||||
|
@ -51,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="im_message_text" ng-if="::historyMessage.message.length || false" ng-bind-html="::historyMessage.richMessage" dir="auto"></div>
|
||||
<!-- <div class="im_message_external_embed_wrap" ng-if="::historyMessage.richUrlEmbed || false" my-external-embed="historyMessage.richUrlEmbed"></div> -->
|
||||
<div class="im_message_external_embed_wrap" ng-if="::historyMessage.richUrlEmbed || false" my-external-embed="historyMessage.richUrlEmbed"></div>
|
||||
<div ng-if="::historyMessage.media || historyMessage.id < 0 ? true : false" class="im_message_media" ng-switch="historyMessage.media._">
|
||||
|
||||
<div ng-switch-when="messageMediaPhoto" my-message-photo></div>
|
||||
@ -60,7 +60,7 @@
|
||||
<div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio"></div>
|
||||
<div ng-switch-when="messageMediaGeo" my-message-map></div>
|
||||
<div ng-switch-when="messageMediaContact" class="im_message_contact" my-message-contact></div>
|
||||
<div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage"></div>
|
||||
<!-- <div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage"></div> -->
|
||||
<div ng-switch-when="messageMediaPending" my-message-pending></div>
|
||||
<div ng-switch-when="messageMediaUnsupported">
|
||||
<div class="im_message_text">
|
||||
|
32
app/partials/desktop/password_recovery_modal.html
Normal file
32
app/partials/desktop/password_recovery_modal.html
Normal file
@ -0,0 +1,32 @@
|
||||
<div class="md_simple_modal_wrap" my-modal-position>
|
||||
|
||||
<div class="md_simple_modal_body">
|
||||
|
||||
<form class="modal_simple_form" ng-submit="checkCode()">
|
||||
|
||||
<h4 my-i18n="login_recovery_title"></h4>
|
||||
|
||||
<div class="md_simple_form_description" my-i18n="login_recovery_description_md">
|
||||
<my-i18n-param name="email">
|
||||
<strong ng-bind="recovery.email_pattern"></strong>
|
||||
</my-i18n-param>
|
||||
</div>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': recovery.error_field == 'code'}" my-labeled-input ng-switch="recovery.error_field == 'code'">
|
||||
<label ng-switch-when="true" class="md-input-label" my-i18n="login_code_incorrect"></label>
|
||||
<label ng-switch-default class="md-input-label" my-i18n="login_code_placeholder"></label>
|
||||
<input class="md-input" my-focused type="text" ng-model="recovery.code" name="code" my-focused />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="md_simple_modal_footer">
|
||||
|
||||
<button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button>
|
||||
<button class="btn btn-md btn-md-primary" ng-class="{disabled: recovery.updating}" ng-click="checkCode()" ng-disabled="recovery.updating" ng-bind="recovery.updating ? 'password_recover_active' : 'password_recover_submit' | i18n"></button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
@ -4,34 +4,38 @@
|
||||
|
||||
<form class="modal_simple_form" ng-submit="updatePassword()">
|
||||
|
||||
<h4 my-i18n="username_edit_modal_title"></h4>
|
||||
<h4 ng-switch="action">
|
||||
<my-i18n ng-switch-when="disable" msgid="password_delete_title"></my-i18n>
|
||||
<my-i18n ng-switch-default msgid="password_change_title"></my-i18n>
|
||||
</h4>
|
||||
|
||||
<div ng-if="password._ != 'account.noPassword'" class="md-input-group" ng-class="{'md-input-error': checked.error}" my-labeled-input>
|
||||
<div ng-if="password._ != 'account.noPassword'" class="md-input-group" ng-class="{'md-input-error': passwordSettings.error_field == 'cur_password'}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_current_placeholder"></label>
|
||||
<input class="md-input" my-focused type="text" ng-model="passwordSettings.current_password" name="current_password" />
|
||||
<input class="md-input" my-focused type="password" ng-model="passwordSettings.cur_password" name="cur_password" my-focus-on="cur_password_focus" />
|
||||
</div>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': checked.error}" my-labeled-input>
|
||||
<div ng-if="action != 'disable'" class="md-input-group md-input-grouped" ng-class="{'md-input-error': passwordSettings.error_field == 'new_password'}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_new_placeholder"></label>
|
||||
<input class="md-input" type="text" ng-model="passwordSettings.new_password" name="new_password" />
|
||||
<input class="md-input" type="password" ng-model="passwordSettings.new_password" name="new_password" my-focus-on="new_password_focus" />
|
||||
</div>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': checked.error}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_new_placeholder"></label>
|
||||
<input class="md-input" type="text" ng-model="passwordSettings.confirm_password" name="confirm_password" />
|
||||
<div ng-if="action != 'disable'" class="md-input-group" ng-class="{'md-input-error': passwordSettings.confirm_password && passwordSettings.new_password && passwordSettings.confirm_password != passwordSettings.new_password}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_confirm_placeholder"></label>
|
||||
<input class="md-input" type="password" ng-model="passwordSettings.confirm_password" name="confirm_password" my-focus-on="confirm_password_focus" />
|
||||
</div>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': checked.error}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_new_placeholder"></label>
|
||||
<div ng-if="action != 'disable'" class="md-input-group" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_hint_placeholder"></label>
|
||||
<input class="md-input" type="text" ng-model="passwordSettings.hint" name="hint" />
|
||||
</div>
|
||||
|
||||
<div class="md-input-group" ng-class="{'md-input-error': checked.error}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_new_placeholder"></label>
|
||||
<div ng-if="action != 'disable'" class="md_simple_form_description" my-i18n="password_create_description"></div>
|
||||
|
||||
<div ng-if="action != 'disable'" class="md-input-group" ng-class="{'md-input-error': passwordSettings.error_field == 'email'}" my-labeled-input>
|
||||
<label class="md-input-label" my-i18n="password_email_placeholder"></label>
|
||||
<input class="md-input" type="text" ng-model="passwordSettings.email" name="email" />
|
||||
</div>
|
||||
|
||||
<div class="md_simple_form_description" my-i18n="username_edit_description_md"></div>
|
||||
|
||||
</form>
|
||||
|
||||
@ -40,7 +44,10 @@
|
||||
<div class="md_simple_modal_footer">
|
||||
|
||||
<button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button>
|
||||
<button class="btn btn-md btn-md-primary" ng-class="{disabled: passwordSettings.updating}" ng-click="updatePassword()" ng-bind="passwordSettings.updating ? 'username_edit_submit_active' : 'username_edit_submit' | i18n" ng-disabled="passwordSettings.updating"></button>
|
||||
<button class="btn btn-md btn-md-primary" ng-class="{disabled: passwordSettings.updating}" ng-click="updatePassword()" ng-disabled="passwordSettings.updating" ng-switch="action">
|
||||
<span ng-switch-when="disable" ng-bind="passwordSettings.updating ? 'password_delete_active' : 'password_delete_submit' | i18n"></span>
|
||||
<span ng-switch-default ng-bind="passwordSettings.updating ? 'password_create_active' : 'password_create_submit' | i18n"></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -111,10 +111,17 @@
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap">
|
||||
<a ng-if="password._ == 'account.noPassword' && !password.email_unconfirmed_pattern" class="md_modal_section_link" ng-click="changePassword()">Set password</a>
|
||||
<a ng-if="password._ == 'account.noPassword' && password.email_unconfirmed_pattern.length" class="md_modal_section_link" ng-click="changePassword({cancelEmail: true})">Cancel pending {{password.email_unconfirmed_pattern}}</a>
|
||||
<a ng-if="password._ == 'account.password'" class="md_modal_section_link" ng-click="updatePassword({disable: true})">Turn off</a>
|
||||
<a ng-if="password._ == 'account.password'" class="md_modal_section_link" ng-click="changePassword()">Change password</a>
|
||||
<a ng-if="password._ == 'account.noPassword' && password.email_unconfirmed_pattern.length" class="md_modal_section_link pull-right" ng-click="changePassword({action: 'cancel_email'})" my-i18n="settings_modal_password_email_pending_cancel">
|
||||
</a>
|
||||
<span class="md_modal_section_text" ng-if="password._ == 'account.noPassword' && password.email_unconfirmed_pattern.length" class="md_modal_section_link" my-i18n="settings_modal_password_email_pending">
|
||||
<my-i18n-param name="email">
|
||||
<span ng-bind="password.email_unconfirmed_pattern"></span>
|
||||
</my-i18n-param>
|
||||
</span>
|
||||
<a ng-if="password._ == 'account.noPassword' && !password.email_unconfirmed_pattern" class="md_modal_section_link" ng-click="changePassword({action: 'create'})" my-i18n="settings_modal_set_password"></a>
|
||||
|
||||
<a ng-if="password._ == 'account.password'" class="md_modal_section_link pull-right" ng-click="changePassword({action: 'disable'})" my-i18n="settings_modal_disable_password"></a>
|
||||
<a ng-if="password._ == 'account.password'" class="md_modal_section_link" ng-click="changePassword({action: 'change'})" my-i18n="settings_modal_change_password"></a>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap">
|
||||
|
Loading…
x
Reference in New Issue
Block a user