Skip to content

Commit

Permalink
fixup! fixup! fixup! fixup! fixup! add support for mongodb Client Sid…
Browse files Browse the repository at this point in the history
…e Field Level Encryption (CSFLE)
  • Loading branch information
dill0wn committed Sep 12, 2024
1 parent 1e118db commit 0bbf3c8
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 25 deletions.
29 changes: 29 additions & 0 deletions ming/declarative.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from typing import TypeVar, Mapping, Any

from pymongo.encryption import ClientEncryption

from ming.base import Object
from ming.datastore import DataStore
from ming.metadata import Manager

M = TypeVar('M')
Expand All @@ -16,6 +19,32 @@ class Document(Object):
@classmethod
def make(cls, data, allow_extra=False, strip_extra=True) -> Document: ...

# Encryption-Related fields:

@classmethod
def make_encr(cls, data: dict) -> Document: ...

@classmethod
def encr(cls, s: str | None, _first_attempt=True, provider='local') -> bytes | None: ...

@classmethod
def decr(cls, b: bytes | None) -> str | None: ...

@classmethod
def encryptor(cls, ming_ds: DataStore) -> ClientEncryption: ...

@classmethod
def make_data_key(cls): ...

@classmethod
def decrypted_field_names(cls) -> list[str]: ...

@classmethod
def encrypted_field_names(cls) -> list[str]: ...

@classmethod
def encrypt_some_fields(cls, data: dict) -> dict: ...

# ...
# class __mongometa__:
# name: Any = ...
Expand Down
21 changes: 1 addition & 20 deletions ming/encryption.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from __future__ import annotations

import base64
from copy import deepcopy
from contextlib import contextmanager
import json
import os
import random
from typing import TYPE_CHECKING, TypeVar, Generic

from cachetools import cached, RRCache
Expand All @@ -20,21 +16,6 @@
import ming.datastore

Check warning on line 16 in ming/encryption.py

View check run for this annotation

Codecov / codecov/patch

ming/encryption.py#L14-L16

Added lines #L14 - L16 were not covered by tests


@contextmanager
def push_seed(seed):
rstate = random.getstate()
random.seed(seed)
try:
yield
finally:
random.setstate(rstate)


def make_encryption_key(seed=__name__):
with push_seed(seed):
return base64.b64encode(os.urandom(96)).decode('ascii')


class MingEncryptionError(Exception):
pass

Expand Down Expand Up @@ -89,7 +70,7 @@ class EncryptedDocumentMixin:

@classmethod
@cached(RRCache(maxsize=99)) # needs to be per datastore, so we pass that as a param
def encryptor(cls, ming_ds: ming.datastore.DataStore):
def encryptor(cls, ming_ds: ming.datastore.DataStore) -> ClientEncryption:
if not ming_ds.encryption:
raise MingEncryptionError(f'No encryption settings found for {ming_ds}')

Check warning on line 75 in ming/encryption.py

View check run for this annotation

Codecov / codecov/patch

ming/encryption.py#L75

Added line #L75 was not covered by tests
conn: MongoClient = ming_ds.conn
Expand Down
20 changes: 19 additions & 1 deletion ming/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
from ming.encryption import make_encryption_key
import base64
from contextlib import contextmanager
import os
import random


@contextmanager
def push_seed(seed):
rstate = random.getstate()
random.seed(seed)
try:
yield
finally:
random.setstate(rstate)


class EncryptionConfigHelper:

@staticmethod
def make_encryption_key(seed=__name__):
with push_seed(seed):
return base64.b64encode(os.urandom(96)).decode('ascii')

LOCAL_KEY_VAULT_NAMESPACE = 'encryption_test.coll_key_vault_test'
LOCAL_KEY = make_encryption_key('test local key')

Expand Down
3 changes: 1 addition & 2 deletions ming/tests/test_datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from ming import Session
from ming import mim
from ming import create_datastore, create_engine
from ming.encryption import make_encryption_key
from ming.exc import MingConfigError
from ming.datastore import Engine
from ming.tests import EncryptionConfigHelper
Expand Down Expand Up @@ -179,7 +178,7 @@ def test_configure_optional_params(self):
assert session.bind.db is not None

def test_configure_encryption(self):
encryption_key = make_encryption_key('foo')
encryption_key = EncryptionConfigHelper.make_encryption_key('foo')
ming.configure(**{
'ming.main.uri': 'mongodb://localhost:27017/test_db',
'ming.main.replicaSet': 'foobar',
Expand Down
5 changes: 3 additions & 2 deletions ming/tests/test_declarative.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
from ming.base import Cursor
from ming.datastore import create_datastore
from ming.declarative import Document
from ming.encryption import EncryptionConfig, DecryptedField, make_encryption_key
from ming.encryption import EncryptionConfig, DecryptedField
from ming.metadata import Field, Index
from ming import schema as S
from ming.odm.odmsession import ODMSession, ThreadLocalODMSession
from ming.session import Session
from ming.exc import MingException
from ming.tests import EncryptionConfigHelper


def mock_datastore():
Expand Down Expand Up @@ -182,7 +183,7 @@ def setUp(self):
encryption_config = EncryptionConfig({
'kms_providers': {
'local': {
'key': make_encryption_key(__name__),
'key': EncryptionConfigHelper.make_encryption_key(__name__),
},
},
'key_vault_namespace': 'encryption.__keyVault',
Expand Down

0 comments on commit 0bbf3c8

Please sign in to comment.