├── .devcontainer ├── Dockerfile ├── devcontainer.json └── docker-compose.dev.yml ├── .dockerignore ├── .flake8 ├── .github ├── codeql │ └── codeql-config.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.development.md ├── README.md ├── RootTheBox.code-workspace ├── alembic ├── README ├── alembic.ini ├── env.py ├── script.py.mako └── versions │ ├── 098ab7c733ea_add_user_to_flag.py │ ├── 18d11f218dfe_box_rewards.py │ ├── 1ee5b63e716f_add_plain_answer_flag.py │ ├── 31918b83c372_add_box_order.py │ ├── 324e65d824d1_fix_password_token_length.py │ ├── 469f428604aa_box__capture_message.py │ ├── 4aa1bab989f8_add_email_token.py │ ├── 5ca019edf61f_cascade_on_delete.py │ ├── 67bf6ca63a9c_add_email_field.py │ ├── 71aa3c94b7f5_juiceshop_updates.py │ ├── 729a5113fc9c_flag_original_value_null.py │ ├── 83f862086ff0_add_flag_lock.py │ ├── 8fa7d8ac2b2f_add_password_token_table.py │ ├── 9443ded40161_add_box_lock.py │ ├── 9783dbd4d5fe_add_original_value.py │ ├── a143abd40133_expand_field_size.py │ ├── bc091b7be912_add_descriptive_columns.py │ ├── bd7bd19e98bd_sourcecode_cascade.py │ ├── cd4d09aa9c68_rename_column_visible.py │ ├── de5d615ae090_add_user_to_penalty_stat.py │ ├── eb3f7dc1b16f_add_flag__order_field.py │ ├── f443eed40161_add_corp_lock.py │ ├── fe5e615ae090_add_game_history_table.py │ └── ffe623ae412_delete_snapshot_tables.py ├── bot ├── BotMonitor.py ├── bot.py ├── build_bot.py └── rtb.ico ├── cyberchef ├── ChefWorker.js.LICENSE.txt ├── CyberChef.html ├── DishWorker.js.LICENSE.txt ├── InputWorker.js.LICENSE.txt ├── LoaderWorker.js.LICENSE.txt ├── ZipWorker.js.LICENSE.txt ├── assets │ ├── fonts │ │ ├── Roboto72White.fnt │ │ ├── Roboto72White.png │ │ ├── RobotoBlack72White.fnt │ │ ├── RobotoBlack72White.png │ │ ├── RobotoMono72White.fnt │ │ ├── RobotoMono72White.png │ │ ├── RobotoSlab72White.fnt │ │ └── RobotoSlab72White.png │ ├── forge │ │ └── prime.worker.min.js │ ├── main.css │ ├── main.js │ ├── main.js.LICENSE.txt │ └── tesseract │ │ ├── lang-data │ │ └── eng.traineddata.gz │ │ ├── tesseract-core.wasm.js │ │ ├── worker.min.js │ │ └── worker.min.js.LICENSE.txt ├── images │ ├── cook_male-32x32.png │ ├── cyberchef-128x128.png │ ├── file-128x128.png │ ├── file-32x32.png │ └── fork_me.png └── modules │ ├── Bletchley.js │ ├── Bletchley.js.LICENSE.txt │ ├── Charts.js │ ├── Charts.js.LICENSE.txt │ ├── Ciphers.js │ ├── Ciphers.js.LICENSE.txt │ ├── Code.js │ ├── Code.js.LICENSE.txt │ ├── Compression.js │ ├── Compression.js.LICENSE.txt │ ├── Crypto.js │ ├── Crypto.js.LICENSE.txt │ ├── Diff.js │ ├── Diff.js.LICENSE.txt │ ├── Encodings.js │ ├── Encodings.js.LICENSE.txt │ ├── Hashing.js │ ├── Hashing.js.LICENSE.txt │ ├── Image.js │ ├── Image.js.LICENSE.txt │ ├── OCR.js │ ├── OCR.js.LICENSE.txt │ ├── PGP.js │ ├── PGP.js.LICENSE.txt │ ├── Protobuf.js │ ├── Protobuf.js.LICENSE.txt │ ├── PublicKey.js │ ├── PublicKey.js.LICENSE.txt │ ├── Regex.js │ ├── Regex.js.LICENSE.txt │ ├── Serialise.js │ ├── Serialise.js.LICENSE.txt │ ├── Shellcode.js │ ├── Shellcode.js.LICENSE.txt │ ├── URL.js │ ├── URL.js.LICENSE.txt │ ├── UserAgent.js │ ├── UserAgent.js.LICENSE.txt │ ├── Yara.js │ └── Yara.js.LICENSE.txt ├── docker-compose.yml ├── files ├── avatars │ ├── box │ │ ├── README.md │ │ ├── attack.jpg │ │ ├── backlit_keyboard.jpg │ │ ├── capturetheflag.jpg │ │ ├── cybersecurity.jpg │ │ ├── cybersecurity2.jpg │ │ ├── digitalhead.jpg │ │ ├── directory.jpeg │ │ ├── hack.jpg │ │ ├── hacker.jpg │ │ ├── keyshield.jpeg │ │ ├── linux_logo.png │ │ ├── malware.jpg │ │ ├── malware2.jpg │ │ ├── matrix.jpg │ │ ├── memory.jpg │ │ ├── network.jpg │ │ ├── network2.jpg │ │ ├── security_key.jpg │ │ ├── webcode.jpeg │ │ └── windows_logo.png │ ├── default_box.jpg │ ├── default_team.jpg │ ├── default_user.jpg │ ├── team │ │ └── README.md │ ├── upload │ │ └── README.md │ └── user │ │ └── README.md ├── flag_attachments │ └── README.md ├── game_materials │ └── README.md ├── icons │ └── README.md ├── shares │ └── README.md ├── source_code_market │ └── README.md └── story │ └── README.md ├── handlers ├── APIHanders.py ├── AdminHandlers │ ├── AdminGameHandlers.py │ ├── AdminGameObjectHandlers.py │ ├── AdminUserHandlers.py │ └── __init__.py ├── BaseHandlers.py ├── BotnetHandlers.py ├── ChefHandler.py ├── ErrorHandlers.py ├── FileUploadHandlers.py ├── MarketHandlers.py ├── MaterialsHandler.py ├── MissionsHandler.py ├── NotificationHandlers.py ├── PastebinHandlers.py ├── PublicHandlers.py ├── ScoreboardHandlers.py ├── StaticFileHandler.py ├── UpgradeHandlers.py ├── UserHandlers.py └── __init__.py ├── libs ├── BotManager.py ├── ChatManager.py ├── ConfigHelpers.py ├── ConsoleColors.py ├── DatabaseConnection.py ├── EmailHelpers.py ├── EventManager.py ├── Identicon.py ├── Scoreboard.py ├── SecurityDecorators.py ├── Sessions.py ├── Singleton.py ├── StringCoding.py ├── ValidationError.py ├── WebhookHelpers.py ├── XSSImageCheck.py └── __init__.py ├── locale ├── ar.csv ├── bn.csv ├── ca.csv ├── de.csv ├── es.csv ├── fr.csv ├── hi.csv ├── ja.csv ├── ko.csv ├── pt.csv ├── ru.csv └── zh.csv ├── models ├── BaseModels.py ├── Box.py ├── Category.py ├── Corporation.py ├── EmailToken.py ├── FileUpload.py ├── Flag.py ├── FlagAttachment.py ├── FlagChoice.py ├── GameHistory.py ├── GameLevel.py ├── Hint.py ├── IpAddress.py ├── MarketItem.py ├── Notification.py ├── PasswordToken.py ├── PasteBin.py ├── Penalty.py ├── Permission.py ├── RegistrationToken.py ├── Relationships.py ├── SourceCode.py ├── Swat.py ├── Team.py ├── Theme.py ├── User.py ├── WallOfSheep.py └── __init__.py ├── modules ├── AppTheme.py ├── Menu.py ├── Recaptcha.py └── __init__.py ├── rootthebox.py ├── setup ├── __init__.py ├── bootstrap.py ├── create_database.py ├── dbupdate.sql ├── demo_juiceshop.xml ├── depends.sh ├── nginx.conf ├── nginx_vhost_rtb.conf ├── recovery.py ├── requirements.txt ├── restart.sh ├── rtb-upstart.conf ├── rtb.service └── xmlsetup.py ├── static ├── css │ ├── 32px.png │ ├── 40px.png │ ├── animate.css │ ├── bootstrap-responsive.css │ ├── docs.css │ ├── droidsans.css │ ├── font-awesome.min.css │ ├── icons.css │ ├── icons │ │ ├── application.png │ │ ├── cd.png │ │ ├── code.png │ │ ├── css.png │ │ ├── db.png │ │ ├── directory-lock.png │ │ ├── directory.png │ │ ├── doc.png │ │ ├── file-lock.png │ │ ├── file.png │ │ ├── film.png │ │ ├── flash.png │ │ ├── folder_open.png │ │ ├── hdd.png │ │ ├── html.png │ │ ├── java.png │ │ ├── linux.png │ │ ├── music.png │ │ ├── pcap.png │ │ ├── pdf.png │ │ ├── php.png │ │ ├── picture.png │ │ ├── ppt.png │ │ ├── psd.png │ │ ├── ruby.png │ │ ├── script.png │ │ ├── spinner.gif │ │ ├── txt.png │ │ ├── xls.png │ │ └── zip.png │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ ├── ui-icons_555555_256x240.png │ │ ├── ui-icons_777620_256x240.png │ │ ├── ui-icons_777777_256x240.png │ │ ├── ui-icons_cc0000_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ └── glyphicons-halflings.png │ ├── jquery-ui.css │ ├── jstree.css │ ├── login.css │ ├── main.css │ ├── markdown-toolbar.css │ ├── menu.css │ ├── notifier.css │ ├── pages │ │ ├── admin │ │ │ ├── configuration.css │ │ │ ├── game_objects.css │ │ │ └── home.css │ │ ├── public │ │ │ ├── feed.css │ │ │ ├── login.css │ │ │ ├── registration.css │ │ │ └── summary.css │ │ └── user │ │ │ └── home.css │ ├── terminal.css │ ├── themes │ │ ├── 386.css │ │ ├── 386.responsive.css │ │ ├── amelia.min.css │ │ ├── bootstrap.min.css │ │ ├── cerulean.min.css │ │ ├── cyborg.min.css │ │ ├── geocities.min.css │ │ ├── journal.min.css │ │ ├── readable.min.css │ │ ├── simplex.min.css │ │ ├── slate.min.css │ │ ├── spacelab.min.css │ │ ├── spruce.min.css │ │ ├── superhero.min.css │ │ └── united.min.css │ └── throbber.gif ├── epicsaxguy.mp3 ├── font │ ├── Fixedsys500c.eot │ ├── Fixedsys500c.otf │ ├── Fixedsys500c.svg │ ├── Fixedsys500c.ttf │ ├── Fixedsys500c.woff │ ├── FontAwesome.otf │ ├── droidsans-bold.woff │ ├── droidsans.woff │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── images │ ├── bf.png │ ├── blackheart.png │ ├── clippy.jpg │ ├── clippy.svg │ ├── ctftime.svg │ ├── dialog_overlay.png │ ├── epicsaxguy.gif │ ├── error.png │ ├── example.png │ ├── favicon.ico │ ├── federal_reserve.png │ ├── info.png │ ├── morris.jpg │ ├── password_security.png │ ├── rtb.jpg │ ├── rtb2.png │ ├── rtb3.jpg │ ├── rtb4.png │ ├── source_code_market.png │ ├── sprite.png │ ├── success.png │ ├── swat.png │ └── warning.png └── js │ ├── backbone.min.js │ ├── bootstrap.min.js │ ├── jquery-ui.min.js │ ├── jquery.min.js │ ├── libs │ ├── animator.min.js │ ├── clipboard │ │ ├── clipboard.min.js │ │ ├── clipfeed.js │ │ ├── snippets.js │ │ └── tooltips.js │ ├── commonmark.min.js │ ├── highcharts-all.js │ ├── highcharts-more.js │ ├── html5.js │ ├── jstree.js │ ├── markdown-toolbar.js │ ├── mousewheel-min.js │ ├── notifier.js │ └── terminal.min.js │ ├── pages │ ├── admin │ │ ├── configuration.js │ │ ├── create │ │ │ ├── box.js │ │ │ ├── category.js │ │ │ ├── corporation.js │ │ │ ├── flags.js │ │ │ ├── game_level.js │ │ │ ├── hint.js │ │ │ └── team.js │ │ ├── export.js │ │ ├── home.js │ │ ├── upgrades │ │ │ ├── source_code_market.js │ │ │ └── swat.js │ │ ├── users.js │ │ └── view │ │ │ ├── categories.js │ │ │ ├── game_levels.js │ │ │ ├── game_objects.js │ │ │ ├── market_objects.js │ │ │ ├── statistics.js │ │ │ └── token.js │ ├── anchor.js │ ├── botnet │ │ └── monitor.js │ ├── file_upload │ │ ├── material_files.js │ │ └── shared_files.js │ ├── main.js │ ├── market │ │ └── view.js │ ├── menu │ │ └── refresh.js │ ├── missions │ │ ├── box.js │ │ ├── captured.js │ │ ├── firstlogin.js │ │ └── view.js │ ├── pastebin.js │ ├── public │ │ ├── registration.js │ │ └── reset.js │ ├── scoreboard │ │ ├── feed.js │ │ ├── history.js │ │ ├── rankingTableUpdate.js │ │ ├── summary.js │ │ └── teams.js │ ├── upgrades │ │ ├── federal_reserve.js │ │ ├── source_code_market.js │ │ └── swat.js │ └── user │ │ ├── home.js │ │ └── settings.js │ ├── themes │ └── 386.js │ └── underscore.min.js ├── templates ├── admin │ ├── configuration.html │ ├── create │ │ ├── box.html │ │ ├── category.html │ │ ├── corporation.html │ │ ├── flag-choice.html │ │ ├── flag-datetime.html │ │ ├── flag-file.html │ │ ├── flag-regex.html │ │ ├── flag-static.html │ │ ├── flag.html │ │ ├── game_level.html │ │ ├── hint.html │ │ ├── team.html │ │ └── token.html │ ├── export.html │ ├── home.html │ ├── import.html │ ├── reset.html │ ├── upgrades │ │ ├── source_code_market.html │ │ └── swat.html │ └── view │ │ ├── categories.html │ │ ├── game_levels.html │ │ ├── game_objects.html │ │ ├── market_objects.html │ │ ├── notifications.html │ │ ├── pastebin.html │ │ ├── shared_files.html │ │ ├── statistics.html │ │ ├── token.html │ │ └── users.html ├── botnet │ └── monitor.html ├── file_upload │ ├── material_files.html │ └── shared_files.html ├── main.html ├── market │ └── view.html ├── menu │ ├── admin.html │ ├── public.html │ └── user.html ├── missions │ ├── box.html │ ├── captured.html │ ├── firstlogin.html │ ├── status.html │ └── view.html ├── notifications │ └── view.html ├── pastebin │ ├── create.html │ ├── display.html │ └── view.html ├── public │ ├── 403.html │ ├── 404.html │ ├── about.html │ ├── email.html │ ├── forgot.html │ ├── home.html │ ├── jointeam.html │ ├── login.html │ ├── noob.html │ ├── registration.html │ ├── reset.html │ ├── reset_email.html │ ├── stopped.html │ ├── successful_reg.html │ └── valid_email.html ├── recaptcha │ ├── captcha.html │ └── disabled.html ├── scoreboard │ ├── feed.html │ ├── history.html │ ├── mvp_table.html │ ├── summary.html │ ├── summary_table.html │ ├── teams.html │ └── wall_of_sheep.html ├── theme │ └── theme.html ├── upgrades │ ├── federal_reserve.html │ ├── password_security.html │ ├── source_code_market.html │ └── swat.html └── user │ ├── home.html │ └── settings.html └── tests ├── HTTPClient.py ├── Helpers.py ├── __init__.py ├── testHandlers.py └── testModels.py /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | 3 | ADD [ "https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb", "/" ] 4 | 5 | RUN apt-get -qq update \ 6 | && export DEBIAN_FRONTEND=noninteractive \ 7 | && apt-get -qq upgrade -y \ 8 | && apt-get -qq install -y --no-install-recommends \ 9 | lsb-release \ 10 | locales \ 11 | build-essential \ 12 | zlib1g-dev \ 13 | python3-pycurl \ 14 | # MySQL Tools 15 | && dpkg -i /mysql-apt-config_0.8.32-1_all.deb \ 16 | && apt-get -qq update \ 17 | && apt-get -qq install -y --no-install-recommends \ 18 | mysql-shell \ 19 | mysql-client \ 20 | # Clean up 21 | && apt-get autoremove -y \ 22 | && apt-get clean -y \ 23 | && rm -rf /var/lib/apt/lists/* \ 24 | && rm mysql-apt-config*.deb 25 | 26 | # Generate the en_US.UTF-8 locale used by mysqlsh 27 | RUN sed -Ei 's/^# en_US\.UTF-8 UTF-8$/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 28 | 29 | COPY ./setup/requirements.txt ./ 30 | RUN pip install --no-cache-dir -r requirements.txt --upgrade && pip install --upgrade pylint 31 | 32 | # Create a new user dev (1000 matches the default user in WSL) 33 | ARG USERNAME=rtbdev 34 | ARG UID=1000 35 | ARG GID=1000 36 | RUN groupadd --gid $GID $USERNAME 37 | RUN useradd --create-home --shell /bin/bash --uid $UID --gid $GID $USERNAME 38 | 39 | # Run with dev user 40 | USER $USERNAME 41 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rootthebox", 3 | "dockerComposeFile": ["../docker-compose.yml", "docker-compose.dev.yml"], 4 | "service": "webapp", 5 | "workspaceFolder": "/home/rtbdev/code/", 6 | "extensions": [ 7 | "ms-python.python", 8 | "redhat.vscode-xml" 9 | ], 10 | "forwardPorts": [ 8888 ], 11 | "settings": { 12 | "terminal.integrated.cwd": "/home/rtbdev/code/", 13 | "files.exclude": { 14 | "**/.devcontainer": true, 15 | "**/.vscode": true 16 | }, 17 | "launch": { 18 | "configurations": [ 19 | { 20 | "name": "RootTheBox", 21 | "type": "python", 22 | "request": "launch", 23 | "program": "rootthebox.py", 24 | "args": [ 25 | "--start", 26 | "--debug", 27 | "--autostart_game=True", 28 | "--autoreload_source=False" 29 | ], 30 | "console": "integratedTerminal", 31 | "serverReadyAction": { 32 | "action": "openExternally", 33 | "pattern": "Starting RTB on http://localhost:([0-9]+)", 34 | "uriFormat": "http://localhost:%s" 35 | } 36 | } 37 | ] 38 | } 39 | }, 40 | "postCreateCommand": [ 41 | "/usr/local/bin/python3", 42 | "/home/rtbdev/code/rootthebox.py", 43 | "--setup=prod", 44 | "--tests", 45 | "--sql_dialect=mysql", 46 | "--sql_host=mysql", 47 | "--sql_user=rtb", 48 | "--sql_password=rootthebox", 49 | "--memcached=memcached", 50 | "--admin_ips=[]", 51 | "--debug" 52 | ] 53 | } -------------------------------------------------------------------------------- /.devcontainer/docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | services: 2 | webapp: 3 | hostname: 'rtbdev' 4 | build: 5 | context: . 6 | dockerfile: .devcontainer/Dockerfile 7 | volumes: 8 | - .:/home/rtbdev/code/:cached 9 | command: /bin/sh -c "while sleep 1000; do :; done" 10 | depends_on: 11 | mysql: 12 | condition: service_healthy 13 | memcached: 14 | condition: service_started 15 | 16 | mysql: 17 | image: mysql:8.0 18 | hostname: 'mysql' 19 | command: >- 20 | --character-set-server=utf8mb4 21 | --collation-server=utf8mb4_general_ci 22 | --skip-name-resolve=OFF 23 | --default-authentication-plugin=mysql_native_password 24 | ports: 25 | - "3306:3306" 26 | healthcheck: 27 | test: ["CMD-SHELL", "mysqladmin ping -P 3306 | grep 'mysqld is alive' || exit 1"] 28 | interval: 5s 29 | timeout: 30s 30 | retries: 12 31 | environment: 32 | - MYSQL_ALLOW_EMPTY_PASSWORD=True 33 | - MYSQL_DATABASE=rootthebox 34 | - MYSQL_USER=rtb 35 | - MYSQL_PASSWORD=rootthebox 36 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .gitignore 3 | 4 | docker-compose.yml 5 | Dockerfile 6 | 7 | README.md 8 | LICENSE 9 | 10 | *.db 11 | files/*.cfg 12 | files/*.state 13 | files/*.key 14 | files/*.log 15 | files/data/*-* 16 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E203, E266, E501, W503, F403, F401, F405 3 | max-line-length = 88 4 | max-complexity = 18 5 | select = B,C,E,F,W,T4,B9 6 | per-file-ignores = 7 | setup/create_database.py:E402 8 | models/__init__.py:E402 -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "My CodeQL config" 2 | 3 | paths-ignore: 4 | - cyberchef 5 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [master, ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 23 * * 4' 11 | 12 | jobs: 13 | analyse: 14 | name: Analyse 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v2 20 | with: 21 | # We must fetch at least the immediate parents so that if this is 22 | # a pull request then we can checkout the head. 23 | fetch-depth: 2 24 | 25 | # Initializes the CodeQL tools for scanning. 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@v2 28 | with: 29 | config-file: ./.github/codeql/codeql-config.yml 30 | # Override language selection by uncommenting this and choosing your languages 31 | # with: 32 | # languages: go, javascript, csharp, python, cpp, java 33 | 34 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 35 | # If this step fails, then you should remove it and run the build manually (see below) 36 | - name: Autobuild 37 | uses: github/codeql-action/autobuild@v2 38 | 39 | # ℹ️ Command-line programs to run using the OS shell. 40 | # 📚 https://git.io/JvXDl 41 | 42 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 43 | # and modify them (or add more) to build your code if your project 44 | # uses a compiled language 45 | 46 | #- run: | 47 | # make bootstrap 48 | # make release 49 | 50 | - name: Perform CodeQL Analysis 51 | uses: github/codeql-action/analyze@v2 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Bytecode 2 | *.py[co] 3 | 4 | # Leftovers from merges 5 | *.orig 6 | 7 | # File uploads and what not 8 | files/avatars/*-* 9 | files/avatars/user/* 10 | 11 | files/avatars/team/* 12 | files/avatars/box/* 13 | files/avatars/upload/* 14 | files/story/* 15 | files/icons/*-* 16 | files/shares/*-* 17 | files/source_code_market/*-* 18 | files/game_materials/* 19 | files/flag_attachments/* 20 | files/*.db 21 | files/*.cfg 22 | 23 | #Alembic 24 | alembic/alembic.ini 25 | 26 | #Locale 27 | locale/.~* 28 | 29 | # Packages 30 | *.egg 31 | *.egg-info 32 | dist 33 | build 34 | eggs 35 | parts 36 | bin 37 | var 38 | sdist 39 | develop-eggs 40 | .installed.cfg 41 | 42 | # SSL Stuff 43 | *.crt 44 | *.key 45 | 46 | # XML exports 47 | *.xml 48 | !demo_juiceshop.xml 49 | 50 | # SQLite3 databases 51 | *.db 52 | *.db-journal 53 | 54 | # Screen files 55 | *.0 56 | 57 | # Log files 58 | *.log 59 | 60 | # Installer logs 61 | pip-log.txt 62 | 63 | # IDE 64 | .project 65 | .pydevproject 66 | .idea/* 67 | .vscode/* 68 | 69 | # OSX 70 | .DS_Store 71 | .dccache 72 | 73 | __pycache__ 74 | */__pycache__ 75 | 76 | # Backups 77 | *.bak 78 | 79 | # Readme 80 | !*README.md 81 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Docker test for Travis 2 | sudo: required 3 | language: python 4 | 5 | services: 6 | - docker 7 | 8 | install: 9 | - docker build --build-arg MODE=dev -t="rtb_w_sqlite" . 10 | 11 | script: 12 | - docker run -d -p 80:8888 --name="rtb_w_sqlite" rtb_w_sqlite 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #################################### 2 | # 3 | # Dockerfile for Root the Box 4 | # v0.1.3 - By Moloch, ElJeffe 5 | 6 | FROM python:3.8 7 | 8 | RUN mkdir /opt/rtb 9 | ADD . /opt/rtb 10 | 11 | RUN apt-get update && apt-get install -y \ 12 | build-essential zlib1g-dev rustc \ 13 | python3-pycurl sqlite3 libsqlite3-dev 14 | 15 | ADD ./setup/requirements.txt ./ 16 | RUN pip install --no-cache-dir -r requirements.txt --upgrade 17 | 18 | ENV SQL_DIALECT=sqlite 19 | 20 | VOLUME ["/opt/rtb/files"] 21 | ENTRYPOINT ["python3", "/opt/rtb/rootthebox.py", "--setup=docker"] 22 | -------------------------------------------------------------------------------- /README.development.md: -------------------------------------------------------------------------------- 1 | # First time we start developing with visual studio 2 | -Clone repo 3 | `git clone https://github.com/pedcremo/RootTheBox.git` 4 | -Install dependencies 5 | `sudo ./setup/depends.sh` 6 | -Create config file (PATH files/rootthebox.cfg) 7 | `./rootthebox.py --update` 8 | Edit files/rootthebox.cfg to set locale (i18n) and database. Sqlite to develop 9 | sql_dialect = "sqlite" 10 | -Create database schema 11 | `./rootthebox.py --setup=prod` 12 | 13 | # Every time we start to develop 14 | `./rootthebox.py --start` 15 | 16 | 17 | 18 | Cal fer còpia de: 19 | files/game_materials 20 | files/rootthebox.cfg 21 | files/botnet.db 22 | rootthebox.db 23 | 24 | 25 | MORE INFO: https://github.com/moloch--/RootTheBox/wiki/Installation -------------------------------------------------------------------------------- /RootTheBox.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "RootTheBox", 5 | "path": "." 6 | } 7 | ], 8 | "settings": {} 9 | } -------------------------------------------------------------------------------- /alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /alembic/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # timezone to use when rendering the date 11 | # within the migration file as well as the filename. 12 | # string value is passed to dateutil.tz.gettz() 13 | # leave blank for localtime 14 | # timezone = 15 | 16 | # max length of characters to apply to the 17 | # "slug" field 18 | #truncate_slug_length = 40 19 | 20 | # set to 'true' to run the environment during 21 | # the 'revision' command, regardless of autogenerate 22 | # revision_environment = false 23 | 24 | # set to 'true' to allow .pyc and .pyo files without 25 | # a source .py file to be detected as revisions in the 26 | # versions/ directory 27 | # sourceless = false 28 | 29 | # version location specification; this defaults 30 | # to alembic/versions. When using multiple version 31 | # directories, initial revisions must be specified with --version-path 32 | # version_locations = %(here)s/bar %(here)s/bat alembic/versions 33 | 34 | # the output encoding used when revision files 35 | # are written from script.py.mako 36 | # output_encoding = utf-8 37 | 38 | #sqlalchemy.url = driver://user:pass@localhost/dbname 39 | 40 | # Logging configuration 41 | [loggers] 42 | keys = root,sqlalchemy,alembic 43 | 44 | [handlers] 45 | keys = console 46 | 47 | [formatters] 48 | keys = generic 49 | 50 | [logger_root] 51 | level = WARN 52 | handlers = console 53 | qualname = 54 | 55 | [logger_sqlalchemy] 56 | level = WARN 57 | handlers = 58 | qualname = sqlalchemy.engine 59 | 60 | [logger_alembic] 61 | level = INFO 62 | handlers = 63 | qualname = alembic 64 | 65 | [handler_console] 66 | class = StreamHandler 67 | args = (sys.stderr,) 68 | level = NOTSET 69 | formatter = generic 70 | 71 | [formatter_generic] 72 | format = %(levelname)-5.5s [%(name)s] %(message)s 73 | datefmt = %H:%M:%S 74 | -------------------------------------------------------------------------------- /alembic/env.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | from logging.config import fileConfig 4 | 5 | from sqlalchemy import engine_from_config, pool 6 | 7 | from alembic import context 8 | 9 | # this is the Alembic Config object, which provides 10 | # access to the values within the .ini file in use. 11 | # alembic.context is only available for the env.py 12 | # script when it is executed through the alembic 13 | # pylint: disable=method-hidden,no-member 14 | config = context.config 15 | 16 | # Interpret the config file for Python logging. 17 | # This line sets up loggers basically. 18 | if config.attributes.get("configure_logger", True): 19 | fileConfig(config.config_file_name) 20 | 21 | # add your model's MetaData object here 22 | # for 'autogenerate' support 23 | # from myapp import mymodel 24 | # target_metadata = mymodel.Base.metadata 25 | target_metadata = None 26 | 27 | # other values from the config, defined by the needs of env.py, 28 | # can be acquired: 29 | # my_important_option = config.get_main_option("my_important_option") 30 | # ... etc. 31 | 32 | 33 | def run_migrations_offline(): 34 | """Run migrations in 'offline' mode. 35 | 36 | This configures the context with just a URL 37 | and not an Engine, though an Engine is acceptable 38 | here as well. By skipping the Engine creation 39 | we don't even need a DBAPI to be available. 40 | 41 | Calls to context.execute() here emit the given string to the 42 | script output. 43 | 44 | """ 45 | url = config.get_main_option("sqlalchemy.url") 46 | context.configure(url=url, target_metadata=target_metadata, literal_binds=True) 47 | 48 | with context.begin_transaction(): 49 | context.run_migrations() 50 | 51 | 52 | def run_migrations_online(): 53 | """Run migrations in 'online' mode. 54 | 55 | In this scenario we need to create an Engine 56 | and associate a connection with the context. 57 | 58 | """ 59 | connectable = engine_from_config( 60 | config.get_section(config.config_ini_section), 61 | prefix="sqlalchemy.", 62 | poolclass=pool.NullPool, 63 | ) 64 | 65 | with connectable.connect() as connection: 66 | context.configure(connection=connection, target_metadata=target_metadata) 67 | 68 | with context.begin_transaction(): 69 | context.run_migrations() 70 | 71 | 72 | if context.is_offline_mode(): 73 | run_migrations_offline() 74 | else: 75 | run_migrations_online() 76 | -------------------------------------------------------------------------------- /alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /alembic/versions/098ab7c733ea_add_user_to_flag.py: -------------------------------------------------------------------------------- 1 | """add user_to_flag 2 | 3 | Revision ID: 098ab7c733ea 4 | Revises: 4aa1bab989f8 5 | Create Date: 2021-08-08 23:03:49.444306 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "098ab7c733ea" 14 | down_revision = "4aa1bab989f8" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.create_table( 21 | "user_to_flag", 22 | sa.Column( 23 | "user_id", 24 | sa.Integer, 25 | sa.ForeignKey("user.id", ondelete="CASCADE"), 26 | nullable=False, 27 | ), 28 | sa.Column( 29 | "flag_id", 30 | sa.Integer, 31 | sa.ForeignKey("flag.id", ondelete="CASCADE"), 32 | nullable=False, 33 | ), 34 | ) 35 | op.add_column("category", sa.Column("_description", sa.VARCHAR(1024))) 36 | op.add_column("user", sa.Column("_expire", sa.DateTime)) 37 | 38 | 39 | def downgrade(): 40 | op.drop_table("user_to_flag") 41 | op.drop_column("category", "_description") 42 | op.drop_column("user", "_expire") 43 | -------------------------------------------------------------------------------- /alembic/versions/18d11f218dfe_box_rewards.py: -------------------------------------------------------------------------------- 1 | """Box Rewards 2 | 3 | Revision ID: 18d11f218dfe 4 | Revises: 5ca019edf61f 5 | Create Date: 2019-06-24 11:48:06.497803 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "18d11f218dfe" 14 | down_revision = "5ca019edf61f" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("box", sa.Column("_value", sa.INTEGER, nullable=True)) 21 | 22 | 23 | def downgrade(): 24 | op.drop_column("box", "_value") 25 | -------------------------------------------------------------------------------- /alembic/versions/1ee5b63e716f_add_plain_answer_flag.py: -------------------------------------------------------------------------------- 1 | """add_plain_answer_flag 2 | 3 | Revision ID: 1ee5b63e716f 4 | Revises: a143abd40133 5 | Create Date: 2024-02-15 11:17:27.270274 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from sqlalchemy.engine.reflection import Inspector 10 | from sqlalchemy.sql.expression import func 11 | 12 | from alembic import op 13 | 14 | # revision identifiers, used by Alembic. 15 | revision = '1ee5b63e716f' 16 | down_revision = 'a143abd40133' 17 | branch_labels = None 18 | depends_on = None 19 | 20 | try: 21 | conn = op.get_bind() 22 | inspector = Inspector.from_engine(conn) 23 | tables = inspector.get_table_names() 24 | except: 25 | conn = None 26 | inspector = None 27 | tables = None 28 | 29 | def _table_has_column(table, column): 30 | if not inspector: 31 | return True 32 | has_column = False 33 | for col in inspector.get_columns(table): 34 | if column not in col["name"]: 35 | continue 36 | has_column = True 37 | return has_column 38 | 39 | 40 | def _has_table(table_name): 41 | tables = inspector.get_table_names() 42 | return table_name in tables 43 | 44 | 45 | def upgrade(): 46 | if not _table_has_column("flag", "_plain_answer"): 47 | op.add_column("flag", sa.Column("_plain_answer", sa.VARCHAR(256))) 48 | 49 | 50 | def downgrade(): 51 | if _table_has_column("flag", "_plain_answer"): 52 | op.drop_column("flag", "_plain_answer") 53 | -------------------------------------------------------------------------------- /alembic/versions/31918b83c372_add_box_order.py: -------------------------------------------------------------------------------- 1 | """add box order 2 | 3 | Revision ID: 31918b83c372 4 | Revises: 83f862086ff0 5 | Create Date: 2022-10-12 23:02:22.212759 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "31918b83c372" 14 | down_revision = "83f862086ff0" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("box", sa.Column("_order", sa.INTEGER)) 21 | op.create_index("order", "box", ["_order"]) 22 | 23 | 24 | def downgrade(): 25 | op.drop_column("box", "_order") 26 | -------------------------------------------------------------------------------- /alembic/versions/324e65d824d1_fix_password_token_length.py: -------------------------------------------------------------------------------- 1 | """fix password_token length 2 | 3 | Revision ID: 324e65d824d1 4 | Revises: 8fa7d8ac2b2f 5 | Create Date: 2020-11-07 10:41:52.945898 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "324e65d824d1" 14 | down_revision = "8fa7d8ac2b2f" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("password_token") as batch_op: 21 | batch_op.alter_column( 22 | "value", 23 | existing_type=sa.VARCHAR(length=32), 24 | type_=sa.VARCHAR(length=64), 25 | ) 26 | 27 | 28 | def downgrade(): 29 | with op.batch_alter_table("password_token") as batch_op: 30 | batch_op.alter_column( 31 | "value", 32 | existing_type=sa.VARCHAR(length=64), 33 | type_=sa.VARCHAR(length=32), 34 | ) 35 | -------------------------------------------------------------------------------- /alembic/versions/469f428604aa_box__capture_message.py: -------------------------------------------------------------------------------- 1 | """box _capture_message 2 | 3 | Revision ID: 469f428604aa 4 | Revises: 729a5113fc9c 5 | Create Date: 2019-04-06 21:11:56.017968 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "469f428604aa" 14 | down_revision = "729a5113fc9c" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("box", sa.Column("_capture_message", sa.VARCHAR(length=1024))) 21 | 22 | 23 | def downgrade(): 24 | op.drop_column("box", "_capture_message") 25 | -------------------------------------------------------------------------------- /alembic/versions/4aa1bab989f8_add_email_token.py: -------------------------------------------------------------------------------- 1 | """add email token 2 | 3 | Revision ID: 4aa1bab989f8 4 | Revises: 324e65d824d1 5 | Create Date: 2021-01-29 13:39:42.842889 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "4aa1bab989f8" 14 | down_revision = "324e65d824d1" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.create_table( 21 | "email_token", 22 | sa.Column("id", sa.Integer, primary_key=True), 23 | sa.Column("created", sa.DateTime, nullable=True), 24 | sa.Column( 25 | "user_id", 26 | sa.Integer, 27 | sa.ForeignKey("user.id", ondelete="CASCADE"), 28 | nullable=False, 29 | ), 30 | sa.Column("value", sa.VARCHAR(length=64), nullable=False, unique=True), 31 | sa.Column("valid", sa.BOOLEAN), 32 | ) 33 | 34 | 35 | def downgrade(): 36 | op.drop_table("email_token") 37 | -------------------------------------------------------------------------------- /alembic/versions/67bf6ca63a9c_add_email_field.py: -------------------------------------------------------------------------------- 1 | """add email field 2 | 3 | Revision ID: 67bf6ca63a9c 4 | Revises: 9783dbd4d5fe 5 | Create Date: 2018-12-09 22:51:59.947266 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "67bf6ca63a9c" 14 | down_revision = "9783dbd4d5fe" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("user", sa.Column("_email", sa.VARCHAR(length=64))) 21 | 22 | 23 | def downgrade(): 24 | op.drop_column("user", "_email") 25 | -------------------------------------------------------------------------------- /alembic/versions/71aa3c94b7f5_juiceshop_updates.py: -------------------------------------------------------------------------------- 1 | """JuiceShop Updates 2 | 3 | Revision ID: 71aa3c94b7f5 4 | Revises: 18d11f218dfe 5 | Create Date: 2019-11-14 08:52:52.530520 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "71aa3c94b7f5" 14 | down_revision = "18d11f218dfe" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("category") as batch_op: 21 | batch_op.alter_column( 22 | "_category", 23 | existing_type=sa.VARCHAR(length=24), 24 | type_=sa.VARCHAR(length=64), 25 | ) 26 | 27 | 28 | def downgrade(): 29 | with op.batch_alter_table("category") as batch_op: 30 | batch_op.alter_column( 31 | "_category", 32 | existing_type=sa.VARCHAR(length=64), 33 | type_=sa.VARCHAR(length=24), 34 | ) 35 | -------------------------------------------------------------------------------- /alembic/versions/729a5113fc9c_flag_original_value_null.py: -------------------------------------------------------------------------------- 1 | """flag original_value null 2 | 3 | Revision ID: 729a5113fc9c 4 | Revises: eb3f7dc1b16f 5 | Create Date: 2019-02-26 21:13:42.243218 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "729a5113fc9c" 14 | down_revision = "eb3f7dc1b16f" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("flag") as batch_op: 21 | batch_op.alter_column( 22 | "_original_value", existing_type=sa.INTEGER, nullable=True 23 | ) 24 | 25 | 26 | def downgrade(): 27 | with op.batch_alter_table("flag") as batch_op: 28 | batch_op.alter_column( 29 | "_original_value", existing_type=sa.INTEGER, nullable=False 30 | ) 31 | -------------------------------------------------------------------------------- /alembic/versions/83f862086ff0_add_flag_lock.py: -------------------------------------------------------------------------------- 1 | """add flag lock 2 | 3 | Revision ID: 83f862086ff0 4 | Revises: cd4d09aa9c68 5 | Create Date: 2022-05-13 21:46:22.838283 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "83f862086ff0" 14 | down_revision = "cd4d09aa9c68" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("flag", sa.Column("_locked", sa.BOOLEAN)) 21 | 22 | 23 | def downgrade(): 24 | op.drop_column("flag", "_locked") 25 | -------------------------------------------------------------------------------- /alembic/versions/8fa7d8ac2b2f_add_password_token_table.py: -------------------------------------------------------------------------------- 1 | """add password_token table 2 | 3 | Revision ID: 8fa7d8ac2b2f 4 | Revises: 9443ded40161 5 | Create Date: 2020-09-06 19:23:34.831352 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "8fa7d8ac2b2f" 14 | down_revision = "9443ded40161" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.create_table( 21 | "password_token", 22 | sa.Column("id", sa.Integer, primary_key=True), 23 | sa.Column("created", sa.DateTime, nullable=True), 24 | sa.Column( 25 | "user_id", 26 | sa.Integer, 27 | sa.ForeignKey("user.id", ondelete="CASCADE"), 28 | nullable=False, 29 | ), 30 | sa.Column("value", sa.VARCHAR(length=64), nullable=False, unique=True), 31 | sa.Column("used", sa.BOOLEAN), 32 | ) 33 | 34 | 35 | def downgrade(): 36 | op.drop_table("password_token") 37 | -------------------------------------------------------------------------------- /alembic/versions/9443ded40161_add_box_lock.py: -------------------------------------------------------------------------------- 1 | """add box lock 2 | 3 | Revision ID: 9443ded40161 4 | Revises: bc091b7be912 5 | Create Date: 2020-03-07 17:01:22.454528 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "9443ded40161" 14 | down_revision = "bc091b7be912" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("box", sa.Column("_locked", sa.BOOLEAN)) 21 | 22 | 23 | def downgrade(): 24 | op.drop_column("box", "_locked") 25 | -------------------------------------------------------------------------------- /alembic/versions/9783dbd4d5fe_add_original_value.py: -------------------------------------------------------------------------------- 1 | """add original_value 2 | 3 | Revision ID: 9783dbd4d5fe 4 | Revises: 5 | Create Date: 2018-12-09 16:53:45.599267 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "9783dbd4d5fe" 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("hint") as batch_op: 21 | batch_op.alter_column( 22 | "_description", 23 | existing_type=sa.VARCHAR(length=512), 24 | type_=sa.VARCHAR(length=1024), 25 | ) 26 | op.add_column("flag", sa.Column("_original_value", sa.INTEGER)) 27 | 28 | 29 | def downgrade(): 30 | with op.batch_alter_table("hint") as batch_op: 31 | batch_op.alter_column( 32 | "_description", 33 | existing_type=sa.VARCHAR(length=1024), 34 | type_=sa.VARCHAR(length=512), 35 | ) 36 | op.drop_column("flag", "_original_value") 37 | -------------------------------------------------------------------------------- /alembic/versions/bc091b7be912_add_descriptive_columns.py: -------------------------------------------------------------------------------- 1 | """add descriptive columns 2 | 3 | Revision ID: bc091b7be912 4 | Revises: bd7bd19e98bd 5 | Create Date: 2020-03-03 18:23:40.855666 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "bc091b7be912" 14 | down_revision = "bd7bd19e98bd" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | op.add_column("user", sa.Column("_notes", sa.VARCHAR(512))) 21 | op.add_column("team", sa.Column("_notes", sa.VARCHAR(512))) 22 | op.add_column("game_level", sa.Column("_description", sa.VARCHAR(512))) 23 | op.add_column("corporation", sa.Column("_description", sa.VARCHAR(512))) 24 | 25 | 26 | def downgrade(): 27 | op.drop_column("user", "_notes") 28 | op.drop_column("team", "_notes") 29 | op.drop_column("game_level", "_description") 30 | op.drop_column("corporation", "_description") 31 | -------------------------------------------------------------------------------- /alembic/versions/bd7bd19e98bd_sourcecode_cascade.py: -------------------------------------------------------------------------------- 1 | """sourcecode cascade 2 | 3 | Revision ID: bd7bd19e98bd 4 | Revises: 71aa3c94b7f5 5 | Create Date: 2020-02-22 10:37:39.239191 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "bd7bd19e98bd" 14 | down_revision = "71aa3c94b7f5" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("source_code") as batch_op: 21 | batch_op.drop_constraint("source_code_ibfk_1", type_="foreignkey") 22 | op.create_foreign_key( 23 | "source_code_ibfk_1", 24 | "source_code", 25 | "box", 26 | ["box_id"], 27 | ["id"], 28 | ondelete="CASCADE", 29 | ) 30 | 31 | 32 | def downgrade(): 33 | with op.batch_alter_table("source_code") as batch_op: 34 | batch_op.drop_constraint("source_code_ibfk_1", type_="foreignkey") 35 | op.create_foreign_key( 36 | "source_code_ibfk_1", 37 | "source_code", 38 | "box", 39 | ["box_id"], 40 | ["id"], 41 | ondelete="RESTRICT", 42 | ) 43 | -------------------------------------------------------------------------------- /alembic/versions/cd4d09aa9c68_rename_column_visible.py: -------------------------------------------------------------------------------- 1 | """rename column visible 2 | 3 | Revision ID: cd4d09aa9c68 4 | Revises: 098ab7c733ea 5 | Create Date: 2022-01-05 10:00:05.629776 6 | 7 | """ 8 | import sqlalchemy as sa 9 | 10 | from alembic import op 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "cd4d09aa9c68" 14 | down_revision = "098ab7c733ea" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | with op.batch_alter_table("ip_address") as batch_op: 21 | batch_op.alter_column( 22 | "visable", new_column_name="visible", existing_type=sa.BOOLEAN 23 | ) 24 | 25 | 26 | def downgrade(): 27 | with op.batch_alter_table("ip_address") as batch_op: 28 | batch_op.alter_column( 29 | "visible", new_column_name="visable", existing_type=sa.BOOLEAN 30 | ) 31 | -------------------------------------------------------------------------------- /alembic/versions/de5d615ae090_add_user_to_penalty_stat.py: -------------------------------------------------------------------------------- 1 | """add user to penalty stat 2 | 3 | Revision ID: de5d615ae090 4 | Revises: 31918b83c372 5 | Create Date: 2022-10-14 19:33:02.808038 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from sqlalchemy.engine.reflection import Inspector 10 | 11 | from alembic import op 12 | 13 | try: 14 | conn = op.get_bind() 15 | inspector = Inspector.from_engine(conn) 16 | tables = inspector.get_table_names() 17 | except: 18 | conn = None 19 | inspector = None 20 | tables = None 21 | 22 | # revision identifiers, used by Alembic. 23 | revision = "de5d615ae090" 24 | down_revision = "31918b83c372" 25 | branch_labels = None 26 | depends_on = None 27 | 28 | 29 | def _table_has_column(table, column): 30 | if not inspector: 31 | return True 32 | has_column = False 33 | for col in inspector.get_columns(table): 34 | if column not in col["name"]: 35 | continue 36 | has_column = True 37 | return has_column 38 | 39 | 40 | def _has_table(table_name): 41 | tables = inspector.get_table_names() 42 | return table_name in tables 43 | 44 | 45 | def upgrade(): 46 | if not _table_has_column("penalty", "user_id"): 47 | with op.batch_alter_table("penalty") as batch_op: 48 | batch_op.add_column(sa.Column("user_id", sa.INTEGER)) 49 | batch_op.create_foreign_key( 50 | "penalty_ibfk_3", 51 | "user", 52 | ["user_id"], 53 | ["id"], 54 | ondelete="SET NULL", 55 | ) 56 | 57 | 58 | def downgrade(): 59 | if _table_has_column("penalty", "user_id"): 60 | op.drop_column("penalty", "user_id") 61 | -------------------------------------------------------------------------------- /alembic/versions/eb3f7dc1b16f_add_flag__order_field.py: -------------------------------------------------------------------------------- 1 | """add flag _order field 2 | 3 | Revision ID: eb3f7dc1b16f 4 | Revises: 67bf6ca63a9c 5 | Create Date: 2018-12-14 10:56:12.295780 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from sqlalchemy.engine.reflection import Inspector 10 | 11 | from alembic import op 12 | 13 | try: 14 | conn = op.get_bind() 15 | inspector = Inspector.from_engine(conn) 16 | tables = inspector.get_table_names() 17 | except: 18 | conn = None 19 | inspector = None 20 | tables = None 21 | 22 | # revision identifiers, used by Alembic. 23 | revision = "eb3f7dc1b16f" 24 | down_revision = "67bf6ca63a9c" 25 | branch_labels = None 26 | depends_on = None 27 | 28 | 29 | def _table_has_column(table, column): 30 | if not inspector: 31 | return True 32 | has_column = False 33 | for col in inspector.get_columns(table): 34 | if column not in col["name"]: 35 | continue 36 | has_column = True 37 | return has_column 38 | 39 | 40 | def _has_table(table_name): 41 | tables = inspector.get_table_names() 42 | return table_name in tables 43 | 44 | 45 | def upgrade(): 46 | if not _table_has_column("flag", "_order"): 47 | op.add_column("flag", sa.Column("_order", sa.INTEGER)) 48 | op.create_index("order", "flag", ["_order"]) 49 | 50 | 51 | def downgrade(): 52 | if _table_has_column("flag", "_order"): 53 | op.drop_column("flag", "_order") 54 | -------------------------------------------------------------------------------- /alembic/versions/f443eed40161_add_corp_lock.py: -------------------------------------------------------------------------------- 1 | """add corp lock 2 | 3 | Revision ID: f443eed40161 4 | Revises: ffe623ae412 5 | Create Date: 2023-05-27 17:01:22.454528 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from sqlalchemy.engine.reflection import Inspector 10 | from sqlalchemy.sql.expression import func 11 | 12 | from alembic import op 13 | 14 | try: 15 | conn = op.get_bind() 16 | inspector = Inspector.from_engine(conn) 17 | tables = inspector.get_table_names() 18 | except: 19 | conn = None 20 | inspector = None 21 | tables = None 22 | 23 | 24 | # revision identifiers, used by Alembic. 25 | revision = "f443eed40161" 26 | down_revision = "ffe623ae412" 27 | branch_labels = None 28 | depends_on = None 29 | 30 | 31 | def _table_has_column(table, column): 32 | if not inspector: 33 | return True 34 | has_column = False 35 | for col in inspector.get_columns(table): 36 | if column not in col["name"]: 37 | continue 38 | has_column = True 39 | return has_column 40 | 41 | 42 | def _has_table(table_name): 43 | tables = inspector.get_table_names() 44 | return table_name in tables 45 | 46 | 47 | def upgrade(): 48 | if not _table_has_column("corporation", "_locked"): 49 | op.add_column("corporation", sa.Column("_locked", sa.BOOLEAN)) 50 | if not _table_has_column("game_level", "_locked"): 51 | op.add_column("game_level", sa.Column("_locked", sa.BOOLEAN)) 52 | 53 | 54 | def downgrade(): 55 | if _table_has_column("corporation", "_locked"): 56 | op.drop_column("corporation", "_locked") 57 | if _table_has_column("game_level", "_locked"): 58 | op.drop_column("game_level", "_locked") 59 | -------------------------------------------------------------------------------- /alembic/versions/fe5e615ae090_add_game_history_table.py: -------------------------------------------------------------------------------- 1 | """add game history table 2 | 3 | Revision ID: fe5e615ae090 4 | Revises: de5d615ae090 5 | Create Date: 2023-02-28 19:33:02.808038 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from sqlalchemy.engine.reflection import Inspector 10 | from sqlalchemy.sql.expression import func 11 | 12 | from alembic import op 13 | 14 | try: 15 | conn = op.get_bind() 16 | inspector = Inspector.from_engine(conn) 17 | tables = inspector.get_table_names() 18 | except: 19 | conn = None 20 | inspector = None 21 | tables = None 22 | 23 | # revision identifiers, used by Alembic. 24 | revision = "fe5e615ae090" 25 | down_revision = "de5d615ae090" 26 | branch_labels = None 27 | depends_on = None 28 | 29 | 30 | def _table_has_column(table, column): 31 | if not inspector: 32 | return True 33 | has_column = False 34 | for col in inspector.get_columns(table): 35 | if column not in col["name"]: 36 | continue 37 | has_column = True 38 | return has_column 39 | 40 | 41 | def _has_table(table_name): 42 | tables = inspector.get_table_names() 43 | return table_name in tables 44 | 45 | 46 | def upgrade(): 47 | if not _has_table("game_history"): 48 | op.create_table( 49 | "game_history", 50 | sa.Column("id", sa.Integer, primary_key=True), 51 | sa.Column("created", sa.DateTime, nullable=True), 52 | sa.Column( 53 | "team_id", 54 | sa.Integer, 55 | sa.ForeignKey("team.id", ondelete="CASCADE"), 56 | nullable=False, 57 | ), 58 | sa.Column("_type", sa.VARCHAR(length=20), nullable=False), 59 | sa.Column("_value", sa.Integer, default=0, nullable=False), 60 | ) 61 | 62 | 63 | def downgrade(): 64 | if _has_table("game_history"): 65 | op.drop_table("game_history") 66 | -------------------------------------------------------------------------------- /bot/build_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Created on Feb 24, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | --------- 21 | 22 | Requires Py2Exe, builds a .exe file for easy of use on windows 23 | 24 | """ 25 | 26 | import os 27 | import sys 28 | from distutils.core import setup 29 | 30 | import py2exe 31 | 32 | sys.argv.append("py2exe") 33 | 34 | setup( 35 | options={"py2exe": {"bundle_files": 1, "compressed": 1, "optimize": 2}}, 36 | console=[{"script": "bot.py", "icon_resources": [(1, "rtb.ico")]}], 37 | zipfile=None, 38 | ) 39 | -------------------------------------------------------------------------------- /bot/rtb.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/bot/rtb.ico -------------------------------------------------------------------------------- /cyberchef/InputWorker.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * The buffer module from node.js, for the browser. 3 | * 4 | * @author Feross Aboukhadijeh 5 | * @license MIT 6 | */ 7 | 8 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ 9 | 10 | /** 11 | * Base64 functions. 12 | * 13 | * @author n1474335 [n1474335@gmail.com] 14 | * @copyright Crown Copyright 2016 15 | * @license Apache-2.0 16 | */ 17 | 18 | /** 19 | * Custom error type for handling operation input errors. 20 | * i.e. where the operation can handle the error and print a message to the screen. 21 | * 22 | * @author d98762625 [d98762625@gmail.com] 23 | * @copyright Crown Copyright 2018 24 | * @license Apache-2.0 25 | */ 26 | 27 | /** 28 | * CyberChef - The Cyber Swiss Army Knife 29 | * 30 | * @copyright Crown Copyright 2016 31 | * @license Apache-2.0 32 | * 33 | * Copyright 2016 Crown Copyright 34 | * 35 | * Licensed under the Apache License, Version 2.0 (the "License"); 36 | * you may not use this file except in compliance with the License. 37 | * You may obtain a copy of the License at 38 | * 39 | * http://www.apache.org/licenses/LICENSE-2.0 40 | * 41 | * Unless required by applicable law or agreed to in writing, software 42 | * distributed under the License is distributed on an "AS IS" BASIS, 43 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 44 | * See the License for the specific language governing permissions and 45 | * limitations under the License. 46 | */ 47 | 48 | /** 49 | * Decimal functions. 50 | * 51 | * @author n1474335 [n1474335@gmail.com] 52 | * @copyright Crown Copyright 2018 53 | * @license Apache-2.0 54 | */ 55 | 56 | /** 57 | * File signatures and extractor functions 58 | * 59 | * @author n1474335 [n1474335@gmail.com] 60 | * @copyright Crown Copyright 2018 61 | * @license Apache-2.0 62 | * 63 | */ 64 | 65 | /** 66 | * File type functions 67 | * 68 | * @author n1474335 [n1474335@gmail.com] 69 | * @copyright Crown Copyright 2018 70 | * @license Apache-2.0 71 | * 72 | */ 73 | 74 | /** 75 | * Stream class for parsing binary protocols. 76 | * 77 | * @author n1474335 [n1474335@gmail.com] 78 | * @author tlwr [toby@toby.codes] 79 | * @copyright Crown Copyright 2018 80 | * @license Apache-2.0 81 | * 82 | */ 83 | 84 | /** 85 | * Web worker to handle the inputs. 86 | * Handles storage, modification and retrieval of the inputs. 87 | * 88 | * @author j433866 [j433866@gmail.com] 89 | * @copyright Crown Copyright 2019 90 | * @license Apache-2.0 91 | */ 92 | -------------------------------------------------------------------------------- /cyberchef/LoaderWorker.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * CyberChef - The Cyber Swiss Army Knife 3 | * 4 | * @copyright Crown Copyright 2016 5 | * @license Apache-2.0 6 | * 7 | * Copyright 2016 Crown Copyright 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | /** 23 | * Web Worker to load large amounts of data without locking up the UI. 24 | * 25 | * @author n1474335 [n1474335@gmail.com] 26 | * @copyright Crown Copyright 2017 27 | * @license Apache-2.0 28 | */ 29 | -------------------------------------------------------------------------------- /cyberchef/assets/fonts/Roboto72White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/assets/fonts/Roboto72White.png -------------------------------------------------------------------------------- /cyberchef/assets/fonts/RobotoBlack72White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/assets/fonts/RobotoBlack72White.png -------------------------------------------------------------------------------- /cyberchef/assets/fonts/RobotoMono72White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/assets/fonts/RobotoMono72White.png -------------------------------------------------------------------------------- /cyberchef/assets/fonts/RobotoSlab72White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/assets/fonts/RobotoSlab72White.png -------------------------------------------------------------------------------- /cyberchef/assets/tesseract/lang-data/eng.traineddata.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/assets/tesseract/lang-data/eng.traineddata.gz -------------------------------------------------------------------------------- /cyberchef/assets/tesseract/worker.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * The buffer module from node.js, for the browser. 3 | * 4 | * @author Feross Aboukhadijeh 5 | * @license MIT 6 | */ 7 | 8 | /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */ 9 | -------------------------------------------------------------------------------- /cyberchef/images/cook_male-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/images/cook_male-32x32.png -------------------------------------------------------------------------------- /cyberchef/images/cyberchef-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/images/cyberchef-128x128.png -------------------------------------------------------------------------------- /cyberchef/images/file-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/images/file-128x128.png -------------------------------------------------------------------------------- /cyberchef/images/file-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/images/file-32x32.png -------------------------------------------------------------------------------- /cyberchef/images/fork_me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/cyberchef/images/fork_me.png -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | memcached: 4 | image: memcached:latest 5 | ports: 6 | - "11211:11211" 7 | webapp: 8 | build: . 9 | ports: 10 | - "8888:8888" 11 | volumes: 12 | - ./files:/opt/rtb/files:rw 13 | environment: 14 | - COMPOSE_CONVERT_WINDOWS_PATHS=1 15 | -------------------------------------------------------------------------------- /files/avatars/box/README.md: -------------------------------------------------------------------------------- 1 | Box Avatars 2 | ============= 3 | Admin provided Box Avatars can be placed in this directory. w500 x h250, 'png', 'jpeg', 'gif', 'bmp' -------------------------------------------------------------------------------- /files/avatars/box/attack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/attack.jpg -------------------------------------------------------------------------------- /files/avatars/box/backlit_keyboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/backlit_keyboard.jpg -------------------------------------------------------------------------------- /files/avatars/box/capturetheflag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/capturetheflag.jpg -------------------------------------------------------------------------------- /files/avatars/box/cybersecurity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/cybersecurity.jpg -------------------------------------------------------------------------------- /files/avatars/box/cybersecurity2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/cybersecurity2.jpg -------------------------------------------------------------------------------- /files/avatars/box/digitalhead.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/digitalhead.jpg -------------------------------------------------------------------------------- /files/avatars/box/directory.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/directory.jpeg -------------------------------------------------------------------------------- /files/avatars/box/hack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/hack.jpg -------------------------------------------------------------------------------- /files/avatars/box/hacker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/hacker.jpg -------------------------------------------------------------------------------- /files/avatars/box/keyshield.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/keyshield.jpeg -------------------------------------------------------------------------------- /files/avatars/box/linux_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/linux_logo.png -------------------------------------------------------------------------------- /files/avatars/box/malware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/malware.jpg -------------------------------------------------------------------------------- /files/avatars/box/malware2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/malware2.jpg -------------------------------------------------------------------------------- /files/avatars/box/matrix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/matrix.jpg -------------------------------------------------------------------------------- /files/avatars/box/memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/memory.jpg -------------------------------------------------------------------------------- /files/avatars/box/network.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/network.jpg -------------------------------------------------------------------------------- /files/avatars/box/network2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/network2.jpg -------------------------------------------------------------------------------- /files/avatars/box/security_key.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/security_key.jpg -------------------------------------------------------------------------------- /files/avatars/box/webcode.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/webcode.jpeg -------------------------------------------------------------------------------- /files/avatars/box/windows_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/box/windows_logo.png -------------------------------------------------------------------------------- /files/avatars/default_box.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/default_box.jpg -------------------------------------------------------------------------------- /files/avatars/default_team.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/default_team.jpg -------------------------------------------------------------------------------- /files/avatars/default_user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/files/avatars/default_user.jpg -------------------------------------------------------------------------------- /files/avatars/team/README.md: -------------------------------------------------------------------------------- 1 | Team Avatars 2 | ============= 3 | Admin provided Team Avatars can be placed in this directory. w500 x h250, 'png', 'jpeg', 'gif', 'bmp', 'svg' 4 | -------------------------------------------------------------------------------- /files/avatars/upload/README.md: -------------------------------------------------------------------------------- 1 | Avatar Uploads 2 | ============= 3 | User based avatar uploads are placed in this directory by RTB. -------------------------------------------------------------------------------- /files/avatars/user/README.md: -------------------------------------------------------------------------------- 1 | User Avatars 2 | ============= 3 | Admin provided User Avatars can be placed in this directory. w500 x h250, 'png', 'jpeg', 'gif', 'bmp', 'svg' 4 | -------------------------------------------------------------------------------- /files/flag_attachments/README.md: -------------------------------------------------------------------------------- 1 | Placeholder 2 | ============= 3 | -------------------------------------------------------------------------------- /files/game_materials/README.md: -------------------------------------------------------------------------------- 1 | Game Materials 2 | ============= 3 | Location for you to drop game materials that the player can use in the game - such as documents, files, applications, forensic images, etc. Can include folder structure. 4 | If a folder is named after a box and use_box_materials_dir is True, the files within will be noted in the box page. 5 | -------------------------------------------------------------------------------- /files/icons/README.md: -------------------------------------------------------------------------------- 1 | Placeholder 2 | ============= 3 | -------------------------------------------------------------------------------- /files/shares/README.md: -------------------------------------------------------------------------------- 1 | Placeholder 2 | ============= 3 | -------------------------------------------------------------------------------- /files/source_code_market/README.md: -------------------------------------------------------------------------------- 1 | Placeholder 2 | ============= 3 | -------------------------------------------------------------------------------- /files/story/README.md: -------------------------------------------------------------------------------- 1 | Story Avatars 2 | ============= 3 | Admin provided Story Images can be placed in this directory and referenced by "/story/imagefile.jpg". 4 | -------------------------------------------------------------------------------- /handlers/APIHanders.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 13, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | ---------------------------------------------------------------------------- 21 | 22 | This file contains handlers related to the file sharing functionality 23 | 24 | """ 25 | 26 | 27 | import json 28 | import logging 29 | 30 | from libs.SecurityDecorators import apikey, restrict_ip_address 31 | 32 | from .AdminHandlers.AdminGameHandlers import AdminGameHandler 33 | from .BaseHandlers import BaseHandler 34 | 35 | 36 | class APIActionHandler(BaseHandler): 37 | 38 | @apikey 39 | @restrict_ip_address 40 | def post(self, *args, **kwargs): 41 | actions = AdminGameHandler.admin_actions(self) 42 | self.write(json.dumps(actions)) 43 | 44 | def check_xsrf_cookie(self): 45 | pass 46 | -------------------------------------------------------------------------------- /handlers/AdminHandlers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Nov 24, 2014 4 | 5 | @author: moloch 6 | 7 | Copyright 2014 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | 22 | This file contains all of the administrative functions. 23 | There's a lot of code in here ... and it's mostly ugly validation code... 24 | 25 | Guidelines for writing code in this file: 26 | - GET requests should NEVER alter application state 27 | - All functions should check authentication/IP address/permission 28 | """ 29 | 30 | from .AdminGameHandlers import * 31 | from .AdminGameObjectHandlers import * 32 | from .AdminUserHandlers import * 33 | -------------------------------------------------------------------------------- /handlers/ChefHandler.py: -------------------------------------------------------------------------------- 1 | from handlers.BaseHandlers import BaseHandler 2 | from libs.SecurityDecorators import authenticated 3 | 4 | 5 | class ChefHandler(BaseHandler): 6 | @authenticated 7 | def get(self): 8 | with open("cyberchef/CyberChef.html", "r") as myfile: 9 | data = myfile.read() 10 | self.write(data) 11 | -------------------------------------------------------------------------------- /handlers/NotificationHandlers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 15, 2012 4 | 5 | @author: haddaway, moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | import logging 23 | 24 | from handlers.BaseHandlers import BaseHandler, BaseWebSocketHandler 25 | from libs.EventManager import EventManager 26 | from libs.SecurityDecorators import * 27 | 28 | 29 | class NotifySocketHandler(BaseWebSocketHandler): 30 | 31 | """Handles websocket connections""" 32 | 33 | event_manager = EventManager.instance() 34 | 35 | def open(self): 36 | """When we receive a new websocket connect""" 37 | self.event_manager.add_connection(self) 38 | if self.session is not None and "team_id" in self.session: 39 | logging.debug( 40 | "Opened new websocket with user id: %s" % (self.session["user_id"],) 41 | ) 42 | self.io_loop.add_callback( 43 | self.event_manager.push_user, self.team_id, self.user_id 44 | ) 45 | else: 46 | logging.debug("[Web Socket] Opened public notification socket.") 47 | 48 | def on_close(self): 49 | """Lost connection to client""" 50 | self.event_manager.remove_connection(self) 51 | 52 | @property 53 | def team_id(self): 54 | if self.session is not None and "team_id" in self.session: 55 | return self.session["team_id"] 56 | 57 | @team_id.setter 58 | def team_id(self, value): 59 | raise ValueError("Cannot set team_id") 60 | 61 | @property 62 | def user_id(self): 63 | if self.session is not None and "user_id" in self.session: 64 | return self.session["user_id"] 65 | 66 | @user_id.setter 67 | def user_id(self, value): 68 | raise ValueError("Cannot set user_id") 69 | 70 | 71 | class AllNotificationsHandler(BaseHandler): 72 | @authenticated 73 | def get(self, *args, **kwargs): 74 | user = self.get_current_user() 75 | self.render("notifications/view.html", user=user) 76 | -------------------------------------------------------------------------------- /handlers/StaticFileHandler.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 13, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | ------------- 21 | 22 | Modification of the tornado web StaticFileHandler 23 | 24 | """ 25 | 26 | 27 | import logging 28 | 29 | from tornado.options import options 30 | from tornado.web import StaticFileHandler as DefaultStaticHandler 31 | 32 | 33 | class StaticFileHandler(DefaultStaticHandler): 34 | 35 | """ 36 | Same as the normal Tornado StaticFileHandler with a 37 | couple overloaded methods. 38 | """ 39 | 40 | session = None 41 | config = options 42 | 43 | def set_default_headers(self): 44 | """ 45 | We need to add the security headers here too, especially the 46 | X-Content-Type-Options header, since we whitelist file extensions. 47 | this should prevent anyone from serving html/etc from the static 48 | handler 49 | """ 50 | if options.force_download_game_materials: 51 | self.set_header("Content-Disposition", "attachment") 52 | self.set_header("Server", "Microsoft-IIS/7.5") 53 | self.add_header("X-AspNetMvc-Version", "3.0") 54 | self.add_header("X-AspNet-Version", "4.0.30319") 55 | self.add_header("X-Powered-By", "ASP.NET") 56 | self.add_header("X-Frame-Options", "DENY") 57 | self.add_header("X-XSS-Protection", "1; mode=block") 58 | self.add_header("X-Content-Type-Options", "nosniff") 59 | if self.config.ssl: 60 | self.add_header("Strict-Transport-Security", "max-age=31536000;") 61 | 62 | def write_error(self, status_code, **kwargs): 63 | """Render a generic error page""" 64 | logging.error( 65 | "Static file request from %s resulted in %d status" 66 | % (self.request.remote_ip, status_code) 67 | ) 68 | # Regardless of error, send a 404 69 | self.render("public/404.html") 70 | -------------------------------------------------------------------------------- /libs/ConsoleColors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2012 Root the Box 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | """ 17 | 18 | import platform 19 | 20 | if platform.system().lower() in ["linux", "darwin"]: 21 | 22 | # === Text Colors === 23 | W = "\033[0m" # default/white 24 | BLA = "\033[30m" # black 25 | R = "\033[31m" # red 26 | G = "\033[32m" # green 27 | O = "\033[33m" # orange 28 | BLU = "\033[34m" # blue 29 | P = "\033[35m" # purple 30 | C = "\033[36m" # cyan 31 | GR = "\033[37m" # gray 32 | 33 | # === Styles === 34 | bold = "\033[1m" 35 | underline = "\033[4m" 36 | blink = "\033[5m" 37 | reverse = "\033[7m" 38 | concealed = "\033[8m" 39 | 40 | # === Background Colors === 41 | bkgd_black = "\033[40m" 42 | bkgd_red = "\033[41m" 43 | bkgd_green = "\033[42m" 44 | bkgd_yellow = "\033[43m" 45 | bkgd_blue = "\033[44m" 46 | bkgd_magenta = "\033[45m" 47 | bkgd_cyan = "\033[46m" 48 | bkgd_white = "\033[47m" 49 | 50 | else: 51 | 52 | # Sets all colors to blank strings 53 | # === Text Colors === 54 | W = "" 55 | BLA = "" 56 | R = "" 57 | G = "" 58 | O = "" 59 | BLU = "" 60 | P = "" 61 | C = "" 62 | GR = "" 63 | 64 | # === Styles === 65 | bold = "" 66 | underline = "" 67 | blink = "" 68 | reverse = "" 69 | concealed = "" 70 | 71 | # === Background Colors === 72 | bkgd_black = "" 73 | bkgd_red = "" 74 | bkgd_green = "" 75 | bkgd_yellow = "" 76 | bkgd_blue = "" 77 | bkgd_magenta = "" 78 | bkgd_cyan = "" 79 | bkgd_white = "" 80 | 81 | # === Macros === 82 | INFO = bold + C + "[*] " + W 83 | WARN = bold + R + "[!] " + W 84 | PROMPT = bold + P + "[?] " + W 85 | -------------------------------------------------------------------------------- /libs/Identicon.py: -------------------------------------------------------------------------------- 1 | # source: https://github.com/evuez/svg-identicon 2 | # Modified for 2 x 1 ratio - RootTheBox 3 | from hashlib import md5 4 | from os import path 5 | 6 | from tornado.options import options 7 | 8 | 9 | def _svg(width, height, body, color): 10 | return """ 11 | 15 | 16 | {body} 17 | """.format( 18 | w=width, h=height, body=body, color=color 19 | ) 20 | 21 | 22 | def _rect(x, y, width, height, color, stroke, stroke_weight): 23 | return ''.format( 24 | x, y, width, height, color, stroke, stroke_weight 25 | ) 26 | 27 | 28 | def identicon(str_, size, background="#f0f0f0", square=False): 29 | digest = int(md5(str_.encode("utf-8")).hexdigest(), 16) 30 | color = "#{:06x}".format(digest & 0xFFFFFF) 31 | stroke_weight = 0.02 32 | digest, body = digest >> 24, "" 33 | x = y = 0 34 | if square: 35 | for t in range(size**2 // 2): 36 | if digest & 1: 37 | body += _rect(x, y, 1, 1, color, background, stroke_weight) 38 | body += _rect(size - x - 1, y, 1, 1, color, background, stroke_weight) 39 | digest, y = digest >> 1, y + 1 40 | x, y = (x + 1, 0) if y == size else (x, y) 41 | image_data = _svg(size, size, body, background) 42 | else: 43 | for t in range(size**2): 44 | if digest & 1: 45 | body += _rect(x, y, 1, 1, color, background, stroke_weight) 46 | body += _rect( 47 | size * 2 - x - 1, y, 1, 1, color, background, stroke_weight 48 | ) 49 | digest, y = digest >> 1, y + 1 50 | x, y = (x + 1, 0) if y == size else (x, y) 51 | image_data = _svg(size * 2, size, body, background) 52 | avatar = "upload/%s.svg" % str(digest) 53 | file_path = path.join(options.avatar_dir, avatar) 54 | with open(file_path, "w") as fp: 55 | fp.write(image_data) 56 | return avatar 57 | -------------------------------------------------------------------------------- /libs/Singleton.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @author: moloch 4 | 5 | Copyright 2013 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | """ 19 | 20 | 21 | from builtins import object 22 | from threading import Lock 23 | 24 | 25 | class Singleton(object): 26 | """Thread safe singleton""" 27 | 28 | def __init__(self, decorated): 29 | self._decorated = decorated 30 | self._instance_lock = Lock() 31 | 32 | def instance(self): 33 | """ 34 | Returns the singleton instance. Upon its first call, it creates a 35 | new instance of the decorated class and calls its `__init__` method. 36 | On all subsequent calls, the already created instance is returned. 37 | """ 38 | if not hasattr(self, "_instance"): 39 | with self._instance_lock: 40 | if not hasattr(self, "_instance"): 41 | self._instance = self._decorated() 42 | return self._instance 43 | 44 | def __call__(self): 45 | raise TypeError("Singletons must be accessed through the `instance` method.") 46 | -------------------------------------------------------------------------------- /libs/ValidationError.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @author: moloch 4 | 5 | Copyright 2013 6 | 7 | -------------------------------------------- 8 | 9 | Custom exception we throw when validating model data 10 | 11 | """ 12 | 13 | 14 | class ValidationError(Exception): 15 | 16 | """Maybe extend this later""" 17 | 18 | def __init__(self, message): 19 | Exception.__init__(self, message) 20 | -------------------------------------------------------------------------------- /libs/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /models/BaseModels.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 12, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | import re 23 | from builtins import object 24 | from datetime import datetime 25 | 26 | from sqlalchemy import Column 27 | from sqlalchemy.ext.declarative import declarative_base, declared_attr 28 | from sqlalchemy.types import DateTime, Integer 29 | 30 | 31 | class _DatabaseObject(object): 32 | 33 | """All game objects inherit from this object""" 34 | 35 | @declared_attr 36 | def __tablename__(self): 37 | """Converts name from camel case to snake case""" 38 | name = self.__name__ 39 | return name[0].lower() + re.sub( 40 | r"([A-Z])", lambda letter: "_" + letter.group(0).lower(), name[1:] 41 | ) 42 | 43 | id = Column(Integer, primary_key=True) # lint:ok 44 | created = Column(DateTime, default=datetime.now) 45 | 46 | 47 | # Create an instance called "BaseObject" 48 | DatabaseObject = declarative_base(cls=_DatabaseObject) 49 | -------------------------------------------------------------------------------- /models/EmailToken.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Jan 29, 2021 4 | 5 | @author: eljeffe 6 | 7 | Copyright 2021 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from datetime import datetime, timedelta 24 | from hashlib import sha256 25 | from os import urandom 26 | 27 | from sqlalchemy import Column, ForeignKey, desc 28 | from sqlalchemy.types import Boolean, Integer, String 29 | 30 | from libs.StringCoding import encode 31 | from models import dbsession 32 | from models.BaseModels import DatabaseObject 33 | 34 | 35 | class EmailToken(DatabaseObject): 36 | """Email verification token definition""" 37 | 38 | user_id = Column(Integer, ForeignKey("user.id", ondelete="CASCADE"), nullable=False) 39 | value = Column(String(64), unique=True, nullable=False) 40 | valid = Column(Boolean, nullable=False, default=False) 41 | 42 | @classmethod 43 | def all(cls): 44 | """Returns a list of all objects in the database""" 45 | return dbsession.query(cls).all() 46 | 47 | @classmethod 48 | def by_id(cls, _id): 49 | """Returns the object with id of _id""" 50 | return dbsession.query(cls).filter_by(id=_id).first() 51 | 52 | @classmethod 53 | def by_user_id(cls, user_id, all=False): 54 | """Returns the object with id of user_id""" 55 | if all: 56 | return dbsession.query(cls).filter_by(user_id=user_id).all() 57 | else: 58 | return ( 59 | dbsession.query(cls) 60 | .filter_by(user_id=user_id) 61 | .order_by(desc("id")) 62 | .first() 63 | ) 64 | 65 | @classmethod 66 | def count(cls): 67 | """Returns a count of all objects in the database""" 68 | return dbsession.query(cls).count() 69 | 70 | @classmethod 71 | def by_value(cls, value): 72 | """Returns the object with value of value""" 73 | return dbsession.query(cls).filter_by(value=value).order_by(desc("id")).first() 74 | -------------------------------------------------------------------------------- /models/MarketItem.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 12, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | import json 24 | from builtins import str 25 | from uuid import uuid4 26 | 27 | from sqlalchemy import Column 28 | from sqlalchemy.types import Integer, String, Unicode 29 | 30 | from models import dbsession 31 | from models.BaseModels import DatabaseObject 32 | 33 | 34 | class MarketItem(DatabaseObject): 35 | """Item definition""" 36 | 37 | uuid = Column(String(36), unique=True, nullable=False, default=lambda: str(uuid4())) 38 | name = Column(Unicode(64), nullable=False) 39 | price = Column(Integer, nullable=False) 40 | image = Column(Unicode(256), nullable=False) 41 | description = Column(Unicode(1024)) 42 | 43 | @classmethod 44 | def all(cls): 45 | """Returns a list of all objects in the database""" 46 | return dbsession.query(cls).all() 47 | 48 | @classmethod 49 | def by_id(cls, _id): 50 | """Returns a the object with id of _id""" 51 | return dbsession.query(cls).filter_by(id=_id).first() 52 | 53 | @classmethod 54 | def by_uuid(cls, _uuid): 55 | """Returns a the object with a given uuid""" 56 | return dbsession.query(cls).filter_by(uuid=str(_uuid)).first() 57 | 58 | @classmethod 59 | def by_name(cls, _name): 60 | """Returns an object with a given name""" 61 | return dbsession.query(cls).filter_by(name=str(_name)).first() 62 | 63 | def to_dict(self): 64 | """Returns object data as dictionary object""" 65 | return { 66 | "name": self.name, 67 | "price": self.price, 68 | "image": self.image, 69 | "description": self.description, 70 | "uuid": self.uuid, 71 | } 72 | 73 | def __eq__(self, other): 74 | """Equivalency""" 75 | return self.uuid == other.uuid 76 | 77 | def __ne__(self, other): 78 | """Not Equivalent""" 79 | return not self == other 80 | 81 | def __hash__(self): 82 | return hash(self.name) 83 | -------------------------------------------------------------------------------- /models/PasswordToken.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sep 6, 2020 4 | 5 | @author: eljeffe 6 | 7 | Copyright 2020 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from datetime import datetime, timedelta 24 | from hashlib import sha256 25 | from os import urandom 26 | 27 | from sqlalchemy import Column, ForeignKey 28 | from sqlalchemy.types import Boolean, Integer, String 29 | 30 | from libs.StringCoding import encode 31 | from models import dbsession 32 | from models.BaseModels import DatabaseObject 33 | 34 | 35 | class PasswordToken(DatabaseObject): 36 | """Password token definition""" 37 | 38 | user_id = Column(Integer, ForeignKey("user.id", ondelete="CASCADE"), nullable=False) 39 | value = Column(String(64), unique=True, nullable=False) 40 | used = Column(Boolean, nullable=False, default=False) 41 | 42 | @classmethod 43 | def all(cls): 44 | """Returns a list of all objects in the database""" 45 | return dbsession.query(cls).all() 46 | 47 | @classmethod 48 | def by_id(cls, _id): 49 | """Returns a the object with id of _id""" 50 | return dbsession.query(cls).filter_by(id=_id).first() 51 | 52 | @classmethod 53 | def by_user_id(cls, user_id): 54 | """Returns a the object with id of user_id""" 55 | return dbsession.query(cls).filter_by(user_id=user_id).first() 56 | 57 | @classmethod 58 | def count(cls): 59 | """Returns a list of all objects in the database""" 60 | return dbsession.query(cls).count() 61 | 62 | @classmethod 63 | def by_value(cls, value): 64 | """Returns a the object with value of value""" 65 | return dbsession.query(cls).filter_by(value=value).first() 66 | 67 | def is_expired(self, hours=3): 68 | """Check if the token is expired""" 69 | now = datetime.now() 70 | expired = self.created + timedelta(hours=hours) 71 | return now > expired 72 | -------------------------------------------------------------------------------- /models/PasteBin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 12, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from builtins import str 24 | from uuid import uuid4 25 | 26 | from sqlalchemy import Column, ForeignKey 27 | from sqlalchemy.types import Integer, String, Unicode 28 | from tornado.options import options 29 | 30 | from models import dbsession 31 | from models.BaseModels import DatabaseObject 32 | 33 | 34 | class PasteBin(DatabaseObject): 35 | """PasteBin definition""" 36 | 37 | uuid = Column(String(36), unique=True, nullable=False, default=lambda: str(uuid4())) 38 | 39 | team_id = Column(Integer, ForeignKey("team.id"), nullable=False) 40 | _name = Column(Unicode(32), nullable=False) 41 | _contents = Column(Unicode(options.max_pastebin_size), nullable=False) 42 | 43 | @classmethod 44 | def all(cls): 45 | """Returns a list of all objects in the database""" 46 | return dbsession.query(cls).all() 47 | 48 | @classmethod 49 | def by_id(cls, _id): 50 | """Returns a the object with id of _id""" 51 | return dbsession.query(cls).filter_by(id=_id).first() 52 | 53 | @classmethod 54 | def by_uuid(cls, _uuid): 55 | """Get a paste object by uuid""" 56 | return dbsession.query(cls).filter_by(uuid=_uuid).first() 57 | 58 | @property 59 | def name(self): 60 | return self._name 61 | 62 | @name.setter 63 | def name(self, value): 64 | self._name = str(value) 65 | 66 | @property 67 | def contents(self): 68 | return self._contents 69 | 70 | @contents.setter 71 | def contents(self, value): 72 | self._contents = str(value[: options.max_pastebin_size]) 73 | 74 | def __repr__(self): 75 | return "" % (self.name, self.user_id) 76 | -------------------------------------------------------------------------------- /models/Permission.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 12, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | from sqlalchemy import Column, ForeignKey 23 | from sqlalchemy.types import Integer, Unicode 24 | 25 | from models import dbsession 26 | from models.BaseModels import DatabaseObject 27 | 28 | 29 | class Permission(DatabaseObject): 30 | """Permission definition""" 31 | 32 | user_id = Column(Integer, ForeignKey("user.id", ondelete="CASCADE"), nullable=False) 33 | name = Column(Unicode(64), nullable=False) 34 | 35 | @classmethod 36 | def all(cls): 37 | """Returns a list of all objects in the database""" 38 | return dbsession.query(cls).all() 39 | 40 | @classmethod 41 | def by_id(cls, _id): 42 | """Returns a the object with id of _id""" 43 | return dbsession.query(cls).filter_by(id=_id).first() 44 | 45 | @classmethod 46 | def by_user_id(cls, _id): 47 | return dbsession.query(cls).filter_by(user_id=_id).all() 48 | 49 | def to_xml(self, parent): 50 | pass 51 | 52 | def __repr__(self): 53 | return "" % (self.name, self.user_id) 54 | -------------------------------------------------------------------------------- /models/RegistrationToken.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sep 22, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | import binascii 24 | from builtins import str 25 | from os import urandom 26 | 27 | from sqlalchemy import Column 28 | from sqlalchemy.types import Boolean, String 29 | 30 | from libs.StringCoding import decode, encode 31 | from models import dbsession 32 | from models.BaseModels import DatabaseObject 33 | 34 | def gen_token(): 35 | return binascii.hexlify(urandom(3)) 36 | 37 | 38 | class RegistrationToken(DatabaseObject): 39 | """Registration token definition""" 40 | 41 | value = Column(String(6), unique=True, nullable=False, default=gen_token) 42 | used = Column(Boolean, nullable=False, default=False) 43 | 44 | @classmethod 45 | def all(cls): 46 | """Returns a list of all objects in the database""" 47 | return dbsession.query(cls).all() 48 | 49 | @classmethod 50 | def by_id(cls, _id): 51 | """Returns a the object with id of _id""" 52 | return dbsession.query(cls).filter_by(id=_id).first() 53 | 54 | @classmethod 55 | def count(cls): 56 | """Returns a list of all objects in the database""" 57 | return dbsession.query(cls).count() 58 | 59 | @classmethod 60 | def by_value(cls, _value): 61 | """Returns a the object with value of value""" 62 | return dbsession.query(cls).filter_by(value=encode(_value)).first() 63 | 64 | def getvalue(self): 65 | return decode(self.value) 66 | 67 | 68 | -------------------------------------------------------------------------------- /modules/AppTheme.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 14, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from tornado.options import options 24 | from tornado.web import UIModule 25 | 26 | from models.Theme import Theme 27 | 28 | 29 | class AppTheme(UIModule): 30 | 31 | theme = Theme.by_name(options.default_theme) 32 | 33 | def render(self, *args, **kwargs): 34 | """Includes different CSS themes based on user prefs""" 35 | 36 | if ( 37 | options.allow_user_to_change_theme 38 | and self.handler.session is not None 39 | and self.handler.session["theme"] is not None 40 | ): 41 | return self.render_string( 42 | "theme/theme.html", theme_files=self.handler.session["theme"] 43 | ) 44 | else: 45 | return self.render_string("theme/theme.html", theme_files=self.theme) 46 | -------------------------------------------------------------------------------- /modules/Menu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 14, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from tornado.options import options 24 | from tornado.web import UIModule 25 | 26 | from models.User import User 27 | 28 | 29 | class Menu(UIModule): 30 | 31 | # TODO: Put everything in the session that we need to construct the menu 32 | # to avoid having to go to the database to render the menu. 33 | 34 | def render(self, *args, **kwargs): 35 | """Renders the top menu""" 36 | if self.handler.session is not None: 37 | user = User.by_id(self.handler.session["user_id"]) 38 | else: 39 | user = None 40 | scoreboard_visible = self.scoreboard_visible(user) 41 | registration_allowed = self.registration_allowed() 42 | if self.handler.session is not None: 43 | if self.handler.session["menu"] == "user": 44 | return self.render_string( 45 | "menu/user.html", user=user, scoreboard_visible=scoreboard_visible 46 | ) 47 | elif self.handler.session["menu"] == "admin": 48 | return self.render_string( 49 | "menu/admin.html", user=user, scoreboard_visible=scoreboard_visible 50 | ) 51 | return self.render_string( 52 | "menu/public.html", 53 | scoreboard_visible=scoreboard_visible, 54 | registration_visible=registration_allowed, 55 | ) 56 | 57 | def scoreboard_visible(self, user): 58 | if options.scoreboard_visibility == "public": 59 | return True 60 | if user: 61 | return options.scoreboard_visibility == "players" or user.is_admin() 62 | return False 63 | 64 | def registration_allowed(self): 65 | if options.auth == "azuread": 66 | return False 67 | return True 68 | -------------------------------------------------------------------------------- /modules/Recaptcha.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 14, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | """ 21 | 22 | 23 | from tornado.options import options 24 | from tornado.web import UIModule 25 | 26 | 27 | class Recaptcha(UIModule): 28 | def render(self, *args, **kwargs): 29 | if ( 30 | options.use_recaptcha 31 | and len(options.recaptcha_site_key) > 0 32 | and len(options.recaptcha_secret_key) > 0 33 | ): 34 | return self.render_string( 35 | "recaptcha/captcha.html", recaptcha_site_key=options.recaptcha_site_key 36 | ) 37 | else: 38 | return self.render_string("recaptcha/disabled.html") 39 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /setup/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | __version__ = "3.13.1" 3 | -------------------------------------------------------------------------------- /setup/create_database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | @author: moloch 4 | 5 | Copyright 2013 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | """ 19 | 20 | 21 | from models import engine 22 | from models.BaseModels import DatabaseObject 23 | 24 | 25 | def create_tables(sqla_engine, sqla_metadata, echo=False): 26 | """Create all the tables""" 27 | setattr(sqla_engine, "echo", echo) 28 | sqla_metadata.create_all(sqla_engine) 29 | 30 | 31 | # Get the SQLAlchemy metadata object 32 | metadata = DatabaseObject.metadata 33 | 34 | # Create secondary tables 35 | # Import your models here 36 | from models.Box import Box 37 | from models.Category import Category 38 | from models.Corporation import Corporation 39 | from models.EmailToken import EmailToken 40 | from models.FileUpload import FileUpload 41 | from models.Flag import Flag 42 | from models.FlagAttachment import FlagAttachment 43 | from models.FlagChoice import FlagChoice 44 | from models.GameLevel import GameLevel 45 | from models.Hint import Hint 46 | from models.IpAddress import IpAddress 47 | from models.MarketItem import MarketItem 48 | from models.Notification import Notification 49 | from models.PasswordToken import PasswordToken 50 | from models.PasteBin import PasteBin 51 | from models.Penalty import Penalty 52 | from models.Permission import Permission 53 | from models.RegistrationToken import RegistrationToken 54 | from models.Relationships import * 55 | from models.SourceCode import SourceCode 56 | from models.Swat import Swat 57 | from models.Team import Team 58 | from models.Theme import Theme, ThemeFile 59 | from models.User import User 60 | from models.WallOfSheep import WallOfSheep 61 | -------------------------------------------------------------------------------- /setup/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | 5 | worker_connections 1024; 6 | 7 | } 8 | 9 | http { 10 | 11 | sendfile on; 12 | 13 | gzip on; 14 | gzip_http_version 1.0; 15 | gzip_proxied any; 16 | gzip_min_length 500; 17 | gzip_disable "MSIE [1-6]\."; 18 | gzip_types text/plain text/xml text/css 19 | text/comma-separated-values 20 | text/javascript 21 | application/x-javascript 22 | application/atom+xml; 23 | 24 | map $http_upgrade $connection_upgrade { 25 | default upgrade; 26 | '' close; 27 | } 28 | 29 | # Configuration containing list of application servers 30 | # As of now we only use one process for the main app 31 | upstream rtb_server { 32 | server 127.0.0.1:8888; 33 | } 34 | 35 | 36 | # dynamite server config 37 | server { 38 | 39 | server_name game.root-the-box.com; 40 | 41 | # Running port 42 | listen 80; 43 | 44 | # We can offload serving static files onto nginx 45 | # this should be the parent directory of /static/ 46 | location ^~ /static/ { 47 | 48 | # Include content-types 49 | include /usr/local/etc/nginx/mime.types; 50 | 51 | # Add security headers 52 | add_header X-Frame-Options DENY; 53 | add_header X-Content-Type-Options nosniff; 54 | 55 | # The directory just above /static/ 56 | root /opt/rootthebox; 57 | 58 | } 59 | 60 | # WebSocket: scoreboard connections 61 | location ^~ /scoreboard/wsocket { 62 | 63 | proxy_pass http://rtb_server; 64 | proxy_http_version 1.1; 65 | proxy_set_header Host $host; 66 | proxy_set_header Upgrade $http_upgrade; 67 | proxy_set_header Connection $connection_upgrade; 68 | 69 | } 70 | 71 | # WebSocket: notification connections 72 | location ^~ /connect/notifications { 73 | proxy_pass http://rtb_server; 74 | proxy_http_version 1.1; 75 | proxy_set_header Host $host; 76 | proxy_pass_header X-XSRF-TOKEN; 77 | proxy_set_header Upgrade $http_upgrade; 78 | proxy_set_header Connection $connection_upgrade; 79 | 80 | } 81 | 82 | 83 | # Proxy connections to the application servers 84 | # rtb_server 85 | location / { 86 | 87 | proxy_pass http://rtb_server; 88 | proxy_redirect off; 89 | proxy_set_header Host $host; 90 | proxy_set_header X-Real-IP $remote_addr; 91 | proxy_set_header X-Forwarded-For $remote_addr; 92 | proxy_set_header X-Forwarded-Host $server_name; 93 | 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /setup/nginx_vhost_rtb.conf: -------------------------------------------------------------------------------- 1 | server { 2 | server_name ; 3 | 4 | # Running port 5 | listen 80; 6 | 7 | # We can offload serving static files onto nginx 8 | # this should be the parent directory of /static/ 9 | location ^~ /static/ { 10 | 11 | # Include content-types 12 | include /etc/nginx/mime.types; 13 | 14 | # Add security headers 15 | add_header X-Frame-Options DENY; 16 | add_header X-Content-Type-Options nosniff; 17 | 18 | # The directory just above /static/ 19 | root ; 20 | 21 | } 22 | 23 | # WebSocket: scoreboard connections 24 | location ^~ /scoreboard/wsocket { 25 | 26 | proxy_pass http://rtb_server; 27 | proxy_http_version 1.1; 28 | proxy_set_header Host $host; 29 | proxy_set_header Upgrade $http_upgrade; 30 | proxy_set_header Connection $connection_upgrade; 31 | 32 | } 33 | 34 | # WebSocket: notification connections 35 | location ^~ /connect/notifications { 36 | proxy_pass http://rtb_server; 37 | proxy_http_version 1.1; 38 | proxy_set_header Host $host; 39 | proxy_pass_header X-XSRF-TOKEN; 40 | proxy_set_header Upgrade $http_upgrade; 41 | proxy_set_header Connection $connection_upgrade; 42 | 43 | } 44 | 45 | 46 | # Proxy connections to the application servers 47 | # rtb_server 48 | location / { 49 | 50 | proxy_pass http://rtb_server; 51 | proxy_redirect off; 52 | proxy_set_header Host $host; 53 | proxy_set_header X-Real-IP $remote_addr; 54 | proxy_set_header X-Forwarded-For $remote_addr; 55 | proxy_set_header X-Forwarded-Host $server_name; 56 | 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /setup/requirements.txt: -------------------------------------------------------------------------------- 1 | tornado==5.*; python_version<'3.0' 2 | tornado; python_version>='3.0' 3 | pbkdf2 4 | PyMySQL==0.10.1; python_version<'3.0' 5 | PyMySQL; python_version>='3.0' 6 | python-binary-memcached==0.27.0; python_version<'3.0' 7 | python-binary-memcached; python_version>='3.0' 8 | python-dateutil 9 | defusedxml 10 | netaddr 11 | nose 12 | future 13 | python-resize-image 14 | sqlalchemy==1.* 15 | alembic 16 | enum34 17 | mysqlclient 18 | rocketchat_API 19 | setuptools-rust==0.10.3; python_version<'3.0' 20 | setuptools-rust; python_version>='3.0' 21 | msal 22 | requests 23 | -------------------------------------------------------------------------------- /setup/restart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Kill exact match command. 3 | for process in $(pgrep -f "(python|python3) ./rootthebox.py --start"); do 4 | kill -9 $process; 5 | done && 6 | 7 | # Restart 8 | python3 ./rootthebox.py --start 9 | -------------------------------------------------------------------------------- /setup/rtb-upstart.conf: -------------------------------------------------------------------------------- 1 | # Root the box upstart script 2 | start on runlevel 2 3 | stop on runlevel [!2] 4 | respawn 5 | 6 | # Settings 7 | USER=tornado 8 | RTB_HOME=/opt/rootthebox 9 | 10 | 11 | # Execute commands 12 | exec su -c "$RTB_HOME/rootthebox.py --start" $USER 13 | 14 | -------------------------------------------------------------------------------- /setup/rtb.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Root The Box daemon 3 | After=network-online.target 4 | 5 | [Service] 6 | Type=simple 7 | User=rtb 8 | Group=rtb 9 | 10 | ExecStart=/opt/CTF/RootTheBox/rootthebox.py --start 11 | Restart=always 12 | RestartSec=1 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /static/css/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/32px.png -------------------------------------------------------------------------------- /static/css/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/40px.png -------------------------------------------------------------------------------- /static/css/droidsans.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Droid Sans'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Droid Sans'), local('DroidSans'), url(/static/font/droidsans.woff) format('woff'); 6 | } 7 | 8 | @font-face { 9 | font-family: 'Droid Sans'; 10 | font-style: normal; 11 | font-weight: 700; 12 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url(/static/font/droidsans-bold.woff) format('woff'); 13 | } -------------------------------------------------------------------------------- /static/css/icons/application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/application.png -------------------------------------------------------------------------------- /static/css/icons/cd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/cd.png -------------------------------------------------------------------------------- /static/css/icons/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/code.png -------------------------------------------------------------------------------- /static/css/icons/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/css.png -------------------------------------------------------------------------------- /static/css/icons/db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/db.png -------------------------------------------------------------------------------- /static/css/icons/directory-lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/directory-lock.png -------------------------------------------------------------------------------- /static/css/icons/directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/directory.png -------------------------------------------------------------------------------- /static/css/icons/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/doc.png -------------------------------------------------------------------------------- /static/css/icons/file-lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/file-lock.png -------------------------------------------------------------------------------- /static/css/icons/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/file.png -------------------------------------------------------------------------------- /static/css/icons/film.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/film.png -------------------------------------------------------------------------------- /static/css/icons/flash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/flash.png -------------------------------------------------------------------------------- /static/css/icons/folder_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/folder_open.png -------------------------------------------------------------------------------- /static/css/icons/hdd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/hdd.png -------------------------------------------------------------------------------- /static/css/icons/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/html.png -------------------------------------------------------------------------------- /static/css/icons/java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/java.png -------------------------------------------------------------------------------- /static/css/icons/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/linux.png -------------------------------------------------------------------------------- /static/css/icons/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/music.png -------------------------------------------------------------------------------- /static/css/icons/pcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/pcap.png -------------------------------------------------------------------------------- /static/css/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/pdf.png -------------------------------------------------------------------------------- /static/css/icons/php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/php.png -------------------------------------------------------------------------------- /static/css/icons/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/picture.png -------------------------------------------------------------------------------- /static/css/icons/ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/ppt.png -------------------------------------------------------------------------------- /static/css/icons/psd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/psd.png -------------------------------------------------------------------------------- /static/css/icons/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/ruby.png -------------------------------------------------------------------------------- /static/css/icons/script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/script.png -------------------------------------------------------------------------------- /static/css/icons/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/spinner.gif -------------------------------------------------------------------------------- /static/css/icons/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/txt.png -------------------------------------------------------------------------------- /static/css/icons/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/xls.png -------------------------------------------------------------------------------- /static/css/icons/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/icons/zip.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /static/css/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/css/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/css/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 40px; 3 | padding-bottom: 40px; 4 | background-color: #eee; 5 | } 6 | .form-signin { 7 | max-width: 430px; 8 | padding: 15px; 9 | margin: 0 auto; 10 | } 11 | .form-signin .form-signin-heading, 12 | .form-signin .checkbox { 13 | margin-bottom: 10px; 14 | } 15 | .form-signin .checkbox { 16 | font-weight: normal; 17 | } 18 | .form-signin .form-control { 19 | position: relative; 20 | font-size: 16px; 21 | height: auto; 22 | padding: 10px; 23 | -webkit-box-sizing: border-box; 24 | -moz-box-sizing: border-box; 25 | box-sizing: border-box; 26 | } 27 | .form-signin .form-control:focus { 28 | z-index: 2; 29 | } 30 | .form-signin input[type="text"] { 31 | margin-bottom: -1px; 32 | border-bottom-left-radius: 0; 33 | border-bottom-right-radius: 0; 34 | } 35 | .form-signin input[type="password"] { 36 | margin-bottom: 10px; 37 | border-top-left-radius: 0; 38 | border-top-right-radius: 0; 39 | } -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 60px; 3 | padding-bottom: 40px; 4 | } 5 | footer { 6 | font-size: 75%; 7 | position: fixed; 8 | bottom: -30px; 9 | width: 100%; 10 | } 11 | .footernav { 12 | padding: 5px 20px; 13 | } 14 | .img-polaroid { 15 | width: 500px; 16 | } 17 | .shortcolumn { 18 | width: 1px; 19 | white-space: nowrap; 20 | } 21 | .descriptioncol { 22 | white-space: pre-wrap; 23 | word-wrap: break-word; 24 | max-width: 350px; 25 | } 26 | .levelheader { 27 | display: inline; 28 | vertical-align: middle; 29 | } 30 | .statcolumn { 31 | text-align: center !important; 32 | vertical-align: middle !important; 33 | width: 100px; 34 | } 35 | .centercolumn { 36 | text-align: center !important; 37 | vertical-align: middle !important; 38 | } 39 | .wordbreak { 40 | word-wrap: break-word; 41 | } 42 | .successtext { 43 | font-size: 225%; 44 | color: green; 45 | } 46 | .disabledtext { 47 | font-size: 275%; 48 | } 49 | .avatarused { 50 | color: white; 51 | font-size: 23pt; 52 | position: absolute; 53 | top: -11px; 54 | right: -5px; 55 | } 56 | .avatarused-top { 57 | font-size: 16pt; 58 | position: absolute; 59 | top: -6px; 60 | right: -1px; 61 | } 62 | 63 | .preformatted { 64 | font-family: monospace; 65 | font-size: 95%; 66 | white-space: pre-wrap; 67 | display: block; 68 | margin: 1em 0; 69 | } 70 | 71 | .markdown p { 72 | display: inline; 73 | } 74 | 75 | .markdown ul { 76 | margin-bottom: 0px; 77 | } 78 | 79 | code, 80 | pre { 81 | background-color: #000 !important; 82 | font-family: unset !important; 83 | font-size: unset !important; 84 | padding: 0px 6px 1px 5px !important; 85 | white-space: pre-wrap !important; 86 | 87 | } 88 | 89 | code { 90 | color: #f52323 !important; 91 | border: 1px solid #979797 !important; 92 | } -------------------------------------------------------------------------------- /static/css/markdown-toolbar.css: -------------------------------------------------------------------------------- 1 | .toolbar { 2 | min-width: 265px; 3 | } 4 | 5 | .toolbar-commenting { 6 | margin-top: 7px; 7 | } 8 | 9 | .toolbar-group { 10 | display: inline-block; 11 | margin-right: 15px; 12 | } 13 | 14 | .toolbar-item.dropdown { 15 | padding: 0; 16 | } 17 | 18 | .toolbar-item { 19 | display: block; 20 | float: left; 21 | padding: 4px 5px; 22 | color: #767676; 23 | background: none; 24 | border: 0; 25 | } 26 | 27 | .toolbar-item .menu-target { 28 | display: block; 29 | padding: 4px 5px; 30 | color: #767676; 31 | background: none; 32 | border: 0; 33 | } 34 | 35 | .toolbar-item .dropdown-caret { 36 | display: block; 37 | float: right; 38 | margin-top: 6px; 39 | margin-left: 2px; 40 | } 41 | 42 | .dropdown-caret { 43 | display: inline-block; 44 | width: 0; 45 | height: 0; 46 | vertical-align: -2px; 47 | content: ""; 48 | border: 4px solid; 49 | border-right-color: transparent; 50 | border-bottom-color: transparent; 51 | border-left-color: transparent; 52 | } 53 | 54 | .octicon { 55 | display: inline-block; 56 | vertical-align: text-top; 57 | fill: currentColor; 58 | } 59 | 60 | .dropdown-menu-s { 61 | right: 50%; 62 | left: auto; 63 | -webkit-transform: translateX(50%); 64 | transform: translateX(50%); 65 | } 66 | 67 | .markdown-toolbar { 68 | white-space: nowrap; 69 | } 70 | 71 | .markdown-preview { 72 | background-color: #eee; 73 | } 74 | 75 | .markdown-preview blockquote { 76 | margin: 10px 0 10px 0; 77 | padding: 5px 10px; 78 | border-left: 5px solid #b2cbea; 79 | font-size: 14px; 80 | color: #666; 81 | } -------------------------------------------------------------------------------- /static/css/menu.css: -------------------------------------------------------------------------------- 1 | .btncollapse { 2 | float: right; 3 | } 4 | @media screen and (min-width: 980px) { 5 | .btncollapse {display: none;} 6 | } 7 | .dropdown-alert-menu { 8 | min-width: 375px !important; 9 | margin-left: -214px !important; 10 | } 11 | .navbar .nav>li>.dropdown-alert-menu:before{ 12 | left:220px !important; 13 | } 14 | .navbar .nav>li>.dropdown-alert-menu:after{ 15 | left:221px !important; 16 | } -------------------------------------------------------------------------------- /static/css/notifier.css: -------------------------------------------------------------------------------- 1 | .box { 2 | display: inline-block; 3 | vertical-align: top; 4 | padding: 0 30px; 5 | } 6 | .box .title { 7 | font: 24px "Droid Serif", serif; 8 | } 9 | .box .list { 10 | list-style: square; 11 | } -------------------------------------------------------------------------------- /static/css/pages/admin/configuration.css: -------------------------------------------------------------------------------- 1 | .control-section { 2 | margin-left: 50px; 3 | } 4 | -------------------------------------------------------------------------------- /static/css/pages/admin/game_objects.css: -------------------------------------------------------------------------------- 1 | .locked { 2 | background-color: rgb(128, 0, 0) !important; 3 | } -------------------------------------------------------------------------------- /static/css/pages/admin/home.css: -------------------------------------------------------------------------------- 1 | .game_button { 2 | padding: 8px 12px; 3 | margin-right: 12px; 4 | } 5 | .game_button_area { 6 | margin: 18px 10px; 7 | } 8 | .game_button_text { 9 | display: inline; 10 | vertical-align: middle; 11 | } 12 | .gitstatus { 13 | padding-left: 15px; 14 | font-size: 150%; 15 | } 16 | 17 | .gitstatus.info { 18 | color: #4d9ecb; 19 | } 20 | 21 | .gitstatus.ok { 22 | color: #adff2f; 23 | } 24 | 25 | .gitstatus.warn { 26 | color: #eff834; 27 | } 28 | 29 | .gitform { 30 | padding-top: 15px; 31 | padding-left: 15px; 32 | } 33 | -------------------------------------------------------------------------------- /static/css/pages/public/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 40px; 3 | padding-bottom: 40px; 4 | 5 | } 6 | .container { 7 | margin-top: 70px; 8 | } 9 | .form-signin { 10 | max-width: 400px; 11 | padding: 19px 29px 29px; 12 | margin: 0 auto 20px; 13 | 14 | border: 1px solid #e5e5e5; 15 | -webkit-border-radius: 5px; 16 | -moz-border-radius: 5px; 17 | border-radius: 5px; 18 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05); 19 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.05); 20 | box-shadow: 0 1px 2px rgba(0,0,0,.05); 21 | } 22 | .form-signin .form-signin-heading, 23 | .form-signin .checkbox { 24 | margin-bottom: 10px; 25 | } 26 | .form-signin input[type="text"], 27 | .form-signin input[type="password"] { 28 | font-size: 16px; 29 | height: auto; 30 | margin-bottom: 15px; 31 | padding: 7px 9px; 32 | } -------------------------------------------------------------------------------- /static/css/pages/public/registration.css: -------------------------------------------------------------------------------- 1 | .teammode { 2 | margin-left: 20px !important; 3 | margin-right: 10px !important; 4 | margin-top: -2px !important; 5 | } -------------------------------------------------------------------------------- /static/css/pages/public/summary.css: -------------------------------------------------------------------------------- 1 | .summarycolumn { 2 | padding-bottom: 0px !important; 3 | } 4 | .glow { 5 | color: #fff; 6 | font-weight: bold; 7 | -webkit-animation: glow 1s ease-in-out infinite alternate; 8 | -moz-animation: glow 1s ease-in-out infinite alternate; 9 | animation: glow 1s ease-in-out infinite alternate; 10 | } 11 | .timercount { 12 | padding-top: 200px; 13 | color: red; 14 | text-align: center; 15 | font-size: 500%; 16 | } 17 | 18 | @-webkit-keyframes glow { 19 | from { 20 | text-shadow: 0 0 1px #fff, 0 0 4px #e67b00, 0 0 8px #e67b00, 0 0 12px #e67b00, 0 0 16px #e67b00; 21 | } 22 | to { 23 | text-shadow: 0 0 2px #e69d00, 0 0 6px #e69d00, 0 0 18px #e69d00, 0 0 24px #e69d00, 0 0 30px #e69d00; 24 | } 25 | } -------------------------------------------------------------------------------- /static/css/pages/user/home.css: -------------------------------------------------------------------------------- 1 | .notifications-title { 2 | display: inline; 3 | } 4 | 5 | .notifications { 6 | display: inline; 7 | float: right; 8 | } 9 | 10 | .msgdescription { 11 | width: 82% !important; 12 | } -------------------------------------------------------------------------------- /static/css/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/css/throbber.gif -------------------------------------------------------------------------------- /static/epicsaxguy.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/epicsaxguy.mp3 -------------------------------------------------------------------------------- /static/font/Fixedsys500c.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/Fixedsys500c.eot -------------------------------------------------------------------------------- /static/font/Fixedsys500c.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/Fixedsys500c.otf -------------------------------------------------------------------------------- /static/font/Fixedsys500c.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/Fixedsys500c.ttf -------------------------------------------------------------------------------- /static/font/Fixedsys500c.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/Fixedsys500c.woff -------------------------------------------------------------------------------- /static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /static/font/droidsans-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/droidsans-bold.woff -------------------------------------------------------------------------------- /static/font/droidsans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/droidsans.woff -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/images/bf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/bf.png -------------------------------------------------------------------------------- /static/images/blackheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/blackheart.png -------------------------------------------------------------------------------- /static/images/clippy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/clippy.jpg -------------------------------------------------------------------------------- /static/images/clippy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/images/ctftime.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 13 | 15 | 17 | 19 | 20 | 22 | 24 | 25 | 26 | 27 | 28 | Dailyillustration.ru 29 | Dailyillustration.ru 30 | 31 | 32 | -------------------------------------------------------------------------------- /static/images/dialog_overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/dialog_overlay.png -------------------------------------------------------------------------------- /static/images/epicsaxguy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/epicsaxguy.gif -------------------------------------------------------------------------------- /static/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/error.png -------------------------------------------------------------------------------- /static/images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/example.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/federal_reserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/federal_reserve.png -------------------------------------------------------------------------------- /static/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/info.png -------------------------------------------------------------------------------- /static/images/morris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/morris.jpg -------------------------------------------------------------------------------- /static/images/password_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/password_security.png -------------------------------------------------------------------------------- /static/images/rtb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/rtb.jpg -------------------------------------------------------------------------------- /static/images/rtb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/rtb2.png -------------------------------------------------------------------------------- /static/images/rtb3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/rtb3.jpg -------------------------------------------------------------------------------- /static/images/rtb4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/rtb4.png -------------------------------------------------------------------------------- /static/images/source_code_market.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/source_code_market.png -------------------------------------------------------------------------------- /static/images/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/sprite.png -------------------------------------------------------------------------------- /static/images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/success.png -------------------------------------------------------------------------------- /static/images/swat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/swat.png -------------------------------------------------------------------------------- /static/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moloch--/RootTheBox/aa53eb2500187c8ba58ccc6ed87ed2d43cd35c8b/static/images/warning.png -------------------------------------------------------------------------------- /static/js/libs/clipboard/clipfeed.js: -------------------------------------------------------------------------------- 1 | var clipboardFeed = new ClipboardJS('[data-clipboard-btn]'); 2 | clipboardFeed.on('success', function (e) { 3 | e.clearSelection(); 4 | //console.info('Action:', e.action); 5 | //console.info('Text:', e.text); 6 | //console.info('Trigger:', e.trigger); 7 | showTooltip(e.trigger, 'Copied!'); 8 | }); 9 | clipboardFeed.on('error', function (e) { 10 | //console.error('Action:', e.action); 11 | //console.error('Trigger:', e.trigger); 12 | showTooltip(e.trigger, fallbackMessage(e.action)); 13 | }); -------------------------------------------------------------------------------- /static/js/libs/clipboard/snippets.js: -------------------------------------------------------------------------------- 1 | var snippets = document.querySelectorAll('.snippet'); 2 | [].forEach.call(snippets, function (snippet) { 3 | snippet.firstChild.insertAdjacentHTML('beforebegin', ''); 4 | }); 5 | var clipboardSnippets = new ClipboardJS('[data-clipboard-snippet]', { 6 | target: function (trigger) { 7 | return trigger.nextElementSibling; 8 | } 9 | }); 10 | clipboardSnippets.on('success', function (e) { 11 | e.clearSelection(); 12 | showTooltip(e.trigger, 'Copied!'); 13 | }); 14 | clipboardSnippets.on('error', function (e) { 15 | showTooltip(e.trigger, fallbackMessage(e.action)); 16 | }); -------------------------------------------------------------------------------- /static/js/libs/clipboard/tooltips.js: -------------------------------------------------------------------------------- 1 | var btns = document.querySelectorAll('.btn'); 2 | for (var i = 0; i < btns.length; i++) { 3 | btns[i].addEventListener('mouseleave', clearTooltip); 4 | btns[i].addEventListener('blur', clearTooltip); 5 | } 6 | 7 | function clearTooltip(e) { 8 | e.currentTarget.setAttribute('class', 'btn'); 9 | e.currentTarget.removeAttribute('aria-label'); 10 | } 11 | 12 | function showTooltip(elem, msg) { 13 | elem.setAttribute('class', 'btn tooltipped tooltipped-s'); 14 | elem.setAttribute('aria-label', msg); 15 | } 16 | 17 | function fallbackMessage(action) { 18 | var actionMsg = ''; 19 | var actionKey = (action === 'cut' ? 'X' : 'C'); 20 | if (/iPhone|iPad/i.test(navigator.userAgent)) { 21 | actionMsg = 'No support :('; 22 | } else if (/Mac/i.test(navigator.userAgent)) { 23 | actionMsg = 'Press ⌘-' + actionKey + ' to ' + action; 24 | } else { 25 | actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action; 26 | } 27 | return actionMsg; 28 | } -------------------------------------------------------------------------------- /static/js/libs/html5.js: -------------------------------------------------------------------------------- 1 | /*! HTML5 Shiv vpre3.6 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 2 | Uncompressed source: https://github.com/aFarkas/html5shiv */ 3 | (function(a,b){function h(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function i(){var a=l.elements;return typeof a=="string"?a.split(" "):a}function j(a){var b={},c=a.createElement,f=a.createDocumentFragment,g=f();a.createElement=function(a){if(!l.shivMethods)return c(a);var f;return b[a]?f=b[a].cloneNode():e.test(a)?f=(b[a]=c(a)).cloneNode():f=c(a),f.canHaveChildren&&!d.test(a)?g.appendChild(f):f},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+i().join().replace(/\w+/g,function(a){return c(a),g.createElement(a),'c("'+a+'")'})+");return n}")(l,g)}function k(a){var b;return a.documentShived?a:(l.shivCSS&&!f&&(b=!!h(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),g||(b=!j(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea|object|iframe|option|optgroup)$/i,e=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,f,g;(function(){var c=b.createElement("a");c.innerHTML="",f="hidden"in c,f&&typeof injectElementWithStyles=="function"&&injectElementWithStyles("#modernizr{}",function(b){b.hidden=!0,f=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).display=="none"}),g=c.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var l={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:k};a.html5=l,k(b)})(this,document) -------------------------------------------------------------------------------- /static/js/libs/mousewheel-min.js: -------------------------------------------------------------------------------- 1 | (function(c){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),e=0,h=0,f=0;a=c.event.fix(b);a.type="mousewheel";if(b.wheelDelta)e=b.wheelDelta/120;if(b.detail)e=-b.detail/3;f=e;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){f=0;h=-1*e}if(b.wheelDeltaY!==undefined)f=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,e,h,f);return(c.event.dispatch||c.event.handle).apply(this,i)}var d=["DOMMouseScroll","mousewheel"];if(c.event.fixHooks)for(var j=d.length;j;)c.event.fixHooks[d[--j]]= 2 | c.event.mouseHooks;c.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=d.length;a;)this.addEventListener(d[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=d.length;a;)this.removeEventListener(d[--a],g,false);else this.onmousewheel=null}};c.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery); 3 | -------------------------------------------------------------------------------- /static/js/pages/admin/create/category.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Enable popovers */ 4 | $("#category").popover({placement: 'right', trigger: 'hover'}); 5 | }); 6 | -------------------------------------------------------------------------------- /static/js/pages/admin/create/corporation.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Enable popovers */ 4 | $("#corporation-name").popover({placement: 'right', trigger: 'hover'}); 5 | }); 6 | -------------------------------------------------------------------------------- /static/js/pages/admin/create/game_level.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | 3 | /* Popovers */ 4 | $("#level-number").popover({ placement: 'right', trigger: 'focus' }); 5 | $("#buyout").popover({ placement: 'right', trigger: 'focus' }); 6 | $("#game_level-reward").popover({ placement: 'right', trigger: 'focus' }); 7 | $("#game_level-type").popover({ placement: 'right', trigger: 'focus' }); 8 | $("#game_level-name").popover({ placement: 'right', trigger: 'focus' }); 9 | 10 | $("#game_level-type").change(function () { 11 | if (this.value === "none" || this.value === "hidden") { 12 | $("#buyoutcost").hide(); 13 | } else if (this.value === "buyout") { 14 | $("#buyoutlabel").text("Unlock Cost"); 15 | $("#buyout").attr('max', ''); 16 | $("#buyout").attr('data-original-title', 'Unlock Cost'); 17 | $("#buyout").attr('data-content', 'Cost to open this level and see flags [0-9]+'); 18 | $("#buyoutcost").show(); 19 | $("#buyout").show(); 20 | $("#buyoutlvl").hide(); 21 | } else if (this.value === "progress") { 22 | $("#buyoutlabel").text("% Complete of Prior Level"); 23 | $("#buyout").attr('max', 100); 24 | $("#buyout").attr('data-original-title', '% Complete of Prior Level'); 25 | $("#buyout").attr('data-content', 'This level will unlock automatically after this percentage of prior level is completed (value 0-100).'); 26 | $("#buyoutcost").show(); 27 | $("#buyout").show(); 28 | $("#buyoutlvl").hide(); 29 | } else if (this.value === "points") { 30 | $("#buyoutlabel").text("Points Required"); 31 | $("#buyout").attr('max', ''); 32 | $("#buyout").attr('data-original-title', 'Points Required'); 33 | $("#buyout").attr('data-content', 'This level will unlock automatically after the score reaches this amount.'); 34 | $("#buyoutcost").show(); 35 | $("#buyout").show(); 36 | $("#buyoutlvl").hide(); 37 | } else if (this.value === "level") { 38 | $("#buyoutlabel").text("Completion of Level"); 39 | $("#buyoutcost").show(); 40 | $("#buyoutlvl").show(); 41 | $("#buyout").hide(); 42 | } 43 | }); 44 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/create/hint.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | /* markdown */ 3 | $(function () { 4 | var reader = new commonmark.Parser({smart: true}); 5 | var writer = new commonmark.HtmlRenderer({safe: true, softbreak: "
"}); 6 | $('[data-toggle="tooltip"]').tooltip(); 7 | $('.toolbar').markdownToolbar(false, reader, writer); 8 | }) 9 | 10 | /* Popovers */ 11 | $("#price").popover({placement:'right', trigger:'hover'}); 12 | $("#description").popover({placement:'right', trigger:'hover'}); 13 | 14 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/create/team.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Popovers */ 4 | $("#team-name").popover({placement:'right', trigger:'focus'}); 5 | $("#motto").popover({placement:'right', trigger:'focus'}); 6 | 7 | /* Avatar */ 8 | $(".teamavatarimg").click(function() { 9 | var filename = $(this).attr('value'); 10 | $("#team_avatar_select").val(filename); 11 | $("#avatarfilename").text("File: " + filename.replace("team/","").replace(/^C:\\fakepath\\/, "")); 12 | $("#avatarclose").click(); 13 | }); 14 | $("#team-avatar").change(function(){ 15 | $("#avatarfilename").text("File: " + $(this).val().replace(/^C:\\fakepath\\/, "")); 16 | $("#team_avatar_select").val(""); 17 | }); 18 | 19 | $("#uploadbutton").click(function(){ 20 | $("#team-avatar").click(); 21 | }); 22 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/export.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("#export-game-objects-button").click(function() { 4 | if ($("#game-objects").val() === "true") { 5 | $("#game-objects").val("false"); 6 | } else { 7 | $("#game-objects").val("true"); 8 | } 9 | }); 10 | 11 | $("#export-users-button").click(function() { 12 | if ($("#users").val() === "true") { 13 | $("#users").val("false"); 14 | } else { 15 | $("#users").val("true"); 16 | } 17 | }); 18 | 19 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/upgrades/source_code_market.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("a[id^=add-source-code-button]").click(function() { 4 | $("#add-source-code-uuid").val($(this).data("uuid")); 5 | }); 6 | 7 | $("#add-source-code-submit").click(function() { 8 | $("#add-source-code-form").submit(); 9 | }); 10 | 11 | $("a[id^=delete-source-code-button]").click(function() { 12 | $("#delete-source-code-uuid").val($(this).data("uuid")); 13 | }); 14 | 15 | $("#delete-source-code-submit").click(function() { 16 | $("#delete-source-code-form").submit(); 17 | }); 18 | 19 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/upgrades/swat.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Accept */ 4 | $("a[id^=accept-bribe-button]").click(function() { 5 | $("#accept-bribe-uuid").val($(this).data("uuid")); 6 | }); 7 | 8 | $("#accept-bribe-submit").click(function() { 9 | $("#accept-bribe-form").submit(); 10 | }); 11 | 12 | /* Decline */ 13 | $("a[id^=decline-bribe-button]").click(function() { 14 | $("#decline-bribe-uuid").val($(this).data("uuid")); 15 | }); 16 | 17 | $("#decline-bribe-submit").click(function() { 18 | $("#decline-bribe-form").submit(); 19 | }); 20 | 21 | /* Complete */ 22 | $("a[id^=complete-bribe-button]").click(function() { 23 | $("#complete-bribe-uuid").val($(this).data("uuid")); 24 | }); 25 | 26 | $("#complete-bribe-submit").click(function() { 27 | $("#complete-bribe-form").submit(); 28 | }); 29 | 30 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/view/categories.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Category Item */ 4 | $("a[id^=edit-category-item-button]").click(function() { 5 | $("#edit-category-item-uuid").val($(this).data("uuid")); 6 | $("#edit-category-item-name").val($(this).data("name")); 7 | $("#edit-category-description").val($(this).data("description")); 8 | }); 9 | 10 | $("#edit-category-item-submit").click(function() { 11 | $("#edit-category-item-form").submit(); 12 | }); 13 | 14 | $("a[id^=delete-category-button]").click(function() { 15 | $("#delete-category-uuid").val($(this).data("uuid")); 16 | }); 17 | 18 | $("#delete-category-submit").click(function() { 19 | $("#delete-category-form").submit(); 20 | }); 21 | 22 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/view/market_objects.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Market Item */ 4 | $("a[id^=edit-market-item-button]").click(function() { 5 | $("#edit-market-item-uuid").val($(this).data("uuid")); 6 | $("#edit-market-item-price").val($(this).data("price")); 7 | }); 8 | 9 | $("#edit-market-item-submit").click(function() { 10 | $("#edit-market-item-form").submit(); 11 | }); 12 | 13 | }); -------------------------------------------------------------------------------- /static/js/pages/admin/view/token.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("a[id^=delete-token-button]").click(function() { 4 | $("#token-value").val($(this).data("value")); 5 | $("#token-form").submit(); 6 | }); 7 | 8 | }); -------------------------------------------------------------------------------- /static/js/pages/botnet/monitor.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('#table-footer').text('WebSocket Connecting ...'); 3 | var monitor_ws = new WebSocket(wsUrl() + "/botnet/webmonitor"); 4 | 5 | monitor_ws.onerror = function (evt) { 6 | alert("ERROR: " + evt.data.toString()); 7 | }; 8 | 9 | monitor_ws.onmessage = function (evt) { 10 | msg = jQuery.parseJSON(evt.data); 11 | if ('opcode' in msg) { 12 | if (msg['opcode'] == 'update' && 'bots' in msg) { 13 | bots = msg['bots']; 14 | $('#box-table').text(''); 15 | $('#table-footer').text(''); 16 | if (0 < bots.length) { 17 | for (var index = 0; index < bots.length; index++) { 18 | $('#box-table').append( 19 | "" + 20 | " " + (index + 1).toString() + "" + 21 | " " + escapeHtml(bots[index]['team_name']) + "" + 22 | " " + escapeHtml(bots[index]['box_name']) + "" + 23 | " " + escapeHtml(bots[index]['remote_ip']) + "" + 24 | "$" + escapeHtml(bots[index]['total_reward']) + "" + 25 | " " + escapeHtml(bots[index]['last_ping']) + "" + 26 | "" 27 | ); 28 | } 29 | } else { 30 | $('#table-footer').text('No bots yet, get hacking!'); 31 | } 32 | } else { 33 | alert("Error: Update contains no bots."); 34 | } 35 | } else { 36 | alert("Error: Malformed message from server."); 37 | } 38 | }; 39 | }); 40 | 41 | var entityMap = { 42 | '&': '&', 43 | '<': '<', 44 | '>': '>', 45 | '"': '"', 46 | "'": ''', 47 | '/': '/', 48 | '`': '`', 49 | '=': '=' 50 | }; 51 | 52 | function escapeHtml (string) { 53 | return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) { 54 | return entityMap[s]; 55 | }); 56 | } -------------------------------------------------------------------------------- /static/js/pages/file_upload/material_files.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | data = {'_xsrf': getCookie("_xsrf")} 3 | subdir = $('#container').data("subdir"); 4 | $.post('/materials' + subdir, data, function(response) { 5 | $('#container').jstree({ 6 | 'core' : { 7 | 'themes' : { name : 'default-dark' }, 8 | 'data' : $.parseJSON(response)["children"] 9 | } 10 | }); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /static/js/pages/file_upload/shared_files.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | /* Download Buttons */ 4 | $("button[id^=file-upload-download]").click(function() { 5 | var uuid = $(this).data("uuid"); 6 | window.open('/user/shares/download?uuid=' + uuid, '_newtab'); 7 | }); 8 | 9 | /* Delete Buttons */ 10 | $("button[id^=delete-file-upload-button]").click(function() { 11 | $("#delete-file-upload-uuid").val($(this).data("uuid")); 12 | }); 13 | 14 | $("#delete-file-upload-submit").click(function() { 15 | $("#delete-file-upload-form").submit(); 16 | }); 17 | 18 | }); -------------------------------------------------------------------------------- /static/js/pages/main.js: -------------------------------------------------------------------------------- 1 | function wsUrl() { 2 | if (window.location.protocol != "https:") { 3 | return "ws://" + window.location.host 4 | } else { 5 | return "wss://" + window.location.host 6 | } 7 | } 8 | 9 | function getCookie(name) { 10 | var value = "; " + document.cookie; 11 | var parts = value.split("; " + name + "="); 12 | if (parts.length == 2) { 13 | return parts.pop().split(";").shift(); 14 | } 15 | } 16 | 17 | function htmlEncode(value) { 18 | return $('
').text(value).html(); 19 | } 20 | 21 | $(document).ready(function() { 22 | if ($("#logout").length) { 23 | $("#logout").click(function() { 24 | $("#logout-form").submit(); 25 | }); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /static/js/pages/market/view.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("a[id^=item-details-button]").click(function() { 4 | var uuid = $(this).data("uuid"); 5 | $("#buy-market-item-uuid").val(uuid); 6 | $.getJSON('/user/market/details?uuid=' + uuid, function(data) { 7 | $.each(data, function(key, val) { 8 | //console.log("#" + key.toString() + " -> " + val.toString()); 9 | if (key !== "image") { 10 | $("#" + key).text(val); 11 | } else { 12 | $("#image").attr("src", function() { 13 | return "/static/images/" + val; 14 | }); 15 | } 16 | }); 17 | }); 18 | }); 19 | 20 | $("#buy-market-item-submit").click(function() { 21 | $("#buy-market-item-form").submit(); 22 | }); 23 | 24 | }); -------------------------------------------------------------------------------- /static/js/pages/menu/refresh.js: -------------------------------------------------------------------------------- 1 | const perfEntries = performance.getEntriesByType('navigation'); 2 | if (perfEntries.length && perfEntries[0].type == 'back_forward') { 3 | location.reload(); 4 | } -------------------------------------------------------------------------------- /static/js/pages/missions/firstlogin.js: -------------------------------------------------------------------------------- 1 | var dialog; 2 | function text_animation(term) { 3 | var index = 0; 4 | var intro_frames = $.parseJSON(dialog); 5 | 6 | term.echo("[[b;;]**************** BEGIN SECURE COMMUNIQUE ****************]\n"); 7 | 8 | function display(term, index) { 9 | term.echo(intro_frames[index]); 10 | index += 1; 11 | if (index < intro_frames.length) { 12 | setTimeout(display, 1500, term, index); 13 | } else { 14 | term.echo("[[b;;]**************** END OF TRANSMISSION ****************]"); 15 | } 16 | } 17 | setTimeout(display, 2000, term, index); 18 | } 19 | 20 | function loading(term) { 21 | term.clear(); 22 | var count = 0; 23 | loading_bar = ["|", "/", "-", "\\"]; 24 | message = "\n[[b;;]> Establishing communication channel, please wait...]"; 25 | 26 | function display(term, count) { 27 | term.clear(); 28 | sym = loading_bar[count % loading_bar.length]; 29 | term.echo(message + sym); 30 | count += 1; 31 | if (count < 35) { 32 | setTimeout(display, 100, term, count); 33 | } else { 34 | $(".c-glitch").empty(); 35 | term.clear(); 36 | text_animation(term); 37 | } 38 | } 39 | display(term, count); 40 | } 41 | 42 | function greetings(term) { 43 | term.pause(); 44 | loading(term); 45 | } 46 | 47 | $(document).ready(function() { 48 | $("#closebutton").click(function(){ 49 | window.location = '/user'; 50 | }); 51 | /* Update Summary Table */ 52 | $.get("/user/missions/ajax/firstlogin", function(firstlogin) { 53 | dialog = firstlogin; 54 | $('#console').terminal({ 55 | /* No commands just animation */ 56 | }, { 57 | prompt: " > ", 58 | name: 'console', 59 | greetings: null, 60 | tabcompletion: true, 61 | onInit: function(term) { 62 | greetings(term); 63 | }, 64 | }); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /static/js/pages/missions/view.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | barcolor(); 3 | }); 4 | 5 | function barcolor() { 6 | $("a[id^=unlock-game-level-button]").click(function() { 7 | var buyout = $(this).data("buyout"); 8 | var banking = $(this).data("banking"); 9 | $("#unlock-game-level-uuid").val($(this).data("uuid")); 10 | var description = "Would you like to unlock this level for "; 11 | if (banking) { 12 | description += "$" + buyout + "?"; 13 | } else { 14 | description += buyout + " point(s)"; 15 | } 16 | $("#description").text(description); 17 | }); 18 | 19 | $("#unlock-game-level-submit").click(function() { 20 | $("#unlock-game-level-form").submit(); 21 | }); 22 | 23 | $(".minibar").each(function() { 24 | if (this.style.width == "100%") { 25 | $(this).css('background-color', "#00bb00"); 26 | $(this).css('background-image', 'linear-gradient(to bottom,#00bb00,#009900)') 27 | } else { 28 | $(this).css('background-color', "#eeee00"); 29 | $(this).css('background-image', 'linear-gradient(to bottom,#eeee00,#b3b300)'); 30 | } 31 | }); 32 | } -------------------------------------------------------------------------------- /static/js/pages/pastebin.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("#create-paste").click(function() { 4 | $.get('/user/share/pastebin/create', function(data) { 5 | $('#display-paste').html(data); 6 | }); 7 | }); 8 | 9 | $("a[id^=view-paste]").click(function() { 10 | var uuid = $(this).data("uuid"); 11 | $.get('/user/share/pastebin/display?paste_uuid=' + uuid, function(data) { 12 | $('#display-paste').html(data); 13 | $("#create-paste").click(function() { 14 | $.get('/user/share/pastebin/create', function(data) { 15 | $('#display-paste').html(data); 16 | }); 17 | }); 18 | $("#delete-paste").click(function() { 19 | var uuid = $(this).data("uuid"); 20 | $('#delete-paste-uuid').val(uuid); 21 | $("#delete-paste-form").submit(); 22 | }); 23 | }); 24 | }); 25 | 26 | }); -------------------------------------------------------------------------------- /static/js/pages/public/reset.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $("#pass1").popover({placement:'right', trigger:'focus'}); 3 | $("#pass2").popover({placement:'right', trigger:'focus'}); 4 | }); -------------------------------------------------------------------------------- /static/js/pages/scoreboard/feed.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $.get("/scoreboard/ajax/feed", function(feed) { 3 | $("#snippet").find("pre").text(JSON.stringify(feed, undefined, 4)); 4 | }); 5 | }); -------------------------------------------------------------------------------- /static/js/pages/scoreboard/teams.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | window.scoreboard_ws = new WebSocket(wsUrl() + "/scoreboard/wsocket/pause_score"); 3 | 4 | if ($("#timercount_hidescoreboard").length > 0) { 5 | $.get("/scoreboard/ajax/timer", function(distance) { 6 | distance = distance * 1000; 7 | setTimer(distance, "_hidescoreboard"); 8 | }); 9 | scoreboard_ws.onmessage = function(event) { 10 | if (event.data !== "pause") { 11 | location.reload(); 12 | } 13 | } 14 | } else { 15 | if ($("#timercount").length > 0) { 16 | $.get("/scoreboard/ajax/timer", function(distance) { 17 | distance = distance * 1000; 18 | setTimer(distance, ""); 19 | }); 20 | } 21 | scoreboard_ws.onmessage = function(event) { 22 | if (event.data === "pause") { 23 | location.reload(); 24 | } 25 | } 26 | } 27 | $("#page_count").on('change', function() { 28 | document.location.href = "/teams?count=" + this.value + "&page=1"; 29 | }); 30 | }); 31 | 32 | function padDigits(number, digits) { 33 | return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number; 34 | } 35 | 36 | function setTimer(distance, id) { 37 | // Update the count down every 1 second 38 | var x = setInterval(function() { 39 | // Time calculations for days, hours, minutes and seconds 40 | var days = Math.max(0,Math.floor((distance) / (1000 * 60 * 60 * 24))); 41 | var hours = Math.max(0,Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); 42 | var minutes = Math.max(0,Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))); 43 | var seconds = Math.max(0,Math.floor((distance % (1000 * 60)) / 1000)); 44 | 45 | // Display the result in the element with id="timercount" 46 | var timercount = padDigits(minutes,2) + "m " + padDigits(seconds,2) + "s "; 47 | if (hours > 0) { 48 | timercount = hours + "h " + timercount; 49 | } 50 | if (days > 0) { 51 | timercount = days + "d " + timercount; 52 | } 53 | $("#timercount" + id).text(timercount); 54 | 55 | // If the count down is finished, write some text 56 | if (distance <= 0) { 57 | clearInterval(x); 58 | $("#timercount" + id).text("EXPIRED"); 59 | } 60 | distance = distance - 1000; 61 | }, 1000); 62 | } -------------------------------------------------------------------------------- /static/js/pages/upgrades/source_code_market.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("a[id^='buy-source-code-button']").click(function() { 4 | $("#buy-source-code-uuid").val($(this).data("uuid")); 5 | $("#buy-source-code-dialog").text( 6 | "Are you sure you want to buy this code for " + $(this).data("price") + "?" 7 | ); 8 | }); 9 | 10 | $("#buy-source-code-submit").click(function() { 11 | $("#buy-source-code-form").submit(); 12 | }); 13 | 14 | $("a[id^='download-source-code-button']").click(function() { 15 | window.open('/source_code_market/download?uuid=' + $(this).data("uuid"), '_newtab'); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /static/js/pages/upgrades/swat.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | $("a[id^=swat-player-button]").click(function() { 4 | $("#swat-player-uuid").val($(this).data("uuid")); 5 | var msg = "Bribe police to SWAT player for $" + $(this).data("price") + "?"; 6 | $("#swat-player-description").text(msg); 7 | }); 8 | 9 | $("#swat-player-submit").click(function() { 10 | $("#swat-player-form").submit(); 11 | }); 12 | 13 | }); -------------------------------------------------------------------------------- /static/js/pages/user/home.js: -------------------------------------------------------------------------------- 1 | var skills_chart; 2 | /* Highcharts code */ 3 | $(document).ready(function() { 4 | /* Skill Chart */ 5 | if ($("#spider_skills").length > 0) { 6 | skill_chart = new Highcharts.Chart({ 7 | chart: { 8 | renderTo: 'spider_skills', 9 | plotBackgroundColor: null, 10 | plotBorderWidth: null, 11 | plotShadow: false, 12 | backgroundColor:'transparent', 13 | polar: true, 14 | type: 'line', 15 | marginTop: 55 16 | }, 17 | title: { 18 | text: '' + $("#spider_skills").data("name") + '', 19 | style: { 20 | color: '#FFFFFF', 21 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif', 22 | 'text-shadow': '-1px 0 black, 0 1px black, 1px 0 black, 0 -1px black', 23 | }, 24 | }, 25 | tooltip: { 26 | shared: true, 27 | pointFormat: '{series.name}: {point.y:,.0f}
' 28 | }, 29 | xAxis: { 30 | categories: "", 31 | tickmarkPlacement: 'on', 32 | lineWidth: 0 33 | }, 34 | yAxis: { 35 | gridLineInterpolation: 'polygon', 36 | lineWidth: 0, 37 | min: 0 38 | }, 39 | legend: { 40 | enabled: false, 41 | align: 'right', 42 | verticalAlign: 'top', 43 | y: 70, 44 | layout: 'vertical' 45 | }, 46 | series: [{ 47 | name: 'Skill Progress', 48 | type: 'area', 49 | data: [5,6,8], 50 | pointPlacement: 'on' 51 | }], 52 | }); 53 | } 54 | }); 55 | 56 | /* Update code */ 57 | $(document).ready(function() { 58 | if ($("#spider_skills").length > 0) { 59 | skill_chart.xAxis[0].setCategories($.parseJSON(categories)); 60 | /* Update Graph */ 61 | $.get("/scoreboard/ajax/skills?uuid=" + $("#spider_skills").data("uuid"), function(skillvalues) { 62 | skill_chart.series[0].setData($.parseJSON(skillvalues), true); 63 | }); 64 | } 65 | }); -------------------------------------------------------------------------------- /static/js/pages/user/settings.js: -------------------------------------------------------------------------------- 1 | /* Add click events */ 2 | $(document).ready(function() { 3 | $(".teamavatarimg").click(function() { 4 | $("#team_avatar_select").val($(this).attr('value')); 5 | $("#team-avatar-form").click(); 6 | }); 7 | 8 | $(".useravatarimg").click(function() { 9 | $("#user_avatar_select").val($(this).attr('value')); 10 | $("#user-avatar-form").click(); 11 | }); 12 | }); -------------------------------------------------------------------------------- /static/js/themes/386.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | var 3 | character = { 4 | height: 20, 5 | width: 12.4 6 | }, 7 | wrap = document.createElement('div'), 8 | bar = wrap.appendChild(document.createElement('div')), 9 | 10 | cursor = document.createElement('div'), 11 | // If the user specified that the visibility is hidden, then we 12 | // start at the first pass ... otherwise we just do the 13 | // cursor fly-by 14 | pass = ($(document.body).css('visibility') == 'visible') ? 1 : 0, 15 | height = $(window).height(), 16 | width = $(window).width(), 17 | 18 | // this makes the loading of the screen proportional to the real-estate of the window. 19 | // it helps keep the cool sequence there while not making it waste too much time. 20 | rounds = (height * width / 165000), 21 | column = width, row = height - character.height; 22 | // TODO: externalize this 23 | // 24 | wrap.setAttribute('style', 'z-index:9999999;background:#000084;position:fixed;bottom:0;right:0;height:100%;width:100%'); 25 | bar.setAttribute('style', 'color:#fff;font-weight:bold;float:right;background:#000084;height:20px;margin-top:-20px;width:100%'); 26 | cursor.setAttribute('style', 'z-index:9999999;color:#fff;font-weight:bold;position:fixed;bottom:0;right:0'); 27 | 28 | cursor.innerHTML = bar.innerHTML = '▄'; 29 | 30 | // only inject the wrap if the pass is 0 31 | if(pass === 0) { 32 | document.body.appendChild(wrap); 33 | document.body.style.visibility='visible'; 34 | } else { 35 | document.body.appendChild(cursor); 36 | rounds /= 2; 37 | character.height *= 4; 38 | } 39 | 40 | var ival = setInterval(function(){ 41 | for(var m = 0; m < rounds; m++) { 42 | column -= character.width; 43 | 44 | if(column <= 0) { 45 | column = width; 46 | row -= character.height; 47 | } 48 | if(row <= 0) { 49 | pass++; 50 | row = height - character.height; 51 | 52 | if(pass == 2) { 53 | document.body.removeChild(cursor); 54 | clearInterval(ival); 55 | } else { 56 | wrap.parentNode.removeChild(wrap); 57 | document.body.appendChild(cursor); 58 | rounds /= 2; 59 | character.height *= 4; 60 | } 61 | } 62 | 63 | if(pass === 0) { 64 | bar.style.width = column + "px"; 65 | wrap.style.height = row + "px"; 66 | } else { 67 | cursor.style.right = column + "px"; 68 | cursor.style.bottom = row + "px"; 69 | } 70 | } 71 | }, 1); 72 | }); 73 | 74 | -------------------------------------------------------------------------------- /templates/admin/create/category.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{_("Create Category")}}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 |
11 |

12 | 13 | {{_("Create Category")}} 14 |

15 |
{% if errors is not None and len(errors) != 0 %} 16 | {% for error in errors %} 17 |
18 | × 19 |

{{_("ERROR")}}

20 | {{ error }} 21 |
22 | {% end %} 23 | {% end %} 24 |
25 |
26 | {% raw xsrf_form_html() %} 27 |
28 | 29 |
30 | 34 |
35 |
36 |
37 |
38 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 |
50 |
51 | {% end %} 52 | -------------------------------------------------------------------------------- /templates/admin/create/corporation.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{_("Create Corporation")}}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 |
11 |

12 | 13 | {{_("Create Corporation")}} 14 |

15 |
{% if errors is not None and len(errors) != 0 %} 16 | {% for error in errors %} 17 |
18 | × 19 |

{{_("ERROR")}}

20 | {{ error }} 21 |
22 | {% end %} 23 | {% end %} 24 |
25 |
26 | {% raw xsrf_form_html() %} 27 |
28 | 29 |
30 | 34 |
35 |
36 |
37 | 38 |
39 | 42 |
43 |
44 |
45 |
46 | 47 |
48 |
49 |
50 |
51 |
52 | {% end %} 53 | -------------------------------------------------------------------------------- /templates/admin/create/flag.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{_("Create Flag")}}{% end %} 4 | 5 | {% block content %} 6 | {% set thebox = "?box=" + box.uuid if box else "" %} 7 | 35 | {% end %} 36 | -------------------------------------------------------------------------------- /templates/admin/create/token.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{_("Registration Token")}}{% end %} 4 | 5 | {% block content %} 6 |
7 |
8 |
9 |
10 |

{{_("Token")}}: {{ token.getvalue() }}

11 |
12 |
13 |
14 |
15 |
16 | {% end %} 17 | -------------------------------------------------------------------------------- /templates/admin/export.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Export XML") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 |
11 |

12 | 13 | {{ _("Export XML") }} 14 |

15 |
16 | {% if errors is not None and len(errors) != 0 %} 17 | {% for error in errors %} 18 |
19 | × 20 |

{{ _("ERROR") }}

21 | {{ error }} 22 |
23 | {% end %} 24 | {% end %} 25 |
26 |
27 | {% raw xsrf_form_html() %} 28 | 29 | 30 | 40 |

  {{ _("Export Game Objects") }}

41 |
42 | {{ _("Include gameplay settings (such as those under ") }} {{ _("configuration") }}{{ _(") and logos in export.") }} 43 |

44 |
45 |
46 | 50 |
51 |
52 |
53 | {{ _("Note") }}: {{ _("Export of gameplay settings does not include the entire server and database configuration.")}} {{ _("To restore this RTB instance, you may also need the contents under the files directory, to include the rootthebox.cfg.")}} 54 |
55 |
56 |
57 | {% end %} 58 | -------------------------------------------------------------------------------- /templates/admin/import.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Import XML") }}{% end %} 4 | 5 | {% block content %} 6 |
7 |

8 | 9 | {{ _("Import XML") }} 10 |

11 |
12 | {% if errors is not None and len(errors) != 0 %} 13 | {% for error in errors %} 14 |
15 | × 16 |

{{ _("ERROR") }}

17 | {{ error }} 18 |
19 | {% end %} 20 | {% end %} 21 | {% if success is not None %} 22 |
23 | × 24 |

{{ _("SUCCESS") }}

25 | {{ success }} 26 |
27 | {% end %} 28 |
29 |
30 | {% raw xsrf_form_html() %} 31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 |
39 | 40 |
41 |
42 |
43 |
44 |
45 | {% end %} 46 | -------------------------------------------------------------------------------- /templates/admin/view/notifications.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{ _("All Notifications") }}{% end %} 4 | 5 | {% block content %} 6 | {% from models.Notification import Notification %} 7 |
8 |

9 | 10 | {{ _("All Notifications") }} 11 |

12 |
13 |
14 | {% for notify in reversed(list(Notification.admin())) %} 15 |
16 |
17 | {% if notify.icon_url is not None %} 18 | 19 | {% end %} 20 |
21 |
22 |

23 | {{ _(notify.title) }} 24 | {{ notify.created.strftime("%I:%M%p %x") }} 25 |
{{ notify.message }} 26 |

27 |
28 |
29 |
30 | {% end %} 31 |
32 |
33 | {% end %} -------------------------------------------------------------------------------- /templates/admin/view/pastebin.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{ _("PasteBin") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 | {% from tornado.options import options %} 11 | {% from models.Team import Team %} 12 |
13 | {% raw xsrf_form_html() %} 14 | 15 |
16 |
17 |
18 | {% set teams = Team.all() %} 19 | {% for team in teams %} 20 | 36 | {% end %} 37 |
38 |
39 | 47 |
48 |
49 | {% end %} -------------------------------------------------------------------------------- /templates/admin/view/token.html: -------------------------------------------------------------------------------- 1 | {% extends "../../main.html" %} 2 | 3 | {% block title %}{{ _("Create")}} {{_("Registration Tokens") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 | {% from models.RegistrationToken import RegistrationToken %} 11 |
12 |

{{ _("Registration Tokens") }}

13 |
14 |
15 | {% raw xsrf_form_html() %} 16 | 17 |
18 | {% if errors != None and len(errors) != 0 %} 19 | {% for error in errors %} 20 |
21 | × 22 |

{{ _("ERROR") }}

23 | {{ error }} 24 |
25 | {% end %} 26 | {% end %} 27 |
28 | {% if RegistrationToken.count() %} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for index, token in enumerate(RegistrationToken.all()) %} 40 | 41 | 42 | 43 | 44 | 50 | 51 | {% end %} 52 | 53 |
#{{ _("Token") }}{{ _("Used") }}
{{ index + 1 }}{{ token.getvalue() }}{{ token.used }} 45 | 46 | 47 | {{ _("Delete") }} 48 | 49 |
54 | {% else %} 55 |

{{ _("No Tokens in Database") }}

56 | {% end %} 57 |
58 |
59 | {% end %} -------------------------------------------------------------------------------- /templates/botnet/monitor.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Botnet") }} C & C{% end %} 4 | {% block header %} 5 | 6 | {% if not teamname %} 7 | 12 | {% end %} 13 | {% end %} 14 | {% block content %} 15 | {% from tornado.options import options %} 16 | 17 |
18 |

19 | 20 | {{ _("Botnet Command & Control") }} 21 |

22 |
23 |
24 | × 25 |

{{ _("Are You Elite") }}?

26 | 27 | {{ _("Download the command line botnet monitor") }} (Linux / BSD) 28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
#{% if options.teams %}{{ _("Team") }}{% else %}{{ _("Player") }}{% end %}{{ _("Box Name") }}{{ _("IP Address") }}{% if options.banking %}{{ _("Income") }}{% else %}{{ _("Points") }}{% end %}{{ _("Last Ping") }}
45 | 46 |
47 |
48 | {% end %} -------------------------------------------------------------------------------- /templates/file_upload/material_files.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Game Materials") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | 8 | 9 | 10 | {% end %} 11 | 12 | {% block content %} 13 |
14 |

15 | 16 | {{ _("Game Materials") }} 17 |

18 |
19 | {% if errors != None and len(errors) != 0 %} 20 | {% for error in errors %} 21 |
22 | × 23 |

{{ _("ERROR") }}

24 | {{ error }} 25 |
26 | {% end %} 27 | {% end %} 28 |
29 |
30 |
31 |
32 |
33 | {% end %} -------------------------------------------------------------------------------- /templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %} handler.application.settings['game_name'] {% end %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% block header %}{% end %} 26 | {% module Theme() %} 27 | 28 | {% block modals %}{% end %} 29 | 30 | {% module Menu() %} 31 |
32 | {% block content %} {{ _("Content Missing") }} {% end %} 33 | 34 |
35 |
36 | {% from tornado.options import options %} 37 |
38 | 42 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /templates/missions/captured.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Capture Message") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | 8 | 9 | 10 | {% end %} 11 | 12 | {% block content %} 13 | {% from tornado.options import options %} 14 |
15 |
16 |
17 | 18 |

19 | 20 | {{ _("Incoming Transmission") }} 21 |

22 | 23 | {% set message = "" %} 24 | {% if box and flag %} 25 | {% set message = str(flag.capture_message + "\n\n" + box.capture_message).strip() %} 26 | {% elif box %} 27 | {% set message = box.capture_message %} 28 | {% else %} 29 | {% set message = flag.capture_message %} 30 | {% end %} 31 | {% set message = message + "\n\n".join(options.story_signature) %} 32 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | {% end %} 52 | -------------------------------------------------------------------------------- /templates/missions/firstlogin.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("First Login") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | 8 | 9 | 10 | {% end %} 11 | 12 | {% block content %} 13 | {% from tornado.options import options %} 14 |
15 |
16 |
17 | 18 |

19 | 20 | {{ _("Incoming Transmission") }} 21 |

22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | {% end %} 38 | -------------------------------------------------------------------------------- /templates/missions/status.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Missions") }}{% end %} 4 | 5 | {% block content %} 6 | 7 | 8 |
9 |

{{ _("Missions") }}

10 |
11 | {% if errors is not None and len(errors) != 0 %} 12 | {% for error in errors %} 13 |
14 | × 15 |

{{ _("ERROR") }}

16 | {{ error }} 17 |
18 | {% end %} 19 | {% end %} 20 | {% if info is not None and len(info) != 0 %} 21 | {% for msg in info %} 22 |
23 | × 24 |

{{ _("INFO") }}

25 | {{ msg }} 26 |
27 | {% end %} 28 | {% end %} 29 | 30 |
31 | {% end %} 32 | -------------------------------------------------------------------------------- /templates/notifications/view.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("All Notifications") }}{% end %} 4 | 5 | {% block content %} 6 |
7 |

8 | 9 | {{ _("All Notifications") }} 10 |

11 |
12 |
13 | {% for notify in reversed(list(user.notifications)) %} 14 |
15 |
16 | {% if notify.icon_url is not None %} 17 | 18 | {% end %} 19 |
20 |
21 |

22 | {{ _(notify.title) }} 23 | {{ notify.created.strftime("%I:%M%p %x") }} 24 |
{{ notify.message }} 25 |

26 |
27 |
28 |
29 | {% end %} 30 |
31 |
32 | {% end %} -------------------------------------------------------------------------------- /templates/pastebin/create.html: -------------------------------------------------------------------------------- 1 | 9 |
10 |
11 | {% if errors is not None and len(errors) != 0 %} 12 | {% for error in errors %} 13 |
14 | × 15 |

{{ _("ERROR") }}

16 | {{ error }} 17 |
18 | {% end %} 19 | {% end %} 20 |
21 | {% raw xsrf_form_html() %} 22 | {% from tornado.options import options %} 23 |
24 | {{ _("Create New Paste") }} 25 | {% if user.is_admin() %} 26 | {% from models.Team import Team %} 27 |

28 | 29 |

30 | 36 |
37 |

38 | {% end %} 39 |

40 | 41 | 42 |

43 |

44 | 45 | 47 |

48 |
49 |

50 | 51 |

52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /templates/pastebin/display.html: -------------------------------------------------------------------------------- 1 | 10 |
11 |
12 | {% if paste is not None %} 13 |

{{ paste.name }} - {{ paste.created.strftime("%I:%M%p %x") }}

14 | 19 | {% end %} 20 |
21 |
22 | -------------------------------------------------------------------------------- /templates/pastebin/view.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("PasteBin") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 |
11 | {% raw xsrf_form_html() %} 12 | 13 |
14 |
15 |
16 | 32 |
33 |
34 | 42 |
43 |
44 | {% end %} -------------------------------------------------------------------------------- /templates/public/403.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}403{% end %} 4 | 5 | {% block content %} 6 |
7 | {% if locked %} 8 |

403 - {{ _("Account Locked!") }}

9 | {% elif xsrf %} 10 |

403 - {{ _("Invalid CSRF Token") }}

11 | {% else %} 12 |

403 - {{ _("Forbidden") }}

13 | {% end %} 14 |
15 |

16 | 17 | 20 |

21 |
22 | {% end %} 23 | -------------------------------------------------------------------------------- /templates/public/404.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title%}404{% end %} 4 | 5 | {% block content %} 6 |
7 |

404 - {{ _("Glitch in the Matrix") }}

8 | 9 |
10 |

11 | {{ _("It looks like you typed a URL incorrectly, or were attempting to find something you ought not have access to.") }} 12 |
13 | {{ _("The only other possibility is that I messed up some of the code, and that doesn't seem very likely.") }} 14 |

15 |
16 | {% end %} -------------------------------------------------------------------------------- /templates/public/forgot.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Password Reset") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% end %} 8 | 9 | {% block content %} 10 |
11 | 41 |
42 |
43 | {% end %} -------------------------------------------------------------------------------- /templates/public/home.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %} 4 | {% from tornado.options import options %} 5 | {{ options.game_name }} 6 | {% end %} 7 | 8 | {% block content %} 9 |
10 |
11 | 12 |

{{options.ctf_tagline}}

13 |
14 |
15 | {% end %} 16 | -------------------------------------------------------------------------------- /templates/public/login.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Authenticate") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | {% from tornado.options import options %} 8 | {% end %} 9 | 10 | {% block content %} 11 |
12 | 50 |
51 |
52 | {% end %} -------------------------------------------------------------------------------- /templates/public/stopped.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Game Status") }}{% end %} 4 | 5 | {% block content %} 6 | 7 | 8 |
9 |

{{ _("Game Status") }}

10 |
11 | {% if errors is not None and len(errors) != 0 %} 12 | {% for error in errors %} 13 |
14 | × 15 |

{{ _("ERROR") }}

16 | {{ error }} 17 |
18 | {% end %} 19 | {% end %} 20 | {% if info is not None and len(info) != 0 %} 21 | {% for msg in info %} 22 |
23 |   {{ msg }} 24 |
25 | {% end %} 26 | {% end %} 27 |
28 | {% end %} 29 | -------------------------------------------------------------------------------- /templates/public/successful_reg.html: -------------------------------------------------------------------------------- 1 | {% extends ../main.html %} 2 | 3 | {% block title %}{{ _("Successful Registration") }}{% end %} 4 | 5 | {% block content %} 6 | {% from tornado.options import options %} 7 |
8 |
9 |

{{ _("Successfully created a new account for") }} {{ user.handle }}!

10 | {% if options.teams and user.team %} 11 |

    {{ user.team.code }}
    12 | {{ _("Share your team code to allow other players to join") }} {{ user.team.name }}. 13 |

14 | {% end %} 15 |
16 | {% if validate %} 17 |

      18 | {{ _("Please check your email for account validation") }}

19 | {% else %} 20 | {{ _("Click here to login") }} » 21 | {% end %} 22 |
23 |
24 | {% end %} 25 | -------------------------------------------------------------------------------- /templates/recaptcha/captcha.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 |
8 |
-------------------------------------------------------------------------------- /templates/recaptcha/disabled.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

-------------------------------------------------------------------------------- /templates/scoreboard/mvp_table.html: -------------------------------------------------------------------------------- 1 | {% from tornado.options import options %} 2 | 3 | {% for index, user in enumerate(users) %} 4 | {% if users[user].get("money") > 0 %} 5 | 6 | {{ user }} 7 | {% if options.banking %}{{ _("$") }}{% end %}{{ users[user].get("money") }} 8 | 9 | {% end %} 10 | 11 | {% if index >= options.mvp_max - 1 %} 12 | {% break %} 13 | {% end %} 14 | {% end %} -------------------------------------------------------------------------------- /templates/theme/theme.html: -------------------------------------------------------------------------------- 1 | {% for resource in theme_files %}{% if resource.endswith(".css") %} 2 | {% elif resource.endswith(".js") %} 3 | {% end %}{% end %} -------------------------------------------------------------------------------- /templates/upgrades/federal_reserve.html: -------------------------------------------------------------------------------- 1 | {% extends "../main.html" %} 2 | 3 | {% block title %}{{ _("Federal Reserve") }}{% end %} 4 | 5 | {% block header %} 6 | 7 | 8 | 9 | 10 | {% end %} 11 | 12 | {% from tornado.options import options %} 13 | {% block content %} 14 | {% if "Federal Reserve" in options.allowed_market_items and user.has_item("Federal Reserve") %} 15 |
16 |

{{ _("Federal Reserve Bank") }}

17 |
18 |
19 |
20 | {% raw xsrf_form_html() %} 21 |
22 |

23 | 24 | {{ _("Mainframe Console") }} 25 |

26 |
27 |
28 |
29 |
30 | {% end %} 31 | {% end %} 32 | -------------------------------------------------------------------------------- /tests/Helpers.py: -------------------------------------------------------------------------------- 1 | from tornado.options import options 2 | 3 | from models import dbsession 4 | from models.Box import Box 5 | from models.Corporation import Corporation 6 | from models.GameLevel import GameLevel 7 | from models.Team import Team 8 | from models.User import User 9 | 10 | 11 | def create_team(): 12 | team = Team() 13 | team.name = "TestTeam" 14 | team.motto = "TestMotto" 15 | dbsession.add(team) 16 | dbsession.commit() 17 | return team 18 | 19 | 20 | def create_user(): 21 | user = User.by_handle("HacKer") 22 | if user is None: 23 | options.banking = True 24 | user = User() 25 | user.handle = "HacKer" 26 | user.password = "TestPassword" 27 | user.bank_password = "Test123" 28 | dbsession.add(user) 29 | dbsession.commit() 30 | return user 31 | 32 | 33 | def create_corp(): 34 | corp = Corporation() 35 | corp.name = "TestCorp" 36 | dbsession.add(corp) 37 | dbsession.commit() 38 | return corp 39 | 40 | 41 | def create_box(corp=None): 42 | if corp is None: 43 | corp = create_corp() 44 | game_level = GameLevel.all()[0] 45 | box = Box(corporation_id=corp.id, game_level_id=game_level.id) 46 | box.name = "TestBox" 47 | box.description = "Some description" 48 | box.difficuly = "Easy" 49 | corp.boxes.append(box) 50 | dbsession.add(box) 51 | dbsession.commit() 52 | return box, corp 53 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mar 12, 2012 4 | 5 | @author: moloch 6 | 7 | Copyright 2012 Root the Box 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | ------------------------------------------------------------------------------ 21 | 22 | Setup / delete the unit test database 23 | 24 | """ 25 | 26 | 27 | import logging 28 | import os 29 | 30 | from tornado.options import options 31 | 32 | 33 | def setup_database(db_name): 34 | # Setup the test database 35 | logging.debug("Setting up the test database connection ...") 36 | 37 | options.sql_dialect = "sqlite" 38 | options.sql_database = db_name 39 | 40 | # Create the default tables 41 | logging.debug("Creating tables ... ") 42 | from setup.create_database import create_tables, engine, metadata 43 | 44 | create_tables(engine, metadata, False) 45 | import setup.bootstrap 46 | 47 | 48 | def teardown_database(db_name): 49 | if os.path.exists("%s.db" % db_name): 50 | os.unlink("%s.db" % db_name) 51 | else: 52 | raise ValueError("Cannot delete test database: %s.db" % db_name) 53 | --------------------------------------------------------------------------------