52 lines
2.7 KiB
Python
52 lines
2.7 KiB
Python
import base64
|
|
import copy
|
|
import unittest
|
|
from datetime import datetime, timezone
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
from monitor_runtime.licensing import canonical, verify_document, LicenseError
|
|
|
|
class OfflineLicenseTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.key = Ed25519PrivateKey.generate()
|
|
self.public = self.key.public_key().public_bytes(serialization.Encoding.PEM,serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
self.now = datetime(2026,8,30,tzinfo=timezone.utc).timestamp()
|
|
self.payload = dict(schema_version=1,product='monitor',license_id='test-id',customer='test',
|
|
machine_fingerprint='v1:'+'a'*64,issued_at='2026-08-29T00:00:00Z',expires_at=None)
|
|
|
|
def sign(self, payload=None):
|
|
payload = payload or self.payload
|
|
return {'payload':payload,'signature':base64.b64encode(self.key.sign(canonical(payload))).decode()}
|
|
|
|
def verify(self, document, **kwargs):
|
|
return verify_document(document,kwargs.get('public',self.public),
|
|
kwargs.get('fingerprint',self.payload['machine_fingerprint']),kwargs.get('now',self.now))
|
|
|
|
def test_perpetual_and_dated(self):
|
|
self.assertEqual(self.verify(self.sign())['customer'],'test')
|
|
self.payload['expires_at']='2026-08-31T00:00:00Z'
|
|
self.verify(self.sign())
|
|
|
|
def test_expiry_boundary_and_future_issue(self):
|
|
self.payload['expires_at']='2026-08-30T00:00:00Z'
|
|
with self.assertRaises(LicenseError):self.verify(self.sign())
|
|
self.payload['expires_at']=None
|
|
self.payload['issued_at']='2026-09-01T00:00:00Z'
|
|
with self.assertRaises(LicenseError):self.verify(self.sign())
|
|
|
|
def test_machine_signature_and_key_mismatch(self):
|
|
doc=self.sign()
|
|
with self.assertRaises(LicenseError):self.verify(doc,fingerprint='another')
|
|
bad=copy.deepcopy(doc);bad['payload']['customer']='tampered'
|
|
with self.assertRaises(LicenseError):self.verify(bad)
|
|
other=Ed25519PrivateKey.generate().public_key().public_bytes(serialization.Encoding.PEM,serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
with self.assertRaises(LicenseError):self.verify(doc,public=other)
|
|
|
|
def test_product_version_structure_and_timezone(self):
|
|
for field,value in [('product','other'),('schema_version',2),('issued_at','2026-08-29'),('customer','')]:
|
|
with self.subTest(field=field):
|
|
payload=dict(self.payload);payload[field]=value
|
|
with self.assertRaises(LicenseError):self.verify(self.sign(payload))
|
|
bad=self.sign();bad['unexpected']=1
|
|
with self.assertRaises(LicenseError):self.verify(bad)
|