Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
!/apps/admin_audit
!/apps/updatenotification
!/apps/theming
!/apps/twofactor_backupcodes
!/apps/workflowengine
/apps/files_external/3rdparty/irodsphp/PHPUnitTest
/apps/files_external/3rdparty/irodsphp/web
Expand Down
22 changes: 22 additions & 0 deletions apps/twofactor_backupcodes/appinfo/app.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* @author Christoph Wurst <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the copyright header from

/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <[email protected]>
* @copyright Copyright (c) 2016 Lukas Reschke <[email protected]>
*
* @author Bjoern Schiessle <[email protected]>
* @author Julius Haertl <[email protected]>
* @author Lukas Reschke <[email protected]>
* @author oparoz <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
? That clearly indicates who are authors and who copyright holders as well as makes it AGPL3 plus :)

OC_App::registerPersonal('twofactor_backupcodes', 'settings/personal');
48 changes: 48 additions & 0 deletions apps/twofactor_backupcodes/appinfo/database.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<database>
<name>*dbname*</name>
<create>true</create>
<overwrite>false</overwrite>
<charset>utf8</charset>
<table>
<name>*dbprefix*twofactor_backup_codes</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<autoincrement>1</autoincrement>
<default>0</default>
<notnull>true</notnull>
<length>4</length>
</field>
<field>
<name>user_id</name>
<type>text</type>
<default></default>
<notnull>true</notnull>
<length>64</length>
</field>
<field>
<name>code</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
</field>
<field>
<name>used</name>
<type>integer</type>
<notnull>true</notnull>
<default>0</default>
<length>1</length>
</field>

<index>
<name>two_factor_backupcodes_user_id</name>
<field>
<name>user_id</name>
<sorting>ascending</sorting>
</field>
</index>
</declaration>
</table>
</database>
19 changes: 19 additions & 0 deletions apps/twofactor_backupcodes/appinfo/info.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0"?>
<info>
<id>twofactor_backupcodes</id>
<name>Two factor backup codes</name>
<description>A two-factor auth backup codes provider</description>
<licence>agpl</licence>
<author>Christoph Wurst</author>
<version>1.0.0</version>
<namespace>TwoFactor_BackupCodes</namespace>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, no underscores in PSR-4 Namespaces

<category>other</category>

<two-factor-providers>
<provider>OCA\TwoFactor_BackupCodes\Provider\BackupCodesProvider</provider>
</two-factor-providers>

<dependencies>
<owncloud min-version="9.2" max-version="9.2" />
</dependencies>
</info>
35 changes: 35 additions & 0 deletions apps/twofactor_backupcodes/appinfo/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/**
* @author Christoph Wurst <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
return [
'routes' => [
[
'name' => 'settings#state',
'url' => '/settings/state',
'verb' => 'GET'
],
[
'name' => 'settings#createCodes',
'url' => '/settings/create',
'verb' => 'POST'
],
]
];
25 changes: 25 additions & 0 deletions apps/twofactor_backupcodes/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.challenge-form {
margin: 16px auto 1px !important;
}

.challenge {
margin-top: 0 !important;
margin-left: 0 !important;
}

.confirm-inline {
position: absolute;
right: 10px;
top: 0;
margin: 0 !important;
padding-right: 25px !important;
background-color: transparent !important;
border: none !important;
opacity: .5;
}

.backup-code {
font-family: monospace;
letter-spacing: 0.02em;
font-size: 1.2em;
}
16 changes: 16 additions & 0 deletions apps/twofactor_backupcodes/js/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* global OC */

(function (OC) {
'use strict';

OC.Settings = OC.Settings || {};
OC.Settings.TwoFactorBackupCodes = OC.Settings.TwoFactorBackupCodes || {};

$(function () {
var view = new OC.Settings.TwoFactorBackupCodes.View({
el: $('#twofactor-backupcodes-settings')
});
view.render();
});
})(OC);

120 changes: 120 additions & 0 deletions apps/twofactor_backupcodes/js/settingsview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* global Backbone, Handlebars, OC, _ */

(function (OC, Handlebars, $, _) {
'use strict';

OC.Settings = OC.Settings || {};
OC.Settings.TwoFactorBackupCodes = OC.Settings.TwoFactorBackupCodes || {};

var TEMPLATE = '<div>'
+ '{{#unless enabled}}'
+ '<button id="generate-backup-codes">' + t('twofactor_backupcodes', 'Generate backup codes') + '</button>'
+ '{{else}}'
+ '<p>'
+ '{{#unless codes}}'
+ t('twofactor_backupcodes', 'Backup codes have been generated. {{used}} of {{total}} codes have been used.')
+ '{{else}}'
+ t('twofactor_backupcodes', 'These are your backup codes. Please save and/or print them as you will not be able to read the codes again later')
+ '<ul>'
+ '{{#each codes}}'
+ '<li class="backup-code">{{this}}</li>'
+ '{{/each}}'
+ '</ul>'
+ '<a href="{{download}}" class="button" download="Nextcloud-backup-codes.txt">' + t('twofactor_backupcodes', 'Save backup codes') + '</a>'
+ '<button id="print-backup-codes" class="button">' + t('twofactor_backupcodes', 'Print backup codes') + '</button>'
+ '{{/unless}}'
+ '</p>'
+ '<p>'
+ '<button id="generate-backup-codes">' + t('twofactor_backupcodes', 'Regenerate backup codes') + '</button>'
+ '</p>'
+ '<p>'
+ t('twofactor_backupcodes', 'If you regenerate backup codes, you automatically invalidate old codes.')
+ '</p>'
+ '{{/unless}}'
+ '</div';

var View = OC.Backbone.View.extend({
_template: undefined,
template: function (data) {
if (!this._template) {
this._template = Handlebars.compile(TEMPLATE);
}
return this._template(data);
},
_loading: undefined,
_enabled: undefined,
_total: undefined,
_used: undefined,
_codes: undefined,
events: {
'click #generate-backup-codes': '_onGenerateBackupCodes',
'click #print-backup-codes': '_onPrintBackupCodes',
},
initialize: function () {
this._load();
},
render: function () {
this.$el.html(this.template({
enabled: this._enabled,
total: this._total,
used: this._used,
codes: this._codes,
download: this._getDownloadDataHref()
}));
},
_getDownloadDataHref: function () {
if (!this._codes) {
return '';
}
return 'data:text/plain,' + encodeURIComponent(_.reduce(this._codes, function (prev, code) {
return prev + code + "\r\n";
}, ''));
},
_load: function () {
this._loading = true;

var url = OC.generateUrl('/apps/twofactor_backupcodes/settings/state');
var loading = $.ajax(url, {
method: 'GET',
});

$.when(loading).done(function (data) {
this._enabled = data.enabled;
this._total = data.total;
this._used = data.used;
}.bind(this));
$.when(loading).always(function () {
this._loading = false;
this.render();
}.bind(this));
},
_onGenerateBackupCodes: function () {
// Hide old codes
this._enabled = false;
this.render();
$('#generate-backup-codes').addClass('icon-loading-small');
var url = OC.generateUrl('/apps/twofactor_backupcodes/settings/create');
$.ajax(url, {
method: 'POST'
}).done(function (data) {
this._enabled = data.state.enabled;
this._total = data.state.total;
this._used = data.state.used;
this._codes = data.codes;
this.render();
}.bind(this)).fail(function () {
OC.Notification.showTemporary('An error occurred while generating your backup codes');
$('#generate-backup-codes').removeClass('icon-loading-small');
});
},
_onPrintBackupCodes: function () {
var url = this._getDownloadDataHref();
window.open(url, 'Nextcloud backpu codes');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙈

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the typo I mean

window.print();
window.close();
}
});

OC.Settings.TwoFactorBackupCodes.View = View;

})(OC, Handlebars, $, _);
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

/**
* @author Christoph Wurst <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\TwoFactor_BackupCodes\Controller;

use OCA\TwoFactor_BackupCodes\Service\BackupCodeStorage;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
use OCP\IUserSession;

class SettingsController extends Controller {

/** @var BackupCodeStorage */
private $storage;

/** @var IUserSession */
private $userSession;

/**
* @param string $appName
* @param IRequest $request
* @param BackupCodeStorage $storage
* @param IUserSession $userSession
*/
public function __construct($appName, IRequest $request, BackupCodeStorage $storage, IUserSession $userSession) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A 👑 for PHPDocs :)

parent::__construct($appName, $request);
$this->userSession = $userSession;
$this->storage = $storage;
}

/**
* @NoAdminRequired
* @return JSONResponse
*/
public function state() {
$user = $this->userSession->getUser();
return $this->storage->getBackupCodesState($user);
}

/**
* @NoAdminRequired
* @return JSONResponse
*/
public function createCodes() {
$user = $this->userSession->getUser();
$codes = $this->storage->createCodes($user);
return [
'codes' => $codes,
'state' => $this->storage->getBackupCodesState($user),
];
}

}
Loading