Skip to content

Commit

Permalink
feat: Implement Raivo import (#26)
Browse files Browse the repository at this point in the history
* Added Raivo import

* Added raivo import test

* Fixed lint
  • Loading branch information
joeldavidw authored Jul 18, 2024
1 parent 7853860 commit bf86938
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Chronos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
6B7383E02B9C3962008E8867 /* Factory in Frameworks */ = {isa = PBXBuildFile; productRef = 6B7383DF2B9C3962008E8867 /* Factory */; };
6B7383E52B9C4230008E8867 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7383E42B9C4230008E8867 /* Container.swift */; };
6B7A54742B94B7A30057DCF9 /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7A54732B94B7A30057DCF9 /* PrivacyView.swift */; };
6B8132F22C4975DA00DB367E /* Raivo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B8132F12C4975DA00DB367E /* Raivo.swift */; };
6B842DD52BE33E2E00056F0F /* RestoreBackupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B842DD42BE33E2E00056F0F /* RestoreBackupView.swift */; };
6B8ABEEC2B8F6A4F00F5B514 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 6B8ABEEB2B8F6A4F00F5B514 /* CryptoSwift */; };
6B9581E22B62AFF80029EF3C /* ViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B9581E12B62AFF80029EF3C /* ViewModifier.swift */; };
Expand Down Expand Up @@ -113,6 +114,7 @@
6B7383E42B9C4230008E8867 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
6B7A546F2B94584E0057DCF9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
6B7A54732B94B7A30057DCF9 /* PrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyView.swift; sourceTree = "<group>"; };
6B8132F12C4975DA00DB367E /* Raivo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Raivo.swift; sourceTree = "<group>"; };
6B842DD42BE33E2E00056F0F /* RestoreBackupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreBackupView.swift; sourceTree = "<group>"; };
6B9581E12B62AFF80029EF3C /* ViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifier.swift; sourceTree = "<group>"; };
6B9581E32B633A880029EF3C /* AddManualTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddManualTokenView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -293,6 +295,7 @@
isa = PBXGroup;
children = (
6B4CBF2E2C490FB700983D44 /* Chronos.swift */,
6B8132F12C4975DA00DB367E /* Raivo.swift */,
);
path = Import;
sourceTree = "<group>";
Expand Down Expand Up @@ -612,6 +615,7 @@
buildActionMask = 2147483647;
files = (
6B4CBF2F2C490FB700983D44 /* Chronos.swift in Sources */,
6B8132F22C4975DA00DB367E /* Raivo.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Chronos/App/Tabs/Settings/Import/ImportSelectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct ImportSource: Identifiable {
struct ImportSelectionView: 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."),
// 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."),
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."),
]

@EnvironmentObject var importNav: ExportNavigation
Expand Down
45 changes: 45 additions & 0 deletions Chronos/Services/ImportService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class ImportService {
switch importSource.id {
case "chronos":
return importFromChronos(json: json)
case "raivo":
return importFromRaivo(json: json)
default:
logger.error("Unsupported import source: \(importSource.id)")
return nil
Expand Down Expand Up @@ -51,4 +53,47 @@ extension ImportService {
return nil
}
}

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

for (key, subJson) in json {
guard
let issuer = subJson["issuer"].string,
let account = subJson["account"].string,
let secret = subJson["secret"].string,

let digitsString = subJson["digits"].string,
let digits = Int(digitsString),

let periodString = subJson["timer"].string,
let period = Int(periodString),

let counterString = subJson["counter"].string,
let counter = Int(counterString),

let kind = subJson["kind"].string,
let algorithm = subJson["algorithm"].string,
let tokenType = TokenTypeEnum(rawValue: kind),
let tokenAlgorithm = TokenAlgorithmEnum(rawValue: algorithm)
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)
}

return tokens
}
}
9 changes: 0 additions & 9 deletions ChronosTests/Import/Chronos.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
@testable import Chronos
import Factory
import SwiftyJSON
import XCTest

final class ChronosTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testValidImport() throws {
let json: JSON = [
"tokens": [
Expand Down
81 changes: 81 additions & 0 deletions ChronosTests/Import/Raivo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
@testable import Chronos
import SwiftyJSON
import XCTest

final class RaivoTests: XCTestCase {
func testValidImport() throws {
let json: JSON = [
[
"secret": "ff",
"timer": "30",
"account": "Test HOTP",
"kind": "HOTP",
"algorithm": "SHA1",
"digits": "6",
"pinned": "false",
"iconValue": "",
"counter": "12",
"issuer": "Raivo",
"iconType": "",
],
[
"issuer": "Raivo",
"secret": "JBSWY3DPEHPK3PXP",
"iconType": "",
"iconValue": "",
"pinned": "false",
"algorithm": "SHA1",
"digits": "6",
"kind": "TOTP",
"timer": "30",
"counter": "0",
"account": "Test TOTP",
],
]

let importService = ImportService()
let tokens = importService.importFromRaivo(json: json)!

XCTAssertEqual(tokens.count, 2)

XCTAssertEqual(tokens[0].digits, 6)
XCTAssertEqual(tokens[0].type, TokenTypeEnum.HOTP)
XCTAssertEqual(tokens[0].counter, 12)
XCTAssertEqual(tokens[0].algorithm, TokenAlgorithmEnum.SHA1)
XCTAssertEqual(tokens[0].issuer, "Raivo")
XCTAssertEqual(tokens[0].account, "Test HOTP")
XCTAssertEqual(tokens[0].period, 30)
XCTAssertEqual(tokens[0].secret, "ff")

XCTAssertEqual(tokens[1].digits, 6)
XCTAssertEqual(tokens[1].type, TokenTypeEnum.TOTP)
XCTAssertEqual(tokens[1].counter, 0)
XCTAssertEqual(tokens[1].algorithm, TokenAlgorithmEnum.SHA1)
XCTAssertEqual(tokens[1].issuer, "Raivo")
XCTAssertEqual(tokens[1].account, "Test TOTP")
XCTAssertEqual(tokens[1].period, 30)
XCTAssertEqual(tokens[1].secret, "JBSWY3DPEHPK3PXP")
}

func testInvalidImport_MissingVariables() throws {
let json: JSON = [
[
"issuer": "Raivo",
"iconType": "",
"iconValue": "",
"pinned": "false",
"algorithm": "SHA1",
"digits": "6",
"kind": "TOTP",
"timer": "30",
"counter": "0",
"account": "Test TOTP",
],
]

let importService = ImportService()
let tokens = importService.importFromChronos(json: json)

XCTAssertNil(tokens)
}
}

0 comments on commit bf86938

Please sign in to comment.