Merge branch 'master' into Permissions
This commit is contained in:
commit
c41fbac467
2
jslib
2
jslib
|
@ -1 +1 @@
|
||||||
Subproject commit f9042408f44b299a7cdd1286490b70f5fd2db999
|
Subproject commit cea09a22e533ef3598bb497ba0503c2fcd5b2dc1
|
|
@ -606,6 +606,9 @@
|
||||||
"message": "WARNING",
|
"message": "WARNING",
|
||||||
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
||||||
},
|
},
|
||||||
|
"confirmVaultExport": {
|
||||||
|
"message": "Confirm Vault Export"
|
||||||
|
},
|
||||||
"exportWarningDesc": {
|
"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."
|
"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": {
|
"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."
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,9 +115,7 @@ export class NativeMessagingBackground {
|
||||||
error = chrome.runtime.lastError.message;
|
error = chrome.runtime.lastError.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error === 'Specified native messaging host not found.' ||
|
if (error != null) {
|
||||||
error === 'Access to the specified native messaging host is forbidden.' ||
|
|
||||||
error === 'An unexpected error occurred') {
|
|
||||||
this.messagingService.send('showDialog', {
|
this.messagingService.send('showDialog', {
|
||||||
text: this.i18nService.t('desktopIntegrationDisabledDesc'),
|
text: this.i18nService.t('desktopIntegrationDisabledDesc'),
|
||||||
title: this.i18nService.t('desktopIntegrationDisabledTitle'),
|
title: this.i18nService.t('desktopIntegrationDisabledTitle'),
|
||||||
|
@ -145,7 +143,7 @@ export class NativeMessagingBackground {
|
||||||
message.timestamp = Date.now();
|
message.timestamp = Date.now();
|
||||||
|
|
||||||
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
|
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> {
|
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) {
|
private async onMessage(rawMessage: any) {
|
||||||
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
|
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
|
||||||
|
|
||||||
|
@ -231,7 +250,7 @@ export class NativeMessagingBackground {
|
||||||
|
|
||||||
message.timestamp = Date.now();
|
message.timestamp = Date.now();
|
||||||
|
|
||||||
this.port.postMessage({appId: this.appId, message: message});
|
this.postMessage({appId: this.appId, message: message});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async showFingerprintDialog() {
|
private async showFingerprintDialog() {
|
||||||
|
|
|
@ -25,12 +25,20 @@ export class SafariApp {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const messageId = now.getTime().toString() + '_' + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
const messageId = now.getTime().toString() + '_' + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||||
|
if (typeof safari === typeof undefined) {
|
||||||
(window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({
|
(window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({
|
||||||
id: messageId,
|
id: messageId,
|
||||||
command: command,
|
command: command,
|
||||||
data: data,
|
data: data,
|
||||||
responseData: null,
|
responseData: null,
|
||||||
}));
|
}));
|
||||||
|
} else {
|
||||||
|
safari.extension.dispatchMessage('bitwarden', {
|
||||||
|
command: command,
|
||||||
|
data: data,
|
||||||
|
responseData: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (resolveNow) {
|
if (resolveNow) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,6 +3,15 @@ window.addEventListener('message', (event) => {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (event.data.command && (event.data.command === 'authResult')) {
|
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({
|
chrome.runtime.sendMessage({
|
||||||
command: event.data.command,
|
command: event.data.command,
|
||||||
code: event.data.code,
|
code: event.data.code,
|
||||||
|
|
|
@ -41,11 +41,11 @@ export class SsoComponent extends BaseSsoComponent {
|
||||||
this.redirectUri = url + '/sso-connector.html';
|
this.redirectUri = url + '/sso-connector.html';
|
||||||
this.clientId = 'browser';
|
this.clientId = 'browser';
|
||||||
|
|
||||||
super.onSuccessfulLogin = () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
|
await syncService.fullSync(true);
|
||||||
BrowserApi.reloadOpenWindows();
|
BrowserApi.reloadOpenWindows();
|
||||||
const thisWindow = window.open('', '_self');
|
const thisWindow = window.open('', '_self');
|
||||||
thisWindow.close();
|
thisWindow.close();
|
||||||
return syncService.fullSync(true);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class ActionButtonsComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
async copy(cipher: CipherView, value: string, typeI18nKey: string, aType: string) {
|
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;
|
return;
|
||||||
} else if (value === cipher.login.totp) {
|
} else if (value === cipher.login.totp) {
|
||||||
value = await this.totpService.getCode(value);
|
value = await this.totpService.getCode(value);
|
||||||
|
|
|
@ -41,13 +41,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
<p>{{'exportMasterPassword' | i18n}}</p>
|
<p>{{'exportMasterPassword' | i18n}}</p>
|
||||||
<strong>{{'warning' | i18n}}</strong>:
|
|
||||||
<span *ngIf="!encryptedFormat">
|
|
||||||
{{'exportWarningDesc' | i18n}}
|
|
||||||
</span>
|
|
||||||
<span *ngIf="encryptedFormat">
|
|
||||||
{{'encExportWarningDesc' | i18n}}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</content>
|
</content>
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<content *ngIf="cipher">
|
<content *ngIf="cipher">
|
||||||
|
<app-callout type="info" *ngIf="allowOwnershipOptions() && !allowPersonal">
|
||||||
|
{{'personalOwnershipPolicyInEffect' | i18n}}
|
||||||
|
</app-callout>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
{{'itemInformation' | i18n}}
|
{{'itemInformation' | i18n}}
|
||||||
|
|
|
@ -16,14 +16,10 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
|
||||||
if initedWebView {
|
if initedWebView {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
|
||||||
initedWebView = true
|
initedWebView = true
|
||||||
let parentHeight = SafariExtensionViewController.shared.preferredContentSize.height
|
let parentHeight = SafariExtensionViewController.shared.preferredContentSize.height
|
||||||
let parentWidth = SafariExtensionViewController.shared.preferredContentSize.width
|
let parentWidth = SafariExtensionViewController.shared.preferredContentSize.width
|
||||||
let webViewConfig = WKWebViewConfiguration()
|
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: "allowFileAccessFromFileURLs")
|
||||||
webViewConfig.preferences.setValue(true, forKey: "developerExtrasEnabled")
|
webViewConfig.preferences.setValue(true, forKey: "developerExtrasEnabled")
|
||||||
webViewConfig.userContentController.add(self, name: "bitwardenApp")
|
webViewConfig.userContentController.add(self, name: "bitwardenApp")
|
||||||
|
@ -31,12 +27,26 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
|
||||||
configuration: webViewConfig)
|
configuration: webViewConfig)
|
||||||
webView.navigationDelegate = self
|
webView.navigationDelegate = self
|
||||||
webView.allowsLinkPreview = false
|
webView.allowsLinkPreview = false
|
||||||
webView.loadFileURL(url!, allowingReadAccessTo: bundleURL)
|
navigateWebView("app/popup/index.html")
|
||||||
webView.alphaValue = 0.0
|
webView.alphaValue = 0.0
|
||||||
webView.uiDelegate = self
|
webView.uiDelegate = self
|
||||||
view.addSubview(webView)
|
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!) {
|
func webView(_ webView: WKWebView, didFinish _: WKNavigation!) {
|
||||||
if #available(OSXApplicationExtension 10.12, *) {
|
if #available(OSXApplicationExtension 10.12, *) {
|
||||||
NSAnimationContext.runAnimationGroup({ _ in
|
NSAnimationContext.runAnimationGroup({ _ in
|
||||||
|
@ -179,6 +189,14 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe
|
||||||
replyMessage(message: m)
|
replyMessage(message: m)
|
||||||
} else if command == "createNewTab" {
|
} else if command == "createNewTab" {
|
||||||
if let data = m.data, let url = URL(string: data) {
|
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
|
SFSafariApplication.getActiveWindow { win in
|
||||||
win?.openTab(with: url, makeActiveIfPossible: true, completionHandler: { _ in
|
win?.openTab(with: url, makeActiveIfPossible: true, completionHandler: { _ in
|
||||||
// Tab opened
|
// Tab opened
|
||||||
|
|
|
@ -254,7 +254,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoFillResponse = await this.doAutoFill({
|
const totpCode = await this.doAutoFill({
|
||||||
cipher: cipher,
|
cipher: cipher,
|
||||||
pageDetails: pageDetails,
|
pageDetails: pageDetails,
|
||||||
skipTotp: !fromCommand,
|
skipTotp: !fromCommand,
|
||||||
|
@ -265,12 +265,12 @@ export default class AutofillService implements AutofillServiceInterface {
|
||||||
fillNewPassword: fromCommand,
|
fillNewPassword: fromCommand,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only update last used index if doAutoFill didn't throw an exception
|
// Update last used index as autofill has succeed
|
||||||
if (fromCommand) {
|
if (fromCommand) {
|
||||||
this.cipherService.updateLastUsedIndexForUrl(tab.url);
|
this.cipherService.updateLastUsedIndexForUrl(tab.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return autoFillResponse;
|
return totpCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
Loading…
Reference in New Issue