First Commit

This commit is contained in:
2026-05-31 10:17:09 +07:00
commit 17a9c69379
4547 changed files with 1170384 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
import datetime
import functools
import json
import uuid
import jwt
from odoo import fields, http
from odoo.http import request
from odoo.tools import config
JWT_ISSUER = 'odoo'
JWT_AUDIENCE = 'odoo-api'
def json_response(payload, status=200):
return request.make_response(
json.dumps(payload),
headers=[('Content-Type', 'application/json')],
status=status,
)
def get_jwt_secret():
secret_key = config.get('jwt_secret')
if not secret_key or len(secret_key) < 32:
return None
return secret_key
def check_jwt_auth(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
auth_header = request.httprequest.headers.get('Authorization', '')
if not auth_header.startswith('Bearer '):
return json_response({'error': 'Bearer token is required.'}, status=401)
secret_key = get_jwt_secret()
if not secret_key:
return json_response({'error': 'JWT secret is not configured.'}, status=500)
token = auth_header.split(' ', 1)[1].strip()
try:
payload = jwt.decode(
token,
secret_key,
algorithms=['HS256'],
issuer=JWT_ISSUER,
audience=JWT_AUDIENCE,
options={'require': ['exp', 'iat', 'sub', 'client_id']},
)
user_id = int(payload['sub'])
client = request.env['api.client'].sudo().search([
('client_id', '=', payload['client_id']),
('active', '=', True),
('user_id', '=', user_id),
], limit=1)
user = request.env['res.users'].sudo().browse(user_id).exists()
if not client or not user or not user.active:
return json_response({'error': 'Token subject is not allowed.'}, status=401)
request.jwt_payload = payload
request.jwt_client = client
request.jwt_user_id = user_id
request.update_env(user=user_id)
except jwt.ExpiredSignatureError:
return json_response({'error': 'Token has expired.'}, status=401)
except (jwt.InvalidTokenError, ValueError):
return json_response({'error': 'Token is invalid.'}, status=401)
return func(self, *args, **kwargs)
return wrapper
class JwtAuthController(http.Controller):
@http.route('/api/auth/token', type='http', auth='public', methods=['POST'], csrf=False)
def generate_token(self, **kwargs):
data = request.httprequest.get_json(silent=True) or kwargs
client_id = data.get('client_id')
client_secret = data.get('client_secret') or data.get('secret_key')
if not client_id or not client_secret:
return json_response({'error': 'client_id and client_secret are required.'}, status=400)
secret_key = get_jwt_secret()
if not secret_key:
return json_response({'error': 'JWT secret is not configured.'}, status=500)
client = request.env['api.client'].sudo().search([
('client_id', '=', client_id),
('active', '=', True),
], limit=1)
if not client or not client._check_secret(client_secret) or not client.user_id.active:
return json_response({'error': 'Invalid credentials.'}, status=401)
now = datetime.datetime.now(datetime.UTC)
expires_at = now + datetime.timedelta(seconds=client.token_ttl)
payload = {
'iss': JWT_ISSUER,
'aud': JWT_AUDIENCE,
'exp': expires_at,
'iat': now,
'jti': str(uuid.uuid4()),
'sub': str(client.user_id.id),
'client_id': client.client_id,
}
token = jwt.encode(payload, secret_key, algorithm='HS256')
client.last_used = fields.Datetime.now()
return json_response({
'access_token': token,
'expires_in': client.token_ttl,
'token_type': 'Bearer',
})
@http.route('/api/ifc/projects', type='http', auth='public', methods=['GET', 'POST'], csrf=False)
@check_jwt_auth
def get_ifc_projects(self, **kwargs):
return json_response({
'message': 'JWT token is valid.',
'user_id': request.env.user.id,
'user_name': request.env.user.name,
'client_id': request.jwt_payload.get('client_id'),
'data': ['Proyek_IFC_Gedung_A', 'Proyek_IFC_Infrastruktur_B'],
})