diff --git a/build/sns.sh b/build/sns.sh new file mode 100755 index 0000000..3073c0c --- /dev/null +++ b/build/sns.sh @@ -0,0 +1,359 @@ +#!/bin/bash +# Simple Note System +# Copyright (C) 2016, Jon Lewis +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# 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, otherwise, sns will + # use the editor specified in the environment. + +DATE_FMT="+%D %T" # Date Format: + # If you would like to modify the date format, you may + # specify one appropriate to the \`date\` command. + +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 [-cedlp] " + 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" " -i | --init : Write default config and initalize SNS store" + printf "\n%s" " -l | --list : List all notes in NOTEBOOK" + printf "\n%s" " -p | --print : Print note to console" + printf "\n" +} +function p_header(){ + printf "# %s\n## %s\n" "$(basename ${NOTE%.*})" "$(date "$DATE_FMT")" +} +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 "$NOTES_DIR/$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 "$NOTES_DIR/$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%.*}." + #Cleanup empty notebooks/sections] + find "$NOTES_DIR" -mindepth 1 -type d | tac |\ + while read -r DIR ; do + if [ ! "$(ls -A $DIR)" ]; then + rmdir "$DIR" + fi + done + 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 "$NOTES_DIR/$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 "$NOTES_DIR/$NOTE" "$NOTES_DIR/$NOTE.bk" #Insurance + TMP_NOTE="$TMP_DIR/$SESSION_ID" + decrypt > "$TMP_NOTE" +else + TMP_NOTE="$NOTES_DIR/$NOTE"; +fi + +# Write an ammendment header +if [ -z "$CREATE" ]; then + printf "\n%s\n" "edit - $(date "$DATE_FMT")" >> "$TMP_NOTE" + printf "%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 + echo "reencrypting" + rm "$NOTES_DIR/$NOTE" + encrypt; + rm "$TMP_NOTE" + if [ ! -r "$NOTES_DIR/$NOTE" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n" "error: note was not saved." + cp "$NOTES_DIR/$NOTE.bk" "$NOTES_DIR/$NOTE" + else + rm "$NOTES_DIR/$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 +} +#!/bin/bash +function list(){ + # This function, given a folder, $NOTE, will list the contents of $NOTE. + cd "$(dirname "$NOTES_DIR/$NOTE")" + find . -type f -name "*$EXT" | while read file; do + printf "%s\n" "$file" + done + + +} +# End Section: Functions +#============================================================================== +# Stage 1: Read Configuration / Verify Integrity +#============================================================================== + +if [ -r "$CONFIG_FILE" ]; then + source "$CONFIG_FILE" + verify_store +elif [ $1 != "-i" ]; then + >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ + "Configuration not 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 + else + cd "$NOTES_DIR" + find . -type f -name "*.$EXT" | grep -v "gpg" | while read TMP_NOTE; do + NOTE="${TMP_NOTE%.$EXT}.gpg.$EXT" + echo $NOTE + encrypt + if [ -r $NOTE ]; then + rm $TMP_NOTE + fi + done + + 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.gpg.$EXT" +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 1ddfc3c..5dd3cab 100644 --- a/src/main/stage1.sns.sh +++ b/src/main/stage1.sns.sh @@ -20,5 +20,16 @@ if [ "$ENCRYPTION" == "TRUE" ]; then >&2 printf " $RED_COLOR!$RESET_COLOR %s\n\t%s\n"\ "No GPG recipient was provided in $CONFIG_FILE. " exit 110 + else + cd "$NOTES_DIR" + find . -type f -name "*.$EXT" | grep -v "gpg" | while read TMP_NOTE; do + NOTE="${TMP_NOTE%.$EXT}.gpg.$EXT" + echo $NOTE + encrypt + if [ -r $NOTE ]; then + rm $TMP_NOTE + fi + done + fi fi