From fe4fe5ceffc481b14a6353bd268164d781db48f9 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 24 Sep 2023 19:01:01 -0400 Subject: [PATCH] MacPDF: Support opening password-protected PDFs This is a bit janky for several reasons: * `initialize` is now no longer called on a bg thread * sheet UI is janky both visually and from an implementation PoV But hey, it works for now. --- Meta/Lagom/Contrib/MacPDF/LagomPDFDocument.mm | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/Meta/Lagom/Contrib/MacPDF/LagomPDFDocument.mm b/Meta/Lagom/Contrib/MacPDF/LagomPDFDocument.mm index 12ba0432aa..e90c5cf351 100644 --- a/Meta/Lagom/Contrib/MacPDF/LagomPDFDocument.mm +++ b/Meta/Lagom/Contrib/MacPDF/LagomPDFDocument.mm @@ -20,13 +20,57 @@ @implementation LagomPDFDocument +- (void)promptForPassword:(NSWindow*)window +{ + auto alert = [[NSAlert alloc] init]; + alert.messageText = @"Password"; + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + + auto textField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)]; + alert.accessoryView = textField; + alert.window.initialFirstResponder = textField; + + // Without this, the window's not visible yet and the sheet can't attach to it. + // FIXME: This causes the window to change position after restoring, so this isn't quite right either. + // Probably nicest to put the password prompt right in the window, instead of in a sheet. + [window orderFront:self]; + + [alert beginSheetModalForWindow:window + completionHandler:^(NSModalResponse response) { + if (response == NSAlertFirstButtonReturn) { + NSString* password = [textField stringValue]; + StringView password_view { [password UTF8String], strlen([password UTF8String]) }; + if (!self->_doc->security_handler()->try_provide_user_password(password_view)) { + warnln("invalid password '{}'", password); + [self performSelector:@selector(promptForPassword:) withObject:window]; + return; + } + [self initializePDF]; + } else if (response == NSAlertSecondButtonReturn) { + [self close]; + } + }]; +} + - (PDF::PDFErrorOr>)load:(NSData*)data { + // Runs on background thread, can't interact with UI. auto document = TRY(PDF::Document::create(ReadonlyBytes { [data bytes], [data length] })); - TRY(document->initialize()); return document; } +- (void)initializePDF +{ + // FIXME: on background thread? + if (auto err = _doc->initialize(); err.is_error()) { + // FIXME: show error? + NSLog(@"failed to load 2: %@", @(err.error().message().characters())); + } else { + [_pdfView setDocument:_doc->make_weak_ptr()]; + } +} + - (NSString*)windowNibName { // Override to return the nib file name of the document. @@ -39,7 +83,11 @@ [super windowControllerDidLoadNib:aController]; if (_doc) { - [_pdfView setDocument:_doc->make_weak_ptr()]; + if (auto handler = _doc->security_handler(); handler && !handler->has_user_password()) { + [self promptForPassword:aController.window]; + return; + } + [self initializePDF]; } } @@ -71,8 +119,6 @@ if (auto doc_or = [self load:data]; !doc_or.is_error()) { _doc = doc_or.value(); _data = data; - // [self pageChanged]; - return YES; } else { NSLog(@"failed to load: %@", @(doc_or.error().message().characters()));