Skip to main content

A randomized on-screen secret keyboard modal for Textual applications

Project description

terpinkb

terpinkb is a small Textual package for collecting PINs or short secrets with a randomized on-screen keyboard. It is designed for applications that want to avoid sending secret characters through the physical keyboard input path.

Threat Model

This component helps with keyboard-channel avoidance. Users choose characters by mouse or by non-secret keyboard navigation such as Tab, arrow keys, Enter, Backspace, Escape, Shift, Caps, and palette switching.

It does not make secret entry safe on a compromised host, compromised terminal emulator, compromised Python process, screen scraper, memory inspector, hostile shell, terminal escape injection path, or malware that observes mouse events or process memory.

Features

  • Native Textual ModalScreen.
  • Randomized character buttons.
  • Locale-aware default palettes with letters, numbers, punctuation, and symbols.
  • On-screen Shift, Caps, Space, Backspace, Clear, Shuffle, OK, and Cancel.
  • Optional coarse policy and strength/status display.
  • PinResult returns bytes and supports explicit in-place destruction.

Installation

pip install -e ".[dev]"

The preferred local workflow uses uv:

uv venv
uv pip install -e ".[dev]"
uv run pytest
uv run ruff check .
uv run mypy src

Usage

from textual.app import App, ComposeResult
from textual.widgets import Button

from terpinkb import RandomizedPinModal, PinResult


class DemoApp(App):
    def compose(self) -> ComposeResult:
        yield Button("Enter Secret", id="enter-secret")

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "enter-secret":
            self.push_screen(
                RandomizedPinModal(secret_length=6),
                self.handle_secret_result,
            )

    def handle_secret_result(self, result: PinResult | None) -> None:
        if result is None:
            self.notify("Secret entry canceled")
            return

        try:
            secret_bytes = result.consume()
            # Verify immediately, then drop application-side references.
        finally:
            result.destroy()

Demo

python examples/demo.py

The demo shows only masked receipt status. It never prints or displays the secret itself.

Testing

pytest
ruff check .
mypy src

Release

Build and validate distribution artifacts locally:

python -m build
twine check dist/*

Publishing is configured through GitHub Actions and PyPI Trusted Publishing. To publish a release, configure the akarasulu/terpinkb repository as a trusted publisher for the terpinkb PyPI project, then publish a GitHub release. The release workflow will test, build, validate, and upload the package to PyPI.

Policy And Strength

SecretPolicy can enforce simple metadata-based requirements such as minimum length or requiring a digit. These rules are optional and disabled by default. Strength/status text is deliberately coarse and advisory. It is not a cryptographic guarantee and is less useful for short fixed PIN workflows or HSM PINs with device retry counters.

HSM PINs

terpinkb may be used to collect an HSM, smart-card, token, or PKCS#11 PIN when the embedding application can pass the returned bytes directly to its HSM library or middleware. Do not pass the PIN in command-line arguments, environment variables, config files, logs, or external prompts. Respect device retry counters and lockout behavior, and let the embedding application handle vendor-specific PIN formats.

Security Caveats

Python cannot guarantee complete memory secrecy. PinResult.destroy() overwrites the package-owned bytearray, but immutable bytes copies returned to the caller cannot be wiped by this package. Verify immediately and drop references as soon as possible.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

terpinkb-0.1.0.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

terpinkb-0.1.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file terpinkb-0.1.0.tar.gz.

File metadata

  • Download URL: terpinkb-0.1.0.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for terpinkb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c33620160be399144f281b1322e90c1f1e532e5b937c50486a24496a8ec04c86
MD5 253d0c968df01fc5b074b726ea3ad55d
BLAKE2b-256 07c7d79a339a48df96a2a789daa3d0fb6376927ba14befcb2bc3f99e7544deb4

See more details on using hashes here.

Provenance

The following attestation bundles were made for terpinkb-0.1.0.tar.gz:

Publisher: publish.yml on akarasulu/terpinkb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file terpinkb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: terpinkb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for terpinkb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a7b40bf86adcf166e15992c0e566fd69ac82c206156000edc8d3b5e6676a04fe
MD5 93b564e3e86bea0a39513e563b020bbe
BLAKE2b-256 f5a7e3b006678ca5744ce54e7cfba573465be47a73d7b9ebbb798902b1645277

See more details on using hashes here.

Provenance

The following attestation bundles were made for terpinkb-0.1.0-py3-none-any.whl:

Publisher: publish.yml on akarasulu/terpinkb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page