blob: 41d15f9e012813abe1d54d53305cc3664e3305b5 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {AsyncUtil} from '../../common/js/async_util.js';
/** @type {!HTMLTemplateElement} */
const htmlTemplate = html`{__html_template__}`;
/**
* Dialog to request user to enter password. Uses the askForPassword() which
* resolves with either the password or rejected with
* FilesPasswordDialog.USER_CANCELLED.
* @extends HTMLElement
*/
export class FilesPasswordDialog extends HTMLElement {
constructor() {
super();
// Create element content.
const fragment = htmlTemplate.content.cloneNode(true);
this.attachShadow({mode: 'open'}).appendChild(fragment);
/**
* Mutex used to serialize modal dialogs and error notifications.
* @private {?AsyncUtil.Queue}
*/
this.mutex_ = null;
/**
* Name of the encrypted file.
* @private {string}
*/
this.filename_ = '';
/**
* Controls whether the user is validating the password (Unlock button or
* Enter key) or cancelling the dialog (Cancel button or Escape key).
* @private {boolean}
*/
this.success_ = false;
/**
* Return input password using the resolve method of a Promise.
* @private {?function(string)}
*/
this.resolve_ = null;
/**
* Return password prompt error using the reject method of a Promise.
* @private {?function(!Error)}
*/
this.reject_ = null;
/**
* Password dialog.
* @private {!CrDialogElement}
*/
this.dialog_ = /** @type {!CrDialogElement} */
(this.shadowRoot.querySelector('#password-dialog'));
this.dialog_.consumeKeydownEvent = true;
/**
* Input field for password.
* @private {!CrInputElement}
*/
this.input_ = /** @type {!CrInputElement} */
(this.shadowRoot.querySelector('#input'));
this.input_.errorMessage =
loadTimeData.getString('PASSWORD_DIALOG_INVALID');
}
get mutex() {
if (!this.mutex_) {
this.mutex_ = new AsyncUtil.Queue();
}
return this.mutex_;
}
/**
* Called when this element is attached to the DOM.
*
* @private
*/
connectedCallback() {
const cancelButton = this.shadowRoot.querySelector('#cancel');
cancelButton.onclick = () => this.cancel_();
const unlockButton = this.shadowRoot.querySelector('#unlock');
unlockButton.onclick = () => this.unlock_();
this.dialog_.addEventListener('close', () => this.onClose_());
}
/**
* Asks the user for a password to open the given file.
* @param {string} filename Name of the file to open.
* @param {?string} password Previously entered password. If not null, it
* indicates that an invalid password was previously tried.
* @return {!Promise<!string>} Password provided by the user. The returned
* promise is rejected with FilesPasswordDialog.USER_CANCELLED if the user
* presses Cancel.
*/
async askForPassword(filename, password = null) {
const mutexUnlock = await this.mutex.lock();
try {
return await new Promise((resolve, reject) => {
this.success_ = false;
this.resolve_ = resolve;
this.reject_ = reject;
if (password != null) {
this.input_.value = password;
// An invalid password has previously been entered for this file.
// Display an 'invalid password' error message.
this.input_.invalid = true;
} else {
this.input_.invalid = false;
}
this.showModal_(filename);
this.input_.focus();
});
} finally {
mutexUnlock();
}
}
/**
* Shows the password prompt represented by |filename|.
* @param {!string} filename
* @private
*/
showModal_(filename) {
this.filename_ = filename;
this.dialog_.querySelector('#name').innerText = filename;
this.dialog_.showModal();
}
/**
* Triggers a 'Cancelled by user' error.
* @private
*/
cancel_() {
this.dialog_.close();
}
/**
* Sends user input password.
* @private
*/
unlock_() {
this.dialog_.close();
this.success_ = true;
}
/**
* Resolves the promise when the dialog is closed.
* This can be triggered by the buttons, Esc key or anything that closes the
* dialog.
* @private
*/
onClose_() {
if (this.success_) {
this.resolve_(this.input_.value);
} else {
this.reject_(FilesPasswordDialog.USER_CANCELLED);
}
this.input_.value = '';
}
}
/**
* Exception thrown when user cancels the password dialog box.
* @const {!Error}
*/
FilesPasswordDialog.USER_CANCELLED = new Error('Cancelled by user');
window.customElements.define('files-password-dialog', FilesPasswordDialog);
//# sourceURL=//ui/file_manager/file_manager/foreground/elements/files_password_dialog.js