
├── background.html ├── css ├── bootstrap.css ├── content-script.css ├── custom.css ├── iframe.css └── options.css ├── iframe.html ├── img ├── checkmark.png ├── disabled.png ├── enabled.png ├── expand.png ├── home.png ├── icon128.png ├── icon16.png ├── icon48.png ├── options.png ├── shrink.png ├── switch-screenshot.png └── title.png ├── js ├── background.js ├── chrome │ ├── messages.js │ └── url.js ├── content-script.js ├── core │ ├── flower-password.js │ ├── hsimp.cp.js │ └── hsimp.js ├── iframe.js ├── libs │ ├── domain.js │ ├── jquery.js │ ├── md5.js │ └── utils.js ├── options.js ├── options │ ├── base.js │ ├── content-script.js │ ├── global.js │ ├── iframe.js │ └── local.js └── page.js ├── manifest.json └── options.html /background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /css/content-script.css: -------------------------------------------------------------------------------- 1 | #flower-password-iframe { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | position: absolute; 6 | width: 0; 7 | height: 0; 8 | z-index: 999999999; 9 | } 10 | 11 | #flower-password-iframe.transparent { 12 | opacity: 0.5; 13 | } 14 | 15 | #flower-password-iframe.transparent:hover, #flower-password-iframe.transparent.nontransparent { 16 | opacity: 1.0; 17 | } -------------------------------------------------------------------------------- /css/custom.css: -------------------------------------------------------------------------------- 1 | body { 2 | font: 14px/1.5 Tahoma, Helvetica, Arial, \5b8b\4f53; 3 | color: #000; 4 | } 5 | 6 | label { 7 | font-size: 14px; 8 | margin-bottom: 0; 9 | } 10 | 11 | input { 12 | font-size: 14px; 13 | font-family: inherit; 14 | padding: 5px; 15 | } 16 | 17 | .checkbox { 18 | padding-left: 10px; 19 | } 20 | 21 | .checkbox input[type="checkbox"] { 22 | width: 15px; 23 | height: 15px; 24 | margin: 2px 10px 0 0; 25 | border-radius: 3px; 26 | -webkit-appearance: none; 27 | } 28 | 29 | .checkbox input[type="checkbox"]:checked:after { 30 | content: url(../img/checkmark.png); 31 | bottom: 1px; 32 | position: relative; 33 | } 34 | 35 | .form-horizontal .control-label { 36 | width: 60px; 37 | padding-top: 6px; 38 | } 39 | 40 | .form-horizontal .controls { 41 | margin-left: 70px; 42 | } -------------------------------------------------------------------------------- /css/iframe.css: -------------------------------------------------------------------------------- 1 | body { 2 | overflow: hidden; 3 | } 4 | 5 | #main { 6 | width: 250px; 7 | padding: 10px; 8 | border: 2px solid #08C; 9 | position: relative; 10 | line-height: 1; 11 | } 12 | 13 | #close { 14 | border: 2px solid #08C; 15 | font-weight: bold; 16 | color: #FFF; 17 | background: #08C; 18 | width: 16px; 19 | height: 16px; 20 | overflow: hidden; 21 | position: absolute; 22 | top: -2px; 23 | right: -2px; 24 | cursor: pointer; 25 | } 26 | 27 | #close:before { 28 | text-align: center; 29 | line-height: 16px; 30 | content: "\D7"; 31 | display: block; 32 | width: 16px; 33 | height: 16px; 34 | position: relative; 35 | top: -1px; 36 | } 37 | 38 | #title { 39 | cursor: move; 40 | } 41 | 42 | .control-group.first { 43 | margin-top: 12px; 44 | } 45 | 46 | .form-horizontal .control-group { 47 | margin-bottom: 10px; 48 | } 49 | 50 | .control-group.info > label, 51 | .control-group.info .help-block, 52 | .control-group.info .help-inline { 53 | color: #3a87ad; 54 | } 55 | .control-group.info input, 56 | .control-group.info select, 57 | .control-group.info textarea { 58 | color: #3a87ad; 59 | border-color: #3a87ad; 60 | } 61 | .control-group.info input:focus, 62 | .control-group.info select:focus, 63 | .control-group.info textarea:focus { 64 | border-color: #2d6987; 65 | } 66 | 67 | input { 68 | width: 160px; 69 | } 70 | 71 | #key.default { 72 | color: #888; 73 | } 74 | 75 | #key.last { 76 | background: #FAFFBD; 77 | } 78 | 79 | p, ul, li, #toolbar { 80 | margin: 0; 81 | font-size: 12px; 82 | font-family: inherit; 83 | } 84 | 85 | .alert { 86 | position: relative; 87 | margin: 12px 0 0; 88 | padding: 8px; 89 | } 90 | 91 | .alert.with-arrow { 92 | margin: 16px 0 0; 93 | } 94 | 95 | .alert .arrow { 96 | position: absolute; 97 | top: -12px; 98 | left: 180px; 99 | width: 24px; 100 | height: 13px; 101 | overflow: hidden; 102 | } 103 | 104 | .alert .arrow:after { 105 | content: ""; 106 | position: absolute; 107 | left: 3px; 108 | top: 4px; 109 | width: 16px; 110 | height: 16px; 111 | background-color: #FCF8E3; 112 | border: 1px solid #FBEED5; 113 | -webkit-transform: rotate(45deg); 114 | } 115 | 116 | .alert-error .arrow:after { 117 | background-color: #F2DEDE; 118 | border-color: #EED3D7; 119 | } 120 | 121 | .alert-info .arrow:after { 122 | background-color: #D9EDF7; 123 | border-color: #BCE8F1; 124 | } 125 | 126 | .alert-success .arrow:after { 127 | background-color: #DFF0D8; 128 | border-color: #D6E9C6; 129 | } 130 | 131 | .alert .close { 132 | right: -2px; 133 | top: -6px; 134 | font-size: inherit; 135 | } 136 | 137 | .alert-heading { 138 | display: block; 139 | margin-bottom: 5px; 140 | } 141 | 142 | .alert .message-list { 143 | list-style-position: inside; 144 | } 145 | 146 | a { 147 | cursor: pointer; 148 | } 149 | 150 | a img { 151 | vertical-align: middle; 152 | margin-right: 4px; 153 | } 154 | 155 | #toolbar { 156 | text-align: right; 157 | } 158 | 159 | #toolbar a { 160 | margin-left: 10px; 161 | } 162 | 163 | span.help { 164 | border-bottom: 1px dotted; 165 | cursor: help; 166 | } -------------------------------------------------------------------------------- /css/options.css: -------------------------------------------------------------------------------- 1 | body { 2 | text-align: center; 3 | } 4 | 5 | header { 6 | width: 540px; 7 | height: 50px; 8 | margin: 0 auto; 9 | text-align: left; 10 | border-bottom: 2px solid #08C; 11 | } 12 | 13 | header h1 { 14 | line-height: 48px; 15 | font-size: 32px; 16 | color: #08C; 17 | } 18 | 19 | #main { 20 | width: 540px; 21 | margin: 0 auto; 22 | text-align: left; 23 | } 24 | 25 | .control-group:first-child { 26 | margin-top: 18px; 27 | } 28 | 29 | p { 30 | font-size: 12px; 31 | font-family: inherit; 32 | color: #999; 33 | margin-bottom: 18px; 34 | text-align: left; 35 | } 36 | 37 | .center { 38 | text-align: center; 39 | } 40 | 41 | footer { 42 | margin: 18px auto; 43 | border-top: 2px solid #08C; 44 | padding: 5px 0 0; 45 | width: 540px; 46 | } -------------------------------------------------------------------------------- /iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 78 | 79 | -------------------------------------------------------------------------------- /img/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/checkmark.png -------------------------------------------------------------------------------- /img/disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/disabled.png -------------------------------------------------------------------------------- /img/enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/enabled.png -------------------------------------------------------------------------------- /img/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/expand.png -------------------------------------------------------------------------------- /img/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/home.png -------------------------------------------------------------------------------- /img/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/icon128.png -------------------------------------------------------------------------------- /img/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/icon16.png -------------------------------------------------------------------------------- /img/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/icon48.png -------------------------------------------------------------------------------- /img/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/options.png -------------------------------------------------------------------------------- /img/shrink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/shrink.png -------------------------------------------------------------------------------- /img/switch-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/switch-screenshot.png -------------------------------------------------------------------------------- /img/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlowerPassword/chrome-extension/4fb647b456fa9bd544ac524f9a185221b929ee81/img/title.png -------------------------------------------------------------------------------- /js/background.js: -------------------------------------------------------------------------------- 1 | function forEachTab(callback) { 2 | chrome.windows.getAll({ populate: true }, function(windows) { 3 | for (var i = 0; i < windows.length; i++) { 4 | var tabs = windows[i].tabs; 5 | if (tabs) { 6 | for (var j = 0; j < tabs.length; j++) { 7 | var tab = tabs[j]; 8 | callback(tab); 9 | } 10 | } 11 | } 12 | }); 13 | } 14 | 15 | function showAllPageActions() { 16 | forEachTab(function(tab) { 17 | updatePageAction(tab); 18 | }); 19 | } 20 | 21 | function updatePageAction(tab) { 22 | chrome.pageAction.hide(tab.id); 23 | messages.extension.sendTo(tab.id, 'getLocalEnabled'); 24 | } 25 | 26 | function notifyOptionsChanged() { 27 | forEachTab(function(tab) { 28 | chrome.pageAction.hide(tab.id); 29 | messages.extension.sendTo(tab.id, 'setGlobalOptions', {value: options.global.cache}); 30 | }); 31 | } 32 | 33 | function setPageEnabled(tab, value) { 34 | var icon; 35 | var title; 36 | if (value) { 37 | icon = 'img/enabled.png'; 38 | title = '单击后将在本网站停用花密'; 39 | } else { 40 | icon = 'img/disabled.png'; 41 | title = '单击后将在本网站启用花密'; 42 | } 43 | chrome.pageAction.setIcon({tabId: tab.id, path: icon}); 44 | chrome.pageAction.setTitle({tabId: tab.id, title: title}); 45 | chrome.pageAction.show(tab.id); 46 | } 47 | 48 | function attachListeners() { 49 | $.extend(messages.extension.handlers, { 50 | getGlobalOptions: function(data, reply) { 51 | reply('setGlobalOptions', {value: options.global.cache}); 52 | }, 53 | setGlobalOption: function(data) { 54 | options.global.set(data.name, data.value); 55 | if (data.name == 'defaultEnabled') { 56 | notifyOptionsChanged(); 57 | } 58 | }, 59 | setLocalEnabled: function(data, reply, sender) { 60 | setPageEnabled(sender.tab, data.value); 61 | }, 62 | copyToClipboard: function(data) { 63 | $('#copy-to-clipboard').val(data.value).get(0).select(); 64 | document.execCommand('copy'); 65 | } 66 | }); 67 | chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { 68 | if (request.transit) { 69 | chrome.tabs.sendMessage(sender.tab.id, request, function(response) { 70 | if (sendResponse) { 71 | sendResponse(response); 72 | sendResponse = null; 73 | } 74 | }); 75 | return true; 76 | } 77 | }); 78 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 79 | if (tab.status == 'loading') { 80 | updatePageAction(tab); 81 | } 82 | }); 83 | chrome.pageAction.onClicked.addListener(function(tab) { 84 | messages.extension.sendTo(tab.id, 'toggleLocalEnabled'); 85 | }); 86 | } 87 | 88 | function init() { 89 | options.init(); 90 | attachListeners(); 91 | showAllPageActions(); 92 | } 93 | 94 | init(); 95 | -------------------------------------------------------------------------------- /js/chrome/messages.js: -------------------------------------------------------------------------------- 1 | var messages = {}; 2 | 3 | (function() { 4 | messages.extension = { 5 | send: function(action, data) { 6 | chrome.extension.sendMessage($.extend({action: action}, data), function(response) { 7 | if (response) { 8 | var handler = messages.extension.handlers[response.action]; 9 | if (handler) { 10 | handler(response); 11 | } 12 | } 13 | }); 14 | }, 15 | sendTo: function(tab, action, data) { 16 | chrome.tabs.sendMessage(tab, $.extend({action: action}, data), function(response) { 17 | if (response) { 18 | var handler = messages.extension.handlers[response.action]; 19 | if (handler) { 20 | handler(response, function(){}, {tab: {id: tab}}); 21 | } 22 | } 23 | }); 24 | }, 25 | handlers: {} 26 | }; 27 | 28 | messages.page = { 29 | broadcast: function(action, data) { 30 | chrome.extension.sendMessage($.extend({action: action, transit: true}, data), function(){}); 31 | }, 32 | sendTo: function(target, action, data) { 33 | target.postMessage($.extend({action: action, flowerPassword: true}, data), '*'); 34 | }, 35 | sendToTop: function(action, data) { 36 | if (window.top) { 37 | messages.page.sendTo(window.top, action, data); 38 | } else { 39 | chrome.extension.sendMessage($.extend({action: action, transit: true}, data), function(response) { 40 | if (response) { 41 | var handler = messages.page.handlers[response.action]; 42 | if (handler) { 43 | handler(response); 44 | } 45 | } 46 | }); 47 | } 48 | }, 49 | handlers: {} 50 | }; 51 | 52 | messages.all = { 53 | broadcast: function(action, data) { 54 | messages.extension.send(action, data); 55 | messages.page.broadcast(action, data); 56 | } 57 | }; 58 | 59 | chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { 60 | var handler = null; 61 | if (request.transit) { 62 | handler = messages.page.handlers[request.action]; 63 | } else { 64 | handler = messages.extension.handlers[request.action]; 65 | } 66 | if (handler) { 67 | var replied = false; 68 | handler(request, function(action, data) { 69 | replied = true; 70 | sendResponse($.extend({action: action}, data)); 71 | }, sender); 72 | if (!replied) { 73 | sendResponse({}); 74 | } 75 | } 76 | }); 77 | 78 | $(window).on('message', function(e) { 79 | var data = e.originalEvent.data; 80 | if (typeof data === 'object' && data.flowerPassword) { 81 | var handler = messages.page.handlers[data.action]; 82 | if (handler) { 83 | handler(data, function(){}); 84 | } 85 | } 86 | }); 87 | })(); 88 | -------------------------------------------------------------------------------- /js/chrome/url.js: -------------------------------------------------------------------------------- 1 | var getURL = chrome.extension.getURL; -------------------------------------------------------------------------------- /js/content-script.js: -------------------------------------------------------------------------------- 1 | var current = {field: null, left: 0, top: 0, width: 0, height: 0}; 2 | var events = { 3 | onFocusInPassword: new OnEvent(), 4 | onFocusOutPassword: new OnEvent(), 5 | onKeyDown: new OnEvent(), 6 | onResize: new OnEvent() 7 | }; 8 | var showIframe, closeIframe, focusIframe, locateIframe; 9 | 10 | function setupListeners() { 11 | if (options.isEnabled()) { 12 | $(document).on('focus.fp', 'input:password', function() { 13 | events.onFocusInPassword.fireEvent(this); 14 | }) 15 | .on('focusin.fp mousedown.fp', function(e) { 16 | if (!$(e.target).is('input:password')) { 17 | events.onFocusOutPassword.fireEvent(); 18 | } 19 | }) 20 | .on('keydown.fp', function(e) { 21 | events.onKeyDown.fireEvent(e); 22 | }); 23 | 24 | $(window).on('resize.fp', function() { 25 | events.onResize.fireEvent(); 26 | }); 27 | 28 | $('input:password:focus').focus(); 29 | } else { 30 | $(document).off('.fp'); 31 | $(window).off('.fp'); 32 | } 33 | } 34 | 35 | events.onFocusInPassword.addListener(function(field) { 36 | if (!current.field || current.field[0] !== field) { 37 | messages.page.broadcast('setupIframe', {options: options.local.cache, domain: $.getDomain()}); 38 | } 39 | current.field = $(field); 40 | }); 41 | 42 | if (isTopWindow()) { 43 | (function() { 44 | function updateCurrentFieldBounds(bounds) { 45 | if (isUndefined(bounds)) { 46 | var width = current.field.outerWidth(); 47 | var height = current.field.outerHeight(); 48 | var offset = current.field.offset(); 49 | $.extend(current, {left: offset.left, top: offset.top, width: width, height: height}); 50 | } else { 51 | $.extend(current, {left: bounds.left, top: bounds.top, width: bounds.width, height: bounds.height}); 52 | } 53 | } 54 | 55 | showIframe = function(bounds) { 56 | updateCurrentFieldBounds(bounds); 57 | locateDialog(); 58 | $('#flower-password-iframe').show(); 59 | }; 60 | closeIframe = function(focusCurrentField) { 61 | if ($('#flower-password-iframe').is(':visible')) { 62 | $('#flower-password-iframe').hide(); 63 | messages.page.broadcast('iframeClosed', {focusCurrentField: focusCurrentField}); 64 | } 65 | }; 66 | focusIframe = function() { 67 | if ($('#flower-password-iframe').is(':visible')) { 68 | messages.page.broadcast('focusPassword'); 69 | } 70 | }; 71 | locateIframe = function(bounds) { 72 | updateCurrentFieldBounds(bounds); 73 | if ($('#flower-password-iframe').is(':visible')) { 74 | locateDialog(); 75 | } 76 | }; 77 | 78 | events.onResize.addListener(function() { 79 | if (current.field) { 80 | locateIframe(); 81 | } else { 82 | messages.page.broadcast('windowResized'); 83 | } 84 | }); 85 | 86 | function calculateDialogOffset() { 87 | var result; 88 | if (current.left - $(document).scrollLeft() + current.width + $('#flower-password-iframe').outerWidth() <= $(window).width()) { 89 | result = {left: current.left + current.width, top: current.top}; 90 | } else { 91 | result = {left: current.left, top: current.top + current.height}; 92 | } 93 | return result; 94 | } 95 | 96 | var dialogOffset = null; 97 | function locateDialog(offset) { 98 | if (!offset) { 99 | offset = calculateDialogOffset(); 100 | } 101 | $('#flower-password-iframe').css({left: offset.left + "px", top: offset.top + "px"}); 102 | dialogOffset = offset; 103 | } 104 | 105 | function injectIframe() { 106 | if ($('#flower-password-iframe').size() > 0) { 107 | return; 108 | } 109 | $('body').append(''); 110 | if (options.isTransparent()) { 111 | $('#flower-password-iframe').addClass('transparent'); 112 | } 113 | } 114 | 115 | options.onIframeReady.addListener(setupListeners); 116 | options.onReady.addListener(function() { 117 | injectIframe(); 118 | }); 119 | options.onSetEnabled.addListener(function() { 120 | if (!options.isEnabled()) { 121 | closeIframe(); 122 | } 123 | }); 124 | 125 | $.extend(messages.page.handlers, { 126 | iframeReady: function() { 127 | options.onIframeReady.fireEventOnce(); 128 | }, 129 | closeIframe: function(data) { 130 | closeIframe(data.focusCurrentField); 131 | }, 132 | setIframeSize: function(data) { 133 | $('#flower-password-iframe').width(data.width).height(data.height); 134 | if (data.locate) locateDialog(); 135 | }, 136 | focusinIframe: function() { 137 | $('#flower-password-iframe').addClass('nontransparent'); 138 | }, 139 | focusoutIframe: function() { 140 | $('#flower-password-iframe').removeClass('nontransparent'); 141 | }, 142 | moveIframe: function(data) { 143 | locateDialog({left: dialogOffset.left + data.dx, top: dialogOffset.top + data.dy}); 144 | }, 145 | focusIframe: function() { 146 | focusIframe(); 147 | }, 148 | receiveMessage: function(data) { 149 | if (data.message === 'showIframe') { 150 | showIframe(data); 151 | } else if (data.message === 'locateIframe') { 152 | locateIframe(data); 153 | } 154 | } 155 | }); 156 | })(); 157 | } // endif (isTopWindow()) 158 | 159 | if (isIframe()) { 160 | (function() { 161 | function getCurrentFieldBounds() { 162 | var width = current.field.outerWidth(); 163 | var height = current.field.outerHeight(); 164 | var box = current.field[0].getBoundingClientRect(); 165 | return {left: box.left, top: box.top, width: width, height: height}; 166 | } 167 | 168 | showIframe = function() { 169 | messages.page.sendTo(window, 'startMessage', $.extend({message: 'showIframe'}, getCurrentFieldBounds())); 170 | }; 171 | closeIframe = function() { 172 | messages.page.sendToTop('closeIframe'); 173 | }; 174 | focusIframe = function() { 175 | messages.page.sendToTop('focusIframe'); 176 | }; 177 | locateIframe = function() { 178 | messages.page.sendTo(window, 'startMessage', $.extend({message: 'locateIframe'}, getCurrentFieldBounds())); 179 | }; 180 | 181 | $.extend(messages.page.handlers, { 182 | windowResized: function() { 183 | if (current.field) { 184 | locateIframe(); 185 | } 186 | } 187 | }); 188 | })(); 189 | } // endif (isIframe()) 190 | 191 | // commons for top window and iframes 192 | (function() { 193 | events.onFocusInPassword.addListener(function() { 194 | showIframe(); 195 | }); 196 | events.onFocusOutPassword.addListener(function() { 197 | closeIframe(); 198 | }); 199 | events.onKeyDown.addListener(function(e) { 200 | if (e.matchKey(87, {alt: true})) { 201 | closeIframe(); 202 | } else if (e.matchKey(83, {alt: true})) { 203 | focusIframe(); 204 | } 205 | }); 206 | 207 | $.extend(messages.page.handlers, { 208 | iframeClosed: function(data) { 209 | if (data.focusCurrentField && current.field) { 210 | events.onFocusInPassword.disable(); 211 | current.field.focus(); 212 | events.onFocusInPassword.enable(); 213 | } 214 | current.field = null; 215 | }, 216 | setCurrentFieldValue: function(data) { 217 | if (current.field) { 218 | current.field.valLimited(data.value); 219 | } 220 | } 221 | }); 222 | 223 | options.onSetEnabled.addListener(setupListeners); 224 | 225 | function injectPageScript() { 226 | var script = document.createElement('script'); 227 | script.setAttribute('type', 'text/javascript'); 228 | script.setAttribute('src', getURL('js/page.js')); 229 | document.head.appendChild(script); 230 | } 231 | injectPageScript(); 232 | 233 | options.init(); 234 | })(); -------------------------------------------------------------------------------- /js/core/flower-password.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function countCode(password, key){ 3 | if(password && key){ 4 | var md5one = $.md5(password,key); 5 | var md5two = $.md5(md5one,'snow'); 6 | var md5three = $.md5(md5one,'kise'); 7 | //计算大小写 8 | var rule = md5three.split(""); 9 | var source = md5two.split(""); 10 | for(var i=0;i<=31;i++){ 11 | if(isNaN(source[i])){ 12 | var str ="sunlovesnow1990090127xykab"; 13 | if(str.search(rule[i]) > -1){ 14 | source[i] = source[i].toUpperCase(); 15 | } 16 | } 17 | } 18 | var code32 = source.join(""); 19 | var code1 = code32.slice(0,1); 20 | if(isNaN(code1)){ 21 | var code16 = code32.slice(0,16); 22 | }else{ 23 | var code16 = "K" + code32.slice(1,16); 24 | } 25 | return [code16, code32]; 26 | } 27 | } 28 | 29 | window.flowerPassword = { 30 | encrypt: function(password, key) { 31 | var result = countCode(password, key); 32 | return result && result[0]; 33 | } 34 | }; 35 | })(); 36 | -------------------------------------------------------------------------------- /js/core/hsimp.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var hsimp = window.hsimp = {}; 3 | var levels = hsimp.levels = { 4 | weak: 0, normal: 1, strong: 2 5 | }; 6 | 7 | hsimp.check = function(password) { 8 | var result = { 9 | level: levels.strong, 10 | messages: [] 11 | }; 12 | for (var i in hsimp.checks) { 13 | var r = hsimp.checks[i](password); 14 | if (!isUndefined(r)) { 15 | result.level = Math.min(r.level, result.level); 16 | result.messages.push(r.message); 17 | } 18 | } 19 | return result; 20 | }; 21 | hsimp.checks = { 22 | 'Common Password': function (password) { 23 | if (hsimp.commonPasswords[password]) { 24 | return { 25 | level: levels.weak, 26 | message: '该密码是常用密码之一,可被瞬间破解' 27 | }; 28 | } 29 | }, 30 | 'Length': function (password) { 31 | if (password.length < 5) { 32 | return { 33 | level: levels.weak, 34 | message: '该密码太短,请使用8位或以上的密码' 35 | }; 36 | } else if (password.length < 8) { 37 | return { 38 | level: levels.normal, 39 | message: '该密码比较短,请使用8位或以上的密码' 40 | }; 41 | } 42 | }, 43 | 'Character Variety': function (password) { 44 | if (password.match(/^[A-Za-z]+$/)) { 45 | return { 46 | level: levels.normal, 47 | message: '该密码只包含字母,加入数字和符号可提高强度' 48 | }; 49 | } else if (password.match(/^[0-9]+$/)) { 50 | return { 51 | level: levels.normal, 52 | message: '该密码只包含数字,加入字母和符号可提高强度' 53 | }; 54 | } else if (password.match(/^[A-Za-z0-9]+$/)) { 55 | return { 56 | level: levels.normal, 57 | message: '该密码只包含数字和字母,加入符号可提高强度' 58 | }; 59 | } 60 | }, 61 | 'Repeated Pattern': function (password) { 62 | if (password.match(/(.+)\1{2,}/gi)) { 63 | return { 64 | level: levels.weak, 65 | message: '该密码包含重复的部分,这使其更容易被破解' 66 | }; 67 | } 68 | }, 69 | 'Possibly a Word': function (password) { 70 | if (password.match(/^[a-zA-Z]+$/)) { 71 | return { 72 | level: levels.weak, 73 | message: '该密码可能是一个单词或一个名字,如果是的话,这将使其很容易被破解' 74 | }; 75 | } 76 | }, 77 | 'Possibly a Telephone Number / Date': function (password) { 78 | if (password.match(/^[\-\(\)\.\/\s0-9]+$/)) { 79 | return { 80 | level: levels.weak, 81 | message: '该密码可能是一个电话号码或一个日期,如果是的话,这将使其很容易被破解' 82 | }; 83 | } 84 | }, 85 | 'Possibly a Word and a Number': function (password) { 86 | if (password.match(/^[a-zA-Z]+[0-9]+$/) || password.match(/^[0-9]+[a-zA-Z]+$/)) { 87 | return { 88 | level: levels.weak, 89 | message: '该密码可能是一个单词和几个数字的组合,这是很常见的模式,因此可以被快速的破解' 90 | }; 91 | } 92 | } 93 | }; 94 | })(); -------------------------------------------------------------------------------- /js/iframe.js: -------------------------------------------------------------------------------- 1 | $.fn.hideAndNotify = function() { 2 | if (this.is(':visible')) { 3 | this.hide(); 4 | adjustIframeSize(); 5 | } 6 | }; 7 | 8 | $.fn.showAndNotify = function() { 9 | if (!this.is(':visible')) { 10 | this.show(); 11 | adjustIframeSize(); 12 | } 13 | }; 14 | 15 | var domain = ''; 16 | function getDefaultKey() { 17 | var value = domain; 18 | if (options.isAppendScramble()) { 19 | value += options.getScramble(); 20 | } 21 | return value; 22 | } 23 | 24 | function fillKey(reset) { 25 | $("#key").removeClass('last default'); 26 | $('#key').parents('.control-group').removeClass('warning'); 27 | $("#no-maxlength").hideAndNotify(); 28 | if (options.hasLastKey()) { 29 | var value = options.getLastKey(); 30 | $("#key").valLimited(value).change().addClass('last'); 31 | 32 | if (options.isFillKeyWithDomain()) { 33 | var defaultKey = getDefaultKey(); 34 | if (value.length == 15 && defaultKey.length > 15 && defaultKey.indexOf(value) == 0) { 35 | $('#key').parents('.control-group').addClass('warning'); 36 | $("#no-maxlength").showAndNotify(); 37 | } 38 | } 39 | 40 | } else if (options.isFillKeyWithDomain()) { 41 | var value = getDefaultKey(); 42 | $("#key").valLimited(value).change().addClass('default'); 43 | } else if (reset) { 44 | $("#key").val(''); 45 | } 46 | } 47 | 48 | function fillDefaultKey() { 49 | options.removeLastKey(); 50 | fillKey(); 51 | } 52 | 53 | function adjustIframeSize(locate) { 54 | var width = $('#main').outerWidth(); 55 | var height = $('#main').outerHeight(); 56 | messages.page.sendToTop('setIframeSize', {width: width, height: height, locate: locate}); 57 | } 58 | 59 | function setupScrambleField() { 60 | if (options.isAppendScramble() && options.getScramble() == '') { 61 | $('#scramble').val(options.getScramble()); 62 | $('#scramble-field').showAndNotify(); 63 | } else { 64 | $('#scramble-field').hideAndNotify(); 65 | } 66 | }; 67 | 68 | options.onReady.addListener(function() { 69 | if (options.accessLocalStorageFailed) { 70 | $('.extension-id').html(chrome.i18n.getMessage("@@extension_id")); 71 | $('#write-local-storage-failed').show(); 72 | } 73 | 74 | if (options.isTransparent()) { 75 | $('#main').focusin(function() { 76 | messages.page.sendToTop('focusinIframe'); 77 | }).focusout(function() { 78 | messages.page.sendToTop('focusoutIframe'); 79 | }); 80 | } 81 | 82 | $('#close').click(function() { 83 | messages.page.sendToTop('closeIframe'); 84 | }); 85 | 86 | var mousedownOffset = null; 87 | function moveIframe(e) { 88 | messages.page.sendToTop('moveIframe', {dx: e.pageX - mousedownOffset.x, dy: e.pageY - mousedownOffset.y}); 89 | } 90 | $('#title').mousedown(function(e) { 91 | if (e.button == 0) { 92 | mousedownOffset = {x: e.pageX, y: e.pageY}; 93 | e.preventDefault(); 94 | } 95 | }); 96 | $(document).on('mouseup', function(e) { 97 | if (mousedownOffset) { 98 | moveIframe(e); 99 | mousedownOffset = null; 100 | e.preventDefault(); 101 | } 102 | }) 103 | .on('mousemove', function(e) { 104 | if (mousedownOffset) { 105 | moveIframe(e); 106 | e.preventDefault(); 107 | } 108 | }); 109 | 110 | $('#password, #key').change(function() { 111 | var password = $("#password").val(); 112 | var key = $("#key").val(); 113 | var result = flowerPassword.encrypt(password, key); 114 | if (result) { 115 | messages.page.broadcast('setCurrentFieldValue', {value: result}); 116 | if (options.isCopyToClipboard()) { 117 | messages.extension.send('copyToClipboard', {value: result}); 118 | } 119 | } 120 | }).keyup(function(e) { 121 | if (e.matchKey(13) || e.matchKey(27)) { 122 | messages.page.sendToTop('closeIframe', {focusCurrentField: true}); 123 | } else { 124 | $(this).change(); 125 | } 126 | }); 127 | 128 | $('#password').change(function() { 129 | if (options.isCheckPasswordStrength()) { 130 | var e = $(this); 131 | e.prop('title', ''); 132 | e.parents('.control-group').removeClass('error info success'); 133 | $('#password-strength').removeClass('alert-error alert-info').hideAndNotify(); 134 | var password = e.val(); 135 | if (password) { 136 | var result = hsimp.check(password); 137 | 138 | var messages = ''; 139 | for (var i = 0; i < result.messages.length; ++i) { 140 | messages += 't |