πŸ•ΆοΈ
VICEINTELPRO
GitHub: HorrorClause
  • In Tenebris Videmus
  • 🚩CTFs
    • πŸ’ΎHack the Box
      • 🏫Academy
        • Command Injection Assessment
        • XSS Assessment
        • Web Attacks Assessment
    • Try Hack Me
      • In Progress
  • πŸ“–Documents
  • πŸ‘¨β€πŸ«HOW-TOs
    • Obisidian How-To
    • Setup Mandiant FLARE VM
  • πŸ“‘Security Fundamentals
    • Security Controls
      • Physical Security
      • Endpoint Security
      • Email Security
      • Network Security
      • AAA Controls
    • Networking 101
      • OSI Model
      • Network Fundamentals
      • Network Devices
      • Network Tools
      • Protocols and Ports
    • πŸ‘¨β€πŸ’ΌManagement Principles
      • Risk
      • Policies and Procedures
      • Compliance and Frameworks
      • Change and Patch Management
  • πŸ›‘οΈSecurity Concepts
    • ⚠️Risk Assessment Models
      • DREAD Risk Assessment Model
      • STRIDE Threat Model
      • Common Vulnerability Scoring System (CVSS)
    • Pentesting
      • Common Terms
      • AV Identification-Evasion
      • Introduction to Payloads
      • Automating Payloads & Delivery with Metasploit
      • Shells Jack Us In, Payloads Deliver Us Shells
      • Web Shells
      • Pentesting Overview
      • Penetration Testing Process
    • πŸ›Vulnerability Assessment
      • Common Vulnerabilities and Exposures (CVE)
      • Common Vulnerability Scoring System (CVSS)
      • Assessment Standards
      • Vulnerability Assessment
      • Vulnerability Scanning
      • Reporting
      • 🎯Nessus
        • Getting Started with Nessus
        • Nessus Scan
        • Working with Nessus Scan Output
        • Advanced Settings
        • Scanning Issues
      • 🦴OpenVAS (Greenbone)
        • Getting Started with OpenVAS
        • OpenVAS
        • Exporting Results
    • Passwords
      • Password Managers
      • Password Policies
      • Password Security Fundamentals
    • Frameworks
    • GRC
    • Logon Types
    • What is Dev-Null ?
  • βš”οΈOffensive Security
    • OSINT
      • OSINT - Websites
      • Google Dorks
    • πŸ”«Attacking Common Services
      • The Concept of Attacks
      • Interacting with Common Services
      • Finding Sensitive Information
      • Attacking DNS
      • Attacking Email Services
      • Attacking FTP
      • Attacking RDP
      • Attacking SMB
      • Attacking SQL Databases
      • Cheat Sheet - Attacking Common Services
      • Service Misconfigurations
    • πŸ”ͺAttacking Web Apps with Ffuf
      • Web Fuzzing
      • Directory Fuzzing
      • Page Fuzzing
      • Recursive Fuzzing
      • DNS Records
      • Sub-domain Fuzzing
      • Vhost Fuzzing
      • Filtering Results
      • Parameter Fuzzing - GET
      • Parameter Fuzzing - POST
      • Value Fuzzing
    • ☁️Cloud
      • AWS
        • AWS S3 Buckets
    • πŸ’‰Command Injection
      • Command Injection Cheat Sheet
      • Intro to Command Injections
      • Detection
      • Injecting Commands
      • Other Injection Operators
      • Identifying Filters
      • Bypassing Space Filters
      • Bypassing Other Blacklisted Characters
      • Bypassing Blacklisted Commands
      • Advanced Command Obfuscation
      • Evasion Tools
      • Command Injection Prevention
    • Containers
      • Docker
    • ❌Cross-Site Scripting (XSS)
      • Introduction to XSS
      • Stored XSS
      • Reflected XSS
      • DOM XSS
      • XSS Discovery
      • Defacing
      • Phishing
      • Session Hijacking
      • XSS Prevention
    • Directory Busting
      • DirB
      • DirBuster
      • Ffuf
      • Gobuster
    • πŸ…°οΈDNS
      • DNSRecon
      • Fierce
    • File Inclusion
      • Local File Inclusion Cheatsheet
      • Intro to File Inclusion
      • Local File Inclusion (LFI)
      • Basic Bypass
      • PHP Filters
      • PHP Wrappers
      • Remote File Inclusion (RFI)
      • LFI and File Uploads
      • Log Poisoning
      • Automated Scanning
      • File Inclusion Prevention
    • File Transfers
      • Transferring Files
      • File Transfer - Quick Commands
      • Living off the Land
      • Windows File Transfer Methods
      • Linux File Transfer Methods
      • Catching Files over HTTP(S)
      • Transferring Files with Code
      • Miscellaneous File Transfer Methods
      • Protected File Transfers
      • Mounting Encrypted VHD Drives
      • Mounting VHD in Kali
      • File Transfer Detection
    • File Upload Attacks
      • File Upload Cheatsheet
      • Absent Validation
      • Upload Exploitation
      • Client-Side Validation
      • Blacklist Filters
      • Whitelist Filters
      • Type Filters
      • Limited File Uploads
      • Other Upload Attacks
      • Preventing File Upload Vulnerabilities
    • πŸ‘£Footprinting
      • Linux Remote Management Protocols
      • Windows Remote Management Protocols
      • Enumeration
        • Enumeration Methodology
        • πŸ–₯️Host Based
          • Quick Commands
          • DNS
          • FTP
          • IMAP-POP3
          • IPMI
          • MSSQL
          • MySQL
          • NFS
          • Oracle TNS
          • SMB
  • Powershell
    • Powershell CheatSheet
  • Python
    • Map
    • Anonymous Functions
    • Recursion
      • ZipMap
      • Nested Sum
      • Recursion on a Tree
      • Count Nested Levels
      • Longest Word
    • Function Transformations
      • More Transformations
      • Why Transform?
    • Closures
    • Currying
    • Decorators
    • Sum Types
    • Enums
    • Match
    • Regex
  • Kusto (KQL)
    • SQL and KQL Comparison
    • Using the Where and Sort Operators
    • KQL Queries
  • HTML
  • Insecure File Uploads
Powered by GitBook
On this page
  • Sum Types
  • Assignment
  • Solution:
  1. Python

Sum Types

PreviousDecoratorsNextEnums

Last updated 2 months ago

A "sum" type is the opposite of a "product" type. This Python object is an example of a product type:

man.studies_finance = True
man.has_trust_fund = False

The total number of combinations a man can have is 4, the product of 2 * 2:

studies_finance
has_trust_fund

True

True

True

False

False

True

False

False

If we add a third attribute, perhaps a has_blue_eyes boolean, the total number of possibilities multiplies again, to 8!

studies_finance
has_trust_fund
has_blue_eyes

True

True

True

True

True

False

True

False

True

True

False

False

False

True

True

False

True

False

False

False

True

False

False

False

But let's pretend that we live in a world where there are really only that our program cares about:

  1. Dateable

  2. Undateable

  3. Maybe dateable

We can reduce the number of cases our code needs to handle by using a (admittedly fake Pythonic) sum type with only 3 possible types:

class Person:
    def __init__(self, name):
        self.name = name

class Dateable(Person):
    pass

class MaybeDateable(Person):
    pass

class Undateable(Person):
    pass
def respond_to_text(guy_at_bar):
    if isinstance(guy_at_bar, Dateable):
        return f"Hey {guy_at_bar.name}, I'd love to go out with you!"
    elif isinstance(guy_at_bar, MaybeDateable):
        return f"Hey {guy_at_bar.name}, I'm busy but let's hang out sometime later."
    elif isinstance(guy_at_bar, Undateable):
        return "Have you tried being rich?"
    else:
        raise ValueError("invalid person type")

Sum Types

As opposed to product types, which can have many (often infinite) combinations, sum types have a fixed number of possible values. To be clear: Python doesn't really support sum types. We have to use a workaround and invent our own little system and enforce it ourselves.

Assignment

Whenever a document is parsed by Doc2Doc, it can either succeed or fail. In functional programming, we often represent errors as data (e.g. the ParseError class) rather than by raiseing exceptions, because exceptions are side effects. (This isn't standard Python practice, but it's useful to understand from an FP perspective)

Complete the Parsed and ParseError subclasses.

  • Parsed represents success. It should accept a doc_name string and a text string and save them as properties of the same name.

  • ParseError represents failure. It should accept a doc_name string and an err string and save them as properties of the same name.

The test suite uses the isinstance function to see if an error occurred based on the class type.

Solution:

class MaybeParsed:
    pass


# don't touch above this line


class Parsed(MaybeParsed):
    def __init__(self, doc_name, text):
        self.doc_name = doc_name
        self.text = text


class ParseError(MaybeParsed):
    def __init__(self, doc_name, err):
        self.doc_name = doc_name
        self.err = err

Why Does This Work?

This works because it correctly follows object-oriented principles while staying true to a functional programming (FP) approach to error handling. Here’s why:

βœ… 1. Inheritance Helps Categorize Outcomes

  • Parsed and ParseError inherit from MaybeParsed, meaning they share a common parent.

  • This allows us to easily check whether an object represents a parsing result using isinstance().

βœ… 2. Each Class Stores Its Own Data Correctly

  • Parsed saves successful results:

    self.doc_name = doc_name
    self.text = text
    • It stores the document name (doc_name) and its extracted text (text).

  • ParseError saves failure information:

    self.doc_name = doc_name
    self.err = err
    • Instead of text, it stores err, which describes the reason for failure.

βœ… 3. Functional Programming Approach

  • Instead of throwing exceptions, we return an instance of either Parsed or ParseError to represent success or failure.

  • This makes it easy to handle results using pattern matching or conditional checks.

Example Usage: Handling Success and Failure

def process_document(doc_name, content):
    if content:  # If content is not empty, parsing succeeds
        return Parsed(doc_name, content)
    else:  # If content is empty, return an error
        return ParseError(doc_name, "Document is empty")


# Example 1: Successful parsing
result1 = process_document("report.txt", "This is the document content.")

# Example 2: Failed parsing
result2 = process_document("error_doc.txt", "")


# Handling the results
if isinstance(result1, Parsed):
    print(f"Success: {result1.doc_name} parsed with content: {result1.text}")
elif isinstance(result1, ParseError):
    print(f"Failed: {result1.doc_name} - {result1.err}")

if isinstance(result2, Parsed):
    print(f"Success: {result2.doc_name} parsed with content: {result2.text}")
elif isinstance(result2, ParseError):
    print(f"Failed: {result2.doc_name} - {result2.err}")

Output:

Success: report.txt parsed with content: This is the document content.
Failed: error_doc.txt - Document is empty

Key Takeaways

  1. We avoid exceptions. Instead of raise Exception("Parsing failed"), we use structured data to represent errors.

  2. We use isinstance to distinguish success and failure. This makes error handling explicit.

  3. We keep the data encapsulated in objects. Instead of returning just strings ("Success" or "Error: file not found"), we return structured objects with attributes (doc_name, text, err).

  4. This pattern is common in functional languages like Haskell and Scala. It mimics Result types found in FP languages.

Then we can use the built-in function to check if a Person is an instance of one of the subclasses. It's a clunky way to represent sum types, but hey, it's Python.

three types of people
isinstance