aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java
blob: 590a779e41134e0e37fc9174dc57b6c967e769a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package com.zeapo.pwdstore;

import android.net.Uri;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;

/**
 * A single entry in password store.
 */
public class PasswordEntry {

    private static final String[] USERNAME_FIELDS = new String[]{"login", "username"};

    private String extraContent;
    private final String password;
    private final String username;
    private final String totpSecret;
    private final String hotpSecret;
    private final Long hotpCounter;
    private final String content;
    private boolean isIncremented = false;

    public PasswordEntry(final ByteArrayOutputStream os) throws UnsupportedEncodingException {
        this(os.toString("UTF-8"));
    }

    public PasswordEntry(final String decryptedContent) {
        final String[] passContent = decryptedContent.split("\n", 2);
        content = decryptedContent;
        password = passContent[0];
        totpSecret = findTotpSecret(content);
        hotpSecret = findHotpSecret(content);
        hotpCounter = findHotpCounter(content);
        extraContent = findExtraContent(passContent);
        username = findUsername();
     }

    public String getPassword() {
        return password;
    }

    public String getExtraContent() {
        return extraContent;
    }

    public String getUsername() {
        return username;
    }

    public String getTotpSecret() {
        return totpSecret;
    }

    public Long getHotpCounter() {
        return hotpCounter;
    }

    public String getHotpSecret() {
        return hotpSecret;
    }

    public boolean hasExtraContent() {
        return extraContent.length() != 0;
    }

    public boolean hasUsername() {
        return username != null;
    }

    public boolean hasTotp() {
        return totpSecret != null;
    }

    public boolean hasHotp() {
        return hotpSecret != null && hotpCounter != null;
    }

    public boolean hotpIsIncremented() { return isIncremented; }

    public void incrementHotp() {
        for (String line : content.split("\n")) {
            if (line.startsWith("otpauth://hotp/")) {
                extraContent = extraContent.replaceFirst("counter=[0-9]+", "counter=" + Long.toString(hotpCounter + 1));
                isIncremented = true;
            }
        }
    }

    private String findUsername() {
        final String[] extraLines = extraContent.split("\n");
        for (String line : extraLines) {
            for (String field : USERNAME_FIELDS) {
                if (line.toLowerCase().startsWith(field + ":")) {
                    return line.split(": *", 2)[1];
                }
            }
        }
        return null;
    }

    private String findTotpSecret(String decryptedContent) {
        for (String line : decryptedContent.split("\n")) {
            if (line.startsWith("otpauth://totp/")) {
                return Uri.parse(line).getQueryParameter("secret");
            }
        }
        return null;
    }

    private String findHotpSecret(String decryptedContent) {
        for (String line : decryptedContent.split("\n")) {
            if (line.startsWith("otpauth://hotp/")) {
                return Uri.parse(line).getQueryParameter("secret");
            }
        }
        return null;
    }

    private Long findHotpCounter(String decryptedContent) {
        for (String line : decryptedContent.split("\n")) {
            if (line.startsWith("otpauth://hotp/")) {
                return Long.parseLong(Uri.parse(line).getQueryParameter("counter"));
            }
        }
        return null;
    }

    private String findExtraContent(String [] passContent) {
        String extraContent = passContent.length > 1 ? passContent[1] : "";
        // if there is a HOTP URI, we must return the extra content with the counter incremented
        if (hasHotp()) {
            return extraContent.replaceFirst("counter=[0-9]+", "counter=" + Long.toString(hotpCounter));
        }
        return extraContent;
    }
}