Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented 2fas import #60

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading