Commit 0272cb6c authored by Oliver Wiese's avatar Oliver Wiese

Merge branch 'dev'

Conflicts:
	enzevalos_iphone.xcodeproj/project.pbxproj
	enzevalos_iphone.xcodeproj/xcshareddata/xcschemes/enzevalos_iphone.xcscheme
	enzevalos_iphone/Base.lproj/Main.storyboard
	enzevalos_iphone/ContactViewController.swift
	enzevalos_iphone/SwiftUI/Inbox/Inbox.swift
	enzevalos_iphoneTests/GeneratedMocks.swift
parents 8ca668ee b631329b
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -49,9 +49,39 @@
ReferencedContainer = "container:enzevalos_iphone.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "CryptoTests/testfindNotSignedMailForPublicKey()">
</Test>
<Test
Identifier = "GamificationDataUnitTest">
</Test>
<Test
Identifier = "MailServerConfigurationTest">
</Test>
<Test
Identifier = "MailTest/testK9SecureInlineMail()">
</Test>
<Test
Identifier = "MailTest/testK9SecureMail()">
</Test>
<Test
Identifier = "MailTest/testK9SigedInlineMail()">
</Test>
<Test
Identifier = "MailTest/testK9SigedMail()">
</Test>
<Test
Identifier = "MailTest/testMacSecureMail()">
</Test>
<Test
Identifier = "MailTest/testMacSigedMail()">
</Test>
<Test
Identifier = "MailTest/testThunderbirdSigedInlineMail()">
</Test>
<Test
Identifier = "MailTest/testThunderbirdSigedMail()">
</Test>
</SkippedTests>
</TestableReference>
<TestableReference
......
......@@ -129,6 +129,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
});
}
}
func showBadgeCase() {
guard let vc = self.window?.rootViewController as? UINavigationController else {
fatalError("No rootViewController!")
}
let nextVC = UIHostingController(rootView: BadgeCaseView())
vc.navigationBar.isHidden = true
vc.pushViewController(nextVC, animated: true)
}
// Option removed from Settings app, but this might still be usefull in the future
func resetApp() {
......
//
// BadgeCaseView.swift
// enzevalos_iphone
//
// Created by Sezzart on 23.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import SwiftUI
struct BadgeCaseView: View {
init() {
UITableView.appearance().separatorStyle = .none
}
let badges: [Badge] = GamificationData.sharedInstance.badges.map { Badge(type: $0.type, description: $0.displayName, imageOn: $0.onName, imageOff: $0.offName, isActive: $0.isAchieved()) }
var body: some View {
NavigationView {
VStack {
Divider()
Spacer()
List {
ForEach(badges) { badge in
NavigationLink(destination: BadgeProgressView(badge: badge)) {
BadgeItem(badgeType: badge.type, badgeImageSrcOn: badge.imageOn, badgeImageSrcOff: badge.imageOff, badgeTitle: badge.description, isActive: badge.isActive)
}
}
}
}.navigationBarTitle(Text(NSLocalizedString("Gamification.Overview.HeaderTitle", comment:"Badge Case Navigation Title" )), displayMode: .inline).navigationBarItems(leading: Button(action: goBack, label: {
Text(NSLocalizedString("Back", comment: ""))
}))
}
}
func goBack() {
if let coord = AppDelegate.getAppDelegate().inboxCoordinator {
coord.goBack()
}
}
}
struct Badge: Identifiable {
var id = UUID()
var type: BadgeType
var description: String
var imageOn: String
var imageOff: String
var isActive: Bool
}
struct BadgeItem: View {
let badgeType: BadgeType
let badgeImageSrcOn: String
let badgeImageSrcOff: String
let badgeTitle: String
var isActive: Bool
init(badgeType: BadgeType, badgeImageSrcOn: String, badgeImageSrcOff: String, badgeTitle: String, isActive: Bool = false) {
self.badgeType = badgeType
self.badgeImageSrcOn = badgeImageSrcOn
self.badgeImageSrcOff = badgeImageSrcOff
self.badgeTitle = badgeTitle
self.isActive = isActive
}
var body: some View {
HStack {
Image(isActive ? badgeImageSrcOn : badgeImageSrcOff)
.resizable()
.scaledToFit()
.frame(width: 40,height: 40)
.padding(10)
Text(self.badgeTitle)
}
}
}
struct BadgeCaseView_Previews: PreviewProvider {
static var previews: some View {
BadgeCaseView()
}
}
//
// BadgeProgressView.swift
// enzevalos_iphone
//
// Created by Sezzart on 23.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import SwiftUI
struct BadgeProgressView: View {
let badge: Badge
var body: some View {
VStack {
titleBar
Divider()
List {
ForEach(GamificationData.sharedInstance.subBadgesforBadge(badge: badge.type).map { Badge(type: $0.type, description: $0.displayName, imageOn: $0.onName, imageOff: $0.offName, isActive: $0.isAchieved()) }) { subBadge in
Quest(isQuestCompleted: subBadge.isActive, description: subBadge.description, imageOn: subBadge.imageOn, imageOff: subBadge.imageOff)
}
}
}
}
private var titleBar: some View {
HStack{
Image(badge.imageOn)
.resizable()
.scaledToFit()
.frame(width: 50,height: 50)
.padding(5)
Text(badge.description)
Spacer()
}
}
}
struct Quest: View {
let isQuestCompleted: Bool
let description: String
let imageOn: String
let imageOff: String
init(isQuestCompleted: Bool, description: String, imageOn: String, imageOff: String) {
self.isQuestCompleted = isQuestCompleted
self.description = description
self.imageOn = imageOn
self.imageOff = imageOff
}
var body: some View {
HStack {
Image(isQuestCompleted ? imageOn : imageOff)
.resizable()
.scaledToFit()
.frame(width: 40,height: 40)
.padding(10)
Text(description)
}
}
}
struct BadgeProgressView_Previews: PreviewProvider {
static var previews: some View {
BadgeProgressView(badge: Badge(type: .MailMaster, description: NSLocalizedString("Mailmaster", comment:"Mailmaster badge" ), imageOn: "verschluesseltOn", imageOff: "verschluesseltOff", isActive: true))
}
}
......@@ -35,6 +35,7 @@ enum BadgeType: Int {
case onBoarding
case inviteAFriend
case Ambassador
case friendlyKeyMaster
case MailMaster
case MailMaster1
......@@ -51,6 +52,11 @@ enum BadgeType: Int {
case SecureMailMaster100
case SecureMailMaster1000
case None // for SubBadge
case FriendlyKeyMaster
case FriendlyKeyMaster10
case FriendlyKeyMaster50
case FriendlyKeyMaster100
}
/**
......@@ -72,6 +78,10 @@ enum Achievment {
case SecureMails1000
case SecureSend
case SecureReceived
case FriendlyKeyMaster1
case FriendlyKeyMaster10
case FriendlyKeyMaster50
case FriendlyKeyMaster100
}
/**
......
//
// CHelpers.swift
// enzevalos_iphone
//
// Created by lazarog98 on 10.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import Foundation
/**
Creates an arraz of C Strings from an array of swift strings
Always call deallocateCStrArr after using this!
*/
func createCStrArr(sarr: [String]) -> UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?{
let len = sarr.count
let carr = init_str_arr(Int32(len))
for i in 0..<len
{
let str = sarr[i]
add_str_to_arr(str,carr,Int32(i))
}
return carr
}
/**
Deallocates an array of c strings
*/
func deallocateCStrArr(arr: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, len: Int){
return deallocate_str_arr(arr, Int32(len))
}
//
// Certificate.swift
// enzevalos_iphone
//
// Created by lazarog98 on 18.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import Foundation
/**
Contains information about a certificate
*/
class Certificate {
let pem: String // raw PEM string
let fingerPrint: String
let eMails: [String]?
let issuer: String?
let hasPrivateKey: Bool
let subject: String?
let startDate: String?
let endDate: String?
init(pem: String) {
let cCertInfo = get_cert_data(pem)
defer {
deallocateCertInfo(certInfo: cCertInfo)
}
let certInfo = cCertInfo?.pointee
self.hasPrivateKey = pem.contains("PRIVATE KEY")
let (fingerPrint, _, errors) = getFingerprintFromPem(pem: pem)
// if it crashes on this line, you can loop through the errors and see what's wrong
self.fingerPrint = fingerPrint!
self.pem = pem
self.eMails = certInfo?.extractField(field: CertInfoString.emails)
self.endDate = certInfo?.extractField(field: CertInfoString.endDate)
self.startDate = certInfo?.extractField(field: CertInfoString.startDate)
self.subject = certInfo?.extractField(field: CertInfoString.subject)
self.issuer = certInfo?.extractField(field: CertInfoString.issuer)
}
}
/**
An enum used in the extractString() method of cert_info
*/
enum CertInfoString {
case issuer;
case subject;
case startDate;
case endDate;
case emails;
}
/**
extensions to the C struct so that memory deallocation is automatic
*/
extension cert_info {
/**
Extracts an array of certs in PEM of the respective function from the result object
Deallocates the "errors" part of the result object
Only use in combination with_extractOutput and _extractErrors
*/
private func extractEmails() -> [String]? {
let arr = self.emails
var strArr: [String]? = nil
if arr != nil {
strArr = []
let size = self.num_emails
//print("Size:",size)
for i in 0..<size {
let str = String(cString: arr![Int(i)]!)
strArr?.append(str)
// (arr![Int(i)])!.deallocate()
}
// arr?.deallocate()
}
return strArr
}
/**
Extracts the output of the respective function from the result object
Deallocates the "res" part of the result object
Only use in combination with_extractErrors
- parameters:
- field: the result object
*/
private func extractString(field: CertInfoString) -> String? {
let cStr: UnsafeMutablePointer<Int8>?
switch field {
case .endDate:
cStr = self.date_end
case .startDate:
cStr = self.date_start
case .issuer:
cStr = self.issuer
case .subject:
cStr = self.subject
default:
return nil
}
var swiftStr: String? = nil
if cStr != nil {
swiftStr = String(cString: cStr!)
}
return swiftStr
}
/**
A generic function that reads a field and casts it to the type of the variable that stores the result. The variable must therefore have the correct type
- parameters:
- field: enum, specifiying the field to extract
*/
func extractField<T>(field: CertInfoString) -> T? {
switch field {
case .emails:
let emails = self.extractEmails()
if emails is T? {
return emails as! T?
}
default:
let res = self.extractString(field: field)
if res is T? {
return res as! T?
}
}
return nil
}
}
......@@ -86,11 +86,7 @@ class ContactViewController: UIViewController {
if let row = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: row, animated: false)
}
navigationController?.isToolbarHidden = true
}
override func viewWillDisappear(_ animated: Bool){
navigationController?.isToolbarHidden = true
navigationController?.navigationBar.isHidden = false
}
@objc func feedback() {
......@@ -541,7 +537,7 @@ extension ContactViewController: UITableViewDataSource {
let badgeCell = tableView.dequeueReusableCell(withIdentifier: "BadgeCaseCell", for: indexPath)
badgeCell.detailTextLabel?.text = NSLocalizedString("YourBadges", comment: "")
if StudySettings.hideBadges {
badgeCell.isHidden = true
badgeCell.isHidden = false
}
return badgeCell
case 6 where isUser:
......@@ -651,6 +647,13 @@ extension ContactViewController: UITableViewDelegate {
UIPasteboard.general.string = keyRecord!.ezContact.getMailAddresses()[indexPath.row].mailAddress
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let BADGE_CASE_CELL_ROW = 5
if indexPath.section == BADGE_CASE_CELL_ROW {
AppDelegate.getAppDelegate().showBadgeCase()
}
}
}
extension ContactViewController: UINavigationControllerDelegate {
......
......@@ -55,12 +55,15 @@ enum EncryptionState: Int16 {
public enum CryptoScheme {
case PGP
case SMIME
case UNKNOWN
var description: String {
switch self {
case .PGP:
return "PGP"
case .SMIME:
return "SMIME"
default:
return ""
}
......@@ -78,6 +81,8 @@ public enum CryptoScheme {
switch self {
case CryptoScheme.PGP:
return 0
case CryptoScheme.SMIME:
return 1
case CryptoScheme.UNKNOWN:
return 99
}
......@@ -91,6 +96,7 @@ public class CryptoObject {
let signatureState: SignatureState
var encryptionState: EncryptionState
let signKey: String?
let signedKeys: [String]
let encType: CryptoScheme
let passcode: String?
let signedAdrs: [String]
......@@ -109,7 +115,6 @@ public class CryptoObject {
return nil
}
init(chiphertext: Data?, plaintext: String?, decryptedData: Data?, sigState: SignatureState, encState: EncryptionState, signKey: String?, encType: CryptoScheme, signedAdrs: [String]) {
self.chiphertext = chiphertext
self.plaintext = plaintext
......@@ -120,5 +125,25 @@ public class CryptoObject {
self.encType = encType
self.passcode = nil
self.signedAdrs = signedAdrs
if signKey != nil
{
self.signedKeys = [signKey!]
}
else{
self.signedKeys = []
}
}
init(chiphertext: Data?, plaintext: String?, decryptedData: Data?, sigState: SignatureState, encState: EncryptionState, signKey: String?, encType: CryptoScheme, signedAdrs: [String], signedKeys: [String]) {
self.chiphertext = chiphertext
self.plaintext = plaintext
self.decryptedData = decryptedData
self.signatureState = sigState
self.encryptionState = encState
self.signKey = signKey
self.encType = encType
self.passcode = nil
self.signedAdrs = signedAdrs
self.signedKeys = signedKeys
}
}
......@@ -1127,19 +1127,17 @@ class DataHandler {
return []
}
/**
Filters all Presistent Mails with encState == EncryptionState.UnableToDecrypt
*/
func getAllNotDecryptedPersistentMail() -> [PersistentMail] {
let result = getAllPersistentMails().filter({ $0.encState == EncryptionState.UnableToDecrypt })
return result
}
// filter all presistent mails without public key
func getAllNoPublicKeyPersistentMail() -> [PersistentMail] {
let result = getAllPersistentMails().filter({ $0.sigState == SignatureState.NoPublicKey })
return result
}
/**
Filters all Presistent Mails with sigState == SignatureState.NoPublicKey
*/
func getAllNotSignedPersistentMail() -> [PersistentMail] {
let result = getAllPersistentMails().filter({ $0.sigState == SignatureState.NoPublicKey })
return result
......
......@@ -43,7 +43,8 @@ class GamificationData: NSObject {
Badges.init(type: .SecureMailMaster , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", segue: .LinearBadge, displayName: NSLocalizedString("Secure Mailmaster", comment:"Secure Mailmaster badge" )),
Badges.init(type: .onBoarding, pictureOff: "onboardingOff", pictureOn: "onboardingOn", segue: .LinearBadge, displayName: NSLocalizedString("Onboarded", comment:"Onboarded" )),
Badges.init(type: .inviteAFriend, pictureOff: "invitefriendOff", pictureOn: "invitefriendOn", segue: .inviteFriend, displayName: NSLocalizedString("Invite a friend", comment: "Invite a friend" )),
Badges.init(type: .Ambassador, pictureOff: "ambassadorOff", pictureOn: "ambassadorOn", segue: .inviteFriend, displayName: NSLocalizedString("Ambassador", comment:"Ambassador" ))
Badges.init(type: .Ambassador, pictureOff: "ambassadorOff", pictureOn: "ambassadorOn", segue: .inviteFriend, displayName: NSLocalizedString("Ambassador", comment:"Ambassador" )),
Badges.init(type: .friendlyKeyMaster, pictureOff: "keymasterOff", pictureOn: "keymasterOn", segue: .LinearBadge, displayName: NSLocalizedString("Friendly Key Master", comment: "Friendly Key Master" ))
]
......@@ -89,6 +90,14 @@ class GamificationData: NSObject {
Badges.init(type: .SecureMailMaster100 , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", displayName: NSLocalizedString("100 secure Mails Send/Received", comment:"SecureMailMaster Subbadge" ), achievmentsNeeded: [.SecureMails100]),
Badges.init(type: .SecureMailMaster1000 , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", displayName: NSLocalizedString("1000 secure Mails Send/Received", comment:"SecureMailMaster Subbadge" ), achievmentsNeeded: [.SecureMails1000])
]
case .friendlyKeyMaster:
return [
Badges.init(type: .FriendlyKeyMaster , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("One friends public key stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster1 ]),
Badges.init(type: .FriendlyKeyMaster10 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("10 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster10 ]),
Badges.init(type: .FriendlyKeyMaster50 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("50 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster50 ]),
Badges.init(type: .FriendlyKeyMaster100 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("100 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster100])
]
default:
return [Badges]()
......@@ -286,6 +295,14 @@ class GamificationData: NSObject {
return secureMailsSend > 0
case .SecureReceived:
return secureMailsReceived > 0
case .FriendlyKeyMaster1:
return secureContactsCount > 0
case .FriendlyKeyMaster10:
return secureContactsCount > 9
case .FriendlyKeyMaster50:
return secureContactsCount > 49
case .FriendlyKeyMaster100:
return secureContactsCount > 99
// default: return false
}
}
......
This diff is collapsed.
//
// MailComparison.swift
// enzevalos_iphone
//
// Created by Katharina Müller and Viktoria Sorgalla on 04.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import Foundation
import CoreData
private let datahandler = DataHandler.handler
public enum ResultCompareSenderToContacts {
case isContact, isSender, OnlyIdentity, Unknown
}
extension String {
/**
compares the given mail address to the persistant mails and returns the number of matches
***/
private func countMatches(_ mailAddr: String, _ inboxMails: [PersistentMail]) -> Int {
var senders: [String] = []
for sender in inboxMails{
let sender: String = sender.from.mailAddress
senders.append(sender)
}
var numberOfFoundMatches = 0
for addr in senders{
if addr == mailAddr{
numberOfFoundMatches += 1
}
}
return numberOfFoundMatches
}
/**
returns a mail address, wich has the same identity as the given one but a different domain
***/
private func getIdentityWithDifferentDomain(_ mailAdd: String, inboxMails: [PersistentMail]) -> String{
let senderIdentity = mailAdd.getLocalMailIdentity()
var senderDomain = mailAdd.splitAddress()
senderDomain.removeFirst()
var senders: [String] = []
for sender in inboxMails{
let sender: String = sender.from.mailAddress
senders.append(sender)
}
var foundMatch = ""
for addr in senders{
let foundIdentity = addr.getLocalMailIdentity()
var foundDomain = addr.splitAddress()
foundDomain.removeFirst()