Skip to content

Commit 680f30d

Browse files
committed
created module spp_encryption
1 parent 799fd97 commit 680f30d

File tree

7 files changed

+146
-0
lines changed

7 files changed

+146
-0
lines changed

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ bravado_core
44
faker
55
geojson
66
jsonschema
7+
jwcrypto
78
pyjwt>=2.4.0
89
pyproj
910
python-magic
11+
qrcode
1012
shapely
1113
simplejson
1214
swagger_spec_validator

spp_encryption/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

spp_encryption/__manifest__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
2+
3+
4+
{
5+
"name": "SPP Encryption",
6+
"category": "OpenSPP",
7+
"version": "17.0.1.0.0",
8+
"sequence": 1,
9+
"author": "OpenSPP.org",
10+
"website": "https://github.com/OpenSPP/openspp-modules",
11+
"license": "LGPL-3",
12+
"development_status": "Beta",
13+
"maintainers": ["jeremi", "gonzalesedwin1123"],
14+
"depends": [
15+
"g2p_encryption",
16+
],
17+
"external_dependencies": {"python": ["jwcrypto"]},
18+
"data": [
19+
"views/encryption_provider.xml",
20+
],
21+
"assets": {},
22+
"demo": [],
23+
"images": [],
24+
"application": False,
25+
"installable": True,
26+
"auto_install": False,
27+
}

spp_encryption/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import encryption_provider
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import json
2+
import uuid
3+
4+
from jwcrypto import jwe, jwk, jwt
5+
from jwcrypto.common import json_decode, json_encode
6+
from jwcrypto.jws import InvalidJWSSignature
7+
8+
from odoo import fields, models
9+
10+
11+
class JWCryptoEncryptionProvider(models.Model):
12+
_inherit = "g2p.encryption.provider"
13+
14+
type = fields.Selection(selection_add=[("jwcrypto", "JWCrypto")])
15+
16+
jwcrypto_key = fields.Char(help="JWK key in JSON format for encryption, decryption, signing, and verification")
17+
18+
def _get_jwk_key(self):
19+
self.ensure_one()
20+
if not self.jwcrypto_key:
21+
raise ValueError("JWCrypto key is not set.")
22+
return jwk.JWK.from_json(self.jwcrypto_key)
23+
24+
def encrypt_data_jwcrypto(self, data: bytes, **kwargs) -> bytes:
25+
self.ensure_one()
26+
key = self._get_jwk_key()
27+
enc = jwe.JWE(data, json_encode({"alg": "RSA-OAEP", "enc": "A256GCM"}))
28+
enc.add_recipient(key)
29+
return enc.serialize(compact=True).encode("utf-8")
30+
31+
def decrypt_data_jwcrypto(self, data: bytes, **kwargs) -> bytes:
32+
self.ensure_one()
33+
key = self._get_jwk_key()
34+
enc = jwe.JWE()
35+
enc.deserialize(data.decode("utf-8"), key=key)
36+
return enc.payload
37+
38+
def jwt_sign_jwcrypto(self, data, **kwargs) -> str:
39+
self.ensure_one()
40+
key = self._get_jwk_key()
41+
token = jwt.JWT(header={"alg": "RS256"}, claims=data)
42+
token.make_signed_token(key)
43+
return token.serialize()
44+
45+
def jwt_verify_jwcrypto(self, token: str, **kwargs):
46+
self.ensure_one()
47+
key = self._get_jwk_key()
48+
try:
49+
received_jwt = jwt.JWT(key=key, jwt=token)
50+
verified = True
51+
except InvalidJWSSignature:
52+
received_jwt = None
53+
verified = False
54+
return verified, received_jwt
55+
56+
def get_jwks_jwcrypto(self, **kwargs):
57+
self.ensure_one()
58+
key = self._get_jwk_key()
59+
public_key = key.export_public()
60+
jwks = {"keys": [json_decode(public_key)]}
61+
return jwks
62+
63+
def generate_and_store_jwcrypto_key(self, key_type="RSA", size=2048):
64+
"""
65+
Generates a new JWK (JSON Web Key) for the current record and stores it in the `jwcrypto_key` field.
66+
:param key_type: The type of key to generate, e.g., 'RSA'.
67+
:param size: The size of the key (applies to RSA keys).
68+
:return: None
69+
"""
70+
if key_type != "RSA":
71+
raise ValueError("Unsupported key type. Currently, only 'RSA' is supported.")
72+
73+
key = jwk.JWK.generate(kty=key_type, size=size)
74+
75+
kid = str(uuid.uuid4())
76+
77+
key_export = key.export()
78+
79+
export_data = json.loads(key_export)
80+
export_data["kid"] = kid
81+
82+
key_export = json.dumps(export_data)
83+
84+
# Assuming this method is called on a specific record, not on the model class itself
85+
self.jwcrypto_key = key_export

spp_encryption/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<odoo>
3+
<record id="view_encryption_provider_form" model="ir.ui.view">
4+
<field name="name">view_encryption_provider_form</field>
5+
<field name="model">g2p.encryption.provider</field>
6+
<field name="inherit_id" ref="g2p_encryption.view_encryption_provider_form" />
7+
<field name="arch" type="xml">
8+
<xpath expr="//group[@name='Base']" position="after">
9+
<field name="jwcrypto_key" invisible="1" />
10+
<button
11+
name="generate_and_store_jwcrypto_key"
12+
string="Create Jwcrypto Key"
13+
type="object"
14+
class="oe_highlight btn-primary"
15+
invisible="jwcrypto_key"
16+
/>
17+
<button
18+
name="generate_and_store_jwcrypto_key"
19+
string="Update Jwcrypto Key"
20+
type="object"
21+
class="oe_highlight btn-primary"
22+
invisible="not jwcrypto_key"
23+
/>
24+
</xpath>
25+
</field>
26+
</record>
27+
</odoo>

0 commit comments

Comments
 (0)