Skip to content

Force HTTPS redirection for log in and sign up #319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 30, 2017
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ This project is currently in development! It will be announced when there is a (
9. Open and close the Redux DevTools using `ctrl+h`, and move them with `ctrl+w`

###Testing SSL on your local machine
Please refer to [this gist](https://gist.github.com/andrewn/953ffd5cb17ac2634dc969fc7bdaff3f). This allows you to access the editor using both HTTP and HTTPS. Don't worry about this unless you need to make changes or test HTTPS behavior.
Please refer to [this gist](https://gist.github.com/andrewn/953ffd5cb17ac2634dc969fc7bdaff3f). This allows you to access the editor using both HTTP and HTTPS. Don't worry about this unless you need to make changes or test HTTPS behavior.

The automatic redirection to HTTPS is turned off by default in development. If you need to test this behavior, put `FORCE_TO_HTTPS=true` in your `.env` file.

##Production Installation
1. Clone this repostory and `cd` into it
Expand Down
44 changes: 44 additions & 0 deletions client/components/forceProtocol.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { PropTypes } from 'react';

/**
* A Higher Order Component that forces the protocol to change on mount
*
* targetProtocol: the protocol to redirect to on mount
* sourceProtocol: the protocol to redirect back to on unmount
* disable: if true, the redirection will not happen but what should
* have happened will be logged to the console
*/
const forceProtocol = ({ targetProtocol = 'https:', sourceProtocol, disable = false }) => WrappedComponent => (
class ForceProtocol extends React.Component {
static propTypes = {}

componentDidMount() {
this.redirectToProtocol(targetProtocol);
}

componentWillUnmount() {
if (sourceProtocol != null) {
this.redirectToProtocol(sourceProtocol);
}
}

redirectToProtocol(protocol) {
const currentProtocol = window.location.protocol;

if (protocol !== currentProtocol) {
if (disable === true) {
console.info(`forceProtocol: would have redirected from "${currentProtocol}" to "${protocol}"`);
} else {
window.location = window.location.href.replace(currentProtocol, protocol);
}
}
}

render() {
return <WrappedComponent {...this.props} />;
}
}
);


export default forceProtocol;
3 changes: 2 additions & 1 deletion client/modules/IDE/reducers/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const initialState = () => {
const generatedString = generate({ words: 2 }).spaced;
const generatedName = generatedString.charAt(0).toUpperCase() + generatedString.slice(1);
return {
name: generatedName
name: generatedName,
serveSecure: false,
};
};

Expand Down
31 changes: 24 additions & 7 deletions client/routes.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Route, IndexRoute } from 'react-router';
import React from 'react';
import forceProtocol from './components/forceProtocol';
import App from './modules/App/App';
import IDEView from './modules/IDE/pages/IDEView';
import FullView from './modules/IDE/pages/FullView';
Expand All @@ -15,22 +16,38 @@ const checkAuth = (store) => {
store.dispatch(getUser());
};

const routes = store =>
(
const routes = (store) => {
const sourceProtocol = store.getState().project.serveSecure === true ?
'https:' :
'http:';

// If the flag is false, we stay on HTTP
const forceToHttps = forceProtocol({
targetProtocol: 'https:',
sourceProtocol,
// prints debugging but does not reload page
disable: process.env.FORCE_TO_HTTPS === false,
});

return (
<Route path="/" component={App}>
<IndexRoute component={IDEView} onEnter={checkAuth(store)} />
<Route path="/login" component={LoginView} />
<Route path="/signup" component={SignupView} />
<Route path="/reset-password" component={ResetPasswordView} />
<Route path="/reset-password/:reset_password_token" component={NewPasswordView} />
<Route path="/login" component={forceToHttps(LoginView)} />
<Route path="/signup" component={forceToHttps(SignupView)} />
<Route path="/reset-password" component={forceToHttps(ResetPasswordView)} />
<Route
path="/reset-password/:reset_password_token"
component={forceToHttps(NewPasswordView)}
/>
<Route path="/projects/:project_id" component={IDEView} />
<Route path="/full/:project_id" component={FullView} />
<Route path="/sketches" component={IDEView} />
<Route path="/:username/sketches/:project_id" component={IDEView} />
<Route path="/:username/sketches" component={IDEView} />
<Route path="/:username/account" component={AccountView} />
<Route path="/:username/account" component={forceToHttps(AccountView)} />
<Route path="/about" component={IDEView} />
</Route>
);
};

export default routes;
6 changes: 6 additions & 0 deletions server/routes/server.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,10 @@ router.route('/:username/sketches').get((req, res) => {
));
});

router.route('/:username/account').get((req, res) => {
userExists(req.params.username, exists => (
exists ? res.send(renderIndex()) : get404Sketch(html => res.send(html))
));
});

export default router;
3 changes: 3 additions & 0 deletions webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ module.exports = {
'process.env': {
API_URL: '"' + process.env.API_URL + '"',
CLIENT: JSON.stringify(true),
FORCE_TO_HTTPS: process.env.FORCE_TO_HTTPS === 'true' ?
JSON.stringify(true) :
JSON.stringify(false),
'NODE_ENV': JSON.stringify('development'),
'S3_BUCKET': '"' + process.env.S3_BUCKET + '"'
}
Expand Down