Python code protection
Project description
Stonefish
Industry-grade Python code protection.
Quickstart
Protecting Python packages
If you have a Python package that you'd like to build with Stonefish, make
sure it follows PEP 517 and contains
at least a minimal pyproject.toml
. There, simply replace the your build system
(e.g., setuptools
) with stonefish
:
[build-system]
# requires = ["setuptools"]
# build-backend = "setuptools.build_meta"
requires = ["stonefish"]
build-backend = "stonefish.build_meta"
# ...
# more project metadata if you follow PEP 621
# <https://peps.python.org/pep-0621/>
# (recommended)
# ...
Done! Your project builds are now protected with Stonefish. Try it out with
pip install .
or
(pip install build)
python -m build . --wheel
Protecting standalone Python scripts
If you'd like to project just a single Python file, you
can use the stonefish
command-line utility, e.g.,
stonefish /path/to/file.py
How Stonefish protects your code
Python packages ship their code to all users, and there are different ways for every user to retrieve it. Unless built with Stonefish. Some examples:
Just opening the source files
After installation, users will find the package code in, e.g.,
~/.local/lib/python3.11/site-packages/numpy
. (The path is different for
different operation systems.)
When building with Stonefish, though, a source code like
├── pyproject.toml
└── stonefish_example
└── __init__.py
is installed as
├── _agg
│ ├── __init__.dat
│ ├── __init__.py
│ └── __pycache__
│ └── __init__.cpython-311.pyc
├── __init__.py
└── __pycache__
└── __init__.cpython-311.pyc
where all program logic is encrypted in the binary __init__.dat
. The actual
source code remains protected.
inspect — Inspect live objects
import stonefish_example
import inspect
print(inspect.getsource(stonefish_example.solve))
Without Stonefish | With Stonefish |
|
|
Dill
import stonefish_example
from dill.source import getsource
print(getsource(stonefish_example.solve))
Without Stonefish | With Stonefish |
|
|
IPython's ??
In [1]: import stonefish_example
In [2]: stonefish_example.solve??
Without Stonefish | With Stonefish |
|
|
dis — Disassembler for Python bytecode
import stonefish_example
import dis
dis.dis(stonefish_example.solve)
Without Stonefish | With Stonefish |
|
|
xdis
import stonefish_example
import xdis.std as dis
dis.dis(stonefish_example.solve)
Without Stonefish | With Stonefish |
|
|
decompyle3, uncompyle6 etc.
Those tools are meant to recreated Python code from .pyc
files.
Since Stonefish moves the actual code into an encrypted
decompyle3 ~/path/to/__init__.cpython-38.pyc
Without Stonefish | With Stonefish |
|
|
Limitations
-
Stonefish renames class/function names, so you cannot rely on the
__name__
attribute in your code. -
Users must add
*.dat
files to their package data, e.g.,[tool.setuptools.package-data] "*" = ["*.dat"]
in
pyproject.toml
. This is because the encrypted code must be shipped with the package. -
Local imports must be relative, i.e.,
from . import x
instead ofimport x
ifx/
/x.py
is an internal folder or directory. This is recommended anyway. -
Stonefish will put all data files in a flat directory structure. That's why it cannot yet handle files that are read from two different Python paths, e.g.,
./data.dat ./a.py Path(__file__).parent / "data.dat" ./b/b.py Path(__file__).parent / .. / "data.dat"
-
Stonefish discards private (underscored) names from the API. If you want your users to use these variables or functions, you'll have to rename them.
-
Stonefish cannot yet handle relative
*
imports, e.g.,from .utils import *
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 Distributions
Built Distribution
Hashes for stonefish-0.3.26-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d1763b08e4ac094b9c92e15dd5bd7723d7234460197af1ecfe05ac41ad1c8258 |
|
MD5 | 33e70254560f910b634f9caf19793e92 |
|
BLAKE2b-256 | 089cff874d7240e1af75d0fad6571f38cfcd2c30015116d9d18db749dc70a7ad |