mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-20 11:47:53 +02:00
Merge branch 'hotfix-sql-xss-injection' into dev
This commit is contained in:
commit
a51f0bb2d9
19
.github/SECURITY.md
vendored
Normal file
19
.github/SECURITY.md
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability in 2FAuth, please report it through coordinated disclosure.
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through the repository issues, discussions, or pull requests.**
|
||||||
|
|
||||||
|
Instead, please send an email to contact[at]2fauth.app or open a new [Github security advisory](https://github.com/Bubka/2FAuth/security/advisories/new).
|
||||||
|
|
||||||
|
Please include as much of the information listed below as you can to help me better understand and resolve the issue:
|
||||||
|
|
||||||
|
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
|
This information will help me triage your report more quickly.
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Api\v1\Controllers;
|
namespace App\Api\v1\Controllers;
|
||||||
|
|
||||||
|
use App\Api\v1\Requests\IconFetchRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\TwoFAccount;
|
use App\Models\TwoFAccount;
|
||||||
use App\Services\LogoService;
|
use App\Services\LogoService;
|
||||||
@ -34,13 +35,11 @@ class IconController extends Controller
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function fetch(Request $request, LogoService $logoService)
|
public function fetch(IconFetchRequest $request, LogoService $logoService)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$validated = $request->validated();
|
||||||
'service' => 'string|regex:/^[^:]+$/i',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$icon = $logoService->getIcon($request->service);
|
$icon = $logoService->getIcon($validated['service']);
|
||||||
|
|
||||||
return $icon
|
return $icon
|
||||||
? response()->json(['filename' => $icon], 201)
|
? response()->json(['filename' => $icon], 201)
|
||||||
|
@ -28,7 +28,7 @@ class GroupStoreRequest extends FormRequest
|
|||||||
return [
|
return [
|
||||||
'name' => [
|
'name' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'regex:/^[a-zA-Z0-9\s\-_]+$/',
|
||||||
'max:32',
|
'max:32',
|
||||||
Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)),
|
Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)),
|
||||||
],
|
],
|
||||||
|
45
app/Api/v1/Requests/IconFetchRequest.php
Normal file
45
app/Api/v1/Requests/IconFetchRequest.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Api\v1\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class IconFetchRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return Auth::check();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'service' => 'string|regex:/^[^:]+$/i',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the data for validation.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$this->merge([
|
||||||
|
'service' => strip_tags($this->service),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ class CaseInsensitiveEmailExists implements Rule
|
|||||||
public function passes($attribute, $value)
|
public function passes($attribute, $value)
|
||||||
{
|
{
|
||||||
$user = DB::table('users')
|
$user = DB::table('users')
|
||||||
->whereRaw('email = \'' . strtolower($value) . '\'' . ('sqlite' === config('database.default') ? ' COLLATE NOCASE' : ''))
|
->whereRaw('email = ?' . ('sqlite' === config('database.default') ? ' COLLATE NOCASE' : ''), [strtolower($value)])
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
return ! $user ? false : true;
|
return ! $user ? false : true;
|
||||||
|
@ -21,6 +21,13 @@ This new version introduces a very common feature in the 2FA app world
|
|||||||
- [issue #180](https://github.com/Bubka/2FAuth/issues/180) OTP does not rotate while close after copy and copy on display is activated - By [@josh-gaby](https://github.com/josh-gaby)
|
- [issue #180](https://github.com/Bubka/2FAuth/issues/180) OTP does not rotate while close after copy and copy on display is activated - By [@josh-gaby](https://github.com/josh-gaby)
|
||||||
- [issue #194](https://github.com/Bubka/2FAuth/issues/194) Container keeps trying to make connection to 172.67.161.186
|
- [issue #194](https://github.com/Bubka/2FAuth/issues/194) Container keeps trying to make connection to 172.67.161.186
|
||||||
|
|
||||||
|
## [4.0.3] - 2023-06-30
|
||||||
|
|
||||||
|
### Security release
|
||||||
|
|
||||||
|
- Fix possible SQL injection in validation rule (thx [@YouGina](https://github.com/YouGina))
|
||||||
|
- Fix various possible XSS injections (thx [@quirinziessler](https://github.com/quirinziessler))
|
||||||
|
|
||||||
## [4.0.2] - 2023-04-19
|
## [4.0.2] - 2023-04-19
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
4
resources/js/mixins.js
vendored
4
resources/js/mixins.js
vendored
@ -137,6 +137,10 @@ Vue.mixin({
|
|||||||
}
|
}
|
||||||
return this.$root.userPreferences.showOtpAsDot ? pwd.replace(/[0-9]/g, '●') : pwd
|
return this.$root.userPreferences.showOtpAsDot ? pwd.replace(/[0-9]/g, '●') : pwd
|
||||||
},
|
},
|
||||||
|
|
||||||
|
strip_tags (str) {
|
||||||
|
return str.replace(/(<([^> ]+)>)/ig, "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
@ -149,7 +149,7 @@
|
|||||||
<div class="block">
|
<div class="block">
|
||||||
{{ $t('errors.data_of_qrcode_is_not_valid_URI') }}
|
{{ $t('errors.data_of_qrcode_is_not_valid_URI') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="block mb-6" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'" v-html="uri"></div>
|
<div class="block mb-6" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'">{{ uri }}</div>
|
||||||
<!-- Copy to clipboard -->
|
<!-- Copy to clipboard -->
|
||||||
<div class="block has-text-link">
|
<div class="block has-text-link">
|
||||||
<button class="button is-link is-outlined is-rounded" v-clipboard="() => uri" v-clipboard:success="clipboardSuccessHandler">
|
<button class="button is-link is-outlined is-rounded" v-clipboard="() => uri" v-clipboard:success="clipboardSuccessHandler">
|
||||||
@ -377,10 +377,10 @@
|
|||||||
this.deleteIcon()
|
this.deleteIcon()
|
||||||
this.tempIcon = response.data.filename;
|
this.tempIcon = response.data.filename;
|
||||||
}
|
}
|
||||||
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) })
|
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) })
|
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -265,10 +265,10 @@
|
|||||||
this.deleteIcon()
|
this.deleteIcon()
|
||||||
this.tempIcon = response.data.filename;
|
this.tempIcon = response.data.filename;
|
||||||
}
|
}
|
||||||
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) })
|
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) })
|
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -105,9 +105,6 @@ class GroupStoreRequestTest extends FeatureTestCase
|
|||||||
[[
|
[[
|
||||||
'name' => true, // string
|
'name' => true, // string
|
||||||
]],
|
]],
|
||||||
[[
|
|
||||||
'name' => 8, // string
|
|
||||||
]],
|
|
||||||
[[
|
[[
|
||||||
'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss', // max:32
|
'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss', // max:32
|
||||||
]],
|
]],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user