├── .dockerignore ├── .github ├── FUNDING.yml └── workflows │ ├── docker-image.yml │ └── lint-python.yml ├── .gitignore ├── .gitmodules ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── entrypoint.sh ├── fogeth ├── Dockerfile ├── README.md ├── entrypoint.sh ├── genesis.json.template └── proxy │ ├── eth-jsonrpc-access.js │ └── nginx.conf ├── pyproject.toml ├── requirements-dev.in ├── requirements-dev.txt ├── requirements.in ├── requirements.txt ├── server.py ├── solidctf ├── __init__.py ├── config.py ├── ethereum.py ├── protobuf │ └── challenge.proto ├── rpc_proxy.py └── service.py └── web ├── .gitignore ├── .prettierrc ├── assets ├── background.jpg └── style.css ├── package.json ├── src ├── app.js └── index.html ├── webpack.config.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | **/*.py[cod] 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: "https://gitcoin.co/grants/6541/chainflag" 14 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | tags: [v*] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | docker: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | submodules: 'true' 17 | 18 | - name: Docker meta 19 | id: meta 20 | uses: docker/metadata-action@v3 21 | with: 22 | images: ${{ secrets.DOCKERHUB_USERNAME }}/solidctf 23 | tags: | 24 | type=ref,event=branch 25 | type=ref,event=pr 26 | type=semver,pattern={{version}} 27 | type=semver,pattern={{major}}.{{minor}} 28 | 29 | - name: Login to DockerHub 30 | uses: docker/login-action@v1 31 | with: 32 | username: ${{ secrets.DOCKERHUB_USERNAME }} 33 | password: ${{ secrets.DOCKERHUB_TOKEN }} 34 | 35 | - name: Build and push 36 | uses: docker/build-push-action@v2 37 | with: 38 | context: . 39 | push: ${{ github.event_name != 'pull_request' }} 40 | tags: ${{ steps.meta.outputs.tags }} 41 | labels: ${{ steps.meta.outputs.labels }} 42 | -------------------------------------------------------------------------------- /.github/workflows/lint-python.yml: -------------------------------------------------------------------------------- 1 | name: Lint Python 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Set up Python 3.9 16 | uses: actions/setup-python@v2 17 | with: 18 | python-version: 3.9 19 | 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install -r requirements.txt 24 | pip install -r requirements-dev.txt 25 | 26 | - name: Lint 27 | run: make lint 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | #.env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # brownie 132 | .history 133 | reports/ 134 | 135 | # other 136 | .idea/ 137 | .DS_Store 138 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "example"] 2 | path = example 3 | url = git@github.com:chainflag/solidity-ctf-template.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-buster as protoc 2 | 3 | WORKDIR /protobuf-build 4 | 5 | RUN apt update && apt install unzip 6 | RUN go install github.com/verloop/twirpy/protoc-gen-twirpy@latest 7 | RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.5/protoc-3.19.5-linux-x86_64.zip && unzip protoc-3.19.5-linux-x86_64.zip && cp bin/protoc /bin/protoc 8 | 9 | COPY solidctf/protobuf protobuf 10 | RUN protoc --python_out=. --twirpy_out=. protobuf/challenge.proto 11 | 12 | FROM node:lts-alpine as frontend 13 | 14 | WORKDIR /frontend-build 15 | 16 | COPY web/package.json web/yarn.lock ./ 17 | RUN yarn install 18 | 19 | COPY web ./ 20 | COPY solidctf/protobuf/challenge.proto . 21 | 22 | RUN apk add --no-cache protoc 23 | RUN yarn build 24 | 25 | FROM python:3.9-slim-buster 26 | 27 | WORKDIR /ctf 28 | 29 | COPY requirements.txt . 30 | RUN pip install -r requirements.txt 31 | 32 | COPY server.py . 33 | COPY solidctf solidctf 34 | COPY example/contracts contracts 35 | COPY example/challenge.yml challenge.yml 36 | 37 | COPY --from=protoc /protobuf-build/protobuf solidctf/protobuf 38 | COPY --from=frontend /frontend-build/dist web/dist 39 | 40 | COPY entrypoint.sh /entrypoint.sh 41 | RUN mkdir /var/log/ctf 42 | RUN chmod +x /entrypoint.sh 43 | 44 | CMD ["/entrypoint.sh"] 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ChainFlag 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dev: 2 | cd example && brownie compile 3 | DEBUG_MODE=True uvicorn server:app --reload 4 | 5 | protoc: 6 | docker build --target protoc -t protoc --platform linux/amd64 . 7 | docker run --name protoc protoc 8 | docker cp protoc:/protobuf-build/protobuf solidctf && docker rm protoc 9 | 10 | lint: 11 | mypy . 12 | black --check . --diff 13 | flake8 --ignore=E501,W503 --show-source 14 | isort --profile black . --check --diff 15 | 16 | format: 17 | black . 18 | isort --profile black . 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SolidCTF 2 | 3 | ![Docker CI](https://img.shields.io/github/actions/workflow/status/chainflag/solidctf/docker-image.yml?branch=main) 4 | ![Docker size](https://badgen.net/docker/size/chainflag/solidctf/latest?color=cyan) 5 | ![Latest tag](https://badgen.net/github/tag/chainflag/solidctf) 6 | ![License: MIT](https://badgen.net/github/license/chainflag/solidctf?color=yellow) 7 | 8 | SolidCTF is an infrastructure solution that simplifies the build of Solidity Capture the Flag (CTF) challenges. It provides the ability to CTF organizers to rapidly set up a playable Solidity CTF environment, freeing them up to concentrate on designing smart contracts for puzzles. 9 | 10 | ## Getting Started 11 | 12 | ### Quick Demo 13 | 14 | Use the following command to run a quick demo: 15 | 16 | ```bash 17 | docker run -it -p 20000:20000 -e WEB3_PROVIDER_URI=https://rpc.sepolia.org chainflag/solidctf:1.0 18 | nc 127.0.0.1 20000 19 | ``` 20 | 21 | ### Usage 22 | 23 | 1. Clone the [solidity-ctf-template](https://github.com/chainflag/solidity-ctf-template) using `git clone git@github.com:chainflag/solidity-ctf-template.git` command to create a new challenge project. 24 | 2. Open the contract directory and code your challenge contract that contains the [isSolved()](https://github.com/chainflag/solidity-ctf-template/blob/main/contracts/Example.sol#L19) to replace the example contract. For the multi-contract challenges, you can deploy them in a setup contract's constructor. 25 | 3. Edit the [challenge.yml](https://github.com/chainflag/solidity-ctf-template/blob/main/challenge.yml) to configure your challenge. See to the comments in this file for more details on how to configure it. 26 | 4. Place your flag in the file [flag.txt](https://github.com/chainflag/solidity-ctf-template/blob/main/flag.txt) file and change the alloc address private key in the [.env](https://github.com/chainflag/solidity-ctf-template/blob/main/.env) to your own. 27 | 5. Run the `docker-compose pull && docker-compose up -d` command to start serving your challenge. 28 | 29 | ## Development 30 | 31 | ### Prerequisites 32 | 33 | Before you start, make sure you have the following installed: 34 | 35 | * Docker 36 | * Python3 37 | * Required packages (`pip install -r requirements.txt`) 38 | 39 | ### Run in development mode 40 | 1. Clone the repository 41 | 42 | ```bash 43 | git clone git@github.com:chainflag/solidctf.git 44 | git submodule update --init --recursive 45 | ``` 46 | 47 | 2. Generate protobuf code and run server 48 | 49 | ```bash 50 | make protoc 51 | export WEB3_PROVIDER_URI="your web3 provider" 52 | make dev 53 | ``` 54 | 55 | ### Format python source 56 | 57 | To format the Python source code, you will need to install additional packages (`pip install -r requirements-dev.txt`) and run the following command: 58 | 59 | ```bash 60 | make format 61 | ``` 62 | 63 | ## Acknowledgements 64 | Many thanks to [JetBrains](https://jb.gg/OpenSourceSupport) for providing their excellent tools and an open source license to support the development of this project. 65 | 66 | ## License 67 | 68 | Distributed under the MIT License. See LICENSE for more information. 69 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | read -r -d '' COMPILE <<-'EOF' 4 | import os 5 | 6 | from brownie import project 7 | from solcx import install 8 | 9 | default = os.getenv( 10 | "SOLC_DOWNLOAD_BASE", "https://cdn.jsdelivr.net/gh/ethereum/solc-bin@latest" 11 | ).rstrip("/") 12 | install.BINARY_DOWNLOAD_BASE = default + "/{}-amd64/{}" 13 | project.load(".") 14 | EOF 15 | 16 | if ! python3 -c "$COMPILE"; then 17 | exit 1 18 | fi 19 | 20 | gunicorn server:app \ 21 | --bind "${HTTP_HOST:-0.0.0.0}":20000 \ 22 | --preload \ 23 | --workers 4 \ 24 | --worker-class uvicorn.workers.UvicornWorker \ 25 | --access-logfile /var/log/ctf/gunicorn.access.log \ 26 | --error-logfile /var/log/ctf/gunicorn.error.log \ 27 | --capture-output 28 | -------------------------------------------------------------------------------- /fogeth/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.22-alpine 2 | 3 | COPY proxy/eth-jsonrpc-access.js /etc/nginx 4 | COPY proxy/nginx.conf /etc/nginx 5 | 6 | COPY genesis.json.template /genesis.json.template 7 | COPY entrypoint.sh /entrypoint.sh 8 | RUN chmod +x /entrypoint.sh 9 | 10 | COPY --from=ethereum/client-go:v1.10.26 /usr/local/bin/geth /usr/local/bin/ 11 | 12 | EXPOSE 8545 13 | 14 | ENTRYPOINT ["/entrypoint.sh"] 15 | -------------------------------------------------------------------------------- /fogeth/README.md: -------------------------------------------------------------------------------- 1 | # Fogeth 2 | Fogeth is a private PoA Ethereum environment tailored for CTF challenges. It restricts access to only whitelisted RPC methods and cleans transaction data from `eth_getBlockByHash` and `eth_getBlockByNumber` responses. This prevents players from searching through blockchain history to find and copy others' transactions and solutions, thereby ensuring fairness in CTF challenges. 3 | 4 | ## Getting Started 5 | 6 | ### Clone the Repository 7 | 8 | ``` 9 | git clone https://github.com/chainflag/solidctf.git 10 | cd solidctf/fogeth 11 | ``` 12 | 13 | ### Start the Node 14 | ```bash 15 | docker build -t chainflag/fogeth . 16 | docker run -d -p 8545:8545 -e ALLOC_ADDRESS_PRIVATE_KEY="private key" chainflag/fogeth 17 | ``` 18 | -------------------------------------------------------------------------------- /fogeth/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | GETH_DATA_DIR=/data 5 | GETH_CHAINDATA_DIR=$GETH_DATA_DIR/geth/chaindata 6 | GETH_KEYSTORE_DIR=$GETH_DATA_DIR/keystore 7 | 8 | CHAIN_ID="${CHAIN_ID:-$((RANDOM + 10000))}" 9 | 10 | [ -f "$GETH_DATA_DIR/alloc-address" ] && ALLOC_ADDRESS_WITHOUT_0X=$(cat "$GETH_DATA_DIR/alloc-address") 11 | [ ! -d "$GETH_DATA_DIR" ] && mkdir "$GETH_DATA_DIR" 12 | 13 | if [ ! -d "$GETH_KEYSTORE_DIR" ]; then 14 | echo "$GETH_KEYSTORE_DIR missing, running account import" 15 | echo -n "$ALLOC_ADDRESS_PRIVATE_KEY" >"$GETH_DATA_DIR/private-key" 16 | echo -n "${ALLOC_ADDRESS_PRIVATE_KEY_PASSWORD:-chainflag}" >"$GETH_DATA_DIR/password" 17 | ALLOC_ADDRESS_WITHOUT_0X=$(geth account import \ 18 | --datadir="$GETH_DATA_DIR" \ 19 | --password="$GETH_DATA_DIR/password" \ 20 | "$GETH_DATA_DIR/private-key" | grep -oE '[[:xdigit:]]{40}') 21 | echo -n "$ALLOC_ADDRESS_WITHOUT_0X" >"$GETH_DATA_DIR/alloc-address" 22 | echo "geth account import complete" 23 | fi 24 | 25 | if [ ! -d "$GETH_CHAINDATA_DIR" ]; then 26 | echo "$GETH_CHAINDATA_DIR missing, running init" 27 | sed "s/\${CHAIN_ID}/$CHAIN_ID/g; s/\${ALLOC_ADDRESS_WITHOUT_0X}/$ALLOC_ADDRESS_WITHOUT_0X/g" /genesis.json.template >/genesis.json 28 | geth init --datadir="$GETH_DATA_DIR" /genesis.json 29 | echo "geth init complete" 30 | fi 31 | 32 | exec geth \ 33 | --datadir="$GETH_DATA_DIR" \ 34 | --password="$GETH_DATA_DIR/password" \ 35 | --allow-insecure-unlock \ 36 | --unlock="$ALLOC_ADDRESS_WITHOUT_0X" \ 37 | --mine \ 38 | --networkid="$CHAIN_ID" --nodiscover \ 39 | --http --http.addr=0.0.0.0 --http.port=18545 \ 40 | --http.api=eth,net,web3 \ 41 | --http.corsdomain='*' --http.vhosts='*' & 42 | 43 | exec nginx -g "daemon off;" 44 | -------------------------------------------------------------------------------- /fogeth/genesis.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "chainId": ${CHAIN_ID}, 4 | "homesteadBlock": 0, 5 | "eip150Block": 0, 6 | "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 7 | "eip155Block": 0, 8 | "eip158Block": 0, 9 | "byzantiumBlock": 0, 10 | "constantinopleBlock": 0, 11 | "petersburgBlock": 0, 12 | "istanbulBlock": 0, 13 | "berlinBlock": 0, 14 | "londonBlock": 0, 15 | "clique": { 16 | "period": 5, 17 | "epoch": 30000 18 | } 19 | }, 20 | "nonce": "0x0", 21 | "timestamp": "0x609ac710", 22 | "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000${ALLOC_ADDRESS_WITHOUT_0X}0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 23 | "gasLimit": "0x1312d00", 24 | "difficulty": "0x1", 25 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 26 | "coinbase": "0x0000000000000000000000000000000000000000", 27 | "alloc": { 28 | "0000000000000000000000000000000000000000": { 29 | "balance": "0x10000000000000000" 30 | }, 31 | "${ALLOC_ADDRESS_WITHOUT_0X}": { 32 | "balance": "0x200000000000000000000000000000000000000000000000000000000000000" 33 | } 34 | }, 35 | "number": "0x0", 36 | "gasUsed": "0x0", 37 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 38 | "baseFeePerGas": null 39 | } -------------------------------------------------------------------------------- /fogeth/proxy/eth-jsonrpc-access.js: -------------------------------------------------------------------------------- 1 | function access(r) { 2 | r.headersOut["Content-Type"] = "application/json"; 3 | try { 4 | var payload = JSON.parse(r.requestBody); 5 | } catch (error) { 6 | r.return(415, createErrorResponse(-32700, "Parse error", null)); 7 | return; 8 | } 9 | 10 | var errorResponse = validateMethod(payload); 11 | if (errorResponse) { 12 | r.return(401, errorResponse); 13 | return; 14 | } 15 | 16 | r.subrequest("/rpc") 17 | .then((res) => { 18 | var responseBody = res.responseBody; 19 | if ( 20 | payload.method === "eth_getBlockByHash" || 21 | payload.method === "eth_getBlockByNumber" 22 | ) { 23 | var data = JSON.parse(res.responseBody); 24 | if (data.result) { 25 | data.result.transactions = []; 26 | } 27 | responseBody = JSON.stringify(data); 28 | } 29 | r.return(res.status, responseBody); 30 | }) 31 | .catch((_) => r.return(500)); 32 | } 33 | 34 | function createErrorResponse(code, message, id) { 35 | return JSON.stringify({ 36 | jsonrpc: "2.0", 37 | error: { 38 | code, 39 | message, 40 | }, 41 | id, 42 | }); 43 | } 44 | 45 | function validateMethod(payload) { 46 | var whitelist = [ 47 | "eth_blockNumber", 48 | "eth_call", 49 | "eth_chainId", 50 | "eth_estimateGas", 51 | "eth_feeHistory", 52 | "eth_gasPrice", 53 | "eth_getBalance", 54 | "eth_getBlockByHash", 55 | "eth_getBlockByNumber", 56 | "eth_getCode", 57 | "eth_getStorageAt", 58 | "eth_getTransactionByHash", 59 | "eth_getTransactionCount", 60 | "eth_getTransactionReceipt", 61 | "eth_sendRawTransaction", 62 | "net_version", 63 | "rpc_modules", 64 | "web3_clientVersion", 65 | ]; 66 | 67 | if ( 68 | Object.keys(payload).filter((key) => key.toLowerCase() === "method") 69 | .length !== 1 70 | ) { 71 | return createErrorResponse(-32600, "Invalid request", payload.id); 72 | } 73 | 74 | if (!whitelist.includes(payload.method)) { 75 | return createErrorResponse(-32004, "Method not supported", payload.id); 76 | } 77 | } 78 | 79 | export default { access }; 80 | -------------------------------------------------------------------------------- /fogeth/proxy/nginx.conf: -------------------------------------------------------------------------------- 1 | load_module modules/ngx_http_js_module.so; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | js_path "/etc/nginx/njs/"; 9 | 10 | js_import main from eth-jsonrpc-access.js; 11 | 12 | log_format format escape=none '$remote_addr - [$time_local] ' 13 | '"$request" $status "$http_user_agent" "$request_body"'; 14 | 15 | server { 16 | listen 8545; 17 | client_body_buffer_size 128k; 18 | subrequest_output_buffer_size 128k; 19 | 20 | if ($request_method !~ ^(POST)$) { 21 | return 403; 22 | } 23 | 24 | location / { 25 | access_log /var/log/nginx/access.log format; 26 | js_content main.access; 27 | } 28 | 29 | location /rpc { 30 | internal; 31 | gunzip on; 32 | proxy_pass http://localhost:18545/; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [project] 6 | name = "solidctf" 7 | authors = [{name = "chainflag"}] 8 | readme = "README.md" 9 | license = {file = "LICENSE"} 10 | classifiers = ["License :: OSI Approved :: MIT License"] 11 | dynamic = ["version", "description"] 12 | 13 | [tool.mypy] 14 | check_untyped_defs = true 15 | ignore_missing_imports = true 16 | no_implicit_optional = true 17 | show_column_numbers = true 18 | show_error_codes = true 19 | show_error_context = true 20 | strict_optional = true 21 | -------------------------------------------------------------------------------- /requirements-dev.in: -------------------------------------------------------------------------------- 1 | black 2 | flake8 3 | flit 4 | isort 5 | mypy 6 | pip-tools 7 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # pip-compile requirements-dev.in 6 | # 7 | black==23.1.0 8 | # via -r requirements-dev.in 9 | build==0.10.0 10 | # via pip-tools 11 | certifi==2022.12.7 12 | # via requests 13 | charset-normalizer==3.1.0 14 | # via requests 15 | click==8.1.3 16 | # via 17 | # black 18 | # pip-tools 19 | docutils==0.19 20 | # via flit 21 | flake8==6.0.0 22 | # via -r requirements-dev.in 23 | flit==3.8.0 24 | # via -r requirements-dev.in 25 | flit-core==3.8.0 26 | # via flit 27 | idna==3.4 28 | # via requests 29 | isort==5.12.0 30 | # via -r requirements-dev.in 31 | mccabe==0.7.0 32 | # via flake8 33 | mypy==1.1.1 34 | # via -r requirements-dev.in 35 | mypy-extensions==1.0.0 36 | # via 37 | # black 38 | # mypy 39 | packaging==23.0 40 | # via 41 | # black 42 | # build 43 | pathspec==0.11.0 44 | # via black 45 | pip-tools==6.12.2 46 | # via -r requirements-dev.in 47 | platformdirs==3.0.0 48 | # via black 49 | pycodestyle==2.10.0 50 | # via flake8 51 | pyflakes==3.0.1 52 | # via flake8 53 | pyproject-hooks==1.0.0 54 | # via build 55 | requests==2.28.2 56 | # via flit 57 | tomli==2.0.1 58 | # via 59 | # black 60 | # build 61 | # mypy 62 | tomli-w==1.0.0 63 | # via flit 64 | typing-extensions==4.4.0 65 | # via 66 | # black 67 | # mypy 68 | urllib3==1.26.15 69 | # via requests 70 | wheel==0.38.4 71 | # via pip-tools 72 | 73 | # The following packages are considered to be unsafe in a requirements file: 74 | # pip 75 | # setuptools 76 | -------------------------------------------------------------------------------- /requirements.in: -------------------------------------------------------------------------------- 1 | aiohttp>=3.5.0,<4 2 | eth-brownie>=1.19.0,<2.0.0 3 | gunicorn>=20.1.0 4 | hexbytes<1 5 | pyseto>=1.7.0,<2 6 | pyyaml>=5.4.0,<6 7 | types-PyYAML>=6 8 | rlp<3 9 | starlette>=0.30.0 10 | twirp>=0.0.7 11 | uvicorn>=0.20.0 12 | web3>=5.31.3,<6 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # pip-compile 6 | # 7 | aiohttp==3.8.3 8 | # via 9 | # -r requirements.in 10 | # eth-brownie 11 | # web3 12 | aiosignal==1.2.0 13 | # via 14 | # aiohttp 15 | # eth-brownie 16 | anyio==3.7.1 17 | # via starlette 18 | argon2-cffi==21.3.0 19 | # via passlib 20 | argon2-cffi-bindings==21.2.0 21 | # via argon2-cffi 22 | asttokens==2.0.5 23 | # via 24 | # eth-brownie 25 | # vyper 26 | async-timeout==4.0.2 27 | # via 28 | # aiohttp 29 | # eth-brownie 30 | attrs==22.1.0 31 | # via 32 | # aiohttp 33 | # eth-brownie 34 | # hypothesis 35 | # jsonschema 36 | # pytest 37 | base58==2.1.1 38 | # via 39 | # eth-brownie 40 | # multiaddr 41 | bitarray==2.6.0 42 | # via 43 | # eth-account 44 | # eth-brownie 45 | black==22.10.0 46 | # via eth-brownie 47 | certifi==2022.9.24 48 | # via 49 | # eth-brownie 50 | # requests 51 | cffi==1.15.1 52 | # via 53 | # argon2-cffi-bindings 54 | # cryptography 55 | charset-normalizer==2.1.1 56 | # via 57 | # aiohttp 58 | # eth-brownie 59 | # requests 60 | click==8.1.3 61 | # via 62 | # black 63 | # eth-brownie 64 | # uvicorn 65 | cryptography==39.0.1 66 | # via pyseto 67 | cytoolz==0.12.0 68 | # via 69 | # eth-brownie 70 | # eth-keyfile 71 | # eth-utils 72 | dataclassy==0.11.1 73 | # via 74 | # eip712 75 | # eth-brownie 76 | eip712==0.1.0 77 | # via eth-brownie 78 | eth-abi==2.2.0 79 | # via 80 | # eip712 81 | # eth-account 82 | # eth-brownie 83 | # eth-event 84 | # web3 85 | eth-account==0.5.9 86 | # via 87 | # eth-brownie 88 | # web3 89 | eth-brownie==1.19.3 90 | # via -r requirements.in 91 | eth-event==1.2.3 92 | # via eth-brownie 93 | eth-hash[pycryptodome]==0.3.3 94 | # via 95 | # eth-brownie 96 | # eth-event 97 | # eth-utils 98 | # web3 99 | eth-keyfile==0.5.1 100 | # via 101 | # eth-account 102 | # eth-brownie 103 | eth-keys==0.3.4 104 | # via 105 | # eth-account 106 | # eth-brownie 107 | # eth-keyfile 108 | eth-rlp==0.2.1 109 | # via 110 | # eth-account 111 | # eth-brownie 112 | # web3 113 | eth-typing==2.3.0 114 | # via 115 | # eip712 116 | # eth-abi 117 | # eth-brownie 118 | # eth-keys 119 | # eth-utils 120 | # web3 121 | eth-utils==1.10.0 122 | # via 123 | # eip712 124 | # eth-abi 125 | # eth-account 126 | # eth-brownie 127 | # eth-event 128 | # eth-keyfile 129 | # eth-keys 130 | # eth-rlp 131 | # rlp 132 | # web3 133 | exceptiongroup==1.1.2 134 | # via anyio 135 | execnet==1.9.0 136 | # via 137 | # eth-brownie 138 | # pytest-xdist 139 | frozenlist==1.3.1 140 | # via 141 | # aiohttp 142 | # aiosignal 143 | # eth-brownie 144 | gunicorn==20.1.0 145 | # via -r requirements.in 146 | h11==0.14.0 147 | # via uvicorn 148 | hexbytes==0.2.3 149 | # via 150 | # -r requirements.in 151 | # eip712 152 | # eth-account 153 | # eth-brownie 154 | # eth-event 155 | # eth-rlp 156 | # web3 157 | hypothesis==6.27.3 158 | # via eth-brownie 159 | idna==3.4 160 | # via 161 | # anyio 162 | # eth-brownie 163 | # requests 164 | # yarl 165 | inflection==0.5.0 166 | # via 167 | # eth-brownie 168 | # mythx-models 169 | # pythx 170 | iniconfig==1.1.1 171 | # via 172 | # eth-brownie 173 | # pytest 174 | ipfshttpclient==0.8.0a2 175 | # via 176 | # eth-brownie 177 | # web3 178 | iso8601==1.1.0 179 | # via pyseto 180 | jsonschema==3.2.0 181 | # via 182 | # eth-brownie 183 | # mythx-models 184 | # web3 185 | lazy-object-proxy==1.7.1 186 | # via eth-brownie 187 | lru-dict==1.1.8 188 | # via 189 | # eth-brownie 190 | # web3 191 | multiaddr==0.0.9 192 | # via 193 | # eth-brownie 194 | # ipfshttpclient 195 | multidict==6.0.2 196 | # via 197 | # aiohttp 198 | # eth-brownie 199 | # yarl 200 | mypy-extensions==0.4.3 201 | # via 202 | # black 203 | # eth-brownie 204 | mythx-models==1.9.1 205 | # via 206 | # eth-brownie 207 | # pythx 208 | netaddr==0.8.0 209 | # via 210 | # eth-brownie 211 | # multiaddr 212 | packaging==21.3 213 | # via 214 | # eth-brownie 215 | # pytest 216 | parsimonious==0.8.1 217 | # via 218 | # eth-abi 219 | # eth-brownie 220 | passlib[argon2]==1.7.4 221 | # via pyseto 222 | pathspec==0.10.1 223 | # via 224 | # black 225 | # eth-brownie 226 | platformdirs==2.5.2 227 | # via 228 | # black 229 | # eth-brownie 230 | pluggy==1.0.0 231 | # via 232 | # eth-brownie 233 | # pytest 234 | prompt-toolkit==3.0.31 235 | # via eth-brownie 236 | protobuf==3.19.5 237 | # via 238 | # eth-brownie 239 | # twirp 240 | # web3 241 | psutil==5.9.2 242 | # via eth-brownie 243 | py==1.11.0 244 | # via 245 | # eth-brownie 246 | # pytest 247 | # pytest-forked 248 | py-solc-ast==1.2.9 249 | # via eth-brownie 250 | py-solc-x==1.1.1 251 | # via eth-brownie 252 | pycparser==2.21 253 | # via cffi 254 | pycryptodome==3.15.0 255 | # via 256 | # eip712 257 | # eth-brownie 258 | # eth-hash 259 | # eth-keyfile 260 | # vyper 261 | pycryptodomex==3.17 262 | # via pyseto 263 | pygments==2.13.0 264 | # via 265 | # eth-brownie 266 | # pygments-lexer-solidity 267 | pygments-lexer-solidity==0.7.0 268 | # via eth-brownie 269 | pyjwt==1.7.1 270 | # via 271 | # eth-brownie 272 | # pythx 273 | pyparsing==3.0.9 274 | # via 275 | # eth-brownie 276 | # packaging 277 | pyrsistent==0.18.1 278 | # via 279 | # eth-brownie 280 | # jsonschema 281 | pyseto==1.7.1 282 | # via -r requirements.in 283 | pytest==6.2.5 284 | # via 285 | # eth-brownie 286 | # pytest-forked 287 | # pytest-xdist 288 | pytest-forked==1.4.0 289 | # via 290 | # eth-brownie 291 | # pytest-xdist 292 | pytest-xdist==1.34.0 293 | # via eth-brownie 294 | python-dateutil==2.8.1 295 | # via 296 | # eth-brownie 297 | # mythx-models 298 | # pythx 299 | python-dotenv==0.16.0 300 | # via eth-brownie 301 | pythx==1.6.1 302 | # via eth-brownie 303 | pyyaml==5.4.1 304 | # via 305 | # -r requirements.in 306 | # eth-brownie 307 | requests==2.28.1 308 | # via 309 | # eth-brownie 310 | # ipfshttpclient 311 | # py-solc-x 312 | # pythx 313 | # twirp 314 | # vvm 315 | # web3 316 | rlp==2.0.1 317 | # via 318 | # -r requirements.in 319 | # eth-account 320 | # eth-brownie 321 | # eth-rlp 322 | semantic-version==2.10.0 323 | # via 324 | # eth-brownie 325 | # py-solc-x 326 | # vvm 327 | # vyper 328 | six==1.16.0 329 | # via 330 | # asttokens 331 | # eth-brownie 332 | # jsonschema 333 | # multiaddr 334 | # parsimonious 335 | # pytest-xdist 336 | # python-dateutil 337 | sniffio==1.3.0 338 | # via anyio 339 | sortedcontainers==2.4.0 340 | # via 341 | # eth-brownie 342 | # hypothesis 343 | starlette==0.30.0 344 | # via -r requirements.in 345 | structlog==22.3.0 346 | # via twirp 347 | toml==0.10.2 348 | # via 349 | # eth-brownie 350 | # pytest 351 | tomli==2.0.1 352 | # via 353 | # black 354 | # eth-brownie 355 | toolz==0.12.0 356 | # via 357 | # cytoolz 358 | # eth-brownie 359 | tqdm==4.64.1 360 | # via eth-brownie 361 | twirp==0.0.7 362 | # via -r requirements.in 363 | types-pyyaml==6.0.12.8 364 | # via -r requirements.in 365 | typing-extensions==4.4.0 366 | # via 367 | # black 368 | # eth-brownie 369 | # starlette 370 | urllib3==1.26.12 371 | # via 372 | # eth-brownie 373 | # requests 374 | uvicorn==0.20.0 375 | # via -r requirements.in 376 | varint==1.0.2 377 | # via 378 | # eth-brownie 379 | # multiaddr 380 | vvm==0.1.0 381 | # via eth-brownie 382 | vyper==0.3.7 383 | # via eth-brownie 384 | wcwidth==0.2.5 385 | # via 386 | # eth-brownie 387 | # prompt-toolkit 388 | web3==5.31.3 389 | # via 390 | # -r requirements.in 391 | # eth-brownie 392 | websockets==9.1 393 | # via 394 | # eth-brownie 395 | # web3 396 | wheel==0.37.1 397 | # via 398 | # eth-brownie 399 | # vyper 400 | wrapt==1.14.1 401 | # via eth-brownie 402 | yarl==1.8.1 403 | # via 404 | # aiohttp 405 | # eth-brownie 406 | 407 | # The following packages are considered to be unsafe in a requirements file: 408 | # setuptools 409 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from starlette.applications import Starlette 4 | from starlette.routing import Mount, Route 5 | from starlette.staticfiles import StaticFiles 6 | 7 | from solidctf.rpc_proxy import rpc_proxy_handler 8 | from solidctf.service import create_asgi_application 9 | 10 | project_root = os.getcwd() 11 | if os.environ.get("DEBUG_MODE", False): 12 | project_root = os.path.join(project_root, "example") 13 | 14 | routes = [ 15 | Mount("/api", app=create_asgi_application(project_root)), 16 | Route("/eth_rpc", endpoint=rpc_proxy_handler, methods=["POST"]), 17 | Mount("/", app=StaticFiles(directory="web/dist", html=True)), 18 | ] 19 | 20 | app = Starlette(routes=routes) 21 | -------------------------------------------------------------------------------- /solidctf/__init__.py: -------------------------------------------------------------------------------- 1 | """SolidCTF is an infrastructure solution that simplifies the build of Solidity CTF challenges.""" 2 | __version_info__ = (1, 0, 0) 3 | __version__ = ".".join(map(str, __version_info__)) 4 | -------------------------------------------------------------------------------- /solidctf/config.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Tuple 3 | 4 | import yaml 5 | 6 | 7 | @dataclass(eq=False, frozen=True) 8 | class Constructor: 9 | args: Tuple 10 | value: int 11 | gas_limit: int 12 | 13 | 14 | @dataclass(eq=False, frozen=True) 15 | class Config: 16 | contract: str 17 | description: str 18 | show_source: bool 19 | solved_event: str 20 | constructor: Constructor 21 | 22 | 23 | def parse_config(path: str) -> Config: 24 | with open(path, "r") as f: 25 | config = yaml.safe_load(f) 26 | 27 | show_source = config.get("show_source", True) 28 | solved_event = config.get("solved_event", "") 29 | constructor = config.get("constructor", {}) 30 | constructor_args = constructor.get("args", ()) 31 | constructor_value = constructor.get("value", 0) 32 | constructor_gas = constructor.get("gas", 0) 33 | 34 | if constructor_value is None or constructor_value < 0: 35 | constructor_value = 0 36 | 37 | return Config( 38 | config["contract"], 39 | config["description"], 40 | show_source, 41 | solved_event, 42 | Constructor(tuple(constructor_args), constructor_value, constructor_gas), 43 | ) 44 | -------------------------------------------------------------------------------- /solidctf/ethereum.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from functools import lru_cache 3 | from typing import Dict, Optional, Tuple, Union 4 | 5 | import rlp 6 | from eth_typing import ChecksumAddress, HexStr 7 | from eth_utils import keccak, to_checksum_address 8 | from hexbytes import HexBytes 9 | from web3 import Web3 10 | from web3.constants import ADDRESS_ZERO 11 | from web3.contract import ContractConstructor 12 | from web3.exceptions import ContractLogicError, ValidationError 13 | from web3.types import ABI 14 | 15 | 16 | class Account: 17 | def __init__(self, private_key: Union[int, bytes, str, None] = None) -> None: 18 | self._lock = threading.Lock() 19 | if private_key is None: 20 | w3account = web3.eth.account.create() 21 | else: 22 | w3account = web3.eth.account.from_key(private_key) 23 | 24 | self._account = w3account 25 | self.address = self._account.address 26 | self.private_key = HexBytes(self._account.key).hex() 27 | 28 | @property 29 | def balance(self) -> int: 30 | balance = web3.eth.get_balance(self.address) 31 | return balance 32 | 33 | @property 34 | def nonce(self) -> int: 35 | return web3.eth.get_transaction_count(self.address) 36 | 37 | def get_deployment_address(self, nonce: Optional[int] = None) -> ChecksumAddress: 38 | if nonce is None: 39 | nonce = self.nonce 40 | 41 | address = HexBytes(self.address) 42 | raw = rlp.encode([address, nonce]) 43 | deployment_address = HexBytes(keccak(raw)[12:]).hex() 44 | 45 | return to_checksum_address(deployment_address) 46 | 47 | def transact(self, tx: Dict) -> str: 48 | with self._lock: 49 | tx["chainId"] = web3.eth.chain_id 50 | tx["from"] = self.address 51 | tx["gasPrice"] = web3.eth.gas_price 52 | if "nonce" not in tx.keys(): 53 | tx["nonce"] = self.nonce 54 | 55 | signed_tx = self._account.sign_transaction(tx).rawTransaction 56 | tx_hash = web3.eth.send_raw_transaction(signed_tx).hex() 57 | return tx_hash 58 | 59 | 60 | class Contract: 61 | def __init__(self, abi: ABI, bytecode: HexStr) -> None: 62 | self.abi = abi 63 | self.bytecode = bytecode 64 | self.deploy = ContractCreation(self) 65 | 66 | def is_solved( 67 | self, 68 | address: ChecksumAddress, 69 | solved_event: str = "", 70 | tx_hash: str = "", 71 | ) -> bool: 72 | is_solved = False 73 | if solved_event: 74 | tx_receipt = web3.eth.get_transaction_receipt(HexStr(tx_hash)) 75 | block_interval: int = web3.eth.block_number - tx_receipt["blockNumber"] 76 | if block_interval > 128: 77 | raise ValidationError( 78 | "cannot use transactions on blocks older than 128 blocks" 79 | ) 80 | 81 | logs = ( 82 | web3.eth.contract(abi=self.abi) 83 | .events[solved_event]() 84 | .processReceipt(tx_receipt) 85 | ) 86 | for item in logs: 87 | if item["address"] == address: 88 | is_solved = True 89 | else: 90 | try: 91 | is_solved = ( 92 | web3.eth.contract(address=address, abi=self.abi) 93 | .functions.isSolved() 94 | .call() 95 | ) 96 | except ContractLogicError: 97 | return False 98 | 99 | return is_solved 100 | 101 | def constructor(self, args: Optional[Tuple]) -> ContractConstructor: 102 | return ContractConstructor(web3, self.abi, self.bytecode, *args) # type: ignore[misc] 103 | 104 | 105 | class ContractCreation: 106 | def __init__(self, parent: "Contract") -> None: 107 | self._parent = parent 108 | 109 | def __call__( 110 | self, 111 | sender: Account, 112 | value: int = 0, 113 | gas_limit: Optional[int] = None, 114 | args: Optional[Tuple] = None, 115 | ) -> str: 116 | return sender.transact( 117 | { 118 | "value": value, 119 | "gas": gas_limit or self._estimate_gas(sender.address, value, args), 120 | "data": self.get_creation_code(args), 121 | }, 122 | ) 123 | 124 | @lru_cache(maxsize=3) 125 | def _estimate_gas( 126 | self, 127 | sender: ChecksumAddress, 128 | value: int = 0, 129 | args: Optional[Tuple] = None, 130 | ) -> int: 131 | return self._parent.constructor(args).estimateGas( 132 | {"from": sender, "value": value} 133 | ) 134 | 135 | def estimate_total_value( 136 | self, 137 | value: int = 0, 138 | gas_limit: Optional[int] = None, 139 | args: Optional[Tuple] = None, 140 | ) -> int: 141 | if not gas_limit: 142 | gas_limit = self._estimate_gas(ADDRESS_ZERO, value, args) 143 | return value + gas_limit * web3.eth.gas_price 144 | 145 | def get_creation_code( 146 | self, 147 | args: Optional[Tuple] = None, 148 | ): 149 | return self._parent.constructor(args).data_in_transaction 150 | 151 | 152 | web3 = Web3() 153 | -------------------------------------------------------------------------------- /solidctf/protobuf/challenge.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package chainflag.solidctf; 4 | 5 | message Info { 6 | string description = 1; 7 | bool show_source = 2; 8 | string solved_event = 3; 9 | } 10 | 11 | message Playground { 12 | string address = 1; 13 | string token = 2; 14 | float value = 3; 15 | } 16 | 17 | message Contract { 18 | string address = 1; 19 | string tx_hash = 2; 20 | } 21 | 22 | message Flag { 23 | string flag = 1; 24 | } 25 | 26 | message Event { 27 | string tx_hash = 1; 28 | } 29 | 30 | message SourceCode { 31 | map source = 1; 32 | } 33 | 34 | message Empty {} 35 | 36 | service Challenge { 37 | rpc GetChallengeInfo(Empty) returns (Info); 38 | rpc NewPlayground(Empty) returns (Playground); 39 | rpc DeployContract(Empty) returns (Contract); 40 | rpc GetFlag(Event) returns (Flag); 41 | rpc GetSourceCode(Empty) returns (SourceCode); 42 | } 43 | -------------------------------------------------------------------------------- /solidctf/rpc_proxy.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | from typing import Optional 4 | 5 | import aiohttp 6 | from starlette.requests import Request 7 | from starlette.responses import JSONResponse, Response 8 | 9 | 10 | @dataclass 11 | class RPCError: 12 | code: int 13 | message: str 14 | 15 | 16 | PARSE_ERROR = RPCError(code=-32700, message="Parse error") 17 | INVALID_REQUEST = RPCError(code=-32600, message="Invalid request") 18 | METHOD_NOT_SUPPORTED = RPCError(code=-32004, message="Method not supported") 19 | RESULT_UNAVAILABLE = RPCError(code=-32002, message="Resource unavailable") 20 | 21 | ALLOWED_METHODS = frozenset( 22 | [ 23 | "eth_blockNumber", 24 | "eth_call", 25 | "eth_chainId", 26 | "eth_estimateGas", 27 | "eth_feeHistory", 28 | "eth_gasPrice", 29 | "eth_getBalance", 30 | "eth_getBlockByHash", 31 | "eth_getBlockByNumber", 32 | "eth_getCode", 33 | "eth_getStorageAt", 34 | "eth_getTransactionByHash", 35 | "eth_getTransactionCount", 36 | "eth_getTransactionReceipt", 37 | "eth_sendRawTransaction", 38 | "net_version", 39 | "rpc_modules", 40 | "web3_clientVersion", 41 | ] 42 | ) 43 | 44 | 45 | def error_response(error: RPCError, status_code: int, request_id: Optional[int] = None): 46 | return JSONResponse( 47 | content={ 48 | "jsonrpc": "2.0", 49 | "error": { 50 | "code": error.code, 51 | "message": error.message, 52 | }, 53 | "id": request_id, 54 | }, 55 | status_code=status_code, 56 | ) 57 | 58 | 59 | async def dispatch_request(provider: str, body: dict): 60 | async with aiohttp.ClientSession() as session: 61 | async with session.post(provider, json=body) as response: 62 | return await response.json() 63 | 64 | 65 | async def rpc_proxy_handler(request: Request) -> Response: 66 | try: 67 | body = await request.json() 68 | except ValueError: 69 | return error_response(PARSE_ERROR, 415) 70 | 71 | request_id = body.get("id") 72 | body_keys = [key.lower() for key in body.keys()] 73 | if body_keys.count("method") != 1 or not isinstance(body["method"], str): 74 | return error_response(INVALID_REQUEST, 401, request_id) 75 | 76 | if body["method"] not in ALLOWED_METHODS: 77 | return error_response(METHOD_NOT_SUPPORTED, 401, request_id) 78 | 79 | try: 80 | response = await dispatch_request( 81 | os.getenv("WEB3_PROVIDER_URI", "http://127.0.0.1:8545"), body 82 | ) 83 | if ( 84 | body["method"] in ("eth_getBlockByHash", "eth_getBlockByNumber") 85 | and "result" in response 86 | ): 87 | response["result"]["transactions"] = [] 88 | return JSONResponse(content=response) 89 | except Exception: 90 | return error_response(RESULT_UNAVAILABLE, 500, request_id) 91 | -------------------------------------------------------------------------------- /solidctf/service.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import secrets 4 | from decimal import Decimal 5 | from glob import glob 6 | from typing import Dict 7 | 8 | import pyseto 9 | from eth_typing import ChecksumAddress 10 | from eth_utils import units 11 | from pyseto import Token 12 | from twirp import ctxkeys, errors 13 | from twirp.asgi import TwirpASGIApp 14 | from twirp.exceptions import InvalidArgument, RequiredArgument, TwirpServerException 15 | 16 | from solidctf.config import Config, parse_config 17 | from solidctf.ethereum import Account, Contract 18 | from solidctf.protobuf import ( # type: ignore[attr-defined] 19 | challenge_pb2, 20 | challenge_twirp, 21 | ) 22 | 23 | AUTHORIZATION_KEY = "authorization" 24 | 25 | 26 | class ChallengeService: 27 | def __init__(self, project_root: str, config: Config) -> None: 28 | self._config = config 29 | self._project_root = project_root 30 | artifact_path = os.path.join(self._project_root, "build", "contracts") 31 | with open(os.path.join(artifact_path, f"{self._config.contract}.json")) as fp: 32 | build_json = json.load(fp) 33 | self._contract: Contract = Contract(build_json["abi"], build_json["bytecode"]) 34 | self._source_code: Dict[str, str] = self._load_challenge_source(artifact_path) 35 | self._token_key = pyseto.Key.new( 36 | version=4, 37 | purpose="local", 38 | key=os.getenv("TOKEN_SECRET", secrets.token_hex(32)), 39 | ) 40 | 41 | def GetChallengeInfo(self, context, empty): 42 | return challenge_pb2.Info( 43 | description=self._config.description, 44 | show_source=self._config.show_source, 45 | solved_event=self._config.solved_event, 46 | ) 47 | 48 | def NewPlayground(self, context, empty): 49 | account: Account = Account() 50 | token: str = pyseto.encode( 51 | self._token_key, payload=account.private_key, footer=self._config.contract 52 | ).decode("utf-8") 53 | 54 | try: 55 | constructor = self._config.constructor 56 | total_value: int = self._contract.deploy.estimate_total_value( 57 | constructor.value, constructor.gas_limit, constructor.args 58 | ) 59 | except Exception as e: 60 | raise TwirpServerException( 61 | code=errors.Errors.Internal, 62 | message=str(e), 63 | ) 64 | 65 | ether_value: Decimal = Decimal(total_value) / units.units["ether"] + Decimal( 66 | "0.0005" 67 | ) 68 | 69 | context.get_logger().info("Playground account %s was created", account.address) 70 | return challenge_pb2.Playground( 71 | address=account.address, 72 | token=token, 73 | value=float(round(ether_value, 3)), 74 | ) 75 | 76 | def DeployContract(self, context, empty): 77 | account: Account = self._recoverAcctFromCtx(context) 78 | if account.balance == 0: 79 | raise TwirpServerException( 80 | code=errors.Errors.FailedPrecondition, 81 | message=f"send test ether to {account.address} first", 82 | ) 83 | 84 | contract_addr: str = account.get_deployment_address() 85 | try: 86 | constructor = self._config.constructor 87 | tx_hash: str = self._contract.deploy( 88 | account, constructor.value, constructor.gas_limit, constructor.args 89 | ) 90 | except Exception as e: 91 | raise TwirpServerException( 92 | code=errors.Errors.Internal, 93 | message=str(e), 94 | ) 95 | 96 | context.get_logger().info( 97 | "Contract %s was deployed by %s. Transaction hash %s", 98 | contract_addr, 99 | account.address, 100 | tx_hash, 101 | ) 102 | return challenge_pb2.Contract(address=contract_addr, tx_hash=tx_hash) 103 | 104 | def GetFlag(self, context, event): 105 | account: Account = self._recoverAcctFromCtx(context) 106 | nonce: int = account.nonce 107 | if nonce == 0: 108 | raise TwirpServerException( 109 | code=errors.Errors.FailedPrecondition, 110 | message="challenge contract has not yet been deployed", 111 | ) 112 | contract_addr: ChecksumAddress = account.get_deployment_address(nonce - 1) 113 | 114 | if self._config.solved_event: 115 | if not event.HasField("tx_hash"): 116 | raise RequiredArgument(argument="tx_hash") 117 | tx_hash = event.tx_hash.strip() 118 | if not ( 119 | len(tx_hash) == 66 120 | and tx_hash.startswith("0x") 121 | and all(c in "0123456789abcdef" for c in tx_hash[2:]) 122 | ): 123 | raise InvalidArgument(argument="tx_hash", error="is invalid") 124 | 125 | try: 126 | is_solved = self._contract.is_solved( 127 | contract_addr, self._config.solved_event, tx_hash 128 | ) 129 | except Exception as e: 130 | raise TwirpServerException( 131 | code=errors.Errors.FailedPrecondition, 132 | message=str(e), 133 | ) 134 | else: 135 | is_solved = self._contract.is_solved(contract_addr) 136 | 137 | if not is_solved: 138 | raise TwirpServerException( 139 | code=errors.Errors.InvalidArgument, 140 | message="you haven't solved this challenge", 141 | ) 142 | 143 | context.get_logger().info( 144 | "Flag was captured in contract %s deployed by %s", 145 | contract_addr, 146 | account.address, 147 | ) 148 | 149 | flag: str = "flag{placeholder}" 150 | try: 151 | file = os.path.join(self._project_root, "flag.txt") 152 | with open(file) as fp: 153 | flag = fp.readline() 154 | except FileNotFoundError: 155 | context.get_logger().warn("flag file %s not found", file) 156 | return challenge_pb2.Flag(flag=flag) 157 | 158 | def GetSourceCode(self, context, token): 159 | return challenge_pb2.SourceCode(source=self._source_code) 160 | 161 | def _load_challenge_source(self, artifact_path) -> Dict[str, str]: 162 | source: Dict[str, str] = {} 163 | if not self._config.show_source: 164 | return source 165 | for path in glob(os.path.join(artifact_path, "*.json")): 166 | try: 167 | with open(path) as fp: 168 | build_json = json.load(fp) 169 | except json.JSONDecodeError: 170 | continue 171 | else: 172 | source_path: str = build_json["sourcePath"] 173 | source[source_path] = build_json["source"] 174 | 175 | return source 176 | 177 | def _recoverAcctFromCtx(self, context) -> Account: 178 | header = context.get(ctxkeys.RAW_HEADERS) 179 | token = header.get(AUTHORIZATION_KEY) 180 | if not token: 181 | raise RequiredArgument(argument="authorization") 182 | 183 | try: 184 | decoded_token: Token = pyseto.decode(self._token_key, token.strip()) 185 | except Exception as e: 186 | raise TwirpServerException( 187 | code=errors.Errors.Unauthenticated, message=str(e) 188 | ) 189 | 190 | if self._config.contract != decoded_token.footer.decode("utf-8"): # type: ignore[union-attr] 191 | raise TwirpServerException( 192 | code=errors.Errors.Unauthenticated, 193 | message="token was not issued by this challenge", 194 | ) 195 | 196 | return Account(decoded_token.payload.decode("utf-8")) # type: ignore[union-attr] 197 | 198 | 199 | def create_asgi_application(project_root: str) -> TwirpASGIApp: 200 | config = parse_config(os.path.join(project_root, "challenge.yml")) 201 | application = TwirpASGIApp() 202 | service = ChallengeService(project_root, config) 203 | application.add_service(challenge_twirp.ChallengeServer(service=service)) 204 | return application 205 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/extensions.json 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "useTabs": false, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "es5", 7 | "bracketSpacing": true, 8 | "arrowParens": "avoid" 9 | } 10 | -------------------------------------------------------------------------------- /web/assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainflag/solidctf/97eed2733b3906ff81e019ecdbc267c6d0c6de08/web/assets/background.jpg -------------------------------------------------------------------------------- /web/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | background-image: url('./background.jpg'); 5 | background-size: cover; 6 | } 7 | 8 | .overlay { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | width: 100%; 13 | height: 100%; 14 | z-index: 1; 15 | } 16 | 17 | .content { 18 | position: absolute; 19 | top: 0%; 20 | left: 20%; 21 | width: 60%; 22 | height: 100%; 23 | z-index: 2; 24 | float: left; 25 | overflow: auto; 26 | padding: 20px; 27 | box-sizing: border-box; 28 | overflow-y: scroll; 29 | overflow-x: scroll; 30 | scrollbar-width: thin; 31 | scrollbar-color: transparent transparent; 32 | } 33 | 34 | .content::-webkit-scrollbar { 35 | width: 0px; 36 | } 37 | 38 | .content::-webkit-scrollbar-track { 39 | background-color: transparent; 40 | } 41 | 42 | .content::-webkit-scrollbar-thumb { 43 | background-color: transparent; 44 | } 45 | 46 | .card { 47 | background-color: rgba(255, 255, 255, 0.85); 48 | border-radius: 8px; 49 | padding: 20px; 50 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 51 | margin-bottom: 20px; 52 | } 53 | 54 | .input-group { 55 | margin-top: 5px; 56 | margin-bottom: 5px; 57 | } 58 | 59 | .input-group input { 60 | width: 100%; 61 | padding: 5px; 62 | border: 1px solid #ccc; 63 | border-radius: 3px; 64 | } 65 | 66 | .input-group button { 67 | background-color: #4caf50; 68 | color: #fff; 69 | border: none; 70 | padding: 8px 16px; 71 | border-radius: 3px; 72 | cursor: pointer; 73 | } 74 | 75 | .danger button { 76 | background-color: #e22b2b; 77 | } 78 | 79 | .my-button { 80 | display: flex; 81 | justify-content: center; 82 | align-items: center; 83 | } 84 | 85 | .button-container { 86 | display: flex; 87 | justify-content: space-between; 88 | } 89 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidctf", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "twirpscript && webpack", 6 | "prettier": "prettier --write 'src/**/*.{css,html,js}'" 7 | }, 8 | "license": "MIT", 9 | "dependencies": { 10 | "highlight.js": "^11.8.0", 11 | "highlightjs-solidity": "^2.0.6", 12 | "jquery": "^3.7.1", 13 | "twirpscript": "^0.0.68" 14 | }, 15 | "devDependencies": { 16 | "css-loader": "^6.8.1", 17 | "html-webpack-plugin": "^5.5.3", 18 | "style-loader": "^3.3.3", 19 | "webpack": "^5.88.2", 20 | "webpack-cli": "^5.1.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /web/src/app.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import { client } from 'twirpscript'; 3 | import hljs from 'highlight.js'; 4 | import hljsDefineSolidity from 'highlightjs-solidity'; 5 | 6 | import { 7 | GetChallengeInfo, 8 | GetSourceCode, 9 | GetFlag, 10 | NewPlayground, 11 | DeployContract, 12 | } from '../challenge.pb.js'; 13 | 14 | import '../assets/style.css'; 15 | 16 | const API_PREFIX = '/api/twirp'; 17 | client.prefix = API_PREFIX; 18 | 19 | client.use((context, next) => { 20 | const auth = localStorage.getItem('auth'); 21 | if (auth) { 22 | context.headers['authorization'] = auth; 23 | } 24 | return next(context); 25 | }); 26 | 27 | hljsDefineSolidity(hljs); 28 | hljs.initHighlightingOnLoad(); 29 | 30 | $(document).ready(async function () { 31 | try { 32 | const infoRes = await GetChallengeInfo({}); 33 | $('#challenge-description').text(infoRes.description); 34 | 35 | if (infoRes.solvedEvent.length === 0) { 36 | $('#input-text').hide(); 37 | } 38 | 39 | if (infoRes.showSource) { 40 | const sourceRes = await GetSourceCode({}); 41 | displaySource(sourceRes.source); 42 | } 43 | } catch (err) { 44 | $('#challenge-status').text(`API error: ${err.msg}`); 45 | } 46 | 47 | if (!localStorage.getItem('auth')) { 48 | try { 49 | const startRes = await NewPlayground({}); 50 | localStorage.setItem('auth', startRes.token); 51 | const msg = `please transfer more than ${startRes.value.toFixed( 52 | 3 53 | )} test ether to the deployer account ${startRes.address} for next step`; 54 | $('#challenge-status').text(msg); 55 | } catch (err) { 56 | $('#challenge-status').text( 57 | `NewPlayground failed, contact admin: ${err.msg}` 58 | ); 59 | } 60 | return; 61 | } 62 | 63 | if (!localStorage.getItem('target')) { 64 | try { 65 | const deployRes = await DeployContract({}); 66 | const target = deployRes.address; 67 | localStorage.setItem('target', target); 68 | $('#challenge-status').text('please solve the contrat @' + target); 69 | } catch (err) { 70 | console.log(err); 71 | $('#challenge-status').text(err.msg); 72 | } 73 | } else { 74 | const target = localStorage.getItem('target'); 75 | $('#challenge-status').text('please solve the contrat @' + target); 76 | } 77 | 78 | $('#get-flag').click(getFlag); 79 | }); 80 | 81 | function displaySource(source) { 82 | for (const filename in source) { 83 | const content = source[filename]; 84 | const card = $('
').addClass('card'); 85 | const pre = $('
');
 86 |     const code = $('')
 87 |       .addClass('language-solidity')
 88 |       .css({
 89 |         'font-weight': 'bold',
 90 |         'font-family': 'Cascadia Mono, monospace',
 91 |       })
 92 |       .text(content);
 93 |     pre.append(code);
 94 |     card.append(pre);
 95 |     $('#target-element').append(card);
 96 |   }
 97 |   hljs.highlightAll();
 98 | }
 99 | 
100 | async function getFlag() {
101 |   try {
102 |     const solve_tx_hash = document.getElementById('input-text').value;
103 |     const res = await GetFlag({txHash: solve_tx_hash});
104 |     console.log(res);
105 |     if ('flag' in res) {
106 |       $('#flag-placeholder').text(`🥰🥰🥰 ${res.flag}`);
107 |     }
108 |   } catch (err) {
109 |     $('#flag-placeholder').text(err.msg);
110 |   }
111 | }
112 | 


--------------------------------------------------------------------------------
/web/src/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     Solid CTF Challenge
 6 |     
10 |     
14 |   
15 | 
16 |   
17 |     
18 |
19 |

Challenge Description

20 |
Error! Please Contract Admin
21 |
22 | 23 |
24 |

25 |
26 | 27 |
28 | 29 |
30 |
31 | 36 |
37 |
38 |
39 | 40 |
41 |
42 | 50 |
51 |
52 |
53 |

54 |
55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /web/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | entry: './src/app.js', 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), 8 | filename: 'bundle.js', 9 | }, 10 | module: { 11 | rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }], 12 | }, 13 | plugins: [ 14 | new HtmlWebpackPlugin({ 15 | template: 'src/index.html', 16 | }), 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /web/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@discoveryjs/json-ext@^0.5.0": 6 | version "0.5.7" 7 | resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" 8 | integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== 9 | 10 | "@jridgewell/gen-mapping@^0.3.0": 11 | version "0.3.3" 12 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" 13 | integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== 14 | dependencies: 15 | "@jridgewell/set-array" "^1.0.1" 16 | "@jridgewell/sourcemap-codec" "^1.4.10" 17 | "@jridgewell/trace-mapping" "^0.3.9" 18 | 19 | "@jridgewell/resolve-uri@^3.1.0": 20 | version "3.1.1" 21 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" 22 | integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== 23 | 24 | "@jridgewell/set-array@^1.0.1": 25 | version "1.1.2" 26 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" 27 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== 28 | 29 | "@jridgewell/source-map@^0.3.3": 30 | version "0.3.5" 31 | resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" 32 | integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== 33 | dependencies: 34 | "@jridgewell/gen-mapping" "^0.3.0" 35 | "@jridgewell/trace-mapping" "^0.3.9" 36 | 37 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": 38 | version "1.4.15" 39 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" 40 | integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== 41 | 42 | "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": 43 | version "0.3.19" 44 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" 45 | integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== 46 | dependencies: 47 | "@jridgewell/resolve-uri" "^3.1.0" 48 | "@jridgewell/sourcemap-codec" "^1.4.14" 49 | 50 | "@types/eslint-scope@^3.7.3": 51 | version "3.7.4" 52 | resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" 53 | integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== 54 | dependencies: 55 | "@types/eslint" "*" 56 | "@types/estree" "*" 57 | 58 | "@types/eslint@*": 59 | version "8.44.2" 60 | resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.2.tgz#0d21c505f98a89b8dd4d37fa162b09da6089199a" 61 | integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== 62 | dependencies: 63 | "@types/estree" "*" 64 | "@types/json-schema" "*" 65 | 66 | "@types/estree@*", "@types/estree@^1.0.0": 67 | version "1.0.1" 68 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" 69 | integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== 70 | 71 | "@types/html-minifier-terser@^6.0.0": 72 | version "6.1.0" 73 | resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" 74 | integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== 75 | 76 | "@types/json-schema@*", "@types/json-schema@^7.0.8": 77 | version "7.0.13" 78 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" 79 | integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== 80 | 81 | "@types/node@*": 82 | version "20.6.2" 83 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" 84 | integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== 85 | 86 | "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": 87 | version "1.11.6" 88 | resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" 89 | integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== 90 | dependencies: 91 | "@webassemblyjs/helper-numbers" "1.11.6" 92 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6" 93 | 94 | "@webassemblyjs/floating-point-hex-parser@1.11.6": 95 | version "1.11.6" 96 | resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" 97 | integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== 98 | 99 | "@webassemblyjs/helper-api-error@1.11.6": 100 | version "1.11.6" 101 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" 102 | integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== 103 | 104 | "@webassemblyjs/helper-buffer@1.11.6": 105 | version "1.11.6" 106 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" 107 | integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== 108 | 109 | "@webassemblyjs/helper-numbers@1.11.6": 110 | version "1.11.6" 111 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" 112 | integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== 113 | dependencies: 114 | "@webassemblyjs/floating-point-hex-parser" "1.11.6" 115 | "@webassemblyjs/helper-api-error" "1.11.6" 116 | "@xtuc/long" "4.2.2" 117 | 118 | "@webassemblyjs/helper-wasm-bytecode@1.11.6": 119 | version "1.11.6" 120 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" 121 | integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== 122 | 123 | "@webassemblyjs/helper-wasm-section@1.11.6": 124 | version "1.11.6" 125 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" 126 | integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== 127 | dependencies: 128 | "@webassemblyjs/ast" "1.11.6" 129 | "@webassemblyjs/helper-buffer" "1.11.6" 130 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6" 131 | "@webassemblyjs/wasm-gen" "1.11.6" 132 | 133 | "@webassemblyjs/ieee754@1.11.6": 134 | version "1.11.6" 135 | resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" 136 | integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== 137 | dependencies: 138 | "@xtuc/ieee754" "^1.2.0" 139 | 140 | "@webassemblyjs/leb128@1.11.6": 141 | version "1.11.6" 142 | resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" 143 | integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== 144 | dependencies: 145 | "@xtuc/long" "4.2.2" 146 | 147 | "@webassemblyjs/utf8@1.11.6": 148 | version "1.11.6" 149 | resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" 150 | integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== 151 | 152 | "@webassemblyjs/wasm-edit@^1.11.5": 153 | version "1.11.6" 154 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" 155 | integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== 156 | dependencies: 157 | "@webassemblyjs/ast" "1.11.6" 158 | "@webassemblyjs/helper-buffer" "1.11.6" 159 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6" 160 | "@webassemblyjs/helper-wasm-section" "1.11.6" 161 | "@webassemblyjs/wasm-gen" "1.11.6" 162 | "@webassemblyjs/wasm-opt" "1.11.6" 163 | "@webassemblyjs/wasm-parser" "1.11.6" 164 | "@webassemblyjs/wast-printer" "1.11.6" 165 | 166 | "@webassemblyjs/wasm-gen@1.11.6": 167 | version "1.11.6" 168 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" 169 | integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== 170 | dependencies: 171 | "@webassemblyjs/ast" "1.11.6" 172 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6" 173 | "@webassemblyjs/ieee754" "1.11.6" 174 | "@webassemblyjs/leb128" "1.11.6" 175 | "@webassemblyjs/utf8" "1.11.6" 176 | 177 | "@webassemblyjs/wasm-opt@1.11.6": 178 | version "1.11.6" 179 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" 180 | integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== 181 | dependencies: 182 | "@webassemblyjs/ast" "1.11.6" 183 | "@webassemblyjs/helper-buffer" "1.11.6" 184 | "@webassemblyjs/wasm-gen" "1.11.6" 185 | "@webassemblyjs/wasm-parser" "1.11.6" 186 | 187 | "@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": 188 | version "1.11.6" 189 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" 190 | integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== 191 | dependencies: 192 | "@webassemblyjs/ast" "1.11.6" 193 | "@webassemblyjs/helper-api-error" "1.11.6" 194 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6" 195 | "@webassemblyjs/ieee754" "1.11.6" 196 | "@webassemblyjs/leb128" "1.11.6" 197 | "@webassemblyjs/utf8" "1.11.6" 198 | 199 | "@webassemblyjs/wast-printer@1.11.6": 200 | version "1.11.6" 201 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" 202 | integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== 203 | dependencies: 204 | "@webassemblyjs/ast" "1.11.6" 205 | "@xtuc/long" "4.2.2" 206 | 207 | "@webpack-cli/configtest@^2.1.1": 208 | version "2.1.1" 209 | resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" 210 | integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== 211 | 212 | "@webpack-cli/info@^2.0.2": 213 | version "2.0.2" 214 | resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" 215 | integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== 216 | 217 | "@webpack-cli/serve@^2.0.5": 218 | version "2.0.5" 219 | resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" 220 | integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== 221 | 222 | "@xtuc/ieee754@^1.2.0": 223 | version "1.2.0" 224 | resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" 225 | integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== 226 | 227 | "@xtuc/long@4.2.2": 228 | version "4.2.2" 229 | resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" 230 | integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== 231 | 232 | acorn-import-assertions@^1.9.0: 233 | version "1.9.0" 234 | resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" 235 | integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== 236 | 237 | acorn@^8.7.1, acorn@^8.8.2: 238 | version "8.10.0" 239 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" 240 | integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== 241 | 242 | ajv-keywords@^3.5.2: 243 | version "3.5.2" 244 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" 245 | integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== 246 | 247 | ajv@^6.12.5: 248 | version "6.12.6" 249 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 250 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 251 | dependencies: 252 | fast-deep-equal "^3.1.1" 253 | fast-json-stable-stringify "^2.0.0" 254 | json-schema-traverse "^0.4.1" 255 | uri-js "^4.2.2" 256 | 257 | ansi-regex@^5.0.1: 258 | version "5.0.1" 259 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 260 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 261 | 262 | boolbase@^1.0.0: 263 | version "1.0.0" 264 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" 265 | integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== 266 | 267 | browserslist@^4.14.5: 268 | version "4.21.10" 269 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" 270 | integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== 271 | dependencies: 272 | caniuse-lite "^1.0.30001517" 273 | electron-to-chromium "^1.4.477" 274 | node-releases "^2.0.13" 275 | update-browserslist-db "^1.0.11" 276 | 277 | buffer-from@^1.0.0: 278 | version "1.1.2" 279 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 280 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 281 | 282 | camel-case@^4.1.2: 283 | version "4.1.2" 284 | resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" 285 | integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== 286 | dependencies: 287 | pascal-case "^3.1.2" 288 | tslib "^2.0.3" 289 | 290 | caniuse-lite@^1.0.30001517: 291 | version "1.0.30001534" 292 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz#f24a9b2a6d39630bac5c132b5dff89b39a12e7dd" 293 | integrity sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q== 294 | 295 | chrome-trace-event@^1.0.2: 296 | version "1.0.3" 297 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" 298 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== 299 | 300 | clean-css@^5.2.2: 301 | version "5.3.2" 302 | resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" 303 | integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== 304 | dependencies: 305 | source-map "~0.6.0" 306 | 307 | clone-deep@^4.0.1: 308 | version "4.0.1" 309 | resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" 310 | integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== 311 | dependencies: 312 | is-plain-object "^2.0.4" 313 | kind-of "^6.0.2" 314 | shallow-clone "^3.0.0" 315 | 316 | colorette@^2.0.14: 317 | version "2.0.20" 318 | resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" 319 | integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== 320 | 321 | commander@^10.0.1: 322 | version "10.0.1" 323 | resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" 324 | integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== 325 | 326 | commander@^2.20.0: 327 | version "2.20.3" 328 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 329 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 330 | 331 | commander@^8.3.0: 332 | version "8.3.0" 333 | resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" 334 | integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== 335 | 336 | cross-spawn@^7.0.3: 337 | version "7.0.3" 338 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 339 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 340 | dependencies: 341 | path-key "^3.1.0" 342 | shebang-command "^2.0.0" 343 | which "^2.0.1" 344 | 345 | css-loader@^6.8.1: 346 | version "6.8.1" 347 | resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" 348 | integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== 349 | dependencies: 350 | icss-utils "^5.1.0" 351 | postcss "^8.4.21" 352 | postcss-modules-extract-imports "^3.0.0" 353 | postcss-modules-local-by-default "^4.0.3" 354 | postcss-modules-scope "^3.0.0" 355 | postcss-modules-values "^4.0.0" 356 | postcss-value-parser "^4.2.0" 357 | semver "^7.3.8" 358 | 359 | css-select@^4.1.3: 360 | version "4.3.0" 361 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" 362 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 363 | dependencies: 364 | boolbase "^1.0.0" 365 | css-what "^6.0.1" 366 | domhandler "^4.3.1" 367 | domutils "^2.8.0" 368 | nth-check "^2.0.1" 369 | 370 | css-what@^6.0.1: 371 | version "6.1.0" 372 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" 373 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 374 | 375 | cssesc@^3.0.0: 376 | version "3.0.0" 377 | resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 378 | integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== 379 | 380 | dom-converter@^0.2.0: 381 | version "0.2.0" 382 | resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" 383 | integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== 384 | dependencies: 385 | utila "~0.4" 386 | 387 | dom-serializer@^1.0.1: 388 | version "1.4.1" 389 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" 390 | integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== 391 | dependencies: 392 | domelementtype "^2.0.1" 393 | domhandler "^4.2.0" 394 | entities "^2.0.0" 395 | 396 | domelementtype@^2.0.1, domelementtype@^2.2.0: 397 | version "2.3.0" 398 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" 399 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== 400 | 401 | domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: 402 | version "4.3.1" 403 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" 404 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== 405 | dependencies: 406 | domelementtype "^2.2.0" 407 | 408 | domutils@^2.5.2, domutils@^2.8.0: 409 | version "2.8.0" 410 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" 411 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== 412 | dependencies: 413 | dom-serializer "^1.0.1" 414 | domelementtype "^2.2.0" 415 | domhandler "^4.2.0" 416 | 417 | dot-case@^3.0.4: 418 | version "3.0.4" 419 | resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" 420 | integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== 421 | dependencies: 422 | no-case "^3.0.4" 423 | tslib "^2.0.3" 424 | 425 | electron-to-chromium@^1.4.477: 426 | version "1.4.523" 427 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz#f82f99243c827df05c26776d49712cb284972df6" 428 | integrity sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg== 429 | 430 | enhanced-resolve@^5.15.0: 431 | version "5.15.0" 432 | resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" 433 | integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== 434 | dependencies: 435 | graceful-fs "^4.2.4" 436 | tapable "^2.2.0" 437 | 438 | entities@^2.0.0: 439 | version "2.2.0" 440 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" 441 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 442 | 443 | envinfo@^7.7.3: 444 | version "7.10.0" 445 | resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.10.0.tgz#55146e3909cc5fe63c22da63fb15b05aeac35b13" 446 | integrity sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw== 447 | 448 | es-module-lexer@^1.2.1: 449 | version "1.3.1" 450 | resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1" 451 | integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== 452 | 453 | escalade@^3.1.1: 454 | version "3.1.1" 455 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 456 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 457 | 458 | eslint-scope@5.1.1: 459 | version "5.1.1" 460 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" 461 | integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== 462 | dependencies: 463 | esrecurse "^4.3.0" 464 | estraverse "^4.1.1" 465 | 466 | esrecurse@^4.3.0: 467 | version "4.3.0" 468 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 469 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 470 | dependencies: 471 | estraverse "^5.2.0" 472 | 473 | estraverse@^4.1.1: 474 | version "4.3.0" 475 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" 476 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== 477 | 478 | estraverse@^5.2.0: 479 | version "5.3.0" 480 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 481 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 482 | 483 | events@^3.2.0: 484 | version "3.3.0" 485 | resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" 486 | integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== 487 | 488 | fast-deep-equal@^3.1.1: 489 | version "3.1.3" 490 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 491 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 492 | 493 | fast-json-stable-stringify@^2.0.0: 494 | version "2.1.0" 495 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 496 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 497 | 498 | fastest-levenshtein@^1.0.12: 499 | version "1.0.16" 500 | resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" 501 | integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== 502 | 503 | find-up@^4.0.0: 504 | version "4.1.0" 505 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 506 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== 507 | dependencies: 508 | locate-path "^5.0.0" 509 | path-exists "^4.0.0" 510 | 511 | function-bind@^1.1.1: 512 | version "1.1.1" 513 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 514 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 515 | 516 | glob-to-regexp@^0.4.1: 517 | version "0.4.1" 518 | resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" 519 | integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== 520 | 521 | google-protobuf@^3.21.2: 522 | version "3.21.2" 523 | resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4" 524 | integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== 525 | 526 | graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: 527 | version "4.2.11" 528 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 529 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 530 | 531 | has-flag@^4.0.0: 532 | version "4.0.0" 533 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 534 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 535 | 536 | has@^1.0.3: 537 | version "1.0.3" 538 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 539 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 540 | dependencies: 541 | function-bind "^1.1.1" 542 | 543 | he@^1.2.0: 544 | version "1.2.0" 545 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 546 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 547 | 548 | highlight.js@^11.8.0: 549 | version "11.8.0" 550 | resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.8.0.tgz#966518ea83257bae2e7c9a48596231856555bb65" 551 | integrity sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg== 552 | 553 | highlightjs-solidity@^2.0.6: 554 | version "2.0.6" 555 | resolved "https://registry.yarnpkg.com/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz#e7a702a2b05e0a97f185e6ba39fd4846ad23a990" 556 | integrity sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg== 557 | 558 | html-minifier-terser@^6.0.2: 559 | version "6.1.0" 560 | resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" 561 | integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== 562 | dependencies: 563 | camel-case "^4.1.2" 564 | clean-css "^5.2.2" 565 | commander "^8.3.0" 566 | he "^1.2.0" 567 | param-case "^3.0.4" 568 | relateurl "^0.2.7" 569 | terser "^5.10.0" 570 | 571 | html-webpack-plugin@^5.5.3: 572 | version "5.5.3" 573 | resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" 574 | integrity sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg== 575 | dependencies: 576 | "@types/html-minifier-terser" "^6.0.0" 577 | html-minifier-terser "^6.0.2" 578 | lodash "^4.17.21" 579 | pretty-error "^4.0.0" 580 | tapable "^2.0.0" 581 | 582 | htmlparser2@^6.1.0: 583 | version "6.1.0" 584 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" 585 | integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== 586 | dependencies: 587 | domelementtype "^2.0.1" 588 | domhandler "^4.0.0" 589 | domutils "^2.5.2" 590 | entities "^2.0.0" 591 | 592 | icss-utils@^5.0.0, icss-utils@^5.1.0: 593 | version "5.1.0" 594 | resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" 595 | integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== 596 | 597 | import-local@^3.0.2: 598 | version "3.1.0" 599 | resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" 600 | integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== 601 | dependencies: 602 | pkg-dir "^4.2.0" 603 | resolve-cwd "^3.0.0" 604 | 605 | interpret@^3.1.1: 606 | version "3.1.1" 607 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" 608 | integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== 609 | 610 | is-core-module@^2.13.0: 611 | version "2.13.0" 612 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" 613 | integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== 614 | dependencies: 615 | has "^1.0.3" 616 | 617 | is-plain-object@^2.0.4: 618 | version "2.0.4" 619 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 620 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== 621 | dependencies: 622 | isobject "^3.0.1" 623 | 624 | isexe@^2.0.0: 625 | version "2.0.0" 626 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 627 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 628 | 629 | isobject@^3.0.1: 630 | version "3.0.1" 631 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 632 | integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== 633 | 634 | jest-worker@^27.4.5: 635 | version "27.5.1" 636 | resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" 637 | integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== 638 | dependencies: 639 | "@types/node" "*" 640 | merge-stream "^2.0.0" 641 | supports-color "^8.0.0" 642 | 643 | jquery@^3.7.1: 644 | version "3.7.1" 645 | resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de" 646 | integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== 647 | 648 | json-parse-even-better-errors@^2.3.1: 649 | version "2.3.1" 650 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 651 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 652 | 653 | json-schema-traverse@^0.4.1: 654 | version "0.4.1" 655 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 656 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 657 | 658 | kind-of@^6.0.2: 659 | version "6.0.3" 660 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 661 | integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== 662 | 663 | loader-runner@^4.2.0: 664 | version "4.3.0" 665 | resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" 666 | integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== 667 | 668 | locate-path@^5.0.0: 669 | version "5.0.0" 670 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" 671 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== 672 | dependencies: 673 | p-locate "^4.1.0" 674 | 675 | lodash@^4.17.20, lodash@^4.17.21: 676 | version "4.17.21" 677 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 678 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 679 | 680 | lower-case@^2.0.2: 681 | version "2.0.2" 682 | resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" 683 | integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== 684 | dependencies: 685 | tslib "^2.0.3" 686 | 687 | lru-cache@^6.0.0: 688 | version "6.0.0" 689 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 690 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 691 | dependencies: 692 | yallist "^4.0.0" 693 | 694 | merge-stream@^2.0.0: 695 | version "2.0.0" 696 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 697 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 698 | 699 | mime-db@1.52.0: 700 | version "1.52.0" 701 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 702 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 703 | 704 | mime-types@^2.1.27: 705 | version "2.1.35" 706 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 707 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 708 | dependencies: 709 | mime-db "1.52.0" 710 | 711 | nanoid@^3.3.6: 712 | version "3.3.6" 713 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" 714 | integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== 715 | 716 | neo-async@^2.6.2: 717 | version "2.6.2" 718 | resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" 719 | integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== 720 | 721 | no-case@^3.0.4: 722 | version "3.0.4" 723 | resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" 724 | integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== 725 | dependencies: 726 | lower-case "^2.0.2" 727 | tslib "^2.0.3" 728 | 729 | node-releases@^2.0.13: 730 | version "2.0.13" 731 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" 732 | integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== 733 | 734 | nth-check@^2.0.1: 735 | version "2.1.1" 736 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" 737 | integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== 738 | dependencies: 739 | boolbase "^1.0.0" 740 | 741 | p-limit@^2.2.0: 742 | version "2.3.0" 743 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 744 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 745 | dependencies: 746 | p-try "^2.0.0" 747 | 748 | p-locate@^4.1.0: 749 | version "4.1.0" 750 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 751 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== 752 | dependencies: 753 | p-limit "^2.2.0" 754 | 755 | p-try@^2.0.0: 756 | version "2.2.0" 757 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 758 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 759 | 760 | param-case@^3.0.4: 761 | version "3.0.4" 762 | resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" 763 | integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== 764 | dependencies: 765 | dot-case "^3.0.4" 766 | tslib "^2.0.3" 767 | 768 | pascal-case@^3.1.2: 769 | version "3.1.2" 770 | resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" 771 | integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== 772 | dependencies: 773 | no-case "^3.0.4" 774 | tslib "^2.0.3" 775 | 776 | path-exists@^4.0.0: 777 | version "4.0.0" 778 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 779 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 780 | 781 | path-key@^3.1.0: 782 | version "3.1.1" 783 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 784 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 785 | 786 | path-parse@^1.0.7: 787 | version "1.0.7" 788 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 789 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 790 | 791 | picocolors@^1.0.0: 792 | version "1.0.0" 793 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 794 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 795 | 796 | pkg-dir@^4.2.0: 797 | version "4.2.0" 798 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" 799 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== 800 | dependencies: 801 | find-up "^4.0.0" 802 | 803 | postcss-modules-extract-imports@^3.0.0: 804 | version "3.0.0" 805 | resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" 806 | integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== 807 | 808 | postcss-modules-local-by-default@^4.0.3: 809 | version "4.0.3" 810 | resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" 811 | integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== 812 | dependencies: 813 | icss-utils "^5.0.0" 814 | postcss-selector-parser "^6.0.2" 815 | postcss-value-parser "^4.1.0" 816 | 817 | postcss-modules-scope@^3.0.0: 818 | version "3.0.0" 819 | resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" 820 | integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== 821 | dependencies: 822 | postcss-selector-parser "^6.0.4" 823 | 824 | postcss-modules-values@^4.0.0: 825 | version "4.0.0" 826 | resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" 827 | integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== 828 | dependencies: 829 | icss-utils "^5.0.0" 830 | 831 | postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: 832 | version "6.0.13" 833 | resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" 834 | integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== 835 | dependencies: 836 | cssesc "^3.0.0" 837 | util-deprecate "^1.0.2" 838 | 839 | postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: 840 | version "4.2.0" 841 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 842 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 843 | 844 | postcss@^8.4.21: 845 | version "8.4.29" 846 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" 847 | integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== 848 | dependencies: 849 | nanoid "^3.3.6" 850 | picocolors "^1.0.0" 851 | source-map-js "^1.0.2" 852 | 853 | prettier@^3.0.0: 854 | version "3.0.3" 855 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" 856 | integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== 857 | 858 | pretty-error@^4.0.0: 859 | version "4.0.0" 860 | resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" 861 | integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== 862 | dependencies: 863 | lodash "^4.17.20" 864 | renderkid "^3.0.0" 865 | 866 | protoscript@0.0.18: 867 | version "0.0.18" 868 | resolved "https://registry.yarnpkg.com/protoscript/-/protoscript-0.0.18.tgz#b8073065530c2b03b7b7006c07c96a401d02ce6a" 869 | integrity sha512-VQGYcyjHwbCWK/p8PE3or1bAWovRPzGlS6ueYSZ5PsK3mXEmA5e6gcT5R1+aMsiCn+4/Wo8CC+yL/meub4DqsA== 870 | dependencies: 871 | google-protobuf "^3.21.2" 872 | prettier "^3.0.0" 873 | 874 | punycode@^2.1.0: 875 | version "2.3.0" 876 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" 877 | integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== 878 | 879 | randombytes@^2.1.0: 880 | version "2.1.0" 881 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 882 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 883 | dependencies: 884 | safe-buffer "^5.1.0" 885 | 886 | rechoir@^0.8.0: 887 | version "0.8.0" 888 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" 889 | integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== 890 | dependencies: 891 | resolve "^1.20.0" 892 | 893 | relateurl@^0.2.7: 894 | version "0.2.7" 895 | resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" 896 | integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== 897 | 898 | renderkid@^3.0.0: 899 | version "3.0.0" 900 | resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" 901 | integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== 902 | dependencies: 903 | css-select "^4.1.3" 904 | dom-converter "^0.2.0" 905 | htmlparser2 "^6.1.0" 906 | lodash "^4.17.21" 907 | strip-ansi "^6.0.1" 908 | 909 | resolve-cwd@^3.0.0: 910 | version "3.0.0" 911 | resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" 912 | integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== 913 | dependencies: 914 | resolve-from "^5.0.0" 915 | 916 | resolve-from@^5.0.0: 917 | version "5.0.0" 918 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" 919 | integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== 920 | 921 | resolve@^1.20.0: 922 | version "1.22.6" 923 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" 924 | integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== 925 | dependencies: 926 | is-core-module "^2.13.0" 927 | path-parse "^1.0.7" 928 | supports-preserve-symlinks-flag "^1.0.0" 929 | 930 | safe-buffer@^5.1.0: 931 | version "5.2.1" 932 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 933 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 934 | 935 | schema-utils@^3.1.1, schema-utils@^3.2.0: 936 | version "3.3.0" 937 | resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" 938 | integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== 939 | dependencies: 940 | "@types/json-schema" "^7.0.8" 941 | ajv "^6.12.5" 942 | ajv-keywords "^3.5.2" 943 | 944 | semver@^7.3.8: 945 | version "7.5.4" 946 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" 947 | integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== 948 | dependencies: 949 | lru-cache "^6.0.0" 950 | 951 | serialize-javascript@^6.0.1: 952 | version "6.0.1" 953 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" 954 | integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== 955 | dependencies: 956 | randombytes "^2.1.0" 957 | 958 | shallow-clone@^3.0.0: 959 | version "3.0.1" 960 | resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" 961 | integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== 962 | dependencies: 963 | kind-of "^6.0.2" 964 | 965 | shebang-command@^2.0.0: 966 | version "2.0.0" 967 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 968 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 969 | dependencies: 970 | shebang-regex "^3.0.0" 971 | 972 | shebang-regex@^3.0.0: 973 | version "3.0.0" 974 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 975 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 976 | 977 | source-map-js@^1.0.2: 978 | version "1.0.2" 979 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 980 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 981 | 982 | source-map-support@~0.5.20: 983 | version "0.5.21" 984 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" 985 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 986 | dependencies: 987 | buffer-from "^1.0.0" 988 | source-map "^0.6.0" 989 | 990 | source-map@^0.6.0, source-map@~0.6.0: 991 | version "0.6.1" 992 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 993 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 994 | 995 | strip-ansi@^6.0.1: 996 | version "6.0.1" 997 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 998 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 999 | dependencies: 1000 | ansi-regex "^5.0.1" 1001 | 1002 | style-loader@^3.3.3: 1003 | version "3.3.3" 1004 | resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" 1005 | integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== 1006 | 1007 | supports-color@^8.0.0: 1008 | version "8.1.1" 1009 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 1010 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 1011 | dependencies: 1012 | has-flag "^4.0.0" 1013 | 1014 | supports-preserve-symlinks-flag@^1.0.0: 1015 | version "1.0.0" 1016 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1017 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1018 | 1019 | tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: 1020 | version "2.2.1" 1021 | resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" 1022 | integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== 1023 | 1024 | terser-webpack-plugin@^5.3.7: 1025 | version "5.3.9" 1026 | resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" 1027 | integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== 1028 | dependencies: 1029 | "@jridgewell/trace-mapping" "^0.3.17" 1030 | jest-worker "^27.4.5" 1031 | schema-utils "^3.1.1" 1032 | serialize-javascript "^6.0.1" 1033 | terser "^5.16.8" 1034 | 1035 | terser@^5.10.0, terser@^5.16.8: 1036 | version "5.19.4" 1037 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.4.tgz#941426fa482bf9b40a0308ab2b3cd0cf7c775ebd" 1038 | integrity sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g== 1039 | dependencies: 1040 | "@jridgewell/source-map" "^0.3.3" 1041 | acorn "^8.8.2" 1042 | commander "^2.20.0" 1043 | source-map-support "~0.5.20" 1044 | 1045 | tslib@^2.0.3: 1046 | version "2.6.2" 1047 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" 1048 | integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== 1049 | 1050 | twirpscript@^0.0.68: 1051 | version "0.0.68" 1052 | resolved "https://registry.yarnpkg.com/twirpscript/-/twirpscript-0.0.68.tgz#c24c82bfb14a0b50a0798972a3736c9ff2dd8f7e" 1053 | integrity sha512-HB/1B+03JQvHfLSP61pKO21dwghlR/qtR1IjijBPwv1/7IK6TkXw0RHM3zQH94ZdfRIsRBMxB0/8BgR6B7CgnQ== 1054 | dependencies: 1055 | protoscript "0.0.18" 1056 | 1057 | update-browserslist-db@^1.0.11: 1058 | version "1.0.11" 1059 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" 1060 | integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== 1061 | dependencies: 1062 | escalade "^3.1.1" 1063 | picocolors "^1.0.0" 1064 | 1065 | uri-js@^4.2.2: 1066 | version "4.4.1" 1067 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 1068 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 1069 | dependencies: 1070 | punycode "^2.1.0" 1071 | 1072 | util-deprecate@^1.0.2: 1073 | version "1.0.2" 1074 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1075 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 1076 | 1077 | utila@~0.4: 1078 | version "0.4.0" 1079 | resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" 1080 | integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== 1081 | 1082 | watchpack@^2.4.0: 1083 | version "2.4.0" 1084 | resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" 1085 | integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== 1086 | dependencies: 1087 | glob-to-regexp "^0.4.1" 1088 | graceful-fs "^4.1.2" 1089 | 1090 | webpack-cli@^5.1.4: 1091 | version "5.1.4" 1092 | resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" 1093 | integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== 1094 | dependencies: 1095 | "@discoveryjs/json-ext" "^0.5.0" 1096 | "@webpack-cli/configtest" "^2.1.1" 1097 | "@webpack-cli/info" "^2.0.2" 1098 | "@webpack-cli/serve" "^2.0.5" 1099 | colorette "^2.0.14" 1100 | commander "^10.0.1" 1101 | cross-spawn "^7.0.3" 1102 | envinfo "^7.7.3" 1103 | fastest-levenshtein "^1.0.12" 1104 | import-local "^3.0.2" 1105 | interpret "^3.1.1" 1106 | rechoir "^0.8.0" 1107 | webpack-merge "^5.7.3" 1108 | 1109 | webpack-merge@^5.7.3: 1110 | version "5.9.0" 1111 | resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" 1112 | integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== 1113 | dependencies: 1114 | clone-deep "^4.0.1" 1115 | wildcard "^2.0.0" 1116 | 1117 | webpack-sources@^3.2.3: 1118 | version "3.2.3" 1119 | resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" 1120 | integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== 1121 | 1122 | webpack@^5.88.2: 1123 | version "5.88.2" 1124 | resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" 1125 | integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== 1126 | dependencies: 1127 | "@types/eslint-scope" "^3.7.3" 1128 | "@types/estree" "^1.0.0" 1129 | "@webassemblyjs/ast" "^1.11.5" 1130 | "@webassemblyjs/wasm-edit" "^1.11.5" 1131 | "@webassemblyjs/wasm-parser" "^1.11.5" 1132 | acorn "^8.7.1" 1133 | acorn-import-assertions "^1.9.0" 1134 | browserslist "^4.14.5" 1135 | chrome-trace-event "^1.0.2" 1136 | enhanced-resolve "^5.15.0" 1137 | es-module-lexer "^1.2.1" 1138 | eslint-scope "5.1.1" 1139 | events "^3.2.0" 1140 | glob-to-regexp "^0.4.1" 1141 | graceful-fs "^4.2.9" 1142 | json-parse-even-better-errors "^2.3.1" 1143 | loader-runner "^4.2.0" 1144 | mime-types "^2.1.27" 1145 | neo-async "^2.6.2" 1146 | schema-utils "^3.2.0" 1147 | tapable "^2.1.1" 1148 | terser-webpack-plugin "^5.3.7" 1149 | watchpack "^2.4.0" 1150 | webpack-sources "^3.2.3" 1151 | 1152 | which@^2.0.1: 1153 | version "2.0.2" 1154 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1155 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1156 | dependencies: 1157 | isexe "^2.0.0" 1158 | 1159 | wildcard@^2.0.0: 1160 | version "2.0.1" 1161 | resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" 1162 | integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== 1163 | 1164 | yallist@^4.0.0: 1165 | version "4.0.0" 1166 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1167 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1168 | --------------------------------------------------------------------------------