This repository has been archived by the owner on Dec 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f7efb5f
commit 3a796b7
Showing
11 changed files
with
427 additions
and
294 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
Ext.ns('Tine.Tinebase'); | ||
|
||
const HTOTOPSecretField = Ext.extend(Ext.form.FieldSet, { | ||
/** | ||
* @cfg {String} type h|totp | ||
*/ | ||
type: 'totp', | ||
|
||
initComponent: function() { | ||
this.title = i18n._('Secret Key'); | ||
this.explainText = new Ext.form.Label({ | ||
text: i18n._("Please note: After saving you can not view this autogenerated secret key again!") | ||
}); | ||
this.secretField = new Ext.form.TextField({ | ||
//@TODO clipboard plugin! | ||
name: 'secret', | ||
anchor: '100%', | ||
hideLabel: true, | ||
setValue: this.setValue.createDelegate(this) | ||
// getValue: this.getValue.createDelegate(this) | ||
}); | ||
this.qrField = new Ext.BoxComponent({ | ||
width: 150, | ||
height: 150, | ||
html: '<img style="width: 100%; height: 100%"/>' | ||
}); | ||
this.items = [ | ||
this.explainText, | ||
this.secretField, | ||
this.qrField | ||
]; | ||
|
||
this.supr().initComponent.call(this); | ||
}, | ||
|
||
onRender: function() { | ||
this.supr().onRender.apply(this, arguments); | ||
this.editDialog = this.findParentBy(function (c) { | ||
return c instanceof Tine.widgets.dialog.EditDialog | ||
}); | ||
}, | ||
setValue: function(value, record) { | ||
const supr = Ext.form.TextField.prototype.setValue.createDelegate(this.secretField); | ||
|
||
if (! record.get('secret')) { | ||
supr(i18n._('Generating secret key ...')); | ||
this.secretField.setDisabled(true); | ||
import(/* webpackChunkName: "Tinebase/js/base32-encode" */ 'base32-encode').then((module) => { | ||
const bytes = new Uint8Array(35); | ||
window.crypto.getRandomValues(bytes); | ||
supr(module.default(bytes, 'RFC3548')); | ||
this.secretField.setDisabled(false); | ||
this.onValueChange(); | ||
}); | ||
} else { | ||
supr(value); | ||
this.onValueChange(); | ||
} | ||
|
||
}, | ||
|
||
onValueChange: async function() { | ||
const QRCode = await import(/* webpackChunkName: "Tinebase/js/qrcode" */ 'qrcode'); | ||
const otpURI = this.getOTPAuthURI(); | ||
const imgURL = await QRCode.toDataURL(otpURI); | ||
|
||
this.qrField.el.child('img').dom.src = imgURL; | ||
}, | ||
|
||
getOTPAuthURI: function() { | ||
const secret = this.secretField.getValue(); | ||
const type = this.type.toLowerCase(); | ||
const account = encodeURIComponent(JSON.parse(this.editDialog.record.json.account_id).accountLoginName); | ||
const issuer = encodeURIComponent(window.location.hostname); | ||
|
||
let uri = `otpauth://${type}/${issuer}:${account}?secret=${secret}&issuer=${issuer}`; | ||
|
||
// uri += "&algorithm=" + this.editDialog.record.get('algorithm'); | ||
// uri += "&digits=" + this.editDialog.record.get('digits'); | ||
// uri += "&period=" + this.editDialog.record.get('period'); | ||
|
||
if (type == "hotp") | ||
uri += "&counter=" + (this.editDialog.record.get('counter') || 0); | ||
|
||
// uri += "&lock=" + ???; // freeOTP only? | ||
uri += "&image=" + encodeURIComponent(Tine.Tinebase.common.getUrl() + Tine.Tinebase.registry.get('installLogo')); // freeOTP only?; | ||
|
||
return uri; | ||
} | ||
|
||
|
||
}); | ||
|
||
Ext.reg('mfa-htotp-secretfield', HTOTOPSecretField) | ||
|
||
Tine.widgets.form.FieldManager.register('Tinebase', 'MFA_TOTPUserConfig', 'secret', { | ||
type: 'totp', | ||
xtype: 'mfa-htotp-secretfield', | ||
height: 300, | ||
}, Tine.widgets.form.FieldManager.CATEGORY_EDITDIALOG); | ||
|
||
Tine.widgets.form.FieldManager.register('Tinebase', 'MFA_HOTPUserConfig', 'secret', { | ||
type: 'hotp', | ||
xtype: 'mfa-htotp-secretfield', | ||
height: 300, | ||
}, Tine.widgets.form.FieldManager.CATEGORY_EDITDIALOG); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Tine 2.0 | ||
* | ||
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3 | ||
* @author Cornelius Weiss <c.weiss@metaways.de> | ||
* @copyright Copyright (c) 2018-2021 Metaways Infosystems GmbH (http://www.metaways.de) | ||
*/ | ||
|
||
import Generic from './Generic' | ||
|
||
class Sms extends Generic { | ||
constructor (config) { | ||
super(config) | ||
this.isOTP = true | ||
this.windowTitle = i18n._('Authenticator code required') | ||
this.questionText = formatMessage('This area is locked. To unlock it you need to provide the code from your authenticator app {mfaDevice.device_name}.', this) | ||
this.passwordFieldLabel = formatMessage('Authenticator code from {mfaDevice.device_name}', this) | ||
} | ||
} | ||
|
||
export default Sms |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.