mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-23 15:29:15 +00:00
Merge pull request #1027 from alexbakker/2fas-schema3
Add support for importing 2FAS schema v3 backups
This commit is contained in:
commit
f8d60fb1b7
4 changed files with 202 additions and 8 deletions
|
@ -7,6 +7,7 @@ import com.beemdevelopment.aegis.crypto.CryptoUtils;
|
|||
import com.beemdevelopment.aegis.encoding.Base32;
|
||||
import com.beemdevelopment.aegis.encoding.Base64;
|
||||
import com.beemdevelopment.aegis.encoding.EncodingException;
|
||||
import com.beemdevelopment.aegis.otp.HotpInfo;
|
||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
||||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||
|
@ -59,7 +60,7 @@ public class TwoFASImporter extends DatabaseImporter {
|
|||
String json = new String(IOUtils.readAll(stream), StandardCharsets.UTF_8);
|
||||
JSONObject obj = new JSONObject(json);
|
||||
int version = obj.getInt("schemaVersion");
|
||||
if (version > 2) {
|
||||
if (version > 3) {
|
||||
throw new DatabaseImporterException(String.format("Unsupported schema version: %d", version));
|
||||
}
|
||||
|
||||
|
@ -173,13 +174,23 @@ public class TwoFASImporter extends DatabaseImporter {
|
|||
try {
|
||||
byte[] secret = Base32.decode(obj.getString("secret"));
|
||||
JSONObject info = obj.getJSONObject("otp");
|
||||
String issuer = info.getString("issuer");
|
||||
String issuer = info.optString("issuer");
|
||||
String name = info.optString("account");
|
||||
int digits = info.optInt("digits", TotpInfo.DEFAULT_DIGITS);
|
||||
int period = info.optInt("period", TotpInfo.DEFAULT_PERIOD);
|
||||
String algorithm = info.optString("algorithm", TotpInfo.DEFAULT_ALGORITHM);
|
||||
|
||||
OtpInfo otp = new TotpInfo(secret, algorithm, digits, period);
|
||||
OtpInfo otp;
|
||||
String tokenType = JsonUtils.optString(info, "tokenType");
|
||||
if (tokenType == null || tokenType.equals("TOTP")) {
|
||||
int period = info.optInt("period", TotpInfo.DEFAULT_PERIOD);
|
||||
otp = new TotpInfo(secret, algorithm, digits, period);
|
||||
} else if (tokenType.equals("HOTP")) {
|
||||
long counter = info.optLong("counter", 0);
|
||||
otp = new HotpInfo(secret, algorithm, digits, counter);
|
||||
} else {
|
||||
throw new DatabaseImporterEntryException(String.format("Unrecognized tokenType: %s", tokenType), obj.toString());
|
||||
}
|
||||
|
||||
return new VaultEntry(otp, name, issuer);
|
||||
} catch (OtpInfoException | JSONException | EncodingException e) {
|
||||
throw new DatabaseImporterEntryException(e, obj.toString());
|
||||
|
|
|
@ -238,7 +238,7 @@ public class DatabaseImporterTest {
|
|||
public void testImportTwoFASAuthenticatorSchema1() throws DatabaseImporterException, IOException, OtpInfoException {
|
||||
List<VaultEntry> entries = importPlain(TwoFASImporter.class, "2fas_authenticator.json");
|
||||
for (VaultEntry entry : entries) {
|
||||
// 2FAS Authenticator doesn't support HOTP, different hash algorithms, periods or digits, so fix those up here
|
||||
// 2FAS Authenticator schema v1 doesn't support HOTP, different hash algorithms, periods or digits, so fix those up here
|
||||
VaultEntry entryVector = getEntryVectorBySecret(entry.getInfo().getSecret());
|
||||
entryVector.setInfo(new TotpInfo(entryVector.getInfo().getSecret()));
|
||||
checkImportedEntry(entryVector, entry);
|
||||
|
@ -248,7 +248,7 @@ public class DatabaseImporterTest {
|
|||
@Test
|
||||
public void testImportTwoFASAuthenticatorSchema2Plain() throws DatabaseImporterException, IOException, OtpInfoException {
|
||||
List<VaultEntry> entries = importPlain(TwoFASImporter.class, "2fas_authenticator_plain.2fas");
|
||||
checkImportedTwoFASEntries(entries);
|
||||
checkImportedTwoFASSchema2Entries(entries);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -257,7 +257,22 @@ public class DatabaseImporterTest {
|
|||
final char[] password = "test".toCharArray();
|
||||
return ((TwoFASImporter.EncryptedState) encryptedState).decrypt(password);
|
||||
});
|
||||
checkImportedTwoFASEntries(entries);
|
||||
checkImportedTwoFASSchema2Entries(entries);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportTwoFASAuthenticatorSchema3Plain() throws DatabaseImporterException, IOException, OtpInfoException {
|
||||
List<VaultEntry> entries = importPlain(TwoFASImporter.class, "2fas_authenticator_plain_v3.2fas");
|
||||
checkImportedEntries(entries);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportTwoFASAuthenticatorSchema3Encrypted() throws DatabaseImporterException, IOException, OtpInfoException {
|
||||
List<VaultEntry> entries = importEncrypted(TwoFASImporter.class, "2fas_authenticator_encrypted_v3.2fas", encryptedState -> {
|
||||
final char[] password = "test".toCharArray();
|
||||
return ((TwoFASImporter.EncryptedState) encryptedState).decrypt(password);
|
||||
});
|
||||
checkImportedEntries(entries);
|
||||
}
|
||||
|
||||
private List<VaultEntry> importPlain(Class<? extends DatabaseImporter> type, String resName)
|
||||
|
@ -302,7 +317,7 @@ public class DatabaseImporterTest {
|
|||
return result.getEntries();
|
||||
}
|
||||
|
||||
private void checkImportedTwoFASEntries(List<VaultEntry> entries) throws OtpInfoException {
|
||||
private void checkImportedTwoFASSchema2Entries(List<VaultEntry> entries) throws OtpInfoException {
|
||||
for (VaultEntry entry : entries) {
|
||||
// 2FAS Authenticator doesn't support certain features, so fix those entries up here
|
||||
VaultEntry entryVector = getEntryVectorBySecret(entry.getInfo().getSecret());
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"services": [],
|
||||
"updatedAt": 1668548484538,
|
||||
"schemaVersion": 3,
|
||||
"appVersionCode": 4000004,
|
||||
"appVersionName": "4.0.0",
|
||||
"appOrigin": "android",
|
||||
"groups": [],
|
||||
"servicesEncrypted": "oAAWclilpn+Y9ol1SENxfw2c1zejXyYdEkC6+G3tpbep7MXXvC\/xAgzwS+RFt\/jXoivKsrpVCFrRbuhziyHUfaWvOmHCydro5NlrQH9SHbeasoGBeoKH+x3H7v5oDXE4PO4L2+rShWfHILmgkum1HHPfc85ojm2qp5NgsCbVxuMPUnnwb+k8BLAsrPZMx708LccaoZLYz+Bkd7Vb6ONYn\/8gkOulNp9Ue9O\/3Q\/ZVLHpR+nveszobXoHAukRNDQ8kNDnmetjqH1xbuJf\/0UMO6kgRs0fdxZvrBg3afFasymlNH6Iwz8S+yfOT32b5YuLcZNo2OkhaV1oqcL+aZEYXSpcPZM3iqB817agI+qeUPQvsqwkgu\/whzMrGVBb1DAf+b7aPEHsxXCGk5E72xgU5dnZwAR6x12vO8LUhuRywEXi7X2klQ1cpiOSzi7ZefnE61dTgJAmbVoMBNM5tXtvjZmuM+zpLHBzl6Z6lIFWabGT2G3b6KQ0yadE3Wmw4FK\/zG0i6bC4qRnA2I0V75CJCIboxOTiN2QodhITZAQvQFfn5AzOUk0bdwJP5XeNKXl1eAWaDzBzo1vNELlF0m3WH9bEXLHzE6Q1IoJmZX\/XY9e7TemwSIIRl0NvZ3Vi\/LrNpYzCQJ8UrcBQzjevuvWuBU4k8xyVIHo9CGF5Y10BeWi1dC2Ws5OpXK9hfni92RWYRVcaBgQjFAJ\/TpE\/ynL33FD\/KTGVwp6wSE6CCedWFdsxk3ushckU53yoUqHAwvRB76Kk3\/TrkWFj3Oph1cTdgPnHz\/0\/6VaphOuNkMtebeAzDtrV55IKqzQZ+6GxRgr5sFDVcy2djrUYGOPemCvYIuXyVhpRq1dbTfJ0lsJ+fiVmnXxmb3hNXskT87QW+TVDFxqfTD7h5RXVFY7IFdXTd5bwq6EyAfvJtuZqu7fX\/Ft1Y3MCPEFbQw9QLyz6CbSZJmG1CafgrIS+R2PlBrJM8LlhId\/BebkwfxXX4tGwI4vAVdw2XmPjeAjZzXiTEpneSz5tFp\/BHoolFnmJkCm+z+F\/zrZbf0K4qtrOiqEdKs+qNWww6h7sEFPPvaXyYBdNGm23F+Rb2N2ZZnUs8tHPaltsI4LSwi+7gNgRnVdI3Ljpp85xbRfEI0OZ7ZJIeS5w3nBWUOu3\/pOBpEsCtwSkpTr9scHwiCC5YDSdYvFSAzZEgIDNVxT28AHFhoQJBcG7JVPIa52mtACYExqoRdbTlQ4DJqMG2WxtnhV\/AHzYqahPD+\/RHmV9yC23vddgMykDrzSQHVxOXzODpioGYSZIZrYIBCGaxIEa7F4wTp7XjR60jvWtUkInr0RontbE7lYMnMTIxttgMqQto2WDxKWMqroMEWHnUnMbfIL5B+7+UpoWN7Zp09z8p\/znXrMn25\/EmcXTcmGXBdP9\/Qh5CBa0v5XUafVvHrTDBoZCDE7RaHnRcou5RBTWIgqDNO+yfKc08PDpw0UJ0QdtxLrKgzkgbIXYvHS+ksGPq5wubp1IrkjYuUwjKKgSaWAuEyB5r4Oa54jdz8KNuJskMLSxqndz0TV2qSBGbB7YdyxR8KyGpG6hfqqudkGmYUkl+nTdeppTGnry67ya9B8iYcijMXBLvk\/3DKVDisv8K4r9kSxvPIfzd5MO\/ui8pRXA+FCRThBxqSS\/lThpcyEIj90VVYxmVyDaA47XE255\/0kEqQm4v67HIwGqIVsK7AfjJkQUAKlVzraKyJB441pDiNParlI5ln0gbpeSnc9iH92zRXfwKZCyF1\/009\/JVbrKIcfNEvDpTUaexwcjetYqc8aLLSEdatqa515Nxhp6nPvHdV1sj1it81Fl+\/nCGrTZ\/YMcYoPoA9Sv7pZU3RMDbCA\/dREsSPGQ0+mCNcwHHe2ZTuki5DIB+nsAsV16g\/OH0vxDr25BLqXuLjhx8Jc9Rlr6jg+32HOJXrRuoSAsFCzyCmtfcwxU0v4+IM\/6cq8\/qdlK8D2zvxMZPL7SUje3\/VB77PHDkceof+DvtmJ\/pUlmXHdSApdXbfWjlfP3DWWYmCZhHlO3pg0TqPKufVSZWFU7AfRuIimNgRs4s\/2ixNs9p9DZbzno6bb5YLh7ql3TqsL2xeYXBTQWpSkGH\/+0BvEOkXGjxbNxdbsjYBxvOp2bVjwCX0omL3C8K84IVnQDZSMEftrLtIlbBmnabN7g5qKzUtNtfN1hB4EFqq7LVvGgkOUCZCZx2dWwmgHqeUEvtKhdlvFuPNEVtd5co0JieFhFJtGqVbGkjMBg22x0uMclaGhma2xYAcgEjiBdg1QVdHq+1gnYyowKG4YGCpXrshC3e4\/ujk+iUmPGkYGYrweglZAnVm+U15OXoJn0lzjBO29jhfZi8d\/DirG5b4lT0C\/6S\/UhG5bGrNcirQsvr5SIbQfoSaLXlJ2SCKuUw51wlF9khENW3o2GPn3L2tlFOaMf5mbuHi4P8eJDhWY2KA6uTEWddjbfVILSPhhKcpWdBu01CxIP\/2gQS5Ou1hjcqyN1jCSxIFVANYkr+IpKooers03bPVmTrLGYalmU+CI8FBYgkZnL4P+OuSqivMxvcscLN25xJ7kz+i2eRz98HoNsOA1Dx+lZEfeailmJh8F\/a\/agUCVWufAem0vC6mZMWjj8QKORpOwh+0wgV2rmWJK6DTPA6lH1ivnqdrE\/JE8V4wOTCE+NeeBb7VIRe0Q4q2\/ORMVPK\/YyrKwARYhmC1L3FuEsFmeimhMweiIzAc7AWeykRY8xS0Laujy7VRzal9y3C6TUSUSeriApPhfhpQmNO8jjYHR22vaA530W4SKOiNEAYdFOolUyoLrUwgADvoH2MWv+Z4JpO4GBGTKUCUbnqn32gMpDgNmc3FzXtpyASF0=:F\/kH8kq9g0PjEEuQmL8eBnoN6eI0oz8AM9UJr\/ADTHoTrqDnbUY4joUQw2dyeNRYxsw1Oj0nGBUxg90dnDhs79X5C\/D2tsgns03tADJUe5I\/hnS8O+njyDcYVODUoS5eC5pHTXzhLmeKNZjhKuVr+XGlKdhnv72gn8JvwjEiwNh52T6RnD10pWwbxLJaMdkBKps7sFDfXxJofCsU8u\/aYmAAolMkViKsTJ1tHcaEz8eG0R4jhB3Lm8m8Cdtx+nGX57pJk+ptmEv+Px\/5rANfDxnNJ6iB+zg9xBFJk+YbJlQ6Cf6dQFye0gAlT3KWi26jA+Ozp+EoGHMm2TCRKnpemw==:q5DxA6tYE2A2AHWz",
|
||||
"reference": "tQdQEgDTckuE\/Q02KeQJxxDYKAsn6mdAW6EYhtI4l9vN7RhVMFyXMYVDnH2Ujnj\/zWlV8lRtUfl3FWBpnBWM8YINff6Un3zTM9jEf0YYftj0HQzd8dnbM0u2ZxCftRblqk0dAiekjA05Vo\/ma6Y+mreGJpj\/awMP8OvgYWSu03F01PfklUOEmxSUrIMk6\/A8HiAZ\/PH9ayDvjOSZHZ05zahndayzqBSecdt0w+bejNFUM4SRWWC+njStxZGz4IfMHkkiGJoYyg0D5ezRHwINcw3u+1IaEzKJ8hqta7qXh+cx4Jig6rqB0cUQbUqY2LoCsEB9POKdlfBihVxKLKFss+TuLZW6DxtUNbAAaImSMBc=:F\/kH8kq9g0PjEEuQmL8eBnoN6eI0oz8AM9UJr\/ADTHoTrqDnbUY4joUQw2dyeNRYxsw1Oj0nGBUxg90dnDhs79X5C\/D2tsgns03tADJUe5I\/hnS8O+njyDcYVODUoS5eC5pHTXzhLmeKNZjhKuVr+XGlKdhnv72gn8JvwjEiwNh52T6RnD10pWwbxLJaMdkBKps7sFDfXxJofCsU8u\/aYmAAolMkViKsTJ1tHcaEz8eG0R4jhB3Lm8m8Cdtx+nGX57pJk+ptmEv+Px\/5rANfDxnNJ6iB+zg9xBFJk+YbJlQ6Cf6dQFye0gAlT3KWi26jA+Ozp+EoGHMm2TCRKnpemw==:giXb4rEQl9ofTh2T"
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
{
|
||||
"services": [
|
||||
{
|
||||
"name": "Deno",
|
||||
"secret": "4SJHB4GSD43FZBAI7C2HLRJGPQ",
|
||||
"updatedAt": 1668540633217,
|
||||
"otp": {
|
||||
"label": "Deno:Mason",
|
||||
"account": "Mason",
|
||||
"issuer": "Deno",
|
||||
"digits": 6,
|
||||
"period": 30,
|
||||
"algorithm": "SHA1",
|
||||
"tokenType": "TOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 0
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SPDX",
|
||||
"secret": "5OM4WOOGPLQEF6UGN3CPEOOLWU",
|
||||
"updatedAt": 1668540644738,
|
||||
"otp": {
|
||||
"label": "SPDX:James",
|
||||
"account": "James",
|
||||
"issuer": "SPDX",
|
||||
"digits": 7,
|
||||
"period": 20,
|
||||
"algorithm": "SHA256",
|
||||
"tokenType": "TOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 1
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Airbnb",
|
||||
"secret": "7ELGJSGXNCCTV3O6LKJWYFV2RA",
|
||||
"updatedAt": 1668540650005,
|
||||
"otp": {
|
||||
"label": "Airbnb:Elijah",
|
||||
"account": "Elijah",
|
||||
"issuer": "Airbnb",
|
||||
"digits": 8,
|
||||
"period": 50,
|
||||
"algorithm": "SHA512",
|
||||
"tokenType": "TOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 2
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Issuu",
|
||||
"secret": "YOOMIXWS5GN6RTBPUFFWKTW5M4",
|
||||
"updatedAt": 1668540656157,
|
||||
"otp": {
|
||||
"label": "Issuu:James",
|
||||
"account": "James",
|
||||
"issuer": "Issuu",
|
||||
"digits": 6,
|
||||
"period": 30,
|
||||
"algorithm": "SHA1",
|
||||
"counter": 1,
|
||||
"tokenType": "HOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 3
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Air Canada",
|
||||
"secret": "KUVJJOM753IHTNDSZVCNKL7GII",
|
||||
"updatedAt": 1668540661393,
|
||||
"otp": {
|
||||
"label": "Air Canada:Benjamin",
|
||||
"account": "Benjamin",
|
||||
"issuer": "Air Canada",
|
||||
"digits": 7,
|
||||
"period": 30,
|
||||
"algorithm": "SHA256",
|
||||
"counter": 50,
|
||||
"tokenType": "HOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 4
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "WWE",
|
||||
"secret": "5VAML3X35THCEBVRLV24CGBKOY",
|
||||
"updatedAt": 1668540666422,
|
||||
"otp": {
|
||||
"label": "WWE:Mason",
|
||||
"account": "Mason",
|
||||
"issuer": "WWE",
|
||||
"digits": 8,
|
||||
"period": 30,
|
||||
"algorithm": "SHA512",
|
||||
"counter": 10300,
|
||||
"tokenType": "HOTP",
|
||||
"source": "Link"
|
||||
},
|
||||
"order": {
|
||||
"position": 5
|
||||
},
|
||||
"icon": {
|
||||
"selected": "IconCollection",
|
||||
"iconCollection": {
|
||||
"id": "a5b3fb65-4ec5-43e6-8ec1-49e24ca9e7ad"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"updatedAt": 1668540786699,
|
||||
"schemaVersion": 3,
|
||||
"appVersionCode": 4000004,
|
||||
"appVersionName": "4.0.0",
|
||||
"appOrigin": "android",
|
||||
"groups": []
|
||||
}
|
Loading…
Add table
Reference in a new issue