From da1af1958f2ad48ea67a8874e31d2ab3be04bb2b Mon Sep 17 00:00:00 2001 From: Oliver Wiese <oliver.wiese@fu-berlin.de> Date: Tue, 29 Jan 2019 12:50:58 +0100 Subject: [PATCH] update study setting parameters --- enzevalos_iphone.xcodeproj/project.pbxproj | 27 +- enzevalos_iphone/AppDelegate.swift | 2 +- enzevalos_iphone/Dialog/DialogOption.swift | 6 +- .../IconsStyleKit.swift | 0 enzevalos_iphone/Logger.swift | 7 +- enzevalos_iphone/New Group/Mailbot.swift | 114 +++++++++ .../SendViewController+Invitation.swift | 4 +- enzevalos_iphone/SendViewController.swift | 2 +- enzevalos_iphone/StudySettings.swift | 235 ++---------------- enzevalos_iphone/UserData.swift | 6 +- .../study parameters/Invitation.swift | 74 ++++++ .../study parameters/SecurityIndicator.swift | 37 ++- .../StudyParameterProtocol.swift | 65 ++++- .../study parameters/Warning.swift | 60 +++++ enzevalos_iphoneTests/StudyTest.swift | 105 ++++++++ 15 files changed, 505 insertions(+), 239 deletions(-) rename enzevalos_iphone/{study parameters => }/IconsStyleKit.swift (100%) create mode 100644 enzevalos_iphone/New Group/Mailbot.swift create mode 100644 enzevalos_iphone/study parameters/Invitation.swift create mode 100644 enzevalos_iphone/study parameters/Warning.swift create mode 100644 enzevalos_iphoneTests/StudyTest.swift diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 16057f89..a82a9d06 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -158,6 +158,10 @@ 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */; }; 477548E521F77DF5000B22A8 /* StudyParameterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */; }; 477548E621F77DF7000B22A8 /* SecurityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E121F77466000B22A8 /* SecurityIndicator.swift */; }; + 478154A721FF3F0900A931EC /* Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154A621FF3F0900A931EC /* Warning.swift */; }; + 478154A921FF3FF400A931EC /* Invitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154A821FF3FF400A931EC /* Invitation.swift */; }; + 478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154AB21FF6A9600A931EC /* Mailbot.swift */; }; + 478154AE2200641900A931EC /* StudyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154AD2200641900A931EC /* StudyTest.swift */; }; 47953AA91FD7000200D4631A /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47953AA81FD7000200D4631A /* bitcoinde.asc */; }; 47953AAA1FD7000200D4631A /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47953AA81FD7000200D4631A /* bitcoinde.asc */; }; 479B5977206914BE00B3944D /* CryptoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479B5976206914BE00B3944D /* CryptoTests.swift */; }; @@ -357,6 +361,10 @@ 477548DD21F5DABE000B22A8 /* MailServerConnectionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailServerConnectionError.swift; sourceTree = "<group>"; }; 477548E121F77466000B22A8 /* SecurityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityIndicator.swift; sourceTree = "<group>"; }; 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyParameterProtocol.swift; sourceTree = "<group>"; }; + 478154A621FF3F0900A931EC /* Warning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Warning.swift; sourceTree = "<group>"; }; + 478154A821FF3FF400A931EC /* Invitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Invitation.swift; sourceTree = "<group>"; }; + 478154AB21FF6A9600A931EC /* Mailbot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mailbot.swift; sourceTree = "<group>"; }; + 478154AD2200641900A931EC /* StudyTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyTest.swift; sourceTree = "<group>"; }; 47953AA81FD7000200D4631A /* bitcoinde.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bitcoinde.asc; sourceTree = "<group>"; }; 479B5976206914BE00B3944D /* CryptoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoTests.swift; sourceTree = "<group>"; }; 479C649521F2139B00A01071 /* support_pk.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = support_pk.asc; sourceTree = "<group>"; }; @@ -635,12 +643,22 @@ isa = PBXGroup; children = ( 477548E121F77466000B22A8 /* SecurityIndicator.swift */, - F1984D711E1D327200804E1E /* IconsStyleKit.swift */, + 478154A621FF3F0900A931EC /* Warning.swift */, 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */, + 478154A821FF3FF400A931EC /* Invitation.swift */, ); path = "study parameters"; sourceTree = "<group>"; }; + 478154AA21FF6A5300A931EC /* mailbot */ = { + isa = PBXGroup; + children = ( + 478154AB21FF6A9600A931EC /* Mailbot.swift */, + ); + name = mailbot; + path = "New Group"; + sourceTree = "<group>"; + }; 47B91AC01EC0C1CF000AE3EE /* coredata */ = { isa = PBXGroup; children = ( @@ -820,6 +838,7 @@ A198270D1D9A8ABC0027F65C /* enzevalos_iphone-Bridging-Header.h */, A1F9922B1DA7C9100073BF1B /* Main.storyboard */, F1984D731E1E92B300804E1E /* LabelStyleKit.swift */, + F1984D711E1D327200804E1E /* IconsStyleKit.swift */, A1123E6C1DA682850069551C /* Localizable.strings */, A13526841D955BDF00D3BFE1 /* LaunchScreen.storyboard */, A1EB05A31D956E32008659C1 /* Assets.xcassets */, @@ -844,6 +863,7 @@ 8428A8561F4369EA007649A5 /* GamificationDataUnitTest.swift */, 479B5976206914BE00B3944D /* CryptoTests.swift */, 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */, + 478154AD2200641900A931EC /* StudyTest.swift */, ); path = enzevalos_iphoneTests; sourceTree = "<group>"; @@ -860,6 +880,7 @@ A17FDFF1202C680A00F7BA89 /* debug and study */ = { isa = PBXGroup; children = ( + 478154AA21FF6A5300A931EC /* mailbot */, 477548E021F77445000B22A8 /* study parameters */, A17FDFF2202C685800F7BA89 /* StudySettings.swift */, 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */, @@ -1525,6 +1546,7 @@ 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */, 3EB4FAA420120096001D0625 /* DialogOption.swift in Sources */, F14239C11F30A99C00998A83 /* QRCodeGenerator.swift in Sources */, + 478154A921FF3FF400A931EC /* Invitation.swift in Sources */, F1AF938F1E2D04BA00755128 /* CustomCells.swift in Sources */, 8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */, F1866C86201F707200B72453 /* EmailHelper.m in Sources */, @@ -1581,11 +1603,13 @@ F12060821DA552FC00F6EF37 /* MailHandlerDelegator.swift in Sources */, A18E7D771FBDE5D9002F7CC9 /* LoggingEventType.swift in Sources */, F1984D741E1E92B300804E1E /* LabelStyleKit.swift in Sources */, + 478154A721FF3F0900A931EC /* Warning.swift in Sources */, 8428A8681F436A11007649A5 /* SubBadgeTableViewCell.swift in Sources */, A1EB05861D956872008659C1 /* FrequentCell.swift in Sources */, F12041FB1DA3FBF7002E4940 /* ListViewController.swift in Sources */, F18B445E1E7044B70080C041 /* FlipTransition.swift in Sources */, 472F397E1E1D0B0B009260FB /* EnzevalosContact+CoreDataProperties.swift in Sources */, + 478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */, 8428A86E1F436A1E007649A5 /* BadgeCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1600,6 +1624,7 @@ 479B5977206914BE00B3944D /* CryptoTests.swift in Sources */, 4715F637202A0248001BFFD0 /* CoreDataTests.swift in Sources */, 47C22281218AFD6300BD2C2B /* AutocryptTest.swift in Sources */, + 478154AE2200641900A931EC /* StudyTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index 9c8c5d37..d4e4d7f5 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -206,7 +206,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let handler = DataHandler.init() _ = handler.createNewSecretKey(adr: UserManager.loadUserValue(Attribute.userAddr) as! String) StudySettings.setupStudyKeys() - StudySettings.firstMail() + Mailbot.firstMail() DataHandler.handler.callForFolders(done: { err in for f in DataHandler.handler.allFolders { if f.flags.contains(MCOIMAPFolderFlag.drafts) { diff --git a/enzevalos_iphone/Dialog/DialogOption.swift b/enzevalos_iphone/Dialog/DialogOption.swift index 902e7cd5..bf3cae52 100644 --- a/enzevalos_iphone/Dialog/DialogOption.swift +++ b/enzevalos_iphone/Dialog/DialogOption.swift @@ -44,7 +44,7 @@ enum DialogOption { case .invitationCode : return nil case .invitationWelcome, .invitationHelp : switch StudySettings.invitationsmode { - case InvitationMode.Censorship: + case .Censorship: var images = [UIImage]() if let sender = UIImage(named: "bg_inviation_censor_sender"), let receiver = UIImage(named: "bg_inviation_censor_receiver") { images.append(sender) @@ -94,12 +94,12 @@ enum DialogOption { case .PasswordEnc : return NSLocalizedString("Invitation.Welcome.Message", comment: "") } case .invitationStep : - if StudySettings.invitationsmode == InvitationMode.Censorship{ + if StudySettings.invitationsmode == Inviation.Censorship{ return NSLocalizedString("Invitation.Step.Message.Censor", comment: "") } return NSLocalizedString("Invitation.Step.Message", comment: "") case .invitationCode(let code) : - if StudySettings.invitationsmode == InvitationMode.Censorship{ + if StudySettings.invitationsmode == Inviation.Censorship{ return "" } return String(format: NSLocalizedString("Invitation.Code.Message", comment: ""), code) diff --git a/enzevalos_iphone/study parameters/IconsStyleKit.swift b/enzevalos_iphone/IconsStyleKit.swift similarity index 100% rename from enzevalos_iphone/study parameters/IconsStyleKit.swift rename to enzevalos_iphone/IconsStyleKit.swift diff --git a/enzevalos_iphone/Logger.swift b/enzevalos_iphone/Logger.swift index 3902a867..ccba139a 100644 --- a/enzevalos_iphone/Logger.swift +++ b/enzevalos_iphone/Logger.swift @@ -64,14 +64,15 @@ class Logger { } } - static func log(setupStudy studypara: [StudyParamter: Int], alreadyRegistered: Bool) { + static func log(setupStudy studypara: [StudyParameterProtocol.Type], alreadyRegistered: Bool) { if !logging { return } var event = plainLogDict() event["type"] = LoggingEventType.setupStudy.rawValue - for (para, value) in studypara { - event[para.name] = value + + for para in studypara{ + event[para.name] = para.load().value } event["alreadyRegistered"] = alreadyRegistered saveToDisk(json: dictToJSON(fields: event)) diff --git a/enzevalos_iphone/New Group/Mailbot.swift b/enzevalos_iphone/New Group/Mailbot.swift new file mode 100644 index 00000000..7c7b0202 --- /dev/null +++ b/enzevalos_iphone/New Group/Mailbot.swift @@ -0,0 +1,114 @@ +// +// Mailbot.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +class Mailbot { + + static let faqURL = "https://userpage.fu-berlin.de/letterbox/faq.html" + static let raffleURL = "" + + + static var entrySurveyURL: String { + get { + return "https://userpage.fu-berlin.de/letterbox/entrysurvey.html?id=\(faqURL)" + } + } + + static let bitcoinStudyBody = + """ + Liebe Teilnehmerin, lieber Teilnehmer, + + Herzlichen Glückwunsch! Sie haben Letterbox erfolgreich installiert. + + Wenn Sie Fragen zur App oder Verschlüsselung haben, besuchen Sie doch unsere Hilfeseite: + \(faqURL) + + Dort finden Sie auch Videos zum Thema Ende-zu-Ende-Verschlüsselung. + Falls Sie Fragen haben oder uns Feedback geben möchten, freuen wir uns auf Ihre E-Mail! + + Die Studie umfasst drei Aufgaben und kann jederzeit abgebrochen werden. Für Fragen schreiben Sie uns bitte eine E-Mail und benutzen Sie bitte nach Möglichkeit die Letterbox dafür. + + In der ersten Aufgabe verfassen Sie bitte einen ersten Brief, indem Sie auf diese E-Mail antworten. Bitte teilen Sie uns Ihre Meinung mit. Ist etwas unklar geblieben? Was war neu für Sie? Was fanden Sie besonders interessant; was uninteressant? Hätten Sie sich noch weitere Informationen gewünscht? Sie können auch gerne Fragen zur Einführung stellen. + + Nach Beantwortung dieser E-Mail senden wir Ihnen zu einem späteren Zeitpunkt eine zweite E-Mail mit der nächsten kurzen Aufgabe zu. + + Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, + Ihr Letterbox-Team + + PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. + """ + + static let welcomeBody = + """ + Liebe Nutzerin, lieber Nutzer von Letterbox, + + Ich bin Lette, der Letterbox-Mailbot. Wir freuen uns, dass du dich für unsere App entschieden hast. Magst du mir gleich auf die E-Mail antworten? Dann kannst du gleich erfahren, wie einfach es ist sichere Mails zu schreiben. Du und ich wissen dann das es bei dir auch klappt. + + Wir freuen uns auch jederzeit über Fragen oder einem Feedback von dir. Wir freuen uns auf deine Antwort! + + Vielen Dank und viele Grüße + Lette + + PS: Diese Nachricht wurde automatisch auf deinem Gerät bei der Installation von Letterbox erzeugt und ist nur hier gespeichert. + """ + + + static func firstMail() { + if !StudySettings.studyMode || !StudySettings.presentFirstQuestionaireMail { + return + } + let subject = "Herzlich Willkommen in Letterbox" + let body = welcomeBody + + mailToParticipat(subject: subject, body: body) + } + + static func givecards() { + if !StudySettings.studyMode || !StudySettings.presentFirstQuestionaireMail { + return + } + let subject = "Teilnahmeentschädigung: Verlosung von Amazon-Gutscheinen" + let body = + """ + Liebe Teilnehmerin, lieber Teilnehmer, + + unter den teilnehmenden Personen werden 20 Amazon-Gutscheine im Wert von jeweils 50 Euro verlost. + + Um an der Verlosung teilnehmen zu können, müssen Sie uns Ihren Namen und die postalische Adresse mitteilen. + Falls Sie einen Gutschein gewinnen, wird dieser Ihnen per Post zugesendet. Außerdem werden Ihr Name und Ihre Adresse für den Nachweis der ordnungsgemäßen Verwendung der Gelder gespeichert, andernfalls werden sie gelöscht. + + Ihre Name und Ihre Adresse werden nicht mit anderen erhobenen Daten verknüpft und getrennt von diesen gespeichert. + + Wenn Sie an der Verlosung teilnehmen möchten, melden Sie sich bitte auf folgenden Link an: + \(raffleURL) + + Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, + Ihr Letterbox-Team + + PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. + """ + + mailToParticipat(subject: subject, body: body) + } + + + private static func mailToParticipat(subject: String, body: String) { + let senderAdr = SUPPORT_MAIL_ADR + let sender = MCOAddress.init(displayName: "Letterbox-Team", mailbox: senderAdr) + var keyID: String? + if let addr = DataHandler.handler.findMailAddress(adr: senderAdr) { + if let pk = addr.primaryKey { + keyID = pk.keyID + } + } + let cryptoObject = CryptoObject(chiphertext: nil, plaintext: body, decryptedData: body.data(using: .utf8), sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: keyID, encType: CryptoScheme.PGP, signedAdrs: [senderAdr]) + + _ = DataHandler.handler.createMail(0, sender: sender, receivers: [], cc: [], time: Date(), received: false, subject: subject, body: body, flags: MCOMessageFlag.init(rawValue: 0), record: nil, autocrypt: nil, decryptedData: cryptoObject, folderPath: UserManager.backendInboxFolderPath, secretKey: nil) + } +} diff --git a/enzevalos_iphone/SendViewController+Invitation.swift b/enzevalos_iphone/SendViewController+Invitation.swift index 4a02f6ff..b18cece7 100644 --- a/enzevalos_iphone/SendViewController+Invitation.swift +++ b/enzevalos_iphone/SendViewController+Invitation.swift @@ -34,7 +34,7 @@ extension SendViewController { var isCensored: Bool { get { - return StudySettings.invitationsmode == InvitationMode.Censorship + return StudySettings.invitationsmode == Inviation.Censorship } } @@ -95,7 +95,7 @@ extension SendViewController { } } - if (self.invitationSelection.code == nil && StudySettings.invitationsmode == InvitationMode.PasswordEnc) { + if (self.invitationSelection.code == nil && StudySettings.invitationsmode == Inviation.PasswordEnc) { self.invitationSelection.code = cipherText.password } var previousText = "" diff --git a/enzevalos_iphone/SendViewController.swift b/enzevalos_iphone/SendViewController.swift index ae5b0b0c..9522cda2 100644 --- a/enzevalos_iphone/SendViewController.swift +++ b/enzevalos_iphone/SendViewController.swift @@ -59,7 +59,7 @@ class SendViewController: UIViewController { var tableDataDelegate = TableViewDataDelegate(insertCallback: { (name: String, address: String) -> Void in return }) var collectionDataDelegate = CollectionDataDelegate(suggestionFunc: AddressHandler.frequentAddresses, insertCallback: { (name: String, address: String) -> Void in return }) var recognizer: UIGestureRecognizer = UIGestureRecognizer.init() - var freeTextInviationTitle = StudySettings.freeTextInvitationTitle + var freeTextInviationTitle = StudySettings.invitationsmode.freeTextInvitationTitle //These attributes may be interesting to set in a segue to SendViewController var prefilledMail: EphemeralMail? = nil diff --git a/enzevalos_iphone/StudySettings.swift b/enzevalos_iphone/StudySettings.swift index 2a2ec0fa..f5c06561 100644 --- a/enzevalos_iphone/StudySettings.swift +++ b/enzevalos_iphone/StudySettings.swift @@ -21,134 +21,40 @@ import Foundation import KeychainAccess -enum StudyParamter: Int { - case Warning = 0 - case Invitation = 1 - case Indicator = 2 - var name: String { - get { - switch self { - case .Warning: - return "warning" - case .Invitation: - return "invitation" - case .Indicator: - return "indicator" - } - } - } - - var keyName: String { - get { - switch self { - case .Warning: - return "hideWarnings" - case .Invitation: - return "invitation mode" - case .Indicator: - return "indicator mode" - } - - } - } - var numberOfTreatments: UInt32 { - get { - switch self { - case .Warning: - return 2 - case .Invitation: - return 3 - case .Indicator: - return 2 - } +class StudySettings { + static let allAvailableParameters: [StudyParameterProtocol.Type] = [SecurityIndicator.self, Warning.self, Inviation.self] + static var parameters: [StudyParameterProtocol.Type] = [SecurityIndicator.self] { + didSet{ + securityIndicator = SecurityIndicator.load() as! SecurityIndicator + invitationsmode = Inviation.load() as! Inviation } } -} - -enum InvitationMode: Int { - case InviteMail - case PasswordEnc - case Censorship - case FreeText -} - - - - -class StudySettings { + static var studyMode = true + static var studyID: String { + return UserDefaults.standard.string(forKey: "studyID") ?? "" + } static var presentFirstQuestionaireMail = false - static let parameters = [StudyParamter.Indicator] - static let securityIndicator = SecurityIndicator.letter - - - - static let bitcoinStudyBody = - """ - Liebe Teilnehmerin, lieber Teilnehmer, - - Herzlichen Glückwunsch! Sie haben Letterbox erfolgreich installiert. - - Wenn Sie Fragen zur App oder Verschlüsselung haben, besuchen Sie doch unsere Hilfeseite: - \(faqURL) - - Dort finden Sie auch Videos zum Thema Ende-zu-Ende-Verschlüsselung. - Falls Sie Fragen haben oder uns Feedback geben möchten, freuen wir uns auf Ihre E-Mail! - - Die Studie umfasst drei Aufgaben und kann jederzeit abgebrochen werden. Für Fragen schreiben Sie uns bitte eine E-Mail und benutzen Sie bitte nach Möglichkeit die Letterbox dafür. - - In der ersten Aufgabe verfassen Sie bitte einen ersten Brief, indem Sie auf diese E-Mail antworten. Bitte teilen Sie uns Ihre Meinung mit. Ist etwas unklar geblieben? Was war neu für Sie? Was fanden Sie besonders interessant; was uninteressant? Hätten Sie sich noch weitere Informationen gewünscht? Sie können auch gerne Fragen zur Einführung stellen. - - Nach Beantwortung dieser E-Mail senden wir Ihnen zu einem späteren Zeitpunkt eine zweite E-Mail mit der nächsten kurzen Aufgabe zu. - - Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, - Ihr Letterbox-Team - PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. - """ + static var securityIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + static var invitationsmode: Inviation = Inviation.load() as! Inviation - static let welcomeBody = - """ - Liebe Nutzerin, lieber Nutzer von Letterbox, - - Ich bin Lette, der Letterbox-Mailbot. Wir freuen uns, dass du dich für unsere App entschieden hast. Magst du mir gleich auf die E-Mail antworten? Dann kannst du gleich erfahren, wie einfach es ist sichere Mails zu schreiben. Du und ich wissen dann das es bei dir auch klappt. - - Wir freuen uns auch jederzeit über Fragen oder einem Feedback von dir. Wir freuen uns auf deine Antwort! - - Vielen Dank und viele Grüße - Lette - - PS: Diese Nachricht wurde automatisch auf deinem Gerät bei der Installation von Letterbox erzeugt und ist nur hier gespeichert. - """ - - - public static var invitationEnabled: Bool { get { return true } } - static var freeTextInvitationTitle: String { - get { - switch self.invitationsmode { - case .FreeText, .InviteMail: - return NSLocalizedString("inviteContacts", comment: "Allows users to invite contacts without encryption key") - case .Censorship, .PasswordEnc: - return NSLocalizedString("inviteContacts.Censor", comment: "Allows users to invite contacts without encryption key") + + static func isStudyParameter(type: StudyParameterProtocol.Type) -> Bool { + for para in parameters { + if type == para { + return true } } + return false } - static let faqURL = "https://userpage.fu-berlin.de/letterbox/faq.html" - static let raffleURL = "" - static var studyID: String { - return UserDefaults.standard.string(forKey: "studyID") ?? "" - } - static var entrySurveyURL: String { - get { - return "https://userpage.fu-berlin.de/letterbox/entrysurvey.html?id=\(studyID)" - } - } + static var bitcoinMails: Bool { //do we recived a mail from bitcoin.de get { return UserDefaults.standard.bool(forKey: "bitcoin") @@ -158,48 +64,10 @@ class StudySettings { let keychain = Keychain(service: "Enzevalos/Study") keychain["bitcoin"] = "true" UserDefaults.standard.set(true, forKey: "bitcoin") -// Logger.queue.async(flags: .barrier) { Logger.log(bitcoinMail: true) -// } - } - } - } - - static var invitationsmode: InvitationMode { - get { - let value = UserDefaults.standard.integer(forKey: StudyParamter.Invitation.keyName) - if let mode = InvitationMode.init(rawValue: value) { - return mode - } - return InvitationMode.InviteMail - } - } - - - private static var studyParameters: [StudyParamter: Int] { - get { - let keychain = Keychain(service: "Enzevalos/Study") - var studyParamters = [StudyParamter: Int]() - for parameter in parameters { - var value: Int? - if let state = keychain[parameter.keyName], let num = Int(state) { - value = num - } else { - value = Int(arc4random_uniform(parameter.numberOfTreatments)) - if let value = value { - keychain[parameter.keyName] = String(value) - } - } - if let v = value { - UserDefaults.standard.set(v, forKey: parameter.keyName) - studyParamters[parameter] = v - } } - return studyParamters } } - - static func setupStudy() { if !studyMode { Logger.logging = false @@ -226,74 +94,9 @@ class StudySettings { keychain["bitcoin"] = "false" UserDefaults.standard.set(false, forKey: "bitcoin") } - let parameters = studyParameters - - -// Logger.queue.async(flags: .barrier) { Logger.log(setupStudy: parameters, alreadyRegistered: !presentFirstQuestionaireMail) -// } - - } - //create local mail for first interview here - - - - - static func firstMail() { - if !studyMode || !presentFirstQuestionaireMail { - return - } - let subject = "Herzlich Willkommen in Letterbox" - let body = StudySettings.welcomeBody - - mailToParticipat(subject: subject, body: body) - } - - static func givecards() { - if !studyMode || !presentFirstQuestionaireMail { - return - } - let subject = "Teilnahmeentschädigung: Verlosung von Amazon-Gutscheinen" - let body = - """ - Liebe Teilnehmerin, lieber Teilnehmer, - - unter den teilnehmenden Personen werden 20 Amazon-Gutscheine im Wert von jeweils 50 Euro verlost. - - Um an der Verlosung teilnehmen zu können, müssen Sie uns Ihren Namen und die postalische Adresse mitteilen. - Falls Sie einen Gutschein gewinnen, wird dieser Ihnen per Post zugesendet. Außerdem werden Ihr Name und Ihre Adresse für den Nachweis der ordnungsgemäßen Verwendung der Gelder gespeichert, andernfalls werden sie gelöscht. - - Ihre Name und Ihre Adresse werden nicht mit anderen erhobenen Daten verknüpft und getrennt von diesen gespeichert. - - Wenn Sie an der Verlosung teilnehmen möchten, melden Sie sich bitte auf folgenden Link an: - \(raffleURL) - - Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, - Ihr Letterbox-Team - - PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. - """ - - mailToParticipat(subject: subject, body: body) } - - private static func mailToParticipat(subject: String, body: String) { - let senderAdr = SUPPORT_MAIL_ADR - let sender = MCOAddress.init(displayName: "Letterbox-Team", mailbox: senderAdr) - var keyID: String? - if let addr = DataHandler.handler.findMailAddress(adr: senderAdr) { - if let pk = addr.primaryKey { - keyID = pk.keyID - } - } - let cryptoObject = CryptoObject(chiphertext: nil, plaintext: body, decryptedData: body.data(using: .utf8), sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: keyID, encType: CryptoScheme.PGP, signedAdrs: [senderAdr]) - - _ = DataHandler.handler.createMail(0, sender: sender, receivers: [], cc: [], time: Date(), received: false, subject: subject, body: body, flags: MCOMessageFlag.init(rawValue: 0), record: nil, autocrypt: nil, decryptedData: cryptoObject, folderPath: UserManager.backendInboxFolderPath, secretKey: nil) - } - - - public static func setupStudyKeys() { if studyMode || Logger.logging { setupStudyPublicKeys() diff --git a/enzevalos_iphone/UserData.swift b/enzevalos_iphone/UserData.swift index f34e39b0..ef442131 100644 --- a/enzevalos_iphone/UserData.swift +++ b/enzevalos_iphone/UserData.swift @@ -204,12 +204,12 @@ struct UserManager { return "" } - static func loadInvitationMode() -> InvitationMode { + static func loadInvitationMode() -> Inviation { let mode = UserDefaults.standard.integer(forKey: "Invitation.Mode") - if let invitationmode = InvitationMode(rawValue: mode) { + if let invitationmode = Inviation.init(rawValue: mode) { return invitationmode } - return InvitationMode.Censorship + return Inviation.defaultValue as! Inviation } static func resetUserValues() { diff --git a/enzevalos_iphone/study parameters/Invitation.swift b/enzevalos_iphone/study parameters/Invitation.swift new file mode 100644 index 00000000..61a1d0b0 --- /dev/null +++ b/enzevalos_iphone/study parameters/Invitation.swift @@ -0,0 +1,74 @@ +// +// Invitation.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum Inviation: Int, StudyParameterProtocol { + case InviteMail = 0, PasswordEnc = 1, Censorship = 2, FreeText = 3 + + static var defaultValue: StudyParameterProtocol { + get { + return Inviation.InviteMail + } + } + + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case Inviation.InviteMail.rawValue: + return Inviation.InviteMail + case Inviation.PasswordEnc.rawValue: + return Inviation.PasswordEnc + case Inviation.Censorship.rawValue: + return Inviation.Censorship + case Inviation.FreeText.rawValue: + return Inviation.FreeText + default: + return defaultValue + } + } + + static var name: String { + get { + return "invitation" + } + } + + static var keyName: String { + get { + return "invitation mode" + } + } + + static var numberOfTreatments: UInt32 { + get { + return 4 + } + } + + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + var freeTextInvitationTitle: String { + get { + switch self { + case .FreeText, .InviteMail: + return NSLocalizedString("inviteContacts", comment: "Allows users to invite contacts without encryption key") + case .Censorship, .PasswordEnc: + return NSLocalizedString("inviteContacts.Censor", comment: "Allows users to invite contacts without encryption key") + } + } + } + +} diff --git a/enzevalos_iphone/study parameters/SecurityIndicator.swift b/enzevalos_iphone/study parameters/SecurityIndicator.swift index 76b0a82a..1841eae6 100644 --- a/enzevalos_iphone/study parameters/SecurityIndicator.swift +++ b/enzevalos_iphone/study parameters/SecurityIndicator.swift @@ -12,29 +12,56 @@ import Foundation enum SecurityIndicator: Int, StudyParameterProtocol { case letter = 0, padlock = 1 - - static func startStudy() { + + static var defaultValue: StudyParameterProtocol { + get { + return SecurityIndicator.letter + } } - var name: String { + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case SecurityIndicator.letter.rawValue: + return SecurityIndicator.letter + case SecurityIndicator.padlock.rawValue: + return SecurityIndicator.padlock + default: + return defaultValue + } + } + + static var name: String { get { return "indicator" } } - var keyName: String { + static var keyName: String { get { return "indicator mode" } } - var numberOfTreatments: UInt32 { + static var numberOfTreatments: UInt32 { get { return 2 } } + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + + + func imageOfSecureIndicator(background: Bool = false, open: Bool = false) -> UIImage { switch self { case .letter: diff --git a/enzevalos_iphone/study parameters/StudyParameterProtocol.swift b/enzevalos_iphone/study parameters/StudyParameterProtocol.swift index b67e66ef..72e54d75 100644 --- a/enzevalos_iphone/study parameters/StudyParameterProtocol.swift +++ b/enzevalos_iphone/study parameters/StudyParameterProtocol.swift @@ -7,10 +7,67 @@ // import Foundation +import KeychainAccess protocol StudyParameterProtocol { - var name: String {get} - var keyName: String {get} - var numberOfTreatments: UInt32 {get} - static func startStudy() + static var name: String {get} + static var keyName: String {get} + static var numberOfTreatments: UInt32 {get} + static var defaultValue: StudyParameterProtocol {get} + static func findParameter(rawvalue: Int) -> StudyParameterProtocol + + var value: Int {get} + func startStudy() } + +extension StudyParameterProtocol { + + static func load() -> StudyParameterProtocol { + if let param = loadKeyChain() { + return param + } + return self.defaultValue + } + + static func reset() -> Bool { + UserDefaults.standard.removeObject(forKey: self.keyName) + let keychain = Keychain(service: "Enzevalos/Study") + do { + try keychain.remove(self.keyName) + } + catch { + print(error) + return false + } + + return true + } + + private static func loadUserDefault() -> StudyParameterProtocol? { + let value = UserDefaults.standard.integer(forKey: self.keyName) + return self.findParameter(rawvalue: value) + } + + private static func loadKeyChain() -> StudyParameterProtocol? { + guard StudySettings.isStudyParameter(type: self) else { + return nil + } + let keychain = Keychain(service: "Enzevalos/Study") + var value: Int? + if let state = keychain[self.keyName], let num = Int(state) { + value = num + } else { + value = Int(arc4random_uniform(self.numberOfTreatments)) + if let value = value { + keychain[self.keyName] = String(value) + } + } + if let v = value { + UserDefaults.standard.set(v, forKey: self.keyName) + return self.findParameter(rawvalue: v) + } + return nil + } +} + + diff --git a/enzevalos_iphone/study parameters/Warning.swift b/enzevalos_iphone/study parameters/Warning.swift new file mode 100644 index 00000000..5aa55e6a --- /dev/null +++ b/enzevalos_iphone/study parameters/Warning.swift @@ -0,0 +1,60 @@ +// +// Warning.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum Warning: Int, StudyParameterProtocol { + case hide = 0, show = 1 + + static var defaultValue: StudyParameterProtocol { + get { + return Warning.hide + } + } + + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case Warning.hide.rawValue: + return Warning.hide + case Warning.hide.rawValue: + return Warning.show + default: + return defaultValue + } + } + + static var name: String { + get { + return "warning" + } + } + + static var keyName: String { + get{ + return "warning" + } + } + + static var numberOfTreatments: UInt32 { + get { + return 2 + } + } + + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + +} diff --git a/enzevalos_iphoneTests/StudyTest.swift b/enzevalos_iphoneTests/StudyTest.swift new file mode 100644 index 00000000..fd501c0f --- /dev/null +++ b/enzevalos_iphoneTests/StudyTest.swift @@ -0,0 +1,105 @@ +// +// StudyTest.swift +// enzevalos_iphoneTests +// +// Created by Oliver Wiese on 29.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import XCTest + +@testable import enzevalos_iphone +class StudyTest: XCTestCase { + /* + Test von einzelnen Parametern + Test von mehreren Parametern kombiniert. + Testen von Erzeugung Aufrufe. + */ + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + + private func reset() { + for p in StudySettings.parameters { + _ = p.reset() + } + } + func testSecurityIndicator(){ + testOneParameter(parameter: SecurityIndicator.self) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + testDistribution(parameter: SecurityIndicator.self) + } + + func testOneParameter(parameter: StudyParameterProtocol.Type) { + StudySettings.parameters = [parameter] + + for para in StudySettings.allAvailableParameters { + if para.self != parameter.self { + XCTAssertEqual(para.defaultValue.value, para.load().value) + if para == Inviation.self { + XCTAssertEqual(para.defaultValue.value, StudySettings.invitationsmode.value) + } + } + } + } + + func testSecurityIndicatorAndWarning() { + testMultipleIndicators(parameters: [SecurityIndicator.self, Warning.self]) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + + } + + func testSecurityIndicatorAndInvitation() { + testMultipleIndicators(parameters: [SecurityIndicator.self, Inviation.self]) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + let invMode: Inviation = Inviation.load() as! Inviation + XCTAssertEqual(invMode.value, StudySettings.invitationsmode.value) + } + + func testMultipleIndicators(parameters: [StudyParameterProtocol.Type]) { + StudySettings.parameters = parameters + for para in StudySettings.allAvailableParameters { + var isPara = false + for x in parameters { + if para.keyName == x.keyName { + isPara = true + } + } + if !isPara { + XCTAssertEqual(para.defaultValue.value, para.load().value) + if para == Inviation.self { + XCTAssertEqual(para.defaultValue.value, StudySettings.invitationsmode.value) + } + } + } + } + + func testDistribution(parameter: StudyParameterProtocol.Type) { + var values: [Int] = Array(repeating: 0, count: Int(parameter.numberOfTreatments)) + let n = 100 + let mean = Double(n) / Double(parameter.numberOfTreatments) + let threshold = mean * 0.1 + + self.reset() + for _ in 0...n { + self.testOneParameter(parameter: parameter) + let v = parameter.load().value + values[v] = values[v] + 1 + self.reset() + } + for v in values { + XCTAssertLessThan(v, Int(mean + threshold)) + XCTAssertGreaterThan(v, Int(mean - threshold)) + } + } +} -- GitLab