11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_credential_display.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 18dp
7 | 16dp
8 | 16dp
9 | 192dp
10 |
11 |
--------------------------------------------------------------------------------
/app/src/test/java/es/wolfi/app/passman/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package es.wolfi.app.passman;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_autofill_interaction.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_refresh_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/10.txt:
--------------------------------------------------------------------------------
1 | - New confirm dialog to delete a credential
2 | - New option to sort credentials by label
3 | - Migrated save and delete buttons to floating action buttons
4 | - Fix broken messages when the keyboard was open
5 | - Use uniform (editable) connect/response timeouts for common api requests
6 | - Fix endless loading dialog after deleting a credential
7 | - Fix autofill vault selection if the vault is active and selected as default
8 | - Security fixes that could have ended on memory corruption on the cryptographic c++ core
9 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/9.txt:
--------------------------------------------------------------------------------
1 | - Add support for managing credentials and files
2 | - New app settings, vault refresh and lock buttons
3 | - New loading dialog
4 | - Deactivate the computationally expensive OTP generation if no OTP has been specified
5 | - Add support for user CA certificates (requires at least Android 7.x)
6 | - Mark compromised credentials
7 | - Add URL copy and open button
8 | - Add app start password option based on the android user authentication
9 | - Implement Android autofill feature (requires at least Android 8)
10 |
--------------------------------------------------------------------------------
/openssl.conf.example:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [[ -z $ANDROID_HOME ]]; then
4 | export ANDROID_HOME=$HOME/Android/Sdk
5 | fi
6 |
7 | export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/28.1.13356709
8 | export HOST_TAG=linux-x86_64 # darwin-x86_64 / linux-x86_64 / windows / windows-x86_64
9 | export MIN_SDK_VERSION=21
10 |
11 | export CFLAGS="-Os -ffunction-sections -fdata-sections -fno-unwind-tables -fno-asynchronous-unwind-tables"
12 | export LDFLAGS="-Wl,-s -Wl,-Bsymbolic -Wl,--gc-sections"
13 | export THREADS=12 # Number of threads to use while compiling openssl
14 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/14.txt:
--------------------------------------------------------------------------------
1 | - add offline cache (can be disabled in settings)
2 | - add local storage encryption for sensitive data (requires at least Android 6 / API 23)
3 | - encrypts the offline cache
4 | - stored vault passwords have to be re-entered
5 | - cloud connection settings will be migrated automatically
6 | - add an internal settings cache to speed up some things a bit
7 | - add vault actions (add, rename, delete)
8 | - delete action requires at least Passman v2.4.0 (server side)
9 | - update dependencies (gradle/appcompat)
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_sort_by_alpha_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_otp_progress.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_lock_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_qr_code_scanner_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_share_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_scan_qrcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_password_list.xml:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | This is an Android app for the Nextcloud password manager Passman.
2 |
3 | This app is only compatible with Passman V2.x or higher.
4 |
5 | Features
6 |
7 | * Setup app (enter the nextcloud server settings or use SSO)
8 | * App start password option based on the android user authentication
9 | * View, add, rename and delete vaults
10 | * Login to vault
11 | * Display credential list
12 | * View, add, edit and delete credentials
13 | * Add, download and delete files
14 | * OTP generation
15 | * Basic Android autofill implementation
16 | * Password generator
17 | * Encrypted offline cache
18 | * Encrypted stored vault and cloud connection passwords
19 |
20 | Requirements
21 |
22 | * Nextcloud
23 | * Nextcloud Passman App
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/progress_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/wolfi/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # This is generated automatically by the Android Gradle plugin.-dontwarn org.conscrypt.Conscrypt$ProviderBuilder
20 | -dontwarn org.conscrypt.Conscrypt
21 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/es/wolfi/app/passman/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package es.wolfi.app.passman;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("es.wolfi.app.passman", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #0082c9
4 | #006AA3
5 | #007CC2
6 | #ffffff
7 | #000000
8 |
11 | @color/white
12 | #7fC0E3
13 |
14 | @color/colorAccent
15 | @color/white
16 | #D6D7D7
17 | @color/black
18 |
19 | #00000000
20 | #FF0000
21 | #36FF0000
22 | #7E4C819F
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/login_decision_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/Filterable.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | public interface Filterable {
26 | public String getFilterableAttribute();
27 | }
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 | app/.cxx
11 | app/release
12 | app/googlePlayRelease
13 | # Built application files
14 | *.apk
15 | *.ap_
16 | output-metadata.json
17 |
18 | # Files for the ART/Dalvik VM
19 | *.dex
20 |
21 | # Java class files
22 | *.class
23 |
24 | # Generated files
25 | bin/
26 | gen/
27 | out/
28 |
29 | # Gradle files
30 | .gradle/
31 | build/
32 |
33 | # Local configuration file (sdk path, etc)
34 | local.properties
35 |
36 | # Proguard folder generated by Eclipse
37 | proguard/
38 |
39 | # Log Files
40 | *.log
41 |
42 | # Android Studio Navigation editor temp files
43 | .navigation/
44 |
45 | # Android Studio captures folder
46 | captures/
47 |
48 | # Intellij
49 | *.iml
50 | .idea/workspace.xml
51 | .idea/tasks.xml
52 | .idea/gradle.xml
53 | .idea/libraries
54 |
55 | # Keystore files
56 | *.jks
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 |
61 | # Google Services (e.g. APIs or Firebase)
62 | google-services.json
63 |
64 | Openssl.conf
65 | openssl.conf
66 | .idea/*
67 |
68 | gradle.properties
69 |
--------------------------------------------------------------------------------
/gradle.properties.example:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 | ALPHA_STORE=alpha/store/file/path
19 | ALPHA_STORE_PASSWORD=alpha store key
20 | ALPHA_KEY_ALIAS=beta
21 | ALPHA_KEY_PASSWORD=alpha key password
22 | RELEASE_STORE=/path/to/release/store
23 | RELEASE_STORE_PASSWORD=release store password
24 | RELEASE_KEY_ALIAS=release
25 | RELEASE_KEY_PASSWORD=release store key
26 | android.useAndroidX=true
27 | android.enableJetifier=true
28 | android.nonTransitiveRClass=false
29 | android.nonFinalResIds=false
30 |
--------------------------------------------------------------------------------
/app/src/main/cpp/SJCL.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | #include
24 |
25 | using namespace std;
26 | namespace WLF {
27 | namespace Crypto {
28 | class SJCL {
29 | public:
30 | static char* decrypt(string sjcl_json, string key);
31 | static char* encrypt(char* message, const string& key);
32 | };
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/otp/CodeGenerationException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2024, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.utils.otp;
24 |
25 | public class CodeGenerationException extends Exception {
26 | public CodeGenerationException(String message, Throwable cause) {
27 | super(message, cause);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/CallbackNames.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 | package es.wolfi.app.passman;
23 |
24 |
25 |
26 | public enum CallbackNames {
27 | LOGIN("login"),
28 | ;
29 |
30 |
31 | private final String name;
32 |
33 | CallbackNames(final String name) {
34 | this.name = name;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return name;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/OfflineStorageValues.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | */
21 |
22 | package es.wolfi.app.passman;
23 |
24 | public enum OfflineStorageValues {
25 | VAULTS("vaults"),
26 | VERSION("version");
27 |
28 | private final String name;
29 |
30 | OfflineStorageValues(final String name) {
31 | this.name = name;
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return name;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/cpp/base64.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | #ifndef BASE64_H
24 | #define BASE64_H
25 |
26 | #include
27 |
28 | namespace WLF {
29 | namespace Crypto {
30 | struct Datagram {
31 | unsigned char* data;
32 | int length;
33 | };
34 |
35 | class BASE64{
36 |
37 | public:
38 | static Datagram* encode(const unsigned char *str, int length);
39 |
40 | static Datagram* decode(const unsigned char *str, int length);
41 | };
42 |
43 | }
44 | }
45 |
46 | #endif //PASSMAN_BASE64_H
47 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/passman/API/SharingACL.java:
--------------------------------------------------------------------------------
1 | package es.wolfi.passman.API;
2 |
3 | public class SharingACL {
4 | public enum PERMISSION {
5 | READ(0x01),
6 | WRITE(0x02),
7 | FILES(0x04),
8 | HISTORY(0x08),
9 | OWNER(0x80);
10 |
11 | final int permissionValue;
12 |
13 | PERMISSION(int value) {
14 | permissionValue = value;
15 | }
16 |
17 | public int permissionValue() {
18 | return permissionValue;
19 | }
20 | }
21 |
22 | private int permission;
23 |
24 | public SharingACL(int permission) {
25 | this.permission = permission;
26 | }
27 |
28 | /**
29 | * Checks if a user has the given permission/s.
30 | */
31 | public boolean hasPermission(PERMISSION permission) {
32 | return permission.permissionValue == (this.permission & permission.permissionValue);
33 | }
34 |
35 | /**
36 | * Adds a permission to a user, leaving any other permissions intact.
37 | */
38 | public void addPermission(PERMISSION permission) {
39 | this.permission = this.permission | permission.permissionValue;
40 | }
41 |
42 | /**
43 | * Removes a given permission from the item, leaving any other intact.
44 | */
45 | public void removePermission(PERMISSION permission) {
46 | this.permission = this.permission & ~permission.permissionValue;
47 | }
48 |
49 | public int getPermission() {
50 | return this.permission;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/ListUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Iterator;
27 |
28 | public class ListUtils {
29 | public static ArrayList filterList(String filter, ArrayList list){
30 | ArrayList copiedList = new ArrayList(list);
31 | Iterator it = copiedList.iterator();
32 | while (it.hasNext()) {
33 | if (!it.next().getFilterableAttribute().contains(filter)) {
34 | it.remove();
35 | }
36 | }
37 | return copiedList;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_password_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/ColorUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2017, Andy Scherzinger
5 | * @license GNU AGPL version 3 or any later version
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as
9 | * published by the Free Software Foundation, either version 3 of the
10 | * License, or (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | *
20 | */
21 |
22 | package es.wolfi.utils;
23 |
24 | import android.graphics.Color;
25 |
26 | /**
27 | * Util implementation for color calculations.
28 | */
29 | public class ColorUtils {
30 |
31 | /**
32 | * calculates a color for a given name.
33 | *
34 | * @param name the name String
35 | * @return the calculated color
36 | */
37 | public static int calculateColor(String name) {
38 | int hash = name.hashCode();
39 | int r = (hash & 0xFF0000) >> 16;
40 | int g = (hash & 0x00FF00) >> 8;
41 | int b = hash & 0x0000FF;
42 |
43 | //pastelize color
44 | r = (r + 127) / 2;
45 | g = (g + 127) / 2;
46 | b = (b + 127) / 2;
47 |
48 | return Color.rgb(r, g, b);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/PRIVACY.md:
--------------------------------------------------------------------------------
1 | # Passman Android - Privacy Policy
2 |
3 | The "Passman" Android-App (in the following referred to as "App") does not collect or send any data from you or your device to a server of the developers or the [Nextcloud GmbH](https://nextcloud.com/). The App sends all data exclusively to the server(s) configured by you with the intention to synchronize the contents of the App with those of the server. This data can contain IP-addresses, timestamps and further information as meta data.
4 | Data entered into the app (e.g. when saving) is necessarily transferred to the configured server(s). This contents can also contain personal information depending on the use. The server(s) you configured are technically outside the access area of this App developers, so that we neither know nor can prevent what happens to your data there. Please consult the privacy policy of the respective server operator.
5 |
6 | ## Permissions
7 |
8 | This is a list of permissions required and asked by the App in order to properly work on your device:
9 |
10 | - `android.permission.INTERNET`
11 |
12 | Used to communicate with your Nextcloud instance and synchronize contents.
13 |
14 | - `android.permission.READ_EXTERNAL_STORAGE`
15 |
16 | Used to select and add files to a credential.
17 |
18 | - `android.permission.WRITE_EXTERNAL_STORAGE`
19 |
20 | Used to store downloaded files from a credential on your device.
21 |
22 | - `android.permission.BIND_AUTOFILL_SERVICE`
23 |
24 | Used to provide a autofill service for known access data.
25 |
26 | - `android.permission.CAMERA`
27 |
28 | Used to provide a QR code scanner for OTP editing.
29 |
30 | ## Nextcloud privacy policy
31 |
32 | You can get more information on Nextcloud general privacy policy which is accessible at [nextcloud.com/privacy](https://nextcloud.com/privacy/).
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/autofill_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
26 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/JSONUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | public class JSONUtils {
26 | /**
27 | * Checks if an string looks like a json object
28 | * @param text to check
29 | * @return true if it looks like a json object, false otherwise
30 | */
31 | public static final boolean isJSONObject(String data){
32 | if (data.length() == 0) return false;
33 | return data.charAt(0) == '{' && data.charAt(data.length() -1) == '}';
34 | }
35 |
36 | /**
37 | * Check if an string seems like a json array
38 | * @param the text to check
39 | * @return true if it looks like an array, false otherwise
40 | */
41 | public static final boolean isJSONArray(String data){
42 | if (data.length() == 0) return false;
43 | return data.charAt(0) == '[' && data.charAt(data.length() -1) == ']';
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_credential_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
28 |
29 |
36 |
37 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_credential_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
28 |
29 |
36 |
37 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/autofill/AutofillFieldCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.app.passman.autofill;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Collections;
27 | import java.util.List;
28 |
29 | public class AutofillFieldCollection extends ArrayList {
30 | public AutofillField getRequiredId(String hint) {
31 | // Order: Android Hint, HTMLInfo, View Hint, Resource id
32 | // Focused First
33 |
34 | Collections.sort(this);
35 |
36 | for (AutofillField field : this) {
37 | if (field.hasHint(hint)) {
38 | return field;
39 | }
40 | }
41 | return null;
42 | }
43 |
44 | public List getOptionalIds(String hint) {
45 | // Order: Android Hint, View Hint, HTMLInfo, Resource id
46 | // Focused First
47 | // Excludes requiredIds
48 | List allMatching = new ArrayList<>();
49 |
50 | Collections.sort(this);
51 |
52 | for (AutofillField field : this) {
53 | if (field.hasHint(hint)) {
54 | allMatching.add(field);
55 | }
56 | }
57 | allMatching.remove(getRequiredId(hint));
58 |
59 | return allMatching;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/autofill_list_item_with_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
26 |
27 |
39 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/SettingValues.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | */
21 |
22 | package es.wolfi.app.passman;
23 |
24 | public enum SettingValues {
25 | HOST("host"),
26 | USER("user"),
27 | PASSWORD("password"),
28 | VAULTS("vaults"),
29 | ACTIVE_VAULT("active_vault"),
30 | AUTOFILL_VAULT_GUID("autofill_vault_guid"),
31 | AUTOFILL_VAULT("autofill_vault"),
32 | ENABLE_AUTOFILL_MANUAL_SEARCH_FALLBACK("enable_autofill_manual_search_fallback"),
33 | ENABLE_APP_START_DEVICE_PASSWORD("enable_app_start_device_password"),
34 | ENABLE_CREDENTIAL_LIST_ICONS("enable_credential_list_icons"),
35 | REQUEST_CONNECT_TIMEOUT("request_connect_timeout"),
36 | REQUEST_RESPONSE_TIMEOUT("request_response_timeout"),
37 | CLEAR_CLIPBOARD_DELAY("clear_clipboard_delay"),
38 | PASSWORD_GENERATOR_SETTINGS("password_generator_settings"),
39 | ENABLE_PASSWORD_GENERATOR_SHORTCUT("enable_password_generator_shortcut"),
40 | OFFLINE_STORAGE("offline_storage"),
41 | ENABLE_OFFLINE_CACHE("enable_offline_cache"),
42 | KEY_STORE_MIGRATION_STATE("key_store_migration_state"),
43 | KEY_STORE_ENCRYPTION_KEY("key_store_encryption_key");
44 |
45 | private final String name;
46 |
47 | SettingValues(final String name) {
48 | this.name = name;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return name;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/CredentialLabelSort.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | import java.util.Comparator;
26 |
27 | import es.wolfi.passman.API.Credential;
28 |
29 | /**
30 | * Created by wolfi on 12/11/17.
31 | */
32 |
33 | public class CredentialLabelSort implements Comparator {
34 |
35 | /**
36 | * credential sort methods:
37 | * description code
38 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as
9 | * published by the Free Software Foundation, either version 3 of the
10 | * License, or (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package es.wolfi.utils;
22 |
23 | import android.content.Context;
24 | import android.content.pm.PackageInfo;
25 | import android.content.pm.PackageManager;
26 |
27 | import java.util.Arrays;
28 | import java.util.List;
29 |
30 | /**
31 | * Utils for Nextcloud files app based SSO
32 | */
33 | public class SSOUtils {
34 |
35 | /**
36 | * Checks whether a supported Nextcloud files app is installed or not.
37 | *
38 | * @param context Context to get packageManager
39 | * @return whether a supported Nextcloud files app is installed or not
40 | */
41 | public static boolean isNextcloudFilesAppInstalled(Context context) {
42 | final String PROD_PACKAGE_ID = "com.nextcloud.client";
43 | final String BETA_PACKAGE_ID = "com.nextcloud.android.beta";
44 | List APPS = Arrays.asList(PROD_PACKAGE_ID, BETA_PACKAGE_ID);
45 |
46 | PackageManager pm = context.getPackageManager();
47 | for (String app : APPS) {
48 | try {
49 | PackageInfo pi = pm.getPackageInfo(app, PackageManager.GET_ACTIVITIES);
50 | // Nextcloud Files app version 30180090 is required by the used SSO library
51 | if ((pi.versionCode >= 30180090 && pi.packageName.equals("com.nextcloud.client")) ||
52 | pi.versionCode >= 20211118 && pi.packageName.equals("com.nextcloud.android.beta")) {
53 | return true;
54 | }
55 | } catch (PackageManager.NameNotFoundException ignored) {
56 | }
57 | }
58 | return false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/QrCodeAnalyzer.java:
--------------------------------------------------------------------------------
1 | package es.wolfi.utils;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.camera.core.ImageAnalysis;
5 | import androidx.camera.core.ImageProxy;
6 |
7 | import com.google.zxing.BinaryBitmap;
8 | import com.google.zxing.ChecksumException;
9 | import com.google.zxing.FormatException;
10 | import com.google.zxing.NotFoundException;
11 | import com.google.zxing.PlanarYUVLuminanceSource;
12 | import com.google.zxing.Result;
13 | import com.google.zxing.common.HybridBinarizer;
14 | import com.google.zxing.qrcode.QRCodeReader;
15 | import com.koushikdutta.async.future.FutureCallback;
16 |
17 | import java.nio.ByteBuffer;
18 |
19 | public class QrCodeAnalyzer implements ImageAnalysis.Analyzer {
20 |
21 | public final static String LOG_TAG = QrCodeAnalyzer.class.getSimpleName();
22 |
23 | private final QRCodeReader qrCodeReader = new QRCodeReader();
24 | private final FutureCallback callback;
25 | private boolean foundToken = false;
26 |
27 | public QrCodeAnalyzer(FutureCallback callback) {
28 | this.callback = callback;
29 | }
30 |
31 | @Override
32 | public void analyze(@NonNull ImageProxy image) {
33 | if (foundToken) {
34 | return;
35 | }
36 |
37 | Result result = null;
38 | Exception exception = null;
39 |
40 | ByteBuffer buffer = image.getPlanes()[0].getBuffer();
41 |
42 | byte[] imageData = new byte[buffer.remaining()];
43 | buffer.get(imageData);
44 |
45 | PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
46 | imageData,
47 | image.getWidth(),
48 | image.getHeight(),
49 | 0,
50 | 0,
51 | image.getWidth(),
52 | image.getHeight(),
53 | false
54 | );
55 |
56 | try {
57 | result = qrCodeReader.decode(new BinaryBitmap(new HybridBinarizer(source)));
58 | foundToken = true;
59 | } catch (NotFoundException | ChecksumException ignored) {
60 | // Whenever reader fails to detect a QR code in image it throws NotFoundException
61 | // Whenever reader detect a QR code with inconsistent QR points it throws ChecksumException
62 | } catch (FormatException e) {
63 | exception = e;
64 | } finally {
65 | qrCodeReader.reset();
66 | }
67 |
68 | image.close();
69 | callback.onCompleted(exception, result);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/otp/Base32Decoder.java:
--------------------------------------------------------------------------------
1 | package es.wolfi.utils.otp;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public class Base32Decoder {
7 | // Standard Base32 alphabet (RFC 4648)
8 | private static final String BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
9 | private static final Map DECODE_MAP = new HashMap<>();
10 |
11 | static {
12 | // Build the decode map
13 | for (int i = 0; i < BASE32_ALPHABET.length(); i++) {
14 | DECODE_MAP.put(BASE32_ALPHABET.charAt(i), i);
15 | }
16 | }
17 |
18 | /**
19 | * Decodes a Base32 encoded string to bytes
20 | *
21 | * @param encoded The Base32 encoded string
22 | * @return The decoded bytes
23 | * @throws IllegalArgumentException if the input is invalid
24 | */
25 | public static byte[] decodeBase32(String encoded) {
26 | if (encoded == null || encoded.isEmpty()) {
27 | return new byte[0];
28 | }
29 |
30 | // Remove padding and convert to uppercase
31 | encoded = encoded.toUpperCase().replaceAll("=", "");
32 |
33 | // Validate input length
34 | if (encoded.isEmpty()) {
35 | return new byte[0];
36 | }
37 |
38 | // Calculate output length
39 | int outputLength = (encoded.length() * 5) / 8;
40 | byte[] output = new byte[outputLength];
41 |
42 | int bits = 0;
43 | int value = 0;
44 | int index = 0;
45 |
46 | for (char c : encoded.toCharArray()) {
47 | Integer charValue = DECODE_MAP.get(c);
48 | if (charValue == null) {
49 | throw new IllegalArgumentException("Invalid Base32 character: " + c);
50 | }
51 |
52 | value = (value << 5) | charValue;
53 | bits += 5;
54 |
55 | if (bits >= 8) {
56 | output[index++] = (byte) ((value >>> (bits - 8)) & 0xFF);
57 | bits -= 8;
58 | }
59 | }
60 |
61 | return output;
62 | }
63 |
64 | /**
65 | * Decodes a Base32 encoded string to a UTF-8 string
66 | *
67 | * @param encoded The Base32 encoded string
68 | * @return The decoded string
69 | * @throws IllegalArgumentException if the input is invalid
70 | */
71 | public static String decodeBase32ToString(String encoded) {
72 | byte[] decoded = decodeBase32(encoded);
73 | return new String(decoded, java.nio.charset.StandardCharsets.UTF_8);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vault_list.xml:
--------------------------------------------------------------------------------
1 |
23 |
29 |
30 |
41 |
42 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/otp/HashingAlgorithm.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2024, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.utils.otp;
24 |
25 | public enum HashingAlgorithm {
26 | SHA1("HmacSHA1", "SHA1"),
27 | SHA256("HmacSHA256", "SHA256"),
28 | SHA512("HmacSHA512", "SHA512");
29 |
30 | public static final String[] hashingAlgorithmsFriendlyArray = new String[]{
31 | HashingAlgorithm.SHA1.getFriendlyName(),
32 | HashingAlgorithm.SHA256.getFriendlyName(),
33 | HashingAlgorithm.SHA512.getFriendlyName()
34 | };
35 |
36 | private final String hmacAlgorithm;
37 | private final String friendlyName;
38 |
39 | HashingAlgorithm(String hmacAlgorithm, String friendlyName) {
40 | this.hmacAlgorithm = hmacAlgorithm;
41 | this.friendlyName = friendlyName;
42 | }
43 |
44 | public String getHmacAlgorithm() {
45 | return hmacAlgorithm;
46 | }
47 |
48 | public String getFriendlyName() {
49 | return friendlyName;
50 | }
51 |
52 | /**
53 | * Parse input text into HashingAlgorithm. Returns HashingAlgorithm.SHA1 as fallback.
54 | */
55 | public static HashingAlgorithm fromStringOrSha1(String friendlyNameInput) {
56 | HashingAlgorithm algorithm = HashingAlgorithm.SHA1;
57 | if (friendlyNameInput.equalsIgnoreCase(HashingAlgorithm.SHA256.friendlyName)) {
58 | algorithm = HashingAlgorithm.SHA256;
59 | } else if (friendlyNameInput.equalsIgnoreCase(HashingAlgorithm.SHA512.friendlyName)) {
60 | algorithm = HashingAlgorithm.SHA512;
61 | }
62 | return algorithm;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_copy_text_item.xml:
--------------------------------------------------------------------------------
1 |
22 |
25 |
26 |
36 |
37 |
44 |
45 |
52 |
53 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/SingleTon.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 | package es.wolfi.app.passman;
23 | import android.view.View;
24 | import java.util.concurrent.ConcurrentHashMap;
25 |
26 |
27 | public class SingleTon {
28 | protected final static SingleTon _ton = new SingleTon();
29 |
30 | protected ConcurrentHashMap _click;
31 | protected ConcurrentHashMap _extra;
32 | protected ConcurrentHashMap _string;
33 |
34 | public SingleTon(){
35 | _string = new ConcurrentHashMap();
36 | _click = new ConcurrentHashMap();
37 | _extra = new ConcurrentHashMap();
38 | }
39 |
40 | public void addClickListener(String name, View.OnClickListener action){
41 | _click.put(name, action);
42 | }
43 |
44 | public void addString(String name, String value){
45 | _string.put(name, value);
46 | }
47 |
48 | public String getString(String name){
49 | return _string.get(name);
50 | }
51 |
52 | public void addExtra(String name, Object data){
53 | _extra.put(name, data);
54 | }
55 | public void removeExtra(String name){
56 | _extra.remove(name);
57 | }
58 |
59 | public void removeString(String name){
60 | _string.remove(name);
61 | }
62 |
63 | public View.OnClickListener getClickListener(String name){
64 | return _click.get(name);
65 | }
66 |
67 | public Object getExtra(String name){
68 | return _extra.get(name);
69 | }
70 |
71 | public final static SingleTon getTon(){
72 | return _ton;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ja-rJP/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 設定
3 | 同期
4 | サーバーアドレス
5 | ユーザー名
6 | パスワード
7 | 接続
8 | NextcloudのURLが間違っているか、接続できない
9 | 設定に誤りがあります
10 | ネットワークエラー
11 | 解除
12 | 保管庫パスワードが間違っています!
13 | ラベル
14 | メール
15 | URL
16 | 説明
17 | クリップボードにコピーしました
18 | 保管庫パスワード
19 | 保管庫パスワードを保存
20 | 未実装です
21 | 作成:
22 | 最終アクセス:
23 | 検索
24 | 保存
25 | 保存しました
26 | エラーが発生しました
27 | 更新
28 | アップデートに成功しました
29 | 削除
30 | 削除に成功しました
31 | アプリ設定
32 | 読み込み中です。お待ちください…
33 | 読み込み中
34 | ファイル
35 | ファイルを追加
36 | Passmanをアンロック
37 | エキスパート設定
38 | はい
39 | キャンセル
40 | パスワードを生成する
41 | すべての文字種を必須にする
42 | あいまいな文字を避ける
43 | 特殊文字を使用する
44 | パスワードの長さ
45 | 新しい保管庫の名前
46 | オフラインキャッシュ
47 | Nextcloud シングルサインオン
48 | 値
49 | FAQ
50 | シークレットキー
51 | 発行者
52 |
53 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/activities/ShortcutActivity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | */
21 | package es.wolfi.app.passman.activities;
22 |
23 | import android.content.ClipData;
24 | import android.content.ClipboardManager;
25 | import android.content.Context;
26 | import android.os.Bundle;
27 | import android.widget.Toast;
28 |
29 | import androidx.appcompat.app.AppCompatActivity;
30 |
31 | import es.wolfi.app.passman.R;
32 | import es.wolfi.utils.PasswordGenerator;
33 |
34 | public class ShortcutActivity extends AppCompatActivity {
35 | public final static String LOG_TAG = "ShortcutActivity";
36 | public final static String GENERATE_PASSWORD_ID = "es.wolfi.app.passman.generate_password";
37 | public final static String GENERATE_PASSWORD_INTENT_ACTION = "custom.actions.intent.GENERATE_PASSWORD";
38 |
39 | @Override
40 | protected void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 |
43 | if (getIntent().getAction().equals(GENERATE_PASSWORD_INTENT_ACTION)) {
44 | generatePassword();
45 | }
46 |
47 | finish();
48 | }
49 |
50 | protected void generatePassword() {
51 | String password = new PasswordGenerator(getApplicationContext()).generateRandomPassword();
52 |
53 | if (password != null && password.length() > 0) {
54 | ClipboardManager clipboard = (ClipboardManager) getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
55 | ClipData clip = ClipData.newPlainText("generated_password", password);
56 | clipboard.setPrimaryClip(clip);
57 |
58 | Toast.makeText(getApplicationContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
59 | return;
60 | }
61 | Toast.makeText(getApplicationContext(), R.string.error_occurred, Toast.LENGTH_SHORT).show();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/ProgressUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | import android.app.ProgressDialog;
26 | import android.content.Context;
27 |
28 | import es.wolfi.app.passman.R;
29 |
30 | public class ProgressUtils {
31 | /**
32 | * Creates and starts a unified loading sequence dialog
33 | *
34 | * @param context App context from view
35 | * @return ProgressDialog required to dismiss the dialog
36 | */
37 | public static ProgressDialog showLoadingSequence(Context context) {
38 | return show(context, context.getString(R.string.loading), context.getString(R.string.wait_while_loading), false);
39 | }
40 |
41 | /**
42 | * Creates and starts a custom progress dialog
43 | *
44 | * @param context App context from view
45 | * @param title Progress dialog title
46 | * @param message Progress dialog message
47 | * @param cancelable Set if the dialog should be cancelable by the user
48 | * @return ProgressDialog required to dismiss the dialog
49 | */
50 | public static ProgressDialog show(Context context, String title, String message, boolean cancelable) {
51 | final ProgressDialog progress = new ProgressDialog(context);
52 | progress.setTitle(title);
53 | progress.setMessage(message);
54 | progress.setCancelable(cancelable);
55 | progress.show();
56 |
57 | return progress;
58 | }
59 |
60 | /**
61 | * Checks if a dialog is shown and calls dismiss() on it if possible
62 | *
63 | * @param progress progress dialog to dismiss
64 | */
65 | public static void dismiss(ProgressDialog progress) {
66 | if (progress != null) {
67 | if (progress.isShowing()) {
68 | progress.dismiss();
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_sso_settings.xml:
--------------------------------------------------------------------------------
1 |
22 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
48 |
49 |
55 |
56 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Passman Android
2 |
3 | [](https://github.com/nextcloud/passman-android/releases)
4 |
5 | [](https://play.google.com/store/apps/details?id=es.wolfi.app.passman.alpha)
8 | [](https://f-droid.org/app/es.wolfi.app.passman)
11 | [](https://apt.izzysoft.de/fdroid/index/apk/es.wolfi.app.passman)
14 |
15 | This app is only compatible with Passman V2.x or higher.
16 | The passwords will be provided by [Passman](https://github.com/nextcloud/passman).
17 |
18 | ## Current features
19 | - Setup app (enter the nextcloud server settings or use SSO)
20 | - App start password option based on the android user authentication
21 | - View, add, rename and delete vaults
22 | - Login to vault
23 | - Display credential list
24 | - View, add, edit and delete credentials
25 | - Add, download and delete files
26 | - OTP generation
27 | - Basic Android autofill implementation
28 | - Password generator
29 | - Encrypted offline cache
30 | - Encrypted stored vault and cloud connection passwords
31 |
32 | ## FAQ
33 | Read our [frequently asked questions article](FAQ.md)
34 |
35 | ## Build locally
36 |
37 | ### Required packages
38 | - cmake
39 | - gcc
40 | - git
41 |
42 | ### Commands
43 | 1. Clone the repo
44 | 1. Setup the git submodules with `git submodule update --init --recursive`
45 | 1. Open project in Android Studio and install the SDK an the NDK
46 | 1. Copy `openssl.conf.example` to `openssl.conf`
47 | 1. Edit the `ANDROID_NDK_HOME` in openssl.conf to match your local NDK path
48 | 1. Edit the `HOST_TAG` in openssl.conf to match your system arch
49 | 1. Run `build-openssl.sh`
50 | 1. If you want to compile either an alpha or release version, create a keystore either
51 | with Android Studio or `keytool` and add at least a key for the alpha build:
52 | ```
53 | keytool -genkey -v -keystore keystore.jks -alias beta -keyalg rsa
54 | ```
55 | 1. Create a `gradle.properties` file based on `gradle.properties.example` and fill in the
56 | appropriate values for your keystore. If you only build debug builds you can leave
57 | the default values.
58 | 1. Use Android Studio to build or otherwise build with gradle.
59 |
60 | ## Testing server
61 | [Here](https://demo.passman.cc/) you can use our demo system.
62 |
63 | ## Support Passman
64 | Passman is open source but we’ll gladly accept a beer *or pizza!* Please consider donating:
65 | * [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2)
66 | * [Patreon](https://www.patreon.com/user?u=4833592)
67 | * [Flattr](https://flattr.com/@passman)
68 | * bitcoin: 1H2c5tkGX54n48yEtM4Wm4UrAGTW85jQpe
69 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/IconUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.app.ResponseHandlers;
24 |
25 | import android.app.ProgressDialog;
26 | import android.os.Handler;
27 | import android.os.Looper;
28 | import android.view.View;
29 | import android.widget.Toast;
30 |
31 | import com.loopj.android.http.AsyncHttpResponseHandler;
32 |
33 | import java.util.List;
34 |
35 | import es.wolfi.app.passman.adapters.FileEditAdapter;
36 | import es.wolfi.app.passman.R;
37 | import es.wolfi.passman.API.File;
38 | import es.wolfi.utils.ProgressUtils;
39 |
40 | public class FileDeleteResponseHandler extends AsyncHttpResponseHandler {
41 |
42 | private final ProgressDialog progress;
43 | private final FileEditAdapter.ViewHolder holder;
44 | private final List mValues;
45 | private final View view;
46 |
47 | public FileDeleteResponseHandler(ProgressDialog progress, FileEditAdapter.ViewHolder holder, List mValues, View view) {
48 | super();
49 |
50 | this.progress = progress;
51 | this.holder = holder;
52 | this.mValues = mValues;
53 | this.view = view;
54 | }
55 |
56 | @Override
57 | public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody) {
58 | if (statusCode == 200) {
59 | mValues.remove(holder.mItem);
60 |
61 | new Handler(Looper.getMainLooper()).post(new Runnable() {
62 | @Override
63 | public void run() {
64 | holder.mContentView.setTextColor(view.getResources().getColor(R.color.disabled));
65 | holder.deleteButton.setVisibility(View.INVISIBLE);
66 | }
67 | });
68 | }
69 | ProgressUtils.dismiss(progress);
70 | }
71 |
72 | @Override
73 | public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody, Throwable error) {
74 | error.printStackTrace();
75 | new Handler(Looper.getMainLooper()).post(new Runnable() {
76 | @Override
77 | public void run() {
78 | Toast.makeText(view.getContext(), R.string.error_occurred, Toast.LENGTH_LONG).show();
79 | }
80 | });
81 | ProgressUtils.dismiss(progress);
82 | }
83 |
84 | @Override
85 | public void onRetry(int retryNo) {
86 | // called when request is retried
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/ResponseHandlers/CustomFieldFileDeleteResponseHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.app.ResponseHandlers;
24 |
25 | import android.app.ProgressDialog;
26 | import android.os.Handler;
27 | import android.os.Looper;
28 | import android.widget.Toast;
29 |
30 | import com.loopj.android.http.AsyncHttpResponseHandler;
31 |
32 | import java.util.List;
33 |
34 | import es.wolfi.app.passman.R;
35 | import es.wolfi.app.passman.adapters.CustomFieldEditAdapter;
36 | import es.wolfi.passman.API.CustomField;
37 | import es.wolfi.utils.ProgressUtils;
38 |
39 | public class CustomFieldFileDeleteResponseHandler extends AsyncHttpResponseHandler {
40 |
41 | private final ProgressDialog progress;
42 | private final CustomFieldEditAdapter.ViewHolder holder;
43 | private final List mValues;
44 | private final CustomFieldEditAdapter customFieldEditAdapter;
45 |
46 | public CustomFieldFileDeleteResponseHandler(ProgressDialog progress, CustomFieldEditAdapter.ViewHolder holder, List mValues, CustomFieldEditAdapter customFieldEditAdapter) {
47 | super();
48 |
49 | this.progress = progress;
50 | this.holder = holder;
51 | this.mValues = mValues;
52 | this.customFieldEditAdapter = customFieldEditAdapter;
53 | }
54 |
55 | @Override
56 | public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody) {
57 | if (statusCode == 200) {
58 | mValues.remove(holder.mItem);
59 | new Handler(Looper.getMainLooper()).post(new Runnable() {
60 | @Override
61 | public void run() {
62 | customFieldEditAdapter.notifyDataSetChanged();
63 | }
64 | });
65 | }
66 | ProgressUtils.dismiss(progress);
67 | }
68 |
69 | @Override
70 | public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody, Throwable error) {
71 | error.printStackTrace();
72 | new Handler(Looper.getMainLooper()).post(new Runnable() {
73 | @Override
74 | public void run() {
75 | Toast.makeText(progress.getContext(), R.string.error_occurred, Toast.LENGTH_LONG).show();
76 | }
77 | });
78 | ProgressUtils.dismiss(progress);
79 | }
80 |
81 | @Override
82 | public void onRetry(int retryNo) {
83 | // called when request is retried
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/utils/FilterListAsyncTask.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.utils;
24 |
25 | import android.os.AsyncTask;
26 | import android.preference.PreferenceManager;
27 |
28 | import androidx.fragment.app.FragmentManager;
29 | import androidx.recyclerview.widget.RecyclerView;
30 |
31 | import java.util.ArrayList;
32 |
33 | import es.wolfi.app.passman.adapters.CredentialViewAdapter;
34 | import es.wolfi.app.passman.adapters.VaultViewAdapter;
35 | import es.wolfi.app.passman.fragments.CredentialItemFragment;
36 | import es.wolfi.app.passman.fragments.VaultFragment;
37 | import es.wolfi.passman.API.Credential;
38 | import es.wolfi.passman.API.Vault;
39 |
40 | public class FilterListAsyncTask extends AsyncTask, Integer, ArrayList> {
41 |
42 | private String filter;
43 | RecyclerView recyclerView;
44 | CredentialItemFragment.OnListFragmentInteractionListener credentialMListener = null;
45 | VaultFragment.OnListFragmentInteractionListener vaultMListener = null;
46 | FragmentManager fragmentManager = null;
47 | Boolean isVaultFragment;
48 |
49 | public FilterListAsyncTask(String filter, RecyclerView recyclerView, CredentialItemFragment.OnListFragmentInteractionListener mListener) {
50 | this.filter = filter;
51 | this.recyclerView = recyclerView;
52 | this.credentialMListener = mListener;
53 | this.isVaultFragment = false;
54 | }
55 |
56 | public FilterListAsyncTask(String filter, RecyclerView recyclerView, VaultFragment.OnListFragmentInteractionListener mListener, FragmentManager fragmentManager) {
57 | this.filter = filter;
58 | this.recyclerView = recyclerView;
59 | this.vaultMListener = mListener;
60 | this.fragmentManager = fragmentManager;
61 | this.isVaultFragment = true;
62 | }
63 |
64 | @Override
65 | protected ArrayList doInBackground(ArrayList... list) {
66 | return new ListUtils().filterList(filter, list[0]);
67 | }
68 |
69 | @Override
70 | protected void onPostExecute(ArrayList filteredList) {
71 | if (isVaultFragment) {
72 | recyclerView.setAdapter(new VaultViewAdapter(recyclerView.getContext(), (ArrayList) filteredList, vaultMListener, fragmentManager));
73 | } else {
74 | recyclerView.setAdapter(new CredentialViewAdapter((ArrayList) filteredList, credentialMListener, PreferenceManager.getDefaultSharedPreferences(recyclerView.getContext())));
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/res/values-da/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Indstillinger
3 | Opdatér
4 | Serveradresse
5 | Brugernavn
6 | Adgangskode
7 | Tilslut
8 | URL\'en er forkert eller ikke i stand til at tilslutte
9 | Indstillingerne er ikke korrekt
10 | Netværksfejl
11 | Lås op
12 | Forkert boks kodeord
13 | Mærkat
14 | E-mail
15 | URL
16 | Beskrivelse
17 | Tekst kopieret til udklipsholder
18 | Boksadgangskode
19 | Gem ny boksadgangskode
20 | Ikke implementeret endnu
21 | Oprettet:
22 | Sidst tilgået:
23 | Søg
24 | Gem
25 | Gemt
26 | Der opstod en fejl
27 | Opdatér
28 | Slet
29 | Indlæser
30 | Filer
31 | Brugerdefineret felter
32 | Tilføj et brugerdefineret felt
33 | Ingen legitimationsoplysninger i boks
34 | Eksportér indstillinger
35 | Er du sikker på at du ønsker at slette disse legitimationsoplysninger?
36 | Ja
37 | Annuller
38 | Aktiver legitimationsoplysninger liste ikoner
39 | legitimationsoplysninger ikon
40 | Generer adgangskode
41 | Kræv alle tegntyper
42 | Undgå tvetydige karakterer
43 | Brug specialtegn
44 | Adgangskode længde
45 | Nyt boksnavn
46 | Cifre
47 | Periode
48 | Værdi
49 | FAQ
50 | Hemmelighed
51 | Udsteder
52 | Ingen matchende legitimationsoplysninger eller auto-udfyldbare felter blev fundet
53 | Ingen aktiv boks. Kan ikke tilføje legitimationsoplysninger
54 | Manuel legitimationsoplysningssøgning som autoudfyld tilbagefaldsmulighed
55 |
56 |
--------------------------------------------------------------------------------
/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Sets the minimum version of CMake required to build the native
2 | # library. You should either keep the default value or only pass a
3 | # value of 3.4.0 or lower.
4 |
5 | cmake_minimum_required(VERSION 3.4.1)
6 |
7 | # Creates and names a library, sets it as either STATIC
8 | # or SHARED, and provides the relative paths to its source code.
9 | # You can define multiple libraries, and CMake builds it for you.
10 | # Gradle automatically packages shared libraries with your APK.
11 |
12 | add_compile_options(
13 | -UANDROID
14 | -O3
15 | )
16 |
17 | add_library( # Sets the name of the library.
18 | passman-lib
19 |
20 | # Sets the library as a shared library.
21 | SHARED
22 |
23 | # Provides a relative path to your source file(s).
24 | # Associated headers in the same location as their source
25 | # file are automatically included.
26 | src/main/cpp/passman-lib.cpp
27 | )
28 |
29 | add_library(
30 | base64-lib
31 | STATIC
32 | src/main/cpp/base64.cpp
33 | )
34 |
35 | add_library(
36 | sjcl-lib
37 | STATIC
38 | src/main/cpp/SJCL.cpp
39 | )
40 |
41 | add_library(
42 | json-lib
43 | STATIC
44 | src/main/cpplibs/SimpleJSON/src/JSON.cpp
45 | src/main/cpplibs/SimpleJSON/src/JSONValue.cpp
46 | )
47 |
48 | include_directories (
49 | #src/main/cpplibs/openssl/include/
50 | ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpplibs/openssl/build/${CMAKE_ANDROID_ARCH_ABI}/include
51 | src/main/cpplibs/SimpleJSON/src/
52 | )
53 |
54 | add_library(
55 | openssl-lib
56 | STATIC
57 | IMPORTED
58 | )
59 | set_target_properties(
60 | openssl-lib
61 | #PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpplibs/openssl/libssl.a
62 | PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpplibs/openssl/build/${CMAKE_ANDROID_ARCH_ABI}/lib/libssl.a
63 | )
64 |
65 | add_library(
66 | opensslcrypto-lib
67 | STATIC
68 | IMPORTED
69 | )
70 | set_target_properties(
71 | opensslcrypto-lib
72 | #PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpplibs/openssl/libcrypto.a
73 | PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpplibs/openssl/build/${CMAKE_ANDROID_ARCH_ABI}/lib/libcrypto.a
74 | )
75 |
76 | # Searches for a specified prebuilt library and stores the path as a
77 | # variable. Because system libraries are included in the search path by
78 | # default, you only need to specify the name of the public NDK library
79 | # you want to add. CMake verifies that the library exists before
80 | # completing its build.
81 |
82 | find_library( # Sets the name of the path variable.
83 | log-lib
84 |
85 | # Specifies the name of the NDK library that
86 | # you want CMake to locate.
87 | log )
88 |
89 | # Specifies libraries CMake should link to your target library. You
90 | # can link multiple libraries, such as libraries you define in the
91 | # build script, prebuilt third-party libraries, or system libraries.
92 |
93 | target_link_libraries( # Specifies the target library.
94 | passman-lib
95 | base64-lib
96 | sjcl-lib
97 | json-lib
98 |
99 | openssl-lib
100 | opensslcrypto-lib
101 | #src/main/cpplib/openssl/libcrypto.so.1.0.0
102 |
103 | # Links the target library to the log library
104 | # included in the NDK.
105 | ${log-lib} )
106 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_credential_item_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
29 |
30 |
34 |
35 |
43 |
44 |
51 |
52 |
53 |
54 |
57 |
58 |
67 |
68 |
69 |
70 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
39 |
40 |
44 |
45 |
49 |
50 |
54 |
55 |
60 |
61 |
66 |
67 |
74 |
75 |
79 |
80 | 90dp
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/ResponseHandlers/CoreAPIGETResponseHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.app.ResponseHandlers;
24 |
25 | import android.os.Handler;
26 | import android.os.Looper;
27 |
28 | import com.koushikdutta.async.future.FutureCallback;
29 | import com.loopj.android.http.AsyncHttpResponseHandler;
30 |
31 | import org.json.JSONException;
32 | import org.json.JSONObject;
33 |
34 | import es.wolfi.utils.JSONUtils;
35 |
36 | public class CoreAPIGETResponseHandler extends AsyncHttpResponseHandler {
37 |
38 | private final FutureCallback callback;
39 |
40 | public CoreAPIGETResponseHandler(final FutureCallback callback) {
41 | super();
42 |
43 | this.callback = callback;
44 | }
45 |
46 | @Override
47 | public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody) {
48 | String result = new String(responseBody);
49 | new Handler(Looper.getMainLooper()).post(new Runnable() {
50 | @Override
51 | public void run() {
52 | if (statusCode == 200) {
53 | if (JSONUtils.isJSONObject(result)) {
54 | try {
55 | JSONObject o = new JSONObject(result);
56 | if (o.has("message") && o.getString("message").equals("Current user is not logged in")) {
57 | callback.onCompleted(new Exception("401"), null);
58 | return;
59 | }
60 | } catch (JSONException e1) {
61 | e1.printStackTrace();
62 | }
63 | }
64 | }
65 | callback.onCompleted(null, result);
66 | }
67 | });
68 | }
69 |
70 | @Override
71 | public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody, Throwable error) {
72 | new Handler(Looper.getMainLooper()).post(new Runnable() {
73 | @Override
74 | public void run() {
75 | String errorMessage = error.getMessage();
76 | if (errorMessage == null) {
77 | error.printStackTrace();
78 | errorMessage = "Unknown error";
79 | }
80 | if (statusCode == 401) {
81 | callback.onCompleted(new Exception("401"), null);
82 | } else {
83 | callback.onCompleted(new Exception(errorMessage), null);
84 | }
85 | }
86 | });
87 | }
88 |
89 | @Override
90 | public void onRetry(int retryNo) {
91 | // called when request is retried
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_manual_server_connection_settings.xml:
--------------------------------------------------------------------------------
1 |
22 |
26 |
27 |
32 |
33 |
38 |
39 |
44 |
45 |
50 |
51 |
59 |
60 |
65 |
66 |
74 |
75 |
80 |
81 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/adapters/FileViewAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | */
21 | package es.wolfi.app.passman.adapters;
22 |
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.widget.TextView;
27 |
28 | import androidx.recyclerview.widget.RecyclerView;
29 |
30 | import java.util.List;
31 |
32 | import es.wolfi.app.passman.fragments.CredentialDisplayFragment;
33 | import es.wolfi.app.passman.R;
34 | import es.wolfi.passman.API.File;
35 | import es.wolfi.utils.FileUtils;
36 |
37 | /**
38 | * {@link RecyclerView.Adapter} that can display a {@link File} and makes a call to the
39 | * specified {@link CredentialDisplayFragment.OnListFragmentInteractionListener}.
40 | */
41 | public class FileViewAdapter extends RecyclerView.Adapter {
42 |
43 | private final List mValues;
44 | private final CredentialDisplayFragment.OnListFragmentInteractionListener filelistListener;
45 |
46 | public FileViewAdapter(List files, CredentialDisplayFragment.OnListFragmentInteractionListener listener) {
47 | mValues = files;
48 | filelistListener = listener;
49 | }
50 |
51 | @Override
52 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
53 | View view = LayoutInflater.from(parent.getContext())
54 | .inflate(R.layout.fragment_credential_file_item, parent, false);
55 | return new ViewHolder(view);
56 | }
57 |
58 | @Override
59 | public void onBindViewHolder(final ViewHolder holder, int position) {
60 | holder.mItem = mValues.get(position);
61 | String filenameToPrint = String.format("%s (%s)", mValues.get(position).getFilename(), FileUtils.humanReadableByteCount((Double.valueOf(mValues.get(position).getSize())).longValue(), true));
62 | holder.mContentView.setText(filenameToPrint);
63 |
64 | holder.mView.setOnClickListener(new View.OnClickListener() {
65 | @Override
66 | public void onClick(View v) {
67 | if (null != filelistListener) {
68 | // Notify the active callbacks interface (the activity, if the
69 | // fragment is attached to one) that an item has been selected.
70 | filelistListener.onListFragmentInteraction(holder.mItem);
71 | }
72 | }
73 | });
74 | }
75 |
76 | @Override
77 | public int getItemCount() {
78 | return mValues.size();
79 | }
80 |
81 | public class ViewHolder extends RecyclerView.ViewHolder {
82 | public final View mView;
83 | public final TextView mContentView;
84 | public File mItem;
85 |
86 | public ViewHolder(View view) {
87 | super(view);
88 | mView = view;
89 | mContentView = (TextView) view.findViewById(R.id.content);
90 | }
91 |
92 | @Override
93 | public String toString() {
94 | return super.toString() + " '" + mContentView.getText() + "'";
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vault_delete.xml:
--------------------------------------------------------------------------------
1 |
23 |
27 |
28 |
31 |
32 |
40 |
41 |
46 |
47 |
54 |
55 |
62 |
63 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Paràmetres
3 | Actualitza
4 | Adreça del servidor
5 | Nom d\'usuari
6 | Contrasenya
7 | Connecta
8 | L\'URL del rerefons del Nextcloud és incorrecte o no es pot establir la connexió
9 | Els paràmetres són incorrectes
10 | Error de xarxa
11 | Desbloca
12 | La contrasenya del magatzem és incorrecta
13 | Etiqueta
14 | Adreça electrònica
15 | URL
16 | Descripció
17 | S\'ha copiat el text al porta-retalls
18 | Contrasenya del magatzem
19 | Desa la contrasenya del magatzem
20 | Encara no s\'ha implementat
21 | Data de creació:
22 | Data del darrer accés:
23 | Cerca
24 | Desar
25 | S\'ha desat correctament
26 | S\'ha produït un error
27 | Actualitzar
28 | Eliminar
29 | Carregant
30 | S\'ha produït un error en baixar el fitxer
31 | S\'ha produït un error en escriure el fitxer
32 | Fitxers
33 | Camps personalitzats
34 | Afegeix un fitxer
35 | Afegeix un camp personalitzat
36 | Cap caixa forta activa
37 | Cal desbloquejar la caixa forta
38 | No hi ha cap credencial en la caixa forta
39 | Caixa forta d\'emplenament automàtic per defecte
40 | Paràmetres Expert
41 | Esteu segur que voleu suprimir aquesta caixa forta?
42 | Sí
43 | Cancel·la
44 | Genera contrasenya
45 | Requereix cada tipus de caràcter
46 | Evita caràcters ambigus
47 | Fes servir caràcters especials
48 | Longitud de la contrasenya
49 | Nom de la caixa forta
50 | Nou nom de la caixa forta
51 | Recorda les caixes fortes xifrades si van carregar-se manualment
52 | Inici de sessió manual
53 | Esteu segur que voleu tancar la sessió?
54 | Dígits
55 | Període
56 | Valor
57 | PMF
58 | Secret
59 | Emissor
60 | S\'ha produït un error en analitzar el codi QR
61 | S\'ha denegat el permís de la càmera
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/cpp/passman-lib.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #include
30 | #include
31 | #include "base64.h"
32 | #include "SJCL.h"
33 |
34 | #define LOG_TAG "Passman lib"
35 |
36 | void throwJavaException(JNIEnv *env, const char *msg)
37 | {
38 | // You can put your own exception here
39 | jclass c = env->FindClass("java/lang/RuntimeException");
40 |
41 | if (NULL == c)
42 | {
43 | //B plan: null pointer ...
44 | c = env->FindClass("java/lang/NullPointerException");
45 | }
46 |
47 | env->ThrowNew(c, msg);
48 | }
49 |
50 | extern "C" {
51 |
52 | jstring Java_es_wolfi_app_passman_SJCLCrypto_decryptStringCpp(JNIEnv *env, jclass jthis, jstring cryptogram, jstring key) {
53 | std::string dt = env->GetStringUTFChars(cryptogram, 0);
54 | std::string password = env->GetStringUTFChars(key, 0);
55 |
56 | WLF::Crypto::Datagram *t = WLF::Crypto::BASE64::decode((const unsigned char *) dt.c_str(),
57 | dt.length());
58 |
59 | std::string json = (char *) t->data;
60 | free(t);
61 |
62 | //__android_log_write(ANDROID_LOG_ERROR, LOG_TAG, json.c_str());
63 |
64 | char *result = WLF::Crypto::SJCL::decrypt(json, password);
65 |
66 | if (result == NULL) {
67 | __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "error decrypting");
68 | }
69 | else {
70 | // __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "WHOOP!");
71 | // __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, result);
72 | jstring str = env->NewStringUTF(result);
73 | free(result);
74 | return str;
75 | }
76 |
77 | throwJavaException(env, "Error decrypting");
78 | return (jstring) "";
79 | }
80 |
81 | jstring Java_es_wolfi_app_passman_SJCLCrypto_encryptStringCpp(JNIEnv *env, jclass jthis, jstring plaintext, jstring key) {
82 | std::string dt = env->GetStringUTFChars(plaintext, 0);
83 | std::string password = env->GetStringUTFChars(key, 0);
84 |
85 | //__android_log_write(ANDROID_LOG_ERROR, LOG_TAG, dt.c_str());
86 |
87 | char *result = WLF::Crypto::SJCL::encrypt(const_cast(dt.c_str()), password);
88 | //__android_log_write(ANDROID_LOG_ERROR, LOG_TAG, result);
89 |
90 | char *arr_result = &result[0];
91 | std::string lengthAsString = to_string(strlen(arr_result));
92 |
93 | if (result == NULL) {
94 | __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "error encrypting");
95 | }
96 | else {
97 | //__android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "WHOOP!");
98 | //__android_log_write(ANDROID_LOG_ERROR, LOG_TAG, result);
99 | WLF::Crypto::Datagram *t = WLF::Crypto::BASE64::encode((const unsigned char *) result,
100 | strlen(arr_result));
101 |
102 | jstring str = env->NewStringUTF((char *) t->data);
103 |
104 | free(t);
105 | return str;
106 | }
107 |
108 | throwJavaException(env, "Error encrypting");
109 | return NULL;
110 | }
111 |
112 | }
--------------------------------------------------------------------------------
/app/src/main/java/es/wolfi/app/passman/PassmanReceiver.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Passman Android App
3 | *
4 | * @copyright Copyright (c) 2021, Sander Brand (brantje@gmail.com)
5 | * @copyright Copyright (c) 2021, Marcos Zuriaga Miguel (wolfi@wolfi.es)
6 | * @copyright Copyright (c) 2021, Timo Triebensky (timo@binsky.org)
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | package es.wolfi.app.passman;
24 |
25 | import android.content.BroadcastReceiver;
26 | import android.content.ClipData;
27 | import android.content.ClipboardManager;
28 | import android.content.Context;
29 | import android.content.Intent;
30 | import android.widget.Toast;
31 |
32 | import androidx.core.app.NotificationManagerCompat;
33 |
34 | import es.wolfi.passman.API.Credential;
35 | import es.wolfi.passman.API.Vault;
36 |
37 | public class PassmanReceiver extends BroadcastReceiver {
38 |
39 | public static final String CopyUsernameIntentAction = "COPYUSERNAMEINTENTACTION";
40 | public static final String CopyEmailIntentAction = "COPYEMAILINTENTACTION";
41 | public static final String CopyPasswordIntentAction = "COPYPASSWORDINTENTACTION";
42 | public static final String DismissCopyIntentAction = "DISMISSCOPYINTENTACTION";
43 |
44 | @Override
45 | public void onReceive(Context context, Intent intent) {
46 | // TODO: This method is called when the BroadcastReceiver is receiving
47 | // an Intent broadcast.
48 | String intentAction = intent.getAction();
49 |
50 | if (intentAction != null) {
51 | if (intentAction.startsWith("COPY")) {
52 | String credGuid = intent.getStringExtra("CredGuid");
53 | String vaultGuid = intent.getStringExtra("VaultGuid");
54 |
55 | if (credGuid != null && vaultGuid != null) {
56 | Vault v = Vault.getVaultByGuid(vaultGuid);
57 | if (v != null) {
58 | Credential c = v.findCredentialByGUID(credGuid);
59 | if (c != null) {
60 | switch (intentAction) {
61 | case CopyUsernameIntentAction:
62 | copyTextToClipboard(context, "Username", c.getUsername());
63 | break;
64 | case CopyEmailIntentAction:
65 | copyTextToClipboard(context, "Email", c.getEmail());
66 | break;
67 | case CopyPasswordIntentAction:
68 | copyTextToClipboard(context, "Password", c.getPassword());
69 | break;
70 | }
71 | }
72 | }
73 | }
74 | } else if (intentAction.equals(DismissCopyIntentAction)) {
75 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
76 |
77 | // notificationId is a unique int for each notification that you must define
78 | notificationManager.cancelAll();
79 | }
80 | }
81 | }
82 |
83 | public void copyTextToClipboard(Context c, String label, String text) {
84 | ClipboardManager clipboard = (ClipboardManager) c.getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
85 | ClipData clip = ClipData.newPlainText(label, text);
86 | clipboard.setPrimaryClip(clip);
87 |
88 | Toast.makeText(c, c.getApplicationContext().getString(R.string.copied_to_clipboard) + ": " + label, Toast.LENGTH_SHORT).show();
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vault_lock_screen.xml:
--------------------------------------------------------------------------------
1 |
22 |
27 |
28 |
31 |
32 |
41 |
42 |
43 |
49 |
50 |
55 |
56 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
75 |
76 |
77 |
78 |
82 |
83 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------