Overview
CorpPro is an address book for corporate users.
It provides a fast and efficient system for corporate users to store their contacts safely and securely. It is also easy to maneuver and access contacts.
CorpPro is powered by JavaFX and boasts an intuitive GUI (Graphical User Interface) with easy-to-use CLI (Command Line Interface).
This portfolio documents my ability to write java programs, as well as documentation in the form of user and developer guides.
Summary of contributions
-
Feature 1: Added the ability for users to secure their address book by encrypting data.
-
What it does: Upon entering the
passwordcommand followed by a password, it will encrypt the address book data usingPBEWithMD5AndDEScipher. -
Justification: This feature was implemented so that corporate users can secure sensitive information in accordance to PDPA (Personal Data Protection Act) rules. This reduces the possibilities of data leaks and unwanted access.
-
Highlights: This feature implements a well-known cipher
PBEWithMD5AndDESandPBEKeySpecwhich accepts the user’s password. Once the file is encrypted, it will not be crackable unless done via brute forcing. It also requires file type checking to make sure that the user can compress both encryption and decryption process into one singlepasswordcommand much like a toggle so that users need not utilise 2 different commands for encrypting and decrypting. -
Credits: Code snippet adapted from Esailija [Stack overflow]
-
-
Feature 2: Implemented smart searching for
findcommand.-
What it does: Users can now search for the contacts they want by approximately specifying other traits/ attributes of the contacts. For example, users can search for contacts who live in Jurong West and are tagged as friends.
-
Justification: Corporate users might need to gather rough statistics of their clients or know which worker(s) to contact and assign work.
-
Highlights: This feature uses Levenshtein and Hamming Distance to find the closest match for the keywords entered. It will then sort the matches based on how close it is to the keywords entered and then perform a set intersection on the search results to narrow it down.
-
-
Feature 3: Implemented custom paths for data storage.
-
What it does: Users can now specify the path they wish to save their addressbook.xml to.
-
Justification: Corporate users might want to have separate address books without the need of storing their application in different folders. They can instead edit the preference file to change the name and location of their data storage file path.
-
Highlights: This feature requires implementing the json reader in
UserPrefsclass and storing it as a public variable for other classes to access.
-
-
Code contributed: [Reposense]
-
Other contributions:
-
Project management:
-
Managed releases
v1.1-v2.0(5 releases) on GitHub
-
-
Documentation:
-
Did cosmetic tweaks to existing contents of the User Guide
-
-
Community:
-
Tools:
-
Integrated a new Github plugin (Travis ci) to the team repo
-
Integrated a new Github plugin (AppVeyor) to the team repo
-
Integrated a new Github plugin (Coverall) to the team repo
-
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Finding persons by attribute : find
Finds persons whose names contain any of the given keywords.
Format: find PREFIX KEYWORD [MORE_KEYWORDS]
Examples:
-
find n/John
DisplaysjohnandJohn Doe -
find n/Betsy Tim John
Displays any person having namesBetsy,Tim, orJohn -
find e/example@domain.com
Displays any person having the emailexample@domain.com -
find a/jurong west ave
Displays any person who lives injurong,west,ave.
To better your experience with search, you should search for specific keywords to get to your results faster. Words such as Jurong would yield closer results compared to Jurong West Ave
|
-
find k/4.0
Displays any person who has a KPI of4.0 -
find d/John is forgetful
Displays any person who has a note containingJohn is forgetful -
find t/tester
Displays any person who is tagged astester -
find n/John Betsy r/secretary a/jurong west ave
Displays any person having namesJohnandBetsywho is asecretaryand lives injurong west ave
Search guessing
This feature will also display actual Keywords matched and Keywords guessed to give you a good indicator of which results were guessed.
From the above results we can see that Bernicc yields Keywords guessed: {Bernice} whereas Alex yields Keywords matched: {Alex}
Examples:
-
find p/9123
Displays any person having the phone number similar to9123eg.91231231,91231234, and so on.
| To narrow down your searches, try to be more specific in the phone number you wish to search for. |
Encrypting data files : password
Encrypts the data file with your password. All commands will be disabled during encryption, your data will be safely protected.
Format: password YOURPASSWORD
You can use the same command to decrypt the file, just hit password and your correct password.
|
Safe analogy
|
This feature does not actually store passwords. You will have to secure it with a password again after decryption to secure it. Passwords can only be alpha-numeric. |
Treat this feature as if it is a safe, once you have locked it, you have to remember the password in order to unlock it again.
And once you have unlocked it, you are free to set a new password.
Examples:
-
password helloworld
Locks address book with a password string and clears all data.
Entering password helloworld again unlocks the address book and restores all data.
|
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Find and Search
Current Implementation
The find function has been revamped to support search guessing and search by attributes.
FindCommand is now backed up by the ClosestMatchList class which uses LevenshteinDistanceUtil and HammingDistanceUtil to generate an ordered set of Person attributes ordered by similarity.
Design Considerations
Aspect: How find command executes
-
Alternative 1: Find using only predicates
-
Pros: Easy to implement.
-
Cons: Search must be exact, cannot have typos or incomplete keywords
-
-
Alternative 2: Store the search results in a
treeMapordered by their Levenshtein or Hamming distances from the search keyword-
Pros: Will also consider searches that are similar to what we want and will account for typos or incomplete keywords
-
Cons: Added complexities in finding and searching, can be vague when searching for number attributes
-
-
Alternative 3 (current choice): Same as alternative 2 but we use Hamming distance for phone numbers and KPI attributes instead.
-
Pros: Phone number and KPI searches are now more precise
-
Cons: Added complexities in finding and searching
-
Aspect: Expanded features of find command
-
Alternative 1: Find only by name
-
Pros: Easy to implement.
-
Cons: Can only search by name of addressees
-
-
Alternative 2: Find by attributes
-
Pros: Can search by email, phone, address, etc instead of just the name of addressees
-
Cons: Can only search for one attribute at a time (i.e find by name or find by email)
-
-
Alternative 3 (current choice): Chain-able find attributes
-
Pros: Can search by email and phone and address, etc instead of just one at a time
-
Cons: Added complexities in find command
-
Aspect: Data structure to support the revamped Find command
treeMap was used to store the search results ordered by their Levenshtein or Hamming distances.
The results are then filtered and
results furthest away from the top few are ignored. The searches will then be passed thru their respective predicates
(NameContainsKeywordsPredicate, AddressContainsKeywordsPredicate, EmailContainsKeywordsPredicate, KpiContainsKeywordPredicate, NoteContainsKeywordsPredicate, PhoneContainsKeywordPredicate, PositionContainsKeywordsPredicate, TagContainsKeywordsPredicate)
before filtering the list.
Searching for a contact:
Step 1. The user executes find a/Clementi t/owesMoney to find all contacts staying in Clementi and bearing the owesMoney tag.
Step 2. The user input is parsed by AddressBookParser which creates a new FindCommandParser object.
Step 3. The arguments a/Clementi t/owesMoney are then parsed by the FindCommandParser.
Step 4. FindCommandParser then checks the validity of the arguments before it creates the FindCommand object.
Step 5. FindCommand then proceeds to create ClosestMatchList objects.
Step 6. It uses the list of keywords obtained from ClosestMatchList to create AddressContainsKeywordsPredicate and TagContainsKeywordsPredicate.
Step 7. These predicates are combined into a combinedPredicate object using the "AND" operation.
Step 8. The model is then updated by calling model.updateFilteredPersonList(combinedPredicate) together with the combined predicate obtained in Step 8.
Step 9. A CommandResult object will be created and an internal method findActualMatches() will be called to generate a string of keywords that are exact matches and keywords that are guessed.
Figure 1. Interactions inside the logic component for the find a/Clementi t/owesMoney command.
Figure 2. Interactions inside the ClosestMatchList class
Data Encryption
Current Implementation
The encrypt/ decrypt mechanism is facilitated by FileEncryptor.
It extends AddressBook with a encrypt/decrypt feature, maintained by PasswordCommand.
Additionally, it implements the following operations:
-
FileEncryptor#process()— Decrypts or encrypts the data file depending on its current state (encrypted or decrypted). -
VersionedAddressBook#decryptFile()— encrypts a file given the path and password. -
VersionedAddressBook#encryptFile()— decrypts a file given the path and password.
Given below is an example usage scenario and how the password mechanism behaves at each step.
Step 1. The user enters the password command with a password.
If the user enters a password which is non alpha-numeric, an error will be thrown at the CommandResult box. Only alpha-numeric passwords are supported by FileEncryptor
|
Step 2. The user closes the address book.
Step 3. The user re-opens the address book. No data will be shown as the XML data file is technically not present in the data folder.
Step 4. The user enters the password command with the right password. Address book will be refreshed and restored back to its former state (before encryption).
| If the user enters the wrong password , an error will be thrown at the CommandResult box. |
Design Considerations
Aspect: How encryption and decryption is done
-
The
PBEKeySpecis first specified using the "PBEWithMD5AndDES" specification. -
A secret key is generated from
SecretKeyFactoryusing "PBEWithMD5AndDES" cipher. -
A
Cipheris then used to encrypt or decrypt the file with a given password and key specifications. -
Additional salt is used in the password to ensure that the password cannot be easily broken down by dictionary attacks.
Aspect: Pros and cons of tight security
-
Pros: Your data is protected and it will be near impossible to use any third part tool to crack the data file.
-
Cons: Data will be permanently lost if you forget the password.
Encrypting the address book:
Step 1. The user executes password test to encrypt the address book with test as the password.
Step 2. PasswordCommandParser checks for the validity of the input password (if its alpha-numeric)
Step 3. If the password is acceptable, it is parsed to the PasswordCommand object
Step 4. Within the PasswordCommand object, a new FileEncryptor object is created and it will check if the address book is currently in a locked state
Step 5. If it is not currently locked, it will create a cipher and begin encrypting the address book with the input password.
Step 6. Previous addressbook.xml will be deleted whereas a new addressbook.xml.encrypted file will be created.
Step 7. A new emptyPredicate object will be instantiated and model.updateFilteredPersonList(emptyPredicate) will be called to clear the address book list.
Step 8. A CommandResult object will be created to notify the user that the encryption was successful
Accessing commands post encryption:
Step 1. The user executes list to list out all the contacts in the address book.
Step 2. The user input is parsed by AddressBookParser which creates a new ListCommandParser object.
Step 3. The arguments are then parsed by the ListCommandParser.
Step 4. ListCommandParser then checks the validity of the arguments before it creates the ListCommand object.
Step 5. ListCommand creates a FileEncryptor object to check if the address book is in a locked state by calling the islocked() method.
Step 6. isLocked() will return true.
Step 7. A CommandException will be thrown to warn the user that the address book is in a locked state.
Figure 1. Interactions inside the logic component for the password command.