Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions .github/workflows/dependency-check.yml

This file was deleted.

56 changes: 38 additions & 18 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,21 @@ android {
versionName "0.1.0-Alpha"
}

flavorDimensions "default"

productFlavors {
dev {
dimension "default"
applicationIdSuffix ".dev"
versionNameSuffix "-Dev"
manifestPlaceholders = [appIcon: "@mipmap/dev_ic_launcher", appLabel: "Devpasscode"] // the name come from a parent project name "PassCodes"
}
prod {
dimension "default"
manifestPlaceholders = [appIcon: "@mipmap/ic_launcher", appLabel: "@string/app_name"]
}
}

signingConfigs {
release {
def keystorePropertiesFile = rootProject.file("keystore.properties")
if (keystorePropertiesFile.exists()) {
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
}

splits {
abi {
enable true
Expand All @@ -66,17 +51,48 @@ android {
if (rootProject.file("keystore.properties").exists()) {
signingConfig signingConfigs.release
}

minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher",
appLabel: "@string/app_name"
]
}

debug {
applicationIdSuffix ".dev"
versionNameSuffix "-Dev"
minifyEnabled false

// the name come from a parent project name "PassCodes"
manifestPlaceholders = [
appIcon: "@mipmap/dev_ic_launcher",
appLabel: "Passcodes Dev"
]
}

staging {
applicationIdSuffix ".staging"
versionNameSuffix "-Staging"

minifyEnabled true
debuggable true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

manifestPlaceholders = [
appIcon: "@mipmap/dev_ic_launcher",
appLabel: "Passcodes Stageing"
]
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

viewBinding {
enabled = true
}
Expand All @@ -86,4 +102,8 @@ dependencies {
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.databinding:viewbinding:7.4.1'
implementation 'org.json:json:20250517'

testImplementation 'junit:junit:4.13.2'
testImplementation "com.google.truth:truth:1.4.4"
}
8 changes: 4 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.passwordmanager">
xmlns:tools="http://schemas.android.com/tools">

<uses-sdk
android:minSdkVersion="26"
android:targetSdkVersion="33" />

<!-- Storage access permission -->
<!-- Storage access permission
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />

<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
android:maxSdkVersion="32" /> -->

<application
android:allowBackup="true"
Expand All @@ -34,6 +33,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.PasswordManagerActivity" />
<activity android:name=".ui.SavePasswordActivity" />
<activity android:name=".ui.LoadPasswordActivity" />
<activity android:name=".ui.ViewPasswordActivity" />
Expand Down
15 changes: 5 additions & 10 deletions app/src/main/java/com/passwordmanager/ui/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,13 @@ public void onRequestPermissionsResult(

// Added all the onclick event listiners
private void addOnClickListenerOnButton(ActivityMainBinding binding) {
binding.savePasswordBtn.setOnClickListener(v -> {
Intent savepasswordintent = new Intent(MainActivity.this, SavePasswordActivity.class);
startActivity(savepasswordintent);
binding.passwordManagerBtn.setOnClickListener(v -> {
Intent passwordmanagerintent = new Intent(MainActivity.this, PasswordManagerActivity.class);
startActivity(passwordmanagerintent);
});

binding.loadPasswordBtn.setOnClickListener(v -> {
Intent loadpasswordintent = new Intent(MainActivity.this, LoadPasswordActivity.class);
startActivity(loadpasswordintent);
});

binding.aboutUsBtn.setOnClickListener(v -> {
Intent aboutusintent = new Intent(MainActivity.this, AboutUsActivity.class);
binding.aboutUsBtn.setOnClickListener(v -> {
Intent aboutusintent = new Intent(MainActivity.this, AboutUsActivity.class);
startActivity(aboutusintent);
});

Expand Down
138 changes: 138 additions & 0 deletions app/src/main/java/com/passwordmanager/ui/PasswordManagerActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.passwordmanager.ui;

import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.widget.Toast;
import androidx.annotation.Nullable;
import android.content.Intent;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat;
import android.view.LayoutInflater;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.passwordmanager.R;
import com.passwordmanager.utils.Controller;
import com.passwordmanager.models.PasswordModel;
import com.passwordmanager.databinding.ActivityPasswordManagerBinding;

import java.util.List;
import java.io.OutputStream;

public class PasswordManagerActivity extends AppCompatActivity {
private Controller controller;
private static final int CREATE_EXPORT_DATA_FILE_REQUEST = 1;

private String exportPasswordsContent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityPasswordManagerBinding binding = ActivityPasswordManagerBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

// Add event onclick listener
addOnClickListenerOnButton(binding);

// Make window fullscreen
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
}

// Added all the onclick event listiners
private void addOnClickListenerOnButton(ActivityPasswordManagerBinding binding) {
binding.savePasswordBtn.setOnClickListener(v -> {
Intent savepasswordintent = new Intent(PasswordManagerActivity.this, SavePasswordActivity.class);
startActivity(savepasswordintent);
});

binding.loadPasswordBtn.setOnClickListener(v -> {
Intent loadpasswordintent = new Intent(PasswordManagerActivity.this, LoadPasswordActivity.class);
startActivity(loadpasswordintent);
});

binding.securityCheckBtn.setOnClickListener(v -> {
Toast.makeText(this, getString(R.string.future_feat_clause), Toast.LENGTH_SHORT).show();
});

binding.importPasswordBtn.setOnClickListener(v -> {
Toast.makeText(this, getString(R.string.future_feat_clause), Toast.LENGTH_SHORT).show();
});

binding.exportPasswordBtn.setOnClickListener(v -> {
controller = new Controller(PasswordManagerActivity.this);
List<PasswordModel> allPasswords = controller.getAllPasswords();
exportPasswordsContent = convertPasswordsToJson(allPasswords);

if (exportPasswordsContent != null) {
createFile(null);
} else {
Toast.makeText(this, "Failed to generate secure report content.", Toast.LENGTH_SHORT).show();
}
});
}

private String convertPasswordsToJson(List<PasswordModel> passwordList) {
JSONArray jsonArray = new JSONArray();
try {
for (PasswordModel password : passwordList) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", password.getId());
jsonObject.put("domain", password.getDomain());
jsonObject.put("username", password.getUsername());
jsonObject.put("password", password.getPassword()); // !!! Highly Sensitive Data !!!
jsonObject.put("notes", password.getNotes());
jsonObject.put("createdAt", password.getCreatedAt());
jsonObject.put("updatedAt", password.getUpdatedAt());
jsonArray.put(jsonObject);
}

return jsonArray.toString(4);
} catch (JSONException e) {
return null;
}
}

private void createFile(@Nullable Uri pickerInitialUri) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/json");
intent.putExtra(Intent.EXTRA_TITLE, "password_manager_data.json");

if (pickerInitialUri != null) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
}

startActivityForResult(intent, CREATE_EXPORT_DATA_FILE_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == CREATE_EXPORT_DATA_FILE_REQUEST) {
if (resultCode == RESULT_OK && data != null) {
Uri uri = data.getData();
if (uri != null && exportPasswordsContent != null) {
try {
OutputStream outputStream = getContentResolver().openOutputStream(uri);
if (outputStream != null) {
outputStream.write(exportPasswordsContent.getBytes());
outputStream.close();
Toast.makeText(this, "Data export successfully to: " + uri.getPath(), Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Error export data: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Failed to get file URI or report content is empty.", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "File creation cancelled.", Toast.LENGTH_SHORT).show();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.passwordmanager.utils;

class ExampleTestableCode {
int checkStrength(String password) {
if (password == null || password.isEmpty()) {
return -1;
}

int length = password.length();

if (length < 8) {
return 0;
} else {
return 1;
}
}
}
Loading