Compare commits
1 Commits
v2023.7.0
...
feature/io
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69cd7d79e7 |
@@ -44,6 +44,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Commo
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Safari", "src\iOS.Safari\iOS.Safari.csproj", "{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@@ -414,6 +416,36 @@ Global
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|Any CPU.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|Any CPU.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|Any CPU.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|Any CPU.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|iPhone.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|iPhone.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|iPhoneSimulator.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.AppStore|iPhoneSimulator.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|Any CPU.Build.0 = Debug|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|Any CPU.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|iPhone.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|Any CPU.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -431,6 +463,7 @@ Global
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{7CE47211-43D4-4BBB-BB16-82A8A337ECE7} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
||||
|
||||
73
src/iOS.Safari/ActionViewController.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
|
||||
using MobileCoreServices;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace iOS.Safari
|
||||
{
|
||||
public partial class ActionViewController : UIViewController
|
||||
{
|
||||
protected ActionViewController(IntPtr handle) : base(handle)
|
||||
{
|
||||
// Note: this .ctor should not contain any initialization logic.
|
||||
}
|
||||
|
||||
public override void DidReceiveMemoryWarning()
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
base.DidReceiveMemoryWarning();
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
public override void ViewDidLoad()
|
||||
{
|
||||
base.ViewDidLoad();
|
||||
|
||||
// Get the item[s] we're handling from the extension context.
|
||||
|
||||
// For example, look for an image and place it into an image view.
|
||||
// Replace this with something appropriate for the type[s] your extension supports.
|
||||
bool imageFound = false;
|
||||
|
||||
foreach (var item in ExtensionContext.InputItems)
|
||||
{
|
||||
foreach (var itemProvider in item.Attachments)
|
||||
{
|
||||
if (itemProvider.HasItemConformingTo(UTType.Image))
|
||||
{
|
||||
// This is an image. We'll load it, then place it in our image view.
|
||||
itemProvider.LoadItem(UTType.Image, null, delegate (NSObject image, NSError error)
|
||||
{
|
||||
var url = image as NSUrl;
|
||||
if (url != null)
|
||||
{
|
||||
NSOperationQueue.MainQueue.AddOperation(delegate
|
||||
{
|
||||
imageView.Image = UIImage.LoadFromData(NSData.FromUrl(url));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
imageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (imageFound)
|
||||
{
|
||||
// We only handle one image, so stop looking for more.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void DoneClicked(NSObject sender)
|
||||
{
|
||||
// Return any edited content to the host app.
|
||||
// This template doesn't do anything, so we just echo the passed-in items.
|
||||
ExtensionContext.CompleteRequest(ExtensionContext.InputItems, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/iOS.Safari/ActionViewController.designer.cs
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// This file has been generated automatically by MonoDevelop to store outlets and
|
||||
// actions made in the Xcode designer. If it is removed, they will be lost.
|
||||
// Manual changes to this file may not be handled correctly.
|
||||
//
|
||||
using Foundation;
|
||||
|
||||
namespace iOS.Safari
|
||||
{
|
||||
[Register("ActionViewController")]
|
||||
partial class ActionViewController
|
||||
{
|
||||
[Outlet]
|
||||
UIKit.UIImageView imageView { get; set; }
|
||||
|
||||
[Action("DoneClicked:")]
|
||||
partial void DoneClicked(Foundation.NSObject sender);
|
||||
|
||||
void ReleaseDesignerOutlets()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
src/iOS.Safari/Entitlements.plist
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>
|
||||
31
src/iOS.Safari/Info.plist
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>iOS.Safari</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>iOS.Safari</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.8bit.bitwarden.iOS-Safari</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.14.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>15.0</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.Safari.web-extension</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>SafariWebExtensionHandler</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
1817
src/iOS.Safari/Resources/_locales/az/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/be/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/bg/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/bn/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ca/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/cs/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/da/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/de/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/el/messages.json
Normal file
1825
src/iOS.Safari/Resources/_locales/en/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/en_GB/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/en_IN/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/es/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/et/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/fa/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/fi/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/fil/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/fr/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/he/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/hi/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/hr/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/hu/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/id/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/it/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ja/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ka/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/kn/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ko/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/lt/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/lv/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ml/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/nb/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/nl/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/nn/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/pl/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/pt_BR/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/pt_PT/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ro/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/ru/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/si/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/sk/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/sl/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/sr/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/sv/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/th/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/tr/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/uk/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/vi/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/zh_CN/messages.json
Normal file
1817
src/iOS.Safari/Resources/_locales/zh_TW/messages.json
Normal file
7
src/iOS.Safari/Resources/background.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<script src="vendor.js"></script><script src="background.js"></script></body>
|
||||
</html>
|
||||
30039
src/iOS.Safari/Resources/background.js
Normal file
36
src/iOS.Safari/Resources/content/autofill.css
Normal file
@@ -0,0 +1,36 @@
|
||||
@-webkit-keyframes bitwardenfill {
|
||||
0% {
|
||||
-webkit-transform: scale(1.0, 1.0);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale(1.2, 1.2);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: scale(1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes bitwardenfill {
|
||||
0% {
|
||||
transform: scale(1.0, 1.0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.2, 1.2);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
span[data-bwautofill].com-bitwarden-browser-animated-fill {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.com-bitwarden-browser-animated-fill {
|
||||
animation: bitwardenfill 200ms ease-in-out 0ms 1;
|
||||
-webkit-animation: bitwardenfill 200ms ease-in-out 0ms 1;
|
||||
}
|
||||
1142
src/iOS.Safari/Resources/content/autofill.js
Normal file
139
src/iOS.Safari/Resources/content/autofiller.js
Normal file
@@ -0,0 +1,139 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./src/content/autofiller.ts");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./src/content/autofiller.ts":
|
||||
/*!***********************************!*\
|
||||
!*** ./src/content/autofiller.ts ***!
|
||||
\***********************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
let pageHref = null;
|
||||
let filledThisHref = false;
|
||||
let delayFillTimeout;
|
||||
const enabledKey = 'enableAutoFillOnPageLoad';
|
||||
chrome.storage.local.get(enabledKey, (obj) => {
|
||||
if (obj != null && obj[enabledKey] === true) {
|
||||
setInterval(() => doFillIfNeeded(), 500);
|
||||
}
|
||||
});
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
if (msg.command === 'fillForm' && pageHref === msg.url) {
|
||||
filledThisHref = true;
|
||||
}
|
||||
});
|
||||
function doFillIfNeeded(force = false) {
|
||||
if (force || pageHref !== window.location.href) {
|
||||
if (!force) {
|
||||
// Some websites are slow and rendering all page content. Try to fill again later
|
||||
// if we haven't already.
|
||||
filledThisHref = false;
|
||||
if (delayFillTimeout != null) {
|
||||
window.clearTimeout(delayFillTimeout);
|
||||
}
|
||||
delayFillTimeout = window.setTimeout(() => {
|
||||
if (!filledThisHref) {
|
||||
doFillIfNeeded(true);
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
pageHref = window.location.href;
|
||||
const msg = {
|
||||
command: 'bgCollectPageDetails',
|
||||
sender: 'autofiller',
|
||||
};
|
||||
chrome.runtime.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
159
src/iOS.Safari/Resources/content/contextMenuHandler.js
Normal file
@@ -0,0 +1,159 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./src/content/contextMenuHandler.ts");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./src/content/contextMenuHandler.ts":
|
||||
/*!*******************************************!*\
|
||||
!*** ./src/content/contextMenuHandler.ts ***!
|
||||
\*******************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
const inputTags = ['input', 'textarea', 'select'];
|
||||
const labelTags = ['label', 'span'];
|
||||
const attributes = ['id', 'name', 'label-aria', 'placeholder'];
|
||||
const invalidElement = chrome.i18n.getMessage('copyCustomFieldNameInvalidElement');
|
||||
const noUniqueIdentifier = chrome.i18n.getMessage('copyCustomFieldNameNotUnique');
|
||||
let clickedEl = null;
|
||||
// Find the best attribute to be used as the Name for an element in a custom field.
|
||||
function getClickedElementIdentifier() {
|
||||
var _a, _b;
|
||||
if (clickedEl == null) {
|
||||
return invalidElement;
|
||||
}
|
||||
const clickedTag = clickedEl.nodeName.toLowerCase();
|
||||
let inputEl = null;
|
||||
// Try to identify the input element (which may not be the clicked element)
|
||||
if (labelTags.includes(clickedTag)) {
|
||||
let inputId = null;
|
||||
if (clickedTag === 'label') {
|
||||
inputId = clickedEl.getAttribute('for');
|
||||
}
|
||||
else {
|
||||
inputId = (_a = clickedEl.closest('label')) === null || _a === void 0 ? void 0 : _a.getAttribute('for');
|
||||
}
|
||||
inputEl = document.getElementById(inputId);
|
||||
}
|
||||
else {
|
||||
inputEl = clickedEl;
|
||||
}
|
||||
if (inputEl == null || !inputTags.includes(inputEl.nodeName.toLowerCase())) {
|
||||
return invalidElement;
|
||||
}
|
||||
for (const attr of attributes) {
|
||||
const attributeValue = inputEl.getAttribute(attr);
|
||||
const selector = '[' + attr + '="' + attributeValue + '"]';
|
||||
if (!isNullOrEmpty(attributeValue) && ((_b = document.querySelectorAll(selector)) === null || _b === void 0 ? void 0 : _b.length) === 1) {
|
||||
return attributeValue;
|
||||
}
|
||||
}
|
||||
return noUniqueIdentifier;
|
||||
}
|
||||
function isNullOrEmpty(s) {
|
||||
return s == null || s === '';
|
||||
}
|
||||
// We only have access to the element that's been clicked when the context menu is first opened.
|
||||
// Remember it for use later.
|
||||
document.addEventListener('contextmenu', event => {
|
||||
clickedEl = event.target;
|
||||
});
|
||||
// Runs when the 'Copy Custom Field Name' context menu item is actually clicked.
|
||||
chrome.runtime.onMessage.addListener(event => {
|
||||
if (event.command === 'getClickedElement') {
|
||||
const identifier = getClickedElementIdentifier();
|
||||
chrome.runtime.sendMessage({
|
||||
command: 'getClickedElementResponse',
|
||||
sender: 'contextMenuHandler',
|
||||
identifier: identifier,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
126
src/iOS.Safari/Resources/content/message_handler.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./src/content/message_handler.ts");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./src/content/message_handler.ts":
|
||||
/*!****************************************!*\
|
||||
!*** ./src/content/message_handler.ts ***!
|
||||
\****************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
window.addEventListener('message', event => {
|
||||
if (event.source !== window)
|
||||
return;
|
||||
if (event.data.command && (event.data.command === 'authResult')) {
|
||||
chrome.runtime.sendMessage({
|
||||
command: event.data.command,
|
||||
code: event.data.code,
|
||||
state: event.data.state,
|
||||
referrer: event.source.location.hostname,
|
||||
});
|
||||
}
|
||||
if (event.data.command && (event.data.command === 'webAuthnResult')) {
|
||||
chrome.runtime.sendMessage({
|
||||
command: event.data.command,
|
||||
data: event.data.data,
|
||||
remember: event.data.remember,
|
||||
referrer: event.source.location.hostname,
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
const forwardCommands = ['promptForLogin', 'addToLockedVaultPendingNotifications', 'unlockCompleted'];
|
||||
chrome.runtime.onMessage.addListener(event => {
|
||||
if (forwardCommands.includes(event.command)) {
|
||||
chrome.runtime.sendMessage(event);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
592
src/iOS.Safari/Resources/content/notificationBar.js
Normal file
@@ -0,0 +1,592 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./src/content/notificationBar.ts");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./src/content/notificationBar.ts":
|
||||
/*!****************************************!*\
|
||||
!*** ./src/content/notificationBar.ts ***!
|
||||
\****************************************/
|
||||
/*! no exports provided */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
if (window.location.hostname.indexOf('vault.bitwarden.com') > -1) {
|
||||
return;
|
||||
}
|
||||
const pageDetails = [];
|
||||
const formData = [];
|
||||
let barType = null;
|
||||
let pageHref = null;
|
||||
let observer = null;
|
||||
const observeIgnoredElements = new Set(['a', 'i', 'b', 'strong', 'span', 'code', 'br', 'img', 'small', 'em', 'hr']);
|
||||
let domObservationCollectTimeout = null;
|
||||
let collectIfNeededTimeout = null;
|
||||
let observeDomTimeout = null;
|
||||
const inIframe = isInIframe();
|
||||
const cancelButtonNames = new Set(['cancel', 'close', 'back']);
|
||||
const logInButtonNames = new Set(['log in', 'sign in', 'login', 'go', 'submit', 'continue', 'next']);
|
||||
const changePasswordButtonNames = new Set(['save password', 'update password', 'change password', 'change']);
|
||||
const changePasswordButtonContainsNames = new Set(['pass', 'change', 'contras', 'senha']);
|
||||
let disabledAddLoginNotification = false;
|
||||
let disabledChangedPasswordNotification = false;
|
||||
chrome.storage.local.get('neverDomains', (ndObj) => {
|
||||
const domains = ndObj.neverDomains;
|
||||
if (domains != null && domains.hasOwnProperty(window.location.hostname)) {
|
||||
return;
|
||||
}
|
||||
chrome.storage.local.get('disableAddLoginNotification', (disAddObj) => {
|
||||
disabledAddLoginNotification = disAddObj != null && disAddObj.disableAddLoginNotification === true;
|
||||
chrome.storage.local.get('disableChangedPasswordNotification', (disChangedObj) => {
|
||||
disabledChangedPasswordNotification = disChangedObj != null &&
|
||||
disChangedObj.disableChangedPasswordNotification === true;
|
||||
if (!disabledAddLoginNotification || !disabledChangedPasswordNotification) {
|
||||
collectIfNeededWithTimeout();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
processMessages(msg, sendResponse);
|
||||
});
|
||||
function processMessages(msg, sendResponse) {
|
||||
if (msg.command === 'openNotificationBar') {
|
||||
if (inIframe) {
|
||||
return;
|
||||
}
|
||||
closeExistingAndOpenBar(msg.data.type, msg.data.typeData);
|
||||
sendResponse();
|
||||
return true;
|
||||
}
|
||||
else if (msg.command === 'closeNotificationBar') {
|
||||
if (inIframe) {
|
||||
return;
|
||||
}
|
||||
closeBar(true);
|
||||
sendResponse();
|
||||
return true;
|
||||
}
|
||||
else if (msg.command === 'adjustNotificationBar') {
|
||||
if (inIframe) {
|
||||
return;
|
||||
}
|
||||
adjustBar(msg.data);
|
||||
sendResponse();
|
||||
return true;
|
||||
}
|
||||
else if (msg.command === 'notificationBarPageDetails') {
|
||||
pageDetails.push(msg.data.details);
|
||||
watchForms(msg.data.forms);
|
||||
sendResponse();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function isInIframe() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
}
|
||||
catch (_a) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function observeDom() {
|
||||
const bodies = document.querySelectorAll('body');
|
||||
if (bodies && bodies.length > 0) {
|
||||
observer = new MutationObserver(mutations => {
|
||||
if (mutations == null || mutations.length === 0 || pageHref !== window.location.href) {
|
||||
return;
|
||||
}
|
||||
let doCollect = false;
|
||||
for (let i = 0; i < mutations.length; i++) {
|
||||
const mutation = mutations[i];
|
||||
if (mutation.addedNodes == null || mutation.addedNodes.length === 0) {
|
||||
continue;
|
||||
}
|
||||
for (let j = 0; j < mutation.addedNodes.length; j++) {
|
||||
const addedNode = mutation.addedNodes[j];
|
||||
if (addedNode == null) {
|
||||
continue;
|
||||
}
|
||||
const tagName = addedNode.tagName != null ? addedNode.tagName.toLowerCase() : null;
|
||||
if (tagName != null && tagName === 'form' &&
|
||||
(addedNode.dataset == null || !addedNode.dataset.bitwardenWatching)) {
|
||||
doCollect = true;
|
||||
break;
|
||||
}
|
||||
if ((tagName != null && observeIgnoredElements.has(tagName)) ||
|
||||
addedNode.querySelectorAll == null) {
|
||||
continue;
|
||||
}
|
||||
const forms = addedNode.querySelectorAll('form:not([data-bitwarden-watching])');
|
||||
if (forms != null && forms.length > 0) {
|
||||
doCollect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (doCollect) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (doCollect) {
|
||||
if (domObservationCollectTimeout != null) {
|
||||
window.clearTimeout(domObservationCollectTimeout);
|
||||
}
|
||||
domObservationCollectTimeout = window.setTimeout(collect, 1000);
|
||||
}
|
||||
});
|
||||
observer.observe(bodies[0], { childList: true, subtree: true });
|
||||
}
|
||||
}
|
||||
function collectIfNeededWithTimeout() {
|
||||
if (collectIfNeededTimeout != null) {
|
||||
window.clearTimeout(collectIfNeededTimeout);
|
||||
}
|
||||
collectIfNeededTimeout = window.setTimeout(collectIfNeeded, 1000);
|
||||
}
|
||||
function collectIfNeeded() {
|
||||
if (pageHref !== window.location.href) {
|
||||
pageHref = window.location.href;
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
observer = null;
|
||||
}
|
||||
collect();
|
||||
if (observeDomTimeout != null) {
|
||||
window.clearTimeout(observeDomTimeout);
|
||||
}
|
||||
observeDomTimeout = window.setTimeout(observeDom, 1000);
|
||||
}
|
||||
if (collectIfNeededTimeout != null) {
|
||||
window.clearTimeout(collectIfNeededTimeout);
|
||||
}
|
||||
collectIfNeededTimeout = window.setTimeout(collectIfNeeded, 1000);
|
||||
}
|
||||
function collect() {
|
||||
sendPlatformMessage({
|
||||
command: 'bgCollectPageDetails',
|
||||
sender: 'notificationBar',
|
||||
});
|
||||
}
|
||||
function watchForms(forms) {
|
||||
if (forms == null || forms.length === 0) {
|
||||
return;
|
||||
}
|
||||
forms.forEach((f) => {
|
||||
const formId = f.form != null ? f.form.htmlID : null;
|
||||
let formEl = null;
|
||||
if (formId != null && formId !== '') {
|
||||
formEl = document.getElementById(formId);
|
||||
}
|
||||
if (formEl == null) {
|
||||
const index = parseInt(f.form.opid.split('__')[2], null);
|
||||
formEl = document.getElementsByTagName('form')[index];
|
||||
}
|
||||
if (formEl != null && formEl.dataset.bitwardenWatching !== '1') {
|
||||
const formDataObj = {
|
||||
data: f,
|
||||
formEl: formEl,
|
||||
usernameEl: null,
|
||||
passwordEl: null,
|
||||
passwordEls: null,
|
||||
};
|
||||
locateFields(formDataObj);
|
||||
formData.push(formDataObj);
|
||||
listen(formEl);
|
||||
formEl.dataset.bitwardenWatching = '1';
|
||||
}
|
||||
});
|
||||
}
|
||||
function listen(form) {
|
||||
form.removeEventListener('submit', formSubmitted, false);
|
||||
form.addEventListener('submit', formSubmitted, false);
|
||||
const submitButton = getSubmitButton(form, logInButtonNames);
|
||||
if (submitButton != null) {
|
||||
submitButton.removeEventListener('click', formSubmitted, false);
|
||||
submitButton.addEventListener('click', formSubmitted, false);
|
||||
}
|
||||
}
|
||||
function locateFields(formDataObj) {
|
||||
const inputs = Array.from(document.getElementsByTagName('input'));
|
||||
formDataObj.usernameEl = locateField(formDataObj.formEl, formDataObj.data.username, inputs);
|
||||
if (formDataObj.usernameEl != null && formDataObj.data.password != null) {
|
||||
formDataObj.passwordEl = locatePassword(formDataObj.formEl, formDataObj.data.password, inputs, true);
|
||||
}
|
||||
else if (formDataObj.data.passwords != null) {
|
||||
formDataObj.passwordEls = [];
|
||||
formDataObj.data.passwords.forEach((pData) => {
|
||||
const el = locatePassword(formDataObj.formEl, pData, inputs, false);
|
||||
if (el != null) {
|
||||
formDataObj.passwordEls.push(el);
|
||||
}
|
||||
});
|
||||
if (formDataObj.passwordEls.length === 0) {
|
||||
formDataObj.passwordEls = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
function locatePassword(form, passwordData, inputs, doLastFallback) {
|
||||
let el = locateField(form, passwordData, inputs);
|
||||
if (el != null && el.type !== 'password') {
|
||||
el = null;
|
||||
}
|
||||
if (doLastFallback && el == null) {
|
||||
el = form.querySelector('input[type="password"]');
|
||||
}
|
||||
return el;
|
||||
}
|
||||
function locateField(form, fieldData, inputs) {
|
||||
if (fieldData == null) {
|
||||
return;
|
||||
}
|
||||
let el = null;
|
||||
if (fieldData.htmlID != null && fieldData.htmlID !== '') {
|
||||
try {
|
||||
el = form.querySelector('#' + fieldData.htmlID);
|
||||
}
|
||||
catch (_a) {
|
||||
// Ignore error, we perform fallbacks below.
|
||||
}
|
||||
}
|
||||
if (el == null && fieldData.htmlName != null && fieldData.htmlName !== '') {
|
||||
el = form.querySelector('input[name="' + fieldData.htmlName + '"]');
|
||||
}
|
||||
if (el == null && fieldData.elementNumber != null) {
|
||||
el = inputs[fieldData.elementNumber];
|
||||
}
|
||||
return el;
|
||||
}
|
||||
function formSubmitted(e) {
|
||||
let form = null;
|
||||
if (e.type === 'click') {
|
||||
form = e.target.closest('form');
|
||||
if (form == null) {
|
||||
const parentModal = e.target.closest('div.modal');
|
||||
if (parentModal != null) {
|
||||
const modalForms = parentModal.querySelectorAll('form');
|
||||
if (modalForms.length === 1) {
|
||||
form = modalForms[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
form = e.target;
|
||||
}
|
||||
if (form == null || form.dataset.bitwardenProcessed === '1') {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < formData.length; i++) {
|
||||
if (formData[i].formEl !== form) {
|
||||
continue;
|
||||
}
|
||||
const disabledBoth = disabledChangedPasswordNotification && disabledAddLoginNotification;
|
||||
if (!disabledBoth && formData[i].usernameEl != null && formData[i].passwordEl != null) {
|
||||
const login = {
|
||||
username: formData[i].usernameEl.value,
|
||||
password: formData[i].passwordEl.value,
|
||||
url: document.URL,
|
||||
};
|
||||
if (login.username != null && login.username !== '' &&
|
||||
login.password != null && login.password !== '') {
|
||||
processedForm(form);
|
||||
sendPlatformMessage({
|
||||
command: 'bgAddLogin',
|
||||
login: login,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!disabledChangedPasswordNotification && formData[i].passwordEls != null) {
|
||||
const passwords = formData[i].passwordEls
|
||||
.filter((el) => el.value != null && el.value !== '')
|
||||
.map((el) => el.value);
|
||||
let curPass = null;
|
||||
let newPass = null;
|
||||
let newPassOnly = false;
|
||||
if (formData[i].passwordEls.length === 3 && passwords.length === 3) {
|
||||
newPass = passwords[1];
|
||||
if (passwords[0] !== newPass && newPass === passwords[2]) {
|
||||
curPass = passwords[0];
|
||||
}
|
||||
else if (newPass !== passwords[2] && passwords[0] === newPass) {
|
||||
curPass = passwords[2];
|
||||
}
|
||||
}
|
||||
else if (formData[i].passwordEls.length === 2 && passwords.length === 2) {
|
||||
if (passwords[0] === passwords[1]) {
|
||||
newPassOnly = true;
|
||||
newPass = passwords[0];
|
||||
curPass = null;
|
||||
}
|
||||
else {
|
||||
const buttonText = getButtonText(getSubmitButton(form, changePasswordButtonNames));
|
||||
const matches = Array.from(changePasswordButtonContainsNames)
|
||||
.filter(n => buttonText.indexOf(n) > -1);
|
||||
if (matches.length > 0) {
|
||||
curPass = passwords[0];
|
||||
newPass = passwords[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newPass != null && curPass != null || (newPassOnly && newPass != null)) {
|
||||
processedForm(form);
|
||||
const changePasswordRuntimeMessage = {
|
||||
newPassword: newPass,
|
||||
currentPassword: curPass,
|
||||
url: document.URL,
|
||||
};
|
||||
sendPlatformMessage({
|
||||
command: 'bgChangedPassword',
|
||||
data: changePasswordRuntimeMessage,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function getSubmitButton(wrappingEl, buttonNames) {
|
||||
if (wrappingEl == null) {
|
||||
return null;
|
||||
}
|
||||
const wrappingElIsForm = wrappingEl.tagName.toLowerCase() === 'form';
|
||||
let submitButton = wrappingEl.querySelector('input[type="submit"], input[type="image"], ' +
|
||||
'button[type="submit"]');
|
||||
if (submitButton == null && wrappingElIsForm) {
|
||||
submitButton = wrappingEl.querySelector('button:not([type])');
|
||||
if (submitButton != null) {
|
||||
const buttonText = getButtonText(submitButton);
|
||||
if (buttonText != null && cancelButtonNames.has(buttonText.trim().toLowerCase())) {
|
||||
submitButton = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (submitButton == null) {
|
||||
const possibleSubmitButtons = Array.from(wrappingEl.querySelectorAll('a, span, button[type="button"], ' +
|
||||
'input[type="button"], button:not([type])'));
|
||||
let typelessButton = null;
|
||||
possibleSubmitButtons.forEach(button => {
|
||||
if (submitButton != null || button == null || button.tagName == null) {
|
||||
return;
|
||||
}
|
||||
const buttonText = getButtonText(button);
|
||||
if (buttonText != null) {
|
||||
if (typelessButton != null && button.tagName.toLowerCase() === 'button' &&
|
||||
button.getAttribute('type') == null &&
|
||||
!cancelButtonNames.has(buttonText.trim().toLowerCase())) {
|
||||
typelessButton = button;
|
||||
}
|
||||
else if (buttonNames.has(buttonText.trim().toLowerCase())) {
|
||||
submitButton = button;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (submitButton == null && typelessButton != null) {
|
||||
submitButton = typelessButton;
|
||||
}
|
||||
}
|
||||
if (submitButton == null && wrappingElIsForm) {
|
||||
// Maybe it's in a modal?
|
||||
const parentModal = wrappingEl.closest('div.modal');
|
||||
if (parentModal != null) {
|
||||
const modalForms = parentModal.querySelectorAll('form');
|
||||
if (modalForms.length === 1) {
|
||||
submitButton = getSubmitButton(parentModal, buttonNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
return submitButton;
|
||||
}
|
||||
function getButtonText(button) {
|
||||
let buttonText = null;
|
||||
if (button.tagName.toLowerCase() === 'input') {
|
||||
buttonText = button.value;
|
||||
}
|
||||
else {
|
||||
buttonText = button.innerText;
|
||||
}
|
||||
return buttonText;
|
||||
}
|
||||
function processedForm(form) {
|
||||
form.dataset.bitwardenProcessed = '1';
|
||||
window.setTimeout(() => {
|
||||
form.dataset.bitwardenProcessed = '0';
|
||||
}, 500);
|
||||
}
|
||||
function closeExistingAndOpenBar(type, typeData) {
|
||||
let barPage = 'notification/bar.html';
|
||||
switch (type) {
|
||||
case 'add':
|
||||
barPage = barPage + '?add=1&isVaultLocked=' + typeData.isVaultLocked;
|
||||
break;
|
||||
case 'change':
|
||||
barPage = barPage + '?change=1&isVaultLocked=' + typeData.isVaultLocked;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const frame = document.getElementById('bit-notification-bar-iframe');
|
||||
if (frame != null && frame.src.indexOf(barPage) >= 0) {
|
||||
return;
|
||||
}
|
||||
closeBar(false);
|
||||
openBar(type, barPage);
|
||||
}
|
||||
function openBar(type, barPage) {
|
||||
barType = type;
|
||||
if (document.body == null) {
|
||||
return;
|
||||
}
|
||||
const barPageUrl = chrome.extension.getURL(barPage);
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.cssText = 'height: 42px; width: 100%; border: 0; min-height: initial;';
|
||||
iframe.id = 'bit-notification-bar-iframe';
|
||||
iframe.src = barPageUrl;
|
||||
const frameDiv = document.createElement('div');
|
||||
frameDiv.setAttribute('aria-live', 'polite');
|
||||
frameDiv.id = 'bit-notification-bar';
|
||||
frameDiv.style.cssText = 'height: 42px; width: 100%; top: 0; left: 0; padding: 0; position: fixed; ' +
|
||||
'z-index: 2147483647; visibility: visible;';
|
||||
frameDiv.appendChild(iframe);
|
||||
document.body.appendChild(frameDiv);
|
||||
iframe.contentWindow.location = barPageUrl;
|
||||
const spacer = document.createElement('div');
|
||||
spacer.id = 'bit-notification-bar-spacer';
|
||||
spacer.style.cssText = 'height: 42px;';
|
||||
document.body.insertBefore(spacer, document.body.firstChild);
|
||||
}
|
||||
function closeBar(explicitClose) {
|
||||
const barEl = document.getElementById('bit-notification-bar');
|
||||
if (barEl != null) {
|
||||
barEl.parentElement.removeChild(barEl);
|
||||
}
|
||||
const spacerEl = document.getElementById('bit-notification-bar-spacer');
|
||||
if (spacerEl) {
|
||||
spacerEl.parentElement.removeChild(spacerEl);
|
||||
}
|
||||
if (!explicitClose) {
|
||||
return;
|
||||
}
|
||||
switch (barType) {
|
||||
case 'add':
|
||||
sendPlatformMessage({
|
||||
command: 'bgAddClose',
|
||||
});
|
||||
break;
|
||||
case 'change':
|
||||
sendPlatformMessage({
|
||||
command: 'bgChangeClose',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function adjustBar(data) {
|
||||
if (data != null && data.height !== 42) {
|
||||
const newHeight = data.height + 'px';
|
||||
doHeightAdjustment('bit-notification-bar-iframe', newHeight);
|
||||
doHeightAdjustment('bit-notification-bar', newHeight);
|
||||
doHeightAdjustment('bit-notification-bar-spacer', newHeight);
|
||||
}
|
||||
}
|
||||
function doHeightAdjustment(elId, heightStyle) {
|
||||
const el = document.getElementById(elId);
|
||||
if (el != null) {
|
||||
el.style.height = heightStyle;
|
||||
}
|
||||
}
|
||||
function sendPlatformMessage(msg) {
|
||||
chrome.runtime.sendMessage(msg);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
1216
src/iOS.Safari/Resources/content/shortcuts.js
Normal file
BIN
src/iOS.Safari/Resources/images/close.png
Normal file
|
After Width: | Height: | Size: 288 B |
BIN
src/iOS.Safari/Resources/images/icon128.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
src/iOS.Safari/Resources/images/icon128_gray.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
src/iOS.Safari/Resources/images/icon16.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/iOS.Safari/Resources/images/icon16_gray.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/iOS.Safari/Resources/images/icon18_safari.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/iOS.Safari/Resources/images/icon18_safari@2x.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/iOS.Safari/Resources/images/icon18_safari_locked.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/iOS.Safari/Resources/images/icon18_safari_locked@2x.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/iOS.Safari/Resources/images/icon19.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/iOS.Safari/Resources/images/icon19_gray.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/iOS.Safari/Resources/images/icon19_locked.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/iOS.Safari/Resources/images/icon32.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
src/iOS.Safari/Resources/images/icon32_gray.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/iOS.Safari/Resources/images/icon38.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/iOS.Safari/Resources/images/icon38_gray.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src/iOS.Safari/Resources/images/icon38_locked.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/iOS.Safari/Resources/images/icon48.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/iOS.Safari/Resources/images/icon48_gray.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/iOS.Safari/Resources/images/icon96.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src/iOS.Safari/Resources/images/icon96_gray.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
144
src/iOS.Safari/Resources/manifest.json
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "__MSG_extName__",
|
||||
"short_name": "__MSG_appName__",
|
||||
"version": "1.54.0",
|
||||
"description": "__MSG_extDesc__",
|
||||
"default_locale": "en",
|
||||
"author": "Bitwarden Inc.",
|
||||
"homepage_url": "https://bitwarden.com",
|
||||
"icons": {
|
||||
"16": "images/icon16.png",
|
||||
"32": "images/icon32.png",
|
||||
"48": "images/icon48.png",
|
||||
"96": "images/icon96.png",
|
||||
"128": "images/icon128.png"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"all_frames": true,
|
||||
"js": [
|
||||
"content/autofill.js",
|
||||
"content/autofiller.js",
|
||||
"content/notificationBar.js",
|
||||
"content/contextMenuHandler.js"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"file:///*"
|
||||
],
|
||||
"run_at": "document_start"
|
||||
},
|
||||
{
|
||||
"all_frames": false,
|
||||
"js": [
|
||||
"content/shortcuts.js"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"file:///*"
|
||||
],
|
||||
"run_at": "document_start"
|
||||
},
|
||||
{
|
||||
"all_frames": false,
|
||||
"js": [
|
||||
"content/message_handler.js"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"file:///*"
|
||||
],
|
||||
"run_at": "document_start"
|
||||
},
|
||||
{
|
||||
"all_frames": true,
|
||||
"css": [
|
||||
"content/autofill.css"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"file:///*"
|
||||
],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
],
|
||||
"background": {
|
||||
"page": "background.html",
|
||||
"persistent": false
|
||||
},
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"19": "images/icon19.png",
|
||||
"38": "images/icon38.png"
|
||||
},
|
||||
"default_title": "Bitwarden",
|
||||
"default_popup": "popup/index.html"
|
||||
},
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"contextMenus",
|
||||
"storage",
|
||||
"unlimitedStorage",
|
||||
"clipboardRead",
|
||||
"clipboardWrite",
|
||||
"idle",
|
||||
"http://*/*",
|
||||
"https://*/*",
|
||||
"webRequestBlocking",
|
||||
"nativeMessaging"
|
||||
],
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"commands": {
|
||||
"_execute_browser_action": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+Y",
|
||||
"linux": "Ctrl+Shift+U"
|
||||
},
|
||||
"description": "__MSG_commandOpenPopup__"
|
||||
},
|
||||
"_execute_sidebar_action": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+Y",
|
||||
"linux": "Alt+Shift+U"
|
||||
},
|
||||
"description": "__MSG_commandOpenSidebar__"
|
||||
},
|
||||
"autofill_login": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+L"
|
||||
},
|
||||
"description": "__MSG_commandAutofillDesc__"
|
||||
},
|
||||
"generate_password": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+9"
|
||||
},
|
||||
"description": "__MSG_commandGeneratePasswordDesc__"
|
||||
},
|
||||
"lock_vault": {
|
||||
"description": "__MSG_commandLockVaultDesc__"
|
||||
}
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
"notification/bar.html",
|
||||
"images/icon38.png",
|
||||
"images/icon38_locked.png",
|
||||
"images/close.png"
|
||||
],
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{446900e4-71c2-419f-a6a7-df9c091e268b}",
|
||||
"strict_min_version": "42.0"
|
||||
}
|
||||
},
|
||||
"sidebar_action": {
|
||||
"default_title": "Bitwarden",
|
||||
"default_panel": "popup/index.html?uilocation=sidebar",
|
||||
"default_icon": "images/icon19.png"
|
||||
}
|
||||
}
|
||||
92
src/iOS.Safari/Resources/notification/bar.css
Normal file
@@ -0,0 +1,92 @@
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
color: #333333;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.outer-wrapper {
|
||||
padding: 0 10px;
|
||||
border-bottom: 2px solid #175ddc;
|
||||
display: grid;
|
||||
grid-template-columns: 24px auto 55px;
|
||||
grid-column-gap: 10px;
|
||||
box-sizing: border-box;
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
.inner-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: auto max-content;
|
||||
}
|
||||
|
||||
.outer-wrapper > *, .inner-wrapper > * {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#close {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
display: block;
|
||||
padding: 5px 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
button:not(.link),
|
||||
button:not(.neutral) {
|
||||
background-color: #175DDC;
|
||||
padding: 5px 15px;
|
||||
border-radius: 3px;
|
||||
color: #ffffff;
|
||||
border: 0;
|
||||
}
|
||||
button:not(.link):hover,
|
||||
button:not(.neutral):hover {
|
||||
cursor: pointer;
|
||||
background-color: #1751bd;
|
||||
}
|
||||
|
||||
button.link,
|
||||
button.neutral {
|
||||
background: none;
|
||||
padding: 5px 15px;
|
||||
color: #175DDC;
|
||||
border: 0;
|
||||
}
|
||||
button.link:hover,
|
||||
button.neutral:hover {
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.select-folder[isVaultLocked=true] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.select-folder {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (print) {
|
||||
body {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
41
src/iOS.Safari/Resources/notification/bar.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Bitwarden</title>
|
||||
<meta charset="utf-8" />
|
||||
<link href="../notification/bar.css" rel="stylesheet"></head>
|
||||
|
||||
<body>
|
||||
<div class="outer-wrapper">
|
||||
<div class="logo">
|
||||
<a href="https://vault.bitwarden.com" target="_blank" id="logo-link">
|
||||
<img id="logo" alt="Bitwarden" />
|
||||
</a>
|
||||
</div>
|
||||
<div id="content"></div>
|
||||
<div>
|
||||
<button type="button" class="neutral" id="close-button">
|
||||
<img id="close" alt="Close" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="templates" style="display: none;">
|
||||
<div class="inner-wrapper" id="template-add">
|
||||
<div class="add-text"></div>
|
||||
<div class="add-buttons">
|
||||
<button type="button" class="never-save link"></button>
|
||||
<select class="select-folder" isVaultLocked="false"></select>
|
||||
<button type="button" class="add-save"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inner-wrapper" id="template-change">
|
||||
<div class="change-text"></div>
|
||||
<div class="change-buttons">
|
||||
<button type="button" class="change-save"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="../notification/bar.js"></script></body>
|
||||
|
||||
</html>
|
||||
273
src/iOS.Safari/Resources/notification/bar.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./src/notification/bar.js");
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ({
|
||||
|
||||
/***/ "./src/notification/bar.js":
|
||||
/*!*********************************!*\
|
||||
!*** ./src/notification/bar.js ***!
|
||||
\*********************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(/*! ./bar.scss */ "./src/notification/bar.scss");
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
var i18n = {};
|
||||
var lang = window.navigator.language;
|
||||
|
||||
i18n.appName = chrome.i18n.getMessage('appName');
|
||||
i18n.close = chrome.i18n.getMessage('close');
|
||||
i18n.never = chrome.i18n.getMessage('never');
|
||||
i18n.folder = chrome.i18n.getMessage('folder');
|
||||
i18n.notificationAddSave = chrome.i18n.getMessage('notificationAddSave');
|
||||
i18n.notificationAddDesc = chrome.i18n.getMessage('notificationAddDesc');
|
||||
i18n.notificationChangeSave = chrome.i18n.getMessage('notificationChangeSave');
|
||||
i18n.notificationChangeDesc = chrome.i18n.getMessage('notificationChangeDesc');
|
||||
lang = chrome.i18n.getUILanguage();
|
||||
|
||||
// delay 50ms so that we get proper body dimensions
|
||||
setTimeout(load, 50);
|
||||
|
||||
function load() {
|
||||
const isVaultLocked = getQueryVariable('isVaultLocked') == 'true';
|
||||
document.getElementById('logo').src = isVaultLocked
|
||||
? chrome.runtime.getURL('images/icon38_locked.png')
|
||||
: chrome.runtime.getURL('images/icon38.png');
|
||||
|
||||
document.getElementById('logo-link').title = i18n.appName;
|
||||
|
||||
var neverButton = document.querySelector('#template-add .never-save');
|
||||
neverButton.textContent = i18n.never;
|
||||
|
||||
var selectFolder = document.querySelector('#template-add .select-folder');
|
||||
selectFolder.setAttribute('aria-label', i18n.folder);
|
||||
selectFolder.setAttribute('isVaultLocked', isVaultLocked.toString());
|
||||
|
||||
var addButton = document.querySelector('#template-add .add-save');
|
||||
addButton.textContent = i18n.notificationAddSave;
|
||||
|
||||
var changeButton = document.querySelector('#template-change .change-save');
|
||||
changeButton.textContent = i18n.notificationChangeSave;
|
||||
|
||||
var closeIcon = document.getElementById('close');
|
||||
closeIcon.src = chrome.runtime.getURL('images/close.png');
|
||||
closeIcon.alt = i18n.close;
|
||||
|
||||
var closeButton = document.getElementById('close-button')
|
||||
closeButton.title = i18n.close;
|
||||
closeButton.setAttribute('aria-label', i18n.close);
|
||||
|
||||
document.querySelector('#template-add .add-text').textContent = i18n.notificationAddDesc;
|
||||
document.querySelector('#template-change .change-text').textContent = i18n.notificationChangeDesc;
|
||||
|
||||
if (getQueryVariable('add')) {
|
||||
setContent(document.getElementById('template-add'));
|
||||
|
||||
var addButton = document.querySelector('#template-add-clone .add-save'),
|
||||
neverButton = document.querySelector('#template-add-clone .never-save');
|
||||
|
||||
addButton.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const folderId = document.querySelector('#template-add-clone .select-folder').value;
|
||||
|
||||
const bgAddSaveMessage = {
|
||||
command: 'bgAddSave',
|
||||
folder: folderId,
|
||||
};
|
||||
sendPlatformMessage(bgAddSaveMessage);
|
||||
});
|
||||
|
||||
neverButton.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
sendPlatformMessage({
|
||||
command: 'bgNeverSave'
|
||||
});
|
||||
});
|
||||
|
||||
if (!isVaultLocked) {
|
||||
const responseFoldersCommand = 'notificationBarGetFoldersList';
|
||||
chrome.runtime.onMessage.addListener((msg) => {
|
||||
if (msg.command === responseFoldersCommand && msg.data) {
|
||||
fillSelectorWithFolders(msg.data.folders);
|
||||
}
|
||||
});
|
||||
sendPlatformMessage({
|
||||
command: 'bgGetDataForTab',
|
||||
responseCommand: responseFoldersCommand
|
||||
});
|
||||
}
|
||||
} else if (getQueryVariable('change')) {
|
||||
setContent(document.getElementById('template-change'));
|
||||
var changeButton = document.querySelector('#template-change-clone .change-save');
|
||||
changeButton.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const bgChangeSaveMessage = {
|
||||
command: 'bgChangeSave'
|
||||
};
|
||||
sendPlatformMessage(bgChangeSaveMessage);
|
||||
});
|
||||
}
|
||||
|
||||
closeButton.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
sendPlatformMessage({
|
||||
command: 'bgCloseNotificationBar'
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("resize", adjustHeight);
|
||||
adjustHeight();
|
||||
}
|
||||
|
||||
function getQueryVariable(variable) {
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split('&');
|
||||
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split('=');
|
||||
if (pair[0] === variable) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function setContent(element) {
|
||||
const content = document.getElementById('content');
|
||||
while (content.firstChild) {
|
||||
content.removeChild(content.firstChild);
|
||||
}
|
||||
|
||||
var newElement = element.cloneNode(true);
|
||||
newElement.id = newElement.id + '-clone';
|
||||
content.appendChild(newElement);
|
||||
}
|
||||
|
||||
function sendPlatformMessage(msg) {
|
||||
chrome.runtime.sendMessage(msg);
|
||||
}
|
||||
|
||||
function fillSelectorWithFolders(folders) {
|
||||
const select = document.querySelector('#template-add-clone .select-folder');
|
||||
select.appendChild(new Option(chrome.i18n.getMessage('selectFolder'), null, true));
|
||||
folders.forEach((folder) => {
|
||||
//Select "No Folder" (id=null) folder by default
|
||||
select.appendChild(new Option(folder.name, folder.id || '', false));
|
||||
});
|
||||
}
|
||||
|
||||
function adjustHeight() {
|
||||
sendPlatformMessage({
|
||||
command: 'bgAdjustNotificationBar',
|
||||
data: {
|
||||
height: document.querySelector('body').scrollHeight
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/notification/bar.scss":
|
||||
/*!***********************************!*\
|
||||
!*** ./src/notification/bar.scss ***!
|
||||
\***********************************/
|
||||
/*! no exports provided */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
// extracted by mini-css-extract-plugin
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||