diff --git a/Vulnerability_Tool/Identified Vulnerabilities Report.docx b/Vulnerability_Tool/Identified Vulnerabilities Report.docx deleted file mode 100644 index af11626..0000000 Binary files a/Vulnerability_Tool/Identified Vulnerabilities Report.docx and /dev/null differ diff --git a/Vulnerability_Tool/Vulnerability Report.docx b/Vulnerability_Tool/Vulnerability Report.docx deleted file mode 100644 index 4aed10b..0000000 Binary files a/Vulnerability_Tool/Vulnerability Report.docx and /dev/null differ diff --git a/Vulnerability_Tool/Vulnerability_Scanner_V1.1.py b/Vulnerability_Tool/Vulnerability_Scanner_V1.1.py deleted file mode 100644 index cabe7cc..0000000 --- a/Vulnerability_Tool/Vulnerability_Scanner_V1.1.py +++ /dev/null @@ -1,113 +0,0 @@ -# Importing modules to assist with vulnerability scanning and detecting -import os -import re - -# Define text Colour -class Colour: - GREEN = '\033[92m' - RED = '\033[91m' - BLUE = '\033[94m' - YELLOW = '\033[93m' - V_PATTEN_NAME = '\033[38;5;208m' # Orange names - NORMAL = '\033[0m' - -# Define Vulnerability Pattern -V_Patterns = { - "Sql_Injection": re.compile(r'\.query\s*\(.*\+.*\)'), - "XSS": re.compile(r'res\.send\s*\(.*\+.*\)'), - "Command_Injection": re.compile(r'exec\s*\(.*\+.*\)'), - "insecure_file_handling": re.compile(r'fs\.unlink\s*\(.*\)'), - "insecure_file_upload": re.compile(r'multer\s*\(\s*{.*dest.*}\s*\)'), -# New Vulnerability Pattern identifications Added in "V1.1" - "Eval_Function": re.compile(r'eval\s*\(.*\)'), - "Directory_Movement": re.compile(r'fs\.readFile\s*\(.*\.\.\/.*\)'), - "Insecure_Token_Generation": re.compile(r'Math\.random\s*\(\)'), - "Dangerous_Permission_Level": re.compile(r'fs\.chmod\s*\(.*\)'), - "Redirects": re.compile(r'res\.redirect\s*\(.*req\.query\..*\)') - -} -# Opening the files for processing -def AnalyseFile(FileLocation): - vulnerabilities = {key: [] for key in V_Patterns.keys()} - try: - with open(FileLocation, 'r', encoding='utf-8') as file: - Data = file.read() - except Exception as e: - print(f"Error reading file {FileLocation}: {e}") - return None - -# Check for vulnerabilities based on pre set V_Patterns - for key, pattern in V_Patterns.items(): - matches = pattern.findall(Data) - if matches: - vulnerabilities[key].extend(matches) - - return vulnerabilities - -# Formatting files for list -def list_files(): - return [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.js')] - -def OrderedF(Dataset): - print("|--------------------------------|\n| JavaScript files for Analysis: |\n|--------------------------------|") - for i, file in enumerate(Dataset, 1): - print(f"{i} - {file}") - -# Result box for outcome of vulnerability scan -def PrintOutcome(Data): - Outside = max(len(line) for line in Data.splitlines()) + 4 - print('|' + '-' * (Outside - 2) + '|') - for line in Data.splitlines(): - print(f"| {line.ljust(Outside - 4)} |") - print('|' + '-' * (Outside - 2) + '|') - -# Catches not JavaScript files in directory -def main(): - Dataset = list_files() - if not Dataset: - print("No .js files found") - return - -# Terminate program when "end" is entered in - while True: - OrderedF(Dataset) - User_Input = input("\nPlease enter a file number from the listed options\nor\nType 'end' to quit the application \n> ") - if User_Input == 'end': - break - -# Catches an input ouside of the file number range - try: - file_index = int(User_Input) - 1 - if file_index < 0 or file_index >= len(Dataset): - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease enter the file number from the listed options") - continue - - JsFile = Dataset[file_index] - print(f"{Colour.YELLOW}\nAnalysing: {Colour.NORMAL}{JsFile}") - vulnerabilities = AnalyseFile(JsFile) - -# This should not get called. However, is left here to future proof the application - if not vulnerabilities: - Outcome = f"Could not read file: {JsFile}" - -# No vulnerabilities have been located - elif not any(vulnerabilities.values()): - Outcome = f"{Colour.GREEN}No vulnerabilities found.{Colour.NORMAL}" - -# Lists the potentiaal vulnerability found - else: - Outcome = f"{Colour.RED}Potential Vulnerability Found: {Colour.NORMAL}\n" - for key, found in vulnerabilities.items(): - if found: - Outcome += f"{Colour.V_PATTEN_NAME} {key.replace('_', ' ').title()} vulnerabilities:{Colour.NORMAL}\n" - for q in found: - Outcome += f" - {q}\n" - -# Print Result - PrintOutcome(Outcome) -# Triggers invalid input - chance to try again - except ValueError: - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease Input a number.") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Vulnerability_Tool/Vulnerability_Scanner_V1.2.py b/Vulnerability_Tool/Vulnerability_Scanner_V1.2.py deleted file mode 100644 index 1e931ba..0000000 --- a/Vulnerability_Tool/Vulnerability_Scanner_V1.2.py +++ /dev/null @@ -1,119 +0,0 @@ -# Importing modules to assist with vulnerability scanning and detecting -import os -import re - -# Define text Colour -class Colour: - GREEN = '\033[92m' - RED = '\033[91m' - BLUE = '\033[94m' - YELLOW = '\033[93m' - V_PATTEN_NAME = '\033[38;5;208m' # Orange names - NORMAL = '\033[0m' - -# Define Vulnerability Pattern -V_Patterns = { - "Sql_Injection": re.compile(r'\.query\s*\(.*\+.*\)'), - "XSS": re.compile(r'res\.send\s*\(.*\+.*\)'), - "Command_Injection": re.compile(r'exec\s*\(.*\+.*\)'), - "insecure_file_handling": re.compile(r'fs\.unlink\s*\(.*\)'), - "insecure_file_upload": re.compile(r'multer\s*\(\s*{.*dest.*}\s*\)'), -# New Vulnerability Pattern Identifications Added in "V1.1" - "Eval_Function": re.compile(r'eval\s*\(.*\)'), - "Directory_Movement": re.compile(r'fs\.readFile\s*\(.*\.\.\/.*\)'), - "Insecure_Token_Generation": re.compile(r'Math\.random\s*\(\)'), - "Dangerous_Permission_Level": re.compile(r'fs\.chmod\s*\(.*\)'), - "Redirects": re.compile(r'res\.redirect\s*\(.*req\.query\..*\)'), -# New Vulnerability Pattern Identifications Added in "V1.2" - "API_Key_Hardcoded": re.compile(r'api_key\s*=\s*[\'"].*[\'"]'), - "Weak_Hashing_Algorithm": re.compile(r'(md5|sha1|des)\s*\('), - "Plainetext_Credentials": re.compile(r'(username|password)\s*=\s*[\'"].*[\'"]'), - "Insecure_SSL_Configeration": re.compile(r'server\.listen\s*\(.*http.*\)'), - "HTTP_Called": re.compile(r'http\.get\s*\(.*\)') - -} -# Opening the files for processing -def AnalyseFile(FileLocation): - vulnerabilities = {key: [] for key in V_Patterns.keys()} - try: - with open(FileLocation, 'r', encoding='utf-8') as file: - Data = file.read() - except Exception as e: - print(f"Error reading file {FileLocation}: {e}") - return None - -# Check for vulnerabilities based on pre set V_Patterns - for key, pattern in V_Patterns.items(): - matches = pattern.findall(Data) - if matches: - vulnerabilities[key].extend(matches) - - return vulnerabilities - -# Formatting files for list -def list_files(): - return [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.js')] - -def OrderedF(Dataset): - print("|--------------------------------|\n| JavaScript files for Analysis: |\n|--------------------------------|") - for i, file in enumerate(Dataset, 1): - print(f"{i} - {file}") - -# Result box for outcome of vulnerability scan -def PrintOutcome(Data): - Outside = max(len(line) for line in Data.splitlines()) + 4 - print('|' + '-' * (Outside - 2) + '|') - for line in Data.splitlines(): - print(f"| {line.ljust(Outside - 4)} |") - print('|' + '-' * (Outside - 2) + '|') - -# Catches not JavaScript files in directory -def main(): - Dataset = list_files() - if not Dataset: - print("No .js files found") - return - -# Terminate program when "end" is entered in - while True: - OrderedF(Dataset) - User_Input = input("\nPlease enter a file number from the listed options\nor\nType 'end' to quit the application \n> ") - if User_Input == 'end': - break - -# Catches an input ouside of the file number range - try: - file_index = int(User_Input) - 1 - if file_index < 0 or file_index >= len(Dataset): - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease enter the file number from the listed options") - continue - - JsFile = Dataset[file_index] - print(f"{Colour.YELLOW}\nAnalysing: {Colour.NORMAL}{JsFile}") - vulnerabilities = AnalyseFile(JsFile) - -# This should not get called. However, is left here to future proof the application - if not vulnerabilities: - Outcome = f"Could not read file: {JsFile}" - -# No vulnerabilities have been located - elif not any(vulnerabilities.values()): - Outcome = f"{Colour.GREEN}No vulnerabilities found.{Colour.NORMAL}" - -# Lists the potentiaal vulnerability found - else: - Outcome = f"{Colour.RED}Potential Vulnerability Found: {Colour.NORMAL}\n" - for key, found in vulnerabilities.items(): - if found: - Outcome += f"{Colour.V_PATTEN_NAME} {key.replace('_', ' ').title()} vulnerabilities:{Colour.NORMAL}\n" - for q in found: - Outcome += f" - {q}\n" - -# Print Result - PrintOutcome(Outcome) -# Triggers invalid input - chance to try again - except ValueError: - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease Input a number.") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Vulnerability_Tool/Vulnerability_Scanner_V1.3.py b/Vulnerability_Tool/Vulnerability_Scanner_V1.3.py deleted file mode 100644 index b1828c8..0000000 --- a/Vulnerability_Tool/Vulnerability_Scanner_V1.3.py +++ /dev/null @@ -1,125 +0,0 @@ -# Importing modules to assist with vulnerability scanning and detecting -import os -import re - -# Define text Colour -class Colour: - GREEN = '\033[92m' - RED = '\033[91m' - BLUE = '\033[94m' - YELLOW = '\033[93m' - V_PATTEN_NAME = '\033[38;5;208m' # Orange names - NORMAL = '\033[0m' - -# Define Vulnerability Pattern -V_Patterns = { - "Sql_Injection": re.compile(r'\.query\s*\(.*\+.*\)'), - "XSS": re.compile(r'res\.send\s*\(.*\+.*\)'), - "Command_Injection": re.compile(r'exec\s*\(.*\+.*\)'), - "insecure_file_handling": re.compile(r'fs\.unlink\s*\(.*\)'), - "insecure_file_upload": re.compile(r'multer\s*\(\s*{.*dest.*}\s*\)'), -# New Vulnerability Pattern Identifications Added in "V1.1" - "Eval_Function": re.compile(r'eval\s*\(.*\)'), - "Directory_Movement": re.compile(r'fs\.readFile\s*\(.*\.\.\/.*\)'), - "Insecure_Token_Generation": re.compile(r'Math\.random\s*\(\)'), - "Dangerous_Permission_Level": re.compile(r'fs\.chmod\s*\(.*\)'), - "Redirects": re.compile(r'res\.redirect\s*\(.*req\.query\..*\)'), -# New Vulnerability Pattern Identifications Added in "V1.2" - "API_Key_Hardcoded": re.compile(r'api_key\s*=\s*[\'"].*[\'"]'), - "Weak_Hashing_Algorithm": re.compile(r'(md5|sha1|des)\s*\('), - "Planetext_Credentials": re.compile(r'(username|password)\s*=\s*[\'"].*[\'"]'), - "Insecure_SSL_Configeration": re.compile(r'server\.listen\s*\(.*http.*\)'), - "HTTP_Called": re.compile(r'http\.get\s*\(.*\)'), -# New Vulnerability Pattern Identifications Added in "V1.3" - "Sensitive_Data_Logging": re.compile(r'console\.(log|debug|error|warn)\s*\(.*(password|secret|key|token).*\)'), - "JSON_Parsing_No_Validation": re.compile(r'JSON\.parse\s*\(.*req\.(body|query|params).*\)'), - "Environment_Variables_In_Planetext": re.compile(r'process\.env\.[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*[\'"].+[\'"]'), - "Debug_Left_Exposed": re.compile(r'app\.get\s*\([\'"].*debug.*[\'"],.*\)'), - "Insecure_File_Paths": re.compile(r'(fs\.(readFile|writeFile))\s*\(.*req\.(body|query|params)\.path.*\)'), - "Unsecured_Spawn": re.compile(r'spawn\s*\(.*\)') -} -# Opening the files for processing -def AnalyseFile(FileLocation): - vulnerabilities = {key: [] for key in V_Patterns.keys()} - try: - with open(FileLocation, 'r', encoding='utf-8') as file: - Data = file.read() - except Exception as e: - print(f"Error reading file {FileLocation}: {e}") - return None - -# Check for vulnerabilities based on pre set V_Patterns - for key, pattern in V_Patterns.items(): - matches = pattern.findall(Data) - if matches: - vulnerabilities[key].extend(matches) - - return vulnerabilities - -# Formatting files for list -def list_files(): - return [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.js')] - -def OrderedF(Dataset): - print("|--------------------------------|\n| JavaScript files for Analysis: |\n|--------------------------------|") - for i, file in enumerate(Dataset, 1): - print(f"{i} - {file}") - -# Result box for outcome of vulnerability scan -def PrintOutcome(Data): - Outside = max(len(line) for line in Data.splitlines()) + 4 - print('|' + '-' * (Outside - 2) + '|') - for line in Data.splitlines(): - print(f"| {line.ljust(Outside - 4)} |") - print('|' + '-' * (Outside - 2) + '|') - -# Catches not JavaScript files in directory -def main(): - Dataset = list_files() - if not Dataset: - print("No .js files found") - return - -# Terminate program when "end" is entered in - while True: - OrderedF(Dataset) - User_Input = input("\nPlease enter a file number from the listed options\nor\nType 'end' to quit the application \n> ") - if User_Input == 'end': - break - -# Catches an input ouside of the file number range - try: - file_index = int(User_Input) - 1 - if file_index < 0 or file_index >= len(Dataset): - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease enter the file number from the listed options") - continue - - JsFile = Dataset[file_index] - print(f"{Colour.YELLOW}\nAnalysing: {Colour.NORMAL}{JsFile}") - vulnerabilities = AnalyseFile(JsFile) - -# This should not get called. However, is left here to future proof the application - if not vulnerabilities: - Outcome = f"Could not read file: {JsFile}" - -# No vulnerabilities have been located - elif not any(vulnerabilities.values()): - Outcome = f"{Colour.GREEN}No vulnerabilities found.{Colour.NORMAL}" - -# Lists the potentiaal vulnerability found - else: - Outcome = f"{Colour.RED}Potential Vulnerability Found: {Colour.NORMAL}\n" - for key, found in vulnerabilities.items(): - if found: - Outcome += f"{Colour.V_PATTEN_NAME} {key.replace('_', ' ').title()} vulnerabilities:{Colour.NORMAL}\n" - for q in found: - Outcome += f" - {q}\n" - -# Print Result - PrintOutcome(Outcome) -# Triggers invalid input - chance to try again - except ValueError: - print(f"\n{Colour.BLUE}|---------------|\n| Invalid input |\n|---------------|{Colour.NORMAL}\nPlease Input a number.") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Vulnerability_Tool/Vulnerability_Scanner_V1.4.py b/Vulnerability_Tool/Vulnerability_Scanner_V1.4.py deleted file mode 100644 index c50e28c..0000000 --- a/Vulnerability_Tool/Vulnerability_Scanner_V1.4.py +++ /dev/null @@ -1,160 +0,0 @@ -import os -import re -import sys -import docx - -# Define Vulnerability Patterns for JavaScript files -JS_Patterns = { - "Sql_Injection": re.compile(r'\.query\s*\(.*\+.*\)'), - "XSS": re.compile(r'res\.send\s*\(.*\+.*\)'), - "Command_Injection": re.compile(r'exec\s*\(.*\+.*\)'), - "insecure_file_handling": re.compile(r'fs\.unlink\s*\(.*\)'), - "insecure_file_upload": re.compile(r'multer\s*\(\s*{.*dest.*}\s*\)'), - "Eval_Function": re.compile(r'eval\s*\(.*\)'), - "Directory_Movement": re.compile(r'fs\.readFile\s*\(.*\.\./.*\)'), - "Insecure_Token_Generation": re.compile(r'Math\.random\s*\(\)'), - "Dangerous_Permission_Level": re.compile(r'fs\.chmod\s*\(.*\)'), - "Redirects": re.compile(r'res\.redirect\s*\(.*req\.query\..*\)'), - "API_Key_Hardcoded": re.compile(r'api_key\s*=\s*[\'"]\S+[\'"]'), - "Weak_Hashing_Algorithm": re.compile(r'(md5|sha1|des)\s*\('), - "Planetext_Credentials": re.compile(r'(username|password)\s*=\s*[\'"]\S+[\'"]'), - "Insecure_SSL_Config": re.compile(r'server\.listen\s*\(.*http.*\)'), - "HTTP_Called": re.compile(r'http\.get\s*\(.*\)'), - "Sensitive_Data_Logging": re.compile(r'console\.(log|debug|error|warn)\s*\(.*(password|secret|key|token).*\)'), - "JSON_Parsing_No_Validation": re.compile(r'JSON\.parse\s*\(.*req\.(body|query|params).*\)'), - "Environment_Variables_In_Planetext": re.compile(r'process\.env\.[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*[\'"]\S+[\'"]'), - "Debug_Left_Exposed": re.compile(r'app\.get\s*\([\'"]\.\*/debug.*[\'"]'), - "Insecure_File_Paths": re.compile(r'(fs\.(readFile|writeFile))\s*\(.*req\.(body|query|params)\.path.*\)'), - "Unsecured_Spawn": re.compile(r'spawn\s*\(.*\)') -} - -Python_Patterns = { - "Eval_Function": re.compile(r'eval\s*\(.*\)'), - "Exec_Function": re.compile(r'exec\s*\(.*\)'), - "OS_Command_Injection": re.compile(r'os\.(system|popen)\s*\(.*\)'), - "Subprocess_Injection": re.compile(r'subprocess\.(Popen|call|run)\s*\(.*\)'), - "Pickle_Load": re.compile(r'pickle\.load\s*\(.*\)'), - "Hardcoded_Credentials": re.compile(r'(username|password)\s*=\s*[\'"]\S+[\'"]'), - "Weak_Hashing_Algorithm": re.compile(r'(md5|sha1|des)\s*\('), - "Insecure_Random": re.compile(r'random\.randint\s*\(.*\)'), - "Unverified_SSL": re.compile(r'requests\.get\s*\(.*verify\s*=\s*False\)'), - "Dangerous_File_Access": re.compile(r'open\s*\(.*\)'), - "Environment_Variables_Exposure": re.compile(r'os\.environ\[\s*[\'"]\S+[\'"]\s*\]'), - "Debug_Logging": re.compile(r'print\s*\(.*(password|secret|key|token).*\)'), - "Deserialization_Risk": re.compile(r'json\.loads\s*\(.*\)'), - "Unsecured_Spawn": re.compile(r'os\.spawn\s*\(.*\)') -} - -Word_Patterns = { - "Hardcoded_Credentials": re.compile(r'(username|password)\s*=\s*[\'"]\S+[\'"]'), - "Sensitive_Keywords": re.compile(r'(confidential|private|classified|top secret)', re.IGNORECASE), - "Email_Addresses": re.compile(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'), - "Phone_Numbers": re.compile(r'\b(?:\+\d{1,3})?[-.\s]?(\d{2,4})?[-.\s]?\d{3}[-.\s]?\d{4}\b'), - "URLs": re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+') -} - -TXT_Patterns = { - "Hardcoded_Credentials": re.compile(r'(username|password|token|secret|access[_-]?key)\s*[:=]\s*[\'"]?\S+[\'"]?', re.IGNORECASE), - "Sensitive_Keywords": re.compile(r'\b(confidential|private|classified|secret|token|proprietary)\b', re.IGNORECASE), - "Email_Addresses": re.compile(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'), - "URLs": re.compile(r'https?://[^\s]+'), - "IP_Addresses": re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b'), - "AWS_Credentials": re.compile(r'AKIA[0-9A-Z]{16}'), - "API_Keys": re.compile(r'(?i)(api[_-]?key|access[_-]?token)\s*[:=]\s*[\'"]?[A-Za-z0-9\-_]{20,}'), - "JWT_Tokens": re.compile(r'eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}\.[A-Za-z0-9._-]{10,}') -} - -YML_Patterns = { - "Hardcoded_Credentials": re.compile(r'(username|password|token|secret|access[_-]?key)\s*:\s*[\'"]?\S+[\'"]?', re.IGNORECASE), - "Sensitive_Keywords": re.compile(r'\b(confidential|private|classified|secret|proprietary)\b', re.IGNORECASE), - "Email_Addresses": re.compile(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'), - "URLs": re.compile(r'https?://[^\s]+'), - "IP_Addresses": re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b'), - "AWS_Credentials": re.compile(r'AKIA[0-9A-Z]{16}'), - "API_Keys": re.compile(r'(?i)(api[_-]?key|access[_-]?token)\s*:\s*[\'"]?[A-Za-z0-9\-_]{20,}'), - "Unsafe_YAML_Object": re.compile(r'!!python/(object|module|function)') -} - - -def AnalyseFile(FileLocation, patterns): - vulnerabilities = {key: [] for key in patterns.keys()} - try: - with open(FileLocation, 'r', encoding='utf-8') as file: - Data = file.read() - except Exception as e: - print(f"Error reading file {FileLocation}: {e}") - return None - for key, pattern in patterns.items(): - matches = pattern.findall(Data) - if matches: - vulnerabilities[key].extend(matches) - return vulnerabilities - -def AnalyseWordFile(FileLocation): - vulnerabilities = {key: [] for key in Word_Patterns.keys()} - try: - doc = docx.Document(FileLocation) - text_data = "\n".join([para.text for para in doc.paragraphs]) - except Exception as e: - print(f"Error reading file {FileLocation}: {e}") - return None - for key, pattern in Word_Patterns.items(): - matches = pattern.findall(text_data) - if matches: - vulnerabilities[key].extend(matches) - return vulnerabilities - -def get_modified_files(): - return os.getenv("MODIFIED_FILES", "").split() - -def PrintOutcome(Data): - Outside = max(len(line) for line in Data.splitlines()) + 4 - print('|' + '-' * (Outside - 2) + '|') - for line in Data.splitlines(): - print(f"| {line.ljust(Outside - 4)} |") - print('|' + '-' * (Outside - 2) + '|') - -def main(): - modified_files = get_modified_files() - if not modified_files: - print("No modified files detected.") - return - for file in modified_files: - if not os.path.exists(file): - print(f"File not found: {file}") - continue - print(f"Detected new file: {file}") - if file.endswith(".js"): - print(f"Scanning {file} for vulnerabilities...") - patterns = JS_Patterns - vulnerabilities = AnalyseFile(file, patterns) - elif file.endswith(".py"): - print(f"Scanning {file} for vulnerabilities...") - patterns = Python_Patterns - vulnerabilities = AnalyseFile(file, patterns) - elif file.endswith(".docx"): - print(f"Scanning {file} for vulnerabilities...") - vulnerabilities = AnalyseWordFile(file) - elif file.endswith(".txt"): - print(f"Scanning {file} for vulnerabilities...") - vulnerabilities = AnalyseFile(file, TXT_Patterns) - elif file.endswith(".yml") or file.endswith("yaml"): - print(f"Scanning {file} for vulnerabilities...") - vulnerabilities = AnalyseFile(file, YML_Patterns) - else: - print(f"{file} is not a JavaScript, Python or Word file. Skipping...") - continue - - if vulnerabilities and any(vulnerabilities.values()): - Outcome = f"Potential Vulnerability Found in {file}:\n" - for key, found in vulnerabilities.items(): - if found: - Outcome += f" {key.replace('_', ' ').title()} vulnerabilities:\n" - for q in found: - Outcome += f" - {q}\n" - else: - Outcome = f"No vulnerabilities found in {file}." - PrintOutcome(Outcome) - -if __name__ == "__main__": - main() diff --git a/package-lock.json b/package-lock.json index c33089a..9a34dfd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,6 +76,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2420,6 +2421,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", @@ -3345,6 +3347,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", diff --git a/server.js b/server.js index c91bd1b..cc3eb4d 100644 --- a/server.js +++ b/server.js @@ -9,7 +9,7 @@ console.log(''); const express = require("express"); const { errorLogger, responseTimeLogger } = require('./middleware/errorLogger'); -const FRONTEND_ORIGIN = "http://localhost:3000"; +const FRONTEND_ORIGIN = "http://localhost:3000"; const helmet = require('helmet'); const cors = require("cors"); @@ -66,23 +66,13 @@ app.use('/api/system', systemRoutes); // CORS app.use(cors({ - origin: (origin, callback) => { - if (!origin) return callback(null, true); - - if ( - origin.startsWith("http://localhost") || - origin.startsWith("http://127.0.0.1") || - origin.startsWith("http://localhost") - ) { - callback(null, true); - } else { - callback(new Error(`CORS blocked: ${origin}`)); - } - }, - credentials: true + origin: FRONTEND_ORIGIN, + credentials: true, + methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], + allowedHeaders: ["Content-Type", "Authorization"] })); app.options("*", cors({ origin: FRONTEND_ORIGIN, credentials: true })); -app.use((req, res, next) => { res.header("Access-Control-Allow-Credentials","true"); next(); }); +app.use((req, res, next) => { res.header("Access-Control-Allow-Credentials", "true"); next(); }); app.set("trust proxy", 1); // Security @@ -90,8 +80,8 @@ app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], - scriptSrc: ["'self'","'unsafe-inline'","https://cdn.jsdelivr.net"], - styleSrc: ["'self'","'unsafe-inline'","https://cdn.jsdelivr.net"], + scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"], + styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"], objectSrc: ["'none'"], }, }, @@ -134,16 +124,16 @@ app.use(errorLogger); // Final error handler app.use((err, req, res, next) => { - const status = err.status || 500; - const message = process.env.NODE_ENV === 'production' - ? 'Internal Server Error' - : err.message; - - res.status(status).json({ - success: false, - error: message, - timestamp: new Date().toISOString() - }); + const status = err.status || 500; + const message = process.env.NODE_ENV === 'production' + ? 'Internal Server Error' + : err.message; + + res.status(status).json({ + success: false, + error: message, + timestamp: new Date().toISOString() + }); }); // Global error handler @@ -152,17 +142,19 @@ process.on('uncaughtException', uncaughtExceptionHandler); process.on('unhandledRejection', unhandledRejectionHandler); // Start -app.listen(port, async () => { - +if (require.main === module) { + app.listen(port, async () => { + console.log('\nšŸŽ‰ NutriHelp API launched successfully!'); + console.log('='.repeat(50)); + console.log(`Server is running on port ${port}`); + console.log(`šŸ“š Swagger UI: http://localhost/api-docs`); + console.log('='.repeat(50)); + console.log('šŸ’” Press Ctrl+C to stop the server \n'); + exec(`start http://localhost:${port}/api-docs`); + }); +} - console.log('\nšŸŽ‰ NutriHelp API launched successfully!'); - console.log('='.repeat(50)); - console.log(`Server is running on port ${port}`); - console.log(`šŸ“š Swagger UI: http://localhost/api-docs`); - console.log('='.repeat(50)); - console.log('šŸ’” Press Ctrl+C to stop the server \n'); - exec(`start http://localhost:${port}/api-docs`); -}); +module.exports = app; app.use(express.json({ limit: "50mb" })); app.use(express.urlencoded({ limit: "50mb", extended: true })); diff --git a/services/authService.js b/services/authService.js index db0f437..14960ae 100644 --- a/services/authService.js +++ b/services/authService.js @@ -1,17 +1,12 @@ console.log("🟢 Loaded AuthService from:", __filename); -const { createClient } = require('@supabase/supabase-js'); +const supabase = require('../dbConnection'); const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); const crypto = require('crypto'); -const supabase = createClient( - process.env.SUPABASE_URL, - process.env.SUPABASE_ANON_KEY -); - class AuthService { constructor() { - this.accessTokenExpiry = '15m'; // 15 minutes + this.accessTokenExpiry = '10m'; // 10 minutes this.refreshTokenExpiry = 7 * 24 * 60 * 60 * 1000; // 7 days } @@ -45,7 +40,7 @@ class AuthService { password: hashedPassword, first_name, last_name, - role_id: 7, + role_id: 7, account_status: 'active', email_verified: false, mfa_enabled: false, @@ -149,7 +144,7 @@ class AuthService { const accessToken = jwt.sign( accessPayload, process.env.JWT_TOKEN, - { + { expiresIn: this.accessTokenExpiry, algorithm: 'HS256' } diff --git a/test/healthNews.test.js b/test/healthNews.test.js index 6a340ff..9956b1f 100644 --- a/test/healthNews.test.js +++ b/test/healthNews.test.js @@ -1,7 +1,7 @@ require("dotenv").config(); const request = require('supertest'); - -const BASE_URL = "http://localhost:80"; +const { expect } = require('chai'); +const app = require('../server'); let createdNewsId; let createdCategoryId; @@ -14,50 +14,50 @@ describe('Health News API', () => { describe('GET /api/health-news', () => { it('should fetch all health news', async () => { - const res = await request(BASE_URL).get('/api/health-news'); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(Array.isArray(res.body.data)).toBe(true); + const res = await request(app).get('/api/health-news'); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data).to.be.an('array'); }); it('should fetch news by ID', async () => { // First create a news item to get by ID - const newsRes = await request(BASE_URL) + const newsRes = await request(app) .post('/api/health-news') .send({ title: 'Test News', summary: 'Summary', content: 'Content' }); createdNewsId = newsRes.body.data.id; - const res = await request(BASE_URL).get('/api/health-news').query({ id: createdNewsId }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(res.body.data.id).toBe(createdNewsId); + const res = await request(app).get('/api/health-news').query({ id: createdNewsId }); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data.id).to.equal(createdNewsId); }); it('should return 400 if getById without ID', async () => { - const res = await request(BASE_URL).get('/api/health-news').query({ action: 'getById' }); - expect(res.statusCode).toBe(400); - expect(res.body.success).toBe(false); + const res = await request(app).get('/api/health-news').query({ action: 'getById' }); + expect(res.statusCode).to.equal(400); + expect(res.body.success).to.be.false; }); it('should fetch all categories', async () => { - const res = await request(BASE_URL).get('/api/health-news').query({ type: 'categories' }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(Array.isArray(res.body.data)).toBe(true); + const res = await request(app).get('/api/health-news').query({ type: 'categories' }); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data).to.be.an('array'); }); it('should fetch all authors', async () => { - const res = await request(BASE_URL).get('/api/health-news').query({ type: 'authors' }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(Array.isArray(res.body.data)).toBe(true); + const res = await request(app).get('/api/health-news').query({ type: 'authors' }); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data).to.be.an('array'); }); it('should fetch all tags', async () => { - const res = await request(BASE_URL).get('/api/health-news').query({ type: 'tags' }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(Array.isArray(res.body.data)).toBe(true); + const res = await request(app).get('/api/health-news').query({ type: 'tags' }); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data).to.be.an('array'); }); }); @@ -65,24 +65,24 @@ describe('Health News API', () => { describe('POST /api/health-news', () => { it('should create a news article', async () => { - const res = await request(BASE_URL) + const res = await request(app) .post('/api/health-news') .send({ title: 'New Jest News', summary: 'Jest Summary', content: 'Some content', }); - expect(res.statusCode).toBe(201); - expect(res.body.success).toBe(true); + expect(res.statusCode).to.equal(201); + expect(res.body.success).to.be.true; createdNewsId = res.body.data.id; }); it('should create an author', async () => { - const res = await request(BASE_URL) + const res = await request(app) .post('/api/health-news') .send({ name: 'Test Author', bio: 'Author Bio' }); - expect(res.statusCode).toBe(201); - expect(res.body.success).toBe(true); + expect(res.statusCode).to.equal(201); + expect(res.body.success).to.be.true; createdAuthorId = res.body.data.id; }); }); @@ -90,39 +90,39 @@ describe('Health News API', () => { // ================== PUT ENDPOINT ================== describe('PUT /api/health-news', () => { it('should update a news article', async () => { - const res = await request(BASE_URL) + const res = await request(app) .put('/api/health-news') .query({ id: createdNewsId }) .send({ title: 'Updated Title' }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(res.body.data.title).toBe('Updated Title'); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.data.title).to.equal('Updated Title'); }); it('should return 400 if id missing', async () => { - const res = await request(BASE_URL) + const res = await request(app) .put('/api/health-news') .send({ title: 'Updated Title' }); - expect(res.statusCode).toBe(400); - expect(res.body.success).toBe(false); + expect(res.statusCode).to.equal(400); + expect(res.body.success).to.be.false; }); }); // ================== DELETE ENDPOINT ================== describe('DELETE /api/health-news', () => { it('should delete a news article', async () => { - const res = await request(BASE_URL) + const res = await request(app) .delete('/api/health-news') .query({ id: createdNewsId }); - expect(res.statusCode).toBe(200); - expect(res.body.success).toBe(true); - expect(res.body.message).toMatch(/successfully deleted/i); + expect(res.statusCode).to.equal(200); + expect(res.body.success).to.be.true; + expect(res.body.message).to.match(/successfully deleted/i); }); it('should return 400 if id missing', async () => { - const res = await request(BASE_URL).delete('/api/health-news'); - expect(res.statusCode).toBe(400); - expect(res.body.success).toBe(false); + const res = await request(app).delete('/api/health-news'); + expect(res.statusCode).to.equal(400); + expect(res.body.success).to.be.false; }); }); }); diff --git a/test_output.txt b/test_output.txt new file mode 100644 index 0000000..48ccbc1 Binary files /dev/null and b/test_output.txt differ