mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-25 22:41:57 +02:00
Remove the ability to set a plain text secret
This commit is contained in:
parent
6f56c84928
commit
b6e4cf50a4
@ -28,4 +28,15 @@ class Helpers
|
||||
// We use the regex for semver detection (see https://semver.org/)
|
||||
return preg_match('/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?/', $release, $version) ? $version[0] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string to comply with Base32 format
|
||||
*
|
||||
* @param string $str
|
||||
* @return string The filename
|
||||
*/
|
||||
public static function PadToBase32Format(?string $str): string
|
||||
{
|
||||
return blank($str) ? '' : strtoupper(str_pad($str, (int) ceil(strlen($str) / 8) * 8, '='));
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ class TwoFAccount extends Model implements Sortable
|
||||
public function setSecretAttribute($value)
|
||||
{
|
||||
// Encrypt when needed
|
||||
$this->attributes['secret'] = $this->encryptOrReturn($value);
|
||||
$this->attributes['secret'] = $this->encryptOrReturn(Helpers::PadToBase32Format($value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\Helpers\Helpers;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use ParagonIE\ConstantTime\Base32;
|
||||
|
||||
@ -27,7 +28,7 @@ class IsBase32Encoded implements Rule
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
try {
|
||||
$secret = Base32::decodeUpper($value);
|
||||
$secret = Base32::decodeUpper(Helpers::PadToBase32Format($value));
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
13
package-lock.json
generated
13
package-lock.json
generated
@ -9,11 +9,10 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.6",
|
||||
"axios": "^1.0.0",
|
||||
"axios": "^1.1.0",
|
||||
"bulma": "^0.9.3",
|
||||
"bulma-checkradio": "^2.1.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"hi-base32": "^0.5.1",
|
||||
"object-equals": "^0.3.0",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.14",
|
||||
@ -5116,11 +5115,6 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/hi-base32": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz",
|
||||
"integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA=="
|
||||
},
|
||||
"node_modules/hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
@ -13647,11 +13641,6 @@
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"hi-base32": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz",
|
||||
"integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA=="
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
|
@ -30,7 +30,6 @@
|
||||
"bulma": "^0.9.3",
|
||||
"bulma-checkradio": "^2.1.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"hi-base32": "^0.5.1",
|
||||
"object-equals": "^0.3.0",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.14",
|
||||
|
@ -101,14 +101,7 @@
|
||||
<div v-if="form.otp_type">
|
||||
<!-- secret -->
|
||||
<label :for="this.inputId('text','secret')" class="label" v-html="$t('twofaccounts.forms.secret.label')"></label>
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<span class="select">
|
||||
<select @change="form.secret=''" v-model="secretIsBase32Encoded">
|
||||
<option v-for="(format) in secretFormats" :key="format.value" :value="format.value">{{ format.text }}</option>
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
<div class="field">
|
||||
<p class="control is-expanded">
|
||||
<input :id="this.inputId('text','secret')" class="input" type="text" v-model="form.secret">
|
||||
</p>
|
||||
@ -146,7 +139,7 @@
|
||||
</form>
|
||||
<!-- modal -->
|
||||
<modal v-model="ShowTwofaccountInModal">
|
||||
<otp-displayer ref="AdvancedFormOtpDisplayer" v-bind="otpdisplayerData" @increment-hotp="incrementHotp" @validation-error="mapDisplayerErrors">
|
||||
<otp-displayer ref="AdvancedFormOtpDisplayer" v-bind="form.data()" @increment-hotp="incrementHotp" @validation-error="mapDisplayerErrors">
|
||||
</otp-displayer>
|
||||
</modal>
|
||||
</form-wrapper>
|
||||
@ -198,7 +191,6 @@
|
||||
import Modal from '../../components/Modal'
|
||||
import Form from './../../components/Form'
|
||||
import OtpDisplayer from '../../components/OtpDisplayer'
|
||||
import Base32 from "hi-base32"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -209,7 +201,6 @@
|
||||
showAlternatives : false,
|
||||
tempIcon: '',
|
||||
uri: '',
|
||||
secretIsBase32Encoded: 0,
|
||||
form: new Form({
|
||||
service: '',
|
||||
account: '',
|
||||
@ -235,10 +226,6 @@
|
||||
{ text: 9, value: 9 },
|
||||
{ text: 10, value: 10 },
|
||||
],
|
||||
secretFormats: [
|
||||
{ text: this.$t('twofaccounts.forms.plain_text'), value: 0 },
|
||||
{ text: 'Base32', value: 1 }
|
||||
],
|
||||
algorithms: [
|
||||
{ text: 'sha1', value: 'sha1' },
|
||||
{ text: 'sha256', value: 'sha256' },
|
||||
@ -260,17 +247,6 @@
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
otpdisplayerData: function() {
|
||||
let o = this.form.data()
|
||||
o.secret = this.secretIsBase32Encoded
|
||||
? o.secret
|
||||
: Base32.encode(o.secret).toString();
|
||||
|
||||
return o
|
||||
}
|
||||
},
|
||||
|
||||
mounted: function () {
|
||||
if( this.$route.params.decodedUri ) {
|
||||
this.uri = this.$route.params.decodedUri
|
||||
@ -279,7 +255,6 @@
|
||||
this.axios.post('/api/v1/twofaccounts/preview', { uri: this.uri }).then(response => {
|
||||
|
||||
this.form.fill(response.data)
|
||||
this.secretIsBase32Encoded = 1
|
||||
this.tempIcon = response.data.icon ? response.data.icon : null
|
||||
this.showQuickForm = true
|
||||
})
|
||||
@ -315,9 +290,6 @@
|
||||
// set current temp icon as account icon
|
||||
this.form.icon = this.tempIcon
|
||||
|
||||
// Secret to base32 if necessary
|
||||
this.form.secret = this.secretIsBase32Encoded ? this.form.secret : Base32.encode(this.form.secret).toString();
|
||||
|
||||
await this.form.post('/api/v1/twofaccounts')
|
||||
|
||||
if( this.form.errors.any() === false ) {
|
||||
@ -359,7 +331,6 @@
|
||||
// Then the otp described by the uri
|
||||
this.axios.post('/api/v1/twofaccounts/preview', { uri: this.uri }).then(response => {
|
||||
this.form.fill(response.data)
|
||||
this.secretIsBase32Encoded = 1
|
||||
this.tempIcon = response.data.icon ? response.data.icon : null
|
||||
})
|
||||
.catch(error => {
|
||||
@ -441,9 +412,7 @@
|
||||
this.form.otp_type = to
|
||||
|
||||
if (to === 'steamtotp') {
|
||||
this.secretIsBase32Encoded = 1
|
||||
this.form.service = 'Steam'
|
||||
this.form.secret = ''
|
||||
this.fetchLogo()
|
||||
}
|
||||
else if (from === 'steamtotp') {
|
||||
|
@ -46,13 +46,6 @@
|
||||
<!-- secret -->
|
||||
<label :for="this.inputId('text','secret')" class="label" v-html="$t('twofaccounts.forms.secret.label')"></label>
|
||||
<div class="field has-addons">
|
||||
<p v-if="!secretIsLocked" class="control">
|
||||
<span class="select">
|
||||
<select @change="form.secret=''" v-model="secretIsBase32Encoded">
|
||||
<option v-for="(format) in secretFormats" :key="format.value" :value="format.value">{{ format.text }}</option>
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control is-expanded">
|
||||
<input :id="this.inputId('text','secret')" class="input" type="text" v-model="form.secret" :disabled="secretIsLocked">
|
||||
</p>
|
||||
@ -141,7 +134,6 @@
|
||||
import Modal from '../../components/Modal'
|
||||
import Form from './../../components/Form'
|
||||
import OtpDisplayer from '../../components/OtpDisplayer'
|
||||
import Base32 from "hi-base32"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -150,7 +142,6 @@
|
||||
counterIsLocked: true,
|
||||
twofaccountExists: false,
|
||||
tempIcon: '',
|
||||
secretIsBase32Encoded: null,
|
||||
form: new Form({
|
||||
service: '',
|
||||
account: '',
|
||||
@ -176,10 +167,6 @@
|
||||
{ text: 9, value: 9 },
|
||||
{ text: 10, value: 10 },
|
||||
],
|
||||
secretFormats: [
|
||||
{ text: this.$t('twofaccounts.forms.plain_text'), value: 0 },
|
||||
{ text: 'Base32', value: 1 }
|
||||
],
|
||||
algorithms: [
|
||||
{ text: 'sha1', value: 'sha1' },
|
||||
{ text: 'sha256', value: 'sha256' },
|
||||
@ -214,7 +201,6 @@
|
||||
const { data } = await this.axios.get('/api/v1/twofaccounts/' + this.$route.params.twofaccountId)
|
||||
|
||||
this.form.fill(data)
|
||||
this.secretIsBase32Encoded = 1
|
||||
this.twofaccountExists = true
|
||||
|
||||
// set account icon as temp icon
|
||||
@ -235,9 +221,6 @@
|
||||
this.deleteIcon()
|
||||
}
|
||||
|
||||
// Secret to base32 if necessary
|
||||
this.form.secret = this.secretIsBase32Encoded ? this.form.secret : Base32.encode(this.form.secret).toString();
|
||||
|
||||
await this.form.put('/api/v1/twofaccounts/' + this.$route.params.twofaccountId)
|
||||
|
||||
if( this.form.errors.any() === false ) {
|
||||
|
@ -171,7 +171,6 @@
|
||||
otp_type: '',
|
||||
icon: '',
|
||||
secret: '',
|
||||
secretIsBase32Encoded: 1,
|
||||
algorithm: '',
|
||||
digits: null,
|
||||
counter: null,
|
||||
|
Loading…
x
Reference in New Issue
Block a user