mirror of https://github.com/dethos/inlinehashes
Add other types of output for the results
This commit is contained in:
parent
9bf236b60d
commit
20fc87f5cd
15
README.rst
15
README.rst
|
@ -43,18 +43,19 @@ This is the available functionality:
|
|||
|
||||
.. code::
|
||||
|
||||
usage: inlinehashes [-h] [-a {sha256,sha384,sha512}] [-f] [-t {all,scripts,styles}] source
|
||||
usage: inlinehashes [-h] [-a {sha256,sha384,sha512}] [-o {table,json,plain}] [-t {all,script-src,style-src}] source
|
||||
|
||||
positional arguments:
|
||||
positional arguments:
|
||||
source URL or local HTML file to check
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-a {sha256,sha384,sha512}, --alg {sha256,sha384,sha512}
|
||||
Hash algorithm to use (default: sha256)
|
||||
-f, --full Include full content in the output
|
||||
-t {all,scripts,styles}, --target {all,scripts,styles}
|
||||
Target inline content to look for
|
||||
Hash algorithm to use (default: sha256)
|
||||
-o {table,json,plain}, --output {table,json,plain}
|
||||
Format used to write the output (default: table)
|
||||
-t {all,script-src,style-src}, --target {all,script-src,style-src}
|
||||
Target inline content to look for (default: all)
|
||||
|
||||
Here is an example of the output:
|
||||
|
||||
|
|
|
@ -10,17 +10,19 @@ from typing import List
|
|||
from urllib.error import URLError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.syntax import Syntax
|
||||
from rich.table import Table
|
||||
|
||||
import inlinehashes
|
||||
|
||||
|
||||
def build_output(
|
||||
inlines: List[inlinehashes.lib.Inline], alg: str, full: bool = False
|
||||
) -> str:
|
||||
def build_json_output(inlines: List[inlinehashes.lib.Inline], alg: str) -> Syntax:
|
||||
"""Build a JSON output from a list of Inline objects."""
|
||||
snippet = "content" if full else "short_content"
|
||||
out = [
|
||||
{
|
||||
"content": getattr(i, snippet),
|
||||
"content": i.short_content,
|
||||
"hash": getattr(i, alg),
|
||||
"directive": i.directive,
|
||||
"line": i.line,
|
||||
|
@ -28,7 +30,32 @@ def build_output(
|
|||
}
|
||||
for i in inlines
|
||||
]
|
||||
return json.dumps(out, indent=2)
|
||||
return Syntax(json.dumps(out, indent=2), "JSON", theme="ansi_dark")
|
||||
|
||||
|
||||
def build_plain_output(inlines: List[inlinehashes.lib.Inline], alg: str) -> str:
|
||||
"""Build a simple output of an inline per line."""
|
||||
return "\n".join(
|
||||
[
|
||||
f"[magenta]{i.directive}[/magenta] [cyan]{i.line}[/cyan] "
|
||||
f"[green]{i.position}[/green] [default]{getattr(i, alg)}[/default]"
|
||||
for i in inlines
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def build_table_output(inlines: List[inlinehashes.lib.Inline], alg: str) -> Table:
|
||||
"""Build a table to output the inlines in a nicer way."""
|
||||
table = Table(box=box.HORIZONTALS)
|
||||
table.add_column("Directive", style="magenta")
|
||||
table.add_column("Line", justify="right", style="cyan")
|
||||
table.add_column("Position", justify="right", style="green")
|
||||
table.add_column("Hash")
|
||||
|
||||
for i in inlines:
|
||||
table.add_row(i.directive, str(i.line), str(i.position), getattr(i, alg))
|
||||
|
||||
return table
|
||||
|
||||
|
||||
def run_cli() -> None:
|
||||
|
@ -43,21 +70,24 @@ def run_cli() -> None:
|
|||
choices=["sha256", "sha384", "sha512"],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--full",
|
||||
help="Include full content in the output",
|
||||
action="store_true",
|
||||
"-o",
|
||||
"--output",
|
||||
help="Format used to write the output (default: table)",
|
||||
default="table",
|
||||
choices=["table", "json", "plain"],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--target",
|
||||
help="Target inline content to look for",
|
||||
help="Target inline content to look for (default: all)",
|
||||
default="all",
|
||||
choices=["all", "script-src", "style-src"],
|
||||
)
|
||||
args = parser.parse_args()
|
||||
path = args.source
|
||||
target = args.target
|
||||
output_format = args.output
|
||||
console = Console()
|
||||
|
||||
try:
|
||||
if path.startswith("http://") or path.startswith("https://"):
|
||||
|
@ -71,13 +101,19 @@ def run_cli() -> None:
|
|||
with open(path, "r") as f:
|
||||
content = f.read()
|
||||
except (URLError, OSError) as error:
|
||||
print(error)
|
||||
print(f"Failed to get source: {path}")
|
||||
console.print(error)
|
||||
console.print(f"Failed to get source: {path}")
|
||||
exit(1)
|
||||
|
||||
inlines = inlinehashes.parse(content, target)
|
||||
out = build_output(inlines, args.alg, bool(args.full))
|
||||
print(out)
|
||||
if output_format == "json":
|
||||
out = build_json_output(inlines, args.alg)
|
||||
elif output_format == "plain":
|
||||
out = build_plain_output(inlines, args.alg)
|
||||
else:
|
||||
out = build_table_output(inlines, args.alg)
|
||||
|
||||
console.print(out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -111,6 +111,43 @@ files = [
|
|||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "2.1.0"
|
||||
description = "Python port of markdown-it. Markdown parsing, done right!"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "markdown-it-py-2.1.0.tar.gz", hash = "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da"},
|
||||
{file = "markdown_it_py-2.1.0-py3-none-any.whl", hash = "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mdurl = ">=0.1,<1.0"
|
||||
|
||||
[package.extras]
|
||||
benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"]
|
||||
code-style = ["pre-commit (==2.6)"]
|
||||
compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"]
|
||||
linkify = ["linkify-it-py (>=1.0,<2.0)"]
|
||||
plugins = ["mdit-py-plugins"]
|
||||
profiling = ["gprof2dot"]
|
||||
rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
|
||||
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
description = "Markdown URL utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "0.991"
|
||||
|
@ -229,6 +266,21 @@ files = [
|
|||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.14.0"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
|
||||
{file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.2.1"
|
||||
|
@ -251,6 +303,25 @@ pluggy = ">=0.12,<2.0"
|
|||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.2.0"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "rich-13.2.0-py3-none-any.whl", hash = "sha256:7c963f0d03819221e9ac561e1bc866e3f95a02248c1234daa48954e6d381c003"},
|
||||
{file = "rich-13.2.0.tar.gz", hash = "sha256:f1a00cdd3eebf999a15d85ec498bfe0b1a77efe9b34f645768a54132ef444ac5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
markdown-it-py = ">=2.1.0,<3.0.0"
|
||||
pygments = ">=2.6.0,<3.0.0"
|
||||
|
||||
[package.extras]
|
||||
jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.229"
|
||||
|
@ -304,4 +375,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "81f9d3306e76f9f7c39291bd7972216d852f39aba794b43afe2b9a0d4a7a2829"
|
||||
content-hash = "ded8c6b34befe59dd43fd80d0a9027a54c17a97bc734445fb5978235f17cc0ca"
|
||||
|
|
|
@ -21,6 +21,7 @@ classifiers = [
|
|||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
beautifulsoup4 = "^4.10.0"
|
||||
rich = "^13.2.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^7.2.1"
|
||||
|
|
Loading…
Reference in New Issue