"""Securesend plugin main class. One-view expiring links for handing someone a credential, encrypted in the browser """ import json import logging from pathlib import Path from typing import List, Dict, Optional, Type from flask import Flask, Blueprint from shopdb.plugins.base import BasePlugin, PluginMeta from .models import SecureSecret from .api import securesend_bp logger = logging.getLogger(__name__) class SecuresendPlugin(BasePlugin): """Securesend plugin. One-view expiring links for handing someone a credential, encrypted in the browser. The key travels in the URL fragment and never reaches the server, so what is stored here is ciphertext nobody on this side can read. """ def __init__(self): manifest_path = Path(__file__).parent / 'manifest.json' with open(manifest_path) as f: self._manifest = json.load(f) @property def meta(self) -> PluginMeta: return PluginMeta( name=self._manifest['name'], version=self._manifest['version'], description=self._manifest['description'], author=self._manifest.get('author', ''), dependencies=self._manifest.get('dependencies', []), core_version=self._manifest.get('core_version', '>=0.1.0'), api_prefix=self._manifest.get('api_prefix'), ) def get_blueprint(self) -> Optional[Blueprint]: return securesend_bp def get_models(self) -> List[Type]: return [SecureSecret] def get_permissions(self) -> List: """One permission, on CREATION only. There is deliberately no read permission: the recipient of a secret usually has no account here, and the unguessable token is what authorises the read. Adding a permission to that side would make the feature useless for the case it exists for - handing a credential to somebody while you are on a call with them. No delete permission either. A secret is spent by being read or by expiring, and both remove the row; a hand-delete route would only add a way to destroy the audit trail of a secret that had not been read yet. """ return [ ('securesend.create', 'Create shared secret links', 'securesend'), ] def init_app(self, app: Flask, db_instance) -> None: logger.info(f'Securesend plugin initialized (v{self.meta.version})') def on_install(self, app: Flask) -> None: # NO ASSET TYPE. The scaffold assumes a plugin extends Asset, and this # one does not: a shared credential is a short-lived event, not a thing # the site owns and inventories. logger.info('Securesend plugin installed')