From e67b46d7256cb11b20916db3b65c97456f457d57 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 18 Aug 2016 19:03:25 +0800 Subject: [PATCH 01/10] Add Autofill support fix #860 auditors: @bridiver, @bbondy --- app/extensions/brave/about-autofill.html | 19 ++ .../brave/locales/en-US/app.properties | 12 ++ .../brave/locales/en-US/autofill.properties | 19 ++ .../locales/en-US/preferences.properties | 3 + app/filtering.js | 53 +++++ app/index.js | 10 + js/about/aboutActions.js | 28 +++ js/about/autofill.js | 204 ++++++++++++++++++ js/about/entry.js | 3 + js/about/preferences.js | 8 + js/actions/appActions.js | 30 +++ js/actions/windowActions.js | 22 ++ js/components/autofillAddressPanel.js | 151 +++++++++++++ js/components/autofillCreditCardPanel.js | 112 ++++++++++ js/components/frame.js | 28 +++ js/components/main.js | 34 +++ js/constants/appConfig.js | 1 + js/constants/appConstants.js | 4 + js/constants/messages.js | 8 + js/constants/settings.js | 2 + js/constants/windowConstants.js | 4 +- js/contextMenus.js | 39 ++++ js/lib/appUrlUtil.js | 3 +- js/state/privacy.js | 34 +++ js/stores/appStore.js | 62 ++++++ js/stores/windowStore.js | 24 +++ less/about/autofill.less | 59 +++++ less/about/preferences.less | 6 + less/forms.less | 28 +++ 29 files changed, 1008 insertions(+), 2 deletions(-) create mode 100644 app/extensions/brave/about-autofill.html create mode 100644 app/extensions/brave/locales/en-US/autofill.properties create mode 100644 js/about/autofill.js create mode 100644 js/components/autofillAddressPanel.js create mode 100644 js/components/autofillCreditCardPanel.js create mode 100644 js/state/privacy.js create mode 100644 less/about/autofill.less diff --git a/app/extensions/brave/about-autofill.html b/app/extensions/brave/about-autofill.html new file mode 100644 index 00000000000..40ec9641bcf --- /dev/null +++ b/app/extensions/brave/about-autofill.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + +
+ + diff --git a/app/extensions/brave/locales/en-US/app.properties b/app/extensions/brave/locales/en-US/app.properties index 45e86970e4b..66a53161949 100644 --- a/app/extensions/brave/locales/en-US/app.properties +++ b/app/extensions/brave/locales/en-US/app.properties @@ -177,3 +177,15 @@ allSiteCookies=All site cookies clear=Clear clearDataWarning=Warning: Selected data, back to the day you installed Brave will be cleared and cannot be undone. clearBrowsingData=Clear browsing data +nameOnCard=Name +creditCardNumber=Card Number +expirationDate=Expiration date +nameOnAddress=Name +organization=Organization +streetAddress=Street Address +city=City +state=State +postalCode=Postal Code +country=Country +phone=Phone +email=Email diff --git a/app/extensions/brave/locales/en-US/autofill.properties b/app/extensions/brave/locales/en-US/autofill.properties new file mode 100644 index 00000000000..5c9bc2ad7c8 --- /dev/null +++ b/app/extensions/brave/locales/en-US/autofill.properties @@ -0,0 +1,19 @@ +autofillTitle=Autofill Settings +addresses=Addresses +creditCards=Credit Cards +addAddress=Add Address +addCreditCard=Add Credit Card +nameOnCard=Name on card +creditCardNumber=Credit card number +expirationDate=Expiration date +noCreditCardsSaved=No saved credit cards +nameOnAddress=Name +organization=Organization +streetAddress=Street Address +city=City +state=State +postalCode=Postal Code +country=Country +phone=Phone +email=Email +noAddressesSaved=No saved addresses diff --git a/app/extensions/brave/locales/en-US/preferences.properties b/app/extensions/brave/locales/en-US/preferences.properties index 281f1bce6c6..d58d2bd9b46 100644 --- a/app/extensions/brave/locales/en-US/preferences.properties +++ b/app/extensions/brave/locales/en-US/preferences.properties @@ -172,3 +172,6 @@ allSiteCookies=All site cookies passwordsAndForms=Passwords and Forms tabSettings=Tab Settings clearBrowsingDataNow=Clear Browsing Data Now... +autofillSettings=Autofill Settings +manageAutofillData=Manage Autofill Data... +enableAutofill=Enable Autofill diff --git a/app/filtering.js b/app/filtering.js index aa1b38b5e8d..a7804619a14 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -579,3 +579,56 @@ module.exports.setDefaultZoomLevel = (zoom) => { ses.userPrefs.setDefaultZoomLevel(zoom) } } + +module.exports.addAutofillAddress = (detail) => { + let guidMap = {} + for (let partition in registeredSessions) { + let ses = registeredSessions[partition] + let guid = ses.autofill.addProfile({ + full_name: detail.name, + company_name: detail.organization, + street_address: detail.streetAddress, + city: detail.city, + state: detail.state, + postal_code: detail.postalCode, + country_code: detail.country, + phone: detail.phone, + email: detail.email + }) + guidMap[partition] = guid + } + return guidMap +} + +module.exports.removeAutofillAddress = (guid) => { + for (let partition in registeredSessions) { + let ses = registeredSessions[partition] + if (guid[partition] !== undefined) { + ses.autofill.removeProfile(guid[partition]) + } + } +} + +module.exports.addAutofillCreditCard = (detail) => { + let guidMap = {} + for (let partition in registeredSessions) { + let ses = registeredSessions[partition] + let guid = ses.autofill.addCreditCard({ + name: detail.name, + card_number: detail.card, + expiration_month: detail.month, + expiration_year: detail.year + }) + guidMap[partition] = guid + } + return guidMap +} + +module.exports.removeAutofillCreditCard = (guid) => { + for (let partition in registeredSessions) { + let ses = registeredSessions[partition] + if (guid[partition] !== undefined) { + ses.autofill.removeCreditCard(guid[partition]) + } + } +} diff --git a/app/index.js b/app/index.js index 1cdf424618d..c895214f734 100644 --- a/app/index.js +++ b/app/index.js @@ -61,6 +61,7 @@ const spellCheck = require('./spellCheck') const ledger = require('./ledger') const flash = require('../js/flash') const contentSettings = require('../js/state/contentSettings') +const privacy = require('../js/state/privacy') // Used to collect the per window state when shutting down the application let perWindowState = [] @@ -392,6 +393,7 @@ app.on('ready', () => { return loadedPerWindowState }).then((loadedPerWindowState) => { contentSettings.init() + privacy.init() Extensions.init() Filtering.init() SiteHacks.init() @@ -747,6 +749,14 @@ app.on('ready', () => { } }) + ipcMain.on(messages.REMOVE_AUTOFILL_ADDRESS, (e, address) => { + appActions.removeAutofillAddress(address) + }) + + ipcMain.on(messages.REMOVE_AUTOFILL_CREDIT_CARD, (e, card) => { + appActions.removeAutofillCreditCard(card) + }) + // Setup the crash handling CrashHerald.init() diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js index 71eb1886276..bea0fcb2739 100644 --- a/js/about/aboutActions.js +++ b/js/about/aboutActions.js @@ -129,6 +129,34 @@ const AboutActions = { createWallet: function () { ipc.send(messages.LEDGER_CREATE_WALLET) + }, + + setLedgerEnabled: function (enabled) { + ipc.send(messages.LEDGER_ENABLE, enabled) + }, + + addAutofillAddress: function () { + ipc.sendToHost(messages.ADD_AUTOFILL_ADDRESS) + }, + + removeAutofillAddress: function (address) { + ipc.send(messages.REMOVE_AUTOFILL_ADDRESS, address) + }, + + editAutofillAddress: function (address) { + ipc.sendToHost(messages.EDIT_AUTOFILL_ADDRESS, address) + }, + + addAutofillCreditCard: function () { + ipc.sendToHost(messages.ADD_AUTOFILL_CREDIT_CARD) + }, + + removeAutofillCreditCard: function (card) { + ipc.send(messages.REMOVE_AUTOFILL_CREDIT_CARD, card) + }, + + editAutofillCreditCard: function (card) { + ipc.sendToHost(messages.EDIT_AUTOFILL_CREDIT_CARD, card) } } module.exports = AboutActions diff --git a/js/about/autofill.js b/js/about/autofill.js new file mode 100644 index 00000000000..bc4d81a5a76 --- /dev/null +++ b/js/about/autofill.js @@ -0,0 +1,204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const React = require('react') +const messages = require('../constants/messages') +const Immutable = require('immutable') +const ImmutableComponent = require('../components/immutableComponent') +const aboutActions = require('./aboutActions') +const Button = require('../components/button') + +const ipc = window.chrome.ipc + +require('../../less/about/autofill.less') +require('../../node_modules/font-awesome/css/font-awesome.css') + +class AddressItem extends ImmutableComponent { + constructor () { + super() + this.onDelete = this.onDelete.bind(this) + this.onEdit = this.onEdit.bind(this) + } + + onDelete () { + aboutActions.removeAutofillAddress(this.props.address.toJS()) + } + + onEdit () { + aboutActions.editAutofillAddress(this.props.address.toJS()) + } + + render () { + const address = this.props.address + return + + + + + {address.get('name')} + {address.get('organization')} + {address.get('streetAddress')} + {address.get('city')} + {address.get('state')} + {address.get('postalCode')} + {address.get('country')} + {address.get('phone')} + {address.get('email')} + + + + + + } +} + +class CreditCardItem extends ImmutableComponent { + constructor () { + super() + this.onDelete = this.onDelete.bind(this) + this.onEdit = this.onEdit.bind(this) + } + + onDelete () { + aboutActions.removeAutofillCreditCard(this.props.creditCard.toJS()) + } + + onEdit () { + aboutActions.editAutofillCreditCard(this.props.creditCard.toJS()) + } + + render () { + const creditCard = this.props.creditCard + return + + + + + {creditCard.get('name')} + {creditCard.get('card')} + + {creditCard.get('month') + '/' + creditCard.get('year')} + + + + + + + } +} + +class AboutAutofill extends React.Component { + constructor () { + super() + this.state = { + addressesDetails: new Immutable.List(), + creditCardsDetails: new Immutable.List() + } + ipc.on(messages.AUTOFILL_ADDRESSES_UPDATED, (e, detail) => { + if (detail) { + this.setState({ + addressesDetails: Immutable.fromJS(detail) + }) + } + }) + ipc.on(messages.AUTOFILL_CREDIT_CARDS_UPDATED, (e, detail) => { + if (detail) { + this.setState({ + creditCardsDetails: Immutable.fromJS(detail) + }) + } + }) + this.onAddAddress = this.onAddAddress.bind(this) + this.onAddCreditCard = this.onAddCreditCard.bind(this) + } + + onAddAddress () { + aboutActions.addAutofillAddress() + } + + onAddCreditCard () { + aboutActions.addAutofillCreditCard() + } + + get isAddresssEmpty () { + return !this.state.addressesDetails || !this.state.addressesDetails.size + } + + get isCreditCardsEmpty () { + return !this.state.creditCardsDetails || !this.state.creditCardsDetails.size + } + + render () { + var savedAddresssPage = this.isAddresssEmpty + ?
+ :
+

+
+ + + + + + + + + + + + + + + + + { + this.state.addressesDetails.sort((a, b) => { + return a.get('name') > b.get('name') ? 1 : -1 + }).map((item) => + ) + } + +
+
+

+ + var savedCreditCardsPage = this.isCreditCardsEmpty + ?
+ :
+

+
+ + + + + + + + + + + { + this.state.creditCardsDetails.sort((a, b) => { + return a.get('name') > b.get('name') ? 1 : -1 + }).map((item) => + ) + } + +
+
+

+ return
+

+ {savedAddresssPage} +

+ } +} + +module.exports = diff --git a/js/about/entry.js b/js/about/entry.js index 8891698c559..20351284766 100644 --- a/js/about/entry.js +++ b/js/about/entry.js @@ -38,6 +38,9 @@ switch (getBaseUrl(getSourceAboutUrl(window.location.href))) { break case 'about:history': element = require('./history') + break + case 'about:autofill': + element = require('./autofill') } if (element) { diff --git a/js/about/preferences.js b/js/about/preferences.js index c95fb8be1bc..3a692603584 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -835,6 +835,14 @@ class SecurityTab extends ImmutableComponent { : null } +
+ + +
+
+ + + } +} + +module.exports = AutofillAddressPanel diff --git a/js/components/autofillCreditCardPanel.js b/js/components/autofillCreditCardPanel.js new file mode 100644 index 00000000000..0867dc3cdff --- /dev/null +++ b/js/components/autofillCreditCardPanel.js @@ -0,0 +1,112 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const React = require('react') +const ImmutableComponent = require('./immutableComponent') +const Dialog = require('./dialog') +const Button = require('./button') +const windowActions = require('../actions/windowActions') +const appActions = require('../actions/appActions') +const KeyCodes = require('../constants/keyCodes') + +class AutofillCreditCardPanel extends ImmutableComponent { + constructor () { + super() + this.onNameChange = this.onNameChange.bind(this) + this.onCardChange = this.onCardChange.bind(this) + this.onExpMonthChange = this.onExpMonthChange.bind(this) + this.onExpYearChange = this.onExpYearChange.bind(this) + this.onKeyDown = this.onKeyDown.bind(this) + this.onSave = this.onSave.bind(this) + this.onClick = this.onClick.bind(this) + } + onNameChange (e) { + let currentDetail = this.props.currentDetail + currentDetail = currentDetail.set('name', e.target.value) + windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail) + } + onCardChange (e) { + let currentDetail = this.props.currentDetail + currentDetail = currentDetail.set('card', e.target.value) + windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail) + } + onExpMonthChange (e) { + let currentDetail = this.props.currentDetail + currentDetail = currentDetail.set('month', e.target.value) + windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail) + } + onExpYearChange (e) { + let currentDetail = this.props.currentDetail + currentDetail = currentDetail.set('year', e.target.value) + windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail) + } + onKeyDown (e) { + switch (e.keyCode) { + case KeyCodes.ENTER: + this.onSave() + break + case KeyCodes.ESC: + this.props.onHide() + break + } + } + onSave () { + appActions.addAutofillCreditCard(this.props.currentDetail, this.props.originalDetail) + this.props.onHide() + } + onClick (e) { + e.stopPropagation() + } + get displayNameOnCard () { + return this.props.currentDetail.get('name') + } + get displayCreditCardNumber () { + return this.props.currentDetail.get('card') + } + render () { + var ExpMonth = [] + for (let i = 1; i <= 12; ++i) { + ExpMonth.push() + } + var ExpYear = [] + var today = new Date() + var year = today.getFullYear() + for (let i = year; i <= year + 9; ++i) { + ExpYear.push() + } + + return +
+
+
+
+
+
+
+
+
+
+
+
+
+ } +} + +module.exports = AutofillCreditCardPanel diff --git a/js/components/frame.js b/js/components/frame.js index ff5c840759b..40b74a435dc 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -108,6 +108,9 @@ class Frame extends ImmutableComponent { } } else if (location === 'about:flash') { this.webview.send(messages.BRAVERY_DEFAULTS_UPDATED, this.braveryDefaults) + } else if (location === 'about:autofill') { + this.webview.send(messages.AUTOFILL_ADDRESSES_UPDATED, this.props.autofillAddresses.toJS()) + this.webview.send(messages.AUTOFILL_CREDIT_CARDS_UPDATED, this.props.autofillCreditCards.toJS()) } // send state to about pages @@ -596,6 +599,19 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('page-title-updated', ({title}) => { windowActions.setFrameTitle(this.frame, title) }) + this.webview.addEventListener('show-autofill-settings', (e) => { + windowActions.newFrame({ location: 'about:autofill' }, true) + }) + this.webview.addEventListener('update-autofill-popup-data-list-values', (e) => { + console.log(e) + }) + this.webview.addEventListener('show-autofill-popup', (e) => { + contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame) + }) + this.webview.addEventListener('hide-autofill-popup', (e) => { + // TODO(Anthony): conflict with contextmenu + // windowActions.setContextMenuDetail() + }) this.webview.addEventListener('ipc-message', (e) => { let method = () => {} switch (e.channel) { @@ -655,6 +671,18 @@ class Frame extends ImmutableComponent { method = (clearBrowsingDataDetail) => windowActions.setClearBrowsingDataDetail(clearBrowsingDataDetail) break + case messages.ADD_AUTOFILL_ADDRESS: + windowActions.setAutofillAddressDetail({}, {}) + break + case messages.EDIT_AUTOFILL_ADDRESS: + windowActions.setAutofillAddressDetail(e.args[0], e.args[0]) + break + case messages.ADD_AUTOFILL_CREDIT_CARD: + windowActions.setAutofillCreditCardDetail({month: '1', year: new Date().getFullYear()}, {}) + break + case messages.EDIT_AUTOFILL_CREDIT_CARD: + windowActions.setAutofillCreditCardDetail(e.args[0], e.args[0]) + break } method.apply(this, e.args) }) diff --git a/js/components/main.js b/js/components/main.js index b49ccf150a6..d4821c13baa 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -27,6 +27,8 @@ const Button = require('./button') const SiteInfo = require('./siteInfo') const BraveryPanel = require('./braveryPanel') const ClearBrowsingDataPanel = require('./clearBrowsingDataPanel') +const AutofillAddressPanel = require('./autofillAddressPanel') +const AutofillCreditCardPanel = require('./autofillCreditCardPanel') const AddEditBookmark = require('./addEditBookmark') const LoginRequired = require('./loginRequired') const ReleaseNotes = require('./releaseNotes') @@ -77,6 +79,8 @@ class Main extends ImmutableComponent { this.onHideSiteInfo = this.onHideSiteInfo.bind(this) this.onHideBraveryPanel = this.onHideBraveryPanel.bind(this) this.onHideClearBrowsingDataPanel = this.onHideClearBrowsingDataPanel.bind(this) + this.onHideAutofillAddressPanel = this.onHideAutofillAddressPanel.bind(this) + this.onHideAutofillCreditCardPanel = this.onHideAutofillCreditCardPanel.bind(this) this.onHideNoScript = this.onHideNoScript.bind(this) this.onHideReleaseNotes = this.onHideReleaseNotes.bind(this) this.onBraveMenu = this.onBraveMenu.bind(this) @@ -537,6 +541,14 @@ class Main extends ImmutableComponent { windowActions.setClearBrowsingDataDetail() } + onHideAutofillAddressPanel () { + windowActions.setAutofillAddressDetail() + } + + onHideAutofillCreditCardPanel () { + windowActions.setAutofillCreditCardDetail() + } + onHideNoScript () { windowActions.setNoScriptVisible(false) } @@ -683,6 +695,8 @@ class Main extends ImmutableComponent { const braveShieldsDisabled = this.braveShieldsDisabled const braveryPanelIsVisible = !braveShieldsDisabled && this.props.windowState.get('braveryPanelDetail') const clearBrowsingDataPanelIsVisible = this.props.windowState.get('clearBrowsingDataDetail') + const autofillAddressPanelIsVisible = this.props.windowState.get('autofillAddressDetail') + const autofillCreditCardPanelIsVisible = this.props.windowState.get('autofillCreditCardDetail') const activeRequestedLocation = this.activeRequestedLocation const noScriptIsVisible = this.props.windowState.getIn(['ui', 'noScriptInfo', 'isVisible']) const releaseNotesIsVisible = this.props.windowState.getIn(['ui', 'releaseNotes', 'isVisible']) @@ -693,6 +707,8 @@ class Main extends ImmutableComponent { !siteInfoIsVisible && !braveryPanelIsVisible && !clearBrowsingDataPanelIsVisible && + !autofillAddressPanelIsVisible && + !autofillCreditCardPanelIsVisible && !releaseNotesIsVisible && !noScriptIsVisible && activeFrame && !activeFrame.getIn(['security', 'loginRequiredDetail']) @@ -784,6 +800,22 @@ class Main extends ImmutableComponent { onHide={this.onHideClearBrowsingDataPanel} /> : null } + { + autofillAddressPanelIsVisible + ? + : null + } + { + autofillCreditCardPanelIsVisible + ? + : null + } { activeFrame && activeFrame.getIn(['security', 'loginRequiredDetail']) ? @@ -937,6 +969,8 @@ class Main extends ImmutableComponent { enableNoScript={this.enableNoScript(this.frameSiteSettings(frame.get('location')))} isPreview={frame.get('key') === this.props.windowState.get('previewFrameKey')} isActive={FrameStateUtil.isFrameKeyActive(this.props.windowState, frame.get('key'))} + autofillCreditCards={this.props.appState.getIn(['autofill', 'creditCards'])} + autofillAddresses={this.props.appState.getIn(['autofill', 'addresses'])} />) } diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 4a78622c32b..199311450a7 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -103,6 +103,7 @@ module.exports = { 'payments.enabled': false, 'payments.notifications': false, 'payments.contribution-amount': 5, // USD + 'privacy.privacy.autofill-enable': false, 'privacy.do-not-track': false, 'security.passwords.active-password-manager': null, // Set in settings.js by passwordManagerDefault (defaults to built in) 'security.passwords.manager-enabled': true, diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 652aa127cf0..2039c7aed96 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -36,6 +36,10 @@ const AppConstants = { APP_ADD_WORD: _, /** @param {string} word, @param {boolean} learn */ APP_SET_DICTIONARY: _, /** @param {string} locale */ APP_SET_BITCOIN_HANDLED: _ /** @param {boolean} handled */ + APP_ADD_AUTOFILL_ADDRESS: _, + APP_REMOVE_AUTOFILL_ADDRESS: _, + APP_ADD_AUTOFILL_CREDIT_CARD: _, + APP_REMOVE_AUTOFILL_CREDIT_CARD: _ } module.exports = mapValuesByKeys(AppConstants) diff --git a/js/constants/messages.js b/js/constants/messages.js index 2f9e969cd82..a0823d5549c 100644 --- a/js/constants/messages.js +++ b/js/constants/messages.js @@ -137,6 +137,14 @@ const messages = { CHECK_FLASH_INSTALLED: _, ABOUT_COMPONENT_INITIALIZED: _, CLEAR_BROWSING_DATA_NOW: _, + ADD_AUTOFILL_ADDRESS: _, + REMOVE_AUTOFILL_ADDRESS: _, + EDIT_AUTOFILL_ADDRESS: _, + ADD_AUTOFILL_CREDIT_CARD: _, + REMOVE_AUTOFILL_CREDIT_CARD: _, + EDIT_AUTOFILL_CREDIT_CARD: _, + AUTOFILL_ADDRESSES_UPDATED: _, + AUTOFILL_CREDIT_CARDS_UPDATED: _, // HTTPS CERT_ERROR_ACCEPTED: _, /** @arg {string} url where a cert error was accepted */ CHECK_CERT_ERROR_ACCEPTED: _, /** @arg {string} url to check cert error, @arg {number} key of frame */ diff --git a/js/constants/settings.js b/js/constants/settings.js index ec01177bcc6..7073b398a6b 100644 --- a/js/constants/settings.js +++ b/js/constants/settings.js @@ -32,6 +32,8 @@ const settings = { SHUTDOWN_CLEAR_DOWNLOADS: 'shutdown.clear-downloads', SHUTDOWN_CLEAR_CACHE: 'shutdown.clear-cache', SHUTDOWN_CLEAR_ALL_SITE_COOKIES: 'shutdown.clear-all-site-cookies', + // Autofill + AUTOFILL_ENABLED: 'privacy.autofill-enabled', // Security Tab: DEPRECATED but still required (for now) PASSWORD_MANAGER_ENABLED: 'security.passwords.manager-enabled', ONE_PASSWORD_ENABLED: 'security.passwords.one-password-enabled', diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js index fa4db57ab3f..0b1a02e8d74 100644 --- a/js/constants/windowConstants.js +++ b/js/constants/windowConstants.js @@ -65,7 +65,9 @@ const windowConstants = { WINDOW_SET_LOGIN_REQUIRED_DETAIL: _, WINDOW_SET_STATE: _, WINDOW_SET_LAST_ZOOM_PERCENTAGE: _, - WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: _ + WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: _, + WINDOW_SET_AUTOFILL_ADDRESS_DETAIL: _, + WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL: _ } module.exports = mapValuesByKeys(windowConstants) diff --git a/js/contextMenus.js b/js/contextMenus.js index 01866344755..9ff9db3f64e 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -374,6 +374,35 @@ function usernameTemplateInit (usernames, origin, action) { return items } +function autofillTemplateInit (suggestions, frame) { + let items = [] + for (let i = 0; i < suggestions.length; ++i) { + let value + let frontendId = suggestions[i].frontend_id + if (frontendId >= 0) { // POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY and Autofill Entry + value = suggestions[i].value + } else if (frontendId === -1) { // POPUP_ITEM_ID_WARNING_MESSAGE + value = 'Disabled due to unsecure connection.' + } else if (frontendId === -4) { // POPUP_ITEM_ID_CLEAR_FORM + value = 'Clear Form' + } else if (frontendId === -5) { // POPUP_ITEM_ID_AUTOFILL_OPTIONS + value = 'Autofill Settings' + } + if (frontendId === -3) { // POPUP_ITEM_ID_SEPARATOR + items.push(CommonMenu.separatorMenuItem) + } else { + items.push({ + label: value, + click: (item, focusedWindow) => { + ipc.send('autofill-selection-clicked', frame.get('tabId'), value, frontendId, i) + windowActions.setContextMenuDetail() + } + }) + } + } + return items +} + function tabTemplateInit (frameProps) { const frameKey = frameProps.get('key') const items = [] @@ -1059,6 +1088,15 @@ function onShowUsernameMenu (usernames, origin, action, boundingRect, })) } +function onShowAutofillMenu (suggestions, boundingRect, frame) { + const menuTemplate = autofillTemplateInit(suggestions, frame) + windowActions.setContextMenuDetail(Immutable.fromJS({ + left: boundingRect.x, + top: boundingRect.y, + template: menuTemplate + })) +} + function onMoreBookmarksMenu (activeFrame, allBookmarkItems, overflowItems, e) { const menuTemplate = moreBookmarksTemplateInit(allBookmarkItems, overflowItems, activeFrame) const rect = e.target.getBoundingClientRect() @@ -1166,6 +1204,7 @@ module.exports = { onSiteDetailContextMenu, onShowBookmarkFolderMenu, onShowUsernameMenu, + onShowAutofillMenu, onMoreBookmarksMenu, onBackButtonHistoryMenu, onForwardButtonHistoryMenu diff --git a/js/lib/appUrlUtil.js b/js/lib/appUrlUtil.js index da24c34e1ba..285660cbce6 100644 --- a/js/lib/appUrlUtil.js +++ b/js/lib/appUrlUtil.js @@ -68,7 +68,8 @@ module.exports.aboutUrls = new Immutable.Map({ 'about:safebrowsing': module.exports.getAppUrl('about-safebrowsing.html'), 'about:passwords': module.exports.getAppUrl('about-passwords.html'), 'about:flash': module.exports.getAppUrl('about-flash.html'), - 'about:error': module.exports.getAppUrl('about-error.html') + 'about:error': module.exports.getAppUrl('about-error.html'), + 'about:autofill': module.exports.getAppUrl('about-autofill.html') }) module.exports.isIntermediateAboutPage = (location) => diff --git a/js/state/privacy.js b/js/state/privacy.js new file mode 100644 index 00000000000..89abe7d4fa7 --- /dev/null +++ b/js/state/privacy.js @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const AppDispatcher = require('../dispatcher/appDispatcher') +const AppStore = require('../stores/appStore') +const AppConstants = require('../constants/appConstants') +const settings = require('../constants/settings') +const { registerUserPrefs } = require('./userPrefs') + +const getAutofillEnabled = (appState) => { + let appSettings = appState.get('settings') + return appSettings.get(settings.AUTOFILL_ENABLED) +} + +const getPrivacySettings = (appState) => { + return { 'autofill.enabled': getAutofillEnabled(appState) } +} + +let updateTrigger + +// Register callback to handle all updates +const doAction = (action) => { + if (action.actionType === AppConstants.APP_CHANGE_SETTING) { + AppDispatcher.waitFor([AppStore.dispatchToken], () => { + updateTrigger() + }) + } +} + +module.exports.init = () => { + updateTrigger = registerUserPrefs(() => getPrivacySettings(AppStore.getState())) + AppDispatcher.register(doAction) +} diff --git a/js/stores/appStore.js b/js/stores/appStore.js index f69349aff20..e66d462b75d 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -545,6 +545,68 @@ const handleAppAction = (action) => { case AppConstants.APP_SET_BITCOIN_HANDLED: appState = appState.set('hasBitcoinHandler', action.handled) break + case AppConstants.APP_ADD_AUTOFILL_ADDRESS: + { + const Filtering = require('../../app/filtering') + if (appState.getIn(['autofill', 'addresses']) === undefined) { + appState = appState.setIn(['autofill', 'addresses'], new Immutable.List()) + } + appState = appState.setIn(['autofill', 'addresses'], + appState.getIn(['autofill', 'addresses']).filterNot((address) => { + return Immutable.is(address, action.originalDetail) + })) + if (action.originalDetail.toJS().guid !== undefined) { + Filtering.removeAutofillAddress(action.originalDetail.toJS().guid) + } + + let addresses = appState.getIn(['autofill', 'addresses']) + const guid = Filtering.addAutofillAddress(action.detail.toJS()) + let detail = action.detail + detail = detail.set('guid', Immutable.fromJS(guid)) + appState = appState.setIn(['autofill', 'addresses'], addresses.push(Immutable.fromJS(detail))) + break + } + case AppConstants.APP_REMOVE_AUTOFILL_ADDRESS: + { + const Filtering = require('../../app/filtering') + appState = appState.setIn(['autofill', 'addresses'], + appState.getIn(['autofill', 'addresses']).filterNot((address) => { + return Immutable.is(address, Immutable.fromJS(action.detail)) + })) + Filtering.removeAutofillAddress(action.detail.guid) + break + } + case AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD: + { + const Filtering = require('../../app/filtering') + if (appState.getIn(['autofill', 'creditCards']) === undefined) { + appState = appState.setIn(['autofill', 'creditCards'], new Immutable.List()) + } + appState = appState.setIn(['autofill', 'creditCards'], + appState.getIn(['autofill', 'creditCards']).filterNot((card) => { + return Immutable.is(card, action.originalDetail) + })) + if (action.originalDetail.toJS().guid !== undefined) { + Filtering.removeAutofillCreditCard(action.originalDetail.toJS().guid) + } + + let creditCards = appState.getIn(['autofill', 'creditCards']) + const guid = Filtering.addAutofillCreditCard(action.detail.toJS()) + let detail = action.detail + detail = detail.set('guid', Immutable.fromJS(guid)) + appState = appState.setIn(['autofill', 'creditCards'], creditCards.push(Immutable.fromJS(detail))) + break + } + case AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD: + { + const Filtering = require('../../app/filtering') + appState = appState.setIn(['autofill', 'creditCards'], + appState.getIn(['autofill', 'creditCards']).filterNot((card) => { + return Immutable.is(card, Immutable.fromJS(action.detail)) + })) + Filtering.removeAutofillCreditCard(action.detail.guid) + break + } default: } diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 7db1c3c1af0..c1a1d6d1fe1 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -704,6 +704,30 @@ const doAction = (action) => { windowState = windowState.set('clearBrowsingDataDetail', Immutable.fromJS(action.clearBrowsingDataDetail)) } break + case WindowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL: + if (!action.currentDetail && !action.originalDetail) { + windowState = windowState.delete('autofillAddressDetail') + } else { + windowState = windowState.mergeIn(['autofillAddressDetail'], { + currentDetail: action.currentDetail, + originalDetail: action.originalDetail + }) + } + // Since the input values of addresses are bound, we need to notify the controls sync. + windowStore.emitChanges() + break + case WindowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL: + if (!action.currentDetail && !action.originalDetail) { + windowState = windowState.delete('autofillCreditCardDetail') + } else { + windowState = windowState.mergeIn(['autofillCreditCardDetail'], { + currentDetail: action.currentDetail, + originalDetail: action.originalDetail + }) + } + // Since the input values of credit cards are bound, we need to notify the controls sync. + windowStore.emitChanges() + break case WindowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE: windowState = windowState.setIn(['ui', 'downloadsToolbar', 'isVisible'], action.isVisible) break diff --git a/less/about/autofill.less b/less/about/autofill.less new file mode 100644 index 00000000000..65f47015f92 --- /dev/null +++ b/less/about/autofill.less @@ -0,0 +1,59 @@ +@import "./common.less"; + +.autofillPage { + margin: 20px; + + .autofillPageContent { + border-top: 1px solid @chromeBorderColor; + + .autofillList { + padding-top: 10px; + overflow: hidden; + } + } +} + +th { + padding: 8px; + text-align: left; +} + +tr { + cursor: default; + overflow: hidden; + white-space: nowrap; + + padding: 12px; + -webkit-user-select: none; + + .autofillItem { + display: flex; + } + + &:hover :not(th) { + background-color: lighten(@highlightBlue, 30%); + } +} + +td:not(.autofillActions) { + padding-right: 8px; + padding-left: 8px; +} + +.autofillAction { + cursor: pointer; + padding: 8px; + &:hover { + background-color: lighten(@highlightBlue, 20%); + } +} + +.autofillPageFooter { + padding: 10px; + margin-bottom: 20px; + span { + color: grey; + cursor: pointer; + text-decoration: underline; + } +} diff --git a/less/about/preferences.less b/less/about/preferences.less index f244b34571e..39f5f72ca88 100644 --- a/less/about/preferences.less +++ b/less/about/preferences.less @@ -295,6 +295,12 @@ span.browserButton.primaryButton.clearBrowsingDataButton { margin-top: 20px; } +span.browserButton.primaryButton.manageAutofillDataButton { + font-size: 0.9em; + padding: 5px 20px; + margin-top: 20px; +} + .settingsList { .settingItem { diff --git a/less/forms.less b/less/forms.less index b1ffc72421e..324098a195b 100644 --- a/less/forms.less +++ b/less/forms.less @@ -99,6 +99,34 @@ } } +.manageAutofillDataPanel { + .manageAutofillData { + .flyoutDialog; + background-color: #f7f7f7; + border-radius: @borderRadius; + max-width: 450px; + padding: 0; + text-align: left; + width: 473px; + -webkit-user-select: none; + cursor: default; + color: #3B3B3B; + overflow-y: auto; + max-height: 100%; + + .clickable { + color: #5B5B5B; + &:hover { + color: #000; + } + } + + .formSelect { + width: 5.5em + } + } +} + .braveryPanelContainer { .braveryPanel { From ca58f90e56e7c4b9d8c0eb472131de3b1f11b80a Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Fri, 19 Aug 2016 11:44:38 +0800 Subject: [PATCH 02/10] Adjust about:autofill layout --- .../brave/locales/en-US/app.properties | 3 +- .../brave/locales/en-US/autofill.properties | 5 +- js/about/autofill.js | 108 +++++++++--------- js/components/autofillAddressPanel.js | 6 +- js/components/autofillCreditCardPanel.js | 6 +- 5 files changed, 65 insertions(+), 63 deletions(-) diff --git a/app/extensions/brave/locales/en-US/app.properties b/app/extensions/brave/locales/en-US/app.properties index 66a53161949..cea752fd39c 100644 --- a/app/extensions/brave/locales/en-US/app.properties +++ b/app/extensions/brave/locales/en-US/app.properties @@ -177,10 +177,9 @@ allSiteCookies=All site cookies clear=Clear clearDataWarning=Warning: Selected data, back to the day you installed Brave will be cleared and cannot be undone. clearBrowsingData=Clear browsing data -nameOnCard=Name +name=Name creditCardNumber=Card Number expirationDate=Expiration date -nameOnAddress=Name organization=Organization streetAddress=Street Address city=City diff --git a/app/extensions/brave/locales/en-US/autofill.properties b/app/extensions/brave/locales/en-US/autofill.properties index 5c9bc2ad7c8..79f5bb6ac36 100644 --- a/app/extensions/brave/locales/en-US/autofill.properties +++ b/app/extensions/brave/locales/en-US/autofill.properties @@ -3,11 +3,10 @@ addresses=Addresses creditCards=Credit Cards addAddress=Add Address addCreditCard=Add Credit Card -nameOnCard=Name on card -creditCardNumber=Credit card number +name=Name +creditCardNumber=Card Number expirationDate=Expiration date noCreditCardsSaved=No saved credit cards -nameOnAddress=Name organization=Organization streetAddress=Street Address city=City diff --git a/js/about/autofill.js b/js/about/autofill.js index bc4d81a5a76..6b8542d4ebd 100644 --- a/js/about/autofill.js +++ b/js/about/autofill.js @@ -137,66 +137,70 @@ class AboutAutofill extends React.Component { var savedAddresssPage = this.isAddresssEmpty ?
:
-

-
- - - - - - - - - - - - - - - - - { - this.state.addressesDetails.sort((a, b) => { - return a.get('name') > b.get('name') ? 1 : -1 - }).map((item) => - ) - } - -
-
+ + + + + + + + + + + + + + + + + { + this.state.addressesDetails.sort((a, b) => { + return a.get('name') > b.get('name') ? 1 : -1 + }).map((item) => + ) + } + +

var savedCreditCardsPage = this.isCreditCardsEmpty ?
:
-

-
- - - - - - - - - - - { - this.state.creditCardsDetails.sort((a, b) => { - return a.get('name') > b.get('name') ? 1 : -1 - }).map((item) => - ) - } - -
-
+ + + + + + + + + + + { + this.state.creditCardsDetails.sort((a, b) => { + return a.get('name') > b.get('name') ? 1 : -1 + }).map((item) => + ) + } + +

return

- {savedAddresssPage} -

+
+

+
+ {savedCreditCardsPage} +
+ } } diff --git a/js/components/autofillAddressPanel.js b/js/components/autofillAddressPanel.js index bb0c16cab9b..c1f7d78f6af 100644 --- a/js/components/autofillAddressPanel.js +++ b/js/components/autofillAddressPanel.js @@ -93,7 +93,7 @@ class AutofillAddressPanel extends ImmutableComponent {
-
-
diff --git a/js/components/autofillCreditCardPanel.js b/js/components/autofillCreditCardPanel.js index 0867dc3cdff..5c830fdd44e 100644 --- a/js/components/autofillCreditCardPanel.js +++ b/js/components/autofillCreditCardPanel.js @@ -80,7 +80,7 @@ class AutofillCreditCardPanel extends ImmutableComponent {
-
@@ -100,8 +100,8 @@ class AutofillCreditCardPanel extends ImmutableComponent {
-
From 9b501c72a2b68e87be37a6d530375199133effff Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Fri, 19 Aug 2016 14:10:25 +0800 Subject: [PATCH 03/10] Adjust autofillPanels layout --- app/extensions/brave/locales/en-US/app.properties | 2 ++ js/components/autofillAddressPanel.js | 1 + js/components/autofillCreditCardPanel.js | 1 + less/forms.less | 7 ++++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/extensions/brave/locales/en-US/app.properties b/app/extensions/brave/locales/en-US/app.properties index cea752fd39c..ecaa2446a37 100644 --- a/app/extensions/brave/locales/en-US/app.properties +++ b/app/extensions/brave/locales/en-US/app.properties @@ -188,3 +188,5 @@ postalCode=Postal Code country=Country phone=Phone email=Email +editAddress=Edit Address +editCreditCard=Edit Credit Card diff --git a/js/components/autofillAddressPanel.js b/js/components/autofillAddressPanel.js index c1f7d78f6af..0e6c6da562a 100644 --- a/js/components/autofillAddressPanel.js +++ b/js/components/autofillAddressPanel.js @@ -91,6 +91,7 @@ class AutofillAddressPanel extends ImmutableComponent { render () { return
+