diff --git a/app/models/cookie-jar.js b/app/models/cookie-jar.js index 55bfb0d7e..59c7d32e3 100644 --- a/app/models/cookie-jar.js +++ b/app/models/cookie-jar.js @@ -12,7 +12,9 @@ export type Cookie = { path: string, key: string, value: string, - expires: number + expires: number, + httpOnly: boolean, + secure: boolean } type BaseCookieJar = { diff --git a/app/models/index.js b/app/models/index.js index 1dce32c35..9595e890d 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -59,7 +59,7 @@ export function types () { return all().map(model => model.type); } -export function getModel (type: string) { +export function getModel (type: string): Object | null { return all().find(m => m.type === type) || null; } @@ -99,7 +99,7 @@ export function initModel (type: string, ...sources: Array) { created: Date.now() }, model.init()); - const fullObject = Object.assign({}, objectDefaults, ...sources); + const fullObject = Object.assign(objectDefaults, ...sources); // Generate an _id if there isn't one yet if (!fullObject._id) { diff --git a/app/ui/components/cookie-list.js b/app/ui/components/cookie-list.js index 7af22cc97..77e9f7d28 100644 --- a/app/ui/components/cookie-list.js +++ b/app/ui/components/cookie-list.js @@ -1,5 +1,5 @@ +// @flow import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; import autobind from 'autobind-decorator'; import {Cookie} from 'tough-cookie'; @@ -9,6 +9,15 @@ import RenderedText from './rendered-text'; @autobind class CookieList extends PureComponent { + props: { + onCookieAdd: Function, + onCookieDelete: Function, + cookies: Array, + newCookieDomainName: string, + handleShowModifyCookieModal: Function, + handleRender: Function + }; + _handleCookieAdd () { const newCookie = new Cookie({ key: 'foo', @@ -22,7 +31,7 @@ class CookieList extends PureComponent { this.props.onCookieAdd(newCookie); } - _handleDeleteCookie (cookie) { + _handleDeleteCookie (cookie: Cookie) { this.props.onCookieDelete(cookie); } @@ -58,7 +67,8 @@ class CookieList extends PureComponent { {cookie.domain} - + {cookieString} @@ -98,13 +108,4 @@ class CookieList extends PureComponent { } } -CookieList.propTypes = { - onCookieAdd: PropTypes.func.isRequired, - onCookieDelete: PropTypes.func.isRequired, - cookies: PropTypes.array.isRequired, - newCookieDomainName: PropTypes.string.isRequired, - handleShowModifyCookieModal: PropTypes.func.isRequired, - handleRender: PropTypes.func.isRequired -}; - export default CookieList; diff --git a/app/ui/components/modals/cookie-modify-modal.js b/app/ui/components/modals/cookie-modify-modal.js index 56c245141..5b38e1e1d 100644 --- a/app/ui/components/modals/cookie-modify-modal.js +++ b/app/ui/components/modals/cookie-modify-modal.js @@ -1,8 +1,8 @@ +// @flow import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; import {Tabs, TabList, Tab, TabPanel} from 'react-tabs'; import autobind from 'autobind-decorator'; -import {Cookie} from 'tough-cookie'; +import * as toughCookie from 'tough-cookie'; import * as models from '../../../models'; import {DEBOUNCE_MILLIS} from '../../../common/constants'; import {trackEvent} from '../../../analytics/index'; @@ -12,14 +12,38 @@ import ModalHeader from '../base/modal-header'; import ModalFooter from '../base/modal-footer'; import OneLineEditor from '../codemirror/one-line-editor'; import {cookieToString} from '../../../common/cookies'; +import type {Cookie, CookieJar} from '../../../models/cookie-jar'; +import type {Workspace} from '../../../models/workspace'; @autobind class CookieModifyModal extends PureComponent { - constructor (props) { + props: { + handleRender: Function, + handleGetRenderContext: Function, + workspace: Workspace, + cookieJar: CookieJar + }; + + state: { + cookie: Cookie | null, + rawValue: string, + isValid: { + key: boolean, + value: boolean, + domain: boolean, + path: boolean, + expires: boolean + } + }; + + modal: Modal | null; + _rawTimeout: number | null; + _cookieUpdateTimeout: number | null; + + constructor (props: any) { super(props); this.state = { - cookieJar: null, cookie: null, rawValue: '', isValid: { @@ -30,52 +54,49 @@ class CookieModifyModal extends PureComponent { expires: true } }; + + this._rawTimeout = null; + this._cookieUpdateTimeout = null; } - _setModalRef (n) { + _setModalRef (n: Modal | null) { this.modal = n; } - async _load () { - const {workspace} = this.props; - const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id); - this.setState({cookieJar}); - } - - async show (cookie) { - await this._load(); - + async show (cookie: Cookie) { // Dunno why this is sent as an array cookie = cookie[0] || cookie; this.setState({cookie}); - this.modal.show(); + this.modal && this.modal.show(); trackEvent('Cookie Modifier', 'Show'); } hide () { - this.modal.hide(); + this.modal && this.modal.hide(); } - async _saveChanges () { - const {cookieJar} = this.state; + async _saveChanges (cookieJar: CookieJar) { await models.cookieJar.update(cookieJar); - await this._load(); } - _handleChangeRawValue (e) { + _handleChangeRawValue (e: Event & {target: HTMLInputElement}) { const value = e.target.value; clearTimeout(this._rawTimeout); this._rawTimeout = setTimeout(async () => { - const cookie = Cookie.parse(value); + const cookie = toughCookie.Cookie.parse(value); + if (!this.state.cookie) { + return; + } + await this._handleCookieUpdate(this.state.cookie, cookie); }, DEBOUNCE_MILLIS); } - async _handleCookieUpdate (oldCookie, cookie) { - const {cookieJar} = this.state; + async _handleCookieUpdate (oldCookie: Cookie, cookie: Cookie) { + const {cookieJar} = this.props; const {cookies} = cookieJar; const index = cookies.findIndex(c => c.domain === oldCookie.domain && c.key === oldCookie.key); @@ -91,21 +112,23 @@ class CookieModifyModal extends PureComponent { trackEvent('Cookie', 'Update'); } - _handleChange (input, field) { + _handleChange (field: string, eventOrValue: Event & {target: HTMLInputElement}) { const {cookie} = this.state; let valid = true; - if (typeof input === 'object') { - input = input.target.checked; - } + const value = typeof eventOrValue === 'object' + ? eventOrValue.target.checked + : eventOrValue; if (valid) { - const newCookie = Object.assign({}, cookie, {[field]: input}); + const newCookie = Object.assign({}, cookie, {[field]: value}); clearTimeout(this._cookieUpdateTimeout); - this._cookieUpdateTimeout = setTimeout(() => { - this._handleCookieUpdate(cookie, newCookie); - this.setState({cookie: newCookie}); + this._cookieUpdateTimeout = setTimeout(async () => { + if (cookie) { + await this._handleCookieUpdate(cookie, newCookie); + this.setState({cookie: newCookie}); + } }, DEBOUNCE_MILLIS * 2); } @@ -117,20 +140,24 @@ class CookieModifyModal extends PureComponent { }); } - _capitalize (str) { + _capitalize (str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } render () { const { + cookieJar, handleRender, handleGetRenderContext } = this.props; + if (!cookieJar) { + return null; + } + const { isValid, - cookie, - cookieJar + cookie } = this.state; if (!cookie || !cookieJar) { @@ -142,7 +169,7 @@ class CookieModifyModal extends PureComponent { let rawCookieString = ''; try { - rawCookieString = cookieToString(Cookie.fromJSON(JSON.stringify(cookie))); + rawCookieString = cookieToString(toughCookie.Cookie.fromJSON(JSON.stringify(cookie))); } catch (err) { console.warn('Failed to parse cookie', err); } @@ -170,13 +197,12 @@ class CookieModifyModal extends PureComponent { ); @@ -193,7 +219,7 @@ class CookieModifyModal extends PureComponent { type="checkbox" name={field} defaultChecked={checked || false} - onChange={(e) => this._handleChange(e, field)} + onChange={e => this._handleChange(field, e)} /> ); @@ -221,11 +247,5 @@ class CookieModifyModal extends PureComponent { } } -CookieModifyModal.propTypes = { - handleRender: PropTypes.func.isRequired, - handleGetRenderContext: PropTypes.func.isRequired, - workspace: PropTypes.object.isRequired -}; - // export CookieModifyModal; export default CookieModifyModal; diff --git a/app/ui/components/modals/cookies-modal.js b/app/ui/components/modals/cookies-modal.js index 24bf554ab..a66deb4b8 100644 --- a/app/ui/components/modals/cookies-modal.js +++ b/app/ui/components/modals/cookies-modal.js @@ -34,6 +34,13 @@ class CookiesModal extends PureComponent { }; } + async _ensureCookieJarExists () { + const {cookieJar, workspace} = this.props; + if (!cookieJar) { + models.cookieJar.getOrCreateForParentId(workspace._id); + } + } + _setModalRef (n: React.Element<*> | null) { this.modal = n; } @@ -85,11 +92,13 @@ class CookiesModal extends PureComponent { } async show () { - this.modal && this.modal.show(); + await this._ensureCookieJarExists(); setTimeout(() => { this.filterInput && this.filterInput.focus(); }, 100); + + this.modal && this.modal.show(); trackEvent('Cookie Manager', 'Show'); } @@ -98,16 +107,22 @@ class CookiesModal extends PureComponent { } render () { - const filteredCookies = this._getFilteredSortedCookies(); const { handleShowModifyCookieModal, - handleRender + handleRender, + cookieJar } = this.props; + if (!cookieJar) { + return null; + } + const { filter } = this.state; + const filteredCookies = this._getFilteredSortedCookies(); + return ( Manage Cookies diff --git a/app/ui/components/rendered-text.js b/app/ui/components/rendered-text.js index 8b3282e60..e166ca31d 100644 --- a/app/ui/components/rendered-text.js +++ b/app/ui/components/rendered-text.js @@ -5,7 +5,8 @@ class RenderedText extends React.PureComponent { props: { component: string, children: string, - render: Function + render: Function, + props?: Object }; state: { @@ -34,8 +35,8 @@ class RenderedText extends React.PureComponent { } render () { - const {component} = this.props; - return React.createElement(component, {}, this.state.renderedText); + const {component, props} = this.props; + return React.createElement(component, props || {}, this.state.renderedText); } } diff --git a/app/ui/components/wrapper.js b/app/ui/components/wrapper.js index 0c93c7f2c..0f30fe491 100644 --- a/app/ui/components/wrapper.js +++ b/app/ui/components/wrapper.js @@ -540,6 +540,7 @@ class Wrapper extends React.PureComponent { handleRender={handleRender} handleGetRenderContext={handleGetRenderContext} ref={registerModal} + cookieJar={activeCookieJar} workspace={activeWorkspace} />