Skip to content

Commit

Permalink
feat: plugin support (#56)
Browse files Browse the repository at this point in the history
API surface exposed is equivalent to the Rust API, including plugin
callbacks (duck-typed at runtime, exposed in type stubs as a
`pyrage.plugin.Callbacks` protocol, all of which's methods are
required to be implemented at runtime, otherwise `AttributeError` is
thrown).

Non-`Clone`ability of plugin instances is resolved by putting them
behind an `Arc`. Perhaps a more elegant solution could be produced
later, by someone with more knowledge of PyO3 internals.

This was tested with rage's example `age-unencrypted-plugin` which
happens to exercise the `display_message` callback, and additionally
with `age-plugin-tpm` to exercise actual encryption functionality.

Typing stubs are amended to cover the new API surface. Conformance to
type-stubs was checked by writing a short Python program exercising
the functionality and type-checking it using `mypy` with the type
stubs installed.
  • Loading branch information
vikanezrimaya authored Apr 13, 2024
1 parent e92ecde commit eac37b3
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 15 deletions.
174 changes: 165 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ crate-type = ["cdylib"]

[dependencies]
age-core = "0.10"
age = { version = "0.10", features = ["ssh"] }
age = { version = "0.10", features = ["ssh", "plugin"] }
pyo3 = { version = "0.21", features = [
"extension-module",
"abi3",
Expand Down
6 changes: 3 additions & 3 deletions pyrage-stubs/pyrage-stubs/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import Sequence, Union

from pyrage import ssh, x25519, passphrase
from pyrage import ssh, x25519, passphrase, plugin

Identity = Union[ssh.Identity, x25519.Identity]
Recipient = Union[ssh.Recipient, x25519.Recipient]
Identity = Union[ssh.Identity, x25519.Identity, plugin.IdentityPluginV1]
Recipient = Union[ssh.Recipient, x25519.Recipient, plugin.RecipientPluginV1]


class RecipientError(Exception):
Expand Down
48 changes: 48 additions & 0 deletions pyrage-stubs/pyrage-stubs/plugin.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations
from typing import Sequence, Self, Optional, Protocol


class Callbacks(Protocol):
def display_message(self, message: str) -> None:
...

def confirm(self, message: str, yes_string: str, no_string: Optional[str]) -> Optional[bool]:
...

def request_public_string(self, description: str) -> Optional[str]:
...

def request_passphrase(self, description: str) -> Optional[str]:
...


class Recipient:
@classmethod
def from_str(cls, v: str) -> Recipient:
...

def plugin(self) -> str:
...


class RecipientPluginV1:
def __new__(cls, plugin_name: str, recipients: Sequence[Recipient], identities: Sequence[Identity], callbacks: Callbacks) -> Self:
...


class Identity:
@classmethod
def from_str(cls, v: str) -> Identity:
...

@classmethod
def default_for_plugin(cls, plugin: str) -> Identity:
...

def plugin(self) -> str:
...


class IdentityPluginV1:
def __new__(cls, plugin_name: str, identities: Sequence[Identity], callbacks: Callbacks) -> Self:
...
Loading

0 comments on commit eac37b3

Please sign in to comment.