|
@ -5,6 +5,7 @@ |
|
|
# |
|
|
# |
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
|
# Author: Ayana KP (odoo@cybrosys.com) |
|
|
# Author: Ayana KP (odoo@cybrosys.com) |
|
|
|
|
|
# Modified by: Broigm - Improvements in API key management |
|
|
# |
|
|
# |
|
|
# You can modify it under the terms of the GNU LESSER |
|
|
# You can modify it under the terms of the GNU LESSER |
|
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|
@ -20,25 +21,117 @@ |
|
|
# |
|
|
# |
|
|
############################################################################# |
|
|
############################################################################# |
|
|
import uuid |
|
|
import uuid |
|
|
from odoo import fields, models |
|
|
import secrets |
|
|
|
|
|
import string |
|
|
|
|
|
from datetime import datetime, timedelta |
|
|
|
|
|
from odoo import fields, models, api |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResUsers(models.Model): |
|
|
class ResUsers(models.Model): |
|
|
"""This class is used to inherit users and add api key generation""" |
|
|
"""Extensión del modelo de usuarios para gestión de API keys""" |
|
|
_inherit = 'res.users' |
|
|
_inherit = 'res.users' |
|
|
|
|
|
|
|
|
api_key = fields.Char(string="API Key", readonly=True, |
|
|
api_key = fields.Char( |
|
|
help="Api key for connecting with the " |
|
|
string="API Key", |
|
|
"Database.The key will be " |
|
|
readonly=True, |
|
|
"generated when authenticating " |
|
|
help="Clave API para autenticación en REST API. Se genera automáticamente." |
|
|
"rest api.") |
|
|
) |
|
|
|
|
|
api_key_expiry = fields.Datetime( |
|
|
|
|
|
string="API Key Expiry", |
|
|
|
|
|
help="Fecha de expiración de la API key (opcional)" |
|
|
|
|
|
) |
|
|
|
|
|
api_key_created = fields.Datetime( |
|
|
|
|
|
string="API Key Created", |
|
|
|
|
|
help="Fecha de creación de la API key" |
|
|
|
|
|
) |
|
|
|
|
|
api_key_last_used = fields.Datetime( |
|
|
|
|
|
string="API Key Last Used", |
|
|
|
|
|
help="Última vez que se usó la API key" |
|
|
|
|
|
) |
|
|
|
|
|
api_requests_count = fields.Integer( |
|
|
|
|
|
string="API Requests Count", |
|
|
|
|
|
default=0, |
|
|
|
|
|
help="Contador de requests realizados con esta API key" |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
def generate_api(self, username): |
|
|
def generate_api_key(self, force_new=False): |
|
|
"""This function is used to generate api-key for each user""" |
|
|
""" |
|
|
users = self.env['res.users'].sudo().search([('login', '=', username)]) |
|
|
Genera una nueva API key o devuelve la existente |
|
|
if not users.api_key: |
|
|
Args: |
|
|
users.api_key = str(uuid.uuid4()) |
|
|
force_new (bool): Fuerza la generación de una nueva key |
|
|
key = users.api_key |
|
|
Returns: |
|
|
|
|
|
str: API key generada |
|
|
|
|
|
""" |
|
|
|
|
|
if not self.api_key or force_new: |
|
|
|
|
|
# Generar una API key más segura |
|
|
|
|
|
alphabet = string.ascii_letters + string.digits |
|
|
|
|
|
api_key = ''.join(secrets.choice(alphabet) for _ in range(64)) |
|
|
|
|
|
|
|
|
|
|
|
self.write({ |
|
|
|
|
|
'api_key': api_key, |
|
|
|
|
|
'api_key_created': datetime.now(), |
|
|
|
|
|
'api_key_last_used': None, |
|
|
|
|
|
'api_requests_count': 0 |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
return self.api_key |
|
|
|
|
|
|
|
|
|
|
|
def regenerate_api_key(self): |
|
|
|
|
|
"""Regenera la API key (útil para botón en interfaz)""" |
|
|
|
|
|
return self.generate_api_key(force_new=True) |
|
|
|
|
|
|
|
|
|
|
|
def revoke_api_key(self): |
|
|
|
|
|
"""Revoca la API key actual""" |
|
|
|
|
|
self.write({ |
|
|
|
|
|
'api_key': False, |
|
|
|
|
|
'api_key_expiry': False, |
|
|
|
|
|
'api_key_created': False, |
|
|
|
|
|
'api_key_last_used': False |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
def set_api_key_expiry(self, days=None): |
|
|
|
|
|
""" |
|
|
|
|
|
Establece fecha de expiración para la API key |
|
|
|
|
|
Args: |
|
|
|
|
|
days (int): Días hasta la expiración (default: sin expiración) |
|
|
|
|
|
""" |
|
|
|
|
|
if days: |
|
|
|
|
|
expiry_date = datetime.now() + timedelta(days=days) |
|
|
|
|
|
self.api_key_expiry = expiry_date |
|
|
else: |
|
|
else: |
|
|
key = users.api_key |
|
|
self.api_key_expiry = False |
|
|
return key |
|
|
|
|
|
|
|
|
def update_api_key_usage(self): |
|
|
|
|
|
"""Actualiza estadísticas de uso de la API key""" |
|
|
|
|
|
self.write({ |
|
|
|
|
|
'api_key_last_used': datetime.now(), |
|
|
|
|
|
'api_requests_count': self.api_requests_count + 1 |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
@api.model |
|
|
|
|
|
def cleanup_expired_api_keys(self): |
|
|
|
|
|
"""Limpia API keys expiradas (para ejecutar en cron)""" |
|
|
|
|
|
expired_users = self.search([ |
|
|
|
|
|
('api_key_expiry', '!=', False), |
|
|
|
|
|
('api_key_expiry', '<', datetime.now()) |
|
|
|
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
for user in expired_users: |
|
|
|
|
|
user.revoke_api_key() |
|
|
|
|
|
|
|
|
|
|
|
return len(expired_users) |
|
|
|
|
|
|
|
|
|
|
|
def is_api_key_valid(self): |
|
|
|
|
|
"""Verifica si la API key es válida y no ha expirado""" |
|
|
|
|
|
if not self.api_key: |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
if self.api_key_expiry and self.api_key_expiry < datetime.now(): |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
# Método legacy para compatibilidad con código anterior |
|
|
|
|
|
def generate_api(self, username): |
|
|
|
|
|
"""Método de compatibilidad con la versión anterior""" |
|
|
|
|
|
return self.generate_api_key() |
|
|