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.
PinResultreturns 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c33620160be399144f281b1322e90c1f1e532e5b937c50486a24496a8ec04c86
|
|
| MD5 |
253d0c968df01fc5b074b726ea3ad55d
|
|
| BLAKE2b-256 |
07c7d79a339a48df96a2a789daa3d0fb6376927ba14befcb2bc3f99e7544deb4
|
Provenance
The following attestation bundles were made for terpinkb-0.1.0.tar.gz:
Publisher:
publish.yml on akarasulu/terpinkb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
terpinkb-0.1.0.tar.gz -
Subject digest:
c33620160be399144f281b1322e90c1f1e532e5b937c50486a24496a8ec04c86 - Sigstore transparency entry: 1611007958
- Sigstore integration time:
-
Permalink:
akarasulu/terpinkb@2da850a5d47f22512ce0363f7942cbfcd17462b7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/akarasulu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2da850a5d47f22512ce0363f7942cbfcd17462b7 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7b40bf86adcf166e15992c0e566fd69ac82c206156000edc8d3b5e6676a04fe
|
|
| MD5 |
93b564e3e86bea0a39513e563b020bbe
|
|
| BLAKE2b-256 |
f5a7e3b006678ca5744ce54e7cfba573465be47a73d7b9ebbb798902b1645277
|
Provenance
The following attestation bundles were made for terpinkb-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on akarasulu/terpinkb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
terpinkb-0.1.0-py3-none-any.whl -
Subject digest:
a7b40bf86adcf166e15992c0e566fd69ac82c206156000edc8d3b5e6676a04fe - Sigstore transparency entry: 1611008059
- Sigstore integration time:
-
Permalink:
akarasulu/terpinkb@2da850a5d47f22512ce0363f7942cbfcd17462b7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/akarasulu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2da850a5d47f22512ce0363f7942cbfcd17462b7 -
Trigger Event:
release
-
Statement type: