Skip to content

Commit

Permalink
feat: implemented 2fas import (#60)
Browse files Browse the repository at this point in the history
* Added 2fas import with tests

* Added period test

* Fixed lint

---------

Co-authored-by: Joel-David <[email protected]>
  • Loading branch information
joeldavidw and jdw-assignment committed Aug 7, 2024
1 parent b77fc82 commit da06777
Show file tree
Hide file tree
Showing 4 changed files with 712 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Chronos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
6B2583AF2B96048700938F3A /* SettingsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2583AE2B96048700938F3A /* SettingsTab.swift */; };
6B27317A2B53E23800F30621 /* UpdateTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2731792B53E23800F30621 /* UpdateTokenView.swift */; };
6B27317C2B53F0B200F30621 /* TokenRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B27317B2B53F0B200F30621 /* TokenRowView.swift */; };
6B2F7A822C635B5A00DB1450 /* 2FAS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2F7A812C635B5A00DB1450 /* 2FAS.swift */; };
6B35A4C92B557EE50004D4C5 /* AlertKit in Frameworks */ = {isa = PBXBuildFile; productRef = 6B35A4C82B557EE50004D4C5 /* AlertKit */; };
6B39629A2BF5E935000410B0 /* MainAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B3962992BF5E935000410B0 /* MainAppView.swift */; };
6B39629C2BF5EB3E000410B0 /* AuthenticationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B39629B2BF5EB3E000410B0 /* AuthenticationView.swift */; };
Expand Down Expand Up @@ -100,6 +101,7 @@
6B2583B02B975D3200938F3A /* Chronos.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Chronos.entitlements; sourceTree = "<group>"; };
6B2731792B53E23800F30621 /* UpdateTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTokenView.swift; sourceTree = "<group>"; };
6B27317B2B53F0B200F30621 /* TokenRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenRowView.swift; sourceTree = "<group>"; };
6B2F7A812C635B5A00DB1450 /* 2FAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = 2FAS.swift; sourceTree = "<group>"; };
6B3962992BF5E935000410B0 /* MainAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppView.swift; sourceTree = "<group>"; };
6B39629B2BF5EB3E000410B0 /* AuthenticationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationView.swift; sourceTree = "<group>"; };
6B39629D2BF63F27000410B0 /* SwiftDataService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDataService.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -325,6 +327,7 @@
6BC5F0562C529A2A00BA106F /* GoogleAuthenticator.swift */,
6BBF32022C562F20003CBA66 /* Aegis.swift */,
6B4987272C569A6E00A7D97A /* LastPass.swift */,
6B2F7A812C635B5A00DB1450 /* 2FAS.swift */,
);
path = Import;
sourceTree = "<group>";
Expand Down Expand Up @@ -695,6 +698,7 @@
6B4987282C569A6E00A7D97A /* LastPass.swift in Sources */,
6BC5F04A2C4FDE6E00BA106F /* ParseOtpAuthUrl.swift in Sources */,
6B8132F22C4975DA00DB367E /* Raivo.swift in Sources */,
6B2F7A822C635B5A00DB1450 /* 2FAS.swift in Sources */,
6B8132FA2C4C0F6300DB367E /* TokenToOtpAuthUrl.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 2 additions & 0 deletions Chronos/App/Tabs/Settings/Import/ImportSourceListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftUI

enum ImportSourceId {
case CHRONOS
case TWOFAS
case AEGIS
case RAIVO
case GOOGLE_AUTHENTICATOR
Expand All @@ -23,6 +24,7 @@ struct ImportSource: Identifiable {
struct ImportSourceListView: View {
let importSources: [ImportSource] = [
ImportSource(id: .CHRONOS, name: "Chronos", desc: "Export your tokens from Chronos to an unencrypted JSON file, then select the file below.", importType: .JSON),
ImportSource(id: .TWOFAS, name: "2FAS Authenticator", desc: "Export your tokens from 2FAS Authenticator using the \"Export\" option. Make sure \"Set a password for this backup file\" is unselected, then select the file below.", importType: .JSON),
ImportSource(id: .AEGIS, name: "Aegis", desc: "Export your tokens from Aegis using \"Export\" option. Select \"JSON\" as the export format and unselect \"Encrypt the vault\", then select the file below.", importType: .JSON),
ImportSource(id: .RAIVO, name: "Raivo", desc: "Export your tokens from Raivo using \"Export OTPs to ZIP archive\" option. Extract the JSON file from the archive, then select the file below.", importType: .JSON),
ImportSource(id: .GOOGLE_AUTHENTICATOR, name: "Google Authenticator", desc: "Export your tokens from Google Authenticator using the \"Transfer accounts\" option. Scan the QR code.", importType: .IMAGE),
Expand Down
40 changes: 40 additions & 0 deletions Chronos/Services/Import/ImportService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,46 @@ extension ImportService {
}
}

func importFrom2FAS(json: JSON) -> [Token]? {
var tokens: [Token] = []

for (key, subJson) in json["services"] {
guard
let issuer = subJson["otp"]["issuer"].string,
let account = subJson["otp"]["account"].string,
let secret = subJson["secret"].string,
let digits = subJson["otp"]["digits"].int,
let counter = subJson["otp"]["counter"].int,
let period = subJson["otp"]["period"].int,
let algorithm = subJson["otp"]["algorithm"].string,
let tokenAlgorithm = TokenAlgorithmEnum(rawValue: algorithm.uppercased()),
let type = subJson["otp"]["tokenType"].string,
let tokenType = TokenTypeEnum(rawValue: type.uppercased())
else {
logger.error("Error parsing token data for key: \(key)")
continue
}

let token = Token()
token.issuer = issuer
token.account = account
token.secret = secret
token.digits = digits
token.period = period
token.counter = counter
token.type = tokenType
token.algorithm = tokenAlgorithm

tokens.append(token)
}

if tokens.count != json["services"].count {
return nil
}

return tokens
}

func importFromRaivo(json: JSON) -> [Token]? {
var tokens: [Token] = []

Expand Down
Loading

0 comments on commit da06777

Please sign in to comment.