Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
Maikhamit committed Nov 27, 2024
1 parent b7cf9b7 commit 9232a3e
Show file tree
Hide file tree
Showing 13 changed files with 2,656 additions and 2,592 deletions.
28 changes: 28 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc build active file",
"command": "/usr/bin/gcc",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}
28 changes: 24 additions & 4 deletions Season-1/Level-1/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,41 @@

from collections import namedtuple

# Define Order and Item
Order = namedtuple('Order', 'id, items')
Item = namedtuple('Item', 'type, description, amount, quantity')

def validorder(order: Order):
if not isinstance(order.items, (list, tuple)):
raise ValueError("Order items must be a list or tuple of Item objects.")

net = 0
total_order_value = 0
MAX_AMOUNT = 10_000 # Maximum allowed per payment or product
MAX_TOTAL_ORDER = 1_000_000 # Maximum allowed per order

for item in order.items:
if not isinstance(item, Item):
raise ValueError(f"Invalid item in order: {item}")
if not isinstance(item.quantity, int) or item.quantity <= 0:
raise ValueError(f"Invalid quantity for item: {item.description}. Must be a positive integer.")
if abs(item.amount) > MAX_AMOUNT:
raise ValueError(f"Invalid amount for item: {item.description}. Must not exceed ${MAX_AMOUNT:.2f}.")

if item.type == 'payment':
net += item.amount
elif item.type == 'product':
net -= item.amount * item.quantity
total_order_value += item.amount * item.quantity
else:
return "Invalid item type: %s" % item.type
raise ValueError(f"Invalid item type: {item.type}")

if net != 0:
return "Order ID: %s - Payment imbalance: $%0.2f" % (order.id, net)
if total_order_value > MAX_TOTAL_ORDER:
return "Total amount payable for an order exceeded"

# Allow for small floating-point inaccuracies
if abs(net) < 1e-6:
return f"Order ID: {order.id} - Full payment received!"
else:
return "Order ID: %s - Full payment received!" % order.id
return f"Order ID: {order.id} - Payment imbalance: ${net:.2f}"

17 changes: 10 additions & 7 deletions Season-1/Level-1/hack.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

class TestOnlineStore(unittest.TestCase):

# Tricks the system and walks away with 1 television, despite valid payment & reimbursement
def test_6(self):
tv_item = c.Item(type='product', description='tv', amount=1000.00, quantity=1)
payment = c.Item(type='payment', description='invoice_4', amount=1e19, quantity=1)
payback = c.Item(type='payment', description='payback_4', amount=-1e19, quantity=1)
order_4 = c.Order(id='4', items=[payment, tv_item, payback])
self.assertEqual(c.validorder(order_4), 'Order ID: 4 - Payment imbalance: $-1000.00')
def test_6(self):
"""Tricks the system with extremely large payment and reimbursement amounts."""
tv_item = c.Item(type='product', description='tv', amount=1000.00, quantity=1)
payment = c.Item(type='payment', description='invoice_4', amount=1e19, quantity=1)
payback = c.Item(type='payment', description='payback_4', amount=-1e19, quantity=1)
order_4 = c.Order(id='4', items=[payment, tv_item, payback])
with self.assertRaises(ValueError) as context:
c.validorder(order_4)
self.assertIn("Invalid amount", str(context.exception))

# Valid payments that should add up correctly, but do not
def test_7(self):
Expand All @@ -21,6 +23,7 @@ def test_7(self):

# The total amount payable in an order should be limited
def test_8(self):
"""Total amount payable in an order should be limited."""
num_items = 12
items = [c.Item(type='product', description='tv', amount=99999, quantity=num_items)]
for i in range(num_items):
Expand Down
25 changes: 13 additions & 12 deletions Season-1/Level-1/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,42 @@

class TestOnlineStore(unittest.TestCase):

# Example 1 - shows a valid and successful payment for a tv
def test_1(self):
"""Valid and successful payment for a TV"""
tv_item = c.Item(type='product', description='tv', amount=1000.00, quantity=1)
payment = c.Item(type='payment', description='invoice_1', amount=1000.00, quantity=1)
order_1 = c.Order(id='1', items=[payment, tv_item])
self.assertEqual(c.validorder(order_1), 'Order ID: 1 - Full payment received!')

# Example 2 - successfully detects payment imbalance as tv was never paid
def test_2(self):
"""Detects payment imbalance as TV was never paid for"""
tv_item = c.Item(type='product', description='tv', amount=1000.00, quantity=1)
order_2 = c.Order(id='2', items=[tv_item])
self.assertEqual(c.validorder(order_2), 'Order ID: 2 - Payment imbalance: $-1000.00')

# Example 3 - successfully reimburses client for a return so payment imbalance exists
def test_3(self):
"""Detects payment imbalance when a reimbursement is made"""
tv_item = c.Item(type='product', description='tv', amount=1000.00, quantity=1)
payment = c.Item(type='payment', description='invoice_3', amount=1000.00, quantity=1)
payback = c.Item(type='payment', description='payback_3', amount=-1000.00, quantity=1)
order_3 = c.Order(id='3', items=[payment, tv_item, payback])
self.assertEqual(c.validorder(order_3), 'Order ID: 3 - Payment imbalance: $-1000.00')

# Example 4 - handles invalid input such as placing an invalid order for 1.5 device
def test_4(self):
"""Handles invalid input such as placing an invalid order with fractional quantity"""
tv = c.Item(type='product', description='tv', amount=1000, quantity=1.5)
order_1 = c.Order(id='1', items=[tv])
try:
order_1 = c.Order(id='4', items=[tv])
with self.assertRaises(ValueError) as context:
c.validorder(order_1)
except:
self.fail("Invalid order detected")
self.assertIn("Invalid quantity", str(context.exception))

# Example 5 - handles an invalid item type called 'service'
def test_5(self):
"""Handles an invalid item type like 'service'"""
service = c.Item(type='service', description='order shipment', amount=100, quantity=1)
order_1 = c.Order(id='1', items=[service])
self.assertEqual(c.validorder(order_1), 'Invalid item type: service')
order_1 = c.Order(id='5', items=[service])
with self.assertRaises(ValueError) as context:
c.validorder(order_1)
self.assertIn("Invalid item type", str(context.exception))

if __name__ == '__main__':
unittest.main()
unittest.main()
102 changes: 59 additions & 43 deletions Season-1/Level-2/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,95 +12,111 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h> // For handling strtol errors

#define MAX_USERNAME_LEN 39
#define SETTINGS_COUNT 10
#define MAX_USERS 100
#define INVALID_USER_ID -1

// For simplicity, both the private (implementation specific) and the public (API) parts
// of this application have been combined inside this header file. In the real-world, it
// is expected for the public (API) parts only to be presented here. Therefore, for the
// purpose of this level, please assume that the private (implementation specific) sections
// of this file, would not be known to the non-privileged users of this application

// Internal counter of user accounts
int userid_next = 0;
unsigned long userid_next = 0;

// The following structure is implementation-speicific and it's supposed to be unknown
// to non-privileged users
// Structure representing a user account
typedef struct {
bool isAdmin;
long userid;
unsigned long userid;
char username[MAX_USERNAME_LEN + 1];
long setting[SETTINGS_COUNT];
} user_account;

// Simulates an internal store of active user accounts
// Array to store active user accounts
user_account *accounts[MAX_USERS];

// The signatures of the following four functions together with the previously introduced
// constants (see #DEFINEs) constitute the API of this module

// Creates a new user account and returns it's unique identifier
// Creates a new user account and returns its unique identifier
int create_user_account(bool isAdmin, const char *username) {
if (userid_next >= MAX_USERS) {
fprintf(stderr, "the maximum number of users have been exceeded");
fprintf(stderr, "The maximum number of users has been exceeded\n");
return INVALID_USER_ID;
}

if (username == NULL) {
fprintf(stderr, "Username cannot be null\n");
return INVALID_USER_ID;
}
}

user_account *ua;
if (strlen(username) > MAX_USERNAME_LEN) {
fprintf(stderr, "the username is too long");
fprintf(stderr, "The username is too long\n");
return INVALID_USER_ID;
}
ua = malloc(sizeof (user_account));
}

user_account *ua = malloc(sizeof(user_account));
if (ua == NULL) {
fprintf(stderr, "malloc failed to allocate memory");
fprintf(stderr, "Memory allocation failed\n");
return INVALID_USER_ID;
}

ua->isAdmin = isAdmin;
ua->userid = userid_next++;
strcpy(ua->username, username);
memset(&ua->setting, 0, sizeof ua->setting);
accounts[userid_next] = ua;
ua->userid = userid_next; // Assign current ID
strncpy(ua->username, username, MAX_USERNAME_LEN);
ua->username[MAX_USERNAME_LEN] = '\0'; // Ensure null termination
memset(ua->setting, 0, sizeof(ua->setting));

accounts[userid_next] = ua; // Store the new user in the correct slot
return userid_next++;
}

// Updates the matching setting for the specified user and returns the status of the operation
// A setting is some arbitrary string associated with an index as a key
// Frees memory allocated for a user account
void delete_user_account(int user_id) {
if (user_id < 0 || user_id >= MAX_USERS || accounts[user_id] == NULL) {
fprintf(stderr, "Invalid user ID\n");
return;
}

free(accounts[user_id]);
accounts[user_id] = NULL;
}

// Updates a setting for a specified user
bool update_setting(int user_id, const char *index, const char *value) {
if (user_id < 0 || user_id >= MAX_USERS)
if (user_id < 0 || user_id >= MAX_USERS || accounts[user_id] == NULL) {
fprintf(stderr, "Invalid user ID\n");
return false;
}

char *endptr;
long i, v;
i = strtol(index, &endptr, 10);
if (*endptr)
errno = 0; // Reset errno before strtol
long i = strtol(index, &endptr, 10);
if (*endptr || errno == ERANGE || i < 0 || i >= SETTINGS_COUNT) {
fprintf(stderr, "Invalid setting index\n");
return false;
}

v = strtol(value, &endptr, 10);
if (*endptr || i >= SETTINGS_COUNT)
errno = 0; // Reset errno before strtol
long v = strtol(value, &endptr, 10);
if (*endptr || errno == ERANGE) {
fprintf(stderr, "Invalid setting value\n");
return false;
}

accounts[user_id]->setting[i] = v;
return true;
}

// Returns whether the specified user is an admin
bool is_admin(int user_id) {
if (user_id < 0 || user_id >= MAX_USERS) {
fprintf(stderr, "invalid user id");
if (user_id < 0 || user_id >= MAX_USERS || accounts[user_id] == NULL) {
fprintf(stderr, "Invalid user ID\n");
return false;
}
}
return accounts[user_id]->isAdmin;
}

// Returns the username of the specified user
const char* username(int user_id) {
// Returns an error for invalid user ids
if (user_id < 0 || user_id >= MAX_USERS) {
fprintf(stderr, "invalid user id");
const char *username(int user_id) {
if (user_id < 0 || user_id >= MAX_USERS || accounts[user_id] == NULL) {
fprintf(stderr, "Invalid user ID\n");
return NULL;
}
}
return accounts[user_id]->username;
}
}
Binary file added Season-1/Level-2/hack
Binary file not shown.
Binary file added Season-1/Level-2/tests
Binary file not shown.
55 changes: 34 additions & 21 deletions Season-1/Level-3/code.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# Welcome to Secure Code Game Season-1/Level-3!

# You know how to play by now, good luck!

import os
from flask import Flask, request

Expand All @@ -21,35 +17,52 @@ def __init__(self, username, password):
self.prof_picture = None
self.tax_form_attachment = None

# returns the path of an optional profile picture that users can set
# Returns the path of an optional profile picture that users can set
def get_prof_picture(self, path=None):
# setting a profile picture is optional
# Setting a profile picture is optional
if not path:
pass

# defends against path traversal attacks
if path.startswith('/') or path.startswith('..'):
return None

# builds path
# Defends against path traversal attacks
base_dir = os.path.dirname(os.path.abspath(__file__))
prof_picture_path = os.path.normpath(os.path.join(base_dir, path))
full_path = os.path.normpath(os.path.join(base_dir, path))

# Ensure the path remains within the base directory
if not full_path.startswith(base_dir):
return None

# Check if the file exists and is accessible
if not os.path.isfile(full_path):
return None

with open(prof_picture_path, 'rb') as pic:
with open(full_path, 'rb') as pic:
picture = bytearray(pic.read())

# assume that image is returned on screen after this
return prof_picture_path
# Assume that the image is returned on screen after this
return full_path

# returns the path of an attached tax form that every user should submit
# Returns the path of an attached tax form that every user should submit
def get_tax_form_attachment(self, path=None):
tax_data = None

# Tax form submission is mandatory
if not path:
raise Exception("Error: Tax form is required for all users")

with open(path, 'rb') as form:
# Defends against path traversal attacks
base_dir = os.path.dirname(os.path.abspath(__file__))
full_path = os.path.normpath(os.path.join(base_dir, path))

# Ensure the path remains within the base directory
if not full_path.startswith(base_dir):
# Instead of raising an exception, return `None` for invalid paths
return None

# Check if the file exists and is accessible
if not os.path.isfile(full_path):
# Instead of raising an exception, return `None` for missing files
return None

with open(full_path, 'rb') as form:
tax_data = bytearray(form.read())

# assume that tax data is returned on screen after this
return path
# Assume that tax data is returned on screen after this
return full_path
Loading

0 comments on commit 9232a3e

Please sign in to comment.