Ext.define('PBS.LoginView', {
extend: 'Ext.container.Container',
xtype: 'loginview',
viewModel: {
data: {
openid: false,
},
formulas: {
button_text: function(get) {
if (get("openid") === true) {
return gettext("Login (OpenID redirect)");
} else {
return gettext("Login");
}
},
},
},
controller: {
xclass: 'Ext.app.ViewController',
init: async function() {
if (Proxmox.consentText !== "") {
Ext.create('Proxmox.window.ConsentModal', {
autoShow: true,
consent: Proxmox.Markdown.parse(
Ext.htmlEncode(
Proxmox.Utils.base64ToUtf8(Proxmox.consentText),
),
),
});
}
},
submitForm: async function() {
var me = this;
var loginForm = me.lookupReference('loginForm');
var unField = me.lookupReference('usernameField');
var saveunField = me.lookupReference('saveunField');
if (!loginForm.isValid()) {
return;
}
let creds = loginForm.getValues();
if (this.getViewModel().data.openid === true) {
const redirectURL = location.origin;
try {
let resp = await Proxmox.Async.api2({
url: '/api2/extjs/access/openid/auth-url',
params: {
realm: creds.realm,
"redirect-url": redirectURL,
},
method: 'POST',
});
window.location = resp.result.data;
} catch (response) {
Proxmox.Utils.authClear();
loginForm.unmask();
Ext.MessageBox.alert(
gettext('Error'),
gettext('OpenID redirect failed, please try again') + `
${response.result.message}`,
);
}
return;
}
creds.username = `${creds.username}@${creds.realm}`;
delete creds.realm;
if (loginForm.isVisible()) {
loginForm.mask(gettext('Please wait...'), 'x-mask-loading');
}
// set or clear username
var sp = Ext.state.Manager.getProvider();
if (saveunField.getValue() === true) {
sp.set(unField.getStateId(), unField.getValue());
} else {
sp.clear(unField.getStateId());
}
sp.set(saveunField.getStateId(), saveunField.getValue());
try {
let resp = await Proxmox.Async.api2({
url: '/api2/extjs/access/ticket',
params: creds,
method: 'POST',
});
let data = resp.result.data;
if (data.ticket.startsWith("PBS:!tfa!")) {
data = await me.performTFAChallenge(data);
}
PBS.Utils.updateLoginData(data);
PBS.app.changeView('mainview');
} catch (error) {
Proxmox.Utils.authClear();
loginForm.unmask();
Ext.MessageBox.alert(
gettext('Error'),
gettext('Login failed. Please try again'),
);
}
},
performTFAChallenge: async function(data) {
let me = this;
let userid = data.username;
let ticket = data.ticket;
let challenge = JSON.parse(decodeURIComponent(
ticket.split(':')[1].slice("!tfa!".length),
));
let resp = await new Promise((resolve, reject) => {
Ext.create('Proxmox.window.TfaLoginWindow', {
userid,
ticket,
challenge,
onResolve: value => resolve(value),
onReject: reject,
}).show();
});
return resp.result.data;
},
control: {
'field[name=username]': {
specialkey: function(f, e) {
if (e.getKey() === e.ENTER) {
var pf = this.lookupReference('passwordField');
if (!pf.getValue()) {
pf.focus(false);
}
}
},
},
'field[name=lang]': {
change: function(f, value) {
var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
Ext.util.Cookies.set('PBSLangCookie', value, dt);
this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
window.location.reload();
},
},
'field[name=realm]': {
change: function(f, value) {
let record = f.store.getById(value);
if (record === undefined) return;
let data = record.data;
this.getViewModel().set("openid", data.type === "openid");
},
},
'button[reference=loginButton]': {
click: 'submitForm',
},
'window[reference=loginwindow]': {
show: function() {
var sp = Ext.state.Manager.getProvider();
var checkboxField = this.lookupReference('saveunField');
var unField = this.lookupReference('usernameField');
var checked = sp.get(checkboxField.getStateId());
checkboxField.setValue(checked);
if (checked === true) {
var username = sp.get(unField.getStateId());
unField.setValue(username);
var pwField = this.lookupReference('passwordField');
pwField.focus();
}
let auth = Proxmox.Utils.getOpenIDRedirectionAuthorization();
if (auth !== undefined) {
Proxmox.Utils.authClear();
let loginForm = this.lookupReference('loginForm');
loginForm.mask(gettext('OpenID login - please wait...'), 'x-mask-loading');
// openID checks the original redirection URL we used, so pass that too
const redirectURL = location.origin;
Proxmox.Utils.API2Request({
url: '/api2/extjs/access/openid/login',
params: {
state: auth.state,
code: auth.code,
"redirect-url": redirectURL,
},
method: 'POST',
failure: function(response) {
loginForm.unmask();
let error = response.htmlStatus;
Ext.MessageBox.alert(
gettext('Error'),
gettext('OpenID login failed, please try again') + `
${error}`,
() => { window.location = redirectURL; },
);
},
success: function(response, options) {
loginForm.unmask();
let creds = response.result.data;
PBS.Utils.updateLoginData(creds);
PBS.app.changeView('mainview');
history.replaceState(null, '', `${redirectURL}#pbsDashboard`);
},
});
}
},
},
},
},
plugins: 'viewport',
layout: {
type: 'border',
},
items: [
{
region: 'north',
xtype: 'container',
layout: {
type: 'hbox',
align: 'middle',
},
margin: '2 5 2 5',
height: 38,
items: [
{
xtype: 'proxmoxlogo',
prefix: '',
},
{
xtype: 'versioninfo',
makeApiCall: false,
},
],
},
{
region: 'center',
},
{
xtype: 'window',
closable: false,
resizable: false,
reference: 'loginwindow',
autoShow: true,
modal: true,
width: 400,
defaultFocus: 'usernameField',
layout: {
type: 'auto',
},
title: gettext('Proxmox Backup Server Login'),
items: [
{
xtype: 'form',
layout: {
type: 'form',
},
defaultButton: 'loginButton',
url: '/api2/extjs/access/ticket',
reference: 'loginForm',
fieldDefaults: {
labelAlign: 'right',
allowBlank: false,
},
items: [
{
xtype: 'textfield',
fieldLabel: gettext('User name'),
name: 'username',
itemId: 'usernameField',
reference: 'usernameField',
stateId: 'login-username',
inputAttrTpl: 'autocomplete=username',
bind: {
visible: "{!openid}",
disabled: "{openid}",
},
},
{
xtype: 'textfield',
inputType: 'password',
fieldLabel: gettext('Password'),
name: 'password',
itemId: 'passwordField',
reference: 'passwordField',
inputAttrTpl: 'autocomplete=current-password',
bind: {
visible: "{!openid}",
disabled: "{openid}",
},
},
{
xtype: 'pmxRealmComboBox',
name: 'realm',
},
{
xtype: 'proxmoxLanguageSelector',
fieldLabel: gettext('Language'),
value: Ext.util.Cookies.get('PBSLangCookie') || Proxmox.defaultLang || '__default__',
name: 'lang',
reference: 'langField',
submitValue: false,
},
],
buttons: [
{
xtype: 'checkbox',
fieldLabel: gettext('Save User name'),
name: 'saveusername',
reference: 'saveunField',
stateId: 'login-saveusername',
labelWidth: 250,
labelAlign: 'right',
submitValue: false,
bind: {
visible: "{!openid}",
},
},
{
bind: {
text: "{button_text}",
},
reference: 'loginButton',
formBind: true,
},
],
},
],
},
],
});