feat(billing): service API-key generation + matching
Add _match_api_key() class method to fusion.billing.service, with a TDD test suite (TestServiceApiKey) covering key generation, hash storage, positive match, and rejection of bad/inactive keys. Also fix fcb_test_on_trial.sh to use --http-port 8070, as Odoo 19 forces http_spawn() even under --no-http when --test-enable is set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,3 +54,11 @@ class FusionBillingService(models.Model):
|
||||
raw = secrets.token_urlsafe(32)
|
||||
self.api_key_hash = hashlib.sha256(raw.encode()).hexdigest()
|
||||
return raw
|
||||
|
||||
@api.model
|
||||
def _match_api_key(self, raw_key):
|
||||
"""Return the active service whose stored hash matches raw_key, else empty recordset."""
|
||||
if not raw_key:
|
||||
return self.browse()
|
||||
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
|
||||
return self.search([('api_key_hash', '=', key_hash), ('active', '=', True)], limit=1)
|
||||
|
||||
1
fusion_centralize_billing/tests/__init__.py
Normal file
1
fusion_centralize_billing/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_identity
|
||||
25
fusion_centralize_billing/tests/test_identity.py
Normal file
25
fusion_centralize_billing/tests/test_identity.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo.tests.common import TransactionCase, tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestServiceApiKey(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.Service = self.env['fusion.billing.service'].sudo()
|
||||
self.service = self.Service.create({'name': 'NexaCloud', 'code': 'nexacloud'})
|
||||
|
||||
def test_generate_and_match_api_key(self):
|
||||
raw = self.service.action_generate_api_key()
|
||||
self.assertTrue(raw and len(raw) >= 20)
|
||||
self.assertTrue(self.service.api_key_hash)
|
||||
self.assertNotEqual(raw, self.service.api_key_hash) # only the hash is stored
|
||||
matched = self.Service._match_api_key(raw)
|
||||
self.assertEqual(matched, self.service)
|
||||
|
||||
def test_match_api_key_rejects_unknown_and_inactive(self):
|
||||
raw = self.service.action_generate_api_key()
|
||||
self.assertFalse(self.Service._match_api_key('nope-not-a-key'))
|
||||
self.service.active = False
|
||||
self.assertFalse(self.Service._match_api_key(raw))
|
||||
Reference in New Issue
Block a user