From 6d915dd533ffa0625bad37d4e1f084d043cabdf5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Dec 2024 08:27:42 +0000 Subject: [PATCH] Initial commit: Add WireGuard VPN provisioning system --- ansible/group_vars/vpn_servers/vars.yml | 4 + ansible/playbooks/templates/client.conf.j2 | 10 + ansible/playbooks/templates/server.conf.j2 | 10 + ansible/playbooks/vpn_provision.yml | 118 ++++++++++ app/__init__.py | 0 app/handlers/__init__.py | 0 app/handlers/webhook_handler.py | 182 +++++++++++++++ app/utils/__init__.py | 0 app/utils/vault_helper.py | 39 ++++ inventory.ini | 2 + venv/bin/Activate.ps1 | 247 +++++++++++++++++++++ venv/bin/activate | 69 ++++++ venv/bin/activate.csh | 26 +++ venv/bin/activate.fish | 69 ++++++ venv/bin/ansible | 8 + venv/bin/ansible-community | 8 + venv/bin/ansible-config | 8 + venv/bin/ansible-connection | 8 + venv/bin/ansible-console | 8 + venv/bin/ansible-doc | 8 + venv/bin/ansible-galaxy | 8 + venv/bin/ansible-inventory | 8 + venv/bin/ansible-playbook | 8 + venv/bin/ansible-pull | 8 + venv/bin/ansible-test | 45 ++++ venv/bin/ansible-vault | 8 + venv/bin/dotenv | 8 + venv/bin/flask | 8 + venv/bin/pip | 8 + venv/bin/pip3 | 8 + venv/bin/pip3.11 | 8 + venv/bin/python | 1 + venv/bin/python3 | 1 + venv/bin/python3.11 | 1 + venv/lib64 | 1 + venv/pyvenv.cfg | 5 + 36 files changed, 958 insertions(+) create mode 100644 ansible/group_vars/vpn_servers/vars.yml create mode 100644 ansible/playbooks/templates/client.conf.j2 create mode 100644 ansible/playbooks/templates/server.conf.j2 create mode 100644 ansible/playbooks/vpn_provision.yml create mode 100644 app/__init__.py create mode 100644 app/handlers/__init__.py create mode 100644 app/handlers/webhook_handler.py create mode 100644 app/utils/__init__.py create mode 100644 app/utils/vault_helper.py create mode 100644 inventory.ini create mode 100644 venv/bin/Activate.ps1 create mode 100644 venv/bin/activate create mode 100644 venv/bin/activate.csh create mode 100644 venv/bin/activate.fish create mode 100755 venv/bin/ansible create mode 100755 venv/bin/ansible-community create mode 100755 venv/bin/ansible-config create mode 100755 venv/bin/ansible-connection create mode 100755 venv/bin/ansible-console create mode 100755 venv/bin/ansible-doc create mode 100755 venv/bin/ansible-galaxy create mode 100755 venv/bin/ansible-inventory create mode 100755 venv/bin/ansible-playbook create mode 100755 venv/bin/ansible-pull create mode 100755 venv/bin/ansible-test create mode 100755 venv/bin/ansible-vault create mode 100755 venv/bin/dotenv create mode 100755 venv/bin/flask create mode 100755 venv/bin/pip create mode 100755 venv/bin/pip3 create mode 100755 venv/bin/pip3.11 create mode 120000 venv/bin/python create mode 120000 venv/bin/python3 create mode 120000 venv/bin/python3.11 create mode 120000 venv/lib64 create mode 100644 venv/pyvenv.cfg diff --git a/ansible/group_vars/vpn_servers/vars.yml b/ansible/group_vars/vpn_servers/vars.yml new file mode 100644 index 0000000..7d10bf2 --- /dev/null +++ b/ansible/group_vars/vpn_servers/vars.yml @@ -0,0 +1,4 @@ +wireguard_interface: wg0 +wireguard_port: 51820 +wireguard_network: 10.0.0.0/24 +server_public_ip: "{{ ansible_host }}" \ No newline at end of file diff --git a/ansible/playbooks/templates/client.conf.j2 b/ansible/playbooks/templates/client.conf.j2 new file mode 100644 index 0000000..ec46067 --- /dev/null +++ b/ansible/playbooks/templates/client.conf.j2 @@ -0,0 +1,10 @@ +[Interface] +PrivateKey = {{ client_private_key.stdout }} +Address = {{ client_ip }}/24 +DNS = 1.1.1.1 + +[Peer] +PublicKey = {{ server_pubkey }} +Endpoint = {{ ansible_host }}:51820 +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 25 \ No newline at end of file diff --git a/ansible/playbooks/templates/server.conf.j2 b/ansible/playbooks/templates/server.conf.j2 new file mode 100644 index 0000000..ba32e23 --- /dev/null +++ b/ansible/playbooks/templates/server.conf.j2 @@ -0,0 +1,10 @@ +[Interface] +Address = {{ server_ip }} +ListenPort = {{ server_port }} +PrivateKey = {{ server_private_key.stdout }} + +# Enable IPv4 forwarding +PostUp = sysctl -w net.ipv4.ip_forward=1 +# NAT configuration (adjust eth0 to your outbound interface if different) +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE diff --git a/ansible/playbooks/vpn_provision.yml b/ansible/playbooks/vpn_provision.yml new file mode 100644 index 0000000..4d210d8 --- /dev/null +++ b/ansible/playbooks/vpn_provision.yml @@ -0,0 +1,118 @@ +--- +- name: Provision WireGuard VPN for new client + hosts: vpn_servers + become: yes + vars: + client_dir: /etc/wireguard/clients + wg_interface: wg0 + server_dir: /etc/wireguard + server_ip: 10.8.0.1/24 + server_port: 51820 + server_endpoint: "{{ ansible_host | default(inventory_hostname) }}" + + tasks: + - name: Debug invoice ID + debug: + msg: "Processing invoice ID: {{ invoice_id }}" + + # Server Setup Tasks + - name: Check if server keys exist + stat: + path: "{{ server_dir }}/{{ wg_interface }}.conf" + register: server_config + + - name: Generate server private key if not exists + shell: wg genkey + register: server_private_key + when: not server_config.stat.exists + + - name: Save server private key + copy: + content: "{{ server_private_key.stdout }}" + dest: "{{ server_dir }}/private.key" + mode: '0600' + when: not server_config.stat.exists + + - name: Generate server public key + shell: "cat {{ server_dir }}/private.key | wg pubkey" + register: server_public_key + when: not server_config.stat.exists + + - name: Save server public key + copy: + content: "{{ server_public_key.stdout }}" + dest: "{{ server_dir }}/public.key" + mode: '0644' + when: not server_config.stat.exists + + - name: Create initial server config + template: + src: templates/server.conf.j2 + dest: "{{ server_dir }}/{{ wg_interface }}.conf" + mode: '0600' + when: not server_config.stat.exists + + # Client Setup Tasks + - name: Ensure client directory exists + file: + path: "{{ client_dir }}/{{ invoice_id }}" + state: directory + mode: '0700' + + - name: Generate client private key + shell: wg genkey + register: client_private_key + no_log: true + + - name: Save client private key + copy: + content: "{{ client_private_key.stdout }}" + dest: "{{ client_dir }}/{{ invoice_id }}/private.key" + mode: '0600' + no_log: true + + - name: Generate client public key + shell: "echo '{{ client_private_key.stdout }}' | wg pubkey" + register: client_public_key + + - name: Save client public key + copy: + content: "{{ client_public_key.stdout }}" + dest: "{{ client_dir }}/{{ invoice_id }}/public.key" + mode: '0644' + + - name: Read server public key + shell: "cat {{ server_dir }}/public.key" + register: server_public_key_read + changed_when: false + + - name: Get next available IP + shell: | + last_ip=$(grep -h '^Address' {{ client_dir }}/*/wg0.conf 2>/dev/null | tail -n1 | grep -oE '[0-9]+$' || echo 1) + echo $((last_ip + 1)) + register: next_ip + + - name: Generate client config + template: + src: templates/client.conf.j2 + dest: "{{ client_dir }}/{{ invoice_id }}/wg0.conf" + mode: '0600' + vars: + client_ip: "10.8.0.{{ next_ip.stdout }}" + server_pubkey: "{{ server_public_key_read.stdout }}" + + - name: Add client to server config + blockinfile: + path: "{{ server_dir }}/{{ wg_interface }}.conf" + marker: "# {mark} ANSIBLE MANAGED BLOCK FOR {{ invoice_id }}" + block: | + [Peer] + PublicKey = {{ client_public_key.stdout }} + AllowedIPs = 10.8.0.{{ next_ip.stdout }}/32 + notify: restart wireguard + + handlers: + - name: restart wireguard + service: + name: wg-quick@{{ wg_interface }} + state: restarted \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/handlers/__init__.py b/app/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/handlers/webhook_handler.py b/app/handlers/webhook_handler.py new file mode 100644 index 0000000..2a684aa --- /dev/null +++ b/app/handlers/webhook_handler.py @@ -0,0 +1,182 @@ +# app/handlers/webhook_handler.py + +import sys +from pathlib import Path +sys.path.append(str(Path(__file__).resolve().parent.parent.parent)) + +from flask import Flask, request, jsonify +import subprocess +import os +import logging +import json +from pathlib import Path +import hmac +import hashlib +import yaml +import traceback +import tempfile +from dotenv import load_dotenv +from app.utils.vault_helper import decrypt_vault_file + +# Load environment variables from .env file +load_dotenv() + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +app = Flask(__name__) + +# Update paths for new structure +BASE_DIR = Path(__file__).resolve().parent.parent.parent +PLAYBOOK_PATH = BASE_DIR / 'ansible' / 'playbooks' / 'vpn_provision.yml' +VAULT_PATH = BASE_DIR / 'ansible' / 'group_vars' / 'vpn_servers' / 'vault.yml' +INVENTORY_PATH = BASE_DIR / 'inventory.ini' + +def get_vault_values(): + """Get decrypted values from Ansible vault""" + try: + # Use vault helper to decrypt contents + vault_contents = decrypt_vault_file(VAULT_PATH) + vault_data = yaml.safe_load(vault_contents) + + # Construct full webhook URL + vault_data['webhook_full_url'] = ( + f"{vault_data['btcpay_base_url']}" + f"{vault_data['btcpay_webhook_path']}" + ) + + return vault_data + + except Exception as e: + logger.error(f"Error reading vault: {str(e)}") + raise + +def verify_signature(payload_body, signature_header): + """Verify BTCPay webhook signature""" + try: + vault_values = get_vault_values() + secret = vault_values['webhook_secret'] + + logger.debug(f"Secret type in verify_signature: {type(secret)}") + + expected_signature = hmac.new( + secret.encode('utf-8'), + payload_body, + hashlib.sha256 + ).hexdigest() + + return hmac.compare_digest( + signature_header.lower(), + f"sha256={expected_signature}".lower() + ) + except Exception as e: + logger.error(f"Signature verification failed: {str(e)}") + return False + +@app.route('/webhook/vpn', methods=['POST']) +def handle_payment(): + try: + # Get vault values first to ensure we can access them + vault_values = get_vault_values() + logger.info(f"Processing webhook on endpoint: {vault_values['webhook_full_url']}") + + # Get the signature from headers + signature = request.headers.get('BTCPay-Sig') + if not signature: + logger.error("Missing BTCPay-Sig header") + return jsonify({"error": "Missing signature"}), 401 + + # Verify signature + is_valid = verify_signature(request.get_data(), signature) + if not is_valid: + logger.error("Invalid signature") + return jsonify({"error": "Invalid signature"}), 401 + + data = request.json + logger.info(f"Received webhook data: {data}") + + invoice_id = data.get('invoiceId') + if not invoice_id: + logger.error("Missing invoiceId in webhook data") + return jsonify({"error": "Missing invoiceId"}), 400 + + # Remove __test__ prefix/suffix for test webhooks + if invoice_id.startswith('__test__') and invoice_id.endswith('__test__'): + invoice_id = invoice_id[8:-8] # Strip the test markers + logger.info(f"Stripped test markers from invoice ID: {invoice_id}") + + # Get vault password from environment + vault_pass = os.getenv('ANSIBLE_VAULT_PASSWORD') + if not vault_pass: + raise Exception("Vault password not found in environment variables") + + # Create temporary vault password file for ansible-playbook + with tempfile.NamedTemporaryFile(mode='w', delete=False) as vault_pass_file: + vault_pass_file.write(vault_pass) + vault_pass_file.flush() + + cmd = [ + 'ansible-playbook', + str(PLAYBOOK_PATH), + '-i', str(INVENTORY_PATH), + '-e', f'invoice_id={invoice_id}', + '--vault-password-file', vault_pass_file.name, + '-vvv' # Add verbose output + ] + + logger.info(f"Running ansible-playbook command: {' '.join(cmd)}") + + result = subprocess.run( + cmd, + capture_output=True, + text=True + ) + + # Clean up the temporary file + os.unlink(vault_pass_file.name) + + # Log the complete output regardless of success/failure + logger.info(f"Ansible playbook stdout: {result.stdout}") + if result.stderr: + logger.error(f"Ansible playbook stderr: {result.stderr}") + + if result.returncode != 0: + error_msg = f"Ansible playbook failed with return code {result.returncode}" + logger.error(error_msg) + return jsonify({ + "error": "Provisioning failed", + "details": error_msg, + "stdout": result.stdout, + "stderr": result.stderr + }), 500 + + logger.info(f"Successfully processed invoice {invoice_id}") + return jsonify({ + "status": "success", + "invoice_id": invoice_id, + "message": "VPN provisioning initiated" + }) + + except Exception as e: + logger.error(f"Error processing webhook: {str(e)}") + return jsonify({ + "error": str(e), + "traceback": traceback.format_exc() + }), 500 + +if __name__ == '__main__': + # Verify we can read the vault and construct URL before starting + try: + vault_values = get_vault_values() + logger.info(f"Successfully loaded vault values") + logger.info(f"Configured webhook URL: {vault_values['webhook_full_url']}") + except Exception as e: + logger.error(f"Failed to load vault values: {str(e)}") + exit(1) + + logger.info(f"Starting webhook handler, watching for playbook at {PLAYBOOK_PATH}") + app.run(host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/vault_helper.py b/app/utils/vault_helper.py new file mode 100644 index 0000000..31b8863 --- /dev/null +++ b/app/utils/vault_helper.py @@ -0,0 +1,39 @@ +"""Helper functions for Ansible vault operations.""" +import os +import tempfile +import subprocess +from pathlib import Path + +def decrypt_vault_file(vault_file_path): + """ + Decrypt an Ansible vault file using the password from environment variables. + + Args: + vault_file_path (str): Path to the encrypted vault file + + Returns: + str: Decrypted contents of the vault file + """ + vault_pass = os.getenv('ANSIBLE_VAULT_PASSWORD') + if not vault_pass: + raise ValueError("ANSIBLE_VAULT_PASSWORD environment variable not set") + + with tempfile.NamedTemporaryFile(mode='w', delete=False) as vault_pass_file: + vault_pass_file.write(vault_pass) + vault_pass_file.flush() + + try: + result = subprocess.run( + ['ansible-vault', 'view', str(vault_file_path)], + capture_output=True, + text=True, + env={**os.environ, 'ANSIBLE_VAULT_PASSWORD_FILE': vault_pass_file.name} + ) + + if result.returncode != 0: + raise Exception(f"Failed to decrypt vault: {result.stderr}") + + return result.stdout + + finally: + os.unlink(vault_pass_file.name) \ No newline at end of file diff --git a/inventory.ini b/inventory.ini new file mode 100644 index 0000000..63c90f6 --- /dev/null +++ b/inventory.ini @@ -0,0 +1,2 @@ +[vpn_servers] +localhost ansible_connection=local \ No newline at end of file diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..7a252fc --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,69 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/hashgate/vpn-btcpay-provisioner/venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(venv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv) " + export VIRTUAL_ENV_PROMPT +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..e05c653 --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,26 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/hashgate/vpn-btcpay-provisioner/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(venv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..994aeb3 --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/); you cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/hashgate/vpn-btcpay-provisioner/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(venv) " +end diff --git a/venv/bin/ansible b/venv/bin/ansible new file mode 100755 index 0000000..40ba212 --- /dev/null +++ b/venv/bin/ansible @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.adhoc import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-community b/venv/bin/ansible-community new file mode 100755 index 0000000..d3fe164 --- /dev/null +++ b/venv/bin/ansible-community @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible_collections.ansible_community import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-config b/venv/bin/ansible-config new file mode 100755 index 0000000..67945b0 --- /dev/null +++ b/venv/bin/ansible-config @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.config import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-connection b/venv/bin/ansible-connection new file mode 100755 index 0000000..d9dba93 --- /dev/null +++ b/venv/bin/ansible-connection @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.scripts.ansible_connection_cli_stub import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-console b/venv/bin/ansible-console new file mode 100755 index 0000000..887852a --- /dev/null +++ b/venv/bin/ansible-console @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.console import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-doc b/venv/bin/ansible-doc new file mode 100755 index 0000000..7e41e15 --- /dev/null +++ b/venv/bin/ansible-doc @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.doc import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-galaxy b/venv/bin/ansible-galaxy new file mode 100755 index 0000000..d763eb7 --- /dev/null +++ b/venv/bin/ansible-galaxy @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.galaxy import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-inventory b/venv/bin/ansible-inventory new file mode 100755 index 0000000..055581c --- /dev/null +++ b/venv/bin/ansible-inventory @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.inventory import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-playbook b/venv/bin/ansible-playbook new file mode 100755 index 0000000..76ddab0 --- /dev/null +++ b/venv/bin/ansible-playbook @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.playbook import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-pull b/venv/bin/ansible-pull new file mode 100755 index 0000000..d44982a --- /dev/null +++ b/venv/bin/ansible-pull @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.pull import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/ansible-test b/venv/bin/ansible-test new file mode 100755 index 0000000..9e61d61 --- /dev/null +++ b/venv/bin/ansible-test @@ -0,0 +1,45 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# PYTHON_ARGCOMPLETE_OK +"""Command line entry point for ansible-test.""" + +# NOTE: This file resides in the _util/target directory to ensure compatibility with all supported Python versions. + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import sys + + +def main(args=None): + """Main program entry point.""" + ansible_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + source_root = os.path.join(ansible_root, 'test', 'lib') + + if os.path.exists(os.path.join(source_root, 'ansible_test', '_internal', '__init__.py')): + # running from source, use that version of ansible-test instead of any version that may already be installed + sys.path.insert(0, source_root) + + # noinspection PyProtectedMember + from ansible_test._util.target.common.constants import CONTROLLER_PYTHON_VERSIONS + + if version_to_str(sys.version_info[:2]) not in CONTROLLER_PYTHON_VERSIONS: + raise SystemExit('This version of ansible-test cannot be executed with Python version %s. Supported Python versions are: %s' % ( + version_to_str(sys.version_info[:3]), ', '.join(CONTROLLER_PYTHON_VERSIONS))) + + if any(not os.get_blocking(handle.fileno()) for handle in (sys.stdin, sys.stdout, sys.stderr)): + raise SystemExit('Standard input, output and error file handles must be blocking to run ansible-test.') + + # noinspection PyProtectedMember + from ansible_test._internal import main as cli_main + + cli_main(args) + + +def version_to_str(version): + """Return a version string from a version tuple.""" + return '.'.join(str(n) for n in version) + + +if __name__ == '__main__': + main() diff --git a/venv/bin/ansible-vault b/venv/bin/ansible-vault new file mode 100755 index 0000000..98dea51 --- /dev/null +++ b/venv/bin/ansible-vault @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from ansible.cli.vault import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/dotenv b/venv/bin/dotenv new file mode 100755 index 0000000..95a5410 --- /dev/null +++ b/venv/bin/dotenv @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from dotenv.__main__ import cli +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli()) diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 0000000..40362fe --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 0000000..3524dcc --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 0000000..3524dcc --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.11 b/venv/bin/pip3.11 new file mode 100755 index 0000000..3524dcc --- /dev/null +++ b/venv/bin/pip3.11 @@ -0,0 +1,8 @@ +#!/home/hashgate/vpn-btcpay-provisioner/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 0000000..ae65fda --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/venv/bin/python3.11 b/venv/bin/python3.11 new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/venv/bin/python3.11 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/lib64 b/venv/lib64 new file mode 120000 index 0000000..7951405 --- /dev/null +++ b/venv/lib64 @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg new file mode 100644 index 0000000..aee7bbd --- /dev/null +++ b/venv/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.11.2 +executable = /usr/bin/python3.11 +command = /usr/bin/python3 -m venv /home/hashgate/vpn-btcpay-provisioner/venv