diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml new file mode 100644 index 000000000000..35c829b139b5 --- /dev/null +++ b/.github/workflows/generator-generic-ossf-slsa3-publish.yml @@ -0,0 +1,66 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow lets you generate SLSA provenance file for your project. +# The generation satisfies level 3 for the provenance requirements - see https://slsa.dev/spec/v0.1/requirements +# The project is an initiative of the OpenSSF (openssf.org) and is developed at +# https://github.com/slsa-framework/slsa-github-generator. +# The provenance file can be verified using https://github.com/slsa-framework/slsa-verifier. +# For more information about SLSA and how it improves the supply-chain, visit slsa.dev. + +name: SLSA generic generator +on: + workflow_dispatch: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + outputs: + digests: ${{ steps.hash.outputs.digests }} + + steps: + - uses: actions/checkout@v4 + + # ======================================================== + # + # Step 1: Build your artifacts. + # + # ======================================================== + - name: Build artifacts + run: | + # These are some amazing artifacts. + echo "artifact1" > artifact1 + echo "artifact2" > artifact2 + + # ======================================================== + # + # Step 2: Add a step to generate the provenance subjects + # as shown below. Update the sha256 sum arguments + # to include all binaries that you generate + # provenance for. + # + # ======================================================== + - name: Generate subject for provenance + id: hash + run: | + set -euo pipefail + + # List the artifacts the provenance will refer to. + files=$(ls artifact*) + # Generate the subjects (base64 encoded). + echo "hashes=$(sha256sum $files | base64 -w0)" >> "${GITHUB_OUTPUT}" + + provenance: + needs: [build] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0 + with: + base64-subjects: "${{ needs.build.outputs.digests }}" + upload-assets: true # Optional: Upload to a new release diff --git a/collections/scam-detection-ai/__pycache__/email_analyzer.cpython-312.pyc b/collections/scam-detection-ai/__pycache__/email_analyzer.cpython-312.pyc new file mode 100644 index 000000000000..17ad068257ce Binary files /dev/null and b/collections/scam-detection-ai/__pycache__/email_analyzer.cpython-312.pyc differ diff --git a/collections/scam-detection-ai/__pycache__/message_analyzer.cpython-312.pyc b/collections/scam-detection-ai/__pycache__/message_analyzer.cpython-312.pyc new file mode 100644 index 000000000000..e568a30d4140 Binary files /dev/null and b/collections/scam-detection-ai/__pycache__/message_analyzer.cpython-312.pyc differ diff --git a/collections/scam-detection-ai/app.py b/collections/scam-detection-ai/app.py new file mode 100644 index 000000000000..90845051323d --- /dev/null +++ b/collections/scam-detection-ai/app.py @@ -0,0 +1,64 @@ +from flask import Flask, render_template, request +from email_analyzer import analyze_email +from email_fetcher import fetch_emails +from message_analyzer import analyze_message + +app = Flask(__name__) + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/analyze', methods=['POST']) +def analyze(): + if 'email_text' in request.form: + email_text = request.form['email_text'] + analysis = analyze_email(email_text) + total_score = sum(analysis.values()) + is_scam = total_score >= 3 + return render_template('result.html', analysis=analysis, is_scam=is_scam, analysis_type='Email') + + elif 'message_text' in request.form: + message_text = request.form['message_text'] + analysis = analyze_message(message_text) + total_score = sum(analysis.values()) + is_scam = total_score >= 2 + return render_template('result.html', analysis=analysis, is_scam=is_scam, analysis_type='Message') + + elif 'fetch_emails' in request.form: + username = request.form['username'] + password = request.form['password'] + emails = fetch_emails(username, password) + + analyzed_emails = [] + if emails: + for email_message in emails: + body = "" + if email_message.is_multipart(): + for part in email_message.walk(): + if part.get_content_type() == "text/plain": + body = part.get_payload(decode=True).decode() + break + else: + body = email_message.get_payload(decode=True).decode() + + analysis = analyze_email(body) + total_score = sum(analysis.values()) + is_scam = total_score >= 3 + + subject, _ = email.header.decode_header(email_message["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode() + + analyzed_emails.append({ + "subject": subject, + "from": email_message['From'], + "analysis": analysis, + "is_scam": is_scam + }) + return render_template('results_list.html', emails=analyzed_emails) + + return "Invalid request", 400 + +if __name__ == '__main__': + app.run(debug=True) diff --git a/collections/scam-detection-ai/chrome-extension/background.js b/collections/scam-detection-ai/chrome-extension/background.js new file mode 100644 index 000000000000..c365c6ca8dca --- /dev/null +++ b/collections/scam-detection-ai/chrome-extension/background.js @@ -0,0 +1,27 @@ +chrome.runtime.onInstalled.addListener(() => { + chrome.contextMenus.create({ + id: "analyzeText", + title: "Analyze for Scams", + contexts: ["selection"] + }); +}); + +chrome.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId === "analyzeText") { + fetch('http://localhost:5000/analyze', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `message_text=${encodeURIComponent(info.selectionText)}` + }) + .then(response => response.text()) + .then(data => { + chrome.storage.local.set({ analysisResult: data }); + }) + .catch(error => { + console.error('Error:', error); + chrome.storage.local.set({ analysisResult: 'Error analyzing text.' }); + }); + } +}); diff --git a/collections/scam-detection-ai/chrome-extension/manifest.json b/collections/scam-detection-ai/chrome-extension/manifest.json new file mode 100644 index 000000000000..946ddd0b94bb --- /dev/null +++ b/collections/scam-detection-ai/chrome-extension/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 3, + "name": "Scam Detection AI", + "version": "1.0", + "description": "Analyzes selected text for scams.", + "permissions": [ + "activeTab", + "contextMenus" + ], + "background": { + "service_worker": "background.js" + }, + "action": { + "default_popup": "popup.html" + } +} diff --git a/collections/scam-detection-ai/chrome-extension/popup.html b/collections/scam-detection-ai/chrome-extension/popup.html new file mode 100644 index 000000000000..49ef9d1b7dd8 --- /dev/null +++ b/collections/scam-detection-ai/chrome-extension/popup.html @@ -0,0 +1,17 @@ + + + + Scam Detection AI + + + +

Scam Detection AI

+ + +
+ + + diff --git a/collections/scam-detection-ai/chrome-extension/popup.js b/collections/scam-detection-ai/chrome-extension/popup.js new file mode 100644 index 000000000000..68d231561d8d --- /dev/null +++ b/collections/scam-detection-ai/chrome-extension/popup.js @@ -0,0 +1,27 @@ +document.addEventListener('DOMContentLoaded', () => { + chrome.storage.local.get(['analysisResult'], (result) => { + if (result.analysisResult) { + document.getElementById('result').innerHTML = result.analysisResult; + chrome.storage.local.remove(['analysisResult']); + } + }); +}); + +document.getElementById('analyzeButton').addEventListener('click', () => { + const text = document.getElementById('textToAnalyze').value; + fetch('http://localhost:5000/analyze', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `message_text=${encodeURIComponent(text)}` + }) + .then(response => response.text()) + .then(data => { + document.getElementById('result').innerHTML = data; + }) + .catch(error => { + console.error('Error:', error); + document.getElementById('result').innerText = 'Error analyzing text.'; + }); +}); diff --git a/collections/scam-detection-ai/email_analyzer.py b/collections/scam-detection-ai/email_analyzer.py new file mode 100644 index 000000000000..cfed604df07f --- /dev/null +++ b/collections/scam-detection-ai/email_analyzer.py @@ -0,0 +1,107 @@ +import re + +import requests + +def get_domain_reputation(domain): + """ + Checks the reputation of a domain using a mock API. + In a real application, this would integrate with a service like VirusTotal. + """ + # This is a mock response. + if "fake" in domain or "suspicious" in domain: + return "Malicious" + return "Clean" + +def analyze_email(email_text): + """ + Analyzes an email for potential scam indicators. + + Args: + email_text: The full text of the email. + + Returns: + A dictionary containing the analysis results. + """ + scam_indicators = { + "urgency": 0, + "generic_greeting": 0, + "suspicious_links": 0, + "unusual_sender": 0, + "payment_requests": 0, + "attachments": 0, + "domain_analysis": {} + } + + # Urgency keywords + urgency_keywords = ["urgent", "immediate", "action required", "limited time", "expire"] + for keyword in urgency_keywords: + if re.search(r'\b' + keyword + r'\b', email_text, re.IGNORECASE): + scam_indicators["urgency"] = 1 + break + + # Generic greeting + generic_greetings = ["dear customer", "dear user", "sir/madam"] + for greeting in generic_greetings: + if greeting in email_text.lower(): + scam_indicators["generic_greeting"] = 1 + break + + # Suspicious links (basic check for non-standard URLs) + if re.search(r'http[s]?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}/[a-zA-Z0-9_.-]+', email_text): + scam_indicators["suspicious_links"] = 1 + + # Unusual sender (very basic check) + if "From:" in email_text: + from_line = email_text.split("From:")[1].split("\n")[0] + if re.search(r'<.*@.*>', from_line) and not re.search(r'<.*@.*\..*>', from_line): + scam_indicators["unusual_sender"] = 1 + + # Payment requests + payment_keywords = ["payment", "invoice", "wire transfer", "bank account", "credit card"] + for keyword in payment_keywords: + if re.search(r'\b' + keyword + r'\b', email_text, re.IGNORECASE): + scam_indicators["payment_requests"] = 1 + break + + # Attachments + if "Content-Disposition: attachment" in email_text: + scam_indicators["attachments"] = 1 + + # Domain analysis + urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email_text) + domains = [re.search(r'//(.*?)/', url).group(1) for url in urls if re.search(r'//(.*?)/', url)] + + for domain in domains: + reputation = get_domain_reputation(domain) + scam_indicators["domain_analysis"][domain] = reputation + + return scam_indicators + +if __name__ == '__main__': + sample_email = """ + From: Suspicious Sender + Subject: Urgent Action Required: Your Account Will Be Deactivated + + Dear user, + + We have detected suspicious activity on your account. For your security, we have temporarily suspended your account. + To reactivate your account, you must verify your identity by clicking the link below and updating your payment information. + + http://suspicious-link.com/verify + + Failure to do so within 24 hours will result in permanent account deactivation. + + Thank you for your cooperation. + + Sincerely, + The Security Team + """ + + analysis = analyze_email(sample_email) + print(analysis) + + total_score = sum(analysis.values()) + if total_score >= 3: + print("\nThis email is likely a scam!") + else: + print("\nThis email seems legitimate.") diff --git a/collections/scam-detection-ai/email_fetcher.py b/collections/scam-detection-ai/email_fetcher.py new file mode 100644 index 000000000000..4430bef5d003 --- /dev/null +++ b/collections/scam-detection-ai/email_fetcher.py @@ -0,0 +1,76 @@ +import imaplib +import email +from email.header import decode_header + +def fetch_emails(username, password, server="imap.gmail.com"): + """ + Fetches emails from an IMAP server. + + Args: + username: The email account username. + password: The email account password. + server: The IMAP server address. + + Returns: + A list of email messages. + """ + try: + # connect to the server + mail = imaplib.IMAP4_SSL(server) + # login + mail.login(username, password) + # select the inbox + mail.select("inbox") + + # search for all emails + status, messages = mail.search(None, "ALL") + email_ids = messages[0].split() + + emails = [] + for email_id in email_ids[-5:]: # Fetch last 5 emails for demonstration + status, msg_data = mail.fetch(email_id, "(RFC822)") + for response_part in msg_data: + if isinstance(response_part, tuple): + msg = email.message_from_bytes(response_part[1]) + emails.append(msg) + + mail.logout() + return emails + + except imaplib.IMAP4.error as e: + print(f"IMAP Error: {e}") + return [] + +if __name__ == '__main__': + # This is a placeholder for a secure way to get credentials + EMAIL_USERNAME = "your_email@gmail.com" + EMAIL_PASSWORD = "your_app_password" + + emails = fetch_emails(EMAIL_USERNAME, EMAIL_PASSWORD) + if emails: + for email_message in emails: + subject, encoding = decode_header(email_message["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode(encoding if encoding else "utf-8") + + print("="*50) + print(f"Subject: {subject}") + print(f"From: {email_message['From']}") + print(f"To: {email_message['To']}") + + if email_message.is_multipart(): + for part in email_message.walk(): + content_type = part.get_content_type() + content_disposition = str(part.get("Content-Disposition")) + try: + body = part.get_payload(decode=True).decode() + if "attachment" not in content_disposition: + print("\n--- Body ---\n", body) + except: + pass + else: + body = email_message.get_payload(decode=True).decode() + print("\n--- Body ---\n", body) + print("="*50 + "\n") + else: + print("Could not fetch emails. Please check your credentials and IMAP settings.") diff --git a/collections/scam-detection-ai/index.md b/collections/scam-detection-ai/index.md new file mode 100644 index 000000000000..06f6f71f6824 --- /dev/null +++ b/collections/scam-detection-ai/index.md @@ -0,0 +1,8 @@ +--- +title: "Scam Detection AI" +layout: collection +permalink: /collection/scam-detection-ai/ +collection: scam-detection-ai +--- + +This collection contains the source code for the Scam Detection AI, a project that aims to detect and prevent scams from various sources like emails, SMS, and fake news. diff --git a/collections/scam-detection-ai/message_analyzer.py b/collections/scam-detection-ai/message_analyzer.py new file mode 100644 index 000000000000..5c2c56912dae --- /dev/null +++ b/collections/scam-detection-ai/message_analyzer.py @@ -0,0 +1,63 @@ +import re + +def analyze_message(message_text): + """ + Analyzes an SMS or other short message for potential scam indicators. + + Args: + message_text: The full text of the message. + + Returns: + A dictionary containing the analysis results. + """ + scam_indicators = { + "shortened_urls": 0, + "unusual_sender": 0, + "urgent_requests": 0, + "prize_offers": 0 + } + + # Check for shortened URLs + shortened_url_patterns = [r'bit\.ly', r't\.co', r'goo\.gl', r'tinyurl\.com'] + for pattern in shortened_url_patterns: + if re.search(pattern, message_text): + scam_indicators["shortened_urls"] = 1 + break + + # Check for unusual sender (e.g., non-numeric sender ID) + # This is a very basic check and would need to be improved. + sender_match = re.search(r'From:\s*(\S+)', message_text, re.IGNORECASE) + if sender_match: + sender = sender_match.group(1) + if not sender.isdigit() and len(sender) > 10: + scam_indicators["unusual_sender"] = 1 + + # Check for urgent requests + urgent_keywords = ["urgent", "verify", "confirm", "login", "account"] + for keyword in urgent_keywords: + if re.search(r'\b' + keyword + r'\b', message_text, re.IGNORECASE): + scam_indicators["urgent_requests"] = 1 + break + + # Check for prize offers + prize_keywords = ["congratulations", "winner", "prize", "claim", "won"] + for keyword in prize_keywords: + if re.search(r'\b' + keyword + r'\b', message_text, re.IGNORECASE): + scam_indicators["prize_offers"] = 1 + break + + return scam_indicators + +if __name__ == '__main__': + sample_message = """ + From: 555-123-4567 + Congratulations! You've won a $1000 gift card. Click here to claim: http://bit.ly/fake-prize + """ + analysis = analyze_message(sample_message) + print(analysis) + + total_score = sum(analysis.values()) + if total_score >= 2: + print("\nThis message is likely a scam!") + else: + print("\nThis message seems legitimate.") diff --git a/collections/scam-detection-ai/static/app.js b/collections/scam-detection-ai/static/app.js new file mode 100644 index 000000000000..35d26bd44897 --- /dev/null +++ b/collections/scam-detection-ai/static/app.js @@ -0,0 +1,2 @@ +// This is a placeholder for your PWA's javascript. +console.log("Scam Detection AI PWA is running."); diff --git a/collections/scam-detection-ai/static/manifest.json b/collections/scam-detection-ai/static/manifest.json new file mode 100644 index 000000000000..5cc27d451507 --- /dev/null +++ b/collections/scam-detection-ai/static/manifest.json @@ -0,0 +1,20 @@ +{ + "name": "Scam Detection AI", + "short_name": "Scam AI", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#000000", + "icons": [ + { + "src": "images/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "images/icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/collections/scam-detection-ai/static/styles.css b/collections/scam-detection-ai/static/styles.css new file mode 100644 index 000000000000..317bd3ce55dc --- /dev/null +++ b/collections/scam-detection-ai/static/styles.css @@ -0,0 +1,4 @@ +/* This is a placeholder for your PWA's styles. */ +body { + background-color: #f0f0f0; +} diff --git a/collections/scam-detection-ai/static/sw.js b/collections/scam-detection-ai/static/sw.js new file mode 100644 index 000000000000..58d566bcef63 --- /dev/null +++ b/collections/scam-detection-ai/static/sw.js @@ -0,0 +1,29 @@ +const CACHE_NAME = 'scam-detection-ai-cache-v1'; +const urlsToCache = [ + '/', + '/static/styles.css', // Assuming you'll have a stylesheet + '/static/app.js' // Assuming you'll have some javascript +]; + +self.addEventListener('install', event => { + event.waitUntil( + caches.open(CACHE_NAME) + .then(cache => { + console.log('Opened cache'); + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', event => { + event.respondWith( + caches.match(event.request) + .then(response => { + if (response) { + return response; + } + return fetch(event.request); + } + ) + ); +}); diff --git a/collections/scam-detection-ai/templates/index.html b/collections/scam-detection-ai/templates/index.html new file mode 100644 index 000000000000..2ecab4ec6ff4 --- /dev/null +++ b/collections/scam-detection-ai/templates/index.html @@ -0,0 +1,60 @@ + + + + + + Scam Detection AI + + + + + + +
+

Scam Detection AI

+ +

Analyze Email Text

+
+ +

+ +
+ +
+ +

Analyze SMS/Message Text

+
+ +

+ +
+ +
+

Fetch and Analyze Emails from Your Inbox

+
+ +
+

+
+

+ +
+
+
+ + diff --git a/collections/scam-detection-ai/templates/result.html b/collections/scam-detection-ai/templates/result.html new file mode 100644 index 000000000000..9e181daccb3c --- /dev/null +++ b/collections/scam-detection-ai/templates/result.html @@ -0,0 +1,37 @@ + + + + + + Analysis Result + + + +

{{ analysis_type }} Analysis Result

+
+

{{ 'This ' + analysis_type.lower() + ' is likely a scam!' if is_scam else 'This ' + analysis_type.lower() + ' seems legitimate.' }}

+ + {% if analysis.domain_analysis %} +

Domain Analysis

+ + {% endif %} +
+
+ Analyze another message or email + + diff --git a/collections/scam-detection-ai/templates/results_list.html b/collections/scam-detection-ai/templates/results_list.html new file mode 100644 index 000000000000..2b6e229da92c --- /dev/null +++ b/collections/scam-detection-ai/templates/results_list.html @@ -0,0 +1,45 @@ + + + + + + Fetched Email Analysis + + + +

Fetched Email Analysis

+ {% if emails %} + {% for email in emails %} +
+

Subject: {{ email.subject }}

+

From: {{ email.from }}

+

{{ 'This email is likely a scam!' if email.is_scam else 'This email seems legitimate.' }}

+ + {% if email.analysis.domain_analysis %} +

Domain Analysis

+ + {% endif %} +
+ {% endfor %} + {% else %} +

Could not fetch or analyze emails. Please check your credentials and try again.

+ {% endif %} +
+ Back to Home + + diff --git a/collections/scam-detection-ai/test_email_analyzer.py b/collections/scam-detection-ai/test_email_analyzer.py new file mode 100644 index 000000000000..4301ed83fec8 --- /dev/null +++ b/collections/scam-detection-ai/test_email_analyzer.py @@ -0,0 +1,45 @@ +import unittest +from email_analyzer import analyze_email + +class TestEmailAnalyzer(unittest.TestCase): + + def test_scam_email(self): + scam_email = """ + From: Urgent Winner + Subject: Action Required: You have won a prize! + + Dear customer, + + You have won a lottery! To claim your prize, please send your bank account details and a payment of $50 for processing fees. + Click this link to proceed: http://fake-prize.com/claim + + This is a limited time offer, it will expire in 24 hours. + """ + analysis = analyze_email(scam_email) + self.assertEqual(analysis['urgency'], 1) + self.assertEqual(analysis['generic_greeting'], 1) + self.assertEqual(analysis['suspicious_links'], 1) + self.assertEqual(analysis['payment_requests'], 1) + self.assertEqual(analysis['domain_analysis']['fake-prize.com'], 'Malicious') + + def test_legitimate_email(self): + legitimate_email = """ + From: John Doe + Subject: Project Update + + Hi Team, + + Here is the update on our project. I've attached the weekly report. + Let's discuss it in our meeting tomorrow. + + Best, + John + """ + analysis = analyze_email(legitimate_email) + self.assertEqual(analysis['urgency'], 0) + self.assertEqual(analysis['generic_greeting'], 0) + self.assertEqual(analysis['suspicious_links'], 0) + self.assertEqual(analysis['payment_requests'], 0) + +if __name__ == '__main__': + unittest.main() diff --git a/collections/scam-detection-ai/test_message_analyzer.py b/collections/scam-detection-ai/test_message_analyzer.py new file mode 100644 index 000000000000..c008dcb09145 --- /dev/null +++ b/collections/scam-detection-ai/test_message_analyzer.py @@ -0,0 +1,20 @@ +import unittest +from message_analyzer import analyze_message + +class TestMessageAnalyzer(unittest.TestCase): + + def test_scam_message(self): + scam_message = "Congratulations! You've won a prize. Click http://bit.ly/scam to claim." + analysis = analyze_message(scam_message) + self.assertEqual(analysis['shortened_urls'], 1) + self.assertEqual(analysis['prize_offers'], 1) + + def test_legitimate_message(self): + legitimate_message = "Your appointment is confirmed for 3 PM tomorrow." + analysis = analyze_message(legitimate_message) + self.assertEqual(analysis['shortened_urls'], 0) + self.assertEqual(analysis['prize_offers'], 0) + self.assertEqual(analysis['urgent_requests'], 0) + +if __name__ == '__main__': + unittest.main()