mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/OATHAuth
synced 2024-11-23 15:56:59 +00:00
Add copy button for recovery codes
Bug: T354028 Co-Authored-by: TheDJ <hartman.wiki@gmail.com> Change-Id: I3edf9f698aa1f7f5a9881516027a65a88ea1cac4
This commit is contained in:
parent
dc63d00723
commit
ffb7da7a45
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"wikimedia/client-es5",
|
||||
"wikimedia/client",
|
||||
"wikimedia/jquery",
|
||||
"wikimedia/mediawiki"
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-env node */
|
||||
module.exports = function ( grunt ) {
|
||||
var conf = grunt.file.readJSON( 'extension.json' );
|
||||
const conf = grunt.file.readJSON( 'extension.json' );
|
||||
|
||||
grunt.loadNpmTasks( 'grunt-banana-checker' );
|
||||
grunt.loadNpmTasks( 'grunt-eslint' );
|
||||
|
|
|
@ -101,16 +101,25 @@
|
|||
}
|
||||
},
|
||||
"ResourceModules": {
|
||||
"ext.oath.totp.showqrcode.styles": {
|
||||
"ext.oath.styles": {
|
||||
"class": "MediaWiki\\ResourceLoader\\CodexModule",
|
||||
"styles": [
|
||||
"totp/ext.oath.showqrcode.styles.less"
|
||||
"totp/ext.oath.showqrcode.styles.less",
|
||||
"recovery/ext.oauth.recovery.less"
|
||||
],
|
||||
"codexStyleOnly": "true",
|
||||
"codexComponents": [
|
||||
"CdxButton",
|
||||
"CdxIcon"
|
||||
]
|
||||
},
|
||||
"ext.oath": {
|
||||
"packageFiles": [
|
||||
"recovery/ext.oath.recovery.copy.js"
|
||||
],
|
||||
"messages": [
|
||||
"oathauth-recoverycodes-copy-success"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ResourceFileModulePaths": {
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
"oathauth-recoverycodes-important": "This step is important! Do not skip this step!",
|
||||
"oathauth-recoverycodes-neveragain": "These codes will never be shown again!",
|
||||
"oathauth-recoverytokens-createdat": "Recovery tokens created: $1",
|
||||
"oathauth-recoverycodes-download": "Download recovery codes",
|
||||
"oathauth-recoverycodes-download": "Download",
|
||||
"oathauth-recoverycodes-copy": "Copy",
|
||||
"oathauth-recoverycodes-copy-success": "Recovery codes were copied to your clipboard!",
|
||||
"oathauth-disable": "Disable two-factor authentication",
|
||||
"oathauth-validatedoath": "Validated two-factor credentials. Two-factor authentication will now be enforced.",
|
||||
"oathauth-noscratchforvalidation": "You cannot use a recovery code to confirm two-factor authentication. Recovery codes are for backup and incidental use only. Please use a code from your two-factor authentication application (such as Google Authenticator).",
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
"oathauth-recoverycodes-neveragain": "Plain text, found on Special:OATH while enabling OATH.",
|
||||
"oathauth-recoverytokens-createdat": "Plain text, found on Special:OATH while enabling OATH.",
|
||||
"oathauth-recoverycodes-download": "Plain text, text of the download link on Special:OATH while enabling OATH.",
|
||||
"oathauth-recoverycodes-copy": "Plain text, label of the button on Special:OATH to copy the recovery codes",
|
||||
"oathauth-recoverycodes-copy-success": "Notification bubble presented on Special:OATH after copying recovery codes",
|
||||
"oathauth-disable": "Page title on Special:OATH while disabling OATH.\n\nSee [https://en.wikipedia.org/wiki/Two_factor_authentication two factor authentication]",
|
||||
"oathauth-validatedoath": "Plain text found on Special:OATH after a token has been validated.\n\nSee [https://en.wikipedia.org/wiki/Two_factor_authentication two factor authentication]",
|
||||
"oathauth-noscratchforvalidation": "Plain text found on Special:OATH if the user used the incorrect type of token while enabling OATH.\n\nSee [https://en.wikipedia.org/wiki/Two_factor_authentication two factor authentication]",
|
||||
|
|
40
modules/recovery/ext.oath.recovery.copy.js
Normal file
40
modules/recovery/ext.oath.recovery.copy.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
class CopyButton {
|
||||
|
||||
static attach() {
|
||||
// eslint-disable-next-line no-jquery/no-global-selector
|
||||
$( '.mw-oathauth-recoverycodes-copy-button' )
|
||||
.addClass( 'clipboard-api-supported' )
|
||||
.on( 'click', ( e ) => {
|
||||
e.preventDefault();
|
||||
// eslint-disable-next-line compat/compat
|
||||
navigator.clipboard.writeText( mw.config.get( 'oathauth-recoverycodes' ) ).then( () => {
|
||||
mw.notify( mw.msg( 'oathauth-recoverycodes-copy-success' ), {
|
||||
type: 'success',
|
||||
tag: 'recoverycodes'
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
if ( navigator.clipboard && navigator.clipboard.writeText ) {
|
||||
// navigator.clipboard() is not supported in Safari 11.1, iOS Safari 11.3-11.4
|
||||
$( CopyButton.attach );
|
||||
}
|
21
modules/recovery/ext.oauth.recovery.less
Normal file
21
modules/recovery/ext.oauth.recovery.less
Normal file
|
@ -0,0 +1,21 @@
|
|||
@import 'mediawiki.skin.variables.less';
|
||||
|
||||
.mw-oathauth-recoverycodes-download-icon {
|
||||
.cdx-mixin-css-icon( @cdx-icon-download, @param-is-button-icon: true );
|
||||
}
|
||||
|
||||
.mw-oathauth-recoverycodes-copy-button {
|
||||
&.cdx-button {
|
||||
margin-right: @spacing-horizontal-button;
|
||||
margin-inline-end: @spacing-horizontal-button;
|
||||
}
|
||||
|
||||
.cdx-button__icon {
|
||||
.cdx-mixin-css-icon( @cdx-icon-copy, @param-is-button-icon: true );
|
||||
}
|
||||
|
||||
.client-nojs &,
|
||||
&:not( .clipboard-api-supported ) {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
@import 'mediawiki.skin.variables.less';
|
||||
|
||||
kbd {
|
||||
font-family: monospace, monospace;
|
||||
white-space: nowrap;
|
||||
|
@ -9,11 +7,3 @@ kbd {
|
|||
fieldset {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.cdx-button.mw-oathauth-recoverycodes-download {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.mw-oathauth-recoverycodes-download-icon {
|
||||
.cdx-mixin-css-icon( @cdx-icon-download, @param-is-button-icon: true );
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ class TOTPEnableForm extends OATHAuthOOUIHTMLForm {
|
|||
* @return string
|
||||
*/
|
||||
public function getHTML( $submitResult ) {
|
||||
$this->getOutput()->addModuleStyles( 'ext.oath.totp.showqrcode.styles' );
|
||||
$out = $this->getOutput();
|
||||
$out->addModuleStyles( 'ext.oath.styles' );
|
||||
$out->addModules( 'ext.oath' );
|
||||
|
||||
return parent::getHTML( $submitResult );
|
||||
}
|
||||
|
@ -69,6 +71,8 @@ class TOTPEnableForm extends OATHAuthOOUIHTMLForm {
|
|||
->build();
|
||||
|
||||
$now = wfTimestampNow();
|
||||
$recoveryCodes = $this->getScratchTokensForDisplay( $key );
|
||||
$this->getOutput()->addJsConfigVars( 'oathauth-recoverycodes', $this->createTextList( $recoveryCodes ) );
|
||||
|
||||
// messages used: oathauth-step1, oathauth-step2, oathauth-step3, oathauth-step4
|
||||
return [
|
||||
|
@ -115,9 +119,10 @@ class TOTPEnableForm extends OATHAuthOOUIHTMLForm {
|
|||
. $this->msg( 'word-separator' )->escaped()
|
||||
. $this->msg( 'parentheses' )->rawParams( wfTimestamp( TS_ISO_8601, $now ) )->escaped()
|
||||
) . '<br/>' .
|
||||
$this->createResourceList( $this->getScratchTokensForDisplay( $key ) ) . '<br/>' .
|
||||
$this->createResourceList( $recoveryCodes ) . '<br/>' .
|
||||
'<strong>' . $this->msg( 'oathauth-recoverycodes-neveragain' )->escaped() . '</strong><br/>' .
|
||||
$this->createDownloadLink( $this->getScratchTokensForDisplay( $key ) ),
|
||||
$this->createCopyButton() .
|
||||
$this->createDownloadLink( $recoveryCodes ),
|
||||
'raw' => true,
|
||||
'section' => 'step3',
|
||||
],
|
||||
|
@ -146,6 +151,15 @@ class TOTPEnableForm extends OATHAuthOOUIHTMLForm {
|
|||
return Html::rawElement( 'ul', [], $resourceList );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createTextList( $items ) {
|
||||
return "* " . implode( "\n* ", $items );
|
||||
}
|
||||
|
||||
private function createDownloadLink( array $scratchTokensForDisplay ): string {
|
||||
$icon = Html::element( 'span', [
|
||||
'class' => [ 'mw-oathauth-recoverycodes-download-icon', 'cdx-button__icon' ],
|
||||
|
@ -167,6 +181,16 @@ class TOTPEnableForm extends OATHAuthOOUIHTMLForm {
|
|||
);
|
||||
}
|
||||
|
||||
private function createCopyButton(): string {
|
||||
return Html::rawElement( 'button', [
|
||||
'class' => 'cdx-button mw-oathauth-recoverycodes-copy-button'
|
||||
], Html::element( 'span', [
|
||||
'class' => 'cdx-button__icon',
|
||||
'aria-hidden' => 'true',
|
||||
] ) . $this->msg( 'oathauth-recoverycodes-copy' )->escaped()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current secret for display purposes
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue