generated from nathanwoodburn/python-webserver-template
Compare commits
7 Commits
99bf4a6a1a
...
a36e467bd4
| Author | SHA1 | Date | |
|---|---|---|---|
|
a36e467bd4
|
|||
|
f70454c9a4
|
|||
|
3d5d203831
|
|||
|
16d7b9f942
|
|||
|
513a3ebd57
|
|||
|
adfa0fd4a0
|
|||
|
994b5bc5bf
|
@@ -2,7 +2,7 @@ FROM --platform=$BUILDPLATFORM python:3.13-alpine
|
|||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||||
|
|
||||||
# Install curl for healthcheck
|
# Install curl for healthcheck
|
||||||
RUN apk add --no-cache curl
|
RUN apk add --no-cache curl openssl
|
||||||
|
|
||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ description = "Add your description here"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cryptography>=46.0.3",
|
||||||
"flask>=3.1.2",
|
"flask>=3.1.2",
|
||||||
"gunicorn>=23.0.0",
|
"gunicorn>=23.0.0",
|
||||||
"python-dotenv>=1.2.1",
|
"python-dotenv>=1.2.1",
|
||||||
"requests>=2.32.5",
|
"requests-doh>=1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|||||||
151
requirements.txt
151
requirements.txt
@@ -1,5 +1,9 @@
|
|||||||
# This file was autogenerated by uv via the following command:
|
# This file was autogenerated by uv via the following command:
|
||||||
# uv export --frozen --output-file=requirements.txt
|
# uv export --frozen --output-file=requirements.txt
|
||||||
|
anyio==4.11.0 \
|
||||||
|
--hash=sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc \
|
||||||
|
--hash=sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4
|
||||||
|
# via httpx
|
||||||
blinker==1.9.0 \
|
blinker==1.9.0 \
|
||||||
--hash=sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf \
|
--hash=sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf \
|
||||||
--hash=sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc
|
--hash=sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc
|
||||||
@@ -7,7 +11,47 @@ blinker==1.9.0 \
|
|||||||
certifi==2025.11.12 \
|
certifi==2025.11.12 \
|
||||||
--hash=sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b \
|
--hash=sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b \
|
||||||
--hash=sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316
|
--hash=sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316
|
||||||
# via requests
|
# via
|
||||||
|
# httpcore
|
||||||
|
# httpx
|
||||||
|
# requests
|
||||||
|
cffi==2.0.0 ; platform_python_implementation != 'PyPy' \
|
||||||
|
--hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \
|
||||||
|
--hash=sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b \
|
||||||
|
--hash=sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f \
|
||||||
|
--hash=sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9 \
|
||||||
|
--hash=sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c \
|
||||||
|
--hash=sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75 \
|
||||||
|
--hash=sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e \
|
||||||
|
--hash=sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25 \
|
||||||
|
--hash=sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b \
|
||||||
|
--hash=sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91 \
|
||||||
|
--hash=sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592 \
|
||||||
|
--hash=sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1 \
|
||||||
|
--hash=sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529 \
|
||||||
|
--hash=sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca \
|
||||||
|
--hash=sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4 \
|
||||||
|
--hash=sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b \
|
||||||
|
--hash=sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205 \
|
||||||
|
--hash=sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27 \
|
||||||
|
--hash=sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512 \
|
||||||
|
--hash=sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d \
|
||||||
|
--hash=sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c \
|
||||||
|
--hash=sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8 \
|
||||||
|
--hash=sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9 \
|
||||||
|
--hash=sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775 \
|
||||||
|
--hash=sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc \
|
||||||
|
--hash=sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13 \
|
||||||
|
--hash=sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26 \
|
||||||
|
--hash=sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b \
|
||||||
|
--hash=sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6 \
|
||||||
|
--hash=sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c \
|
||||||
|
--hash=sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef \
|
||||||
|
--hash=sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad \
|
||||||
|
--hash=sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3 \
|
||||||
|
--hash=sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2 \
|
||||||
|
--hash=sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5
|
||||||
|
# via cryptography
|
||||||
cfgv==3.5.0 \
|
cfgv==3.5.0 \
|
||||||
--hash=sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0 \
|
--hash=sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0 \
|
||||||
--hash=sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132
|
--hash=sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132
|
||||||
@@ -56,10 +100,62 @@ colorama==0.4.6 ; sys_platform == 'win32' \
|
|||||||
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
||||||
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
||||||
# via click
|
# via click
|
||||||
|
cryptography==46.0.3 \
|
||||||
|
--hash=sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217 \
|
||||||
|
--hash=sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d \
|
||||||
|
--hash=sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc \
|
||||||
|
--hash=sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71 \
|
||||||
|
--hash=sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971 \
|
||||||
|
--hash=sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a \
|
||||||
|
--hash=sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926 \
|
||||||
|
--hash=sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc \
|
||||||
|
--hash=sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d \
|
||||||
|
--hash=sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20 \
|
||||||
|
--hash=sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044 \
|
||||||
|
--hash=sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3 \
|
||||||
|
--hash=sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715 \
|
||||||
|
--hash=sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4 \
|
||||||
|
--hash=sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506 \
|
||||||
|
--hash=sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f \
|
||||||
|
--hash=sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0 \
|
||||||
|
--hash=sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683 \
|
||||||
|
--hash=sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3 \
|
||||||
|
--hash=sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21 \
|
||||||
|
--hash=sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91 \
|
||||||
|
--hash=sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c \
|
||||||
|
--hash=sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8 \
|
||||||
|
--hash=sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df \
|
||||||
|
--hash=sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb \
|
||||||
|
--hash=sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7 \
|
||||||
|
--hash=sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04 \
|
||||||
|
--hash=sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db \
|
||||||
|
--hash=sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459 \
|
||||||
|
--hash=sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914 \
|
||||||
|
--hash=sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac \
|
||||||
|
--hash=sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec \
|
||||||
|
--hash=sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1 \
|
||||||
|
--hash=sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb \
|
||||||
|
--hash=sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac \
|
||||||
|
--hash=sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665 \
|
||||||
|
--hash=sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e \
|
||||||
|
--hash=sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5 \
|
||||||
|
--hash=sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936 \
|
||||||
|
--hash=sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de \
|
||||||
|
--hash=sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372 \
|
||||||
|
--hash=sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54 \
|
||||||
|
--hash=sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422 \
|
||||||
|
--hash=sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849 \
|
||||||
|
--hash=sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963 \
|
||||||
|
--hash=sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018
|
||||||
|
# via python-webserver-template
|
||||||
distlib==0.4.0 \
|
distlib==0.4.0 \
|
||||||
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
|
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
|
||||||
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
|
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
|
dnspython==2.6.1 \
|
||||||
|
--hash=sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50 \
|
||||||
|
--hash=sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc
|
||||||
|
# via requests-doh
|
||||||
filelock==3.20.0 \
|
filelock==3.20.0 \
|
||||||
--hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \
|
--hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \
|
||||||
--hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4
|
--hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4
|
||||||
@@ -72,6 +168,32 @@ gunicorn==23.0.0 \
|
|||||||
--hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
|
--hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
|
||||||
--hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
|
--hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
|
||||||
# via python-webserver-template
|
# via python-webserver-template
|
||||||
|
h11==0.16.0 \
|
||||||
|
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
|
||||||
|
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
||||||
|
# via httpcore
|
||||||
|
h2==4.3.0 \
|
||||||
|
--hash=sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1 \
|
||||||
|
--hash=sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd
|
||||||
|
# via dnspython
|
||||||
|
hpack==4.1.0 \
|
||||||
|
--hash=sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496 \
|
||||||
|
--hash=sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca
|
||||||
|
# via h2
|
||||||
|
httpcore==1.0.9 \
|
||||||
|
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
|
||||||
|
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
|
||||||
|
# via
|
||||||
|
# dnspython
|
||||||
|
# httpx
|
||||||
|
httpx==0.28.1 \
|
||||||
|
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
||||||
|
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
||||||
|
# via dnspython
|
||||||
|
hyperframe==6.1.0 \
|
||||||
|
--hash=sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5 \
|
||||||
|
--hash=sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08
|
||||||
|
# via h2
|
||||||
identify==2.6.15 \
|
identify==2.6.15 \
|
||||||
--hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \
|
--hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \
|
||||||
--hash=sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf
|
--hash=sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf
|
||||||
@@ -79,7 +201,10 @@ identify==2.6.15 \
|
|||||||
idna==3.11 \
|
idna==3.11 \
|
||||||
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
|
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
|
||||||
--hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
|
--hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
|
||||||
# via requests
|
# via
|
||||||
|
# anyio
|
||||||
|
# httpx
|
||||||
|
# requests
|
||||||
itsdangerous==2.2.0 \
|
itsdangerous==2.2.0 \
|
||||||
--hash=sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef \
|
--hash=sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef \
|
||||||
--hash=sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173
|
--hash=sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173
|
||||||
@@ -153,6 +278,14 @@ platformdirs==4.5.0 \
|
|||||||
pre-commit==4.4.0 \
|
pre-commit==4.4.0 \
|
||||||
--hash=sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813 \
|
--hash=sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813 \
|
||||||
--hash=sha256:f0233ebab440e9f17cabbb558706eb173d19ace965c68cdce2c081042b4fab15
|
--hash=sha256:f0233ebab440e9f17cabbb558706eb173d19ace965c68cdce2c081042b4fab15
|
||||||
|
pycparser==2.23 ; implementation_name != 'PyPy' and platform_python_implementation != 'PyPy' \
|
||||||
|
--hash=sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2 \
|
||||||
|
--hash=sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934
|
||||||
|
# via cffi
|
||||||
|
pysocks==1.7.1 \
|
||||||
|
--hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5 \
|
||||||
|
--hash=sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0
|
||||||
|
# via requests
|
||||||
python-dotenv==1.2.1 \
|
python-dotenv==1.2.1 \
|
||||||
--hash=sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6 \
|
--hash=sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6 \
|
||||||
--hash=sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61
|
--hash=sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61
|
||||||
@@ -188,9 +321,13 @@ pyyaml==6.0.3 \
|
|||||||
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
||||||
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6
|
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
requests==2.32.5 \
|
requests==2.32.3 \
|
||||||
--hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \
|
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||||
--hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf
|
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||||
|
# via requests-doh
|
||||||
|
requests-doh==1.0.0 \
|
||||||
|
--hash=sha256:6ce8bc96245030a198ef20d2100b4dcb3b120a05a58df703f8be121a79f8f2fb \
|
||||||
|
--hash=sha256:eea6583b792b7d3dfde74fd28eedc2b95d6ea896368119eede31f0d6ff2c838c
|
||||||
# via python-webserver-template
|
# via python-webserver-template
|
||||||
ruff==0.14.5 \
|
ruff==0.14.5 \
|
||||||
--hash=sha256:2d1fa985a42b1f075a098fa1ab9d472b712bdb17ad87a8ec86e45e7fa6273e68 \
|
--hash=sha256:2d1fa985a42b1f075a098fa1ab9d472b712bdb17ad87a8ec86e45e7fa6273e68 \
|
||||||
@@ -212,6 +349,10 @@ ruff==0.14.5 \
|
|||||||
--hash=sha256:f55382725ad0bdb2e8ee2babcbbfb16f124f5a59496a2f6a46f1d9d99d93e6e2 \
|
--hash=sha256:f55382725ad0bdb2e8ee2babcbbfb16f124f5a59496a2f6a46f1d9d99d93e6e2 \
|
||||||
--hash=sha256:f66e9bb762e68d66e48550b59c74314168ebb46199886c5c5aa0b0fbcc81b151 \
|
--hash=sha256:f66e9bb762e68d66e48550b59c74314168ebb46199886c5c5aa0b0fbcc81b151 \
|
||||||
--hash=sha256:f7a75236570318c7a30edd7f5491945f0169de738d945ca8784500b517163a72
|
--hash=sha256:f7a75236570318c7a30edd7f5491945f0169de738d945ca8784500b517163a72
|
||||||
|
sniffio==1.3.1 \
|
||||||
|
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
|
||||||
|
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
|
||||||
|
# via anyio
|
||||||
urllib3==2.5.0 \
|
urllib3==2.5.0 \
|
||||||
--hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \
|
--hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \
|
||||||
--hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc
|
--hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc
|
||||||
|
|||||||
35
server.py
35
server.py
@@ -4,11 +4,13 @@ from flask import (
|
|||||||
render_template,
|
render_template,
|
||||||
send_from_directory,
|
send_from_directory,
|
||||||
send_file,
|
send_file,
|
||||||
|
jsonify,
|
||||||
)
|
)
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import dotenv
|
import dotenv
|
||||||
|
from tools import hip2, wallet_txt
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
@@ -133,11 +135,42 @@ def catch_all(path: str):
|
|||||||
|
|
||||||
@app.route("/api/v1/status")
|
@app.route("/api/v1/status")
|
||||||
def api_status():
|
def api_status():
|
||||||
return {
|
return jsonify(
|
||||||
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"service": "FireExplorer",
|
"service": "FireExplorer",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/v1/hip02/<domain>")
|
||||||
|
def hip02(domain: str):
|
||||||
|
hip2_record = hip2(domain)
|
||||||
|
if hip2_record:
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"success": True,
|
||||||
|
"address": hip2_record,
|
||||||
|
"method": "hip02",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
wallet_record = wallet_txt(domain)
|
||||||
|
if wallet_record:
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"success": True,
|
||||||
|
"address": wallet_record,
|
||||||
|
"method": "wallet_txt",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"success": False,
|
||||||
|
"error": "No HIP02 or WALLET record found for this domain",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Nathan.Woodburn/</title>
|
<title>Nathan.Woodburn/</title>
|
||||||
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="/assets/css/404.css">
|
<link rel="stylesheet" href="/assets/css/404.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,45 @@
|
|||||||
|
:root {
|
||||||
|
--primary-gradient: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
|
||||||
|
--bg-color: #0f172a;
|
||||||
|
--text-primary: #f8fafc;
|
||||||
|
--accent-color: #8b5cf6;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #000000;
|
background-color: var(--bg-color);
|
||||||
color: #ffffff;
|
background-image:
|
||||||
}
|
radial-gradient(at 0% 0%, rgba(59, 130, 246, 0.15) 0px, transparent 50%),
|
||||||
h1 {
|
radial-gradient(at 100% 0%, rgba(236, 72, 153, 0.15) 0px, transparent 50%);
|
||||||
font-size: 50px;
|
color: var(--text-primary);
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.centre {
|
.centre {
|
||||||
margin-top: 10%;
|
margin: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #ffffff;
|
color: var(--accent-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
|
color: #a78bfa;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
:root {
|
||||||
|
--primary-gradient: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 50%, #ec4899 100%);
|
||||||
|
--bg-color: #0f172a;
|
||||||
|
--card-bg: rgba(30, 41, 59, 0.7);
|
||||||
|
--card-border: rgba(148, 163, 184, 0.1);
|
||||||
|
--text-primary: #f8fafc;
|
||||||
|
--text-secondary: #94a3b8;
|
||||||
|
--accent-color: #8b5cf6;
|
||||||
|
--success-color: #10b981;
|
||||||
|
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -5,9 +17,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
|
background-color: var(--bg-color);
|
||||||
color: #e0e0e0;
|
background-image:
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
radial-gradient(at 0% 0%, rgba(59, 130, 246, 0.15) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 100% 0%, rgba(236, 72, 153, 0.15) 0px, transparent 50%);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
@@ -20,24 +35,56 @@ body {
|
|||||||
|
|
||||||
/* Header */
|
/* Header */
|
||||||
header {
|
header {
|
||||||
background: linear-gradient(135deg, #8b2f0a 0%, #6b3d0a 100%);
|
background: rgba(15, 23, 42, 0.8);
|
||||||
padding: 2rem 0;
|
backdrop-filter: blur(12px);
|
||||||
text-align: center;
|
-webkit-backdrop-filter: blur(12px);
|
||||||
box-shadow: 0 4px 20px rgba(255, 107, 53, 0.3);
|
padding: 1.5rem 0;
|
||||||
margin: 0 0 2rem 0;
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
border-bottom: 1px solid var(--card-border);
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
header h1 {
|
||||||
font-size: 3rem;
|
font-size: 1.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #ffffff;
|
display: flex;
|
||||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
header a:hover {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: var(--text-secondary);
|
||||||
font-size: 1.2rem;
|
font-size: 0.9rem;
|
||||||
margin-top: 0.5rem;
|
font-weight: 500;
|
||||||
|
display: none; /* Hidden on mobile, shown on desktop */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.subtitle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main Content */
|
/* Main Content */
|
||||||
@@ -45,26 +92,46 @@ main {
|
|||||||
padding: 2rem 0;
|
padding: 2rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
scroll-margin-top: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cards */
|
/* Cards */
|
||||||
.card {
|
.card {
|
||||||
background: rgba(30, 30, 30, 0.8);
|
background: var(--card-bg);
|
||||||
border-radius: 12px;
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
border-radius: 16px;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
box-shadow: var(--glass-shadow);
|
||||||
border: 1px solid rgba(255, 107, 53, 0.2);
|
border: 1px solid var(--card-border);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||||
|
opacity: 0; /* Start hidden for animation */
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
border-color: rgba(139, 92, 246, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card h2 {
|
.card h2 {
|
||||||
color: #ff6b35;
|
color: var(--text-primary);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
font-size: 1.8rem;
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card h3 {
|
.card h3 {
|
||||||
color: #f7931e;
|
color: var(--text-secondary);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-size: 1.3rem;
|
font-size: 1.1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Status Section */
|
/* Status Section */
|
||||||
@@ -77,25 +144,30 @@ main {
|
|||||||
|
|
||||||
.status-card {
|
.status-card {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-content {
|
.status-content {
|
||||||
color: #b0b0b0;
|
color: var(--text-primary);
|
||||||
font-size: 0.9rem;
|
font-size: 1.1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Info Grid */
|
/* Info Grid */
|
||||||
.info-grid {
|
.info-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
gap: 0.75rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
padding: 0.5rem;
|
padding: 1rem;
|
||||||
background: rgba(20, 20, 20, 0.5);
|
background: rgba(15, 23, 42, 0.4);
|
||||||
border-radius: 6px;
|
border-radius: 12px;
|
||||||
border: 1px solid rgba(255, 107, 53, 0.15);
|
border: 1px solid var(--card-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-item.no-border {
|
.info-item.no-border {
|
||||||
@@ -109,86 +181,125 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info-item strong {
|
.info-item strong {
|
||||||
color: #ff6b35;
|
color: var(--text-secondary);
|
||||||
display: inline-block;
|
display: block;
|
||||||
min-width: 100px;
|
font-size: 0.8rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mono {
|
.mono {
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||||
font-size: 0.85rem;
|
font-size: 0.9rem;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-all-btn {
|
.view-all-btn {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
padding: 0.5rem 1rem;
|
align-items: center;
|
||||||
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
justify-content: center;
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
background: var(--primary-gradient);
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-all-btn:hover {
|
.view-all-btn:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.4);
|
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mempool Transaction List */
|
/* Mempool Transaction List */
|
||||||
.mempool-txs-container {
|
.mempool-txs-container {
|
||||||
margin-top: 1rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mempool-header {
|
.mempool-header {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
background: rgba(255, 107, 53, 0.1);
|
background: rgba(139, 92, 246, 0.1);
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 1rem;
|
||||||
color: #ff6b35;
|
color: var(--accent-color);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-list {
|
.tx-list {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Scrollbar */
|
||||||
|
.tx-list::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-list::-webkit-scrollbar-track {
|
||||||
|
background: rgba(15, 23, 42, 0.3);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-list::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(148, 163, 184, 0.3);
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-item {
|
.tx-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 1rem;
|
||||||
padding: 0.5rem;
|
padding: 0.75rem;
|
||||||
background: rgba(20, 20, 20, 0.5);
|
background: rgba(15, 23, 42, 0.4);
|
||||||
border: 1px solid rgba(255, 107, 53, 0.15);
|
border: 1px solid var(--card-border);
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.75rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
animation: staggerFade 0.4s ease forwards;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-item:hover {
|
||||||
|
border-color: rgba(139, 92, 246, 0.3);
|
||||||
|
background: rgba(139, 92, 246, 0.05);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-hash {
|
.tx-hash {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 0.8rem;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
color: #b0b0b0;
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-view-btn {
|
.tx-view-btn {
|
||||||
padding: 0.4rem 0.8rem;
|
padding: 0.4rem 0.8rem;
|
||||||
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
background: rgba(139, 92, 246, 0.1);
|
||||||
color: #ffffff;
|
color: var(--accent-color);
|
||||||
border: none;
|
border: 1px solid rgba(139, 92, 246, 0.2);
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 0.85rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.2s ease;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-view-btn:hover {
|
.tx-view-btn:hover {
|
||||||
transform: translateY(-1px);
|
background: var(--accent-color);
|
||||||
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.4);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transaction Modal */
|
/* Transaction Modal */
|
||||||
@@ -198,23 +309,39 @@ main {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(15, 23, 42, 0.9);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-modal.active {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-content {
|
.tx-modal-content {
|
||||||
background: rgba(30, 30, 30, 0.95);
|
background: #1e293b;
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 80vh;
|
max-height: 85vh;
|
||||||
border: 1px solid rgba(255, 107, 53, 0.3);
|
border: 1px solid var(--card-border);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||||
|
transform: translateY(20px);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-modal.active .tx-modal-content {
|
||||||
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-header {
|
.tx-modal-header {
|
||||||
@@ -222,33 +349,30 @@ main {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
border-bottom: 1px solid rgba(255, 107, 53, 0.2);
|
border-bottom: 1px solid var(--card-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-header h3 {
|
.tx-modal-header h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #ff6b35;
|
color: var(--text-primary);
|
||||||
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-close {
|
.tx-modal-close {
|
||||||
background: none;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: #e0e0e0;
|
color: var(--text-secondary);
|
||||||
font-size: 2rem;
|
font-size: 1.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0.5rem;
|
||||||
width: 2rem;
|
border-radius: 8px;
|
||||||
height: 2rem;
|
transition: all 0.2s ease;
|
||||||
display: flex;
|
line-height: 1;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 4px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-close:hover {
|
.tx-modal-close:hover {
|
||||||
background: rgba(255, 107, 53, 0.2);
|
background: rgba(255, 255, 255, 0.1);
|
||||||
color: #ff6b35;
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-body {
|
.tx-modal-body {
|
||||||
@@ -258,8 +382,8 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tx-modal-body pre {
|
.tx-modal-body pre {
|
||||||
color: #b0b0b0;
|
color: var(--text-secondary);
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
@@ -268,70 +392,78 @@ main {
|
|||||||
|
|
||||||
/* Transaction Details */
|
/* Transaction Details */
|
||||||
.tx-details {
|
.tx-details {
|
||||||
color: #e0e0e0;
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-section {
|
.tx-section {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-section h4 {
|
.tx-section h4 {
|
||||||
color: #ff6b35;
|
color: var(--accent-color);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-size: 1.1rem;
|
font-size: 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-list {
|
.tx-io-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.75rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-item {
|
.tx-io-item {
|
||||||
background: rgba(20, 20, 20, 0.5);
|
background: rgba(15, 23, 42, 0.4);
|
||||||
border: 1px solid rgba(255, 107, 53, 0.15);
|
border: 1px solid var(--card-border);
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
padding: 0.75rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-header {
|
.tx-io-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-index {
|
.tx-io-index {
|
||||||
color: #ff6b35;
|
color: var(--text-secondary);
|
||||||
font-weight: 600;
|
font-size: 0.85rem;
|
||||||
font-size: 0.9rem;
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-value {
|
.tx-io-value {
|
||||||
color: #f7931e;
|
color: var(--success-color);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-address {
|
.tx-io-address {
|
||||||
color: #b0b0b0;
|
color: var(--text-primary);
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
font-size: 0.85rem;
|
font-size: 0.9rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-io-hash {
|
.tx-io-hash {
|
||||||
color: #808080;
|
color: var(--text-secondary);
|
||||||
font-size: 0.75rem;
|
font-size: 0.8rem;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-covenant {
|
.tx-covenant {
|
||||||
color: #ff6b35;
|
color: var(--accent-color);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.75rem;
|
||||||
font-style: italic;
|
padding-top: 0.75rem;
|
||||||
|
border-top: 1px solid var(--card-border);
|
||||||
|
font-family: 'JetBrains Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tabs */
|
/* Tabs */
|
||||||
@@ -340,38 +472,53 @@ main {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
background: rgba(15, 23, 42, 0.4);
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--card-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-btn {
|
.tab-btn {
|
||||||
background: rgba(50, 50, 50, 0.5);
|
flex: 1;
|
||||||
color: #e0e0e0;
|
background: transparent;
|
||||||
border: 1px solid rgba(255, 107, 53, 0.3);
|
color: var(--text-secondary);
|
||||||
padding: 0.75rem 1.5rem;
|
border: none;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 0.95rem;
|
||||||
transition: all 0.3s ease;
|
font-weight: 500;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-btn:hover {
|
.tab-btn:hover {
|
||||||
background: rgba(255, 107, 53, 0.2);
|
color: var(--text-primary);
|
||||||
border-color: #ff6b35;
|
background: rgba(255, 255, 255, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-btn.active {
|
.tab-btn.active {
|
||||||
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
background: var(--primary-gradient);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border-color: #ff6b35;
|
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
||||||
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content {
|
.tab-content {
|
||||||
display: none;
|
display: none;
|
||||||
|
animation: fadeIn 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content.active {
|
.tab-content.active {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
/* Search Box */
|
/* Search Box */
|
||||||
.search-box {
|
.search-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -383,39 +530,42 @@ main {
|
|||||||
.search-box input {
|
.search-box input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.8rem 1.2rem;
|
||||||
background: rgba(20, 20, 20, 0.8);
|
background: rgba(15, 23, 42, 0.6);
|
||||||
border: 1px solid rgba(255, 107, 53, 0.3);
|
border: 1px solid var(--card-border);
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
color: #e0e0e0;
|
color: var(--text-primary);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box input:focus {
|
.search-box input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #ff6b35;
|
border-color: var(--accent-color);
|
||||||
box-shadow: 0 0 0 2px rgba(255, 107, 53, 0.2);
|
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15), 0 0 20px rgba(139, 92, 246, 0.2);
|
||||||
|
background: rgba(15, 23, 42, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box input::placeholder {
|
.search-box input::placeholder {
|
||||||
color: rgba(224, 224, 224, 0.5);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box button {
|
.search-box button {
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.8rem 1.5rem;
|
||||||
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
background: var(--primary-gradient);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box button:hover {
|
.search-box button:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.4);
|
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box button:active {
|
.search-box button:active {
|
||||||
@@ -423,30 +573,32 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.secondary-btn {
|
.secondary-btn {
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.8rem 1.5rem;
|
||||||
background: rgba(50, 50, 50, 0.8);
|
background: transparent;
|
||||||
color: #ff6b35;
|
color: var(--text-primary);
|
||||||
border: 1px solid #ff6b35;
|
border: 1px solid var(--card-border);
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.secondary-btn:hover {
|
.secondary-btn:hover {
|
||||||
background: rgba(255, 107, 53, 0.2);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Result Box */
|
/* Result Box */
|
||||||
.result-box {
|
.result-box {
|
||||||
background: rgba(10, 10, 10, 0.8);
|
background: rgba(15, 23, 42, 0.4);
|
||||||
border: 1px solid rgba(255, 107, 53, 0.2);
|
border: 1px solid var(--card-border);
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
padding: 1rem;
|
padding: 1.5rem;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-box:empty {
|
.result-box:empty {
|
||||||
@@ -454,16 +606,20 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.result-box pre {
|
.result-box pre {
|
||||||
color: #b0b0b0;
|
color: var(--text-secondary);
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-box .error {
|
.result-box .error {
|
||||||
color: #ff4444;
|
color: #ef4444;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
background: rgba(239, 68, 68, 0.1);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(239, 68, 68, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbar */
|
/* Scrollbar */
|
||||||
@@ -472,58 +628,55 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.result-box::-webkit-scrollbar-track {
|
.result-box::-webkit-scrollbar-track {
|
||||||
background: rgba(20, 20, 20, 0.5);
|
background: rgba(15, 23, 42, 0.3);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-box::-webkit-scrollbar-thumb {
|
.result-box::-webkit-scrollbar-thumb {
|
||||||
background: rgba(255, 107, 53, 0.5);
|
background: rgba(148, 163, 184, 0.3);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-box::-webkit-scrollbar-thumb:hover {
|
.result-box::-webkit-scrollbar-thumb:hover {
|
||||||
background: rgba(255, 107, 53, 0.7);
|
background: rgba(148, 163, 184, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
footer {
|
footer {
|
||||||
background: rgba(20, 20, 20, 0.8);
|
background: rgba(15, 23, 42, 0.8);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
padding: 2rem 0;
|
padding: 2rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 3rem;
|
margin-top: 4rem;
|
||||||
border-top: 1px solid rgba(255, 107, 53, 0.2);
|
border-top: 1px solid var(--card-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
footer p {
|
footer p {
|
||||||
color: rgba(224, 224, 224, 0.7);
|
color: var(--text-secondary);
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timestamp {
|
.timestamp {
|
||||||
font-size: 0.9rem;
|
font-size: 0.85rem;
|
||||||
color: rgba(224, 224, 224, 0.5);
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Links */
|
/* Links */
|
||||||
a {
|
a {
|
||||||
color: #ff6b35;
|
color: var(--accent-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.3s ease;
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #f7931e;
|
color: #a78bfa;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
header h1 {
|
header h1 {
|
||||||
font-size: 2rem;
|
font-size: 1.5rem;
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
@@ -542,6 +695,11 @@ a:hover {
|
|||||||
.status-section {
|
.status-section {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
padding: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loading Animation */
|
/* Loading Animation */
|
||||||
@@ -557,4 +715,87 @@ a:hover {
|
|||||||
.status-content:empty::after {
|
.status-content:empty::after {
|
||||||
content: 'Loading...';
|
content: 'Loading...';
|
||||||
animation: pulse 1.5s ease-in-out infinite;
|
animation: pulse 1.5s ease-in-out infinite;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading Spinner */
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 3rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
animation: fadeIn 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 3px solid rgba(139, 92, 246, 0.1);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: var(--accent-color);
|
||||||
|
animation: spin 1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
animation: pulse 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* New Animations */
|
||||||
|
@keyframes slideUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes staggerFade {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply animations */
|
||||||
|
.card {
|
||||||
|
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||||
|
opacity: 0; /* Start hidden for animation */
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-section .card {
|
||||||
|
animation-delay: 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-section .card:nth-child(1) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-section .card:nth-child(2) {
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.additional-section .card {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-item {
|
||||||
|
animation: staggerFade 0.4s ease forwards;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
<title>Fire Explorer</title>
|
<title>Fire Explorer</title>
|
||||||
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
<link rel="icon" href="/assets/img/favicon.png" type="image/png">
|
||||||
<link rel="stylesheet" href="/assets/css/index.css">
|
<link rel="stylesheet" href="/assets/css/index.css">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||||
<meta name="description" content="A hot new Handshake Blockchain Explorer">
|
<meta name="description" content="A hot new Handshake Blockchain Explorer">
|
||||||
|
|
||||||
<!-- Open Graph Meta Tags -->
|
<!-- Open Graph Meta Tags -->
|
||||||
@@ -30,25 +33,14 @@
|
|||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1><img src="/assets/img/favicon.png" alt="Fire Icon" style="height: 1em; vertical-align: middle;"> Fire Explorer</h1>
|
<div class="brand">
|
||||||
<p class="subtitle">Handshake Blockchain Explorer</p>
|
<a href="/"><h1><img src="/assets/img/favicon.png" alt="Fire Icon" style="height: 1.2em; vertical-align: middle;"> Fire Explorer</h1></a>
|
||||||
|
<span class="subtitle">Handshake Blockchain Explorer</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="container">
|
<main class="container">
|
||||||
<!-- Status Cards -->
|
|
||||||
<section class="status-section">
|
|
||||||
<div class="card status-card">
|
|
||||||
<h3>Chain Info</h3>
|
|
||||||
<div id="chain-status" class="status-content">Loading...</div>
|
|
||||||
</div>
|
|
||||||
<div class="card status-card">
|
|
||||||
<h3>Mempool</h3>
|
|
||||||
<div id="mempool-status" class="status-content">Loading...</div>
|
|
||||||
<div id="mempool-txs" class="mempool-txs-container"></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Search Section -->
|
<!-- Search Section -->
|
||||||
<section class="search-section">
|
<section class="search-section">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -86,6 +78,9 @@
|
|||||||
<button onclick="searchAddressTx()">Get Transactions</button>
|
<button onclick="searchAddressTx()">Get Transactions</button>
|
||||||
<button onclick="searchAddressCoins()">Get Coins</button>
|
<button onclick="searchAddressCoins()">Get Coins</button>
|
||||||
</div>
|
</div>
|
||||||
|
<p style="font-size: 0.85rem; color: var(--text-secondary); margin-top: -0.5rem; margin-bottom: 1.5rem; padding-left: 0.5rem;">
|
||||||
|
<span style="color: var(--accent-color);">Tip:</span> Use <span class="mono" style="color: var(--text-primary);">@name</span> to search via HIP02 alias
|
||||||
|
</p>
|
||||||
<div id="address-result" class="result-box"></div>
|
<div id="address-result" class="result-box"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -106,16 +101,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Coin Lookup -->
|
<!-- Status Cards -->
|
||||||
<section class="additional-section">
|
<section class="status-section">
|
||||||
<div class="card">
|
<div class="card status-card">
|
||||||
<h2>Coin Lookup</h2>
|
<h3>Chain Info</h3>
|
||||||
<div class="search-box">
|
<div id="chain-status" class="status-content">Loading...</div>
|
||||||
<input type="text" id="coin-hash" placeholder="Coin hash" onkeypress="if(event.key === 'Enter') searchCoin()">
|
|
||||||
<input type="text" id="coin-index" placeholder="Index" onkeypress="if(event.key === 'Enter') searchCoin()">
|
|
||||||
<button onclick="searchCoin()">Get Coin Info</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="coin-result" class="result-box"></div>
|
<div class="card status-card">
|
||||||
|
<h3>Mempool</h3>
|
||||||
|
<div id="mempool-status" class="status-content">Loading...</div>
|
||||||
|
<div id="mempool-txs" class="mempool-txs-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
@@ -183,11 +178,6 @@
|
|||||||
searchName();
|
searchName();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (parts.length === 3 && parts[0] === 'coin') {
|
|
||||||
// Handle coin URLs: /coin/hash/index
|
|
||||||
document.getElementById('coin-hash').value = parts[1];
|
|
||||||
document.getElementById('coin-index').value = parts[2];
|
|
||||||
searchCoin();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +218,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve HIP02 alias
|
||||||
|
async function resolveHip02(input) {
|
||||||
|
if (!input.startsWith('@')) return { success: true, address: input };
|
||||||
|
|
||||||
|
const name = input.substring(1);
|
||||||
|
try {
|
||||||
|
// Try HTTPS first
|
||||||
|
const response = await fetch(`/api/v1/hip02/${name}`);
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
return { success: false, error: 'Failed to resolve HIP02 alias. ' + e.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Format chain data nicely
|
// Format chain data nicely
|
||||||
function formatChainData(chain) {
|
function formatChainData(chain) {
|
||||||
return `
|
return `
|
||||||
@@ -244,6 +249,13 @@
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open transaction in search tab
|
||||||
|
function openTx(txId) {
|
||||||
|
document.getElementById('tx-input').value = txId;
|
||||||
|
document.querySelector('[data-tab="tx"]').click();
|
||||||
|
searchTx();
|
||||||
|
}
|
||||||
|
|
||||||
// Format mempool data nicely
|
// Format mempool data nicely
|
||||||
function formatMempoolData(mempool) {
|
function formatMempoolData(mempool) {
|
||||||
// Check if mempool is an array of transaction IDs
|
// Check if mempool is an array of transaction IDs
|
||||||
@@ -259,9 +271,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="tx-list">
|
<div class="tx-list">
|
||||||
${mempool.map(txId => `
|
${mempool.map(txId => `
|
||||||
<div class="tx-item">
|
<div class="tx-item" onclick="openTx('${txId}')">
|
||||||
<span class="tx-hash mono">${txId}</span>
|
<span class="tx-hash mono">${txId}</span>
|
||||||
<button class="tx-view-btn" onclick="window.location.href='/tx/${txId}'">View</button>
|
|
||||||
</div>
|
</div>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
</div>
|
</div>
|
||||||
@@ -929,6 +940,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show loading animation
|
||||||
|
function showLoading(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
element.style.display = 'block';
|
||||||
|
element.innerHTML = `
|
||||||
|
<div class="loading-container">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<div class="loading-text">Lighing Fire...</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// Load status on page load
|
// Load status on page load
|
||||||
async function loadStatus() {
|
async function loadStatus() {
|
||||||
const chainStatus = await apiCall('chain');
|
const chainStatus = await apiCall('chain');
|
||||||
@@ -953,6 +976,8 @@
|
|||||||
alert('Please enter a block height or hash');
|
alert('Please enter a block height or hash');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('block-result');
|
||||||
updateURL('block', blockId);
|
updateURL('block', blockId);
|
||||||
const data = await apiCall(`block/${blockId}`);
|
const data = await apiCall(`block/${blockId}`);
|
||||||
|
|
||||||
@@ -971,6 +996,8 @@
|
|||||||
alert('Please enter a block height or hash');
|
alert('Please enter a block height or hash');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('block-result');
|
||||||
updateURL('header', blockId);
|
updateURL('header', blockId);
|
||||||
const data = await apiCall(`header/${blockId}`);
|
const data = await apiCall(`header/${blockId}`);
|
||||||
|
|
||||||
@@ -989,11 +1016,17 @@
|
|||||||
alert('Please enter a transaction ID');
|
alert('Please enter a transaction ID');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resultElement = document.getElementById('tx-result');
|
||||||
|
showLoading('tx-result');
|
||||||
|
|
||||||
|
// Scroll to the search section
|
||||||
|
document.querySelector('.search-section').scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
|
||||||
updateURL('tx', txId);
|
updateURL('tx', txId);
|
||||||
const data = await apiCall(`tx/${txId}`);
|
const data = await apiCall(`tx/${txId}`);
|
||||||
|
|
||||||
// Use formatted display instead of raw JSON
|
// Use formatted display instead of raw JSON
|
||||||
const resultElement = document.getElementById('tx-result');
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -1002,16 +1035,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function searchAddressTx() {
|
async function searchAddressTx() {
|
||||||
const address = document.getElementById('address-input').value.trim().replace(/,/g, '');
|
let address = document.getElementById('address-input').value.trim().replace(/,/g, '');
|
||||||
if (!address) {
|
if (!address) {
|
||||||
alert('Please enter an address');
|
alert('Please enter an address');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('address-result');
|
||||||
|
const resultElement = document.getElementById('address-result');
|
||||||
|
|
||||||
|
// Check for HIP02 alias
|
||||||
|
if (address.startsWith('@')) {
|
||||||
|
const hip02Result = await resolveHip02(address);
|
||||||
|
if (hip02Result.success && hip02Result.address) {
|
||||||
|
address = hip02Result.address;
|
||||||
|
// Update input to show resolved address
|
||||||
|
document.getElementById('address-input').value = address;
|
||||||
|
// Add a note about resolution
|
||||||
|
const note = document.createElement('div');
|
||||||
|
note.className = 'success-message';
|
||||||
|
note.style.marginBottom = '1rem';
|
||||||
|
note.innerHTML = `Resolved alias <strong>${hip02Result.name || address}</strong> to address`;
|
||||||
|
resultElement.parentNode.insertBefore(note, resultElement);
|
||||||
|
setTimeout(() => note.remove(), 5000);
|
||||||
|
} else {
|
||||||
|
resultElement.innerHTML = `<div class="error">HIP02 Error: ${hip02Result.error || 'Could not resolve alias'}</div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateURL('address', address);
|
updateURL('address', address);
|
||||||
const data = await apiCall(`tx/address/${address}`);
|
const data = await apiCall(`tx/address/${address}`);
|
||||||
|
|
||||||
// Use formatted display instead of raw JSON
|
// Use formatted display instead of raw JSON
|
||||||
const resultElement = document.getElementById('address-result');
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -1020,16 +1076,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function searchAddressCoins() {
|
async function searchAddressCoins() {
|
||||||
const address = document.getElementById('address-input').value.trim().replace(/,/g, '');
|
let address = document.getElementById('address-input').value.trim().replace(/,/g, '');
|
||||||
if (!address) {
|
if (!address) {
|
||||||
alert('Please enter an address');
|
alert('Please enter an address');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('address-result');
|
||||||
|
const resultElement = document.getElementById('address-result');
|
||||||
|
|
||||||
|
// Check for HIP02 alias
|
||||||
|
if (address.startsWith('@')) {
|
||||||
|
const hip02Result = await resolveHip02(address);
|
||||||
|
if (hip02Result.success && hip02Result.address) {
|
||||||
|
address = hip02Result.address;
|
||||||
|
// Update input to show resolved address
|
||||||
|
document.getElementById('address-input').value = address;
|
||||||
|
} else {
|
||||||
|
resultElement.innerHTML = `<div class="error">HIP02 Error: ${hip02Result.error || 'Could not resolve alias'}</div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateURL('address', address);
|
updateURL('address', address);
|
||||||
const data = await apiCall(`coin/address/${address}`);
|
const data = await apiCall(`coin/address/${address}`);
|
||||||
|
|
||||||
// Use formatted display instead of raw JSON
|
// Use formatted display instead of raw JSON
|
||||||
const resultElement = document.getElementById('address-result');
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -1043,6 +1115,8 @@
|
|||||||
alert('Please enter a name');
|
alert('Please enter a name');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('name-result');
|
||||||
const punyName = toPunycode(name);
|
const punyName = toPunycode(name);
|
||||||
updateURL('name', punyName);
|
updateURL('name', punyName);
|
||||||
const data = await apiCall(`name/${punyName}`);
|
const data = await apiCall(`name/${punyName}`);
|
||||||
@@ -1062,6 +1136,8 @@
|
|||||||
alert('Please enter a name');
|
alert('Please enter a name');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('name-result');
|
||||||
const punyName = toPunycode(name);
|
const punyName = toPunycode(name);
|
||||||
const data = await apiCall(`nameresource/${punyName}`);
|
const data = await apiCall(`nameresource/${punyName}`);
|
||||||
|
|
||||||
@@ -1080,6 +1156,8 @@
|
|||||||
alert('Please enter a name');
|
alert('Please enter a name');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('name-result');
|
||||||
const punyName = toPunycode(name);
|
const punyName = toPunycode(name);
|
||||||
const data = await apiCall(`namesummary/${punyName}`);
|
const data = await apiCall(`namesummary/${punyName}`);
|
||||||
|
|
||||||
@@ -1098,6 +1176,8 @@
|
|||||||
alert('Please enter a name hash');
|
alert('Please enter a name hash');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLoading('name-result');
|
||||||
const data = await apiCall(`namehash/${nameHash}`);
|
const data = await apiCall(`namehash/${nameHash}`);
|
||||||
|
|
||||||
// Check if result is valid and redirect to name page
|
// Check if result is valid and redirect to name page
|
||||||
@@ -1112,25 +1192,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchCoin() {
|
|
||||||
const coinHash = document.getElementById('coin-hash').value.trim().replace(/,/g, '');
|
|
||||||
const coinIndex = document.getElementById('coin-index').value.trim().replace(/,/g, '');
|
|
||||||
if (!coinHash || !coinIndex) {
|
|
||||||
alert('Please enter both coin hash and index');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateURL('coin', `${coinHash}/${coinIndex}`);
|
|
||||||
const data = await apiCall(`coin/${coinHash}/${coinIndex}`);
|
|
||||||
|
|
||||||
// Use formatted display instead of raw JSON
|
|
||||||
const resultElement = document.getElementById('coin-result');
|
|
||||||
if (data.error) {
|
|
||||||
resultElement.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
|
||||||
} else {
|
|
||||||
resultElement.innerHTML = formatCoin(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load status when page loads
|
// Load status when page loads
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
loadStatus();
|
loadStatus();
|
||||||
|
|||||||
225
tools.py
Normal file
225
tools.py
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
import dns.resolver
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
import tempfile
|
||||||
|
import subprocess
|
||||||
|
import binascii
|
||||||
|
import datetime
|
||||||
|
import dns.asyncresolver
|
||||||
|
import dns.message
|
||||||
|
import dns.query
|
||||||
|
import dns.rdatatype
|
||||||
|
import httpx
|
||||||
|
from requests_doh import DNSOverHTTPSSession, add_dns_provider
|
||||||
|
import urllib3
|
||||||
|
from cryptography.x509.oid import ExtensionOID
|
||||||
|
|
||||||
|
urllib3.disable_warnings(
|
||||||
|
urllib3.exceptions.InsecureRequestWarning
|
||||||
|
) # Disable insecure request warnings (since we are manually verifying the certificate)
|
||||||
|
|
||||||
|
|
||||||
|
def hip2(domain: str) -> str | None:
|
||||||
|
domain_check = False
|
||||||
|
try:
|
||||||
|
# Get the IP
|
||||||
|
ip = resolve_with_doh(domain)
|
||||||
|
|
||||||
|
# Run the openssl s_client command
|
||||||
|
s_client_command = [
|
||||||
|
"openssl",
|
||||||
|
"s_client",
|
||||||
|
"-showcerts",
|
||||||
|
"-connect",
|
||||||
|
f"{ip}:443",
|
||||||
|
"-servername",
|
||||||
|
domain,
|
||||||
|
]
|
||||||
|
|
||||||
|
s_client_process = subprocess.Popen(
|
||||||
|
s_client_command,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
s_client_output, _ = s_client_process.communicate(input=b"\n")
|
||||||
|
|
||||||
|
certificates = []
|
||||||
|
current_cert = ""
|
||||||
|
for line in s_client_output.split(b"\n"):
|
||||||
|
current_cert += line.decode("utf-8") + "\n"
|
||||||
|
if "-----END CERTIFICATE-----" in line.decode("utf-8"):
|
||||||
|
certificates.append(current_cert)
|
||||||
|
current_cert = ""
|
||||||
|
|
||||||
|
# Remove anything before -----BEGIN CERTIFICATE-----
|
||||||
|
certificates = [
|
||||||
|
cert[cert.find("-----BEGIN CERTIFICATE-----") :] for cert in certificates
|
||||||
|
]
|
||||||
|
|
||||||
|
if certificates:
|
||||||
|
cert = certificates[0]
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_cert_file:
|
||||||
|
temp_cert_file.write(cert)
|
||||||
|
temp_cert_file.seek(
|
||||||
|
0
|
||||||
|
) # Move back to the beginning of the temporary file
|
||||||
|
|
||||||
|
tlsa_command = [
|
||||||
|
"openssl",
|
||||||
|
"x509",
|
||||||
|
"-in",
|
||||||
|
temp_cert_file.name,
|
||||||
|
"-pubkey",
|
||||||
|
"-noout",
|
||||||
|
"|",
|
||||||
|
"openssl",
|
||||||
|
"pkey",
|
||||||
|
"-pubin",
|
||||||
|
"-outform",
|
||||||
|
"der",
|
||||||
|
"|",
|
||||||
|
"openssl",
|
||||||
|
"dgst",
|
||||||
|
"-sha256",
|
||||||
|
"-binary",
|
||||||
|
]
|
||||||
|
|
||||||
|
tlsa_process = subprocess.Popen(
|
||||||
|
" ".join(tlsa_command), shell=True, stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
tlsa_output, _ = tlsa_process.communicate()
|
||||||
|
|
||||||
|
tlsa_server = "3 1 1 " + binascii.hexlify(tlsa_output).decode("utf-8")
|
||||||
|
|
||||||
|
# Get domains
|
||||||
|
cert_obj = x509.load_pem_x509_certificate(
|
||||||
|
cert.encode("utf-8"), default_backend()
|
||||||
|
)
|
||||||
|
|
||||||
|
domains = []
|
||||||
|
for ext in cert_obj.extensions:
|
||||||
|
if ext.oid == ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
|
||||||
|
san_list = ext.value.get_values_for_type(x509.DNSName)
|
||||||
|
domains.extend(san_list)
|
||||||
|
|
||||||
|
# Extract the common name (CN) from the subject
|
||||||
|
common_name = cert_obj.subject.get_attributes_for_oid(
|
||||||
|
x509.NameOID.COMMON_NAME
|
||||||
|
)
|
||||||
|
if common_name:
|
||||||
|
if common_name[0].value not in domains:
|
||||||
|
domains.append(common_name[0].value)
|
||||||
|
|
||||||
|
if domains:
|
||||||
|
if domain in domains:
|
||||||
|
domain_check = True
|
||||||
|
else:
|
||||||
|
# Check if matching wildcard domain exists
|
||||||
|
for d in domains:
|
||||||
|
if d.startswith("*"):
|
||||||
|
if domain.split(".")[1:] == d.split(".")[1:]:
|
||||||
|
domain_check = True
|
||||||
|
break
|
||||||
|
|
||||||
|
expiry_date = cert_obj.not_valid_after_utc
|
||||||
|
# Check if expiry date is past
|
||||||
|
if expiry_date < datetime.datetime.now(datetime.timezone.utc):
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check for TLSA record
|
||||||
|
tlsa = resolve_TLSA_with_doh(domain)
|
||||||
|
|
||||||
|
if not tlsa:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if tlsa_server == str(tlsa):
|
||||||
|
if domain_check:
|
||||||
|
# Get the Hip2 addresss from /.well-known/wallets/HNS
|
||||||
|
add_dns_provider("HNSDoH", "https://au.hnsdoh.com/dns-query")
|
||||||
|
|
||||||
|
session = DNSOverHTTPSSession("HNSDoH")
|
||||||
|
r = session.get(
|
||||||
|
f"https://{domain}/.well-known/wallets/HNS", verify=False
|
||||||
|
)
|
||||||
|
return r.text
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Hip2: TLSA lookup/verification failed with error: {e}", flush=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Catch all exceptions
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Hip2: Lookup failed with error: {e}", flush=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def wallet_txt(domain: str, doh_url="https://au.hnsdoh.com/dns-query") -> str | None:
|
||||||
|
with httpx.Client() as client:
|
||||||
|
q = dns.message.make_query(domain, dns.rdatatype.from_text("TYPE262"))
|
||||||
|
r = dns.query.https(q, doh_url, session=client)
|
||||||
|
|
||||||
|
if not r.answer:
|
||||||
|
return
|
||||||
|
|
||||||
|
wallet_record = None
|
||||||
|
for ans in r.answer:
|
||||||
|
raw = ans[0].to_wire() # type: ignore
|
||||||
|
try:
|
||||||
|
data = raw[1:].decode("utf-8", errors="ignore")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return f"Unknown WALLET record format: {raw.hex()}"
|
||||||
|
|
||||||
|
if data.startswith("HNS:"):
|
||||||
|
wallet_record = data[4:]
|
||||||
|
break
|
||||||
|
elif data.startswith("HNS "):
|
||||||
|
wallet_record = data[4:]
|
||||||
|
break
|
||||||
|
elif data.startswith('"HNS" '):
|
||||||
|
wallet_record = data[6:].strip('"')
|
||||||
|
break
|
||||||
|
return wallet_record
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_with_doh(query_name, doh_url="https://au.hnsdoh.com/dns-query"):
|
||||||
|
with httpx.Client() as client:
|
||||||
|
q = dns.message.make_query(query_name, dns.rdatatype.A)
|
||||||
|
r = dns.query.https(q, doh_url, session=client)
|
||||||
|
|
||||||
|
ip = r.answer[0][0].address # type: ignore
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_TLSA_with_doh(query_name, doh_url="https://au.hnsdoh.com/dns-query"):
|
||||||
|
query_name = "_443._tcp." + query_name
|
||||||
|
with httpx.Client() as client:
|
||||||
|
q = dns.message.make_query(query_name, dns.rdatatype.TLSA)
|
||||||
|
r = dns.query.https(q, doh_url, session=client)
|
||||||
|
|
||||||
|
tlsa = r.answer[0][0]
|
||||||
|
return tlsa
|
||||||
|
|
||||||
|
|
||||||
|
def emoji_to_punycode(emoji):
|
||||||
|
try:
|
||||||
|
return emoji.encode("idna").decode("ascii")
|
||||||
|
except Exception:
|
||||||
|
return emoji
|
||||||
|
|
||||||
|
|
||||||
|
def punycode_to_emoji(punycode):
|
||||||
|
try:
|
||||||
|
return punycode.encode("ascii").decode("idna")
|
||||||
|
except Exception:
|
||||||
|
return punycode
|
||||||
255
uv.lock
generated
255
uv.lock
generated
@@ -2,6 +2,19 @@ version = 1
|
|||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.11.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "sniffio" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blinker"
|
name = "blinker"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@@ -20,6 +33,51 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
|
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfgv"
|
name = "cfgv"
|
||||||
version = "3.5.0"
|
version = "3.5.0"
|
||||||
@@ -91,6 +149,62 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cryptography"
|
||||||
|
version = "46.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "distlib"
|
name = "distlib"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -100,6 +214,22 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
|
{ url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dnspython"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/37/7d/c871f55054e403fdfd6b8f65fd6d1c4e147ed100d3e9f9ba1fe695403939/dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc", size = 332727, upload-time = "2024-02-18T18:48:48.952Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696, upload-time = "2024-02-18T18:48:46.786Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
doh = [
|
||||||
|
{ name = "h2" },
|
||||||
|
{ name = "httpcore" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.20.0"
|
version = "3.20.0"
|
||||||
@@ -138,6 +268,74 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h11"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "4.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "hpack" },
|
||||||
|
{ name = "hyperframe" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hpack"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "httpcore" },
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyperframe"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.6.15"
|
version = "2.6.15"
|
||||||
@@ -272,6 +470,24 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/27/11/574fe7d13acf30bfd0a8dd7fa1647040f2b8064f13f43e8c963b1e65093b/pre_commit-4.4.0-py2.py3-none-any.whl", hash = "sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813", size = 226049, upload-time = "2025-11-08T21:12:10.228Z" },
|
{ url = "https://files.pythonhosted.org/packages/27/11/574fe7d13acf30bfd0a8dd7fa1647040f2b8064f13f43e8c963b1e65093b/pre_commit-4.4.0-py2.py3-none-any.whl", hash = "sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813", size = 226049, upload-time = "2025-11-08T21:12:10.228Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.23"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pysocks"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -286,10 +502,11 @@ name = "python-webserver-template"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "cryptography" },
|
||||||
{ name = "flask" },
|
{ name = "flask" },
|
||||||
{ name = "gunicorn" },
|
{ name = "gunicorn" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
{ name = "requests" },
|
{ name = "requests-doh" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
@@ -300,10 +517,11 @@ dev = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "cryptography", specifier = ">=46.0.3" },
|
||||||
{ name = "flask", specifier = ">=3.1.2" },
|
{ name = "flask", specifier = ">=3.1.2" },
|
||||||
{ name = "gunicorn", specifier = ">=23.0.0" },
|
{ name = "gunicorn", specifier = ">=23.0.0" },
|
||||||
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
||||||
{ name = "requests", specifier = ">=2.32.5" },
|
{ name = "requests-doh", specifier = ">=1.0.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
@@ -350,7 +568,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.5"
|
version = "2.32.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "certifi" },
|
{ name = "certifi" },
|
||||||
@@ -358,9 +576,27 @@ dependencies = [
|
|||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "urllib3" },
|
{ name = "urllib3" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
socks = [
|
||||||
|
{ name = "pysocks" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests-doh"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "dnspython", extra = ["doh"] },
|
||||||
|
{ name = "requests", extra = ["socks"] },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a3/8d/d9b24a0c0975c9330bcc152af2b5c9a34fa5af0307c10366fdc27e75f24e/requests_doh-1.0.0.tar.gz", hash = "sha256:6ce8bc96245030a198ef20d2100b4dcb3b120a05a58df703f8be121a79f8f2fb", size = 13126, upload-time = "2024-09-07T13:42:55.394Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/f1/79f00f86e53510b75a14dc500286f351550cc8207c81e7de1f38072fbcac/requests_doh-1.0.0-py3-none-any.whl", hash = "sha256:eea6583b792b7d3dfde74fd28eedc2b95d6ea896368119eede31f0d6ff2c838c", size = 13879, upload-time = "2024-09-07T13:42:54.189Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -389,6 +625,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" },
|
{ url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sniffio"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user