add androzoo support
This commit is contained in:
parent
43eef100f1
commit
01abb1879d
6 changed files with 465 additions and 206 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
__pycache__
|
||||
|
|
@ -1,214 +1,84 @@
|
|||
import zipfile
|
||||
import io
|
||||
|
||||
from dataclasses import dataclass, asdict
|
||||
from enum import IntEnum
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
from getpass import getpass
|
||||
|
||||
import androguard.core.dex # type: ignore
|
||||
from androguard.core.dex import DEX # type: ignore
|
||||
|
||||
# loguru -> logging framework used by androgard
|
||||
from loguru import logger # type: ignore
|
||||
|
||||
from .platform_classes import (
|
||||
PLATFORM_32_CLASSES,
|
||||
SDK_32_CLASSES,
|
||||
PLATFORM_33_CLASSES,
|
||||
SDK_33_CLASSES,
|
||||
PLATFORM_34_CLASSES,
|
||||
SDK_34_CLASSES,
|
||||
)
|
||||
|
||||
# Remove Androguard logs
|
||||
logger.remove()
|
||||
|
||||
|
||||
# Patch Androguard
|
||||
class PatchedDomapiApiFlag(IntEnum):
|
||||
NONE = 0
|
||||
CORE_PLATFORM_API = 1
|
||||
TEST_API = 2
|
||||
UNKN_3 = 3
|
||||
UNKN_4 = 4
|
||||
UNKN_5 = 5
|
||||
UNKN_6 = 6
|
||||
UNKN_7 = 7
|
||||
UNKN_8 = 8
|
||||
UNKN_9 = 9
|
||||
INKN_10 = 10
|
||||
|
||||
|
||||
class PatchedRestrictionApiFlag(IntEnum):
|
||||
WHITELIST = 0
|
||||
GREYLIST = 1
|
||||
BLACKLIST = 2
|
||||
GREYLIST_MAX_O = 3
|
||||
GREYLIST_MAX_P = 4
|
||||
GREYLIST_MAX_Q = 5
|
||||
GREYLIST_MAX_R = 6
|
||||
GREYLIST_MAX_7 = 7
|
||||
GREYLIST_MAX_8 = 8
|
||||
GREYLIST_MAX_9 = 9
|
||||
GREYLIST_MAX_10 = 10
|
||||
|
||||
|
||||
androguard.core.dex.HiddenApiClassDataItem.DomapiApiFlag = PatchedDomapiApiFlag
|
||||
androguard.core.dex.HiddenApiClassDataItem.RestrictionApiFlag = (
|
||||
PatchedRestrictionApiFlag
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Entry:
|
||||
# sha256: str
|
||||
nb_duplicate_classes: int
|
||||
nb_platform_32_classes: int
|
||||
nb_platform_non_sdk_32_classes: int
|
||||
nb_sdk_32_classes: int
|
||||
nb_platform_33_classes: int
|
||||
nb_platform_non_sdk_33_classes: int
|
||||
nb_sdk_33_classes: int
|
||||
nb_platform_34_classes: int
|
||||
nb_platform_non_sdk_34_classes: int
|
||||
nb_sdk_34_classes: int
|
||||
has_classes0_dex: bool
|
||||
has_classes1_dex: bool
|
||||
has_classes0X_dex: bool
|
||||
has_classes_dex_over_10: bool
|
||||
has_non_numeric_classes_dex: bool
|
||||
has_non_consecutive_classes_dex: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlatformClassesData:
|
||||
nb_duplicate_classes: int
|
||||
nb_platform_32_classes: int
|
||||
nb_platform_non_sdk_32_classes: int
|
||||
nb_sdk_32_classes: int
|
||||
nb_platform_33_classes: int
|
||||
nb_platform_non_sdk_33_classes: int
|
||||
nb_sdk_33_classes: int
|
||||
nb_platform_34_classes: int
|
||||
nb_platform_non_sdk_34_classes: int
|
||||
nb_sdk_34_classes: int
|
||||
|
||||
|
||||
def scan_classes(apk: zipfile.ZipFile, file_names: set[str]) -> PlatformClassesData:
|
||||
all_classes = set()
|
||||
duplicated_classes = set()
|
||||
platform_32_classes = set()
|
||||
sdk_32_classes = set()
|
||||
platform_non_sdk_32_classes = set()
|
||||
platform_33_classes = set()
|
||||
sdk_33_classes = set()
|
||||
platform_non_sdk_33_classes = set()
|
||||
platform_34_classes = set()
|
||||
sdk_34_classes = set()
|
||||
platform_non_sdk_34_classes = set()
|
||||
for name in file_names:
|
||||
with apk.open(name) as dex_f:
|
||||
dex = DEX(dex_f.read())
|
||||
for clazz in map(lambda c: c.name, dex.get_classes()):
|
||||
if clazz in all_classes:
|
||||
duplicated_classes.add(clazz)
|
||||
if clazz in PLATFORM_32_CLASSES:
|
||||
platform_32_classes.add(clazz)
|
||||
if clazz in SDK_32_CLASSES:
|
||||
sdk_32_classes.add(clazz)
|
||||
if clazz in PLATFORM_32_CLASSES and clazz not in SDK_32_CLASSES:
|
||||
platform_non_sdk_32_classes.add(clazz)
|
||||
if clazz in PLATFORM_33_CLASSES:
|
||||
platform_33_classes.add(clazz)
|
||||
if clazz in SDK_33_CLASSES:
|
||||
sdk_33_classes.add(clazz)
|
||||
if clazz in PLATFORM_33_CLASSES and clazz not in SDK_33_CLASSES:
|
||||
platform_non_sdk_33_classes.add(clazz)
|
||||
if clazz in PLATFORM_34_CLASSES:
|
||||
platform_34_classes.add(clazz)
|
||||
if clazz in SDK_34_CLASSES:
|
||||
sdk_34_classes.add(clazz)
|
||||
if clazz in PLATFORM_34_CLASSES and clazz not in SDK_34_CLASSES:
|
||||
platform_non_sdk_34_classes.add(clazz)
|
||||
all_classes.add(clazz)
|
||||
return PlatformClassesData(
|
||||
nb_duplicate_classes=len(duplicated_classes),
|
||||
nb_platform_32_classes=len(platform_32_classes),
|
||||
nb_platform_non_sdk_32_classes=len(platform_non_sdk_32_classes),
|
||||
nb_sdk_32_classes=len(sdk_32_classes),
|
||||
nb_platform_33_classes=len(platform_33_classes),
|
||||
nb_platform_non_sdk_33_classes=len(platform_non_sdk_33_classes),
|
||||
nb_sdk_33_classes=len(sdk_33_classes),
|
||||
nb_platform_34_classes=len(platform_34_classes),
|
||||
nb_platform_non_sdk_34_classes=len(platform_non_sdk_34_classes),
|
||||
nb_sdk_34_classes=len(sdk_34_classes),
|
||||
)
|
||||
|
||||
|
||||
def analyze(apk: zipfile.ZipFile) -> Entry:
|
||||
classes_dex = set(
|
||||
filter(
|
||||
lambda name: name.startswith("classes") and name.endswith(".dex"),
|
||||
apk.namelist(),
|
||||
)
|
||||
)
|
||||
dex_numbers = list(
|
||||
map(
|
||||
int,
|
||||
filter(
|
||||
lambda string: string not in ("", "1")
|
||||
and string.isnumeric()
|
||||
and string[0] != "0",
|
||||
map(
|
||||
lambda name: name.removeprefix("classes").removesuffix(".dex"),
|
||||
classes_dex,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
dex_numbers.sort()
|
||||
|
||||
has_non_numeric_classes_dex = False
|
||||
for name in classes_dex:
|
||||
if name == "classes.dex":
|
||||
continue
|
||||
if not name.removeprefix("classes").removesuffix(".dex").isnumeric():
|
||||
has_non_numeric_classes_dex = True
|
||||
|
||||
has_non_consecutive_classes_dex = False
|
||||
if "classes.dex" in classes_dex and dex_numbers:
|
||||
has_non_consecutive_classes_dex = True
|
||||
last_number = 1
|
||||
for i in range(len(dex_numbers)):
|
||||
if dex_numbers[i] == 0 or dex_numbers[i] == 1:
|
||||
continue
|
||||
# the list is sorted
|
||||
if dex_numbers[i] != last_number + 1:
|
||||
has_non_consecutive_classes_dex = True
|
||||
break
|
||||
|
||||
platform_classes_data = scan_classes(apk, classes_dex)
|
||||
|
||||
return Entry(
|
||||
**asdict(platform_classes_data),
|
||||
has_classes0_dex="classes0.dex" in classes_dex,
|
||||
has_classes1_dex="classes1.dex" in classes_dex,
|
||||
has_classes0X_dex=any(
|
||||
map(lambda name: name.startswith("classes0"), classes_dex)
|
||||
),
|
||||
has_classes_dex_over_10=any(map(lambda x: x >= 10, dex_numbers)),
|
||||
has_non_numeric_classes_dex=has_non_numeric_classes_dex,
|
||||
has_non_consecutive_classes_dex=has_non_consecutive_classes_dex,
|
||||
)
|
||||
from .androzoo import download_apk
|
||||
from .analysis import analyze
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
with open(sys.argv[1], "rb") as file:
|
||||
apk = file.read()
|
||||
parser = ArgumentParser(
|
||||
prog="Android Class Shadowing Scanner",
|
||||
description="Scan application for patern that could be reveling of class shadowing obfuscation",
|
||||
)
|
||||
apk_parser = parser.add_mutually_exclusive_group(required=True)
|
||||
apk_parser.add_argument(
|
||||
"--sha256", help="The sha256 hash of the APK to download", type=str
|
||||
)
|
||||
apk_parser.add_argument("--apk", help="The APK to use", type=Path)
|
||||
key_parser = parser.add_mutually_exclusive_group(required=False)
|
||||
key_parser.add_argument(
|
||||
"--api-key-file",
|
||||
help="The path to a file containing the Androzoo API key",
|
||||
type=Path,
|
||||
)
|
||||
key_parser.add_argument(
|
||||
"--api-key", help="The Androzoo API key (Usage NOT recommanded)", type=str
|
||||
)
|
||||
SECRET_STORAGE_IMPORTED = False
|
||||
try:
|
||||
import secretstorage
|
||||
|
||||
with zipfile.ZipFile(io.BytesIO(apk)) as apk:
|
||||
entry = analyze(apk)
|
||||
SECRET_STORAGE_IMPORTED = True
|
||||
|
||||
pprint.pprint(entry)
|
||||
key_parser.add_argument(
|
||||
"--api-key-keyring-id",
|
||||
help="The ID of the Androzoo API key in the secret service storage",
|
||||
type=str,
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.apk:
|
||||
with args.apk.open("rb") as file:
|
||||
with zipfile.ZipFile(file) as apk:
|
||||
entry = analyze(apk)
|
||||
pprint.pprint(entry)
|
||||
exit()
|
||||
|
||||
sha256s = []
|
||||
if args.sha256:
|
||||
sha256s.append(args.sha256)
|
||||
|
||||
api_key = ""
|
||||
if args.api_key:
|
||||
api_key = args.api_key
|
||||
if args.api_key_file:
|
||||
with args.api_key_file.open("r") as file:
|
||||
api_key = file.read().strip()
|
||||
if SECRET_STORAGE_IMPORTED and not api_key:
|
||||
if args.api_key_keyring_id:
|
||||
key_id = args.api_key_keyring_id
|
||||
else:
|
||||
key_id = "androzoo"
|
||||
try:
|
||||
with secretstorage.dbus_init() as connection:
|
||||
collection = secretstorage.get_default_collection(connection)
|
||||
item = next(collection.search_items({"Title": key_id}))
|
||||
item.unlock()
|
||||
api_key = item.get_secret().decode("utf-8").strip()
|
||||
except:
|
||||
pass
|
||||
if not api_key:
|
||||
api_key = getpass(prompt="Androzoo API key: ").strip()
|
||||
|
||||
for sha256 in sha256s:
|
||||
with zipfile.ZipFile(io.BytesIO(download_apk(sha256, api_key))) as apk:
|
||||
entry = analyze(apk, sha256)
|
||||
pprint.pprint(entry)
|
||||
|
|
|
|||
202
android_class_shadowing_scanner/analysis.py
Normal file
202
android_class_shadowing_scanner/analysis.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
import zipfile
|
||||
import io
|
||||
|
||||
from dataclasses import dataclass, asdict
|
||||
from enum import IntEnum
|
||||
|
||||
import androguard.core.dex # type: ignore
|
||||
from androguard.core.dex import DEX # type: ignore
|
||||
|
||||
# loguru -> logging framework used by androgard
|
||||
from loguru import logger # type: ignore
|
||||
|
||||
from .platform_classes import (
|
||||
PLATFORM_32_CLASSES,
|
||||
SDK_32_CLASSES,
|
||||
PLATFORM_33_CLASSES,
|
||||
SDK_33_CLASSES,
|
||||
PLATFORM_34_CLASSES,
|
||||
SDK_34_CLASSES,
|
||||
)
|
||||
|
||||
# Remove Androguard logs
|
||||
logger.remove()
|
||||
|
||||
|
||||
# Patch Androguard
|
||||
class PatchedDomapiApiFlag(IntEnum):
|
||||
NONE = 0
|
||||
CORE_PLATFORM_API = 1
|
||||
TEST_API = 2
|
||||
UNKN_3 = 3
|
||||
UNKN_4 = 4
|
||||
UNKN_5 = 5
|
||||
UNKN_6 = 6
|
||||
UNKN_7 = 7
|
||||
UNKN_8 = 8
|
||||
UNKN_9 = 9
|
||||
INKN_10 = 10
|
||||
|
||||
|
||||
class PatchedRestrictionApiFlag(IntEnum):
|
||||
WHITELIST = 0
|
||||
GREYLIST = 1
|
||||
BLACKLIST = 2
|
||||
GREYLIST_MAX_O = 3
|
||||
GREYLIST_MAX_P = 4
|
||||
GREYLIST_MAX_Q = 5
|
||||
GREYLIST_MAX_R = 6
|
||||
GREYLIST_MAX_7 = 7
|
||||
GREYLIST_MAX_8 = 8
|
||||
GREYLIST_MAX_9 = 9
|
||||
GREYLIST_MAX_10 = 10
|
||||
|
||||
|
||||
androguard.core.dex.HiddenApiClassDataItem.DomapiApiFlag = PatchedDomapiApiFlag
|
||||
androguard.core.dex.HiddenApiClassDataItem.RestrictionApiFlag = (
|
||||
PatchedRestrictionApiFlag
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApkData:
|
||||
sha256: str
|
||||
nb_duplicate_classes: int
|
||||
nb_platform_32_classes: int
|
||||
nb_platform_non_sdk_32_classes: int
|
||||
nb_sdk_32_classes: int
|
||||
nb_platform_33_classes: int
|
||||
nb_platform_non_sdk_33_classes: int
|
||||
nb_sdk_33_classes: int
|
||||
nb_platform_34_classes: int
|
||||
nb_platform_non_sdk_34_classes: int
|
||||
nb_sdk_34_classes: int
|
||||
has_classes0_dex: bool
|
||||
has_classes1_dex: bool
|
||||
has_classes0X_dex: bool
|
||||
has_classes_dex_over_10: bool
|
||||
has_non_numeric_classes_dex: bool
|
||||
has_non_consecutive_classes_dex: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlatformClassesData:
|
||||
nb_duplicate_classes: int
|
||||
nb_platform_32_classes: int
|
||||
nb_platform_non_sdk_32_classes: int
|
||||
nb_sdk_32_classes: int
|
||||
nb_platform_33_classes: int
|
||||
nb_platform_non_sdk_33_classes: int
|
||||
nb_sdk_33_classes: int
|
||||
nb_platform_34_classes: int
|
||||
nb_platform_non_sdk_34_classes: int
|
||||
nb_sdk_34_classes: int
|
||||
|
||||
|
||||
def scan_classes(apk: zipfile.ZipFile, file_names: set[str]) -> PlatformClassesData:
|
||||
all_classes = set()
|
||||
duplicated_classes = set()
|
||||
platform_32_classes = set()
|
||||
sdk_32_classes = set()
|
||||
platform_non_sdk_32_classes = set()
|
||||
platform_33_classes = set()
|
||||
sdk_33_classes = set()
|
||||
platform_non_sdk_33_classes = set()
|
||||
platform_34_classes = set()
|
||||
sdk_34_classes = set()
|
||||
platform_non_sdk_34_classes = set()
|
||||
for name in file_names:
|
||||
with apk.open(name) as dex_f:
|
||||
dex = DEX(dex_f.read())
|
||||
for clazz in map(lambda c: c.name, dex.get_classes()):
|
||||
if clazz in all_classes:
|
||||
duplicated_classes.add(clazz)
|
||||
if clazz in PLATFORM_32_CLASSES:
|
||||
platform_32_classes.add(clazz)
|
||||
if clazz in SDK_32_CLASSES:
|
||||
sdk_32_classes.add(clazz)
|
||||
if clazz in PLATFORM_32_CLASSES and clazz not in SDK_32_CLASSES:
|
||||
platform_non_sdk_32_classes.add(clazz)
|
||||
if clazz in PLATFORM_33_CLASSES:
|
||||
platform_33_classes.add(clazz)
|
||||
if clazz in SDK_33_CLASSES:
|
||||
sdk_33_classes.add(clazz)
|
||||
if clazz in PLATFORM_33_CLASSES and clazz not in SDK_33_CLASSES:
|
||||
platform_non_sdk_33_classes.add(clazz)
|
||||
if clazz in PLATFORM_34_CLASSES:
|
||||
platform_34_classes.add(clazz)
|
||||
if clazz in SDK_34_CLASSES:
|
||||
sdk_34_classes.add(clazz)
|
||||
if clazz in PLATFORM_34_CLASSES and clazz not in SDK_34_CLASSES:
|
||||
platform_non_sdk_34_classes.add(clazz)
|
||||
all_classes.add(clazz)
|
||||
return PlatformClassesData(
|
||||
nb_duplicate_classes=len(duplicated_classes),
|
||||
nb_platform_32_classes=len(platform_32_classes),
|
||||
nb_platform_non_sdk_32_classes=len(platform_non_sdk_32_classes),
|
||||
nb_sdk_32_classes=len(sdk_32_classes),
|
||||
nb_platform_33_classes=len(platform_33_classes),
|
||||
nb_platform_non_sdk_33_classes=len(platform_non_sdk_33_classes),
|
||||
nb_sdk_33_classes=len(sdk_33_classes),
|
||||
nb_platform_34_classes=len(platform_34_classes),
|
||||
nb_platform_non_sdk_34_classes=len(platform_non_sdk_34_classes),
|
||||
nb_sdk_34_classes=len(sdk_34_classes),
|
||||
)
|
||||
|
||||
|
||||
def analyze(apk: zipfile.ZipFile, sha256: str) -> ApkData:
|
||||
classes_dex = set(
|
||||
filter(
|
||||
lambda name: name.startswith("classes") and name.endswith(".dex"),
|
||||
apk.namelist(),
|
||||
)
|
||||
)
|
||||
dex_numbers = list(
|
||||
map(
|
||||
int,
|
||||
filter(
|
||||
lambda string: string not in ("", "1")
|
||||
and string.isnumeric()
|
||||
and string[0] != "0",
|
||||
map(
|
||||
lambda name: name.removeprefix("classes").removesuffix(".dex"),
|
||||
classes_dex,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
dex_numbers.sort()
|
||||
|
||||
has_non_numeric_classes_dex = False
|
||||
for name in classes_dex:
|
||||
if name == "classes.dex":
|
||||
continue
|
||||
if not name.removeprefix("classes").removesuffix(".dex").isnumeric():
|
||||
has_non_numeric_classes_dex = True
|
||||
|
||||
has_non_consecutive_classes_dex = False
|
||||
if "classes.dex" in classes_dex and dex_numbers:
|
||||
has_non_consecutive_classes_dex = True
|
||||
last_number = 1
|
||||
for i in range(len(dex_numbers)):
|
||||
if dex_numbers[i] == 0 or dex_numbers[i] == 1:
|
||||
continue
|
||||
# the list is sorted
|
||||
if dex_numbers[i] != last_number + 1:
|
||||
has_non_consecutive_classes_dex = True
|
||||
break
|
||||
|
||||
platform_classes_data = scan_classes(apk, classes_dex)
|
||||
|
||||
return ApkData(
|
||||
sha256=sha256,
|
||||
**asdict(platform_classes_data),
|
||||
has_classes0_dex="classes0.dex" in classes_dex,
|
||||
has_classes1_dex="classes1.dex" in classes_dex,
|
||||
has_classes0X_dex=any(
|
||||
map(lambda name: name.startswith("classes0"), classes_dex)
|
||||
),
|
||||
has_classes_dex_over_10=any(map(lambda x: x >= 10, dex_numbers)),
|
||||
has_non_numeric_classes_dex=has_non_numeric_classes_dex,
|
||||
has_non_consecutive_classes_dex=has_non_consecutive_classes_dex,
|
||||
)
|
||||
10
android_class_shadowing_scanner/androzoo.py
Normal file
10
android_class_shadowing_scanner/androzoo.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import http.client
|
||||
|
||||
|
||||
def download_apk(sha256: str, api_key: str) -> bytes:
|
||||
conn = http.client.HTTPSConnection("androzoo.uni.lu")
|
||||
conn.request("GET", f"/api/download?apikey={api_key}&sha256={sha256}")
|
||||
resp = conn.getresponse()
|
||||
if resp.status != 200:
|
||||
raise RuntimeError(f"Failled to download APK {sha256}: {resp.reason}")
|
||||
return resp.read()
|
||||
174
poetry.lock
generated
174
poetry.lock
generated
|
|
@ -102,6 +102,85 @@ files = [
|
|||
[package.extras]
|
||||
dev = ["mypy", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "1.17.1"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
|
||||
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
|
||||
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
|
||||
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
|
||||
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
|
||||
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
|
||||
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
|
||||
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
|
|
@ -211,6 +290,55 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pil
|
|||
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
|
||||
test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "43.0.1"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
|
||||
{file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
|
||||
{file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
|
||||
{file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
|
||||
{file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
|
||||
{file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
|
||||
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
nox = ["nox"]
|
||||
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||
sdist = ["build"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
name = "cycler"
|
||||
version = "0.12.1"
|
||||
|
|
@ -504,6 +632,21 @@ docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alab
|
|||
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
||||
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "jeepney"
|
||||
version = "0.8.0"
|
||||
description = "Low-level, pure Python DBus protocol wrapper."
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
|
||||
{file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"]
|
||||
trio = ["async_generator", "trio"]
|
||||
|
||||
[[package]]
|
||||
name = "kiwisolver"
|
||||
version = "1.4.7"
|
||||
|
|
@ -1256,6 +1399,17 @@ files = [
|
|||
[package.extras]
|
||||
tests = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.22"
|
||||
description = "C parser in Python"
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydot"
|
||||
version = "3.0.2"
|
||||
|
|
@ -1379,6 +1533,21 @@ files = [
|
|||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secretstorage"
|
||||
version = "3.3.3"
|
||||
description = "Python bindings to FreeDesktop.org Secret Service API"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
|
||||
{file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = ">=2.0"
|
||||
jeepney = ">=0.6"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
|
|
@ -1537,7 +1706,10 @@ files = [
|
|||
[package.extras]
|
||||
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
|
||||
[extras]
|
||||
secretstorage = ["SecretStorage"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "b53b77f57e118a7dc8649764dff18035672596a44b2be1983d3cbe17e1d28bc2"
|
||||
content-hash = "17b8e803d4fecdffce0e19b557cedc226cc67d501c8f86b8228af513d9dfc3e3"
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@ readme = "README.md"
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
|
||||
|
||||
androguard = "^4.1.2"
|
||||
|
||||
SecretStorage = { version = "^3.3.3", optional = true }
|
||||
|
||||
[tool.poetry.extras]
|
||||
secretstorage = ["SecretStorage"]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue