Compare commits

..

No commits in common. "master" and "wip-cache" have entirely different histories.

30 changed files with 307 additions and 850 deletions

3
.gitignore vendored
View file

@ -159,6 +159,3 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
ansible/credentials/
terraform/mcaptcha/mcaptcha
sec/

View file

@ -1,27 +0,0 @@
steps:
backend:
image: python:3-bookworm
environment:
- ANSIBLE_HOST_KEY_CHECKING=False
commands:
- export PATH=$PATH:/root/.local/bin
- eval "$(ssh-agent -s)"
- make ci.init
- cat terraform/mcaptcha/hosts.ini
# db: mariadb cache: redis
- . venv/bin/activate && ansible-playbook --become -i terraform/mcaptcha/hosts.ini --extra-vars "database_type=mariadb cache_type=redis" ./ansible/mcaptcha.yml
- INVENTORY=terraform/mcaptcha/hosts.ini make test.cache
- INVENTORY=terraform/mcaptcha/hosts.ini make test.mcaptcha
# db: postgres cache: redis
- . venv/bin/activate && ansible-playbook --become -i terraform/mcaptcha/hosts.ini --extra-vars "database_type=postgres cache_type=redis" ./ansible/mcaptcha.yml
- INVENTORY=terraform/mcaptcha/hosts.ini make test.cache
- INVENTORY=terraform/mcaptcha/hosts.ini make test.mcaptcha
# embedded cache
- . venv/bin/activate && ansible-playbook --become -i terraform/mcaptcha/hosts.ini --extra-vars "database_type=postgres cache_type=embedded" ./ansible/mcaptcha.yml
- INVENTORY=terraform/mcaptcha/hosts.ini make test.mcaptcha
# embedded cache
- . venv/bin/activate && ansible-playbook --become -i terraform/mcaptcha/hosts.ini --extra-vars "database_type=mariadb cache_type=embedded" ./ansible/mcaptcha.yml
- INVENTORY=terraform/mcaptcha/hosts.ini make test.mcaptcha
- make ci.clean
secrets: [TEST_NODE_SSH_KEY]

View file

@ -24,12 +24,6 @@ define configure_cache
ansible-playbook -i $(INVENTORY) -f 10 ./ansible/cache.yml
endef
define configure_mcaptcha
. ./venv/bin/activate && \
ansible-playbook -i $(INVENTORY) -f 10 ./ansible/mcaptcha.yml
endef
define test_base
. ./venv/bin/activate && \
@ -55,19 +49,6 @@ define test_cache
endef
define test_mcaptcha
. ./venv/bin/activate && \
cd tests/mcaptcha/ && \
ANSIBLE_REMOTE_USER=root \
py.test --hosts='ansible://mcaptcha_hosts' \
-n 10 \
--verbose \
--ansible-inventory="../../${INVENTORY}" \
base.py
endef
define test_locust
. ./venv/bin/activate && \
@ -107,13 +88,6 @@ conf.dos: ## Configure all DoS VMs
conf.cache: ## Configure all cache VMs
$(call configure_cache)
# ```bash
# INVENTORY=./terraform/dos/hosts.ini make conf.mcaptcha
# ```
conf.mcaptcha: ## Configure all mcaptcha VMs
$(call configure_mcaptcha)
# ```bash
# INVENTORY=./terraform/dos/hosts.ini make conf.ping
# ```
@ -131,32 +105,7 @@ test.base: ## Test base configuration on all VMs
test.cache: ## Test cache configuration
$(call test_cache)
test.mcaptcha: ## Test mcaptcha configuration
$(call test_mcaptcha)
ci.init:
apt-get update
apt-get install -y ca-certificates curl gnupg tar wget libssl-dev python3-pip cython3 pipx apt-transport-https coreutils iputils-ping openssh-client libvirt-clients genisoimage
./scripts/ci.sh --init "$$TEST_NODE_SSH_KEY"
ssh-add /tmp/ci-ssh-id
ssh -o StrictHostKeyChecking=accept-new mcaptcha-ci@192.168.0.102 "echo f"
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | gpg --no-tty --batch --dearmor -o /etc/apt/keyrings/opentofu.gpg
chmod a+r /etc/apt/keyrings/opentofu.gpg
echo "deb [signed-by=/etc/apt/keyrings/opentofu.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" > /etc/apt/sources.list.d/opentofu.list
echo "deb-src [signed-by=/etc/apt/keyrings/opentofu.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" >> /etc/apt/sources.list.d/opentofu.list
apt-get update
apt-get install -y tofu
tofu -chdir=terraform/mcaptcha/ init
tofu -chdir=terraform/mcaptcha/ plan -var-file="ci.tfvars" -out="mcaptcha"
tofu -chdir=terraform/mcaptcha/ apply "mcaptcha"
pip install virtualenv && virtualenv venv
. venv/bin/activate && pip install -r requirements.txt
. venv/bin/activate && ansible-galaxy install -r ./ansible/requirements.yml
ci.clean:
echo yes | tofu -chdir=terraform/mcaptcha/ destroy -var-file="ci.tfvars"
./scripts/ci.sh --clean
help: ## Prints help for targets with comments
@cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-].+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View file

@ -5,9 +5,12 @@
---
- name: Install and enable firewall
hosts: all
remote_user: atm
pre_tasks:
- name: Ensure all VMs are reachable
ansible.builtin.ping:
roles:
- ufw
tasks:
- name: Install git, zip, nginx, wget, curl & other utils
@ -25,3 +28,4 @@
- python3-pip
- virtualenv
- python3-setuptools
- ufw

View file

@ -6,7 +6,8 @@
ansible.builtin.import_playbook: base.yml
- name: Install redis cache
hosts: all
hosts: mcaptcha_hosts
remote_user: atm
pre_tasks:
- name: Ensure all VMs are reachable
ansible.builtin.ping:

View file

@ -4,11 +4,10 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
- name: Base configuration
ansible.builtin.import_playbook: base.yml
roles:
- ufw
- name: Configure Locust instances
hosts: [mcaptcha_dos]
remote_user: atm
pre_tasks:
- name: Ensure all VMs are reachable
ansible.builtin.ping:

View file

@ -1,84 +0,0 @@
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#---
- name: Base configuration
ansible.builtin.import_playbook: base.yml
- name: Install and configure postgres
hosts: all
become: yes
vars_files:
- vars/mcaptcha/vars.yml
- vars/mcaptcha/postgresql.yml
tasks:
- ansible.builtin.include_role:
name: geerlingguy.postgresql
when:
database_type == "postgres"
- name: Install and configure mariadb
hosts: all
become: yes
vars_files:
- vars/mcaptcha/vars.yml
- vars/mcaptcha/mariadb.yml
tasks:
- ansible.builtin.include_role:
name: geerlingguy.mysql
when:
database_type == "mariadb"
- name: Install and configure cache
hosts: all
become: yes
vars_files:
- vars/mcaptcha/vars.yml
tasks:
- name: conditionally install redis cache
ansible.builtin.include_role:
name: cache
when: cache_type == "redis"
- name: Install mCaptcha binary
hosts: all
vars_files:
- vars/mcaptcha/vars.yml
roles:
- mcaptcha
tasks:
- name: restart mcaptcha
debug:
msg: "mCaptcha successfully deployed to {{ mcaptcha_server_hostname }}"
notify: restart mcaptcha
- name: Install git, zip, nginx, wget, curl & other utils
become: true
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
pkg:
- nginx
- name: Copy nginx vhost
become: true
ansible.builtin.template:
src: ./templates/mcaptcha/nginx.vhost.j2
dest: "/etc/nginx/sites-available/{{ mcaptcha_server_hostname }}"
owner: root
group: root
force: true
mode: "0644"
- name: Copy nginx vhost
become: true
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ mcaptcha_server_hostname }}"
dest: "/etc/nginx/sites-enabled/{{ mcaptcha_server_hostname }}"
state: link
- name: Restart nginx
become: true
ansible.builtin.service:
name: nginx
state: restarted

View file

@ -5,6 +5,7 @@
---
- name: Ping all servers
hosts: all
remote_user: atm
tasks:
- name: Ensure all VMs are reachable

View file

@ -1,3 +0,0 @@
- src: geerlingguy.mysql
- src: geerlingguy.postgresql

View file

@ -72,7 +72,15 @@
force: true
mode: "0755"
- name: Delete download dir
ansible.builtin.file:
path: /tmp/cache-lib
state: absent
# - name: Delete download dir
# ansible.builtin.file:
# path: /tmp/cache-lib
# state: absent
- name: Allow port 6379 for redis
become: true
community.general.ufw:
state: enabled
rule: allow
proto: tcp
port: "6379"

View file

@ -39,8 +39,8 @@
name: docker
state: present
- name: Add user to docker group
- name: Add user atm to docker group
become: true
ansible.builtin.user:
name: "{{ ansible_user_id }}"
name: atm # TODO: add admin user to docker group
groups: docker,users,admin

View file

@ -1,7 +0,0 @@
- name: restart mcaptcha
listen: restart mcaptcha
become: true
ansible.builtin.service:
name: mcaptcha
enabled: true
state: restarted

View file

@ -1,82 +0,0 @@
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
---
- name: Create mCaptcha systemd user
become: true
ansible.builtin.user:
name: mcaptcha
state: present
system: true
comment: mCaptcha systemd user
- name: Create download dir
ansible.builtin.file:
path: /tmp/mcaptcha-dl
state: directory
mode: "0755"
- name: Download binary
ansible.builtin.get_url:
url: https://dl.mcaptcha.org/mcaptcha/mCaptcha/master/mcaptcha-master-linux-amd64.tar.gz
dest: /tmp/mcaptcha-dl
checksum: sha256:https://dl.mcaptcha.org/mcaptcha/mCaptcha/master/mcaptcha-master-linux-amd64.tar.gz.sha256
- name: Extract mcaptcha-master-linux-amd64.tar.gz into /var/lib/foo
ansible.builtin.unarchive:
src: /tmp/mcaptcha-dl/mcaptcha-master-linux-amd64.tar.gz
remote_src: true
dest: /tmp/mcaptcha-dl/
- name: Install binary
become: true
notify: restart mcaptcha
ansible.builtin.copy:
src: /tmp/mcaptcha-dl/mcaptcha-master-linux-amd64/mcaptcha
remote_src: true
dest: /usr/local/bin/mcaptcha
owner: root
group: root
force: true
mode: "0755"
- name: Copy mCaptcha systemd servicefile
become: true
ansible.builtin.template:
src: ./templates/mcaptcha/mcaptcha.service.j2
dest: /etc/systemd/system/mcaptcha.service
owner: root
group: root
force: true
mode: "0777"
- name: Create mCaptcha config dir
become: true
ansible.builtin.file:
path: /etc/mcaptcha
state: directory
mode: "0755"
- name: Copy mCaptcha config file
become: true
notify: restart mcaptcha
ansible.builtin.template:
src: ./templates/mcaptcha/config.toml.j2
dest: /etc/mcaptcha/config.toml
owner: root
group: root
force: true
mode: "0644"
- name: Run mCaptcha as a systemd service
become: true
ansible.builtin.systemd_service:
name: mcaptcha
daemon_reload: true
state: started
enabled: true
- name: Delete download dir
ansible.builtin.file:
path: /tmp/mcaptcha-dl
state: absent

View file

@ -1,81 +0,0 @@
{% if database_type == 'postgres' %}
{% set mcaptcha_database_url = "postgres://" ~ database_owner ~ ":" ~ database_password ~ "@" ~ "localhost:5432/" ~ database_name %}
{% else %}
{% set mcaptcha_database_url = "mysql://" ~ database_owner ~ ":" ~ database_password ~ "@" ~ "localhost/" ~ database_name %}
{% endif %}
debug = "{{ mcaptcha_debug | default('false') }}"
source_code = "{{ mcaptcha_source_code | default('https://github.com/mCaptcha/mCaptcha') }}"
commercial = "{{ mcaptcha_commercial | default('false') }}"
allow_demo = "{{ mcaptcha_allow_demo | default('false') }}"
allow_registration = "{{ mcaptcha_allow_registration | default('true') }}"
[server]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
cookie_secret = "{{ mcaptcha_server_cookie_secret }}"
# The port at which you want authentication to listen to
# takes a number, choose from 1000-10000 if you dont know what you are doing
port = "{{ mcaptcha_server_port | default(7000) }}"
#IP address. Enter 0.0.0.0 to listen on all available addresses
ip= "{{ mcaptcha_server_bind | default('127.0.0.1') }}"
# enter your hostname, eg: example.com
domain = "{{ mcaptcha_server_hostname }}"
# Set true if you have setup TLS with a reverse proxy like Nginx.
# Does HTTPS redirect and sends additional headers that can only be used if
# HTTPS available to improve security
proxy_has_tls = "{{ mcaptcha_proxy_has_tls | default('false') }}"
[captcha]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
salt = "{{ mcaptcha_captcha_salt }}"
# garbage collection period to manage mCaptcha system
# leave untouched if you don't know what you are doing
gc = "{{ mcaptcha_captcha_gc | default(30) }}" #30
runners = "{{ mcaptcha_captcha_runners | default(4) }}" #4
queue_length = "{{ mcaptcha_captcha_queue_length | default(2000) }}" #2000
enable_stats = "{{ mcaptcha_captcha_enable_stats | default('true') }}" #true
[captcha.default_difficulty_strategy]
avg_traffic_difficulty = "{{ mcaptcha_captcha_default_difficulty_strategy_avg_traffic_difficulty | default(50000) }}" # 50000 # almost instant solution
peak_sustainable_traffic_difficulty = "{{ mcaptcha_captcha_default_difficulty_strategy_peak_sustainable_traffic_difficulty | default(3000000) }}" # 3000000 # roughly 1.5s
broke_my_site_traffic_difficulty = "{{ mcaptcha_captcha_default_difficulty_strategy_broke_my_site_traffic_difficulty | default(5000000) }}" # 5000000 # greater than 3.5s
# cooldown period in seconds
duration = "{{ mcaptcha_captcha_default_difficulty_strategy_avg_duration | default(30) }}" # 30
[database]
# This section deals with the database location and how to access it
# Please note that at the moment, we have support for only postgresqa.
# Example, if you are Batman, your config would be:
# url = "postgres://batman:password@batcave.org:5432/batcave"
# database_type = "postgres"
# pool = 4
url = "{{ mcaptcha_database_url }}" # "postgres://example.org" # hack for tests to run successfully
pool = "{{ mcaptcha_database_pool | default(4) }}" #4
{% if cache_type == 'redis' %}
[redis]
# This section deals with the database location and how to access it
# Please note that at the moment, we have support for only postgresqa.
# Example, if you are Batman, your config would be:
url = "{{ mcaptcha_redis_url }}" #"redis://127.0.0.1"
pool = "{{ mcaptcha_redis_pool | default(4) }}" #4
{% endif %}
[smtp]
from = "{{ mcaptcha_smtp_from }}" # "admin@localhost"
reply = "{{ mcaptcha_smtp_reply }}" #"admin@localhost"
url = "{{ mcaptcha_smtp_url }}" #"127.0.0.1"
port = "{{ mcaptcha_smtp_port }}" #10025
username = "{{ mcaptcha_smtp_username }}" #"admin"
password = "{{ mcaptcha_smtp_password }}" #"password"
#[survey]
#nodes = ["http://localhost:7001"]
#rate_limit = 10 # upload every hour
#instance_root_url = "http://localhost:7000"

View file

@ -1,34 +0,0 @@
[Unit]
Description=mCaptcha: PoW CAPTCHA system
After=syslog.target
After=network.target
{% if cache_type == 'redis' %}
Wants=redis.service
After=redis.service
{% endif %}
{% if database_type == 'postgres' %}
Wants=postgresql.service
After=postgresql.service
{% endif %}
{% if database_type == 'mariadb' %}
Wants=mariadb.service
After=mariadb.service
{% endif %}
[Service]
RestartSec=2s
Type=simple
User=mcaptcha
Group=mcaptcha
WorkingDirectory=/home/mcaptcha/
ExecStart=/usr/local/bin/mcaptcha
Restart=always
Environment=USER=mcaptcha HOME=/home/mcaptcha
[Install]
WantedBy=multi-user.target

View file

@ -1,12 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name {{ mcaptcha_server_hostname }};
error_log /var/log/nginx/"{{ mcaptcha_server_hostname }}".error.log;
access_log /var/log/nginx/"{{ mcaptcha_server_hostname }}".access.log;
location / {
proxy_pass http://{{ mcaptcha_server_bind }}:{{ mcaptcha_server_port }};
proxy_set_header Host $host;
}
}

View file

@ -1,136 +0,0 @@
---
# Set this to the user ansible is logging in as - should have root
# or sudo access
mysql_user_home: "/home/{{ ansible_user_id }}"
mysql_user_name: "{{ ansible_user_id }}"
# The default root user installed by mysql - almost always root
mysql_root_home: /root
mysql_root_username: root
mysql_root_password: root
# Set this to `true` to forcibly update the root password.
mysql_root_password_update: true
mysql_user_password_update: true
mysql_enabled_on_startup: true
# Whether my.cnf should be updated on every run.
overwrite_global_mycnf: true
# The following variables have a default value depending on operating system.
# mysql_config_file: /etc/my.cnf
# mysql_config_include_dir: /etc/my.cnf.d
# Pass in a comma-separated list of repos to use (e.g. "remi,epel"). Used only
# for RedHat systems (and derivatives).
mysql_enablerepo: ""
# Define a custom list of packages to install; if none provided, the default
# package list from vars/[OS-family].yml will be used.
# mysql_packages:
# - mysql
# - mysql-server
# - MySQL-python
mysql_python_package_debian: python3-mysqldb
# MySQL connection settings.
mysql_port: "3306"
mysql_bind_address: '0.0.0.0'
mysql_skip_name_resolve: false
mysql_datadir: /var/lib/mysql
mysql_sql_mode: ~
# The following variables have a default value depending on operating system.
# mysql_pid_file: /var/run/mysqld/mysqld.pid
# mysql_socket: /var/lib/mysql/mysql.sock
# Log file settings.
mysql_log_file_group: mysql
# Slow query log settings.
mysql_slow_query_log_enabled: false
mysql_slow_query_time: "2"
# The following variable has a default value depending on operating system.
# mysql_slow_query_log_file: /var/log/mysql-slow.log
# Memory settings (default values optimized ~512MB RAM).
mysql_key_buffer_size: "256M"
mysql_max_allowed_packet: "64M"
mysql_table_open_cache: "256"
mysql_sort_buffer_size: "1M"
mysql_read_buffer_size: "1M"
mysql_read_rnd_buffer_size: "4M"
mysql_myisam_sort_buffer_size: "64M"
mysql_thread_cache_size: "8"
mysql_query_cache_type: "0"
mysql_query_cache_size: "16M"
mysql_query_cache_limit: "1M"
mysql_max_connections: "151"
mysql_tmp_table_size: "16M"
mysql_max_heap_table_size: "16M"
mysql_group_concat_max_len: "1024"
mysql_join_buffer_size: "262144"
# Other settings.
mysql_lower_case_table_names: "0"
mysql_wait_timeout: "28800"
mysql_event_scheduler_state: "OFF"
# InnoDB settings.
mysql_innodb_file_per_table: "1"
# Set .._buffer_pool_size up to 80% of RAM but beware of setting too high.
mysql_innodb_buffer_pool_size: "256M"
# Set .._log_file_size to 25% of buffer pool size.
mysql_innodb_log_file_size: "64M"
mysql_innodb_log_buffer_size: "8M"
mysql_innodb_flush_log_at_trx_commit: "1"
mysql_innodb_lock_wait_timeout: "50"
# These settings require MySQL > 5.5.
mysql_innodb_large_prefix: "1"
mysql_innodb_file_format: "barracuda"
# mysqldump settings.
mysql_mysqldump_max_allowed_packet: "64M"
# Logging settings.
mysql_log: ""
# The following variables have a default value depending on operating system.
# mysql_log_error: /var/log/mysql/mysql.err
# mysql_syslog_tag: mysql
mysql_config_include_files: []
# - src: path/relative/to/playbook/file.cnf
# - { src: path/relative/to/playbook/anotherfile.cnf, force: yes }
# Databases.
mysql_databases:
- name: mcaptcha
collation: utf8_general_ci
encoding: utf8
replicate: 1
# Users.
mysql_users:
- name: mcaptcha
priv: "mcaptcha.*:ALL"
password: "{{ database_password }}"
mysql_disable_log_bin: false
# Replication settings (replication is only enabled if master/user have values).
mysql_server_id: "1"
mysql_max_binlog_size: "100M"
mysql_binlog_format: "ROW"
mysql_expire_logs_days: "10"
mysql_replication_role: ''
mysql_replication_master: ''
mysql_replication_master_inventory_host: "{{ mysql_replication_master }}"
# Same keys as `mysql_users` above.
mysql_replication_user:
- name: mcaptcha
host: 127.0.0.1
mysql_hide_passwords: false

View file

@ -1,48 +0,0 @@
# Set postgresql state when configuration changes are made. Recommended values:
# `restarted` or `reloaded`
postgresql_restarted_state: "restarted"
postgresql_python_library: python-psycopg2
postgresql_user: postgres
postgresql_group: postgres
# `md5` or `scram-sha-256` (https://www.postgresql.org/docs/10/auth-methods.html)
postgresql_auth_method: "md5"
postgresql_unix_socket_directories:
- /var/run/postgresql
postgresql_service_state: started
postgresql_service_enabled: true
# Global configuration options that will be set in postgresql.conf.
postgresql_global_config_options:
- option: unix_socket_directories
value: '{{ postgresql_unix_socket_directories | join(",") }}'
- option: log_directory
value: 'log'
# Host based authentication (hba) entries to be added to the pg_hba.conf. This
# variable's defaults reflect the defaults that come with a fresh installation.
postgresql_hba_entries:
- {type: local, database: all, user: postgres, auth_method: peer}
- {type: local, database: all, user: all, auth_method: peer}
- {type: host, database: all, user: all, address: '127.0.0.1/32', auth_method: "{{ postgresql_auth_method }}"}
- {type: host, database: all, user: all, address: '::1/128', auth_method: "{{ postgresql_auth_method }}"}
# Debian only. Used to generate the locales used by PostgreSQL databases.
postgresql_locales:
- 'en_US.UTF-8'
# Users to ensure exist.
postgresql_users:
- name: "{{ database_owner }}" #required; the rest are optional
password: "{{ database_password }}"
# Databases to ensure exist.
postgresql_databases:
- name: "{{ database_name }}" # required; the rest are optional
owner: "{{ database_owner }}"
# Whether to output user data when managing users.
postgres_users_no_log: true

View file

@ -1,70 +0,0 @@
database_type: "postgres" # REQUIRED. options: "mariadb", "postgres"
cache_type: "redis" # REQUIRED. options: "embedded", "redis"
# database user
database_owner: "mcaptcha"
database_name: "mcaptcha"
# AUTO-GENERATED. database password
database_password: "{{ lookup('ansible.builtin.password', 'credentials/database_password', chars=['ascii_leters', 'digits'], length=32) }}"
# Database connection pool
mcaptcha_database_pool: 4
# debug logging
mcaptcha_debug: false
# doens't do anything at the moment
mcaptcha_commercial: false
# create demo user and allow demo login
mcaptcha_allow_demo: false
# allow registration of new accounts. Required for the first user account.
# Please edit to set to "false" and re-rerun playbook if registration is
# undesirable.
mcaptcha_allow_registration: true
# AUTO-GENERATED. Randomly generated unique value for signing cookies.
mcaptcha_server_cookie_secret: "{{ lookup('ansible.builtin.password', 'credentials/mcaptcha_server_cookie_secret', chars=['ascii_leters', 'digits'], length=32) }}"
# REQUIRED. mcaptcha server port. Won't be exposed to internet, change if something else
# is listening on binding IP and port combination.
mcaptcha_server_port: 7000
# REQUIRED. bind to IP. If using reverse proxy (playbook installs and configures nginx), set to 127.0.0.1.
mcaptcha_server_bind: "127.0.0.1"
# REQUIRED. hostname of the mcaptcha installation. Incorrect hostname will cause login failures.
mcaptcha_server_hostname: "mcaptcha.local"
# AUTO-GENERATED. IGNORE if unfamiliar.
mcaptcha_captcha_salt: "{{ lookup('ansible.builtin.password', 'credentials/mcaptcha_captha_salt', chars=['ascii_leters', 'digits'], length=32) }}"
# IGNORE if unfamiliar. # garbage collection period to manage mCaptcha system
# mcaptcha_captcha_gc: 30
# IGNORE if unfamiliar. Number of threads used to validate Proof-of-Work (PoW)
# mcaptcha_captcha_runners: 4
# IGNORE if unfamiliar. Maximum pending jobs in queue for PoW validation
# mcaptcha_captcha_queue_length: 2000
# Store PoW compute time statistics
mcaptcha_captcha_enable_stats: true
# IGNORE if unfamiliar. Difficulty factor for average traffic. Used in "easy mode" CAPTCHA configuration generation.
#mcaptcha_captcha_default_difficulty_strategy_avg_traffic_difficulty: 50000 # almost instant solution
# IGNORE if unfamiliar. Difficulty factor for peak traffic levels. Used in "easy mode" CAPTCHA configuration generation.
#mcaptcha_captcha_default_difficulty_strategy_peak_sustainable_traffic_difficulty: 3000000 # roughly 1.5s
# IGNORE if unfamiliar. Difficulty factor for maximum traffic levels. Used in "easy mode" CAPTCHA configuration generation.
#mcaptcha_captcha_default_difficulty_strategy_broke_my_site_traffic_difficulty: 5000000 # greater than 3.5s
# IGNORE if unfamiliar. Default cooldown period in seconds for "easy mode".
mcaptcha_captcha_default_difficulty_strategy_avg_duration: 30
# Redis instance URL
mcaptcha_redis_url: "redis://127.0.0.1"
# Redis connection pool
mcaptcha_redis_pool: 4
# smtp configuration
mcaptcha_smtp_from: "admin@localhost"
mcaptcha_smtp_reply: "admin@localhost"
mcaptcha_smtp_url: "127.0.0.1"
mcaptcha_smtp_port: 10025
mcaptcha_smtp_username: "admin"
mcaptcha_smtp_password: "password"
#[survey]
#nodes = ["http://localhost:7001"]
#rate_limit = 10 # upload every hour
#instance_root_url = "http://localhost:7000"

View file

@ -1,21 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":dependencyDashboard"
],
"labels": [
"renovate-bot"
],
"prHourlyLimit": 0,
"timezone": "Asia/kolkata",
"prCreation": "immediate",
"vulnerabilityAlerts": {
"enabled": true,
"labels": [
"renovate-bot",
"renovate-security",
"security"
]
}
}

View file

@ -1,31 +1,289 @@
ansible==9.1.0
ansible-core==2.16.2
certifi==2023.11.17
cffi==1.16.0
charset-normalizer==3.3.2
ansible==8.1.0
ansible-core==2.15.1
certifi==2023.5.7
cffi==1.15.1
charset-normalizer==3.2.0
contextvars==2.4
cryptography==41.0.7
cryptography==41.0.2
distro==1.8.0
execnet==2.0.2
idna==3.6
immutables==0.20
idna==3.4
immutables==0.19
iniconfig==2.0.0
Jinja2==3.1.2
jmespath==1.0.1
looseversion==1.3.0
MarkupSafe==2.1.3
msgpack==1.0.7
packaging==23.2
pluggy==1.3.0
psutil==5.9.6
msgpack==1.0.5
packaging==23.1
pluggy==1.2.0
psutil==5.9.5
pycparser==2.21
pycryptodomex==3.19.0
pytest==7.4.3
pytest-testinfra==10.0.0
pytest-xdist==3.5.0
PyYAML==6.0.1
pyzmq==25.1.2
pycryptodomex==3.18.0
pytest==7.4.0
pytest-testinfra==8.1.0
pytest-xdist==3.3.1
PyYAML==6.0
pyzmq==25.0.2
requests==2.31.0
resolvelib==1.0.1
salt==3006.4
urllib3==2.1.0
salt==3006.1
urllib3==2.0.3
airdrop-ng==1.1
airgraph-ng==1.1
apparmor==3.1.6
appdirs==1.4.4
argcomplete==2.0.0
asttokens==2.2.1
async-timeout==4.0.2
attrs==22.2.0
autocommand==2.2.2
autopage==0.5.1
Babel==2.12.1
beautifulsoup4==4.12.2
binwalk==2.3.3
black==23.7.0
borgbackup==1.2.4
Brlapi==0.8.5
btrfsutil==6.3.3
certifi==2023.7.22
cffi==1.15.1
chardet==5.2.0
charset-normalizer==3.2.0
click==8.1.6
cliff==4.3.0
cmd2==2.4.3
codespell==2.2.5
colorama==0.4.6
ConfigArgParse==1.5.3
contourpy==1.1.0
crit==3.18
cryptography==41.0.3
cupshelpers==1.0
cycler==0.11.0
Cython==3.0.0
dbus-python==1.3.2
debtcollector==2.5.0
decorator==5.1.1
defusedxml==0.7.1
deprecation==2.1.0
devtools==0.11.0
distlib==0.3.7
distro==1.8.0
dnspython==2.3.0
dogpile.cache==1.1.8
executing==1.2.0
fastjsonschema==2.18.0
filelock==3.12.2
fonttools==4.42.0
gevent==22.10.2
git-filter-repo==2.38.0
gpg==1.21.0
greenlet==2.0.2
html5lib==1.1
httpie==3.2.1
idna==3.4
importlib-metadata==5.0.0
inflect==7.0.0
iotop==0.6
iso8601==2.0.0
jaraco.context==4.3.0
jaraco.functools==3.8.1
jaraco.text==3.11.1
jedi==0.18.2
jmespath==1.0.1
jsonpatch==1.33
jsonpointer==2.4
jsonschema==4.19.0
jsonschema-specifications==2023.7.1
keystoneauth1==5.2.1
kiwisolver==1.4.4
lensfun==0.3.4
LibAppArmor==3.1.6
libfdt==1.7.0
libtorrent==2.0.9
libvirt-python==9.6.0
lit==15.0.7.dev0
louis==3.26.0
lxml==4.9.2
Mako==1.2.4
mallard-ducktype==1.0.2
Markdown==3.4.4
markdown-it-py==2.2.0
MarkupSafe==2.1.3
matplotlib==3.7.2
mdurl==0.1.2
MemoizeDB==2021.11.20.2.41.2
meson==1.2.1
more-itertools==10.1.0
msgpack==1.0.5
multidict==6.0.4
mypy-extensions==1.0.0
netaddr==0.8.0
netifaces==0.11.0
nftables==0.1
numpy==1.25.1
openshot-qt==3.1.1
openstacksdk==1.0.1
ordered-set==4.1.0
os-service-types==1.7.0
osc-lib==2.8.0
oslo.config==9.1.1
oslo.i18n==6.0.0
oslo.serialization==5.1.1
oslo.utils==6.1.0
packaging==23.1
parso==0.8.3
pathspec==0.11.2
pbr==5.11.1
perf==0.1
Pillow==10.0.0
pipenv==2023.7.23
pipx==1.2.0
platformdirs==3.10.0
ply==3.11
pm2ml==2021.11.20.2.41.2
pooch==1.7.0
Powerpill==2021.11.20.2.41.2
prettytable==3.6.0
protobuf==4.23.4
psutil==5.9.5
pwquality==1.4.5
pyalpm==0.10.6
pyasn1==0.4.8
pybind11==2.11.1
pycairo==1.24.0
pycparser==2.21
pycups==2.0.1
pycurl==7.45.2
pydantic==1.10.9
Pygments==2.16.1
PyGObject==3.44.1
pynvim==0.4.3
pyOpenSSL==23.2.0
pyparsing==3.0.9
pyperclip==1.8.2
PyQt5==5.15.9
PyQt5-sip==12.12.2
PyQtWebEngine==5.15.6
pyrsistent==0.19.3
pysequoia==0.1.20
PySocks==1.7.1
python-cinderclient==9.3.0
python-dateutil==2.8.2
python-glanceclient==4.1.0
python-keystoneclient==5.1.0
python-novaclient==18.3.0
python-openstackclient==6.2.0
pytz==2023.3
pyxdg==0.28
PyYAML==6.0.1
pyzmq==25.1.1
redis==4.6.0
referencing==0.30.2
Reflector==2023.6.28.0.36.1
requests==2.28.2
requests-toolbelt==1.0.0
requestsexceptions==1.4.0
rfc3986==2.0.0
rich==13.5.2
rpds-py==0.9.2
rpm==4.18.1
scipy==1.11.1
simplejson==3.19.1
six==1.16.0
soupsieve==2.4.1
stevedore==5.1.0
TBB==0.2
tomli==2.0.1
torbrowser-launcher==0.3.6
tqdm==4.65.0
trash-cli==0.23.2.13.2
trimage==1.0.6
trove-classifiers==2023.8.8
typing_extensions==4.7.1
uc-micro-py==1.0.2
ufw==0.36.2
urllib3==1.26.15
userpath==1.8.0
validate-pyproject==0.13.post1.dev0+gb752273.d20230520
vboxapi==1.0
virtualenv==20.24.3
virtualenv-clone==0.5.7
warlock==2.0.1
wcwidth==0.2.6
webencodings==0.5.1
wrapt==1.14.1
XCGF==2021.11.20.2.41.3
XCPF==2021.12.24.10.22.41
youtube-dl==2021.12.17
yt-dlp==2023.7.6
zipp==3.16.2
zope.event==5.0
zope.interface==6.0
ansible==8.1.0
ansible-compat==4.1.6
ansible-core==2.15.1
ansible-lint==6.17.2
astroid==2.15.6
attrs==23.1.0
black==23.7.0
bracex==2.3.post1
certifi==2023.5.7
cffi==1.15.1
charset-normalizer==3.2.0
click==8.1.6
contextvars==2.4
cryptography==41.0.2
dill==0.3.7
distro==1.8.0
execnet==2.0.2
filelock==3.12.2
gitdb==4.0.10
GitPython==3.1.32
idna==3.4
immutables==0.19
iniconfig==2.0.0
isort==5.12.0
Jinja2==3.1.2
jmespath==1.0.1
jsonschema==4.19.0
jsonschema-specifications==2023.7.1
lazy-object-proxy==1.9.0
lint==1.2.1
looseversion==1.3.0
markdown-it-py==3.0.0
MarkupSafe==2.1.3
mccabe==0.7.0
mdurl==0.1.2
msgpack==1.0.5
mypy-extensions==1.0.0
packaging==23.1
pathspec==0.11.2
platformdirs==3.10.0
pluggy==1.2.0
psutil==5.9.5
pycparser==2.21
pycryptodomex==3.18.0
Pygments==2.16.1
pylint==2.17.5
pytest==7.4.0
pytest-testinfra==8.1.0
pytest-xdist==3.3.1
PyYAML==6.0
pyzmq==25.0.2
referencing==0.30.2
requests==2.31.0
resolvelib==1.0.1
rich==13.5.2
rpds-py==0.9.2
ruamel.yaml==0.17.32
ruamel.yaml.clib==0.2.7
salt==3006.1
smmap==5.0.0
subprocess-tee==0.4.1
tomlkit==0.12.1
urllib3==2.0.3
wcmatch==8.4.1
wrapt==1.15.0
yamllint==1.32.0

View file

@ -1,84 +0,0 @@
#!/bin/bash
# ci.sh: Helper script to automate deployment operations on CI/CD
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set -xEeuo pipefail
#source $(pwd)/scripts/lib.sh
readonly SSH_ID_FILE=/tmp/ci-ssh-id
match_arg() {
if [ $1 == $2 ] || [ $1 == $3 ]
then
return 0
else
return 1
fi
}
help() {
cat << EOF
USAGE: ci.sh [SUBCOMMAND]
Helper script to automate deployment operations on CI/CD
Subcommands
-c --clean cleanup secrets, SSH key and other runtime data
-i --init <SSH_PRIVATE_KEY> initialize environment, write SSH private to file
-h --help print this help menu
EOF
}
# $1: SSH private key
write_ssh(){
truncate --size 0 $SSH_ID_FILE
echo "$1" > $SSH_ID_FILE
chmod 600 $SSH_ID_FILE
}
clean() {
if [ -f $SSH_ID_FILE ]
then
shred $SSH_ID_FILE
rm $SSH_ID_FILE
fi
}
if (( "$#" < 1 ))
then
help
exit -1
fi
if match_arg $1 '-i' '--init'
then
if (( "$#" < 2 ))
then
help
exit -1
fi
write_ssh "$2"
elif match_arg $1 '-c' '--clean'
then
clean
elif match_arg $1 '-h' '--help'
then
help
else
help
fi

View file

@ -1,5 +0,0 @@
libvirt_uri = "qemu+ssh://mcaptcha-ci@192.168.0.102/system?keyfile=/tmp/ci-ssh-id&sshauth=privkey&no_verify=1"
libvirt_pool_path = "/home/mcaptcha-ci/libvirt/pool/mcaptcha_basic"
libvirt_debian_src = "http://192.168.0.102/debian-12-generic-amd64.qcow2"
macvtap_ethernet_interface = "enp2s0"
ssh_public_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBCYagT9/PXoeaUae7Z3BKOPKBiEvJsCTUIhPCcRp5fb mcaptcha-ci@hellbat.batsense.net"

View file

@ -1,17 +1,10 @@
#cloud-config
# vim: syntax=yaml
packages:
- sudo
- qemu-guest-agent
runcmd:
- [ systemctl, daemon-reload ]
- [ systemctl, enable, qemu-guest-agent.service ]
- [ systemctl, start, --wait, qemu-guest-agent.service ]
users:
- name: root
ssh_authorized_keys:
- ${ssh_public_key}
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/wXdHpwpY/4ubhYTmuNdGepQpj1kchvTUTApxMZyfyVW4uzrPRTYsle1y9QbTBV35qLkNajRC/wmC5/xPchdXpsJpuD9st1HMhLeR8qwaPyptiYJYT+z/WisWw2k6oWhG3QKvPoRtBdW9nhZnkG+O6zkuGXiRHpS7j2VVboDPpWEe1UdELQFVCwfraRal2g3ENFZ/9V1UrW/4ahRnQnSxERplZUm/fgSxQtmXubTkW68ut7yasBsrKFffMm8JztW0tWgTlTKONd3LCjv4juM0t5+cJDotNDnUR86Tq2PG8io7no/h8BWtazmjdpfGgn02ibX26BkdU0LDEYbJt5q9/Fh9TGk2ZwcMQeyepO1AWQgkmHXZWZELqu6MLQpqdtsOjHp9k0MeSpuIbdwzgf10Ydy7vK1z8irS24tVNNnJaMBwOlVOPwfyztHRADPkFcv2lKSjS1uyKR0FIkV8Kvs4txaIjmwv2LfMg6lF5W6j3ZPLyeE4cplJP0DDjzorSanu31xVnqVb3A8V9awsJ/4H7d59bI99c7QHL4K3fBVP3O0gqd31xAVRsdGs5Tj2P+RpiI6o5JJiOa1+DuBdWzrVIXYchQ30ZjaJp1wTNsYLmAsjeYuQZE2tf1xvywdzD4MB4avugDEWikzRWN9V5PHDZr1bamTCCjOrb2PRCd7eSQ== aravinth7820@gmail.com
- name: atm
gecos: Aravinth Manivannan
groups: users, admin
@ -20,7 +13,7 @@ users:
lock_passwd: true
plain_text_passwd: fooabr12
ssh_authorized_keys:
- ${ssh_public_key}
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/wXdHpwpY/4ubhYTmuNdGepQpj1kchvTUTApxMZyfyVW4uzrPRTYsle1y9QbTBV35qLkNajRC/wmC5/xPchdXpsJpuD9st1HMhLeR8qwaPyptiYJYT+z/WisWw2k6oWhG3QKvPoRtBdW9nhZnkG+O6zkuGXiRHpS7j2VVboDPpWEe1UdELQFVCwfraRal2g3ENFZ/9V1UrW/4ahRnQnSxERplZUm/fgSxQtmXubTkW68ut7yasBsrKFffMm8JztW0tWgTlTKONd3LCjv4juM0t5+cJDotNDnUR86Tq2PG8io7no/h8BWtazmjdpfGgn02ibX26BkdU0LDEYbJt5q9/Fh9TGk2ZwcMQeyepO1AWQgkmHXZWZELqu6MLQpqdtsOjHp9k0MeSpuIbdwzgf10Ydy7vK1z8irS24tVNNnJaMBwOlVOPwfyztHRADPkFcv2lKSjS1uyKR0FIkV8Kvs4txaIjmwv2LfMg6lF5W6j3ZPLyeE4cplJP0DDjzorSanu31xVnqVb3A8V9awsJ/4H7d59bI99c7QHL4K3fBVP3O0gqd31xAVRsdGs5Tj2P+RpiI6o5JJiOa1+DuBdWzrVIXYchQ30ZjaJp1wTNsYLmAsjeYuQZE2tf1xvywdzD4MB4avugDEWikzRWN9V5PHDZr1bamTCCjOrb2PRCd7eSQ== aravinth7820@gmail.com
ssh_pwauth: true
chpasswd:

View file

@ -32,9 +32,6 @@ resource "libvirt_volume" "debian-mcaptcha-qcow2" {
data "template_file" "user_data" {
template = file("${path.module}/cloud_init.cfg")
vars = {
ssh_public_key = var.ssh_public_key
}
}
data "template_file" "network_config" {

View file

@ -13,10 +13,9 @@ resource "libvirt_volume" "mcaptcha_volume" {
resource "libvirt_domain" "mcaptcha_mcaptcha" {
count = var.mcaptcha_vm_count
name = "mcaptcha_mcaptcha_${count.index}"
memory = var.mcaptcha_vm_memory
vcpu = var.mcaptcha_vm_vcpu
qemu_agent = true
name = "mcaptcha_mcaptcha_${count.index}"
memory = var.mcaptcha_vm_memory
vcpu = var.mcaptcha_vm_vcpu
cloudinit = libvirt_cloudinit_disk.commoninit.id
@ -32,9 +31,8 @@ resource "libvirt_domain" "mcaptcha_mcaptcha" {
target_port = "1"
}
network_interface {
macvtap = var.macvtap_ethernet_interface
network_name = "default"
wait_for_lease = true
}
@ -43,8 +41,6 @@ resource "libvirt_domain" "mcaptcha_mcaptcha" {
}
}
locals {
mcaptcha_vm_ips = [for i in libvirt_domain.mcaptcha_mcaptcha : i.network_interface.0.addresses[0]]
mcaptcha_vm_names = [for i in libvirt_domain.mcaptcha_mcaptcha : i.name]

View file

@ -2,4 +2,3 @@ version: 2
ethernets:
ens3:
dhcp4: true
# ip: 192.168.0.115

View file

@ -12,7 +12,7 @@ resource "local_file" "hosts_yml" {
{
mcaptcha_vms_ips = local.mcaptcha_vm_ips,
mcaptcha_vms_names = local.mcaptcha_vm_names,
mcaptcha_vms = local.mcaptcha_vm_map
mcaptcha_vms = local.mcaptcha_vm_map
})

View file

@ -44,15 +44,3 @@ variable "mcaptcha_vm_vcpu" {
type = number
default = 4
}
variable "macvtap_ethernet_interface" {
description = "Ethernet interface on the host machine that can be used as macvtap"
type = string
default = "enp2s0"
}
variable "ssh_public_key" {
description = "Set up SSH login for this public key"
type = string
default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/wXdHpwpY/4ubhYTmuNdGepQpj1kchvTUTApxMZyfyVW4uzrPRTYsle1y9QbTBV35qLkNajRC/wmC5/xPchdXpsJpuD9st1HMhLeR8qwaPyptiYJYT+z/WisWw2k6oWhG3QKvPoRtBdW9nhZnkG+O6zkuGXiRHpS7j2VVboDPpWEe1UdELQFVCwfraRal2g3ENFZ/9V1UrW/4ahRnQnSxERplZUm/fgSxQtmXubTkW68ut7yasBsrKFffMm8JztW0tWgTlTKONd3LCjv4juM0t5+cJDotNDnUR86Tq2PG8io7no/h8BWtazmjdpfGgn02ibX26BkdU0LDEYbJt5q9/Fh9TGk2ZwcMQeyepO1AWQgkmHXZWZELqu6MLQpqdtsOjHp9k0MeSpuIbdwzgf10Ydy7vK1z8irS24tVNNnJaMBwOlVOPwfyztHRADPkFcv2lKSjS1uyKR0FIkV8Kvs4txaIjmwv2LfMg6lF5W6j3ZPLyeE4cplJP0DDjzorSanu31xVnqVb3A8V9awsJ/4H7d59bI99c7QHL4K3fBVP3O0gqd31xAVRsdGs5Tj2P+RpiI6o5JJiOa1+DuBdWzrVIXYchQ30ZjaJp1wTNsYLmAsjeYuQZE2tf1xvywdzD4MB4avugDEWikzRWN9V5PHDZr1bamTCCjOrb2PRCd7eSQ== aravinth7820@gmail.com"
}

View file

@ -1,39 +0,0 @@
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import os
import requests
def test_mcaptcha_nginx_is_listening(host):
socket = host.socket(f"tcp://127.0.0.1:80")
assert socket.is_listening
def test_mcaptcha_config_exists(host):
config = host.file("/etc/mcaptcha/config.toml")
assert config.exists
assert config.is_file
def test_mcaptcha_health(host):
url = f"http://{host.interface.default().addresses[0]}/api/v1/meta/health"
resp = requests.get(url, headers={"Host": "mcaptcha.local"})
assert resp.status_code == 200
data = resp.json()
if "redis" in data:
assert data["redis"] is True
assert data["db"] is True
def test_nginx_service_running_and_enabled(host):
service = host.service("nginx")
assert service.is_running
assert service.is_enabled
def test_mcaptcha_service_running_and_enabled(host):
service = host.service("mcaptcha")
assert service.is_running
assert service.is_enabled