mirror of
https://github.com/bringout/oca-ocb-security.git
synced 2026-04-24 03:42:07 +02:00
Initial commit: Security packages
This commit is contained in:
commit
bb469e4763
1399 changed files with 278378 additions and 0 deletions
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import auth_totp_wizard
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,80 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
import functools
|
||||
import io
|
||||
import qrcode
|
||||
import re
|
||||
import werkzeug.urls
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.addons.base.models.res_users import check_identity
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.auth_totp.models.totp import ALGORITHM, DIGITS, TIMESTEP
|
||||
|
||||
compress = functools.partial(re.sub, r'\s', '')
|
||||
|
||||
class TOTPWizard(models.TransientModel):
|
||||
_name = 'auth_totp.wizard'
|
||||
_description = "2-Factor Setup Wizard"
|
||||
|
||||
user_id = fields.Many2one('res.users', required=True, readonly=True)
|
||||
secret = fields.Char(required=True, readonly=True)
|
||||
url = fields.Char(store=True, readonly=True, compute='_compute_qrcode')
|
||||
qrcode = fields.Binary(
|
||||
attachment=False, store=True, readonly=True,
|
||||
compute='_compute_qrcode',
|
||||
)
|
||||
code = fields.Char(string="Verification Code", size=7)
|
||||
|
||||
@api.depends('user_id.login', 'user_id.company_id.display_name', 'secret')
|
||||
def _compute_qrcode(self):
|
||||
# TODO: make "issuer" configurable through config parameter?
|
||||
global_issuer = request and request.httprequest.host.split(':', 1)[0]
|
||||
for w in self:
|
||||
issuer = global_issuer or w.user_id.company_id.display_name
|
||||
w.url = url = werkzeug.urls.url_unparse((
|
||||
'otpauth', 'totp',
|
||||
werkzeug.urls.url_quote(f'{issuer}:{w.user_id.login}', safe=':'),
|
||||
werkzeug.urls.url_encode({
|
||||
'secret': compress(w.secret),
|
||||
'issuer': issuer,
|
||||
# apparently a lowercase hash name is anathema to google
|
||||
# authenticator (error) and passlib (no token)
|
||||
'algorithm': ALGORITHM.upper(),
|
||||
'digits': DIGITS,
|
||||
'period': TIMESTEP,
|
||||
}), ''
|
||||
))
|
||||
|
||||
data = io.BytesIO()
|
||||
qrcode.make(url.encode(), box_size=4).save(data, optimise=True, format='PNG')
|
||||
w.qrcode = base64.b64encode(data.getvalue()).decode()
|
||||
|
||||
@check_identity
|
||||
def enable(self):
|
||||
try:
|
||||
c = int(compress(self.code))
|
||||
except ValueError:
|
||||
raise UserError(_("The verification code should only contain numbers"))
|
||||
if self.user_id._totp_try_setting(self.secret, c):
|
||||
self.secret = '' # empty it, because why keep it until GC?
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'type': 'success',
|
||||
'message': _("2-Factor authentication is now enabled."),
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
raise UserError(_('Verification failed, please double-check the 6-digit code'))
|
||||
|
||||
def create(self, vals_list):
|
||||
rule = self.env.ref('auth_totp.rule_auth_totp_wizard', raise_if_not_found=False)
|
||||
if rule and rule.sudo().groups:
|
||||
rule.sudo().groups = False
|
||||
return super().create(vals_list)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record model="ir.ui.view" id="view_totp_wizard">
|
||||
<field name="name">auth_totp wizard</field>
|
||||
<field name="model">auth_totp.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="o_auth_totp_enable_2FA container">
|
||||
<div class="mb-3 w-100">
|
||||
<h3 class="fw-bold">Authenticator App Setup</h3>
|
||||
<ul>
|
||||
<div class="d-md-none d-block">
|
||||
<li>
|
||||
<field class="text-wrap" name="url" widget="url" options="{'website_path': True}"
|
||||
text="Click on this link to open your authenticator app"/></li>
|
||||
</div>
|
||||
<li>
|
||||
<div class="d-flex align-items-center flex-wrap">
|
||||
<span class="d-md-none d-block">Or install an authenticator app</span>
|
||||
<span class="d-none d-md-block">Install an authenticator app on your mobile device</span>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<span class="text-muted">Popular ones include Authy, Google Authenticator or the Microsoft Authenticator.</span>
|
||||
<li>Look for an "Add an account" button</li>
|
||||
<li>
|
||||
<span class="d-none d-md-block">When requested to do so, scan the barcode below</span>
|
||||
<span class="d-block d-md-none">When requested to do so, copy the key below</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Desktop version -->
|
||||
<div class="text-center d-none d-md-block">
|
||||
<field name="qrcode" readonly="True" widget="image" options="{'no_reload': true }" />
|
||||
|
||||
<h3 class="fw-bold"><a data-bs-toggle="collapse"
|
||||
href="#collapseTotpSecret" role="button" aria-expanded="false"
|
||||
aria-controls="collapseTotpSecret">Cannot scan it?</a></h3>
|
||||
<div class="collapse" id="collapseTotpSecret">
|
||||
<field name="secret" widget="CopyClipboardChar" readonly="1" class="mb-3 ps-3"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Version -->
|
||||
<div class="text-center d-block d-md-none">
|
||||
<field name="secret" widget="CopyClipboardChar" readonly="1" class="mb-3 ps-3"/>
|
||||
</div>
|
||||
|
||||
<h3 class="fw-bold">Enter your six-digit code below</h3>
|
||||
<div class="mt-2">
|
||||
<label for="code" class="px-0">Verification Code</label>
|
||||
<div class="d-flex align-items-center">
|
||||
<field required="True" name="code" autocomplete="off" class="o_field_highlight px-0 me-2" placeholder="e.g. 123456"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button type="object" name="enable" class="btn btn-primary"
|
||||
string="Activate" data-hotkey="q"/>
|
||||
<button string="Cancel" special="cancel" data-hotkey="z"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue