update from lal-10
This commit is contained in:
@@ -66,6 +66,11 @@ then
|
||||
LS_TYPE=bsd
|
||||
fi
|
||||
|
||||
if [ -x "$(command -v aws)" ]
|
||||
then
|
||||
alias aws='AWS_PROFILE=$(cat ~/.aws/.profile) aws'
|
||||
fi
|
||||
|
||||
if ! limited_terminal
|
||||
then
|
||||
if [ -x "$(command -v lsd)" ]
|
||||
|
||||
@@ -58,9 +58,9 @@ prompt_cmd() {
|
||||
echo -n "]"
|
||||
fi
|
||||
fi
|
||||
if [ -x "$(which aws-creds)" ]
|
||||
if [ -x "$(which aws)" ]
|
||||
then
|
||||
awsprofile=$(aws-creds 2>/dev/null)
|
||||
awsprofile=$(cat ~/.aws/.profile)
|
||||
if [ ! -z "$awsprofile" ]
|
||||
then
|
||||
tput setaf $BASE_COLOR
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
"CopilotChat.nvim": { "branch": "main", "commit": "3d16702149d61d0c0b84a72756e6d2a65f3f30a8" },
|
||||
"LuaSnip": { "branch": "master", "commit": "ccf25a5452b8697a823de3e5ecda63ed3d723b79" },
|
||||
"NvChad": { "branch": "v2.5", "commit": "f107fabe11ac8013dc3435ecd5382bee872b1584" },
|
||||
"base46": { "branch": "v3.0", "commit": "db58475d3fd2a16f9b1467d6895e3c4c195ed7dd" },
|
||||
"base46": { "branch": "v2.5", "commit": "fde7a2cd54599e148d376f82980407c2d24b0fa2" },
|
||||
"cmp-async-path": { "branch": "main", "commit": "0ed1492f59e730c366d261a5ad822fa37e44c325" },
|
||||
"cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" },
|
||||
"cmp-nvim-lsp": { "branch": "main", "commit": "bd5a7d6db125d4654b50eeae9f5217f24bb22fd3" },
|
||||
"cmp-nvim-lua": { "branch": "main", "commit": "f12408bdb54c39c23e67cab726264c10db33ada8" },
|
||||
"cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" },
|
||||
"conform.nvim": { "branch": "master", "commit": "9fd3d5e0b689ec1bf400c53cbbec72c6fdf24081" },
|
||||
"conform.nvim": { "branch": "master", "commit": "26c02e1155a4980900bdccabca4516f4c712aae9" },
|
||||
"ctrlsf-ui.nvim": { "branch": "main", "commit": "4afee49d999946f25b84de004aeec857f094fb6c" },
|
||||
"ctrlsf.vim": { "branch": "master", "commit": "50186c529c881b7844bcd66c7b8e9826eb8990a4" },
|
||||
"friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" },
|
||||
"gitsigns.nvim": { "branch": "main", "commit": "20ad4419564d6e22b189f6738116b38871082332" },
|
||||
"indent-blankline.nvim": { "branch": "master", "commit": "005b56001b2cb30bfa61b7986bc50657816ba4ba" },
|
||||
"lazy.nvim": { "branch": "main", "commit": "f0f5bbb9e5bfae5e6468f9359ffea3d151418176" },
|
||||
"lazy.nvim": { "branch": "main", "commit": "202d8e92b3a74ac88eb3a7f1e40fb59b4c2a6535" },
|
||||
"lazygit.nvim": { "branch": "main", "commit": "2305deed25bc61b866d5d39189e9105a45cf1cfb" },
|
||||
"luarocks.nvim": { "branch": "main", "commit": "1db9093915eb16ba2473cfb8d343ace5ee04130a" },
|
||||
"mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" },
|
||||
@@ -34,7 +34,7 @@
|
||||
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
|
||||
"nvim-web-devicons": { "branch": "master", "commit": "8dcb311b0c92d460fac00eac706abd43d94d68af" },
|
||||
"plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
|
||||
"schemastore.nvim": { "branch": "main", "commit": "8d37e8eb0e48712c823f959beaecf0b3a7a01e75" },
|
||||
"schemastore.nvim": { "branch": "main", "commit": "1b894a46cff15b95f62fc639ccb9081bb90abef0" },
|
||||
"tagbar": { "branch": "master", "commit": "7bfffca1f121afb7a9e38747500bf5270e006bb1" },
|
||||
"telescope.nvim": { "branch": "master", "commit": "b4da76be54691e854d3e0e02c36b0245f945c2c7" },
|
||||
"todo-comments.nvim": { "branch": "main", "commit": "411503d3bedeff88484de572f2509c248e499b38" },
|
||||
|
||||
45
home/any/scripts/bin/aws-profile
Executable file
45
home/any/scripts/bin/aws-profile
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PROFILE_FILE=~/.aws/.profile
|
||||
AWS_CONFIG=~/.aws/config
|
||||
PROFILE_LIST_CMD="grep -P '^\[profile .+\]' $AWS_CONFIG | perl -pe 's/\[profile (\S+)\]/\1/'"
|
||||
|
||||
current_profile="< none >"
|
||||
|
||||
if [ -f $PROFILE_FILE ]
|
||||
then
|
||||
current_profile="$(cat $PROFILE_FILE)"
|
||||
fi
|
||||
|
||||
deisred_profile=""
|
||||
profile_list=$(eval "$PROFILE_LIST_CMD")
|
||||
|
||||
if [ -x "$(command -v fzf)" ]
|
||||
then
|
||||
deisred_profile=$(echo "$profile_list" | fzf)
|
||||
else
|
||||
echo "$profile_list"
|
||||
echo
|
||||
read -p "Which Profile to use?: " deisred_profile
|
||||
fi
|
||||
|
||||
if [ -n "$deisred_profile" ]
|
||||
then
|
||||
if ! grep -qP "^${deisred_profile}$" <(echo "$profile_list")
|
||||
then
|
||||
echo "Invalid Profile Selected!"
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
echo "No Profile Selected."
|
||||
exit 3
|
||||
fi
|
||||
echo
|
||||
|
||||
if [[ "$current_profile" == "$deisred_profile" ]]
|
||||
then
|
||||
echo "Profile Unchanged ($current_profile == $deisred_profile)"
|
||||
else
|
||||
echo "Swtiching from $current_profile --> $deisred_profile"
|
||||
echo "$deisred_profile" > $PROFILE_FILE
|
||||
fi
|
||||
404
home/any/scripts/bin/inspect-cert
Executable file
404
home/any/scripts/bin/inspect-cert
Executable file
@@ -0,0 +1,404 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SSL/TLS Certificate Inspector
|
||||
Fetches and displays certificate details from HTTPS endpoints
|
||||
"""
|
||||
|
||||
import ssl
|
||||
import socket
|
||||
import sys
|
||||
from datetime import datetime
|
||||
import argparse
|
||||
from urllib.parse import urlparse
|
||||
import subprocess
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
def get_certificate(hostname, port=443, timeout=10):
|
||||
"""
|
||||
Fetch SSL certificate from a given hostname and port
|
||||
Even if the certificate is invalid
|
||||
"""
|
||||
# Create an SSL context that doesn't verify certificates
|
||||
context = ssl.create_default_context()
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
# Store verification errors if any
|
||||
verification_errors = []
|
||||
|
||||
# Try to verify the certificate separately to report issues
|
||||
try:
|
||||
verify_context = ssl.create_default_context()
|
||||
with socket.create_connection((hostname, port), timeout=timeout) as sock:
|
||||
with verify_context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
pass # If we get here, cert is valid
|
||||
except ssl.SSLError as e:
|
||||
verification_errors.append(str(e))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Now get the certificate without verification
|
||||
with socket.create_connection((hostname, port), timeout=timeout) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
# Get certificate in binary form (always works)
|
||||
der_cert = ssock.getpeercert(binary_form=True)
|
||||
pem_cert = ssl.DER_cert_to_PEM_cert(der_cert)
|
||||
|
||||
# Get cipher info
|
||||
cipher_info = ssock.cipher()
|
||||
version_info = ssock.version()
|
||||
|
||||
# Parse the certificate using OpenSSL or manual parsing
|
||||
cert_details = parse_certificate_details(pem_cert)
|
||||
|
||||
return cert_details, pem_cert, verification_errors, cipher_info, version_info
|
||||
|
||||
def parse_certificate_details(pem_cert):
|
||||
"""
|
||||
Parse certificate details from PEM certificate
|
||||
"""
|
||||
details = {}
|
||||
|
||||
# First try using OpenSSL command if available
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.pem', delete=False) as f:
|
||||
f.write(pem_cert)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
# Run openssl to get certificate text
|
||||
result = subprocess.run(
|
||||
['openssl', 'x509', '-in', temp_path, '-text', '-noout'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
details = parse_openssl_text(result.stdout)
|
||||
else:
|
||||
# Try with -inform DER if PEM didn't work
|
||||
result = subprocess.run(
|
||||
['openssl', 'x509', '-in', temp_path, '-inform', 'PEM', '-text', '-noout'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
details = parse_openssl_text(result.stdout)
|
||||
|
||||
except (subprocess.SubprocessError, FileNotFoundError):
|
||||
# OpenSSL not available, try basic parsing
|
||||
details = basic_parse_pem(pem_cert)
|
||||
|
||||
finally:
|
||||
try:
|
||||
os.unlink(temp_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
details = basic_parse_pem(pem_cert)
|
||||
|
||||
return details
|
||||
|
||||
def parse_openssl_text(text):
|
||||
"""
|
||||
Parse the output of openssl x509 -text
|
||||
"""
|
||||
import re
|
||||
|
||||
details = {}
|
||||
|
||||
# Parse subject
|
||||
subject_match = re.search(r'Subject:\s*(.+?)(?=\n\s+)', text)
|
||||
if subject_match:
|
||||
details['subject'] = subject_match.group(1).strip()
|
||||
|
||||
# Parse issuer
|
||||
issuer_match = re.search(r'Issuer:\s*(.+?)(?=\n)', text)
|
||||
if issuer_match:
|
||||
details['issuer'] = issuer_match.group(1).strip()
|
||||
|
||||
# Parse serial number
|
||||
serial_match = re.search(r'Serial Number:\s*\n?\s*([a-fA-F0-9:\s]+?)(?=\n)', text)
|
||||
if serial_match:
|
||||
serial = serial_match.group(1).strip().replace(':', '').replace(' ', '').upper()
|
||||
details['serialNumber'] = serial
|
||||
|
||||
# Parse signature algorithm
|
||||
sig_algo_match = re.search(r'Signature Algorithm:\s*(.+?)(?=\n)', text)
|
||||
if sig_algo_match:
|
||||
details['signatureAlgorithm'] = sig_algo_match.group(1).strip()
|
||||
|
||||
# Parse validity dates
|
||||
not_before_match = re.search(r'Not Before:\s*(.+?)(?=\n)', text)
|
||||
if not_before_match:
|
||||
details['notBefore'] = not_before_match.group(1).strip()
|
||||
|
||||
not_after_match = re.search(r'Not After\s*:\s*(.+?)(?=\n)', text)
|
||||
if not_after_match:
|
||||
details['notAfter'] = not_after_match.group(1).strip()
|
||||
|
||||
# Parse version
|
||||
version_match = re.search(r'Version:\s*(\d+)', text)
|
||||
if version_match:
|
||||
details['version'] = version_match.group(1)
|
||||
|
||||
# Parse Subject Alternative Name
|
||||
san_section = re.search(r'X509v3 Subject Alternative Name:\s*(?:critical\s*)?\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text)
|
||||
if san_section:
|
||||
san_text = san_section.group(1).strip()
|
||||
# Clean up the SANs
|
||||
sans = re.findall(r'(DNS|IP|email|URI):([^,\s]+)', san_text)
|
||||
if sans:
|
||||
details['subjectAltName'] = ', '.join([f"{t}:{v}" for t, v in sans])
|
||||
|
||||
# Parse Key Usage
|
||||
key_usage_match = re.search(r'X509v3 Key Usage:\s*(?:critical\s*)?\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text)
|
||||
if key_usage_match:
|
||||
details['keyUsage'] = key_usage_match.group(1).strip()
|
||||
|
||||
# Parse Extended Key Usage
|
||||
ext_key_usage_match = re.search(r'X509v3 Extended Key Usage:\s*\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text)
|
||||
if ext_key_usage_match:
|
||||
details['extKeyUsage'] = ext_key_usage_match.group(1).strip()
|
||||
|
||||
# Parse Authority Key Identifier
|
||||
auth_key_match = re.search(r'X509v3 Authority Key Identifier:\s*\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text)
|
||||
if auth_key_match:
|
||||
details['authorityKeyIdentifier'] = auth_key_match.group(1).strip().replace('\n', ' ')
|
||||
|
||||
# Parse Subject Key Identifier
|
||||
subj_key_match = re.search(r'X509v3 Subject Key Identifier:\s*\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text)
|
||||
if subj_key_match:
|
||||
details['subjectKeyIdentifier'] = subj_key_match.group(1).strip()
|
||||
|
||||
# Parse OCSP
|
||||
ocsp_match = re.search(r'OCSP - URI:(.+?)(?=\n|$)', text)
|
||||
if ocsp_match:
|
||||
details['OCSP'] = ocsp_match.group(1).strip()
|
||||
|
||||
# Parse CA Issuers
|
||||
ca_issuers_match = re.search(r'CA Issuers - URI:(.+?)(?=\n|$)', text)
|
||||
if ca_issuers_match:
|
||||
details['caIssuers'] = ca_issuers_match.group(1).strip()
|
||||
|
||||
# Parse CRL Distribution Points
|
||||
crl_match = re.search(r'X509v3 CRL Distribution Points:\s*\n\s*(.+?)(?=\n\s*[A-Z]|\n\s*$)', text, re.DOTALL)
|
||||
if crl_match:
|
||||
crl_text = crl_match.group(1).strip()
|
||||
crl_uris = re.findall(r'URI:(.+?)(?=\n|$)', crl_text)
|
||||
if crl_uris:
|
||||
details['crlDistributionPoints'] = ', '.join(crl_uris)
|
||||
|
||||
return details
|
||||
|
||||
def basic_parse_pem(pem_cert):
|
||||
"""
|
||||
Basic parsing when OpenSSL is not available
|
||||
"""
|
||||
import base64
|
||||
import re
|
||||
|
||||
details = {}
|
||||
|
||||
# Extract base64 content
|
||||
cert_match = re.search(r'-----BEGIN CERTIFICATE-----\s*(.+?)\s*-----END CERTIFICATE-----',
|
||||
pem_cert, re.DOTALL)
|
||||
|
||||
if cert_match:
|
||||
details['format'] = 'X.509 Certificate (PEM encoded)'
|
||||
# We can't parse much without additional libraries
|
||||
details['note'] = 'Install OpenSSL for detailed parsing: apt-get install openssl'
|
||||
|
||||
return details
|
||||
|
||||
def format_certificate_details(details, verification_errors, cipher_info, version_info):
|
||||
"""
|
||||
Format certificate details for display
|
||||
"""
|
||||
output = []
|
||||
|
||||
# Add verification status
|
||||
if verification_errors:
|
||||
output.append(("⚠️ Certificate Status", "INVALID/UNTRUSTED"))
|
||||
for error in verification_errors:
|
||||
output.append((" Verification Error", error))
|
||||
else:
|
||||
output.append(("✓ Certificate Status", "VALID"))
|
||||
|
||||
output.append(("", "")) # Empty line
|
||||
|
||||
# Certificate details
|
||||
if 'subject' in details:
|
||||
output.append(("Subject", details['subject']))
|
||||
|
||||
if 'issuer' in details:
|
||||
output.append(("Issuer", details['issuer']))
|
||||
|
||||
if 'serialNumber' in details:
|
||||
output.append(("Serial Number", details['serialNumber']))
|
||||
|
||||
if 'signatureAlgorithm' in details:
|
||||
output.append(("Signature Algorithm", details['signatureAlgorithm']))
|
||||
|
||||
if 'version' in details:
|
||||
output.append(("Version", details['version']))
|
||||
|
||||
# Validity
|
||||
if 'notBefore' in details:
|
||||
output.append(("Valid From", details['notBefore']))
|
||||
|
||||
if 'notAfter' in details:
|
||||
output.append(("Valid Until", details['notAfter']))
|
||||
|
||||
# Try to calculate expiry
|
||||
try:
|
||||
# Parse various date formats
|
||||
for fmt in ['%b %d %H:%M:%S %Y %Z', '%b %d %H:%M:%S %Y %Z']:
|
||||
try:
|
||||
expiry_date = datetime.strptime(details['notAfter'], fmt)
|
||||
days_remaining = (expiry_date - datetime.now()).days
|
||||
if days_remaining > 0:
|
||||
output.append(("Days Until Expiry", f"{days_remaining} days"))
|
||||
if days_remaining < 30:
|
||||
output.append((" ⚠️ Warning", "Certificate expires soon!"))
|
||||
else:
|
||||
output.append((" ⚠️ Expiry Status", f"EXPIRED ({abs(days_remaining)} days ago)"))
|
||||
break
|
||||
except:
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
|
||||
# Extensions
|
||||
if 'subjectAltName' in details:
|
||||
output.append(("Subject Alt Names", details['subjectAltName']))
|
||||
|
||||
if 'keyUsage' in details:
|
||||
output.append(("Key Usage", details['keyUsage']))
|
||||
|
||||
if 'extKeyUsage' in details:
|
||||
output.append(("Extended Key Usage", details['extKeyUsage']))
|
||||
|
||||
if 'authorityKeyIdentifier' in details:
|
||||
output.append(("Authority Key ID", details['authorityKeyIdentifier'][:50] + '...'
|
||||
if len(details['authorityKeyIdentifier']) > 50
|
||||
else details['authorityKeyIdentifier']))
|
||||
|
||||
if 'subjectKeyIdentifier' in details:
|
||||
output.append(("Subject Key ID", details['subjectKeyIdentifier']))
|
||||
|
||||
# OCSP and CRL
|
||||
if 'OCSP' in details:
|
||||
output.append(("OCSP", details['OCSP']))
|
||||
|
||||
if 'caIssuers' in details:
|
||||
output.append(("CA Issuers", details['caIssuers']))
|
||||
|
||||
if 'crlDistributionPoints' in details:
|
||||
output.append(("CRL Distribution Points", details['crlDistributionPoints']))
|
||||
|
||||
# Note if limited parsing
|
||||
if 'note' in details:
|
||||
output.append(("", ""))
|
||||
output.append(("Note", details['note']))
|
||||
|
||||
return output
|
||||
|
||||
def print_certificate_details(hostname, port, cert_details, verification_errors,
|
||||
cipher_info, version_info, pem_cert, show_pem):
|
||||
"""
|
||||
Print certificate details in a formatted way
|
||||
"""
|
||||
print("=" * 80)
|
||||
print(f"SSL/TLS Certificate Details for {hostname}:{port}")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
# Connection info
|
||||
if version_info:
|
||||
print(f"TLS Version: {version_info}")
|
||||
if cipher_info:
|
||||
print(f"Cipher Suite: {cipher_info[0]} ({cipher_info[2]} bits)")
|
||||
print()
|
||||
|
||||
# Format and print details
|
||||
output = format_certificate_details(cert_details, verification_errors, cipher_info, version_info)
|
||||
|
||||
if output:
|
||||
max_label_length = max(len(label) for label, _ in output if label)
|
||||
|
||||
for label, value in output:
|
||||
if label:
|
||||
print(f"{label:<{max_label_length + 2}}: {value}")
|
||||
else:
|
||||
print()
|
||||
|
||||
# Show PEM if requested or if parsing failed
|
||||
if show_pem or not cert_details or 'note' in cert_details:
|
||||
print()
|
||||
print("=" * 80)
|
||||
print("PEM Certificate:")
|
||||
print("=" * 80)
|
||||
print(pem_cert)
|
||||
|
||||
def parse_url_or_hostname(input_str):
|
||||
"""
|
||||
Parse input string to extract hostname and port
|
||||
"""
|
||||
port = 443
|
||||
|
||||
if '://' in input_str:
|
||||
parsed = urlparse(input_str)
|
||||
hostname = parsed.hostname
|
||||
if parsed.port:
|
||||
port = parsed.port
|
||||
else:
|
||||
if ':' in input_str:
|
||||
parts = input_str.rsplit(':', 1)
|
||||
hostname = parts[0]
|
||||
try:
|
||||
port = int(parts[1])
|
||||
except ValueError:
|
||||
hostname = input_str
|
||||
else:
|
||||
hostname = input_str
|
||||
|
||||
return hostname, port
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Fetch and display SSL/TLS certificate details from HTTPS endpoints'
|
||||
)
|
||||
|
||||
parser.add_argument('target', help='Target hostname, hostname:port, or HTTPS URL')
|
||||
parser.add_argument('--show-pem', action='store_true', help='Always show the PEM certificate')
|
||||
parser.add_argument('--timeout', type=int, default=10, help='Connection timeout (default: 10)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
hostname, port = parse_url_or_hostname(args.target)
|
||||
|
||||
print(f"Fetching certificate from {hostname}:{port}...")
|
||||
print("Note: Certificate validation is disabled to show all certificate details")
|
||||
print()
|
||||
|
||||
cert_details, pem_cert, verification_errors, cipher_info, version_info = get_certificate(
|
||||
hostname, port, args.timeout
|
||||
)
|
||||
|
||||
print_certificate_details(
|
||||
hostname, port, cert_details, verification_errors,
|
||||
cipher_info, version_info, pem_cert, args.show_pem
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user