diff --git a/CSS436/Week2.md b/CSS436/Week2.md new file mode 100644 index 0000000..b7764a5 --- /dev/null +++ b/CSS436/Week2.md @@ -0,0 +1,2 @@ +# chapter 3 +Locard's principle of transferrence diff --git a/Crowdstrike/ExportReportsScript b/Crowdstrike/ExportReportsScript new file mode 100644 index 0000000..e69de29 diff --git a/Crowdstrike/ExposureReports.py b/Crowdstrike/ExposureReports.py new file mode 100644 index 0000000..238f1ce --- /dev/null +++ b/Crowdstrike/ExposureReports.py @@ -0,0 +1,70 @@ +import requests +import json +import csv +from datetime import datetime, timedelta + +# Replace with your CrowdStrike API credentials +CLIENT_ID = 'YOUR_CLIENT_ID' +CLIENT_SECRET = 'YOUR_CLIENT_SECRET' + +# Base URL for the CrowdStrike Falcon API +BASE_URL = 'https://api.crowdstrike.com' + +# Function to obtain an OAuth2 access token +def get_access_token(): + url = f"{BASE_URL}/oauth2/token" + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + data = { + 'client_id': CLIENT_ID, + 'client_secret': CLIENT_SECRET, + 'grant_type': 'client_credentials' + } + response = requests.post(url, headers=headers, data=data) + response.raise_for_status() + return response.json()['access_token'] + +# Function to fetch exposure management reports (V2 API) +def get_exposure_management_reports(access_token): + url = f"{BASE_URL}/spotlight/queries/reports/v2" + headers = { + 'Authorization': f'Bearer {access_token}', + 'Accept': 'application/json' + } + + # Calculate the timestamp for 24 hours ago + now = datetime.utcnow() + twenty_four_hours_ago = now - timedelta(hours=24) + timestamp_filter = twenty_four_hours_ago.strftime('%Y-%m-%dT%H:%M:%SZ') + + # Filter for reports generated in the last 24 hours + params = { + 'filter': f'created_on:>{timestamp_filter}' + } + + response = requests.get(url, headers=headers, params=params) + response.raise_for_status() + return response.json()['resources'] + +# Function to export a report as CSV (V2 API) +def export_report_to_csv(report_id, access_token): + url = f"{BASE_URL}/spotlight/entities/reports-executions/v1/{report_id}/download" + headers = {'Authorization': f'Bearer {access_token}'} + + response = requests.get(url, headers=headers) + response.raise_for_status() + + # Assuming the report content is in CSV format + with open(f'{report_id}.csv', 'wb') as f: + f.write(response.content) + +# Main script execution +if __name__ == '__main__': + access_token = get_access_token() + reports = get_exposure_management_reports(access_token) + + if reports: + most_recent_report_id = reports[0]['id'] + export_report_to_csv(most_recent_report_id, access_token) + print(f"Exported report {most_recent_report_id} to CSV") + else: + print("No exposure management reports found in the last 24 hours") \ No newline at end of file diff --git a/DavidsDevelopment b/DavidsDevelopment new file mode 160000 index 0000000..db7cc92 --- /dev/null +++ b/DavidsDevelopment @@ -0,0 +1 @@ +Subproject commit db7cc92e66436f01da6fcfb7cf619cc2b270ec5a diff --git a/Docker/Outline/docker-compose.yaml b/Docker/Outline/docker-compose.yaml new file mode 100644 index 0000000..1fca910 --- /dev/null +++ b/Docker/Outline/docker-compose.yaml @@ -0,0 +1,71 @@ +version: "3.2" +services: + + outline: + image: docker.getoutline.com/outlinewiki/outline:latest + env_file: ./docker.env + ports: + - "3000:3000" + volumes: + - storage-data:/var/lib/outline/data + depends_on: + - postgres + - redis + + redis: + image: redis + env_file: ./docker.env + ports: + - "6379:6379" + volumes: + - ./redis.conf:/redis.conf + command: ["redis-server", "/redis.conf"] + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 30s + retries: 3 + + postgres: + image: postgres + env_file: ./docker.env + ports: + - "5432:5432" + volumes: + - database-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-d", "outline", "-U", "user"] + interval: 30s + timeout: 20s + retries: 3 + environment: + POSTGRES_USER: 'user' + POSTGRES_PASSWORD: 'pass' + POSTGRES_DB: 'outline' + + https-portal: + image: steveltn/https-portal + env_file: ./docker.env + ports: + - '80:80' + - '443:443' + links: + - outline + restart: always + volumes: + - https-portal-data:/var/lib/https-portal + healthcheck: + test: ["CMD", "service", "nginx", "status"] + interval: 30s + timeout: 20s + retries: 3 + environment: + DOMAINS: 'docs.mycompany.com -> http://outline:3000' + STAGE: 'production' + WEBSOCKET: 'true' + CLIENT_MAX_BODY_SIZE: '0' + +volumes: + https-portal-data: + storage-data: + database-data: \ No newline at end of file diff --git a/Docker/torrents/cyberghost/.~lock.client.key# b/Docker/torrents/cyberghost/.~lock.client.key# new file mode 100644 index 0000000..7865565 --- /dev/null +++ b/Docker/torrents/cyberghost/.~lock.client.key# @@ -0,0 +1 @@ +,david,pop-os,16.06.2023 16:27,file:///home/david/.config/libreoffice/4; \ No newline at end of file diff --git a/Docker/torrents/cyberghost/ca.crt b/Docker/torrents/cyberghost/ca.crt new file mode 100644 index 0000000..1d150e3 --- /dev/null +++ b/Docker/torrents/cyberghost/ca.crt @@ -0,0 +1,36 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/Docker/torrents/cyberghost/client.crt b/Docker/torrents/cyberghost/client.crt new file mode 100644 index 0000000..a79b4a5 --- /dev/null +++ b/Docker/torrents/cyberghost/client.crt @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIGojCCBIqgAwIBAgIEAmKu/zANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJS +TzESMBAGA1UEBxMJQnVjaGFyZXN0MRgwFgYDVQQKEw9DeWJlckdob3N0IFMuQS4x +GzAZBgNVBAMTEkN5YmVyR2hvc3QgUm9vdCBDQTEhMB8GCSqGSIb3DQEJARYSaW5m +b0BjeWJlcmdob3N0LnJvMB4XDTIzMDIxNzE1MTE0OFoXDTMzMDIxNDE1MTE0OFow +czELMAkGA1UEBhMCUk8xEjAQBgNVBAcMCUJ1Y2hhcmVzdDEYMBYGA1UECgwPQ3li +ZXJHaG9zdCBTLkEuMRMwEQYDVQQDDApYUEVqeGlmWDcyMSEwHwYJKoZIhvcNAQkB +FhJpbmZvQGN5YmVyZ2hvc3Qucm8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQC7tEeEtyGY/c6Xvev31b0pB5NxpZ33d+nw6hAV6UtZnbOnsaBMDSkXzppL +VaMWBayoBTmR0cwhkNayn3+BHjQzPxTBIxResxWVqf/Dm/5o4QTT5YqJ1OE/U8GY +dy4HY8TGdHXjwdt3QkPVGBQUkC2dlsKLMth8eWk7eXOcEC5cLWv37t3Df7WYAzyo +l1tPbzM1z2cL6GQrp6kuBqr78LuQ1QP9OyBoN14mpHKnzkADcw+gmvVrfpFTX/Yi +39lgoSZZZU/74GTHpc89o71B9pPkj19XgCIEimsdBuBrXYhfoCnrNh9ChsNPRd/8 +Ba+rqEsTP/kXbxgWh24fO6fL86ZU6VslSHCHIZfoJhX5CLzthnIeMmPNMwJsPGVy +NN6SPxPPm8tKYAQjzpSbEXmiecO9VYVclU3KQTqjoGUNvUByCUae7wLF3PXIzLVQ +x4Z2hNpmCmT916TcWGPJDKXMjkNQfBF1o7RnYaIFf5Ne4trwgQo/stHNYAz0y0/U +A1gyYUs192vYnUTfIYhN5x8mfUWOFaK7RqT2RIidSlaFMhZ8tH3hASqqdo/b2e03 +D8N1PM38Wq4R12Vfq3SlTqQobEWb/1qXusBZhaOFCttck5LauaWP+kIdvI5hKFiP +VEa7zF1UJuyUjm/ZmN4uYPTrPuvAfkupZybAwuGB1L5pDuRyiQIDAQABo4IBNDCC +ATAwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwNAYJYIZIAYb4QgENBCcWJUN5YmVy +R2hvc3QgR2VuZXJhdGVkIFVzZXIgQ2VydGlmaWNhdGUwEQYJYIZIAYb4QgEBBAQD +AgeAMB0GA1UdDgQWBBQy2dvEDGXhLUYzaV8/VPwiB9+J+jCBrQYDVR0jBIGlMIGi +gBTq10rWD8d7mrON4Cgzl4e3iKf2JaF/pH0wezELMAkGA1UEBhMCUk8xEjAQBgNV +BAcTCUJ1Y2hhcmVzdDEYMBYGA1UEChMPQ3liZXJHaG9zdCBTLkEuMRswGQYDVQQD +ExJDeWJlckdob3N0IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEmluZm9AY3liZXJn +aG9zdC5yb4IJAJxUG61mxDS7MA0GCSqGSIb3DQEBCwUAA4ICAQDVmu2F3OxvBbTA +yf3Wop9H7KaHtHu8dgEr5q3tL6neH2JuqYYnWMi3eMb/5kviFkJ98GQI/cDls/ae +NTuvxZ5Bz9lMQjmPvniqk8YgdIbyxkSa4Qfols08go7ZoAIHsNgPvradJoj/1hOg +1OCl+tlXanPPEDIsNL8S9MnSWUkWfIksq7+jjVXKZzGzrox3OsOSo2kLyoJwPvuH +SwsjGV8KDByhbBUTRNH6MnXY7PPBLdpsTtBmHCJvhNnC/j9xWTCutxifonZhCI2J +z4i1GcAuV4nNyBrj5h7uNjgQGKnP1wvxysRtrO3UNJqcJkJqZqOKKi9Sqmjh/NDv +2o7pwgfvsf+vAXCwVBmv/ea39jKltY7s6ZY3d8JHgfAzU2R8Q0JN+aQRh0L9jcu/ +JC3jB6iYV+lgLfg6ZuBuneTV69yba4G9TRcdEdGpe0SNcj3gWEvDFnmKe3i8c8Px +RUHknJr6+9ielIZl7TeB3zRNWMBWxGfUmGdUx5/SVIfc8kOOWBBHWi3ice6uxa6C +/hQh15dy/Dmro3iF2HF3hxNV8C9VQcceZcS7wOF//mqK6721bjk5/fxNhtBh1CB9 +9nxq719le9XCd0zFRPYMTtnVd6ELqHhOdI7Fw90dFeAOIbBDZ5D3AjbjASUaILR0 +X+/aNMPxoNGpbkCY3G/lb0NzmV0FLQ== +-----END CERTIFICATE----- diff --git a/Docker/torrents/cyberghost/client.key b/Docker/torrents/cyberghost/client.key new file mode 100644 index 0000000..8df6504 --- /dev/null +++ b/Docker/torrents/cyberghost/client.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +T1HH2ae+okFYaHnNKrA9DGZNOgzYGQ== +-----END PRIVATE KEY----- diff --git a/Docker/torrents/cyberghost/docker-compose.yml b/Docker/torrents/cyberghost/docker-compose.yml new file mode 100644 index 0000000..631029a --- /dev/null +++ b/Docker/torrents/cyberghost/docker-compose.yml @@ -0,0 +1,16 @@ +#https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/cyberghost.md +version: "3" +services: + gluetun: + image: qmcgaw/gluetun + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + environment: + - VPN_SERVICE_PROVIDER=cyberghost + - OPENVPN_USER=pvDXWWNiJm + - OPENVPN_PASSWORD=WvCrDvzh8r + - SERVER_COUNTRIES=Netherlands + volumes: + - /mnt/storagepool/media/software/gluetun:/gluetun \ No newline at end of file diff --git a/Docker/torrents/cyberghost/openvpn.ovpn b/Docker/torrents/cyberghost/openvpn.ovpn new file mode 100644 index 0000000..1ee23fa --- /dev/null +++ b/Docker/torrents/cyberghost/openvpn.ovpn @@ -0,0 +1,161 @@ +client +remote 87-1-ca.cg-dialup.net 443 +dev tun +proto udp +auth-user-pass + + +resolv-retry infinite +redirect-gateway def1 +persist-key +persist-tun +nobind +cipher AES-256-CBC +ncp-disable +auth SHA256 +ping 5 +ping-exit 60 +ping-timer-rem +explicit-exit-notify 2 +script-security 2 +remote-cert-tls server +route-delay 5 +verb 4 + +pull-filter ignore "ifconfig-ipv6" +pull-filter ignore "route-ipv6" + + +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + + + +-----BEGIN CERTIFICATE----- +MIIGojCCBIqgAwIBAgIEAmKu/zANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJS +TzESMBAGA1UEBxMJQnVjaGFyZXN0MRgwFgYDVQQKEw9DeWJlckdob3N0IFMuQS4x +GzAZBgNVBAMTEkN5YmVyR2hvc3QgUm9vdCBDQTEhMB8GCSqGSIb3DQEJARYSaW5m +b0BjeWJlcmdob3N0LnJvMB4XDTIzMDIxNzE1MTE0OFoXDTMzMDIxNDE1MTE0OFow +czELMAkGA1UEBhMCUk8xEjAQBgNVBAcMCUJ1Y2hhcmVzdDEYMBYGA1UECgwPQ3li +ZXJHaG9zdCBTLkEuMRMwEQYDVQQDDApYUEVqeGlmWDcyMSEwHwYJKoZIhvcNAQkB +FhJpbmZvQGN5YmVyZ2hvc3Qucm8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQC7tEeEtyGY/c6Xvev31b0pB5NxpZ33d+nw6hAV6UtZnbOnsaBMDSkXzppL +VaMWBayoBTmR0cwhkNayn3+BHjQzPxTBIxResxWVqf/Dm/5o4QTT5YqJ1OE/U8GY +dy4HY8TGdHXjwdt3QkPVGBQUkC2dlsKLMth8eWk7eXOcEC5cLWv37t3Df7WYAzyo +l1tPbzM1z2cL6GQrp6kuBqr78LuQ1QP9OyBoN14mpHKnzkADcw+gmvVrfpFTX/Yi +39lgoSZZZU/74GTHpc89o71B9pPkj19XgCIEimsdBuBrXYhfoCnrNh9ChsNPRd/8 +Ba+rqEsTP/kXbxgWh24fO6fL86ZU6VslSHCHIZfoJhX5CLzthnIeMmPNMwJsPGVy +NN6SPxPPm8tKYAQjzpSbEXmiecO9VYVclU3KQTqjoGUNvUByCUae7wLF3PXIzLVQ +x4Z2hNpmCmT916TcWGPJDKXMjkNQfBF1o7RnYaIFf5Ne4trwgQo/stHNYAz0y0/U +A1gyYUs192vYnUTfIYhN5x8mfUWOFaK7RqT2RIidSlaFMhZ8tH3hASqqdo/b2e03 +D8N1PM38Wq4R12Vfq3SlTqQobEWb/1qXusBZhaOFCttck5LauaWP+kIdvI5hKFiP +VEa7zF1UJuyUjm/ZmN4uYPTrPuvAfkupZybAwuGB1L5pDuRyiQIDAQABo4IBNDCC +ATAwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwNAYJYIZIAYb4QgENBCcWJUN5YmVy +R2hvc3QgR2VuZXJhdGVkIFVzZXIgQ2VydGlmaWNhdGUwEQYJYIZIAYb4QgEBBAQD +AgeAMB0GA1UdDgQWBBQy2dvEDGXhLUYzaV8/VPwiB9+J+jCBrQYDVR0jBIGlMIGi +gBTq10rWD8d7mrON4Cgzl4e3iKf2JaF/pH0wezELMAkGA1UEBhMCUk8xEjAQBgNV +BAcTCUJ1Y2hhcmVzdDEYMBYGA1UEChMPQ3liZXJHaG9zdCBTLkEuMRswGQYDVQQD +ExJDeWJlckdob3N0IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEmluZm9AY3liZXJn +aG9zdC5yb4IJAJxUG61mxDS7MA0GCSqGSIb3DQEBCwUAA4ICAQDVmu2F3OxvBbTA +yf3Wop9H7KaHtHu8dgEr5q3tL6neH2JuqYYnWMi3eMb/5kviFkJ98GQI/cDls/ae +NTuvxZ5Bz9lMQjmPvniqk8YgdIbyxkSa4Qfols08go7ZoAIHsNgPvradJoj/1hOg +1OCl+tlXanPPEDIsNL8S9MnSWUkWfIksq7+jjVXKZzGzrox3OsOSo2kLyoJwPvuH +SwsjGV8KDByhbBUTRNH6MnXY7PPBLdpsTtBmHCJvhNnC/j9xWTCutxifonZhCI2J +z4i1GcAuV4nNyBrj5h7uNjgQGKnP1wvxysRtrO3UNJqcJkJqZqOKKi9Sqmjh/NDv +2o7pwgfvsf+vAXCwVBmv/ea39jKltY7s6ZY3d8JHgfAzU2R8Q0JN+aQRh0L9jcu/ +JC3jB6iYV+lgLfg6ZuBuneTV69yba4G9TRcdEdGpe0SNcj3gWEvDFnmKe3i8c8Px +RUHknJr6+9ielIZl7TeB3zRNWMBWxGfUmGdUx5/SVIfc8kOOWBBHWi3ice6uxa6C +/hQh15dy/Dmro3iF2HF3hxNV8C9VQcceZcS7wOF//mqK6721bjk5/fxNhtBh1CB9 +9nxq719le9XCd0zFRPYMTtnVd6ELqHhOdI7Fw90dFeAOIbBDZ5D3AjbjASUaILR0 +X+/aNMPxoNGpbkCY3G/lb0NzmV0FLQ== +-----END CERTIFICATE----- + + + +-----BEGIN PRIVATE KEY----- +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 +T1HH2ae+okFYaHnNKrA9DGZNOgzYGQ== +-----END PRIVATE KEY----- + diff --git a/Docker/torrents/deluge/docker-compose.yml b/Docker/torrents/deluge/docker-compose.yml new file mode 100644 index 0000000..6ffab39 --- /dev/null +++ b/Docker/torrents/deluge/docker-compose.yml @@ -0,0 +1,12 @@ +deluge: + container_name: deluge + image: linuxserver/deluge:latest + restart: unless-stopped + network_mode: service:gluetun # run on the vpn network + environment: + - PUID=1000 # default user id, defined in .env + - PGID=1000 # default group id, defined in .env + - America/New_York # timezone, defined in .env + volumes: + - /mnt/storagepool/media/downloads:/downloads # downloads folder + - /mnt/storagepool/media/software/deluge:/config # config files \ No newline at end of file diff --git a/Docker/torrents/glueton both 2 deluge.yml b/Docker/torrents/glueton both 2 deluge.yml new file mode 100644 index 0000000..e69de29 diff --git a/Docker/torrents/gluetun both b/Docker/torrents/gluetun both new file mode 100644 index 0000000..91fc3e3 --- /dev/null +++ b/Docker/torrents/gluetun both @@ -0,0 +1,42 @@ +version: "3" +services: + gluetun: + container_name: gluetun + image: qmcgaw/gluetun + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + environment: + - VPN_SERVICE_PROVIDER=cyberghost + - OPENVPN_USER=pvDXWWNiJm # Replace with your actual username + - OPENVPN_PASSWORD=WvCrDvzh8r # Replace with your actual password + - SERVER_COUNTRIES=Netherlands + - PUID=1000 + - PGID=999 + volumes: + - /mnt/storagepool/media/software/gluetun:/gluetun + ports: + - 8112:8112 + restart: always + healthcheck: + test: ["CMD", "curl", "-s", "--fail", "https://www.google.com"] + interval: 30s + timeout: 10s + retries: 5 + + deluge: + container_name: deluge + image: linuxserver/deluge:latest + restart: unless-stopped + network_mode: service:gluetun + environment: + - PUID=1000 + - PGID=999 + - TZ=America/New_York + volumes: + - /mnt/storagepool/media/downloads:/downloads + - /mnt/storagepool/media/software/deluge:/config + depends_on: + gluetun: + condition: service_healthy \ No newline at end of file diff --git a/Docker/whispersetup/docker-compose.yml b/Docker/whispersetup/docker-compose.yml new file mode 100644 index 0000000..4ddcf85 --- /dev/null +++ b/Docker/whispersetup/docker-compose.yml @@ -0,0 +1,10 @@ +version: "2.1" +services: + whisperasr: + image: onerahmet/openai-whisper-asr-webservice:latest + environment: + - ASR_MODEL=small + - ASR_ENGINE=faster_whisper + ports: + - 9000:9000 + restart: unless-stopped \ No newline at end of file diff --git a/MarkdownConversion/ConverttoDOCX.py b/MarkdownConversion/ConverttoDOCX.py new file mode 100644 index 0000000..8058be7 --- /dev/null +++ b/MarkdownConversion/ConverttoDOCX.py @@ -0,0 +1,48 @@ +import os +from markdown import markdown +from docx import Document + +def convert_md_to_docx(md_file_path, docx_file_path): + """Converts a Markdown file to a Word document.""" + with open(md_file_path, 'r', encoding='utf-8') as md_file: + md_content = md_file.read() + + # Convert Markdown to HTML + html_content = markdown(md_content) + + # Create a Word document and add the HTML content + doc = Document() + doc.add_paragraph(html_content) + doc.save(docx_file_path) + print(f"Converted: {md_file_path} -> {docx_file_path}") + +def convert_all_md_to_docx(root_directory, output_directory): + """Traverse the directory tree and convert all .md files to .docx, storing them in a mirrored structure.""" + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + if filename.endswith('.md'): + md_file_path = os.path.join(dirpath, filename) + + # Create mirrored directory structure in the output directory + relative_path = os.path.relpath(dirpath, root_directory) + target_dir = os.path.join(output_directory, relative_path) + os.makedirs(target_dir, exist_ok=True) + + # Define the output .docx file path + docx_file_path = os.path.join(target_dir, os.path.splitext(filename)[0] + '.docx') + + try: + convert_md_to_docx(md_file_path, docx_file_path) + except Exception as e: + print(f"Failed to convert {md_file_path}: {e}") + +if __name__ == "__main__": + # Prompt user for the root directory and output directory + root_dir = input("Enter the root directory to scan for Markdown files: ").strip() + output_dir = input("Enter the output directory to store converted files: ").strip() + + if os.path.exists(root_dir): + os.makedirs(output_dir, exist_ok=True) # Ensure output directory exists + convert_all_md_to_docx(root_dir, output_dir) + else: + print("The specified root directory does not exist.") \ No newline at end of file diff --git a/MarkdownConversion/ConverttoDOCX.txt b/MarkdownConversion/ConverttoDOCX.txt new file mode 100644 index 0000000..8058be7 --- /dev/null +++ b/MarkdownConversion/ConverttoDOCX.txt @@ -0,0 +1,48 @@ +import os +from markdown import markdown +from docx import Document + +def convert_md_to_docx(md_file_path, docx_file_path): + """Converts a Markdown file to a Word document.""" + with open(md_file_path, 'r', encoding='utf-8') as md_file: + md_content = md_file.read() + + # Convert Markdown to HTML + html_content = markdown(md_content) + + # Create a Word document and add the HTML content + doc = Document() + doc.add_paragraph(html_content) + doc.save(docx_file_path) + print(f"Converted: {md_file_path} -> {docx_file_path}") + +def convert_all_md_to_docx(root_directory, output_directory): + """Traverse the directory tree and convert all .md files to .docx, storing them in a mirrored structure.""" + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + if filename.endswith('.md'): + md_file_path = os.path.join(dirpath, filename) + + # Create mirrored directory structure in the output directory + relative_path = os.path.relpath(dirpath, root_directory) + target_dir = os.path.join(output_directory, relative_path) + os.makedirs(target_dir, exist_ok=True) + + # Define the output .docx file path + docx_file_path = os.path.join(target_dir, os.path.splitext(filename)[0] + '.docx') + + try: + convert_md_to_docx(md_file_path, docx_file_path) + except Exception as e: + print(f"Failed to convert {md_file_path}: {e}") + +if __name__ == "__main__": + # Prompt user for the root directory and output directory + root_dir = input("Enter the root directory to scan for Markdown files: ").strip() + output_dir = input("Enter the output directory to store converted files: ").strip() + + if os.path.exists(root_dir): + os.makedirs(output_dir, exist_ok=True) # Ensure output directory exists + convert_all_md_to_docx(root_dir, output_dir) + else: + print("The specified root directory does not exist.") \ No newline at end of file diff --git a/NIST Reports/nvd.py b/NIST Reports/nvd.py new file mode 100644 index 0000000..54109db --- /dev/null +++ b/NIST Reports/nvd.py @@ -0,0 +1,92 @@ +import os +import requests +import pandas as pd +from datetime import datetime, timedelta + +def get_latest_cves(days=3): + try: + end_date = datetime.now() + start_date = end_date - timedelta(days=days) + start_date_str = start_date.strftime("%Y-%m-%dT%H:%M:%S") + end_date_str = end_date.strftime("%Y-%m-%dT%H:%M:%S") + nvd_url = f"https://services.nvd.nist.gov/rest/json/cves/1.0?pubStartDate={start_date_str}&pubEndDate={end_date_str}" + response = requests.get(nvd_url) + if response.status_code == 200: + return response.json() + else: + print(f"Error: Unable to fetch CVE data. Status code: {response.status_code}") + print("Response content:", response.content) + return None + except requests.exceptions.RequestException as e: + print(f"Error: Unable to fetch CVE data. {e}") + return None + +def extract_cvss_data(cve_entry): + cvss_data = cve_entry.get("impact", {}).get("baseMetricV2", {}).get("cvssV2", {}) + if cvss_data: + return { + "CVSS Version": "2.0", + "Vector String": cvss_data.get("vectorString", ""), + "Base Score": cvss_data.get("baseScore", ""), + "Base Severity": cvss_data.get("severity", ""), + "Access Vector": cvss_data.get("accessVector", ""), + "Access Complexity": cvss_data.get("accessComplexity", ""), + "Authentication": cvss_data.get("authentication", ""), + "Confidentiality Impact": cvss_data.get("confidentialityImpact", ""), + "Integrity Impact": cvss_data.get("integrityImpact", ""), + "Availability Impact": cvss_data.get("availabilityImpact", ""), + "Exploitability Score": cve_entry.get("exploitabilityScore", ""), + "Impact Score": cve_entry.get("impactScore", "") + } + else: + return { + "CVSS Version": "", + "Vector String": "", + "Base Score": "", + "Base Severity": "", + "Access Vector": "", + "Access Complexity": "", + "Authentication": "", + "Confidentiality Impact": "", + "Integrity Impact": "", + "Availability Impact": "", + "Exploitability Score": "", + "Impact Score": "" + } + +def generate_excel_report(cves, excel_filename): + try: + data = [] + for vulnerability_entry in cves.get("result", {}).get("CVE_Items", []): + cve_entry = vulnerability_entry.get("cve", {}) + cve_id = cve_entry.get("CVE_data_meta", {}).get("ID", "") + descriptions = cve_entry.get("description", {}).get("description_data", []) + english_descriptions = [desc.get("value", "") for desc in descriptions if desc.get("lang") == "en"] + description = " ".join(english_descriptions) + references = cve_entry.get("references", {}).get("reference_data", []) + reference_urls = [ref.get("url", "") for ref in references] + reference_sources = [ref.get("name", "") for ref in references] + reference_url = reference_urls[0] if reference_urls else "" + reference_source = reference_sources[0] if reference_sources else "" + cvss_data = extract_cvss_data(vulnerability_entry) + data.append({ + "CVE ID": cve_id, + "Description": description, + "Reference URL": reference_url, + "Reference Source": reference_source, + **cvss_data + }) + df = pd.DataFrame(data) + df.to_excel(excel_filename, index=False) + print(f"Excel report generated successfully: {excel_filename}") + except Exception as e: + print(f"Error: Unable to generate Excel report. {e}") + +if __name__ == "__main__": + latest_cves = get_latest_cves() + if latest_cves: + excel_timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + excel_filename = f"latest_cves_{excel_timestamp}.xlsx" + generate_excel_report(latest_cves, excel_filename) + else: + print("No CVEs found.") diff --git a/NIST Reports/nvd_2025.py b/NIST Reports/nvd_2025.py new file mode 100644 index 0000000..301f656 --- /dev/null +++ b/NIST Reports/nvd_2025.py @@ -0,0 +1,121 @@ +import requests +import json +import csv +import datetime +import os +import time + +def get_nist_vulnerabilities(days=3, limit=5000): # Added limit parameter + """Retrieves the latest vulnerabilities from the NIST NVD API v2.0 with a limit.""" + + end_date = datetime.date.today() + start_date = end_date - datetime.timedelta(days=days) + + all_vulnerabilities = [] + startIndex = 0 + resultsPerPage = 2000 + + while True: + url = f"https://services.nvd.nist.gov/rest/json/cves/2.0?startIndex={startIndex}&resultsPerPage={resultsPerPage}" + + try: + response = requests.get(url) + response.raise_for_status() + data = response.json() + vulnerabilities = data.get("vulnerabilities", []) + + if not vulnerabilities: + break + + all_vulnerabilities.extend(vulnerabilities) + startIndex += resultsPerPage + time.sleep(0.5) # Reduced sleep time slightly + + if len(all_vulnerabilities) >= limit: #Enforce limit + print(f"Reached CVE limit of {limit}. Stopping retrieval.") + break + + except requests.exceptions.RequestException as e: + print(f"Error fetching data from NIST API: {e}") + return [] + except json.JSONDecodeError as e: + print(f"Error decoding JSON response: {e}") + return [] + + filtered_vulnerabilities = [ + cve for cve in all_vulnerabilities + if datetime.datetime.fromisoformat(cve.get('cve', {}).get('published', '').replace('Z', '+00:00')).date() >= start_date + ] + return filtered_vulnerabilities + + + +def write_to_csv(vulnerabilities, filename): + # ... (This function is exactly the same as in my previous responses) + if not vulnerabilities: + print("No vulnerabilities found for the specified period.") + return + + fieldnames = ["Product", "Vendor", "CVE ID", "Date Added", "Date Updated", "Description", "Severity"] + + try: + with open(filename, 'w', newline='', encoding='utf-8') as csvfile: + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + for cve in vulnerabilities: + cve_data = cve.get('cve', {}) + + products = [] + vendors = [] + + if 'cpeMatch' in cve_data.get('configurations', {}): + for match in cve_data['configurations']['cpeMatch']: + cpe_string = match.get('cpe23Uri', '') + parts = cpe_string.split(':') + if len(parts) >= 5: + vendors.append(parts[3]) + products.append(parts[4]) + else: + vendors.append("N/A") + products.append("N/A") + + product_str = ", ".join(products) + vendor_str = ", ".join(vendors) + + description = cve_data.get('descriptions', [{}])[0].get('value', 'N/A') + published_date = cve_data.get('published', 'N/A') + last_modified_date = cve_data.get('lastModified', 'N/A') + cve_id = cve_data.get('id', 'N/A') + + severity = 'N/A' + metrics = cve_data.get('metrics', {}) + if 'cvssMetricV31' in metrics: + severity = metrics['cvssMetricV31'][0].get('cvssData', {}).get('baseSeverity', 'N/A') + elif 'cvssMetricV30' in metrics: + severity = metrics['cvssMetricV30'][0].get('cvssData', {}).get('baseSeverity', 'N/A') + elif 'cvssMetricV2' in metrics: + severity = metrics['cvssMetricV2'][0].get('cvssData', {}).get('baseSeverity', 'N/A') + + writer.writerow({ + "Product": product_str, + "Vendor": vendor_str, + "CVE ID": cve_id, + "Date Added": published_date, + "Date Updated": last_modified_date, + "Description": description, + "Severity": severity + }) + print(f"Vulnerabilities written to {filename}") + + except Exception as e: + print(f"Error writing to CSV: {e}") + + + +if __name__ == "__main__": + vulnerabilities = get_nist_vulnerabilities() + + if vulnerabilities: + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"nist_vulnerabilities_{timestamp}.csv" + write_to_csv(vulnerabilities, filename) \ No newline at end of file diff --git a/NIST Reports/readme.md b/NIST Reports/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/Python Course Materials/Week2/pg29Excercise1.py b/Python Course Materials/Week2/pg29Excercise1.py new file mode 100644 index 0000000..bc064f4 --- /dev/null +++ b/Python Course Materials/Week2/pg29Excercise1.py @@ -0,0 +1,24 @@ +#a +print("Hello, world!") +#b +print("Hello", "World!") +#c +print("3") +#d +print("3.0") +#e +print(2 + 3) +#f +print("2.0 + 3.0") +#g +print("2" + "3") +#h +print("2 + 3 =", 2 + 3) +#i +print("2 * 3") +#j +print(2 ** 3) +#k +print(7 / 3) +#l +print(7 // 3) diff --git a/Python Course Materials/Week2/pg29Exercise1.py b/Python Course Materials/Week2/pg29Exercise1.py new file mode 100644 index 0000000..bc064f4 --- /dev/null +++ b/Python Course Materials/Week2/pg29Exercise1.py @@ -0,0 +1,24 @@ +#a +print("Hello, world!") +#b +print("Hello", "World!") +#c +print("3") +#d +print("3.0") +#e +print(2 + 3) +#f +print("2.0 + 3.0") +#g +print("2" + "3") +#h +print("2 + 3 =", 2 + 3) +#i +print("2 * 3") +#j +print(2 ** 3) +#k +print(7 / 3) +#l +print(7 // 3) diff --git a/Python Course Materials/Week2/pg58exercise10.py b/Python Course Materials/Week2/pg58exercise10.py new file mode 100644 index 0000000..e9e157c --- /dev/null +++ b/Python Course Materials/Week2/pg58exercise10.py @@ -0,0 +1,27 @@ +#performs the conversion and prints to the console +def ConvertToMiles(): + kilometers = float(input("Please provide a number of kilometers that you would like to convert to miles: ")) + converted_to_miles = kilometers * 0.62 + print(kilometers, " kilometer(s) is/are equal to " , converted_to_miles , " miles.") + askaboutrepeating() + +#Ask the users if they would like to do it again. +def askaboutrepeating(): + print("Looks like that provided you a converted number. Do you want to convert another number? ") + answer = str(input("Please respond with yes (y) or no (n) :")) + if answer == "y": + ConvertToMiles() + if answer == "n": + exit + else: + print("Woah, something about what you typed was definitley not correct.") + askaboutrepeating() + +# Defines what the script is going to do and calls upon the earlier defined Convert function +def main(): + print("Welcome!\n\n This application was made by David Kifer to take a quantity of kilometers and convert them to miles. In the following prompt, you will be asked to provide the amount of kilometers\n\n ") + ConvertToMiles() + +# Call the main app to kick off the app +main() + diff --git a/Python Course Materials/Week2/pg84exercise5.py b/Python Course Materials/Week2/pg84exercise5.py new file mode 100644 index 0000000..0caf451 --- /dev/null +++ b/Python Course Materials/Week2/pg84exercise5.py @@ -0,0 +1,24 @@ +#Konditorei Coffee shop +def main(): + pounds = float(input("How many pounds of coffee would you like to order?: ")) + coffee_price = float(15.50) + shipping_price = float(0.99 * pounds + 4.50) + grand_total = coffee_price + shipping_price + print("That comes to a grand total of $" , grand_total) + askaboutrepeating() + +# Ask about repeating +def askaboutrepeating(): + print("Thanks for ordering with me! Would you like to order some more?") + answer = str(input("Please respond with yes (y) or no (n) :")) + if answer == "y": + main() + if answer == "n": + exit + else: + print("Woah, something about what you typed was definitley not correct.") + askaboutrepeating() + +# Call the main app to kick off the app +main() + diff --git a/Python Course Materials/Week3/coursera lab.py b/Python Course Materials/Week3/coursera lab.py new file mode 100644 index 0000000..b97b544 --- /dev/null +++ b/Python Course Materials/Week3/coursera lab.py @@ -0,0 +1,119 @@ +menu = { + 1: {"name": 'espresso', "price": 1.99}, + 2: {"name": 'coffee', "price": 2.50}, + 3: {"name": 'cake', "price": 2.79}, + 4: {"name": 'soup', "price": 4.50}, + 5: {"name": 'sandwich', "price": 4.99} +} + +def calculate_subtotal(order): + """Calculates the subtotal of an order. + + [IMPLEMENT ME] + 1. Add up the prices of all items in the order. + 2. Round the result to 2 decimal places and return it. + + Args: + order (list): A list of dicts, where each dict represents an item with a name and price. + + Returns: + float: The subtotal of all item prices, rounded to 2 decimal places. + """ + print('Calculating bill subtotal...') + + ### WRITE SOLUTION HERE + subtotal_calc = float(0.00) + for item in order: + subtotal_calc += item['price'] + return round(subtotal_calc, 2) + +def calculate_tax(subtotal): + """Calculates the tax of an order. + + [IMPLEMENT ME] + 1. Calculate 15% of the subtotal. + 2. Round the tax to 2 decimal places and return it. + + Args: + subtotal (float): The subtotal amount. + + Returns: + float: The calculated tax amount, rounded to 2 decimal places. + """ + print('Calculating tax from subtotal...') + ### WRITE SOLUTION HERE + tax_rate = 0.15 + tax = subtotal * tax_rate + return round(tax, 2) + + +def summarize_order(order): + """Summarizes the order. + + [IMPLEMENT ME] + 1. Calculate subtotal and tax. + 2. Compute the total (subtotal + tax) and round to 2 decimal places. + 3. Extract the item names and return them with the total. + + Args: + order (list): A list of dicts, where each dict represents an item with a name and price. + + Returns: + tuple: A list of item names and the total amount (rounded to 2 decimal places). + """ + + ### WRITE SOLUTION HERE + item_details = list() + for item in order: + item_details.append((item['name'], item['price'])) + subtotal = calculate_subtotal(order) + subtotal = round(subtotal, 2) + tax = calculate_tax(subtotal) + total = round(subtotal + tax, 2) + names = [item['name'] for item in order] + return names, total + + +# This function is provided for you and will print out the items in an order +def print_order(order): + print('You have ordered ' + str(len(order)) + ' items') + items = [item["name"] for item in order] + print(items) + return order + +# This function is provided for you and will display the menu +def display_menu(): + print("------- Menu -------") + for selection in menu: + print(f"{selection}. {menu[selection]['name'] : <9} | {menu[selection]['price'] : >5}") + print() + +# This function is provided for you and will create an order by prompting the user to select menu items +def take_order(): + display_menu() + order = [] + count = 1 + for i in range(3): + item = input('Select menu item number ' + str(count) + ' (from 1 to 5): ') + count += 1 + order.append(menu[int(item)]) + return order + +''' +Here are some sample function calls to help you test your implementations. +Feel free to change, uncomment, and add these as you wish. +''' +def main(): + order = take_order() + print_order(order) + names, total = summarize_order(order) + + + print("Order summary:") + for name, price in [(item['name'], item['price']) for item in order]: + print(f" {name}: ${price:.2f}") + + print(f"Total: ${total:.2f}") + +if __name__ == "__main__": + main() diff --git a/Python Course Materials/Week3/pg263Excercise1.py b/Python Course Materials/Week3/pg263Excercise1.py new file mode 100644 index 0000000..540ef08 --- /dev/null +++ b/Python Course Materials/Week3/pg263Excercise1.py @@ -0,0 +1,36 @@ +# Given the initial statements +# s1 = "spam" +# s2 = "ni!" + +# Show the result of evaluating each of the following string expressions. + +# a) "The knights who say, " + s2 +# b) 3 * s1 +2 * s2 +# c) a1[1] +# d) s1[1:3] +# e) s1[2] + s2[:2] +# f) s1 + s2[-1] +# g) s1.upper() +# h) s1.upper().1just(4) * 3 + +## Initialization +s1 = "spam" +s2 = "ni!" + +StringValues = { + "a": "The knights who say, " + s2, + "b": 3 * s1 + 2 * s2, + "c": s1[1], + "d": s1[1:3], + "e": s1[2] + s2[:2], + "f": s1 + s2[-1], + "g": s1.upper(), + "h": s1.upper().ljust(4) * 3, +} + +def main(): + for key, value in StringValues.items(): + print(f"{key}) {value}") + + +main() \ No newline at end of file diff --git a/Python Course Materials/Week3/pg264Excercise4.py b/Python Course Materials/Week3/pg264Excercise4.py new file mode 100644 index 0000000..2f166fc --- /dev/null +++ b/Python Course Materials/Week3/pg264Excercise4.py @@ -0,0 +1,13 @@ +s1 = "spam" +s2 = "eggs" +num1 = 10 +num2 = 3.14159 + +def main(): + print(f"That is {num1} {s1} and {num1//2} {s2}") + print(f"That is {num1:5} {s1} and {num2:5.2} {s2}") + print(f"{num1:0.2f} {num2:0.2f}") + print(f"{num1:7.5f}{num2:7.5f}") + print(f"Time left {num1:02}:{num2:05.0f}") + +main() \ No newline at end of file diff --git a/Python Course Materials/Week3/pg265Excercise2.py b/Python Course Materials/Week3/pg265Excercise2.py new file mode 100644 index 0000000..11d0cc2 --- /dev/null +++ b/Python Course Materials/Week3/pg265Excercise2.py @@ -0,0 +1,47 @@ +gradetable = { + "90-100": "A", + "80-89": "B", + "70-79": "C", + "60-69": "D", + "0-59": "F" +} + +def main(): + usercontinue = 'yes' + while usercontinue == 'yes': + try: + score = int(input("What was the exam score?: ")) + + if 90 <= score <= 100: + grade = gradetable["90-100"] + elif 80 <= score <= 89: + grade = gradetable["80-89"] + elif 70 <= score <= 79: + grade = gradetable["70-79"] + elif 60 <= score <= 69: + grade = gradetable["60-69"] + elif 0 <= score <= 59: + grade = gradetable["0-59"] + else: + grade = 'invalid score' + + print(f"The letter score of score of the exam was {grade}") + + except ValueError: + print("Invalid input. Please enter a number.") + + + usercontinueprompt = input("Would you like to determine the letter grade of another score? (yes/no): ") + usercontinueprompt = usercontinueprompt.lower() #Convert to lowercase once + + if usercontinueprompt == 'yes': #Corrected to assignment + usercontinue = 'yes' + elif usercontinueprompt == 'no': + print("Thanks, have a great day!") + usercontinue = 'no' # Corrected typo and assignment + else: + print("That wasn't a valid selection. Try again") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Python Course Materials/Week3/pythontest.py b/Python Course Materials/Week3/pythontest.py new file mode 100644 index 0000000..9121df6 --- /dev/null +++ b/Python Course Materials/Week3/pythontest.py @@ -0,0 +1,4 @@ +a = "cool" +input=("") + +print(a) \ No newline at end of file diff --git a/Python Course Materials/Week4/pg291-292DiscussionExcercise1and2.py b/Python Course Materials/Week4/pg291-292DiscussionExcercise1and2.py new file mode 100644 index 0000000..32666ea --- /dev/null +++ b/Python Course Materials/Week4/pg291-292DiscussionExcercise1and2.py @@ -0,0 +1,64 @@ +s1 = [2, 1, 4, 3] +s2 = ["c","a","b"] +print("------------Discussion Part 1----------") +# s1 + s2 +print("-----s1 + s2-----") +print(s1 + s2) + + +#b) 3 * s1 + 2 * s2 +print("--------3 * s1 + 2 * s2-----") +print(3 * s1 + 2 *s2) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#c) s1[1] +print("--------s1[1]-----") +print(s1[1]) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#d) s1[1:3] +print("--------s1[1:3]-----") +print(s1[1:3]) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#e) s1 + s2[-1] +print("--------s1[1:3]------") +print(s1 + [s2[-1]]) +print() + +print("------------Discussion Part 2----------") +#a)s1.remove(2) +print(s1.remove(2)) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#b)s1.sort() +print(s1.sort()) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#c)s1.append([s2.index("b")] +print(s1.append([s2.index("b")])) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#d)s2.pop(s1.pop(0)) +print(s2.pop(s1.pop(0))) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() + +#e)s2.insert(s1[1], "d" +print(s2.insert(s1[1], "d")) +print(f"This is the value of s1: {s1}") +print(f"This is the value of s2: {s2}") +print() diff --git a/Python Course Materials/Week4/pg294excercise4.py b/Python Course Materials/Week4/pg294excercise4.py new file mode 100644 index 0000000..200b68d --- /dev/null +++ b/Python Course Materials/Week4/pg294excercise4.py @@ -0,0 +1,27 @@ +def removeDuplicates(somelist): + seen = set() + result = [] + + for i in somelist: + if i not in seen: + seen.add(i) + result.append(i) + + return result + +def main(): + #Create a list with duplicates + somelist = [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9] + + #Display the list + print(somelist) + + #Use the remove duplicates function to remove duplicate values + list_parsed = removeDuplicates(somelist) + + print(list_parsed) + +if __name__ == "__main__": + main() + + diff --git a/Python Course Materials/Week4/windowscolorexcercise.py b/Python Course Materials/Week4/windowscolorexcercise.py new file mode 100644 index 0000000..ac0d173 --- /dev/null +++ b/Python Course Materials/Week4/windowscolorexcercise.py @@ -0,0 +1,29 @@ +from graphics import * + +win = GraphWin("My Window", 500, 500) + +while True: + key = win.checkKey() + if key == "q": #loop exit + break + if key == "r": + win.setBackground("red") + elif key == "g": + win.setBackground("green") + elif key == "b": + win.setBackground("blue") + elif key == "y": + win.setBackground("yellow") + elif key == "w": + win.setBackground("white") + elif key == "p": + win.setBackground("purple") + elif key == "o": + win.setBackground("orange") + elif key == "c": + win.setBackground("cyan") + else : + win.close() + + + diff --git a/Security Stack/CompanyInvestigation/CompanyReview.py b/Security Stack/CompanyInvestigation/CompanyReview.py new file mode 100644 index 0000000..fb93f75 --- /dev/null +++ b/Security Stack/CompanyInvestigation/CompanyReview.py @@ -0,0 +1,220 @@ +import os +import requests +import whois +from docx import Document +from fpdf import FPDF +import datetime + +def investigate_website(url): + """Investigate the website to find the country of operation and past security breaches.""" + try: + # Perform WHOIS lookup to determine country + domain = url.replace("https://", "").replace("http://", "").split("/")[0] + whois_data = whois.whois(domain) + country = whois_data.get("country", "Unknown") + + # Check for breaches using Have I Been Pwned API (requires API key) + hibp_api_url = f"https://haveibeenpwned.com/api/v3/breachedaccount/{domain}" + headers = {"hibp-api-key": "YOUR_API_KEY_HERE"} # Replace with your HIBP API key + breaches = [] + + try: + breach_response = requests.get(hibp_api_url, headers=headers) + if breach_response.status_code == 200: + breaches = breach_response.json() + elif breach_response.status_code == 404: + breaches = "No breaches found." + else: + breaches = f"Error: {breach_response.status_code}" + except Exception as e: + breaches = f"Error fetching breaches: {e}" + + return { + "country": country, + "breaches": breaches, + "whois_data": str(whois_data) + } + except Exception as e: + return { + "country": "Error determining country", + "breaches": f"Error fetching breaches: {e}", + "whois_data": f"Error: {e}" + } + +def analyze_headers(url): + """Perform a header analysis to identify security weaknesses.""" + try: + response = requests.get(url) + headers = response.headers + + # Security headers to check + security_headers = { + "Content-Security-Policy": "Missing or insufficient Content-Security-Policy", + "Strict-Transport-Security": "Missing Strict-Transport-Security", + "X-Content-Type-Options": "Missing X-Content-Type-Options", + "X-Frame-Options": "Missing X-Frame-Options", + "X-XSS-Protection": "Missing or insufficient X-XSS-Protection", + "Referrer-Policy": "Missing Referrer-Policy", + "Permissions-Policy": "Missing Permissions-Policy" + } + + weaknesses = [] + for header, issue in security_headers.items(): + if header not in headers: + weaknesses.append(issue) + + grade = "A" if not weaknesses else "C" if len(weaknesses) < 3 else "F" + + return { + "grade": grade, + "weaknesses": weaknesses, + "headers": dict(headers) + } + except Exception as e: + return { + "grade": "Error", + "weaknesses": [f"Error analyzing headers: {e}"], + "headers": f"Error: {e}" + } + +def save_results_to_files(data, output_dir, domain): + """Save investigation results to docx, pdf, and markdown files.""" + os.makedirs(output_dir, exist_ok=True) + + # Generate unique filenames using timestamp and domain + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + # Ensure the domain is a valid filename + domain_safe = "".join(c if c.isalnum() else "_" for c in domain) + base_filename = f"{domain_safe}_{timestamp}" + docx_path = os.path.join(output_dir, f"{base_filename}.docx") + pdf_path = os.path.join(output_dir, f"{base_filename}.pdf") + md_path = os.path.join(output_dir, f"{base_filename}.md") + + # Create a Word document + doc = Document() + doc.add_heading("Website Security Analysis", level=1) + + doc.add_heading("1. Website Investigation", level=2) + doc.add_paragraph(f"Country of Operation: {data['investigation'].get('country', 'N/A')}") + doc.add_paragraph(f"Security Breaches: {data['investigation'].get('breaches', 'N/A')}") + + doc.add_heading("2. Header Analysis", level=2) + doc.add_paragraph(f"Security Grade: {data['headers'].get('grade', 'N/A')}") + if data['headers'].get('weaknesses'): + doc.add_paragraph("Weaknesses:") + for weakness in data['headers']['weaknesses']: + doc.add_paragraph(f"- {weakness}", style="List Bullet") + + # Add Appendix + doc.add_heading("Appendix", level=1) + doc.add_heading("Full WHOIS Data", level=2) + doc.add_paragraph(data['investigation'].get('whois_data', 'N/A')) + + doc.add_heading("Full Header Analysis", level=2) + doc.add_paragraph(str(data['headers'].get('headers', 'N/A'))) + + doc.add_heading("Full Breach Data", level=2) + doc.add_paragraph(str(data['investigation'].get('breaches', 'N/A'))) + + doc.save(docx_path) + + # Create a Markdown file + with open(md_path, "w") as md_file: + md_file.write("# Website Security Analysis\n\n") + md_file.write("## 1. Website Investigation\n") + md_file.write(f"- Country of Operation: {data['investigation'].get('country', 'N/A')}\n") + md_file.write(f"- Security Breaches: {data['investigation'].get('breaches', 'N/A')}\n\n") + md_file.write("## 2. Header Analysis\n") + md_file.write(f"- Security Grade: {data['headers'].get('grade', 'N/A')}\n") + if data['headers'].get('weaknesses'): + md_file.write("- Weaknesses:\n") + for weakness in data['headers']['weaknesses']: + md_file.write(f" - {weakness}\n") + + md_file.write("\n# Appendix\n\n") + md_file.write("## Full WHOIS Data\n") + md_file.write(f"```\n{data['investigation'].get('whois_data', 'N/A')}\n```\n") + + md_file.write("## Full Header Analysis\n") + md_file.write(f"```\n{data['headers'].get('headers', 'N/A')}\n```\n") + + md_file.write("## Full Breach Data\n") + md_file.write(f"```\n{data['investigation'].get('breaches', 'N/A')}\n```\n") + + # Create a PDF file using FPDF + pdf = FPDF() + pdf.set_auto_page_break(auto=True, margin=15) + pdf.add_page() + pdf.set_font("Arial", size=12) + + pdf.cell(200, 10, txt="Website Security Analysis", ln=True, align='C') + + pdf.ln(10) + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "1. Website Investigation", ln=True) + + pdf.set_font("Arial", size=12) + pdf.multi_cell(0, 10, f"Country of Operation: {data['investigation'].get('country', 'N/A')}") + pdf.multi_cell(0, 10, f"Security Breaches: {data['investigation'].get('breaches', 'N/A')}") + + pdf.ln(5) + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "2. Header Analysis", ln=True) + + pdf.set_font("Arial", size=12) + pdf.multi_cell(0, 10, f"Security Grade: {data['headers'].get('grade', 'N/A')}") + if data['headers'].get('weaknesses'): + pdf.cell(0, 10, "Weaknesses:", ln=True) + for weakness in data['headers']['weaknesses']: + pdf.cell(0, 10, f"- {weakness}", ln=True) + + pdf.add_page() + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Appendix", ln=True) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full WHOIS Data", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, data['investigation'].get('whois_data', 'N/A')) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full Header Analysis", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, str(data['headers'].get('headers', 'N/A'))) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full Breach Data", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, str(data['investigation'].get('breaches', 'N/A'))) + + pdf.output(pdf_path) + + print(f"Results saved to: {docx_path}, {md_path}, {pdf_path}") + +if __name__ == "__main__": + # User inputs + website_url = input("Enter the website URL (including https://): ").strip() + default_directory = os.getcwd() + print(f"Default save directory: {default_directory}") + use_default = input("Do you want to use the default directory? (y/n): ").strip().lower() + + if use_default == 'y': + output_directory = default_directory + else: + output_directory = input("Enter the directory to save results: ").strip() + + # Extract domain name for unique file naming + domain = website_url.replace("https://", "").replace("http://", "").split("/")[0] + + # Perform analysis + investigation_results = investigate_website(website_url) + header_analysis_results = analyze_headers(website_url) + + # Combine results + results = { + "investigation": investigation_results, + "headers": header_analysis_results + } + + # Save to files + save_results_to_files(results, output_directory, domain) diff --git a/Security Stack/CompanyInvestigation/CompanyReview.txt b/Security Stack/CompanyInvestigation/CompanyReview.txt new file mode 100644 index 0000000..fb93f75 --- /dev/null +++ b/Security Stack/CompanyInvestigation/CompanyReview.txt @@ -0,0 +1,220 @@ +import os +import requests +import whois +from docx import Document +from fpdf import FPDF +import datetime + +def investigate_website(url): + """Investigate the website to find the country of operation and past security breaches.""" + try: + # Perform WHOIS lookup to determine country + domain = url.replace("https://", "").replace("http://", "").split("/")[0] + whois_data = whois.whois(domain) + country = whois_data.get("country", "Unknown") + + # Check for breaches using Have I Been Pwned API (requires API key) + hibp_api_url = f"https://haveibeenpwned.com/api/v3/breachedaccount/{domain}" + headers = {"hibp-api-key": "YOUR_API_KEY_HERE"} # Replace with your HIBP API key + breaches = [] + + try: + breach_response = requests.get(hibp_api_url, headers=headers) + if breach_response.status_code == 200: + breaches = breach_response.json() + elif breach_response.status_code == 404: + breaches = "No breaches found." + else: + breaches = f"Error: {breach_response.status_code}" + except Exception as e: + breaches = f"Error fetching breaches: {e}" + + return { + "country": country, + "breaches": breaches, + "whois_data": str(whois_data) + } + except Exception as e: + return { + "country": "Error determining country", + "breaches": f"Error fetching breaches: {e}", + "whois_data": f"Error: {e}" + } + +def analyze_headers(url): + """Perform a header analysis to identify security weaknesses.""" + try: + response = requests.get(url) + headers = response.headers + + # Security headers to check + security_headers = { + "Content-Security-Policy": "Missing or insufficient Content-Security-Policy", + "Strict-Transport-Security": "Missing Strict-Transport-Security", + "X-Content-Type-Options": "Missing X-Content-Type-Options", + "X-Frame-Options": "Missing X-Frame-Options", + "X-XSS-Protection": "Missing or insufficient X-XSS-Protection", + "Referrer-Policy": "Missing Referrer-Policy", + "Permissions-Policy": "Missing Permissions-Policy" + } + + weaknesses = [] + for header, issue in security_headers.items(): + if header not in headers: + weaknesses.append(issue) + + grade = "A" if not weaknesses else "C" if len(weaknesses) < 3 else "F" + + return { + "grade": grade, + "weaknesses": weaknesses, + "headers": dict(headers) + } + except Exception as e: + return { + "grade": "Error", + "weaknesses": [f"Error analyzing headers: {e}"], + "headers": f"Error: {e}" + } + +def save_results_to_files(data, output_dir, domain): + """Save investigation results to docx, pdf, and markdown files.""" + os.makedirs(output_dir, exist_ok=True) + + # Generate unique filenames using timestamp and domain + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + # Ensure the domain is a valid filename + domain_safe = "".join(c if c.isalnum() else "_" for c in domain) + base_filename = f"{domain_safe}_{timestamp}" + docx_path = os.path.join(output_dir, f"{base_filename}.docx") + pdf_path = os.path.join(output_dir, f"{base_filename}.pdf") + md_path = os.path.join(output_dir, f"{base_filename}.md") + + # Create a Word document + doc = Document() + doc.add_heading("Website Security Analysis", level=1) + + doc.add_heading("1. Website Investigation", level=2) + doc.add_paragraph(f"Country of Operation: {data['investigation'].get('country', 'N/A')}") + doc.add_paragraph(f"Security Breaches: {data['investigation'].get('breaches', 'N/A')}") + + doc.add_heading("2. Header Analysis", level=2) + doc.add_paragraph(f"Security Grade: {data['headers'].get('grade', 'N/A')}") + if data['headers'].get('weaknesses'): + doc.add_paragraph("Weaknesses:") + for weakness in data['headers']['weaknesses']: + doc.add_paragraph(f"- {weakness}", style="List Bullet") + + # Add Appendix + doc.add_heading("Appendix", level=1) + doc.add_heading("Full WHOIS Data", level=2) + doc.add_paragraph(data['investigation'].get('whois_data', 'N/A')) + + doc.add_heading("Full Header Analysis", level=2) + doc.add_paragraph(str(data['headers'].get('headers', 'N/A'))) + + doc.add_heading("Full Breach Data", level=2) + doc.add_paragraph(str(data['investigation'].get('breaches', 'N/A'))) + + doc.save(docx_path) + + # Create a Markdown file + with open(md_path, "w") as md_file: + md_file.write("# Website Security Analysis\n\n") + md_file.write("## 1. Website Investigation\n") + md_file.write(f"- Country of Operation: {data['investigation'].get('country', 'N/A')}\n") + md_file.write(f"- Security Breaches: {data['investigation'].get('breaches', 'N/A')}\n\n") + md_file.write("## 2. Header Analysis\n") + md_file.write(f"- Security Grade: {data['headers'].get('grade', 'N/A')}\n") + if data['headers'].get('weaknesses'): + md_file.write("- Weaknesses:\n") + for weakness in data['headers']['weaknesses']: + md_file.write(f" - {weakness}\n") + + md_file.write("\n# Appendix\n\n") + md_file.write("## Full WHOIS Data\n") + md_file.write(f"```\n{data['investigation'].get('whois_data', 'N/A')}\n```\n") + + md_file.write("## Full Header Analysis\n") + md_file.write(f"```\n{data['headers'].get('headers', 'N/A')}\n```\n") + + md_file.write("## Full Breach Data\n") + md_file.write(f"```\n{data['investigation'].get('breaches', 'N/A')}\n```\n") + + # Create a PDF file using FPDF + pdf = FPDF() + pdf.set_auto_page_break(auto=True, margin=15) + pdf.add_page() + pdf.set_font("Arial", size=12) + + pdf.cell(200, 10, txt="Website Security Analysis", ln=True, align='C') + + pdf.ln(10) + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "1. Website Investigation", ln=True) + + pdf.set_font("Arial", size=12) + pdf.multi_cell(0, 10, f"Country of Operation: {data['investigation'].get('country', 'N/A')}") + pdf.multi_cell(0, 10, f"Security Breaches: {data['investigation'].get('breaches', 'N/A')}") + + pdf.ln(5) + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "2. Header Analysis", ln=True) + + pdf.set_font("Arial", size=12) + pdf.multi_cell(0, 10, f"Security Grade: {data['headers'].get('grade', 'N/A')}") + if data['headers'].get('weaknesses'): + pdf.cell(0, 10, "Weaknesses:", ln=True) + for weakness in data['headers']['weaknesses']: + pdf.cell(0, 10, f"- {weakness}", ln=True) + + pdf.add_page() + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Appendix", ln=True) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full WHOIS Data", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, data['investigation'].get('whois_data', 'N/A')) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full Header Analysis", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, str(data['headers'].get('headers', 'N/A'))) + + pdf.set_font("Arial", style="B", size=12) + pdf.cell(0, 10, "Full Breach Data", ln=True) + pdf.set_font("Arial", size=10) + pdf.multi_cell(0, 10, str(data['investigation'].get('breaches', 'N/A'))) + + pdf.output(pdf_path) + + print(f"Results saved to: {docx_path}, {md_path}, {pdf_path}") + +if __name__ == "__main__": + # User inputs + website_url = input("Enter the website URL (including https://): ").strip() + default_directory = os.getcwd() + print(f"Default save directory: {default_directory}") + use_default = input("Do you want to use the default directory? (y/n): ").strip().lower() + + if use_default == 'y': + output_directory = default_directory + else: + output_directory = input("Enter the directory to save results: ").strip() + + # Extract domain name for unique file naming + domain = website_url.replace("https://", "").replace("http://", "").split("/")[0] + + # Perform analysis + investigation_results = investigate_website(website_url) + header_analysis_results = analyze_headers(website_url) + + # Combine results + results = { + "investigation": investigation_results, + "headers": header_analysis_results + } + + # Save to files + save_results_to_files(results, output_directory, domain) diff --git a/Security Stack/CompanyInvestigation/sitereview.py b/Security Stack/CompanyInvestigation/sitereview.py new file mode 100644 index 0000000..0fb299f --- /dev/null +++ b/Security Stack/CompanyInvestigation/sitereview.py @@ -0,0 +1,79 @@ +import pandas as pd +import os +import whois +import socket +import requests +from ipwhois import IPWhois + +def aggregate_csv_to_excel(folder_path, output_excel): + with pd.ExcelWriter(output_excel, engine='xlsxwriter') as writer: + for filename in os.listdir(folder_path): + if filename.endswith('.csv'): + file_path = os.path.join(folder_path, filename) + df = pd.read_csv(file_path) + + # Filter relevant columns + columns = ['timestamp', 'client_ip', 'server_ip', 'server_port', 'direction', 'total_bytes', 'country', 'flow_state'] + if 'dns' in df.columns: + columns.append('dns') + df = df[columns] + + # Investigate each server IP + df['whois_info'] = df['server_ip'].apply(get_whois_info) + df['geo_info'] = df['server_ip'].apply(get_geo_info) + df['virus_total'] = df['server_ip'].apply(check_virus_total) + df['dns_lookup'] = df['server_ip'].apply(dns_lookup) + + # Write to Excel + sheet_name = os.path.splitext(filename)[0] + df.to_excel(writer, sheet_name=sheet_name, index=False) + +def get_whois_info(ip): + try: + w = whois.whois(ip) + return f"Registrar: {w.registrar}, Country: {w.country}" + except Exception as e: + return f"WHOIS Error: {str(e)}" + +def get_geo_info(ip): + try: + obj = IPWhois(ip) + res = obj.lookup_rdap() + return f"Country: {res['asn_country_code']}, ASN: {res['asn']}" + except Exception as e: + return f"Geo Error: {str(e)}" + +def check_virus_total(ip): + try: + url = f"https://www.virustotal.com/api/v3/ip_addresses/{ip}" + headers = {"x-apikey": "your-api-key-here"} # Replace with your VirusTotal API key + response = requests.get(url, headers=headers) + if response.status_code == 200: + data = response.json() + return f"Reputation: {data.get('data', {}).get('attributes', {}).get('reputation', 'N/A')}" + else: + return f"VT Error: {response.status_code}" + except Exception as e: + return f"VT Error: {str(e)}" + +def dns_lookup(ip): + try: + return socket.gethostbyaddr(ip)[0] + except socket.herror: + return "DNS Lookup Error" + +def main(): + current_dir = os.getcwd() + user_input = input(f"Do you want to use the current directory ({current_dir}) to pull CSV files? (yes/no): ").strip().lower() + + if user_input == 'yes': + folder_path = current_dir + else: + folder_path = input("Please enter the directory where the CSV files are located: ").strip() + + output_excel = os.path.join(current_dir, 'aggregated_investigation.xlsx') + aggregate_csv_to_excel(folder_path, output_excel) + print(f"Aggregated investigation saved to {output_excel}") + +if __name__ == "__main__": + main() diff --git a/Security Stack/SecurityReview/SoftwareSecurityReview.py b/Security Stack/SecurityReview/SoftwareSecurityReview.py new file mode 100644 index 0000000..abb77df --- /dev/null +++ b/Security Stack/SecurityReview/SoftwareSecurityReview.py @@ -0,0 +1,340 @@ +import datetime +from docx import Document +from docx2pdf import convert + +def create_assessment_doc(data): + """Creates a Word document from the assessment data.""" + + document = Document() + document.add_heading('Software/Vendor Security Assessment Request', 0) + + # 1. Requestor Information + document.add_heading('1. Requestor Information', level=1) + document.add_paragraph(f"Name: {data['requestor_name']}") + document.add_paragraph(f"Department: {data['department']}") + document.add_paragraph(f"Email Address: {data['email']}") + document.add_paragraph(f"Phone Number: {data['phone']}") + + # 2. Request Type + document.add_heading('2. Request Type', level=1) + document.add_paragraph(data['request_type']) + + # 3. Deployment Model + document.add_heading('3. Deployment Model', level=1) + document.add_paragraph(data['deployment_model']) + + # 4. Software/Vendor Information + document.add_heading('4. Software/Vendor Information', level=1) + document.add_paragraph(f"Software/Vendor Name: {data['vendor_name']}") + document.add_paragraph(f"Software Name: {data['software_name']}") + document.add_paragraph(f"Software/Vendor Website: {data['vendor_website']}") + document.add_paragraph(f"Software/Vendor Contact Information: {data['vendor_contact']}") + document.add_paragraph(f"Brief Description of Software/Vendor and its Purpose: {data['vendor_description']}") + + # 5. Intended Use + document.add_heading('5. Intended Use', level=1) + document.add_paragraph(f"Describe how the software/vendor will be used within the company: {data['intended_use']}") + document.add_paragraph(f"Specify the departments or teams that will be using the software/vendor: {data['departments_teams']}") + document.add_paragraph(f"Identify any critical business processes or data that will be impacted by the software/vendor: {data['critical_processes_data']}") + + # 6. Prerequisites + document.add_heading('6. Prerequisites', level=1) + document.add_paragraph(f"Operating System Requirements: {data['os_requirements']}") + document.add_paragraph(f"Hardware Requirements (e.g., RAM, storage space): {data['hardware_requirements']}") + document.add_paragraph(f"Network Connectivity (e.g., bandwidth, VPN): {data['network_connectivity']}") + document.add_paragraph(f"Software Dependencies (e.g., libraries, frameworks): {data['software_dependencies']}") + document.add_paragraph(f"User Access Requirements (e.g., specific roles, permissions): {data['user_access_requirements']}") + document.add_paragraph(f"Other Prerequisites: {data['other_prerequisites']}") + + # 7. Technical Information + document.add_heading('7. Technical Information', level=1) + document.add_paragraph(f"Hosting Environment (e.g., cloud provider, on-premise data center): {data['hosting_environment']}") + document.add_paragraph(f"Network Requirements (e.g., ports, protocols, firewall rules): {data['network_requirements']}") + document.add_paragraph(f"Data Storage Requirements (e.g., location, encryption, data retention policies): {data['data_storage_requirements']}") + document.add_paragraph(f"Integration with Existing Systems (if any): {data['integration_existing_systems']}") + document.add_paragraph(f"API Information (if applicable): {data['api_information']}") + + # 8. Security Requirements + document.add_heading('8. Security Requirements', level=1) + document.add_paragraph(f"Data Security - How will data be protected in transit and at rest?: {data['data_protection']}") + document.add_paragraph(f"Data Security - Does the software/vendor comply with relevant data privacy regulations (e.g., GDPR, CCPA)?: {data['data_privacy_compliance']}") + document.add_paragraph(f"Data Security - What data encryption methods are used?: {data['data_encryption_methods']}") + document.add_paragraph(f"Access Control - How will access to the software/vendor be granted and managed?: {data['access_control_management']}") + document.add_paragraph(f"Access Control - Does the software/vendor support multi-factor authentication?: {data['multi_factor_authentication']}") + document.add_paragraph(f"Access Control - What user roles and permissions are available?: {data['user_roles_permissions']}") + document.add_paragraph(f"Vulnerability Management - Does the software/vendor have a vulnerability disclosure program?: {data['vulnerability_disclosure']}") + document.add_paragraph(f"Vulnerability Management - How are security patches and updates managed?: {data['security_patch_management']}") + document.add_paragraph(f"Vulnerability Management - Are regular security assessments and penetration testing conducted?: {data['security_assessments']}") + document.add_paragraph(f"Compliance - Does the software/vendor comply with relevant industry security standards (e.g., ISO 27001, SOC 2)?: {data['industry_security_standards']}") + document.add_paragraph(f"Compliance - Are there any third-party security certifications or audits available?: {data['third_party_certifications']}") + document.add_paragraph(f"Business Continuity and Disaster Recovery - What are the software/vendor's business continuity and disaster recovery plans?: {data['business_continuity_plans']}") + document.add_paragraph(f"Business Continuity and Disaster Recovery - What are the recovery time objectives (RTOs) and recovery point objectives (RPOs)?: {data['rto_rpo']}") + + # 9. Privacy Requirements + document.add_heading('9. Privacy Requirements', level=1) + document.add_paragraph(f"Data Collection - What personal data will be collected by the software/vendor?: {data['personal_data_collected']}") + document.add_paragraph(f"Data Collection - What is the purpose of collecting this data?: {data['data_collection_purpose']}") + document.add_paragraph(f"Data Collection - Will data be shared with third parties? If so, with whom and for what purpose?: {data['data_sharing']}") + document.add_paragraph(f"Data Subject Rights - How does the software/vendor ensure data subject rights (e.g., access, rectification, erasure)?: {data['data_subject_rights']}") + document.add_paragraph(f"Data Subject Rights - Does the software/vendor provide a privacy policy that is readily accessible to users?: {data['privacy_policy']}") + + # 10. Legal and Contractual Requirements + document.add_heading('10. Legal and Contractual Requirements', level=1) + document.add_paragraph(f"Software License Agreement: {data['license_agreement']}") + document.add_paragraph(f"Service Level Agreement (SLA): {data['sla']}") + document.add_paragraph(f"Data Processing Agreement (DPA): {data['dpa']}") + document.add_paragraph(f"Vendor Security Policies: {data['vendor_security_policies']}") + + # 11. Risk Assessment + document.add_heading('11. Risk Assessment', level=1) + document.add_paragraph(f"Identify any potential security or privacy risks associated with the use of the software/vendor: {data['potential_risks']}") + document.add_paragraph(f"Describe the risk mitigation measures that will be implemented: {data['risk_mitigation']}") + + # 12. Approval (This section will likely be filled later) + document.add_heading('12. Approval', level=1) + document.add_paragraph("Security Analyst Review:") + document.add_paragraph("Date of Review: ") + document.add_paragraph("Security Analyst Name: ") + document.add_paragraph("Security Assessment Findings: ") + document.add_paragraph("Approval Status (Approved, Conditionally Approved, Rejected): ") + document.add_paragraph("Management Approval (if required):") + document.add_paragraph("Date of Approval: ") + document.add_paragraph("Approving Manager Name: ") + + # 13. Supporting Documentation + document.add_heading('13. Supporting Documentation', level=1) + document.add_paragraph("Attach any relevant supporting documentation, such as:") + document.add_paragraph("Vendor security questionnaires") + document.add_paragraph("Penetration testing reports") + document.add_paragraph("Security audit reports") + document.add_paragraph("Privacy impact assessments") + + return document + +def create_markdown_file(data, md_filename): # Receive filename as argument + """Creates a Markdown file from the assessment data.""" + + with open(md_filename, "w") as f: # Use the provided filename + # Add all the headings and data from the form in Markdown format + f.write("# Software/Vendor Security Assessment Request\n\n") + + f.write("## 1. Requestor Information\n") + f.write(f"Name: {data['requestor_name']}\n") + f.write(f"Department: {data['department']}\n") + f.write(f"Email Address: {data['email']}\n") + f.write(f"Phone Number: {data['phone']}\n") + + f.write("\n## 2. Request Type\n") + f.write(f"{data['request_type']}\n") + + f.write("\n## 3. Deployment Model\n") + f.write(f"{data['deployment_model']}\n") + + f.write("\n## 4. Software/Vendor Information\n") + f.write(f"Software/Vendor Name: {data['vendor_name']}\n") + f.write(f"Software Name: {data['software_name']}\n") + f.write(f"Software/Vendor Website: {data['vendor_website']}\n") + f.write(f"Software/Vendor Contact Information: {data['vendor_contact']}\n") + f.write(f"Brief Description of Software/Vendor and its Purpose: {data['vendor_description']}\n") + + f.write("\n## 5. Intended Use\n") + f.write(f"Describe how the software/vendor will be used within the company: {data['intended_use']}\n") + f.write(f"Specify the departments or teams that will be using the software/vendor: {data['departments_teams']}\n") + f.write(f"Identify any critical business processes or data that will be impacted by the software/vendor: {data['critical_processes_data']}\n") + + f.write("\n## 6. Prerequisites\n") + f.write(f"Operating System Requirements: {data['os_requirements']}\n") + f.write(f"Hardware Requirements (e.g., RAM, storage space): {data['hardware_requirements']}\n") + f.write(f"Network Connectivity (e.g., bandwidth, VPN): {data['network_connectivity']}\n") + f.write(f"Software Dependencies (e.g., libraries, frameworks): {data['software_dependencies']}\n") + f.write(f"User Access Requirements (e.g., specific roles, permissions): {data['user_access_requirements']}\n") + f.write(f"Other Prerequisites: {data['other_prerequisites']}\n") + + f.write("\n## 7. Technical Information\n") + f.write(f"Hosting Environment (e.g., cloud provider, on-premise data center): {data['hosting_environment']}\n") + f.write(f"Network Requirements (e.g., ports, protocols, firewall rules): {data['network_requirements']}\n") + f.write(f"Data Storage Requirements (e.g., location, encryption, data retention policies): {data['data_storage_requirements']}\n") + f.write(f"Integration with Existing Systems (if any): {data['integration_existing_systems']}\n") + f.write(f"API Information (if applicable): {data['api_information']}\n") + + f.write("\n## 8. Security Requirements\n") + f.write(f"Data Security - How will data be protected in transit and at rest?: {data['data_protection']}\n") + f.write(f"Data Security - Does the software/vendor comply with relevant data privacy regulations (e.g., GDPR, CCPA)?: {data['data_privacy_compliance']}\n") + f.write(f"Data Security - What data encryption methods are used?: {data['data_encryption_methods']}\n") + f.write(f"Access Control - How will access to the software/vendor be granted and managed?: {data['access_control_management']}\n") + f.write(f"Access Control - Does the software/vendor support multi-factor authentication?: {data['multi_factor_authentication']}\n") + f.write(f"Access Control - What user roles and permissions are available?: {data['user_roles_permissions']}\n") + f.write(f"Vulnerability Management - Does the software/vendor have a vulnerability disclosure program?: {data['vulnerability_disclosure']}\n") + f.write(f"Vulnerability Management - How are security patches and updates managed?: {data['security_patch_management']}\n") + f.write(f"Vulnerability Management - Are regular security assessments and penetration testing conducted?: {data['security_assessments']}\n") + f.write(f"Compliance - Does the software/vendor comply with relevant industry security standards (e.g., ISO 27001, SOC 2)?: {data['industry_security_standards']}\n") + f.write(f"Compliance - Are there any third-party security certifications or audits available?: {data['third_party_certifications']}\n") + f.write(f"Business Continuity and Disaster Recovery - What are the software/vendor's business continuity and disaster recovery plans?: {data['business_continuity_plans']}\n") + f.write(f"Business Continuity and Disaster Recovery - What are the recovery time objectives (RTOs) and recovery point objectives (RPOs)?: {data['rto_rpo']}\n") + + f.write("\n## 9. Privacy Requirements\n") + f.write(f"Data Collection - What personal data will be collected by the software/vendor?: {data['personal_data_collected']}\n") + f.write(f"Data Collection - What is the purpose of collecting this data?: {data['data_collection_purpose']}\n") + f.write(f"Data Collection - Will data be shared with third parties? If so, with whom and for what purpose?: {data['data_sharing']}\n") + f.write(f"Data Subject Rights - How does the software/vendor ensure data subject rights (e.g., access, rectification, erasure)?: {data['data_subject_rights']}\n") + f.write(f"Data Subject Rights - Does the software/vendor provide a privacy policy that is readily accessible to users?: {data['privacy_policy']}\n") + + f.write("\n## 10. Legal and Contractual Requirements\n") + f.write(f"Software License Agreement: {data['license_agreement']}\n") + f.write(f"Service Level Agreement (SLA): {data['sla']}\n") + f.write(f"Data Processing Agreement (DPA): {data['dpa']}\n") + f.write(f"Vendor Security Policies: {data['vendor_security_policies']}\n") + + f.write("\n## 11. Risk Assessment\n") + f.write(f"Identify any potential security or privacy risks associated with the use of the software/vendor: {data['potential_risks']}\n") + f.write(f"Describe the risk mitigation measures that will be implemented: {data['risk_mitigation']}\n") + + f.write("\n## 12. Approval\n") + f.write("Security Analyst Review:\n") + f.write("Date of Review: \n") + f.write("Security Analyst Name: \n") + f.write("Security Assessment Findings: \n") + f.write("Approval Status (Approved, Conditionally Approved, Rejected): \n") + f.write("Management Approval (if required):\n") + f.write("Date of Approval: \n") + f.write("Approving Manager Name: \n") + + f.write("\n## 13. Supporting Documentation\n") + f.write("Attach any relevant supporting documentation, such as:\n") + f.write("- Vendor security questionnaires\n") + f.write("- Penetration testing reports\n") + f.write("- Security audit reports\n") + f.write("- Privacy impact assessments\n") + + +def main(): + """Collects assessment data from user input and generates documents.""" + + data = {} + + # 1. Requestor Information + data['requestor_name'] = input("Enter your name: ") + data['department'] = input("Enter your department: ") + data['email'] = input("Enter your email address: ") + data['phone'] = input("Enter your phone number: ") + + # 2. Request Type + print("\nRequest Type:") + print("1. New Software/Vendor") + print("2. Existing Software/Vendor (Renewal/Upgrade)") + print("3. Software/Vendor Decommissioning") + choice = input("Enter your choice (1-3): ") + request_types = { + "1": "New Software/Vendor", + "2": "Existing Software/Vendor (Renewal/Upgrade)", + "3": "Software/Vendor Decommissioning" + } + data['request_type'] = request_types.get(choice) + + # 3. Deployment Model + print("\nDeployment Model:") + print("1. SaaS (Software as a Service)") + print("2. IaaS (Infrastructure as a Service)") + print("3. PaaS (Platform as a Service)") + print("4. On-Premises (Internally Hosted)") + print("5. Hybrid") + print("6. Cloud-Hosted") + print("7. Other (Please Specify)") + choice = input("Enter your choice (1-7): ") + if choice == "7": + data['deployment_model'] = input("Specify the deployment model: ") + else: + deployment_models = { + "1": "SaaS (Software as a Service)", + "2": "IaaS (Infrastructure as a Service)", + "3": "PaaS (Platform as a Service)", + "4": "On-Premises (Internally Hosted)", + "5": "Hybrid", + "6": "Cloud-Hosted" + } + data['deployment_model'] = deployment_models.get(choice) + + # 4. Software/Vendor Information + data['vendor_name'] = input("Enter the Software/Vendor Name: ") + data['software_name'] = input("Enter the Software Name: ") + data['vendor_website'] = input("Enter the Software/Vendor Website: ") + data['vendor_contact'] = input("Enter the Software/Vendor Contact Information: ") + data['vendor_description'] = input("Enter a Brief Description of Software/Vendor and its Purpose: ") + + # 5. Intended Use + data['intended_use'] = input("Describe how the software/vendor will be used within the company: ") + data['departments_teams'] = input("Specify the departments or teams that will be using the software/vendor: ") + data['critical_processes_data'] = input("Identify any critical business processes or data that will be impacted by the software/vendor: ") + + # 6. Prerequisites + data['os_requirements'] = input("List any Operating System Requirements: ") + data['hardware_requirements'] = input("List any Hardware Requirements (e.g., RAM, storage space): ") + data['network_connectivity'] = input("List any Network Connectivity Requirements (e.g., bandwidth, VPN): ") + data['software_dependencies'] = input("List any Software Dependencies (e.g., libraries, frameworks): ") + data['user_access_requirements'] = input("List any User Access Requirements (e.g., specific roles, permissions): ") + data['other_prerequisites'] = input("List any Other Prerequisites: ") + + # 7. Technical Information + data['hosting_environment'] = input("Provide the Hosting Environment (e.g., cloud provider, on-premise data center): ") + data['network_requirements'] = input("Provide the Network Requirements (e.g., ports, protocols, firewall rules): ") + data['data_storage_requirements'] = input("Provide the Data Storage Requirements (e.g., location, encryption, data retention policies): ") + data['integration_existing_systems'] = input("Describe the Integration with Existing Systems (if any): ") + data['api_information'] = input("Provide API Information (if applicable): ") + + # 8. Security Requirements + data['data_protection'] = input("Data Security - How will data be protected in transit and at rest?: ") + data['data_privacy_compliance'] = input("Data Security - Does the software/vendor comply with relevant data privacy regulations (e.g., GDPR, CCPA)?: ") + data['data_encryption_methods'] = input("Data Security - What data encryption methods are used?: ") + data['access_control_management'] = input("Access Control - How will access to the software/vendor be granted and managed?: ") + data['multi_factor_authentication'] = input("Access Control - Does the software/vendor support multi-factor authentication?: ") + data['user_roles_permissions'] = input("Access Control - What user roles and permissions are available?: ") + data['vulnerability_disclosure'] = input("Vulnerability Management - Does the software/vendor have a vulnerability disclosure program?: ") + data['security_patch_management'] = input("Vulnerability Management - How are security patches and updates managed?: ") + data['security_assessments'] = input("Vulnerability Management - Are regular security assessments and penetration testing conducted?: ") + data['industry_security_standards'] = input("Compliance - Does the software/vendor comply with relevant industry security standards (e.g., ISO 27001, SOC 2)?: ") + data['third_party_certifications'] = input("Compliance - Are there any third-party security certifications or audits available?: ") + data['business_continuity_plans'] = input("Business Continuity and Disaster Recovery - What are the software/vendor's business continuity and disaster recovery plans?: ") + data['rto_rpo'] = input("Business Continuity and Disaster Recovery - What are the recovery time objectives (RTOs) and recovery point objectives (RPOs)?: ") + + # 9. Privacy Requirements + data['personal_data_collected'] = input("Data Collection - What personal data will be collected by the software/vendor?: ") + data['data_collection_purpose'] = input("Data Collection - What is the purpose of collecting this data?: ") + data['data_sharing'] = input("Data Collection - Will data be shared with third parties? If so, with whom and for what purpose?: ") + data['data_subject_rights'] = input("Data Subject Rights - How does the software/vendor ensure data subject rights (e.g., access, rectification, erasure)?: ") + data['privacy_policy'] = input("Data Subject Rights - Does the software/vendor provide a privacy policy that is readily accessible to users?: ") + + # 10. Legal and Contractual Requirements + data['license_agreement'] = input("Provide the Software License Agreement: ") + data['sla'] = input("Provide the Service Level Agreement (SLA): ") + data['dpa'] = input("Provide the Data Processing Agreement (DPA): ") + data['vendor_security_policies'] = input("Provide the Vendor Security Policies: ") + + # 11. Risk Assessment + data['potential_risks'] = input("Identify any potential security or privacy risks associated with the use of the software/vendor: ") + data['risk_mitigation'] = input("Describe the risk mitigation measures that will be implemented: ") + + # Generate a unique timestamp + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + + # Sanitize vendor/software name for filename + vendor_name = data['vendor_name'].replace(" ", "_").replace("/", "-") + software_name = data['software_name'].replace(" ", "_").replace("/", "-") + + # Create and save the Word document with unique filename + doc_filename = f"{vendor_name}_{software_name}_assessment_{timestamp}.docx" + doc = create_assessment_doc(data) + doc.save(doc_filename) + print(f"Word document saved as {doc_filename}") + + # Convert to PDF with unique filename + pdf_filename = f"{vendor_name}_{software_name}_assessment_{timestamp}.pdf" + convert(doc_filename, pdf_filename) + print(f"PDF document saved as {pdf_filename}") + + # Create Markdown file with unique filename + md_filename = f"{vendor_name}_{software_name}_assessment_{timestamp}.md" + create_markdown_file(data, md_filename) # Pass filename to function + print(f"Markdown file saved as {md_filename}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Transcoded File Scripts/Find duplicates/findanddelete.py b/Transcoded File Scripts/Find duplicates/findanddelete.py new file mode 100644 index 0000000..3749d31 --- /dev/null +++ b/Transcoded File Scripts/Find duplicates/findanddelete.py @@ -0,0 +1,70 @@ +import os +import csv +import shutil +from collections import defaultdict + +def find_duplicate_basenames(root_directory, valid_extensions): + # Dictionary to store basenames and their corresponding file paths + basenames_to_paths = defaultdict(list) + + # Traverse the directory tree + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + full_path = os.path.join(dirpath, filename) + basename, extension = os.path.splitext(filename) + if extension.lower() in valid_extensions: + basenames_to_paths[basename].append(full_path) + + # Filter basenames with more than one file + duplicate_basenames = {basename: paths for basename, paths in basenames_to_paths.items() if len(paths) > 1} + + return duplicate_basenames + +def get_file_size(path): + try: + return os.path.getsize(path) + except OSError: + return 0 + +def display_parent_levels(path, levels=2): + # Display 'levels' parent directories above the file path + components = path.split(os.sep) + return os.sep.join(components[-levels:]) + +def prompt_user_for_selection(paths): + print("Choose which file to keep:") + for i, path in enumerate(paths, start=1): + size_mb = get_file_size(path) / (1024 * 1024) + print(f"{i}. {display_parent_levels(path)} ({size_mb:.2f} MB)") + + while True: + try: + choice = int(input("Enter the number of the file to keep (or 0 to skip): ")) + if 0 <= choice <= len(paths): + return choice + else: + print("Invalid choice. Please enter a valid number.") + except ValueError: + print("Invalid input. Please enter a number.") + +if __name__ == "__main__": + server_directory = r"\\truenas\isolation\videos" # Replace with your server directory + video_extensions = {".mp4", ".mkv", ".avi", ".mov"} # Add more video extensions if needed + duplicate_files = find_duplicate_basenames(server_directory, video_extensions) + + if duplicate_files: + for basename, paths in duplicate_files.items(): + print(f"\nBasename: {basename}") + choice = prompt_user_for_selection(paths) + if choice == 0: + print("Skipping this duplicate set.") + else: + # Keep the selected file and delete the others + keep_path = paths[choice - 1] + for path in paths: + if path != keep_path: + print(f"Deleting: {display_parent_levels(path)}") + os.remove(path) + print("\nDuplicate files processed.") + else: + print("No duplicate video files found.") diff --git a/Transcoded File Scripts/Find duplicates/main.py b/Transcoded File Scripts/Find duplicates/main.py new file mode 100644 index 0000000..c9f4b46 --- /dev/null +++ b/Transcoded File Scripts/Find duplicates/main.py @@ -0,0 +1,41 @@ +import os +import csv +from collections import defaultdict + +def find_duplicate_basenames(root_directory, valid_extensions): + # Dictionary to store basenames and their corresponding file paths + basenames_to_paths = defaultdict(list) + + # Traverse the directory tree + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + full_path = os.path.join(dirpath, filename) + basename, extension = os.path.splitext(filename) + if extension.lower() in valid_extensions: + basenames_to_paths[basename].append(full_path) + + # Filter basenames with more than one file + duplicate_basenames = {basename: paths for basename, paths in basenames_to_paths.items() if len(paths) > 1} + + return duplicate_basenames + +def export_to_csv(duplicate_files, output_csv): + with open(output_csv, "w", newline="") as csvfile: + fieldnames = ["Basename", "File Paths"] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + for basename, paths in duplicate_files.items(): + writer.writerow({"Basename": basename, "File Paths": ", ".join(paths)}) + +if __name__ == "__main__": + server_directory = r"\\truenas\isolation\videos" # Replace with your server directory + video_extensions = {".mp4", ".mkv", ".avi", ".mov"} # Add more video extensions if needed + duplicate_files = find_duplicate_basenames(server_directory, video_extensions) + + if duplicate_files: + output_csv_file = "duplicate_video_files.csv" + export_to_csv(duplicate_files, output_csv_file) + print(f"Duplicate video files exported to {output_csv_file}") + else: + print("No duplicate video files found.") diff --git a/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/findanddelete.py b/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/findanddelete.py new file mode 100644 index 0000000..3749d31 --- /dev/null +++ b/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/findanddelete.py @@ -0,0 +1,70 @@ +import os +import csv +import shutil +from collections import defaultdict + +def find_duplicate_basenames(root_directory, valid_extensions): + # Dictionary to store basenames and their corresponding file paths + basenames_to_paths = defaultdict(list) + + # Traverse the directory tree + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + full_path = os.path.join(dirpath, filename) + basename, extension = os.path.splitext(filename) + if extension.lower() in valid_extensions: + basenames_to_paths[basename].append(full_path) + + # Filter basenames with more than one file + duplicate_basenames = {basename: paths for basename, paths in basenames_to_paths.items() if len(paths) > 1} + + return duplicate_basenames + +def get_file_size(path): + try: + return os.path.getsize(path) + except OSError: + return 0 + +def display_parent_levels(path, levels=2): + # Display 'levels' parent directories above the file path + components = path.split(os.sep) + return os.sep.join(components[-levels:]) + +def prompt_user_for_selection(paths): + print("Choose which file to keep:") + for i, path in enumerate(paths, start=1): + size_mb = get_file_size(path) / (1024 * 1024) + print(f"{i}. {display_parent_levels(path)} ({size_mb:.2f} MB)") + + while True: + try: + choice = int(input("Enter the number of the file to keep (or 0 to skip): ")) + if 0 <= choice <= len(paths): + return choice + else: + print("Invalid choice. Please enter a valid number.") + except ValueError: + print("Invalid input. Please enter a number.") + +if __name__ == "__main__": + server_directory = r"\\truenas\isolation\videos" # Replace with your server directory + video_extensions = {".mp4", ".mkv", ".avi", ".mov"} # Add more video extensions if needed + duplicate_files = find_duplicate_basenames(server_directory, video_extensions) + + if duplicate_files: + for basename, paths in duplicate_files.items(): + print(f"\nBasename: {basename}") + choice = prompt_user_for_selection(paths) + if choice == 0: + print("Skipping this duplicate set.") + else: + # Keep the selected file and delete the others + keep_path = paths[choice - 1] + for path in paths: + if path != keep_path: + print(f"Deleting: {display_parent_levels(path)}") + os.remove(path) + print("\nDuplicate files processed.") + else: + print("No duplicate video files found.") diff --git a/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/main.py b/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/main.py new file mode 100644 index 0000000..c9f4b46 --- /dev/null +++ b/Transcoded File Scripts/RMF Transcoded File Scripts/Find duplicates/main.py @@ -0,0 +1,41 @@ +import os +import csv +from collections import defaultdict + +def find_duplicate_basenames(root_directory, valid_extensions): + # Dictionary to store basenames and their corresponding file paths + basenames_to_paths = defaultdict(list) + + # Traverse the directory tree + for dirpath, dirnames, filenames in os.walk(root_directory): + for filename in filenames: + full_path = os.path.join(dirpath, filename) + basename, extension = os.path.splitext(filename) + if extension.lower() in valid_extensions: + basenames_to_paths[basename].append(full_path) + + # Filter basenames with more than one file + duplicate_basenames = {basename: paths for basename, paths in basenames_to_paths.items() if len(paths) > 1} + + return duplicate_basenames + +def export_to_csv(duplicate_files, output_csv): + with open(output_csv, "w", newline="") as csvfile: + fieldnames = ["Basename", "File Paths"] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + for basename, paths in duplicate_files.items(): + writer.writerow({"Basename": basename, "File Paths": ", ".join(paths)}) + +if __name__ == "__main__": + server_directory = r"\\truenas\isolation\videos" # Replace with your server directory + video_extensions = {".mp4", ".mkv", ".avi", ".mov"} # Add more video extensions if needed + duplicate_files = find_duplicate_basenames(server_directory, video_extensions) + + if duplicate_files: + output_csv_file = "duplicate_video_files.csv" + export_to_csv(duplicate_files, output_csv_file) + print(f"Duplicate video files exported to {output_csv_file}") + else: + print("No duplicate video files found.") diff --git a/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/did.py b/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/did.py new file mode 100644 index 0000000..25e2a3b --- /dev/null +++ b/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/did.py @@ -0,0 +1,182 @@ +import os +import re +import shutil +from pymediainfo import MediaInfo # You might need to install this: pip install pymediainfo + +# Define the network locations - KEEP THESE UNCHANGED as per user's original request +LOCATION1 = r"\\truenas\isolation\videos\redmilf_refresh" +LOCATION2 = r"\\truenas\isolation\videos\redmilf" +FINAL_LOCATION = r"\\truenas\isolation\videos\redmilf_final" # This is the final destination for ALL copied files + +# Ensure the final destination directory exists +os.makedirs(FINAL_LOCATION, exist_ok=True) + +def bytes_to_mb(bytes_value): + """Converts bytes to megabytes, rounded to two decimal places.""" + return round(bytes_value / (1024 * 1024), 2) + +def extract_did_number(filename): + """ + Extracts the DIDXXX or DIDXXXX number from a filename. + Returns the number as a string if found, otherwise None. + """ + # Regex to match DID followed by 3 or 4 digits + match = re.search(r"DID(\d{3,4})", filename, re.IGNORECASE) + if match: + return match.group(1) # Return the matched number string (e.g., "001" or "1234") + return None + +def get_file_info(filepath): + """ + Gets file size and attempts to get codec/bitrate using pymediainfo. + Returns a dictionary with 'size_bytes', 'size_mb', 'codec', 'bitrate'. + If mediainfo fails, 'codec' and 'bitrate' will be None. + """ + try: + size_bytes = os.path.getsize(filepath) + size_mb = bytes_to_mb(size_bytes) + media_info = MediaInfo.parse(filepath) + codec = None + bitrate = 0 # Use 0 as a default for comparison + + for track in media_info.tracks: + if track.track_type == 'Video': + if track.format: + codec = track.format + if track.bit_rate: + bitrate = track.bit_rate + break # Assuming one video track is sufficient + + return {"size_bytes": size_bytes, "size_mb": size_mb, "codec": codec, "bitrate": bitrate} + except Exception as e: + print(f"Warning: Could not get media info for {filepath}: {e}") + # Fallback if mediainfo fails + size_bytes = os.path.getsize(filepath) + size_mb = bytes_to_mb(size_bytes) + return {"size_bytes": size_bytes, "size_mb": size_mb, "codec": None, "bitrate": 0} + +def main(): + files_in_loc1 = {} + files_in_loc2 = {} + + print("Welcome to the DID Video Comparison and Management Script!") + print("\nDo you want to enable 'Auto-Run' mode?") + print("In 'Auto-Run' mode, the script will automatically:") + print(" 1. Keep the file with the larger size.") + print(f" 2. Use the filename from '{os.path.basename(LOCATION2)}' for the final copy.") + print("If you decline, you will be prompted for each file manually.") + + auto_run_choice = input("Enter 'yes' to enable Auto-Run, or 'no' to run manually (yes/no): ").strip().lower() + auto_run = (auto_run_choice == 'yes') + + if auto_run: + print("\nAuto-Run mode enabled. Processing files automatically.") + else: + print("\nManual mode selected. You will be prompted for each file.") + + # Objective 1: Identify files with the same naming convention + # Scan Location 1 + for root, _, files in os.walk(LOCATION1): + for file in files: + did_num = extract_did_number(file) # Changed function call + if did_num: + if did_num not in files_in_loc1: + files_in_loc1[did_num] = [] + files_in_loc1[did_num].append(os.path.join(root, file)) + + # Scan Location 2 + for root, _, files in os.walk(LOCATION2): + for file in files: + did_num = extract_did_number(file) # Changed function call + if did_num: + if did_num not in files_in_loc2: + files_in_loc2[did_num] = [] + files_in_loc2[did_num].append(os.path.join(root, file)) + + # Process matched files + matched_did_numbers = set(files_in_loc1.keys()).intersection(set(files_in_loc2.keys())) + + if not matched_did_numbers: + print(f"No matching DID files found in both '{LOCATION1}' and '{LOCATION2}'.") + return + + for did_num in sorted(list(matched_did_numbers)): + # Assuming only one file per DIDXXX/XXXX number per location for simplicity. + path1 = files_in_loc1[did_num][0] + path2 = files_in_loc2[did_num][0] + + file1_info = get_file_info(path1) + file2_info = get_file_info(path2) + + print(f"\n--- Processing DID{did_num} ---") + print(f" File 1 (from '{os.path.basename(os.path.dirname(path1))}'): {os.path.basename(path1)} (Size: {file1_info['size_mb']} MB, Codec: {file1_info['codec']}, Bitrate: {file1_info['bitrate']} bps)") + print(f" File 2 (from '{os.path.basename(os.path.dirname(path2))}'): {os.path.basename(path2)} (Size: {file2_info['size_mb']} MB, Codec: {file2_info['codec']}, Bitrate: {file2_info['bitrate']} bps)") + + + file_to_keep_path = None + final_filename = None + + if auto_run: + # Auto-run logic: keep larger size, use filename from Location 2 + if file1_info['size_bytes'] >= file2_info['size_bytes']: + file_to_keep_path = path1 + else: + file_to_keep_path = path2 + final_filename = os.path.basename(path2) # Always use filename from Location 2 + print(f" [Auto] Keeping: {os.path.basename(file_to_keep_path)}") + print(f" [Auto] Using filename: {final_filename}") + + else: # Manual mode + # Original objective 2: Compare size, quality, and codec and list the better file + recommended_better_path = None + # Prioritize bitrate for recommendation + if file1_info['bitrate'] > file2_info['bitrate']: + recommended_better_path = path1 + elif file2_info['bitrate'] > file1_info['bitrate']: + recommended_better_path = path2 + else: + # If bitrates are similar or unavailable, use size as a proxy for recommendation + if file1_info['size_bytes'] >= file2_info['size_bytes']: + recommended_better_path = path1 + else: + recommended_better_path = path2 + print(f" Recommended to keep: {os.path.basename(recommended_better_path)}") + + + # Original objective 3: Prompt the user which one they would like to keep + while True: + choice = input("Which file would you like to keep? (1/2): ").strip() + if choice == '1': + file_to_keep_path = path1 + break + elif choice == '2': + file_to_keep_path = path2 + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Original objective 4: Prompt the user for each file, which one's file name will be used for the final copy + while True: + name_choice = input(f"Which file's name would you like to use for the final copy of DID{did_num}? (1/2): ").strip() # Changed prompt + if name_choice == '1': + final_filename = os.path.basename(path1) + break + elif name_choice == '2': + final_filename = os.path.basename(path2) + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Objective 5: Copy the selected file to the new location with the chosen name + destination_path = os.path.join(FINAL_LOCATION, final_filename) + try: + print(f"Copying '{os.path.basename(file_to_keep_path)}' to '{destination_path}'...") + shutil.copy2(file_to_keep_path, destination_path) # copy2 preserves metadata + print("Copy successful!") + except Exception as e: + print(f"Error copying file {file_to_keep_path} to {destination_path}: {e}") + + print("\nComparison and copying process complete.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/main.py b/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/main.py new file mode 100644 index 0000000..edceed1 --- /dev/null +++ b/Transcoded File Scripts/RMF Transcoded File Scripts/rmf_compare/main.py @@ -0,0 +1,156 @@ +import os +import re +import shutil +from pymediainfo import MediaInfo # You might need to install this: pip install python-mediainfo + +# Define the network locations +LOCATION1 = r"\\truenas\isolation\videos\redmilf_refresh" +LOCATION2 = r"\\truenas\isolation\videos\redmilf" +FINAL_LOCATION = r"\\truenas\isolation\videos\redmilf_final" + +# Ensure the final destination directory exists +os.makedirs(FINAL_LOCATION, exist_ok=True) + +def extract_milf_number(filename): + """ + Extracts the MILFXXX number from a filename. + Returns the number as a string if found, otherwise None. + """ + match = re.search(r"MILF(\d{3})", filename, re.IGNORECASE) + if match: + return match.group(1) + return None + +def get_file_info(filepath): + """ + Gets file size and attempts to get codec/bitrate using pymediainfo. + Returns a dictionary with 'size', 'codec', 'bitrate'. + If mediainfo fails, 'codec' and 'bitrate' will be None. + """ + try: + size = os.path.getsize(filepath) + media_info = MediaInfo.parse(filepath) + codec = None + bitrate = 0 # Use 0 as a default for comparison + + for track in media_info.tracks: + if track.track_type == 'Video': + if track.format: + codec = track.format + if track.bit_rate: + bitrate = track.bit_rate + break # Assuming one video track is sufficient + + return {"size": size, "codec": codec, "bitrate": bitrate} + except Exception as e: + print(f"Warning: Could not get media info for {filepath}: {e}") + return {"size": os.path.getsize(filepath), "codec": None, "bitrate": 0} + +def determine_better_file(file1_info, file2_info, path1, path2): + """ + Compares two file infos to determine which one is 'better'. + Prioritizes bitrate (quality), then size if bitrate is similar or unavailable. + """ + print(f"\nComparing:") + print(f" File 1: {os.path.basename(path1)} (Size: {file1_info['size']} bytes, Codec: {file1_info['codec']}, Bitrate: {file1_info['bitrate']} bps)") + print(f" File 2: {os.path.basename(path2)} (Size: {file2_info['size']} bytes, Codec: {file2_info['codec']}, Bitrate: {file2_info['bitrate']} bps)") + + # Prioritize bitrate for quality + if file1_info['bitrate'] > file2_info['bitrate']: + return path1 + elif file2_info['bitrate'] > file1_info['bitrate']: + return path2 + else: + # If bitrates are similar or unavailable, use size as a proxy + if file1_info['size'] >= file2_info['size']: # Greater or equal size usually means better quality + return path1 + else: + return path2 + +def main(): + files_in_loc1 = {} + files_in_loc2 = {} + + # Objective 1: Identify files with the same naming convention + # Scan Location 1 + for root, _, files in os.walk(LOCATION1): + for file in files: + milf_num = extract_milf_number(file) + if milf_num: + if milf_num not in files_in_loc1: + files_in_loc1[milf_num] = [] + files_in_loc1[milf_num].append(os.path.join(root, file)) + + # Scan Location 2 + for root, _, files in os.walk(LOCATION2): + for file in files: + milf_num = extract_milf_number(file) + if milf_num: + if milf_num not in files_in_loc2: + files_in_loc2[milf_num] = [] + files_in_loc2[milf_num].append(os.path.join(root, file)) + + # Process matched files + matched_milf_numbers = set(files_in_loc1.keys()).intersection(set(files_in_loc2.keys())) + + if not matched_milf_numbers: + print("No matching MILF files found in both locations.") + return + + for milf_num in sorted(list(matched_milf_numbers)): + # Assuming only one file per MILFXXX number per location for simplicity. + # If multiple files with the same MILFXXX number exist in one location, + # this script will compare the first one it finds. + # For a more robust solution, you might need to handle this by comparing + # all permutations or selecting the "best" within each location first. + path1 = files_in_loc1[milf_num][0] + path2 = files_in_loc2[milf_num][0] + + # Objective 2: Compare size, quality, and codec and list the better file + file1_info = get_file_info(path1) + file2_info = get_file_info(path2) + + recommended_better_path = determine_better_file(file1_info, file2_info, path1, path2) + + # Objective 3: Prompt the user which one they would like to keep + print(f"\nFor MILF{milf_num}:") + print(f" Option 1 (from '{os.path.basename(os.path.dirname(path1))}'): {os.path.basename(path1)}") + print(f" Option 2 (from '{os.path.basename(os.path.dirname(path2))}'): {os.path.basename(path2)}") + print(f" Recommended: {os.path.basename(recommended_better_path)}") + + while True: + choice = input("Which file would you like to keep? (1/2): ").strip() + if choice == '1': + file_to_keep_path = path1 + break + elif choice == '2': + file_to_keep_path = path2 + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Objective 4: Prompt the user for each file, which one's file name will be used for the final copy + while True: + name_choice = input(f"Which file's name would you like to use for the final copy of MILF{milf_num}? (1/2): ").strip() + if name_choice == '1': + final_filename = os.path.basename(path1) + break + elif name_choice == '2': + final_filename = os.path.basename(path2) + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Objective 5: Copy the selected file to the new location with the chosen name + destination_path = os.path.join(FINAL_LOCATION, final_filename) + try: + print(f"Copying '{os.path.basename(file_to_keep_path)}' to '{destination_path}'...") + shutil.copy2(file_to_keep_path, destination_path) # copy2 preserves metadata + print("Copy successful!") + except Exception as e: + print(f"Error copying file {file_to_keep_path} to {destination_path}: {e}") + + print("\nComparison and copying process complete.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Transcoded File Scripts/RMF Transcoded File Scripts/transcode replacements/MAIN.py b/Transcoded File Scripts/RMF Transcoded File Scripts/transcode replacements/MAIN.py new file mode 100644 index 0000000..3f0cbc3 --- /dev/null +++ b/Transcoded File Scripts/RMF Transcoded File Scripts/transcode replacements/MAIN.py @@ -0,0 +1,182 @@ +import os +import re +import shutil +from pymediainfo import MediaInfo # You might need to install this: pip install pymediainfo + +# Define the network locations +LOCATION1 = r"\\truenas\isolation\videos\redmilf_refresh" +LOCATION2 = r"\\truenas\isolation\videos\redmilf" +FINAL_LOCATION = r"\\truenas\isolation\videos\redmilf_final" + +# Ensure the final destination directory exists +os.makedirs(FINAL_LOCATION, exist_ok=True) + +def bytes_to_mb(bytes_value): + """Converts bytes to megabytes, rounded to two decimal places.""" + return round(bytes_value / (1024 * 1024), 2) + +def extract_milf_number(filename): + """ + Extracts the MILFXXX or MILFXXXX number from a filename. + Returns the number as a string if found, otherwise None. + """ + # Updated regex to match MILF followed by 3 or 4 digits + match = re.search(r"MILF(\d{3,4})", filename, re.IGNORECASE) + if match: + return match.group(1) # Return the matched number string (e.g., "001" or "1234") + return None + +def get_file_info(filepath): + """ + Gets file size and attempts to get codec/bitrate using pymediainfo. + Returns a dictionary with 'size_bytes', 'size_mb', 'codec', 'bitrate'. + If mediainfo fails, 'codec' and 'bitrate' will be None. + """ + try: + size_bytes = os.path.getsize(filepath) + size_mb = bytes_to_mb(size_bytes) + media_info = MediaInfo.parse(filepath) + codec = None + bitrate = 0 # Use 0 as a default for comparison + + for track in media_info.tracks: + if track.track_type == 'Video': + if track.format: + codec = track.format + if track.bit_rate: + bitrate = track.bit_rate + break # Assuming one video track is sufficient + + return {"size_bytes": size_bytes, "size_mb": size_mb, "codec": codec, "bitrate": bitrate} + except Exception as e: + print(f"Warning: Could not get media info for {filepath}: {e}") + # Fallback if mediainfo fails + size_bytes = os.path.getsize(filepath) + size_mb = bytes_to_mb(size_bytes) + return {"size_bytes": size_bytes, "size_mb": size_mb, "codec": None, "bitrate": 0} + +def main(): + files_in_loc1 = {} + files_in_loc2 = {} + + print("Welcome to the MILF Video Comparison and Management Script!") + print("\nDo you want to enable 'Auto-Run' mode?") + print("In 'Auto-Run' mode, the script will automatically:") + print(" 1. Keep the file with the larger size.") + print(f" 2. Use the filename from '{os.path.basename(LOCATION2)}' for the final copy.") + print("If you decline, you will be prompted for each file manually.") + + auto_run_choice = input("Enter 'yes' to enable Auto-Run, or 'no' to run manually (yes/no): ").strip().lower() + auto_run = (auto_run_choice == 'yes') + + if auto_run: + print("\nAuto-Run mode enabled. Processing files automatically.") + else: + print("\nManual mode selected. You will be prompted for each file.") + + # Objective 1: Identify files with the same naming convention + # Scan Location 1 + for root, _, files in os.walk(LOCATION1): + for file in files: + milf_num = extract_milf_number(file) + if milf_num: + if milf_num not in files_in_loc1: + files_in_loc1[milf_num] = [] + files_in_loc1[milf_num].append(os.path.join(root, file)) + + # Scan Location 2 + for root, _, files in os.walk(LOCATION2): + for file in files: + milf_num = extract_milf_number(file) + if milf_num: + if milf_num not in files_in_loc2: + files_in_loc2[milf_num] = [] + files_in_loc2[milf_num].append(os.path.join(root, file)) + + # Process matched files + matched_milf_numbers = set(files_in_loc1.keys()).intersection(set(files_in_loc2.keys())) + + if not matched_milf_numbers: + print("No matching MILF files found in both locations.") + return + + for milf_num in sorted(list(matched_milf_numbers)): + # Assuming only one file per MILFXXX/XXXX number per location for simplicity. + path1 = files_in_loc1[milf_num][0] + path2 = files_in_loc2[milf_num][0] + + file1_info = get_file_info(path1) + file2_info = get_file_info(path2) + + print(f"\n--- Processing MILF{milf_num} ---") + print(f" File 1 (from '{os.path.basename(os.path.dirname(path1))}'): {os.path.basename(path1)} (Size: {file1_info['size_mb']} MB, Codec: {file1_info['codec']}, Bitrate: {file1_info['bitrate']} bps)") + print(f" File 2 (from '{os.path.basename(os.path.dirname(path2))}'): {os.path.basename(path2)} (Size: {file2_info['size_mb']} MB, Codec: {file2_info['codec']}, Bitrate: {file2_info['bitrate']} bps)") + + + file_to_keep_path = None + final_filename = None + + if auto_run: + # Auto-run logic: keep larger size, use filename from Location 2 + if file1_info['size_bytes'] >= file2_info['size_bytes']: + file_to_keep_path = path1 + else: + file_to_keep_path = path2 + final_filename = os.path.basename(path2) # Always use filename from Location 2 + print(f" [Auto] Keeping: {os.path.basename(file_to_keep_path)}") + print(f" [Auto] Using filename: {final_filename}") + + else: # Manual mode + # Original objective 2: Compare size, quality, and codec and list the better file + recommended_better_path = None + # Prioritize bitrate for recommendation + if file1_info['bitrate'] > file2_info['bitrate']: + recommended_better_path = path1 + elif file2_info['bitrate'] > file1_info['bitrate']: + recommended_better_path = path2 + else: + # If bitrates are similar or unavailable, use size as a proxy for recommendation + if file1_info['size_bytes'] >= file2_info['size_bytes']: + recommended_better_path = path1 + else: + recommended_better_path = path2 + print(f" Recommended to keep: {os.path.basename(recommended_better_path)}") + + + # Original objective 3: Prompt the user which one they would like to keep + while True: + choice = input("Which file would you like to keep? (1/2): ").strip() + if choice == '1': + file_to_keep_path = path1 + break + elif choice == '2': + file_to_keep_path = path2 + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Original objective 4: Prompt the user for each file, which one's file name will be used for the final copy + while True: + name_choice = input(f"Which file's name would you like to use for the final copy of MILF{milf_num}? (1/2): ").strip() + if name_choice == '1': + final_filename = os.path.basename(path1) + break + elif name_choice == '2': + final_filename = os.path.basename(path2) + break + else: + print("Invalid choice. Please enter '1' or '2'.") + + # Objective 5: Copy the selected file to the new location with the chosen name + destination_path = os.path.join(FINAL_LOCATION, final_filename) + try: + print(f"Copying '{os.path.basename(file_to_keep_path)}' to '{destination_path}'...") + shutil.copy2(file_to_keep_path, destination_path) # copy2 preserves metadata + print("Copy successful!") + except Exception as e: + print(f"Error copying file {file_to_keep_path} to {destination_path}: {e}") + + print("\nComparison and copying process complete.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Transcoded File Scripts/transcode replacements/MAIN.py b/Transcoded File Scripts/transcode replacements/MAIN.py new file mode 100644 index 0000000..d9ffa02 --- /dev/null +++ b/Transcoded File Scripts/transcode replacements/MAIN.py @@ -0,0 +1,114 @@ +import sqlite3 +import csv +import os +from datetime import datetime + +# Function to convert Linux path to Windows path and replace specific substring +def convert_path(path): + return path.replace("/", "\\").replace("\\data\\", "\\\\truenas\\isolation\\videos\\") + +# Fileshare path +fileshare_path = r"\\truenas\isolation\stashapp\generated\transcodes" + +# SQLite database path +db_path = r"\\servervm\main\appdata\stashapp\config\stash-go.sqlite" + +# Create a folder for the attempt with current date and time +folder_name = "Attempt_" + datetime.now().strftime("%Y%m%d_%H%M%S") +os.makedirs(folder_name) + +# Connect to SQLite database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Error handling for gathering basenames +try: + # List all file basenames (without extensions) from fileshare path + basenames = [os.path.splitext(name)[0] for name in os.listdir(fileshare_path)] +except FileNotFoundError: + print(f"Error: Fileshare path '{fileshare_path}' not found.") + exit() +except PermissionError: + print(f"Error: Permission denied accessing fileshare path '{fileshare_path}'.") + exit() + +# Check if there are no basenames +if not basenames: + print("Error: No basenames found in the fileshare path.") + exit() + +# Construct the IN clause for the query +placeholders = ",".join(['"{}"'.format(b) for b in basenames]) + +# Construct the query +query_template = """ +SELECT f.*, ff.*, fo.path +FROM files AS f +INNER JOIN files_fingerprints AS ff ON f.id = ff.file_id +INNER JOIN folders AS fo ON f.parent_folder_id = fo.id +WHERE ff.fingerprint IN ({}); +""" + +# Execute query +cursor.execute(query_template.format(placeholders)) +rows = cursor.fetchall() + +# Check if there are any results +if len(rows) == 0: + print("No results found.") + exit() + +# Export result to CSV +csv_path = os.path.join(folder_name, "result.csv") +with open(csv_path, "w", newline="", encoding="utf-8") as csv_file: + csv_writer = csv.writer(csv_file) + csv_writer.writerow([i[0] for i in cursor.description]) # Write header + csv_writer.writerows(rows) + +# Create new CSV with additional columns +new_rows = [] +for row in rows: + converted_path = convert_path(row[-1]) + full_file_path_video = os.path.join(converted_path, row[1]) # Construct full file path for videos + + # Original filename from transcodes directory + original_filename = os.path.join(fileshare_path, str(row[10])) # Assuming the fingerprint ID is in the 11th column (index 10) + + new_rows.append((full_file_path_video, original_filename + ".mp4")) # Append ".mp4" to the second column + +# Write new CSV +new_csv_path = os.path.join(folder_name, "new_result.csv") +with open(new_csv_path, "w", newline="", encoding="utf-8") as csv_file: + csv_writer = csv.writer(csv_file) + csv_writer.writerow(["Full File Path (Videos)", "Original File Path (Transcodes)"]) + csv_writer.writerows(new_rows) + +# Confirm with the user +print("CSV files created successfully in folder:", folder_name) +print("Do you want to proceed to replace the files in column 1 with the files in column 2?") +user_input = input("Enter 'yes' to proceed, or any other key to cancel: ") + +if user_input.lower() == 'yes': + print("Proceeding to replace the files...") + + # Prepare to replace files + for original_file, new_file in new_rows: + original_basename = os.path.basename(original_file) + original_dirname = os.path.dirname(original_file) + new_basename = os.path.basename(new_file) + new_dirname = os.path.dirname(new_file) + + # Remove existing file if exists + if os.path.exists(original_file): + os.remove(original_file) + + # Move the new file to replace the original file + try: + os.rename(new_file, os.path.join(original_dirname, original_basename)) + print(f"Replaced '{original_basename}' with '{new_basename}'.") + except FileNotFoundError: + print(f"Error: '{new_basename}' not found. Skipped replacement.") + + print("Replacement completed.") +else: + print("Replacement canceled.") diff --git a/nginx/deluge.datdamdavid.com.conf b/nginx/deluge.datdamdavid.com.conf new file mode 100644 index 0000000..3302a94 --- /dev/null +++ b/nginx/deluge.datdamdavid.com.conf @@ -0,0 +1,21 @@ +server { + listen 80; + server_name deluge.datdamdavid.com; + + location / { + proxy_pass http://truenas:8112; + proxy_redirect off; + } +} + +server { + listen 443; + server_name deluge.datdamdavid.com; + ssl_certificate /etc/nginx/ssl/deluge.datdamdavid.com.crt; + ssl_certificate_key /etc/nginx/ssl/deluge.datdamdavid.com.key; + + location / { + proxy_pass http://truenas:8112; + proxy_redirect off; + } +} \ No newline at end of file diff --git a/nginx/gitea b/nginx/gitea new file mode 100644 index 0000000..0517f0d --- /dev/null +++ b/nginx/gitea @@ -0,0 +1,15 @@ +server { + listen 80; + server_name git.datdamdavid.com; # Replace with your actual domain + + location / { + proxy_pass http://192.168.1.254:30008; # Corrected IP address + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + # Additional headers if needed (e.g., for websockets) + # proxy_set_header Upgrade $upgrade; + # proxy_set_header Connection "upgrade"; + } +} \ No newline at end of file diff --git a/nginx/jellyseer.datdamdavid.com.conf b/nginx/jellyseer.datdamdavid.com.conf new file mode 100644 index 0000000..b3d6e93 --- /dev/null +++ b/nginx/jellyseer.datdamdavid.com.conf @@ -0,0 +1,21 @@ +server { + listen 80; + server_name jellyseer.datdamdavid.com; + + location / { + proxy_pass http://truenas:30042; + proxy_redirect off; + } +} + +server { + listen 443; + server_name jellyseer.datdamdavid.com; + ssl_certificate /etc/nginx/ssl/jellyseer.datdamdavid.com.crt; + ssl_certificate_key /etc/nginx/ssl/jellyseer.datdamdavid.com.key; + + location / { + proxy_pass http://truenas:30042; + proxy_redirect off; + } +} \ No newline at end of file