]>
git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/window/AddTotp.js
2 Ext
.define('Proxmox.window.AddTotp', {
3 extend
: 'Proxmox.window.Edit',
4 alias
: 'widget.pmxAddTotp',
5 mixins
: ['Proxmox.Mixin.CBind'],
7 onlineHelp
: 'user_mgmt',
11 title
: gettext('Add a TOTP login factor'),
21 issuerName
: `Proxmox - ${document?.location?.hostname || 'unknown'}`,
24 updateQrCode: function() {
26 let values
= me
.lookup('totp_form').getValues();
27 let algorithm
= values
.algorithm
;
34 encodeURIComponent(values
.issuer
) +
36 encodeURIComponent(values
.userid
) +
37 '?secret=' + values
.secret
+
38 '&period=' + values
.step
+
39 '&digits=' + values
.digits
+
40 '&algorithm=' + algorithm
+
41 '&issuer=' + encodeURIComponent(values
.issuer
);
43 me
.getController().getViewModel().set('otpuri', otpuri
);
44 me
.qrcode
.makeCode(otpuri
);
45 me
.lookup('challenge').setVisible(true);
46 me
.down('#qrbox').setVisible(true);
58 secretEmpty: function(get) {
59 return get('secret').length
=== 0;
65 xclass
: 'Ext.app.ViewController',
67 'field[qrupdate=true]': {
69 this.getView().updateQrCode();
73 validitychange: function(field
, valid
) {
75 let viewModel
= me
.getViewModel();
76 let form
= me
.lookup('totp_form');
77 let challenge
= me
.lookup('challenge');
78 let password
= me
.lookup('password');
79 viewModel
.set('valid', form
.isValid() && challenge
.isValid() && password
.isValid());
85 let view
= me
.getView();
87 view
.qrdiv
= document
.createElement('div');
88 view
.qrcode
= new QRCode(view
.qrdiv
, {
91 correctLevel
: QRCode
.CorrectLevel
.M
,
93 view
.down('#qrbox').getEl().appendChild(view
.qrdiv
);
95 view
.getController().randomizeSecret();
100 randomizeSecret: function() {
102 let rnd
= new Uint8Array(32);
103 window
.crypto
.getRandomValues(rnd
);
105 rnd
.forEach(function(b
) {
106 // secret must be base32, so just use the first 5 bits
110 data
+= String
.fromCharCode(b
+ 0x41);
113 data
+= String
.fromCharCode(b
-26 + 0x32);
116 me
.getViewModel().set('secret', data
);
125 reference
: 'totp_form',
131 xtype
: 'pmxDisplayEditField',
134 editable
: (get) => get('isAdd') && !get('fixedUser'),
135 value
: () => Proxmox
.UserName
,
137 fieldLabel
: gettext('User'),
139 xtype
: 'pmxUserSelector',
142 renderer
: Ext
.String
.htmlEncode
,
144 change: function(field
, newValue
, oldValue
) {
145 let vm
= this.up('window').getViewModel();
146 vm
.set('userid', newValue
);
153 fieldLabel
: gettext('Description'),
154 emptyText
: gettext('For example: TFA device ID, required to identify multiple factors.'),
166 fieldLabel
: gettext('Secret'),
167 emptyText
: gettext('Unchanged'),
169 reference
: 'tfa_secret',
170 regex
: /^[A-Z2-7=]+$/,
171 regexText
: 'Must be base32 [A-Z2-7=]',
182 text
: gettext('Randomize'),
183 reference
: 'randomize_button',
184 handler
: 'randomizeSecret',
190 xtype
: 'numberfield',
191 fieldLabel
: gettext('Time period'),
193 // Google Authenticator ignores this and generates bogus data
200 xtype
: 'numberfield',
201 fieldLabel
: gettext('Digits'),
204 // Google Authenticator ignores this and generates bogus data
212 fieldLabel
: gettext('Issuer Name'),
215 value
: '{issuerName}',
222 visible
: false, // will be enabled when generating a qr code
224 visible
: '{!secretEmpty}',
227 'background-color': 'white',
228 'margin-left': 'auto',
229 'margin-right': 'auto',
237 fieldLabel
: gettext('Verify Code'),
239 reference
: 'challenge',
242 disabled
: '{!showTOTPVerifiction}',
243 visible
: '{showTOTPVerifiction}',
245 emptyText
: gettext('Scan QR code in a TOTP app and enter an auth. code here'),
250 reference
: 'password',
251 fieldLabel
: gettext('Verify Password'),
252 inputType
: 'password',
257 hidden
: () => Proxmox
.UserName
=== 'root@pam',
258 disabled
: () => Proxmox
.UserName
=== 'root@pam',
260 Ext
.String
.format(gettext("Confirm your ({0}) password"), Proxmox
.UserName
),
267 initComponent: function() {
269 me
.url
= '/api2/extjs/access/tfa/';
274 getValues: function(dirtyOnly
) {
276 let viewmodel
= me
.getController().getViewModel();
278 let values
= me
.callParent(arguments
);
280 let uid
= encodeURIComponent(values
.userid
);
281 me
.url
= `/api2/extjs/access/tfa/${uid}`;
282 delete values
.userid
;
285 description
: values
.description
,
287 totp
: viewmodel
.get('otpuri'),
288 value
: values
.challenge
,
291 if (values
.password
) {
292 data
.password
= values
.password
;