PROJECT: modsUni

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:

      • Maintained the Glossary section of the Developer Guide (Pull request #83).

      • Updated User Guide and Developer Guide (Pull request #53, #131, #200, #277).

    • Community:

      • Reviewed pull requests (with non-trivial review comments): (Pull request #127 and #189).

      • Reported bugs and suggestions for other teams in the class (examples: 1, 2, 3, 4, 5, 6, 7).

    • 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 name userdata.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.

SaveCommandExample

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.

SaveCommandSuccessful

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!
SaveFileExample

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
    The SaveCommand stores the following attributes of a User 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 same Name.
    • 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.

SaveCommandUML

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.

SDforSaveCommandLogicAndModel

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.

SequenceDiagramforSave

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.

SequenceDiagramforSaveEventHandling

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:

  1. A student will first log into their account and add their preferred modules.

  2. Upon issuing the command save sp/userdata.xml, the save command will call Model#saveUserFile(…​) which then raises SaveUserChangedEvent. This SaveUserChangedEvent is then handled by StorageManager.

  3. StorageManager then utilizes XmlUserStorage#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.

SaveActivityDiagram

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 a byte[] with the specified password and returns the encrypted byte[].

  • DataSecurityUtil#decrypt(…​) — Decrypts a byte[] with the specified password and returns the decrypted byte[].

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.

SequenceDiagramforSaveEventHandlingWithEncryption

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.

SDforSaveCommandLogicAndModelUserDecryption

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.

DecryptionActivityDiagram

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.