Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2451ad3674 | ||
|
|
25804df238 | ||
|
|
474173ba54 | ||
|
|
049a3b703f | ||
|
|
ac77fde892 | ||
|
|
6ee9b22923 | ||
|
|
f355138cd2 | ||
|
|
478d135d1f | ||
|
|
80c9acdabe | ||
|
|
d4eaa7c543 | ||
|
|
2571550da4 | ||
|
|
b3ee3a3506 | ||
|
|
11feccd93b | ||
|
|
bb6ce5c013 |
13
.github/workflows/bundle_windows.yml
vendored
13
.github/workflows/bundle_windows.yml
vendored
@@ -1,5 +1,3 @@
|
||||
# Have to manually unzip this (it gets double zipped) and add it
|
||||
# onto the release after it gets created. Don't want actions with repo write.
|
||||
name: Bundle Windows EXE
|
||||
|
||||
|
||||
@@ -9,8 +7,12 @@ on:
|
||||
types:
|
||||
- created
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref_name:
|
||||
description: Name to use for the release
|
||||
env:
|
||||
target_tag: ${{ github.ref_name }}
|
||||
target_tag: ${{ github.ref_name || github.event.inputs.ref_name }}
|
||||
sha: ${{ github.sha || github.event.inputs.ref_name }}
|
||||
|
||||
|
||||
jobs:
|
||||
@@ -21,7 +23,7 @@ jobs:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.9]
|
||||
python-version: [3.11]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -51,10 +53,11 @@ jobs:
|
||||
- name: Upload the artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: hippolyzer-windows-${{ github.sha }}
|
||||
name: hippolyzer-windows-${{ env.sha }}
|
||||
path: ./hippolyzer-windows-${{ env.target_tag }}.zip
|
||||
|
||||
- uses: ncipollo/release-action@v1.10.0
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
artifacts: hippolyzer-windows-${{ env.target_tag }}.zip
|
||||
tag: ${{ env.target_tag }}
|
||||
|
||||
2
.github/workflows/pypi_publish.yml
vendored
2
.github/workflows/pypi_publish.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
python-version: 3.10
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
2
.github/workflows/pytest.yml
vendored
2
.github/workflows/pytest.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.9", "3.11"]
|
||||
python-version: ["3.10", "3.12"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -27,7 +27,7 @@ with low-level SL details. See the [Local Animation addon example](https://githu
|
||||
|
||||
### From Source
|
||||
|
||||
* Python 3.8 or above is **required**. If you're unable to upgrade your system Python package due to
|
||||
* Python 3.10 or above is **required**. If you're unable to upgrade your system Python package due to
|
||||
being on a stable distro, you can use [pyenv](https://github.com/pyenv/pyenv) to create
|
||||
a self-contained Python install with the appropriate version.
|
||||
* [Create a clean Python 3 virtualenv](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment)
|
||||
|
||||
21
addon_examples/packet_stats.py
Normal file
21
addon_examples/packet_stats.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import collections
|
||||
|
||||
from hippolyzer.lib.base.message.message import Message
|
||||
from hippolyzer.lib.proxy.addon_utils import BaseAddon, GlobalProperty
|
||||
from hippolyzer.lib.proxy.commands import handle_command
|
||||
from hippolyzer.lib.proxy.region import ProxiedRegion
|
||||
from hippolyzer.lib.proxy.sessions import Session
|
||||
|
||||
|
||||
class PacketStatsAddon(BaseAddon):
|
||||
packet_stats: collections.Counter = GlobalProperty(collections.Counter)
|
||||
|
||||
def handle_lludp_message(self, session: Session, region: ProxiedRegion, message: Message):
|
||||
self.packet_stats[message.name] += 1
|
||||
|
||||
@handle_command()
|
||||
async def print_packet_stats(self, _session: Session, _region: ProxiedRegion):
|
||||
print(self.packet_stats.most_common(10))
|
||||
|
||||
|
||||
addons = [PacketStatsAddon()]
|
||||
@@ -160,8 +160,12 @@ class HippoLLSDBinaryParser(base_llsd.serde_binary.LLSDBinaryParser):
|
||||
return bytes_val
|
||||
|
||||
|
||||
# Python uses one, C++ uses the other, and everyone's unhappy.
|
||||
_BINARY_HEADERS = (b'<? LLSD/Binary ?>', b'<?llsd/binary?>')
|
||||
|
||||
|
||||
def parse_binary(data: bytes):
|
||||
if data.startswith(b'<?llsd/binary?>'):
|
||||
if any(data.startswith(x) for x in _BINARY_HEADERS):
|
||||
data = data.split(b'\n', 1)[1]
|
||||
return HippoLLSDBinaryParser().parse(data)
|
||||
|
||||
@@ -187,7 +191,7 @@ def parse(data: bytes):
|
||||
# content-type is usually nonsense.
|
||||
try:
|
||||
data = data.lstrip()
|
||||
if data.startswith(b'<?llsd/binary?>'):
|
||||
if any(data.startswith(x) for x in _BINARY_HEADERS):
|
||||
return parse_binary(data)
|
||||
elif data.startswith(b'<'):
|
||||
return parse_xml(data)
|
||||
|
||||
@@ -90,6 +90,7 @@ class AssetType(LookupIntEnum):
|
||||
RESERVED_5 = 54
|
||||
RESERVED_6 = 55
|
||||
SETTINGS = 56
|
||||
MATERIAL = 57
|
||||
UNKNOWN = 255
|
||||
NONE = -1
|
||||
|
||||
@@ -125,6 +126,7 @@ class AssetType(LookupIntEnum):
|
||||
AssetType.PERSON: InventoryType.PERSON,
|
||||
AssetType.MESH: InventoryType.MESH,
|
||||
AssetType.SETTINGS: InventoryType.SETTINGS,
|
||||
AssetType.MATERIAL: InventoryType.MATERIAL,
|
||||
}.get(self, AssetType.NONE)
|
||||
|
||||
|
||||
@@ -166,6 +168,7 @@ class InventoryType(LookupIntEnum):
|
||||
WIDGET = 23
|
||||
PERSON = 24
|
||||
SETTINGS = 25
|
||||
MATERIAL = 26
|
||||
UNKNOWN = 255
|
||||
NONE = -1
|
||||
|
||||
@@ -235,10 +238,11 @@ class FolderType(LookupIntEnum):
|
||||
# Note: We actually *never* create folders with that type. This is used for icon override only.
|
||||
MARKETPLACE_VERSION = 55
|
||||
SETTINGS = 56
|
||||
MATERIAL = 57
|
||||
# Firestorm folders, may not actually exist in legacy schema
|
||||
FIRESTORM = 57
|
||||
PHOENIX = 58
|
||||
RLV = 59
|
||||
FIRESTORM = 58
|
||||
PHOENIX = 59
|
||||
RLV = 60
|
||||
# Opensim folders
|
||||
MY_SUITCASE = 100
|
||||
NONE = -1
|
||||
|
||||
@@ -8,6 +8,7 @@ import queue
|
||||
import typing
|
||||
import uuid
|
||||
import weakref
|
||||
from typing import Iterable
|
||||
|
||||
import mitmproxy.certs
|
||||
import mitmproxy.ctx
|
||||
@@ -15,7 +16,10 @@ import mitmproxy.log
|
||||
import mitmproxy.master
|
||||
import mitmproxy.options
|
||||
import mitmproxy.proxy
|
||||
from cryptography import x509
|
||||
from cryptography.x509 import GeneralNames
|
||||
from mitmproxy.addons import core, clientplayback, proxyserver, next_layer, disable_h2c
|
||||
from mitmproxy.certs import CertStoreEntry
|
||||
from mitmproxy.http import HTTPFlow
|
||||
from mitmproxy.proxy.layers import tls
|
||||
import OpenSSL
|
||||
@@ -26,9 +30,16 @@ from hippolyzer.lib.proxy.caps import SerializedCapData
|
||||
|
||||
|
||||
class SLCertStore(mitmproxy.certs.CertStore):
|
||||
def get_cert(self, commonname: typing.Optional[str], sans: typing.List[str], *args, **kwargs):
|
||||
def get_cert(
|
||||
self,
|
||||
commonname: str | None,
|
||||
sans: Iterable[x509.GeneralName],
|
||||
organization: str | None = None,
|
||||
*args,
|
||||
**kwargs
|
||||
) -> CertStoreEntry:
|
||||
entry = super().get_cert(commonname, sans, *args, **kwargs)
|
||||
cert, privkey, chain = entry.cert, entry.privatekey, entry.chain_file
|
||||
cert, privkey, chain, chain_certs = entry.cert, entry.privatekey, entry.chain_file, entry.chain_certs
|
||||
x509 = cert.to_pyopenssl()
|
||||
# The cert must have a subject key ID or the viewer will reject it.
|
||||
for i in range(0, x509.get_extension_count()):
|
||||
@@ -48,10 +59,10 @@ class SLCertStore(mitmproxy.certs.CertStore):
|
||||
])
|
||||
x509.sign(OpenSSL.crypto.PKey.from_cryptography_key(privkey), "sha256") # type: ignore
|
||||
new_entry = mitmproxy.certs.CertStoreEntry(
|
||||
mitmproxy.certs.Cert.from_pyopenssl(x509), privkey, chain
|
||||
mitmproxy.certs.Cert.from_pyopenssl(x509), privkey, chain, chain_certs,
|
||||
)
|
||||
# Replace the cert that was created in the base `get_cert()` with our modified cert
|
||||
self.certs[(commonname, tuple(sans))] = new_entry
|
||||
self.certs[(commonname, GeneralNames(sans))] = new_entry
|
||||
self.expire_queue.pop(-1)
|
||||
self.expire(new_entry)
|
||||
return new_entry
|
||||
|
||||
113
requirements.txt
113
requirements.txt
@@ -1,70 +1,77 @@
|
||||
aiohttp==3.8.3
|
||||
aiosignal==1.2.0
|
||||
aiohttp==3.9.1
|
||||
aioquic==0.9.25
|
||||
aiosignal==1.3.1
|
||||
appdirs==1.4.4
|
||||
Arpeggio==1.10.2
|
||||
asgiref==3.4.1
|
||||
async-timeout==4.0.1
|
||||
attrs==21.2.0
|
||||
blinker==1.4
|
||||
Brotli==1.0.9
|
||||
certifi==2022.12.7
|
||||
cffi==1.15.0
|
||||
charset-normalizer==2.0.9
|
||||
click==8.0.3
|
||||
cryptography==36.0.2
|
||||
Arpeggio==2.0.2
|
||||
asgiref==3.7.2
|
||||
attrs==23.2.0
|
||||
blinker==1.7.0
|
||||
Brotli==1.1.0
|
||||
certifi==2023.11.17
|
||||
cffi==1.16.0
|
||||
click==8.1.7
|
||||
cryptography==41.0.7
|
||||
dataclasses-json==0.6.3
|
||||
defusedxml==0.7.1
|
||||
Flask==2.0.2
|
||||
frozenlist==1.3.3
|
||||
Flask==2.3.3
|
||||
frozenlist==1.4.1
|
||||
gltflib==1.0.13
|
||||
Glymur==0.9.6
|
||||
h11==0.12.0
|
||||
h11==0.14.0
|
||||
h2==4.1.0
|
||||
hpack==4.0.0
|
||||
hyperframe==6.0.1
|
||||
idna==2.10
|
||||
itsdangerous==2.0.1
|
||||
jedi==0.18.1
|
||||
Jinja2==3.0.3
|
||||
kaitaistruct==0.9
|
||||
lazy-object-proxy==1.6.0
|
||||
itsdangerous==2.1.2
|
||||
jedi==0.19.1
|
||||
Jinja2==3.1.2
|
||||
kaitaistruct==0.10
|
||||
lazy-object-proxy==1.10.0
|
||||
ldap3==2.9.1
|
||||
llsd~=1.0.0
|
||||
lxml==4.9.2
|
||||
MarkupSafe==2.0.1
|
||||
mitmproxy==8.0.0
|
||||
msgpack==1.0.3
|
||||
multidict==5.2.0
|
||||
numpy==1.24.2
|
||||
outleap~=0.4.1
|
||||
llsd==1.0.0
|
||||
lxml==5.1.0
|
||||
MarkupSafe==2.1.3
|
||||
marshmallow==3.20.1
|
||||
mitmproxy==10.2.1
|
||||
mitmproxy_rs==0.5.1
|
||||
msgpack==1.0.7
|
||||
multidict==6.0.4
|
||||
mypy-extensions==1.0.0
|
||||
numpy==1.26.3
|
||||
outleap==0.5.1
|
||||
packaging==23.2
|
||||
parso==0.8.3
|
||||
passlib==1.7.4
|
||||
prompt-toolkit==3.0.23
|
||||
protobuf==3.18.1
|
||||
ptpython==3.0.20
|
||||
prompt-toolkit==3.0.43
|
||||
protobuf==4.25.1
|
||||
ptpython==3.0.25
|
||||
publicsuffix2==2.20191221
|
||||
pyasn1==0.4.8
|
||||
pyasn1==0.5.1
|
||||
pyasn1-modules==0.3.0
|
||||
pycollada==0.8
|
||||
pycparser==2.21
|
||||
pycollada==0.7.2
|
||||
Pygments==2.10.0
|
||||
pyOpenSSL==22.0.0
|
||||
pyparsing==2.4.7
|
||||
Pygments==2.17.2
|
||||
pylsqpack==0.3.18
|
||||
pyOpenSSL==23.3.0
|
||||
pyparsing==3.1.1
|
||||
pyperclip==1.8.2
|
||||
PySide6-Essentials==6.4.2
|
||||
qasync==0.22.0
|
||||
PySide6-Essentials==6.6.1
|
||||
python-dateutil==2.8.2
|
||||
qasync==0.27.1
|
||||
recordclass==0.18.2
|
||||
requests==2.26.0
|
||||
ruamel.yaml==0.17.21
|
||||
ruamel.yaml.clib==0.2.7
|
||||
shiboken6==6.4.2
|
||||
ruamel.yaml==0.18.5
|
||||
ruamel.yaml.clib==0.2.8
|
||||
service-identity==23.1.0
|
||||
shiboken6==6.6.1
|
||||
six==1.16.0
|
||||
sortedcontainers==2.4.0
|
||||
tornado==6.1
|
||||
transformations==2021.6.6
|
||||
typing-extensions==4.0.1
|
||||
urllib3==1.26.7
|
||||
urwid==2.1.2
|
||||
wcwidth==0.2.5
|
||||
Werkzeug==2.0.2
|
||||
wsproto==1.0.0
|
||||
yarl==1.8.2
|
||||
zstandard<0.18.0
|
||||
tornado==6.4
|
||||
transformations==2024.6.1
|
||||
typing-inspect==0.9.0
|
||||
typing_extensions==4.9.0
|
||||
urwid-mitmproxy==2.1.2.1
|
||||
wcwidth==0.2.13
|
||||
Werkzeug==2.3.8
|
||||
wsproto==1.2.0
|
||||
yarl==1.9.4
|
||||
zstandard==0.22.0
|
||||
|
||||
9
setup.py
9
setup.py
@@ -25,7 +25,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
here = path.abspath(path.dirname(__file__))
|
||||
|
||||
version = '0.14.3'
|
||||
version = '0.15.0'
|
||||
|
||||
with open(path.join(here, 'README.md')) as readme_fh:
|
||||
readme = readme_fh.read()
|
||||
@@ -42,7 +42,6 @@ setup(
|
||||
"Operating System :: POSIX",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
@@ -79,7 +78,7 @@ setup(
|
||||
}
|
||||
},
|
||||
zip_safe=False,
|
||||
python_requires='>=3.9',
|
||||
python_requires='>=3.10',
|
||||
install_requires=[
|
||||
'llsd<1.1.0',
|
||||
'defusedxml',
|
||||
@@ -100,8 +99,8 @@ setup(
|
||||
# Proxy-specific stuff
|
||||
'outleap<1.0',
|
||||
'arpeggio',
|
||||
# 7.x will be a major change.
|
||||
'mitmproxy>=8.0.0,<8.1',
|
||||
# 11.x will be a major change.
|
||||
'mitmproxy>=10.0.0,<11',
|
||||
'Werkzeug<3.0',
|
||||
# For REPLs
|
||||
'ptpython<4.0',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import glob
|
||||
|
||||
import setuptools # noqa
|
||||
|
||||
import os
|
||||
@@ -32,20 +34,20 @@ TO_DELETE = [
|
||||
"lib/aiohttp/_http_writer.c",
|
||||
"lib/aiohttp/_websocket.c",
|
||||
# Improve this to work with different versions.
|
||||
"lib/aiohttp/python39.dll",
|
||||
"lib/lazy_object_proxy/python39.dll",
|
||||
"lib/lxml/python39.dll",
|
||||
"lib/markupsafe/python39.dll",
|
||||
"lib/multidict/python39.dll",
|
||||
"lib/numpy/core/python39.dll",
|
||||
"lib/numpy/fft/python39.dll",
|
||||
"lib/numpy/linalg/python39.dll",
|
||||
"lib/numpy/random/python39.dll",
|
||||
"lib/python39.dll",
|
||||
"lib/recordclass/python39.dll",
|
||||
"lib/regex/python39.dll",
|
||||
"lib/aiohttp/python3*.dll",
|
||||
"lib/lazy_object_proxy/python3*.dll",
|
||||
"lib/lxml/python3*.dll",
|
||||
"lib/markupsafe/python3*.dll",
|
||||
"lib/multidict/python3*.dll",
|
||||
"lib/numpy/core/python3*.dll",
|
||||
"lib/numpy/fft/python3*.dll",
|
||||
"lib/numpy/linalg/python3*.dll",
|
||||
"lib/numpy/random/python3*.dll",
|
||||
"lib/python3*.dll",
|
||||
"lib/recordclass/python3*.dll",
|
||||
"lib/regex/python3*.dll",
|
||||
"lib/test",
|
||||
"lib/yarl/python39.dll",
|
||||
"lib/yarl/python3*.dll",
|
||||
]
|
||||
|
||||
COPY_TO_ZIP = [
|
||||
@@ -77,11 +79,12 @@ class FinalizeCXFreezeCommand(Command):
|
||||
if path.name.startswith("exe.") and path.is_dir():
|
||||
for cleanse_suffix in TO_DELETE:
|
||||
cleanse_path = path / cleanse_suffix
|
||||
shutil.rmtree(cleanse_path, ignore_errors=True)
|
||||
try:
|
||||
os.unlink(cleanse_path)
|
||||
except:
|
||||
pass
|
||||
for globbed in glob.glob(str(cleanse_path)):
|
||||
shutil.rmtree(globbed, ignore_errors=True)
|
||||
try:
|
||||
os.unlink(globbed)
|
||||
except:
|
||||
pass
|
||||
for to_copy in COPY_TO_ZIP:
|
||||
shutil.copy(BASE_DIR / to_copy, path / to_copy)
|
||||
shutil.copytree(BASE_DIR / "addon_examples", path / "addon_examples")
|
||||
@@ -95,6 +98,7 @@ options = {
|
||||
"passlib",
|
||||
"_cffi_backend",
|
||||
"hippolyzer",
|
||||
"mitmproxy_windows",
|
||||
],
|
||||
# exclude packages that are not really needed
|
||||
"excludes": [
|
||||
|
||||
Reference in New Issue
Block a user