]>
Commit | Line | Data |
---|---|---|
fbeac4ea | 1 | Ext.define('PBS.window.AddTfaRecovery', { |
884fec77 | 2 | extend: 'Proxmox.window.Edit', |
fbeac4ea WB |
3 | alias: 'widget.pbsAddTfaRecovery', |
4 | mixins: ['Proxmox.Mixin.CBind'], | |
5 | ||
6 | onlineHelp: 'user_mgmt', | |
884fec77 DC |
7 | isCreate: true, |
8 | isAdd: true, | |
9 | subject: gettext('TFA recovery keys'), | |
fbeac4ea | 10 | width: 512, |
884fec77 | 11 | method: 'POST', |
fbeac4ea WB |
12 | |
13 | fixedUser: false, | |
14 | ||
884fec77 DC |
15 | url: '/api2/extjs/access/tfa', |
16 | submitUrl: function(url, values) { | |
17 | let userid = values.userid; | |
18 | delete values.userid; | |
19 | return `${url}/${userid}`; | |
20 | }, | |
fbeac4ea | 21 | |
884fec77 DC |
22 | apiCallDone: function(success, response) { |
23 | if (!success) { | |
24 | return; | |
25 | } | |
26 | ||
8ae6d28c WB |
27 | let values = response |
28 | .result | |
29 | .data | |
30 | .recovery | |
31 | .map((v, i) => `${i}: ${v}`) | |
32 | .join("\n"); | |
884fec77 DC |
33 | Ext.create('PBS.window.TfaRecoveryShow', { |
34 | autoShow: true, | |
492bc2ba | 35 | userid: this.getViewModel().get('userid'), |
884fec77 DC |
36 | values, |
37 | }); | |
fbeac4ea WB |
38 | }, |
39 | ||
40 | viewModel: { | |
41 | data: { | |
42 | has_entry: false, | |
958055a7 | 43 | userid: null, |
3189d051 TL |
44 | }, |
45 | formulas: { | |
46 | passwordConfirmText: (get) => { | |
47 | let id = get('userid'); | |
48 | return Ext.String.format(gettext("Confirm password of '{0}'"), id); | |
49 | }, | |
fbeac4ea WB |
50 | }, |
51 | }, | |
52 | ||
53 | controller: { | |
54 | xclass: 'Ext.app.ViewController', | |
fbeac4ea WB |
55 | hasEntry: async function(userid) { |
56 | let me = this; | |
57 | let view = me.getView(); | |
58 | ||
59 | try { | |
60 | await PBS.Async.api2({ | |
884fec77 | 61 | url: `${view.url}/${userid}/recovery`, |
fbeac4ea WB |
62 | method: 'GET', |
63 | }); | |
64 | return true; | |
65 | } catch (_ex) { | |
66 | return false; | |
67 | } | |
68 | }, | |
69 | ||
884fec77 | 70 | init: function(view) { |
fbeac4ea WB |
71 | this.onUseridChange(null, Proxmox.UserName); |
72 | }, | |
73 | ||
884fec77 | 74 | onUseridChange: async function(field, userid) { |
fbeac4ea | 75 | let me = this; |
3189d051 | 76 | let vm = me.getViewModel(); |
fbeac4ea WB |
77 | |
78 | me.userid = userid; | |
3189d051 | 79 | vm.set('userid', userid); |
fbeac4ea WB |
80 | |
81 | let has_entry = await me.hasEntry(userid); | |
3189d051 | 82 | vm.set('has_entry', has_entry); |
fbeac4ea | 83 | }, |
fbeac4ea WB |
84 | }, |
85 | ||
86 | items: [ | |
87 | { | |
88 | xtype: 'pmxDisplayEditField', | |
89 | name: 'userid', | |
90 | cbind: { | |
91 | editable: (get) => !get('fixedUser'), | |
958055a7 | 92 | value: () => Proxmox.UserName, |
fbeac4ea WB |
93 | }, |
94 | fieldLabel: gettext('User'), | |
95 | editConfig: { | |
96 | xtype: 'pbsUserSelector', | |
97 | allowBlank: false, | |
884fec77 DC |
98 | validator: function(_value) { |
99 | return !this.up('window').getViewModel().get('has_entry'); | |
100 | }, | |
fbeac4ea WB |
101 | }, |
102 | renderer: Ext.String.htmlEncode, | |
fbeac4ea WB |
103 | listeners: { |
104 | change: 'onUseridChange', | |
105 | }, | |
106 | }, | |
884fec77 DC |
107 | { |
108 | xtype: 'hiddenfield', | |
109 | name: 'type', | |
110 | value: 'recovery', | |
111 | }, | |
fbeac4ea WB |
112 | { |
113 | xtype: 'displayfield', | |
114 | bind: { | |
115 | hidden: '{!has_entry}', | |
116 | }, | |
884fec77 DC |
117 | hidden: true, |
118 | userCls: 'pmx-hint', | |
fbeac4ea WB |
119 | value: gettext('User already has recovery keys.'), |
120 | }, | |
121 | { | |
122 | xtype: 'textfield', | |
aab9a264 TL |
123 | name: 'password', |
124 | reference: 'password', | |
125 | fieldLabel: gettext('Verify Password'), | |
fbeac4ea | 126 | inputType: 'password', |
fbeac4ea | 127 | minLength: 5, |
fbeac4ea WB |
128 | allowBlank: false, |
129 | validateBlank: true, | |
958055a7 TL |
130 | cbind: { |
131 | hidden: () => Proxmox.UserName === 'root@pam', | |
132 | disabled: () => Proxmox.UserName === 'root@pam', | |
133 | }, | |
3189d051 TL |
134 | bind: { |
135 | emptyText: '{passwordConfirmText}', | |
136 | }, | |
fbeac4ea WB |
137 | }, |
138 | ], | |
fbeac4ea WB |
139 | }); |
140 | ||
141 | Ext.define('PBS.window.TfaRecoveryShow', { | |
142 | extend: 'Ext.window.Window', | |
143 | alias: ['widget.pbsTfaRecoveryShow'], | |
144 | mixins: ['Proxmox.Mixin.CBind'], | |
145 | ||
146 | width: 600, | |
147 | modal: true, | |
148 | resizable: false, | |
149 | title: gettext('Recovery Keys'), | |
854319d8 | 150 | onEsc: Ext.emptyFn, |
fbeac4ea WB |
151 | |
152 | items: [ | |
153 | { | |
a442bd97 DC |
154 | xtype: 'form', |
155 | layout: 'anchor', | |
fbeac4ea WB |
156 | bodyPadding: 10, |
157 | border: false, | |
158 | fieldDefaults: { | |
fbeac4ea WB |
159 | anchor: '100%', |
160 | }, | |
fbeac4ea WB |
161 | items: [ |
162 | { | |
163 | xtype: 'textarea', | |
164 | editable: false, | |
165 | inputId: 'token-secret-value', | |
166 | cbind: { | |
167 | value: '{values}', | |
168 | }, | |
169 | fieldStyle: { | |
170 | 'fontFamily': 'monospace', | |
171 | }, | |
172 | height: '160px', | |
173 | }, | |
a442bd97 DC |
174 | { |
175 | xtype: 'displayfield', | |
176 | border: false, | |
177 | padding: '5 0 0 0', | |
178 | userCls: 'pmx-hint', | |
179 | value: gettext('Please record recovery keys - they will only be displayed now'), | |
180 | }, | |
fbeac4ea WB |
181 | ], |
182 | }, | |
fbeac4ea WB |
183 | ], |
184 | buttons: [ | |
185 | { | |
186 | handler: function(b) { | |
187 | document.getElementById('token-secret-value').select(); | |
188 | document.execCommand("copy"); | |
189 | }, | |
99549210 TL |
190 | iconCls: 'fa fa-clipboard', |
191 | text: gettext('Copy Recovery Keys'), | |
fbeac4ea | 192 | }, |
492bc2ba TL |
193 | { |
194 | handler: function(b) { | |
195 | let win = this.up('window'); | |
196 | win.paperkeys(win.values, win.userid); | |
197 | }, | |
198 | iconCls: 'fa fa-print', | |
199 | text: gettext('Print Recovery Keys'), | |
200 | }, | |
fbeac4ea | 201 | ], |
492bc2ba TL |
202 | paperkeys: function(keyString, userid) { |
203 | let me = this; | |
204 | ||
205 | let printFrame = document.createElement("iframe"); | |
206 | Object.assign(printFrame.style, { | |
207 | position: "fixed", | |
208 | right: "0", | |
209 | bottom: "0", | |
210 | width: "0", | |
211 | height: "0", | |
212 | border: "0", | |
213 | }); | |
214 | const host = document.location.host; | |
215 | const title = document.title; | |
216 | const html = `<html><head><script> | |
217 | window.addEventListener('DOMContentLoaded', (ev) => window.print()); | |
218 | </script><style>@media print and (max-height: 150mm) { | |
219 | h4, p { margin: 0; font-size: 1em; } | |
220 | }</style></head><body style="padding: 5px;"> | |
221 | <h4>Recovery Keys for '${userid}' - ${title} (${host})</h4> | |
222 | <p style="font-size:1.5em;line-height:1.5em;font-family:monospace; | |
223 | white-space:pre-wrap;overflow-wrap:break-word;"> | |
224 | ${keyString} | |
225 | </p> | |
226 | </body></html>`; | |
227 | ||
228 | printFrame.src = "data:text/html;base64," + btoa(html); | |
229 | document.body.appendChild(printFrame); | |
230 | }, | |
fbeac4ea | 231 | }); |