Skip to content

Commit

Permalink
secret: Add plugin type Secret
Browse files Browse the repository at this point in the history
  • Loading branch information
aghinsa authored Jun 3, 2020
1 parent b0e5a5d commit 7162ef6
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 2 deletions.
32 changes: 32 additions & 0 deletions dffml/secret/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import abc
from typing import Union

from ..df.base import BaseDataFlowObjectContext, BaseDataFlowObject
from ..util.entrypoint import base_entry_point


class BaseSecretContext(BaseDataFlowObjectContext):
def __init__(self, parent: "BaseSecret"):
self.parent = parent

@abc.abstractmethod
async def get(self, name: str) -> Union[bytes, None]:
"""
Get value mapped to name
"""

@abc.abstractmethod
async def set(self, name: str, value: bytes):
"""
Store value and map it to name
"""


@base_entry_point("dffml.secret", "secret")
class BaseSecret(BaseDataFlowObject):
"""
Base Class for secret storage
"""

def __call__(self) -> BaseSecretContext:
return self.CONTEXT(self)
47 changes: 47 additions & 0 deletions dffml/secret/ini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import warnings
from typing import Union, Any

from ..base import config
from ..record import Record
from ..util.entrypoint import entrypoint
from .base import BaseSecretContext, BaseSecret
from ..source.memory import MemorySourceContext
from ..source.ini import INISourceConfig, INISource


@config
class INISecretConfig:
filename: str
readwrite: bool = True
allowempty: bool = False


class INISecretContext(BaseSecretContext, MemorySourceContext):
async def get(self, name: str) -> Union[None, str]:
record = self.parent.mem.get("secrets", None)
if not record:
return None
return record.features().get(name, None)

async def set(self, name: str, value: Any):
record = Record("secrets", data={"features": {name: value}})
record.merge(self.parent.mem.get("secrets", Record("secrets")))
await self.update(record)


@entrypoint("ini")
class INISecret(BaseSecret, INISource):

CONTEXT = INISecretContext
CONFIG = INISecretConfig

def __init__(self, config: INISourceConfig):
warnings.warn(
"""
INSECURE This just writes secret to an ini file
"""
)
BaseSecret.__init__(self, config)
INISource.__init__(self, config)
4 changes: 2 additions & 2 deletions service/http/dffml_service_http/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,12 @@ async def multicomm_dataflow(self, config, request):
value = await request.text()
elif preprocess_mode == "bytes":
value = await request.read()
elif preprocess == "stream":
elif preprocess_mode == "stream":
value = request.content
else:
return web.json_response(
{
"error": f"preprocess tag must be one of {IO_MODES}, got {preprocess}"
"error": f"preprocess tag must be one of {IO_MODES}, got {preprocess_mode}"
},
status=HTTPStatus.NOT_FOUND,
)
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,7 @@
"dffml.db": ["sqlite = dffml.db.sqlite:SqliteDatabase"],
# Models
"dffml.model": ["slr = dffml.model.slr:SLRModel"],
# Secrets
"dffml.secret": ["ini = dffml.secret.ini:INISecret"],
},
)
Empty file added tests/secret/__init__.py
Empty file.
48 changes: 48 additions & 0 deletions tests/secret/test_ini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import io
import os
import pathlib
import inspect
import tempfile
import contextlib

from dffml.secret.ini import INISecret
from dffml.util.asynctestcase import AsyncTestCase


class TestINISecret(AsyncTestCase):
@classmethod
def setUpClass(cls):
cls.secret_file = tempfile.NamedTemporaryFile(
prefix="secret_", suffix=".ini"
)

@classmethod
def tearDownClass(cls):
cls.secret_file.close()

async def test_set_get(self):
async with INISecret(filename=self.secret_file.name) as secret_store:
async with secret_store() as secret_ctx:
await secret_ctx.set(name="foo", value="bar")
await secret_ctx.set(name="steins", value="gate")

contents = pathlib.Path(self.secret_file.name).read_text().strip()

self.assertIn(
"[secrets]", contents,
)
self.assertIn(
"steins = gate", contents,
)
self.assertIn(
"foo = bar", contents,
)

async with INISecret(filename=self.secret_file.name) as secret_store:
async with secret_store() as secret_ctx:
value = await secret_ctx.get(name="foo")
self.assertEqual(value, "bar")
value = await secret_ctx.get(name="steins")
self.assertEqual(value, "gate")
value = await secret_ctx.get(name="non_existent")
self.assertFalse(value)

0 comments on commit 7162ef6

Please sign in to comment.