diff --git a/Summer-2024/CS-3424/Assignments/Assignment-2/.gitignore b/Summer-2024/CS-3424/Assignments/Assignment-2/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/Summer-2024/CS-3424/Assignments/Assignment-2/.gitignore @@ -0,0 +1 @@ +result diff --git a/Summer-2024/CS-3424/Assignments/Assignment-2/flake.lock b/Summer-2024/CS-3424/Assignments/Assignment-2/flake.lock new file mode 100644 index 0000000..47e4bd2 --- /dev/null +++ b/Summer-2024/CS-3424/Assignments/Assignment-2/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1720955038, + "narHash": "sha256-GaliJqfFwyYxReFywxAa8orCO+EnDq2NK2F+5aSc8vo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "aa247c0c90ecf4ae7a032c54fdc21b91ca274062", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/Summer-2024/CS-3424/Assignments/Assignment-2/flake.nix b/Summer-2024/CS-3424/Assignments/Assignment-2/flake.nix new file mode 100644 index 0000000..6fab135 --- /dev/null +++ b/Summer-2024/CS-3424/Assignments/Assignment-2/flake.nix @@ -0,0 +1,61 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = + inputs@{ self, ... }: + inputs.flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + in + rec { + packages.assign2 = pkgs.writeShellApplication { + name = "assign2"; + runtimeInputs = with pkgs; [ + gnused + coreutils + ]; + derivationArgs = { + src = ./src; + checkPhase = + let + check-redaction-valid = pkgs.writeShellApplication { + name = "check-redaction-valid"; + runtimeInputs = with pkgs; [ + diffutils + gnused + coreutils + ]; + text = '' + set -eEuo pipefail + cp "${./data/redactme.txt}" ./redactme-alterable.txt + chmod 0600 ./redactme-alterable.txt + # shellcheck disable=SC2154 + "$out/bin/assign2" ./redactme-alterable.txt + diff \ + --color=auto \ + --ignore-matching-lines='^Date:.*$' \ + ./redactme-alterable.txt \ + "${./data/redactme-after.txt}" + ''; + }; + in + '' + set -eEuo pipefail + ${pkgs.shellcheck}/bin/shellcheck ${self}/src/assign2.bash + ${pkgs.shfmt}/bin/shfmt -d ${self}/src/assign2.bash + ${check-redaction-valid}/bin/check-redaction-valid + ''; + }; + text = ''${pkgs.bash}/bin/bash ${self}/src/assign2.bash "$@"''; + }; + packages.default = packages.assign2; + apps.default = { + type = "app"; + program = "${packages.assign2}/bin/assign2"; + }; + } + ); +} diff --git a/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.bash b/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.bash new file mode 100755 index 0000000..3f671e3 --- /dev/null +++ b/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.bash @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +set -eEuo pipefail + +SCRIPT_PATH="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SCRIPT_PATH")" + +####################################### +# Print the given message to STDERR +####################################### +err() { + printf "%s\n" "${*}" >&2 +} + +####################################### +# End the script with a non-zero exit code and the given message +# Arguments: +# msg: The message to print to STDERR before exiting +####################################### +die() { + local msg="${*}" + err "$msg" + exit 1 +} + +####################################### +# Print a usage synopsis for the script to stdout +####################################### +usage() { + cat <<-__EOS__ + Usage: + ${SCRIPT_PATH} + Args: + : One or more paths to files on the system + Example: + ${SCRIPT_PATH} ./some/file/to/handle.txt ./another/file/to/handle.txt + __EOS__ +} + +####################################### +# Replace all instances of or with todays date in day/month/year +# format in place for the given file +# Arguments: +# file: The file to template in the date for +####################################### +replace_date_placeholders_in_file() { + local file="${1}" + local current_date + current_date="$(date +"%d\/%m\/%Y")" + sed -ri "s/(|)/$current_date/g" "$file" + +} + +####################################### +# Redact the given file with the included sed script in place for the given file +# Arguments: +# file: The file to redact +####################################### +redact_file() { + local file="${1}" + sed -ri -f "${SCRIPT_DIR}/assign2.sed" "$file" +} + +####################################### +# Check that the given file can be used within the script. For example, check +# that the current script/user has read & write permissions for the given file. +# Arguments: +# file: The file to check +####################################### +check_file() { + local file="${1}" + if ! [[ -r "$file" ]]; then + err "Unable to read '${file}', the current user lacks read permissions or the file does not exist!" + return 1 + fi + + if ! [[ -w "$file" ]]; then + err "Unable to modify '${file}', the current user lacks write permissions!" + return 1 + fi +} + +####################################### +# Check all given files and return a single error code if any given check fails. +# This is done so all errors for the given files are output to the user prior to +# exiting. +# Arguments: +# files: an array of files to loop through and validate +####################################### +validate_files() { + local ret_code=0 + local files=("${@}") + for file in "${files[@]}"; do + if ! check_file "$file"; then + ret_code=1 + fi + done + return "$ret_code" +} + +main() { + local files=("${@}") + if (("${#files[@]}" == 0)); then + usage + die "No arguments provided!" + fi + + validate_files "${files[@]}" || die "File checks failed, refusing to run script!" + + for file in "${files[@]}"; do + redact_file "$file" + replace_date_placeholders_in_file "$file" + done +} + +main "${@}" diff --git a/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.sed b/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.sed new file mode 100644 index 0000000..58310ba --- /dev/null +++ b/Summer-2024/CS-3424/Assignments/Assignment-2/src/assign2.sed @@ -0,0 +1,18 @@ +# Redact Driver's License numbers +s/[a-zA-Z]{2}\s?DL [0-9]{6,8}/DL /g + +# Redact Credit Card Numbers +## Visa Cards +s/4[0-9]{3}-?[0-9]{4}-?[0-9]{4}-?([0-9]{4})/VISA-\1/g +## Master Cards +s/5[0-9]{3}-?[0-9]{4}-?[0-9]{4}-?([0-9]{4})/MC-\1/g +## Discover Cards +s/6[0-9]{3}-?[0-9]{4}-?[0-9]{4}-?([0-9]{4})/DISC-\1/g +## Amex Cards (Important that it comes last because it collides inside larger card lengths) +s/3[47][0-9]{2}-?[0-9]{6}-?[0-9]([0-9]{4})/AMEX-\1/g + +# Redact license plates +s/TX\s?[[:alnum:]]{3}-?([[:digit:]]{4}|[[:alnum:]]{3})/TX /g + +# Template in the municipality name +s/(|)/City of Brook Haven, Connecticut/g