Web Inspector: Network: add button to show system certificate dialog
[WebKit-https.git] / Source / WebKit / UIProcess / mac / RemoteWebInspectorProxyMac.mm
1 /*
2  * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "RemoteWebInspectorProxy.h"
28
29 #if PLATFORM(MAC) && WK_API_ENABLED
30
31 #import "RemoteWebInspectorProxyMessages.h"
32 #import "RemoteWebInspectorUIMessages.h"
33 #import "WKFrameInfo.h"
34 #import "WKInspectorViewController.h"
35 #import "WKNavigationAction.h"
36 #import "WKNavigationDelegate.h"
37 #import "WKWebViewInternal.h"
38 #import "WebInspectorProxy.h"
39 #import "WebPageGroup.h"
40 #import "WebPageProxy.h"
41 #import <SecurityInterface/SFCertificatePanel.h>
42 #import <SecurityInterface/SFCertificateView.h>
43 #import <WebCore/CertificateInfo.h>
44 #import <wtf/text/Base64.h>
45
46 @interface WKRemoteWebInspectorProxyObjCAdapter : NSObject <WKInspectorViewControllerDelegate> {
47     WebKit::RemoteWebInspectorProxy* _inspectorProxy;
48 }
49 - (instancetype)initWithRemoteWebInspectorProxy:(WebKit::RemoteWebInspectorProxy*)inspectorProxy;
50 @end
51
52 @implementation WKRemoteWebInspectorProxyObjCAdapter
53
54 - (instancetype)initWithRemoteWebInspectorProxy:(WebKit::RemoteWebInspectorProxy*)inspectorProxy
55 {
56     if (!(self = [super init]))
57         return nil;
58
59     _inspectorProxy = inspectorProxy;
60
61     return self;
62 }
63
64 - (void)inspectorViewControllerInspectorDidCrash:(WKInspectorViewController *)inspectorViewController
65 {
66     _inspectorProxy->closeFromCrash();
67 }
68
69 - (BOOL)inspectorViewControllerInspectorIsUnderTest:(WKInspectorViewController *)inspectorViewController
70 {
71     return _inspectorProxy->isUnderTest();
72 }
73
74 @end
75
76 namespace WebKit {
77 using namespace WebCore;
78
79 WKWebView *RemoteWebInspectorProxy::webView() const
80 {
81     return m_inspectorView.get().webView;
82 }
83
84 WebPageProxy* RemoteWebInspectorProxy::platformCreateFrontendPageAndWindow()
85 {
86     m_objCAdapter = adoptNS([[WKRemoteWebInspectorProxyObjCAdapter alloc] initWithRemoteWebInspectorProxy:this]);
87
88     m_inspectorView = adoptNS([[WKInspectorViewController alloc] initWithInspectedPage:nil]);
89     [m_inspectorView.get() setDelegate:m_objCAdapter.get()];
90
91     m_window = WebInspectorProxy::createFrontendWindow(NSZeroRect);
92     [m_window setFrameAutosaveName:@"WKRemoteWebInspectorWindowFrame"];
93
94     NSView *contentView = m_window.get().contentView;
95     [webView() setFrame:contentView.bounds];
96     [contentView addSubview:webView()];
97
98     return webView()->_page.get();
99 }
100
101 void RemoteWebInspectorProxy::platformCloseFrontendPageAndWindow()
102 {
103     if (m_window) {
104         [m_window setDelegate:nil];
105         [m_window close];
106         m_window = nil;
107     }
108
109     if (m_inspectorView) {
110         [m_inspectorView.get() setDelegate:nil];
111         m_inspectorView = nil;
112     }
113
114     if (m_objCAdapter)
115         m_objCAdapter = nil;
116 }
117
118 void RemoteWebInspectorProxy::platformBringToFront()
119 {
120     [m_window makeKeyAndOrderFront:nil];
121     [m_window makeFirstResponder:webView()];
122 }
123
124 void RemoteWebInspectorProxy::platformSave(const String& suggestedURL, const String& content, bool base64Encoded, bool forceSaveDialog)
125 {
126     // FIXME: Share with WebInspectorProxyMac.
127
128     ASSERT(!suggestedURL.isEmpty());
129     
130     NSURL *platformURL = m_suggestedToActualURLMap.get(suggestedURL).get();
131     if (!platformURL) {
132         platformURL = [NSURL URLWithString:suggestedURL];
133         // The user must confirm new filenames before we can save to them.
134         forceSaveDialog = true;
135     }
136     
137     ASSERT(platformURL);
138     if (!platformURL)
139         return;
140
141     // Necessary for the block below.
142     String suggestedURLCopy = suggestedURL;
143     String contentCopy = content;
144
145     auto saveToURL = ^(NSURL *actualURL) {
146         ASSERT(actualURL);
147
148         m_suggestedToActualURLMap.set(suggestedURLCopy, actualURL);
149
150         if (base64Encoded) {
151             Vector<char> out;
152             if (!base64Decode(contentCopy, out, Base64ValidatePadding))
153                 return;
154             RetainPtr<NSData> dataContent = adoptNS([[NSData alloc] initWithBytes:out.data() length:out.size()]);
155             [dataContent writeToURL:actualURL atomically:YES];
156         } else
157             [contentCopy writeToURL:actualURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
158
159         m_inspectorPage->process().send(Messages::RemoteWebInspectorUI::DidSave([actualURL absoluteString]), m_inspectorPage->pageID());
160     };
161
162     if (!forceSaveDialog) {
163         saveToURL(platformURL);
164         return;
165     }
166
167     NSSavePanel *panel = [NSSavePanel savePanel];
168     panel.nameFieldStringValue = platformURL.lastPathComponent;
169
170     // If we have a file URL we've already saved this file to a path and
171     // can provide a good directory to show. Otherwise, use the system's
172     // default behavior for the initial directory to show in the dialog.
173     if (platformURL.isFileURL)
174         panel.directoryURL = [platformURL URLByDeletingLastPathComponent];
175
176     auto completionHandler = ^(NSInteger result) {
177         if (result == NSModalResponseCancel)
178             return;
179         ASSERT(result == NSModalResponseOK);
180         saveToURL(panel.URL);
181     };
182
183     if (m_window)
184         [panel beginSheetModalForWindow:m_window.get() completionHandler:completionHandler];
185     else
186         completionHandler([panel runModal]);
187 }
188
189 void RemoteWebInspectorProxy::platformAppend(const String& suggestedURL, const String& content)
190 {
191     // FIXME: Share with WebInspectorProxyMac.
192
193     ASSERT(!suggestedURL.isEmpty());
194     
195     RetainPtr<NSURL> actualURL = m_suggestedToActualURLMap.get(suggestedURL);
196     // Do not append unless the user has already confirmed this filename in save().
197     if (!actualURL)
198         return;
199
200     NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:actualURL.get() error:NULL];
201     [handle seekToEndOfFile];
202     [handle writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
203     [handle closeFile];
204
205     WebPageProxy* inspectorPage = webView()->_page.get();
206     inspectorPage->process().send(Messages::RemoteWebInspectorUI::DidAppend([actualURL absoluteString]), inspectorPage->pageID());
207 }
208
209 void RemoteWebInspectorProxy::platformStartWindowDrag()
210 {
211     webView()->_page->startWindowDrag();
212 }
213
214 void RemoteWebInspectorProxy::platformOpenInNewTab(const String& url)
215 {
216     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
217 }
218
219 void RemoteWebInspectorProxy::platformShowCertificate(const CertificateInfo& certificateInfo)
220 {
221     ASSERT(!certificateInfo.isEmpty());
222
223     RetainPtr<SFCertificatePanel> certificatePanel = adoptNS([[SFCertificatePanel alloc] init]);
224
225     ASSERT(m_window);
226 #if HAVE(SEC_TRUST_SERIALIZATION)
227     [certificatePanel beginSheetForWindow:m_window.get() modalDelegate:nil didEndSelector:NULL contextInfo:nullptr trust:certificateInfo.trust() showGroup:YES];
228 #else
229     [certificatePanel beginSheetForWindow:m_window.get() modalDelegate:nil didEndSelector:NULL contextInfo:nullptr certificates:(NSArray *)certificateInfo.certificateChain() showGroup:YES];
230 #endif
231
232     // This must be called after the trust panel has been displayed, because the certificateView doesn't exist beforehand.
233     SFCertificateView *certificateView = [certificatePanel certificateView];
234     [certificateView setDisplayTrust:YES];
235     [certificateView setEditableTrust:NO];
236     [certificateView setDisplayDetails:YES];
237     [certificateView setDetailsDisclosed:YES];
238 }
239
240 } // namespace WebKit
241
242 #endif