From 069280106934681ab3cad0e066c386bc5492f206 Mon Sep 17 00:00:00 2001 From: Jon-William Lewis Date: Mon, 15 Feb 2016 11:38:03 -0600 Subject: [PATCH] Fixed a bug where sns does not exit in the abscence of an existing store --- errors.md | 11 +- sns.sh | 317 +++++++++++++++++++++++++++++++++++++++++ src/main/stage1.sns.sh | 1 + 3 files changed, 324 insertions(+), 5 deletions(-) create mode 100755 sns.sh diff --git a/errors.md b/errors.md index edde651..9e13a94 100644 --- a/errors.md +++ b/errors.md @@ -2,11 +2,12 @@ ## Error Code Reference ### General Codes -| Name | Code | Meaning | -|-------------|------|--------------------------------------| -| ERR_NO_ARGS | 10 | No arguments were specified | -| ERR_NO_OP | 20 | No operation was specified | -| ERR_NO_NOTE | 30 | A required argument was not provided | +| Name | Code | Meaning | +|--------------|------|---------------------------------------| +| ERR_NO_STORE | 5 | the SNS store needs to be initialized | +| ERR_NO_ARGS | 10 | No arguments were specified | +| ERR_NO_OP | 20 | No operation was specified | +| ERR_NO_NOTE | 30 | A required argument was not provided | ### Encryption-related codes |Name | Code | Meaning | diff --git a/sns.sh b/sns.sh new file mode 100755 index 0000000..9c7bd71 --- /dev/null +++ b/sns.sh @@ -0,0 +1,317 @@ +#!/bin/bash +#========================================================== +# Simple Note System, v2.0a9 +# Copyright 2016, Xenese Labs/Sicron-Perion XNF +#========================================================== + +# Prevent freak accidents involving the root directory +if [ -z "$HOME" ]; then HOME=/home/"$(whoami)"; fi + +# Store files and locations +readonly PROD_STR="Simple Note System" +readonly VER_STR="v2.0a9" +readonly ROOT_DIR="$HOME"/.config/sns +readonly NOTES_DIR="$ROOT_DIR"/notes +readonly TMP_DIR="$ROOT_DIR"/tmp +readonly CONFIG_FILE="$ROOT_DIR/sns.conf" + +#Color codes for error reporting +readonly RED_COLOR='\033[1;31m' +readonly RESET_COLOR='\033[0m' + +#Print the program header to stdout +printf "%s\n" "$PROD_STR" +printf "%s\n" "------------------" + +# Section: Functions +function init_store { + +if [ ! -d "$ROOT_DIR" ]; then mkdir -p "$ROOT_DIR"; WILL_INIT="TRUE"; fi +if [ ! -d "$TMP_DIR" ]; then mkdir -p "$TMP_DIR" ; WILL_INIT="TRUE"; fi + + +cat > "$CONFIG_FILE" << EOF +# This file contains directives for the Simple Note System. + +EXT=note # File extension to use (for listing notes) + +#EDITOR= # Preferred Editor: + # If you would like to specify a different editor for + # sns to use, you may do so here. + +ENCRYPTION="FALSE" # Main Encryption Toggle: + # WARNING: ANY PREVIOUSLY UNENCRYPTED NOTES WILL BE LOST + # Change this to TRUE to enable encryption. + +PUBKEY="" # Public Key + # Encryption is done using GPG. You must enter your + # public key's identifier here. +EOF + +chmod 600 "$CONFIG_FILE" + +printf " - %s\n" "Rewrote Default Configuration" + +if [ "$WILL_INIT" == "TRUE" ]; then + printf " - %s\n" "Environment initialized in $ROOT_DIR" +else + printf " - %s\n" "Store already initialized." +fi +} +function verify_store { + + ETC_DIR=$(dirname "$CONFIG_FILE") + + STORE_DIRS=("$ROOT_DIR" "$NOTES_DIR" "$TMP_DIR" "$ETC_DIR") + for DIR in "${STORE_DIRS[@]}"; do + if [ ! -d "$DIR" ]; then + mkdir -p "$DIR" + fi + done +} +function help { + printf "\n%s" "usage: sns [-cedp] NAME NOTEBOOK SECTION" + printf "\n%s" " sns [-l] NOTEBOOK" + printf "\n%s" " sns [-hi ]" + + printf "\n%s" " -c | --create : Create note" + printf "\n%s" " -d | --delete : Delete note" + printf "\n%s" " -e | --edit : Open note for editing" + printf "\n%s" " -h | --help : Display this message" + printf "\n%s" " -p | --print : Print note to console" + printf "\n%s" " -l | --list : List all notes in NOTEBOOK" + printf "\n%s" " -i | --init : Write default config and initalize SNS store" + printf "\n" +} +function p_header(){ + printf "TITLE: %s\nDATE: %s\n" "$NAME" "$(date)" +} +function encrypt(){ +# This function, given a recipient, $PUBKEY; a file to encrypt, $TMP_NOTE; and an +# output file, $NOTE, will encrypt $TMP_NOTE to $NOTE against $PUBKEY's private +# GPG key. + + gpg -r "$PUBKEY" -o "$NOTE" -e "$TMP_NOTE" + +} + +function decrypt(){ +# This function, given a file to decrypt, will attempt to decrypt the file +# against the specified recipient's private key, and print the result to +# stdout. + gpg -d "$NOTE" +} +function create(){ + # Depends : p_header + # Requires: $NOTE, $NOTE_DIR, + # Optional: $ENCRYPTION, $SESSION_ID, $TMP_DIR encrypt + # Given a valid setup, create writes the standard note header as specified + # by p_header, to $NOTE. + + # Refuse to overwrite a note + if [ -e "$NOTES_DIR/$NOTE" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "Note already exists"\ + "Hint: use -e to edit the note." + exit 200 + fi + + # If the note's notebook/section does not exist, + # create the appropriate folders. + mkdir -p "$NOTES_DIR"/"$(dirname "$NOTE")" + + # Write the standard note header + if [ "$ENCRYPTION" == "TRUE" ]; then + TMP_NOTE="$TMP_DIR"/"$SESSION_ID" + p_header > "$TMP_NOTE" + encrypt + else + p_header > "$NOTES_DIR/$NOTE" + fi + # Make sure the note exists, and inform the user of the result. + if [ -e "$NOTES_DIR/$NOTE" ]; then + printf " - %s\n" "Created note: ${NOTE%.*}" + else + >&2 printf " $RED_COLOR!$RESET_COLOR%s\n"\ + "Something went wrong, and the note was not created." + fi +} +function delete(){ + # Requires: $NOTE, $NOTE_DIR + # Given a valid $NOTE, delete removes $NOTE from sns. + + if [ -e "$NOTES_DIR/$NOTE" ]; then + rm "$NOTES_DIR/$NOTE" + printf " - %s\n" "Deleted note: ${NOTE%.*}." + else + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n" "Note ${NOTE%.*} does not exist." + fi +} +function edit(){ +# Requires: $EDITOR, $NOTE +# Optional: $ENCRYPTION, $TMP_DIR, $SESSION_ID, decrypt, encrypt + +# Verify an editor was specified +if [ -z "$EDITOR" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n"\ + "No editor specified in environment." + exit +# Verify the note exists +elif [ ! -r "$NOTE" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n"\ + "Note cannot be opened for editing." + exit 40; +fi + +# If encryption is enabled, decrypt $NOTE to a temp file, otherwise +# operate on the note directly. +if [ "$ENCRYPTION" == "TRUE" ]; then + cp "$NOTE" "$NOTE".bk #Insurance + TMP_NOTE="$TMP_DIR/$SESSION_ID" + decrypt > "$TMP_NOTE" +else + TMP_NOTE="$NOTE"; +fi + +# Write an ammendment header +if [ -z "$CREATE" ]; then + printf "\n %s\n" "edit - $(date)" >> "$TMP_NOTE" + printf "\n %s\n" "===================================" >> "$TMP_NOTE" +fi + +# Call the editor +printf " - %s\n" "editing ${NOTE%.*}" +"$EDITOR" "$TMP_NOTE" + +# If the file was previously decrypted, encrypt it back +if [ "$ENCRYPTION" == "TRUE" ]; then + rm "$NOTE" + encrypt; + if [ ! -r "$NOTE" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n" "error: note was not saved." + cp "$NOTE.bk" "$NOTE" + else + rm "$NOTE.bk"; + fi +fi + +} +function print(){ +# Given an existing file, $NOTE, print prints the contents of $NOTE to stdout. + +if [ -r "$NOTE" ]; then + if [ "$ENCRYPTION" == "TRUE" ]; then decrypt #to stdout + else cat "$NOTE"; fi +else + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "Note cannot be found." + exit 205 #ERR_NOTE_NO_READ +fi +} +function list(){ + # This function, given a folder, $NOTE, will list the contents of $NOTE. + ls "$NOTE" +} +# End Section: Functions +#============================================================================== +# Stage 1: Read Configuration / Verify Integrity +#============================================================================== + +if [ -r "$CONFIG_FILE" ]; then + source "$CONFIG_FILE" + verify_store +else + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "Configuration note found. Please run sns -i." + exit 5 #ERR_NO_STORE +fi + +if [ "$ENCRYPTION" == "TRUE" ]; then + if [ ! -r "$(which gpg)" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "Encryption was specified, but GPG is not installed." + exit 100 + elif [ -z "$PUBKEY" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "No GPG recipient was provided in $CONFIG_FILE. " + exit 110 + fi +fi +#============================================================================== +# Stage 2: Argument Parsing +#============================================================================== +NOTE="" +if [ -z "$1" ]; then help; exit 20 +else + for ARG in "$@"; do + case "$ARG" in + -c|--create) + CREATE="TRUE" + OP="TRUE" + ;; + -d|--delete) + DELETE="TRUE" + OP="TRUE" + ;; + -e|--edit) + EDIT="TRUE" + OP="TRUE" + ;; + -ce|-ec) + CREATE="TRUE" + EDIT="TRUE" + OP="TRUE" + ;; + -l|--list) + LIST="TRUE" + OP="TRUE" + ;; + -p|--print) + PRINT="TRUE" + OP="TRUE" + ;; + -h|--help) + help + exit 0 + ;; + -i|--init-store) + init_store + exit 0 + ;; + *) + NOTE="$ARG" + break; + ;; + esac + done +fi +#============================================================================== +# Section: Actions / Stage 3 +#============================================================================== +# Default behavior +# If no operation was specified, print help and exit on ERR_NO_OP + if [ "$OP" != "TRUE" ]; then + help; exit 20 + fi +# All options not requiring a note to be specified have been dealt +# with; if one isn't specified, exit on ERR_NO_NOTE. +if [ -z "$NOTE" ]; then + printf " $RED_COLOR!$RESET_COLOR %s\n" "No note specified." + exit 30 +fi + +if [ "$ENCRYPTION" == "TRUE" ]; then + SESSION_ID="$RANDOM" #SESSION_ID later becomes the temporary filename + readonly NOTE="$NOTE.$EXT.gpg" +else + readonly NOTE="$NOTE.$EXT" +fi + +if [ "$LIST" == "TRUE" ]; then list ; exit 0; fi +if [ "$PRINT" == "TRUE" ]; then print ; exit 0; fi +if [ "$DELETE" == "TRUE" ]; then delete; exit 0; fi +if [ "$CREATE" == "TRUE" ]; then create; fi +if [ "$EDIT" == "TRUE" ]; then edit ; fi +#============================================================================== +# End Section: Actions / Stage 3 +#============================================================================== diff --git a/src/main/stage1.sns.sh b/src/main/stage1.sns.sh index 26ec031..ede1d7d 100644 --- a/src/main/stage1.sns.sh +++ b/src/main/stage1.sns.sh @@ -8,6 +8,7 @@ if [ -r "$CONFIG_FILE" ]; then else >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ "Configuration note found. Please run sns -i." + exit 5 #ERR_NO_STORE fi if [ "$ENCRYPTION" == "TRUE" ]; then