Merge branch 'master' into Permissions

This commit is contained in:
addison 2021-01-12 18:51:36 -05:00
commit c41fbac467
11 changed files with 86 additions and 30 deletions

2
jslib

@ -1 +1 @@
Subproject commit f9042408f44b299a7cdd1286490b70f5fd2db999
Subproject commit cea09a22e533ef3598bb497ba0503c2fcd5b2dc1

View File

@ -606,6 +606,9 @@
"message": "WARNING",
"description": "WARNING (should stay in capitalized letters if the language permits)"
},
"confirmVaultExport": {
"message": "Confirm Vault Export"
},
"exportWarningDesc": {
"message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it."
},
@ -1431,5 +1434,8 @@
},
"personalOwnershipSubmitError": {
"message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections."
},
"personalOwnershipPolicyInEffect": {
"message": "An organization policy is affecting your ownership options."
}
}

View File

@ -115,9 +115,7 @@ export class NativeMessagingBackground {
error = chrome.runtime.lastError.message;
}
if (error === 'Specified native messaging host not found.' ||
error === 'Access to the specified native messaging host is forbidden.' ||
error === 'An unexpected error occurred') {
if (error != null) {
this.messagingService.send('showDialog', {
text: this.i18nService.t('desktopIntegrationDisabledDesc'),
title: this.i18nService.t('desktopIntegrationDisabledTitle'),
@ -145,7 +143,7 @@ export class NativeMessagingBackground {
message.timestamp = Date.now();
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
this.port.postMessage({appId: this.appId, message: encrypted});
this.postMessage({appId: this.appId, message: encrypted});
}
getResponse(): Promise<any> {
@ -154,6 +152,27 @@ export class NativeMessagingBackground {
});
}
private postMessage(message: any) {
// Wrap in try-catch to when the port disconnected without triggering `onDisconnect`.
try {
this.port.postMessage(message);
} catch (e) {
// tslint:disable-next-line
console.error("NativeMessaging port disconnected, disconnecting.");
this.sharedSecret = null;
this.privateKey = null;
this.connected = false;
this.messagingService.send('showDialog', {
text: this.i18nService.t('nativeMessagingInvalidEncryptionDesc'),
title: this.i18nService.t('nativeMessagingInvalidEncryptionTitle'),
confirmText: this.i18nService.t('ok'),
type: 'error',
});
}
}
private async onMessage(rawMessage: any) {
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
@ -231,7 +250,7 @@ export class NativeMessagingBackground {
message.timestamp = Date.now();
this.port.postMessage({appId: this.appId, message: message});
this.postMessage({appId: this.appId, message: message});
}
private async showFingerprintDialog() {

View File

@ -25,12 +25,20 @@ export class SafariApp {
return new Promise((resolve) => {
const now = new Date();
const messageId = now.getTime().toString() + '_' + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
(window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({
id: messageId,
command: command,
data: data,
responseData: null,
}));
if (typeof safari === typeof undefined) {
(window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({
id: messageId,
command: command,
data: data,
responseData: null,
}));
} else {
safari.extension.dispatchMessage('bitwarden', {
command: command,
data: data,
responseData: null,
});
}
if (resolveNow) {
resolve();
} else {

View File

@ -3,6 +3,15 @@ window.addEventListener('message', (event) => {
return;
if (event.data.command && (event.data.command === 'authResult')) {
if (typeof chrome === typeof undefined) {
safari.extension.dispatchMessage('bitwarden', {
command: event.data.command,
code: event.data.code,
state: event.data.state,
referrer: event.source.location.hostname,
});
return;
}
chrome.runtime.sendMessage({
command: event.data.command,
code: event.data.code,

View File

@ -41,11 +41,11 @@ export class SsoComponent extends BaseSsoComponent {
this.redirectUri = url + '/sso-connector.html';
this.clientId = 'browser';
super.onSuccessfulLogin = () => {
super.onSuccessfulLogin = async () => {
await syncService.fullSync(true);
BrowserApi.reloadOpenWindows();
const thisWindow = window.open('', '_self');
thisWindow.close();
return syncService.fullSync(true);
};
}
}

View File

@ -57,7 +57,7 @@ export class ActionButtonsComponent {
}
async copy(cipher: CipherView, value: string, typeI18nKey: string, aType: string) {
if (value == null || !this.displayTotpCopyButton(cipher)) {
if (value == null || aType === 'TOTP' && !this.displayTotpCopyButton(cipher)) {
return;
} else if (value === cipher.login.totp) {
value = await this.totpService.getCode(value);

View File

@ -41,13 +41,6 @@
</div>
<div class="box-footer">
<p>{{'exportMasterPassword' | i18n}}</p>
<strong>{{'warning' | i18n}}</strong>:
<span *ngIf="!encryptedFormat">
{{'exportWarningDesc' | i18n}}
</span>
<span *ngIf="encryptedFormat">
{{'encExportWarningDesc' | i18n}}
</span>
</div>
</div>
</content>

View File

@ -14,6 +14,9 @@
</div>
</header>
<content *ngIf="cipher">
<app-callout type="info" *ngIf="allowOwnershipOptions() && !allowPersonal">
{{'personalOwnershipPolicyInEffect' | i18n}}
</app-callout>
<div class="box">
<div class="box-header">
{{'itemInformation' | i18n}}

View File

@ -16,14 +16,10 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
if initedWebView {
return
}
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
initedWebView = true
let parentHeight = SafariExtensionViewController.shared.preferredContentSize.height
let parentWidth = SafariExtensionViewController.shared.preferredContentSize.width
let webViewConfig = WKWebViewConfiguration()
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("app/popup/index.html")
let url = URL(string: "\(html.absoluteString)?appVersion=\(version!)")
webViewConfig.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
webViewConfig.preferences.setValue(true, forKey: "developerExtrasEnabled")
webViewConfig.userContentController.add(self, name: "bitwardenApp")
@ -31,12 +27,26 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
configuration: webViewConfig)
webView.navigationDelegate = self
webView.allowsLinkPreview = false
webView.loadFileURL(url!, allowingReadAccessTo: bundleURL)
navigateWebView("app/popup/index.html")
webView.alphaValue = 0.0
webView.uiDelegate = self
view.addSubview(webView)
}
func navigateWebView(_ relativeUrl: String){
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
let bundleUrl = Bundle.main.resourceURL!.absoluteURL
if var urlComponents = URLComponents(string: bundleUrl.absoluteString + relativeUrl) {
if (urlComponents.queryItems?.first(where: { $0.name == "appVersion" })?.value == nil) {
urlComponents.queryItems = urlComponents.queryItems ?? []
urlComponents.queryItems!.append(URLQueryItem(name: "appVersion", value: version))
}
webView.loadFileURL(urlComponents.url!, allowingReadAccessTo: bundleUrl)
}
}
func webView(_ webView: WKWebView, didFinish _: WKNavigation!) {
if #available(OSXApplicationExtension 10.12, *) {
NSAnimationContext.runAnimationGroup({ _ in
@ -179,6 +189,14 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
replyMessage(message: m)
} else if command == "createNewTab" {
if let data = m.data, let url = URL(string: data) {
if !data.starts(with: "https://") && !data.starts(with: "http://") {
SFSafariApplication.getActiveWindow { win in
win?.getToolbarItem(completionHandler: { item in
item?.showPopover()
self.navigateWebView("app/" + url.absoluteString)
})
}
}
SFSafariApplication.getActiveWindow { win in
win?.openTab(with: url, makeActiveIfPossible: true, completionHandler: { _ in
// Tab opened

View File

@ -254,7 +254,7 @@ export default class AutofillService implements AutofillServiceInterface {
}
}
const autoFillResponse = await this.doAutoFill({
const totpCode = await this.doAutoFill({
cipher: cipher,
pageDetails: pageDetails,
skipTotp: !fromCommand,
@ -265,12 +265,12 @@ export default class AutofillService implements AutofillServiceInterface {
fillNewPassword: fromCommand,
});
// Only update last used index if doAutoFill didn't throw an exception
// Update last used index as autofill has succeed
if (fromCommand) {
this.cipherService.updateLastUsedIndexForUrl(tab.url);
}
return autoFillResponse;
return totpCode;
}
// Helpers