Skip to content

Commit

Permalink
Merge branch 'add/magic-link-auth' into lantean/1605-invalid-link-alert
Browse files Browse the repository at this point in the history
  • Loading branch information
jleandroperez committed Jul 1, 2024
2 parents 1a2c087 + 6152f21 commit 86af35a
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 81 deletions.
16 changes: 16 additions & 0 deletions Simplenote.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@
BA4499B325ED8AB0000C563E /* NoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4499B225ED8AB0000C563E /* NoticeView.swift */; };
BA4499BC25ED95D0000C563E /* Notice.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4499BB25ED95D0000C563E /* Notice.swift */; };
BA4499C525ED95E5000C563E /* NoticeAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4499C425ED95E5000C563E /* NoticeAction.swift */; };
BA4A01902C1CCEC100EEE567 /* RecoveryArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4A018F2C1CCEC100EEE567 /* RecoveryArchiver.swift */; };
BA4C6CFC264C744300B723A7 /* SeparatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C6CFB264C744300B723A7 /* SeparatorsView.swift */; };
BA5249FD26DF0BC600DAC945 /* WidgetWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA5249FC26DF0BC600DAC945 /* WidgetWarningView.swift */; };
BA524A0226DF1AE800DAC945 /* WidgetsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA524A0126DF1AE800DAC945 /* WidgetsState.swift */; };
Expand All @@ -489,6 +490,7 @@
BA6DA19226DB5F1B000464C8 /* URLComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA6DA19026DB5F1B000464C8 /* URLComponents.swift */; };
BA7071E526BB68A300D5DFF0 /* ListWidgetIntent.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = BA7071E426BB68A300D5DFF0 /* ListWidgetIntent.intentdefinition */; };
BA7071E626BB68A300D5DFF0 /* ListWidgetIntent.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = BA7071E426BB68A300D5DFF0 /* ListWidgetIntent.intentdefinition */; };
BA7240222C1BA1210088EC11 /* RecoveryUnarchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7240212C1BA1210088EC11 /* RecoveryUnarchiver.swift */; };
BA75D8A326C084E900883FFA /* Text+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA75D87D26C0843600883FFA /* Text+Simplenote.swift */; };
BA75D8AE26C0862E00883FFA /* View+Simplenote.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA75D8AD26C0862E00883FFA /* View+Simplenote.swift */; };
BA75D8BA26C0865C00883FFA /* Filling.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA75D8B926C0865C00883FFA /* Filling.swift */; };
Expand Down Expand Up @@ -1174,6 +1176,7 @@
BA4499B225ED8AB0000C563E /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = "<group>"; };
BA4499BB25ED95D0000C563E /* Notice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notice.swift; sourceTree = "<group>"; };
BA4499C425ED95E5000C563E /* NoticeAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeAction.swift; sourceTree = "<group>"; };
BA4A018F2C1CCEC100EEE567 /* RecoveryArchiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryArchiver.swift; sourceTree = "<group>"; };
BA4C6CFB264C744300B723A7 /* SeparatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorsView.swift; sourceTree = "<group>"; };
BA5249FC26DF0BC600DAC945 /* WidgetWarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetWarningView.swift; sourceTree = "<group>"; };
BA524A0126DF1AE800DAC945 /* WidgetsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetsState.swift; sourceTree = "<group>"; };
Expand All @@ -1193,6 +1196,7 @@
BA6D7B8A2BE588F0006AE368 /* IntentsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentsError.swift; sourceTree = "<group>"; };
BA6DA19026DB5F1B000464C8 /* URLComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponents.swift; sourceTree = "<group>"; };
BA7071E426BB68A300D5DFF0 /* ListWidgetIntent.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = ListWidgetIntent.intentdefinition; sourceTree = "<group>"; };
BA7240212C1BA1210088EC11 /* RecoveryUnarchiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryUnarchiver.swift; sourceTree = "<group>"; };
BA75D87D26C0843600883FFA /* Text+Simplenote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Simplenote.swift"; sourceTree = "<group>"; };
BA75D8AD26C0862E00883FFA /* View+Simplenote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Simplenote.swift"; sourceTree = "<group>"; };
BA75D8B926C0865C00883FFA /* Filling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filling.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2244,6 +2248,7 @@
BA3856CC2681715700F388CC /* CoreDataManager.swift */,
BA9B59012685549F00DAD1ED /* StorageSettings.swift */,
BA32A90E26B7469F00727247 /* WidgetError.swift */,
BA7240212C1BA1210088EC11 /* RecoveryUnarchiver.swift */,
);
name = Tools;
sourceTree = "<group>";
Expand Down Expand Up @@ -2421,6 +2426,14 @@
name = Notices;
sourceTree = "<group>";
};
BA4A018E2C1CCEB300EEE567 /* Tools */ = {
isa = PBXGroup;
children = (
BA4A018F2C1CCEC100EEE567 /* RecoveryArchiver.swift */,
);
path = Tools;
sourceTree = "<group>";
};
BA57692A269D2103008B510E /* Remotes */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2469,6 +2482,7 @@
BAB5762526703C8200B0C56F /* SimplenoteIntents */ = {
isa = PBXGroup;
children = (
BA4A018E2C1CCEB300EEE567 /* Tools */,
BA34B04F2BEAEF4800580E15 /* SimplenoteIntentsRelease.entitlements */,
092FD78026D7BB72006BE8E2 /* Supporting Files */,
BAB5762626703C8200B0C56F /* IntentHandler.swift */,
Expand Down Expand Up @@ -3467,6 +3481,7 @@
B543C7E323CF76EA00003A80 /* NotesListFilter.swift in Sources */,
46A3C96717DFA81A002865AE /* NSManagedObjectContext+CoreDataExtensions.m in Sources */,
A6C0DFA725C0992D00B9BE39 /* NoteScrollPositionCache.swift in Sources */,
BA7240222C1BA1210088EC11 /* RecoveryUnarchiver.swift in Sources */,
B59314D81A486B3800B651ED /* SPConstants.m in Sources */,
375D24B421E01131007AB25A /* escape.c in Sources */,
B50F47A61D1D791B00822748 /* NSURL+Extensions.swift in Sources */,
Expand Down Expand Up @@ -3856,6 +3871,7 @@
BA86622426B3AE4A00466746 /* ExtensionResultsController.swift in Sources */,
BABFFF2426CF9094003A4C25 /* WidgetDefaults.swift in Sources */,
BA289B762BE45BBB000E6794 /* OpenNoteIntentHandler.swift in Sources */,
BA4A01902C1CCEC100EEE567 /* RecoveryArchiver.swift in Sources */,
BAF8D46E26AE118800CA9383 /* SPCredentials.swift in Sources */,
BAF8D5C526AE254100CA9383 /* Simplenote.xcdatamodeld in Sources */,
BAB6C04426BA49F3007495C4 /* ContentSlice.swift in Sources */,
Expand Down
31 changes: 31 additions & 0 deletions Simplenote/Classes/FileManager+Simplenote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,35 @@ extension FileManager {
var sharedContainerURL: URL {
containerURL(forSecurityApplicationGroupIdentifier: SimplenoteConstants.sharedGroupDomain)!
}

func recoveryDirectoryURL() -> URL? {
let dir = sharedContainerURL.appendingPathComponent(Constants.recoveryDir)

do {
try createDirectoryIfNeeded(at: dir)
} catch {
NSLog("Could not create recovery directory because: $@", error.localizedDescription)
return nil
}

return dir
}

func createDirectoryIfNeeded(at url: URL, withIntermediateDirectories: Bool = true) throws {
if directoryExistsAtURL(url) {
return
}

try createDirectory(at: url, withIntermediateDirectories: true)
}

func directoryExistsAtURL(_ url: URL) -> Bool {
var isDir: ObjCBool = false
let exists = self.fileExists(atPath: url.path, isDirectory: &isDir)
return exists && isDir.boolValue
}
}

private struct Constants {
static let recoveryDir = "Recovery"
}
19 changes: 12 additions & 7 deletions Simplenote/Classes/MagicLinkAuthenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ extension NSNotification.Name {
struct MagicLinkAuthenticator {
let authenticator: SPAuthenticator

func handle(url: URL) {
guard url.host == Constants.host else {
return
func handle(url: URL) -> Bool {
guard AllowedHosts.all.contains(url.host) else {
return false
}

guard let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems else {
return
return false
}

if attemptLoginWithToken(queryItems: queryItems) {
return
return true
}

attemptLoginWithAuthCode(queryItems: queryItems)
return attemptLoginWithAuthCode(queryItems: queryItems)
}
}

Expand Down Expand Up @@ -102,8 +102,13 @@ private extension Array where Element == URLQueryItem {

// MARK: - Constants
//
private struct AllowedHosts {
static let hostForSimplenoteSchema = "login"
static let hostForUniversalLinks = URL(string: SPCredentials.defaultEngineURL)!.host
static let all = [hostForSimplenoteSchema, hostForUniversalLinks]
}

private struct Constants {
static let host = "login"
static let emailField = "email"
static let tokenField = "token"
static let authKeyField = "auth_key"
Expand Down
51 changes: 51 additions & 0 deletions Simplenote/RecoveryUnarchiver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation
import UniformTypeIdentifiers
import CoreData

public class RecoveryUnarchiver {
private let fileManager: FileManager
private let simperium: Simperium

public init(fileManager: FileManager = .default, simperium: Simperium) {
self.fileManager = fileManager
self.simperium = simperium
}

// MARK: Restore
//
public func insertNotesFromRecoveryFilesIfNeeded() {
guard let recoveryURL = fileManager.recoveryDirectoryURL(),
let recoveryFiles = try? fileManager.contentsOfDirectory(at: recoveryURL, includingPropertiesForKeys: nil),
!recoveryFiles.isEmpty else {
return
}

recoveryFiles.forEach { url in
insertNote(from: url)
try? fileManager.removeItem(at: url)
}
}

private func insertNote(from url: URL) {
guard let data = fileManager.contents(atPath: url.path),
let recoveredContent = String(data: data, encoding: .utf8),
let note = simperium.notesBucket.insertNewObject() as? Note else {
return
}

var content = Constants.recoveredContentHeader
content += "\n\n"
content += recoveredContent
note.content = content

note.modificationDate = Date()
note.creationDate = Date()
note.markdown = UserDefaults.standard.bool(forKey: .markdown)

simperium.save()
}
}

private struct Constants {
static let recoveredContentHeader = NSLocalizedString("Recovered Note Cotent - ", comment: "Header to put on any files that need to be recovered")
}
23 changes: 21 additions & 2 deletions Simplenote/SPAppDelegate+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,20 @@ private extension SPAppDelegate {
// MARK: - Magic Link authentication
//
extension SPAppDelegate {
@objc
func performMagicLinkAuthentication(with url: URL) {

@objc @discardableResult
func performMagicLinkAuthentication(with url: URL) -> Bool {
MagicLinkAuthenticator(authenticator: simperium.authenticator).handle(url: url)
}

@objc(performMagicLinkAuthenticationWithUserActivity:)
func performMagicLinkAuthentication(with userActivity: NSUserActivity) -> Bool {
guard let url = userActivity.webpageURL else {
return false
}

return performMagicLinkAuthentication(with: url)
}
}

// MARK: - Scroll position cache
Expand Down Expand Up @@ -557,3 +567,12 @@ extension SPAppDelegate {
UserDefaults.standard.set(true, forKey: .hasMigratedSustainerPreferences)
}
}

// MARK: - Content Recovery
//
extension SPAppDelegate {
@objc
func attemptContentRecoveryIfNeeded() {
RecoveryUnarchiver(simperium: simperium).insertNotesFromRecoveryFilesIfNeeded()
}
}
5 changes: 5 additions & 0 deletions Simplenote/SPAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ - (void)applicationDidBecomeActive:(UIApplication *)application
{
[SPTracker trackApplicationOpened];
[self syncWidgetDefaults];
[self attemptContentRecoveryIfNeeded];
}

- (void)applicationDidEnterBackground:(UIApplication *)application
Expand All @@ -199,6 +200,10 @@ - (void)applicationWillEnterForeground:(UIApplication *)application

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
if ([self performMagicLinkAuthenticationWithUserActivity:userActivity]) {
return YES;
}

return [[ShortcutsHandler shared] handleUserActivity:userActivity];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<key>INIntentDefinitionSystemVersion</key>
<string>23E214</string>
<key>INIntentDefinitionToolsBuildVersion</key>
<string>15E204a</string>
<string>15F31d</string>
<key>INIntentDefinitionToolsVersion</key>
<string>15.3</string>
<string>15.4</string>
<key>INIntents</key>
<array>
<dict>
Expand Down Expand Up @@ -308,10 +308,33 @@
<true/>
</dict>
<dict>
<key>INIntentResponseCodeFormatString</key>
<string>${failureReason}</string>
<key>INIntentResponseCodeFormatStringID</key>
<string>Lyqq4K</string>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
<key>INIntentResponseLastParameterTag</key>
<integer>1</integer>
<key>INIntentResponseParameters</key>
<array>
<dict>
<key>INIntentResponseParameterDisplayName</key>
<string>Failure Reason</string>
<key>INIntentResponseParameterDisplayNameID</key>
<string>PueDbo</string>
<key>INIntentResponseParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentResponseParameterName</key>
<string>failureReason</string>
<key>INIntentResponseParameterTag</key>
<integer>1</integer>
<key>INIntentResponseParameterType</key>
<string>String</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Append To Note</string>
Expand Down Expand Up @@ -409,10 +432,33 @@
<true/>
</dict>
<dict>
<key>INIntentResponseCodeFormatString</key>
<string>${failureReason}</string>
<key>INIntentResponseCodeFormatStringID</key>
<string>d67xB8</string>
<key>INIntentResponseCodeName</key>
<string>failure</string>
</dict>
</array>
<key>INIntentResponseLastParameterTag</key>
<integer>1</integer>
<key>INIntentResponseParameters</key>
<array>
<dict>
<key>INIntentResponseParameterDisplayName</key>
<string>Failure Reason</string>
<key>INIntentResponseParameterDisplayNameID</key>
<string>2w6Mce</string>
<key>INIntentResponseParameterDisplayPriority</key>
<integer>1</integer>
<key>INIntentResponseParameterName</key>
<string>failureReason</string>
<key>INIntentResponseParameterTag</key>
<integer>1</integer>
<key>INIntentResponseParameterType</key>
<string>String</string>
</dict>
</array>
</dict>
<key>INIntentTitle</key>
<string>Create New Note With Content</string>
Expand Down Expand Up @@ -660,26 +706,6 @@
<key>INIntentParameterPromptDialogType</key>
<string>Primary</string>
</dict>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogFormatString</key>
<string>There are ${count} options matching ‘${note}’.</string>
<key>INIntentParameterPromptDialogFormatStringID</key>
<string>VBtgac</string>
<key>INIntentParameterPromptDialogType</key>
<string>DisambiguationIntroduction</string>
</dict>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogFormatString</key>
<string>Just to confirm, you wanted ‘${note}’?</string>
<key>INIntentParameterPromptDialogFormatStringID</key>
<string>MdiZid</string>
<key>INIntentParameterPromptDialogType</key>
<string>Confirmation</string>
</dict>
</array>
<key>INIntentParameterSupportsDynamicEnumeration</key>
<true/>
Expand Down Expand Up @@ -797,26 +823,6 @@
<key>INIntentParameterPromptDialogType</key>
<string>Primary</string>
</dict>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogFormatString</key>
<string>There are ${count} options matching ‘${tag}’.</string>
<key>INIntentParameterPromptDialogFormatStringID</key>
<string>U4ce2H</string>
<key>INIntentParameterPromptDialogType</key>
<string>DisambiguationIntroduction</string>
</dict>
<dict>
<key>INIntentParameterPromptDialogCustom</key>
<true/>
<key>INIntentParameterPromptDialogFormatString</key>
<string>Just to confirm, you wanted ‘${tag}’?</string>
<key>INIntentParameterPromptDialogFormatStringID</key>
<string>qYKqOP</string>
<key>INIntentParameterPromptDialogType</key>
<string>Confirmation</string>
</dict>
</array>
<key>INIntentParameterSupportsDynamicEnumeration</key>
<true/>
Expand Down
Loading

0 comments on commit 86af35a

Please sign in to comment.