1. Overview
This portfolio documents my contribution to the project - modsUni. modsUni is an open-sourced project that was collaborated with 4 other coursemates from the module CS2103 (Introduction to Software Engineering).
Project modsUni is a desktop application that was developed in 6 weeks which allowed us to practice our software engineering skills in a short time frame. This project aims to accelerate the process of planning a candidature for a university student. It was developed for users who prefer to interact with a Command Line Interface (CLI) over a Graphical User Interface (GUI). We have managed to contribute ~27,000 lines of code to a code base of 10,000 lines of code. Currently, we are targeting undergraduates from the National University of Singapore (NUS), and plan to expand to other local universities.
My contributions include the implementation of saving a user’s information securely into a local file and restoring the user’s information into the application using the saved file.
2. Summary of Contributions
-
Major enhancement: This enhancement added functionality to save and load a user’s (admin or student) data.
-
What it does:
-
Allows a user to save their information as a local file on the disk.
-
Allows returning users to restore their information using the previously saved file.
-
Encrypts a user’s information by default during the saving process.
-
Displays the saved information upon issue the save command.
-
-
Justification: Improves the user experience of modsUni significantly by having the ability to save their information locally onto a disk, allowing them to restore their data during the login process.
-
Highlights: Puts confidentiality in high regard with multiple security concerns raised and discussed prior to implementation. The inbuilt security feature was also made robust to prevent users from being frustrated.
-
-
Minor enhancement: This enhancement added functionality to enable a user to navigate between different tabs within the application using CLI.
-
Code contributed: [Functional code]
-
Other contributions:
-
Project management:
-
Updated Project Dashboard on GitHub to ensure cards are up-to-date.
-
Updated Pull Requests(PRs) with the relevant tags.
-
-
Documentation:
-
Community:
-
Tool: Integrated RepoSense to the project (Pull request #217).
-
3. 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. |
Saving user data: save
The save command stores the current user’s information locally to a file. The saved file is used during the login process to restore a user’s information.
Format: save sp/<FILE_NAME>.xml
Example:
-
save sp/userdata.xml
Saves the current user’s data to the file nameuserdata.xml
.
The prefix "sp" is the short form for "save path" .
|
Figure 1 shows an example on the usage of the save command in the application.
Figure 1. An example of a save command typed in the CLI
Upon entering the command, you will see the types of information stored as well as a successful message as shown in Figure 2.
Figure 2. An example of the application displaying the saved information and successful message upon entering save command
Upon entering the save command, a file depicted in Figure 3 will be generated. This file will be required when logging in.
Modifying the saved file may result in the loss of data that is unrecoverable. Edit at your own risk! |
Figure 3. An example of a saved file containing a user’s information
4. 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. |
Save User Feature
The save user feature involves mainly the saving process of a user’s attributes. A user can save their data only after they have logged in or registered an account.
Data refers to a user’s attributes listed in SaveCommand under the current implementation of the save user feature in the next section.
|
This section will describe in details the current implementation and the design considerations of the save user feature.
Current Implementation
The save mechanism is facilitated by the following classes:
-
SaveCommand
TheSaveCommand
stores the following attributes of aUser
object:-
Attributes that exist in all user:
-
Username
The username of a user. -
Name
The name of the user. -
Role
The role of the user.Username
is unique to every user and is used for logging in.Name
is non-unique and multiple users can use the sameName
.
-
-
Attributes that only exist in an admin:
-
Salary
The salary of an administrator. -
Employment Date
The employment date of an administrator.
-
-
Attributes that only exist in a student:
-
Enrollment Date
The enrollment date of a student. -
Major(s)
A list of a student’s major. -
Minor(s)
A list of a student’s minor. -
Modules Taken
A list of modules took by a student. -
Modules Staged
A list of modules staged for the generation of candidature.A student must have at least one major and can have no minor.
-
-
-
UserStorage
It provides methods to save the current user’s attributes as well as to load a file containing previously saved data.
UserStorage
implements the following operations:-
StorageManager#saveUser(…)
— Save the user’s data into the specified file path. -
StorageManager#readUser(…)
— Reads the user’s data from the specified file path.
-
Implementation of the save feature
The save
mechanism of modsUni is facilitated by SaveCommand
class and is event-driven.
It allows a user to save their data as an XML file.
Both admin and student can use the save feature. |
The SaveCommand
class extends from the Command
class as shown below in Figure 1.
Figure 1. SaveCommand UML Diagram
The parsing of command is performed by SaveCommandParser
, which returns a SaveCommand
object after parsing the save file path.
The sequence diagram shown below in Figure 2 illustrates the interactions between the Logic and Model components when the SaveCommand is being executed.
Figure 2. Sequence Diagram for the interaction between Logic and Model Components when executing SaveCommand
The save
feature uses multiple components of the modsUni application.
The sequence diagram shown below in Figure 3 illustrates the interactions between some of these components.
In addition, the sequence diagram also illustrates that SaveCommand
is driven by the SaveUserChangedEvent
.
Figure 3. High-Level Sequence Diagram for the save sp/userdata.xml
command
The SaveUserChangedEvent
mentioned above is handled by the Storage
component as shown in Figure 4.
Figure 4. High-Level Sequence Diagram showing how the Storage component handles SaveUserChangedEvent
which was triggered by EventsCenter
The Storage component makes use of XmlUserStorage
class to write User
to a file specified by the file path.
Both the conversion of User
object to XmlSerializableUser
as well as writing to file is shown in the following code snippet below:
public void saveUser(User user, Path filePath, String password) throws IOException {
// ... null checks ...
FileUtil.createIfMissing(filePath);
XmlFileStorage.saveDataToFile(filePath, new XmlSerializableUser(user, password));
}
XmlFileStorage#saveDataToFile(…)
utilizes XmlUtil#saveDataToFile(…)
to save the newly created XmlSerializableUser
object to the file as shown in the code snipplets below:
public static void saveDataToFile(Path file, XmlSerializableUser user) throws FileNotFoundException {
try {
XmlUtil.saveDataToFile(file, user);
} catch (JAXBException e) {
throw new AssertionError("Unexpected exception " + e.getMessage(), e);
}
}
Given below is an example usage scenario and how the save mechanism behaves:
-
A student will first log into their account and add their preferred modules.
-
Upon issuing the command
save sp/userdata.xml
, the save command will callModel#saveUserFile(…)
which then raisesSaveUserChangedEvent
. ThisSaveUserChangedEvent
is then handled byStorageManager
. -
StorageManager
then utilizesXmlUserStorage#saveUser(…)
which saves the file to the file path specified by the user.
A newly registered Student would be initialized and automatically logged in which enables the student to perform the save command. |
The following activity diagram shown in Figure 5 summarizes what happens when a user executes the save command.
Figure 5. Activity Diagram for the save command
Design Considerations
Aspect: Data to save
-
Alternative 1 (current choice): Save every attribute of a
User
.-
Pros: Able to restore to any state of a user.
-
Cons: Harder to implement as support for converting data of user to XML format needs to be added.
-
-
Alternative 2: Save only the staged modules.
-
Pros: Will use less storage space (saving only staged module vs saving all user data).
-
Cons: Does not restore the state of a user entirely.
-
Data Security Feature
The data security feature involves mainly the encryption of the user data file when using the save
command and the decryption of a user data file when logging in using the login
command.
Advanced Encryption Standard (AES) is the algorithm used for encryption. |
This section will describe in details the current implementation and the design considerations of the data encryption & decryption feature.
Current Implementation
The data security feature is facilitated by DataSecurityUtil
class.
DataSecurityUtil
implements the following operations:
-
DataSecurityUtil#encrypt(…)
— Encrypts abyte[]
with the specified password and returns the encryptedbyte[]
. -
DataSecurityUtil#decrypt(…)
— Decrypts abyte[]
with the specified password and returns the decryptedbyte[]
.
DataSecurityUtil
class utilizes javax.crypto.cipher
and javax.crypto.spec.SecretKeySpec
packages for the operations mentioned above.
The Hashing
class is also used to generate an SHA-1 hash to ensure that there are at least 16 bytes (128 bits) which is required to generate SecretKeySpec
.
The encryption and decryption of user data are performed in XMLAdaptedUser
.
Implementation of the encryption feature
The encryption feature is integrated with the Save User Feature.
During the conversion of a User
object to XML, the encryption is performed in XMLAdapterUser
, right before the file is written locally.
Currently, only Username
(for all users) and Salary
(for administrators) is encrypted.
The following code snippet shown below illustrates the encryption process:
public XmlAdaptedUser(User user, String password) {
// ... null checks ...
// All users
this.username = DataSecurityUtil.bytesToBase64(DataSecurityUtil.encrypt(
user.getUsername().toString().getBytes(), password));
this.name = user.getName().toString();
this.role = user.getRole().toString();
this.pathToProfilePic = user.getPathToProfilePic().toString();
// Admin
if (user.getRole() == Role.ADMIN) {
Admin admin = (Admin) user;
this.salary = DataSecurityUtil.bytesToBase64(DataSecurityUtil.encrypt(
admin.getSalary().toString().getBytes(), password));
this.employmentDate = admin.getEmploymentDate().toString();
}
// ... removed for brevity ...
}
The sequence diagram shown below in Figure 1 illustrates the integration of encryption with the save user feature.
Figure 1. Sequence Diagram for the interaction between EventsCenter and Storage Components when executing SaveCommand with encryption
Implementation of the decryption feature
The decryption feature is integrated with the login feature under User Account Management.
When LoginCommand
calls model.readUser(…)
the loading of user file will commence and the decryption will occur in XMLAdapterUser#toModelType(…)
.
This is shown in the following code snippets below:
public User toModelType(String password) throws IllegalValueException, CorruptedFileException,
NoSuchPaddingException, InvalidPasswordException, NoSuchAlgorithmException, InvalidKeyException {
User user = null;
checkMandatoryFields();
// Applies to all user
String decryptedUsername = decryptUsername(password);
// Applies to only admin
if ("ADMIN".equals(role)) {
checkAdminFields();
String decryptedSalary = decryptSalary(password);
user = new Admin(new Username(decryptedUsername), new Name(name), Role.ADMIN, new Salary(decryptedSalary), new EmployDate(employmentDate));
}
// ... removed for brevity ...
return user;
}
The code snippets of decryptUsername(…)
and decryptSalary(…)
are shown below respectively:
private String decryptUsername(String password) throws NoSuchAlgorithmException, InvalidKeyException,
InvalidPasswordException, CorruptedFileException, NoSuchPaddingException {
return new String(DataSecurityUtil.decrypt(
DataSecurityUtil.base64ToBytes(username), password), StandardCharsets.UTF_8);
}
private String decryptSalary(String password) throws NoSuchAlgorithmException, InvalidKeyException,
InvalidPasswordException, CorruptedFileException, NoSuchPaddingException {
return new String(DataSecurityUtil.decrypt(
DataSecurityUtil.base64ToBytes(salary), password), StandardCharsets.UTF_8);
}
The sequence diagram shown below in Figure 2 illustrates the integration of decryption with the login feature.
Figure 2. Sequence Diagram for the interaction between Logic Component and DataSecurityUtil when executing LoginCommand
The following activity diagram shown in Figure 3 summarizes what happens in the decryption process when a user executes the login command.
Figure 3. Activity Diagram for decryption feature in the login command
Design Considerations
Aspect: How encryption is implemented
-
Alternative 1 (current choice): Implement as an inbuilt feature.
-
Pros: Confidentiality of a user’s data file is preserved at all times.
-
Cons: User does not have full control over user data file.
-
-
Alternative 2: Implement as a command.
-
Pros: User will have more control over data security.
-
Cons: Enforcement of data security outside of the application would be harder.
-
Aspect: Generation of security key for encryption/decryption
-
Alternative 1 (current choice): Generate the key using a user’s password.
-
Pros: User does not need to supply additional information or file for encryption or decryption.
-
Cons: User is unable to decrypt their user data file if they forget their password.
-
-
Alternative 2: Generate the key using
KeyGenerator
and an additional file is needed to log in.-
Pros: The key will be more secured compared to the key generated from alternative one since a weak password that is susceptible to password cracking may be used by a user.
-
Cons: User is unable to decrypt their user data file if the key file is lost or corrupted.
-
Aspect: What fields to encrypt
-
Alternative 1 (current choice): Encrypt some fields (Username and Salary).
-
Pros: The encryption of username ensures that a malicious user is unable to correlate a specific user data file to a credential in the credential store. In addition, advance users can edit unencrypted fields in the user data file.
-
Cons: The user data file will contain unencrypted information.
-
-
Alternative 2: Encrypt every field.
-
Pros: The user data file is secure since every field is encrypted.
-
Cons: Advance user are unable to edit from the user data file manually.
-