Inital user auth commit

This commit is contained in:
Stuart Taylor
2018-04-11 14:46:46 +01:00
committed by Mrugesh Mohapatra
parent 6dd6b44848
commit c4108aca5d
9 changed files with 333 additions and 40 deletions

View File

@ -9,7 +9,7 @@ module.exports = {
siteUrl: 'https://learn.freecodecamp.org'
},
proxy: {
prefix: '/',
prefix: '/api',
url: 'http://localhost:3000'
},
plugins: [

View File

@ -69,7 +69,13 @@ exports.createPages = ({ graphql, boundActionCreators }) => {
// Create challenge pages.
result.data.allChallengeNode.edges.forEach((edge, index, thisArray) => {
const { fields: { slug }, required = [], template, challengeType, id } = edge.node;
const {
fields: { slug },
required = [],
template,
challengeType,
id
} = edge.node;
const next = thisArray[index + 1];
const nextChallengePath = next ? next.node.fields.slug : '/';
createPage({

View File

@ -5,6 +5,7 @@
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"adler32": "^0.1.7",
"auth0-js": "^9.4.2",
"babel-core": "^6.26.0",
"babel-jest": "^22.4.3",
"babel-standalone": "^6.26.0",

View File

@ -0,0 +1,120 @@
import auth0 from 'auth0-js';
import { navigateTo } from 'gatsby-link';
import { ajax$ } from '../templates/Challenges/utils/ajax-stream';
const AUTH0_DOMAIN = 'freecodecamp.auth0.com';
const AUTH0_CLIENT_ID = 'vF70CJZyPKbZR4y0avecXXLkfyMNnyKn';
export default class Auth {
constructor() {
this.login = this.login.bind(this);
this.logout = this.logout.bind(this);
this.handleAuthentication = this.handleAuthentication.bind(this);
this.isAuthenticated = this.isAuthenticated.bind(this);
this.sessionEmail = '';
}
auth0 = new auth0.WebAuth({
domain: AUTH0_DOMAIN,
clientID: AUTH0_CLIENT_ID,
redirectUri: 'http://localhost:8000/callback',
audience: `https://${AUTH0_DOMAIN}/api/v2/`,
responseType: 'token id_token',
scope: 'openid profile email'
});
login() {
this.auth0.authorize();
}
logout() {
localStorage.removeItem('access_token');
localStorage.removeItem('id_token');
localStorage.removeItem('expires_at');
localStorage.removeItem('user');
}
handleAuthentication() {
if (typeof window !== 'undefined') {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.setSession(authResult);
} else if (err) {
console.error(err);
}
// Return to the homepage after authentication.
navigateTo('/');
});
}
}
isAuthenticated() {
const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
const isAuth = new Date().getTime() < expiresAt;
// isAuth && this.getFCCUser();
return isAuth;
}
setSession(authResult) {
const expiresAt = JSON.stringify(
authResult.expiresIn * 9000 + new Date().getTime()
);
localStorage.setItem('access_token', authResult.accessToken);
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('expires_at', expiresAt);
this.auth0.client.userInfo(authResult.accessToken, (err, user) => {
if (err) {
console.error(err);
}
localStorage.setItem('user', JSON.stringify(user));
});
}
getFCCUser() {
const token = localStorage.getItem('access_token');
if (!token) {
console.warn('no token found');
}
const { email } = JSON.parse(localStorage.getItem('user'));
const headers = {
Authorization: `Bearer ${token}`
};
const body = { email };
ajax$({
url: '/api/auth/auth0/login',
headers,
body
}).subscribe(
resp => {
console.info('YES');
console.log(resp);
},
err => {
console.warn('NO?');
console.log(err.message);
},
() => {
console.log('done');
}
);
}
getUser() {
if (localStorage.getItem('user')) {
return JSON.parse(localStorage.getItem('user'));
}
return null;
}
getUserName() {
if (this.getUser()) {
return this.getUser().name;
}
return null;
}
}

View File

@ -1,32 +1,99 @@
import React from 'react';
import React, { Component } from 'react';
import Link from 'gatsby-link';
const Header = () => (
<div
style={{
background: '#006400',
marginBottom: '1.45rem'
}}
>
<div
style={{
margin: '0 auto',
maxWidth: 960
}}
>
<h1 style={{ margin: 0 }}>
<Link
import Auth from '../../auth';
const auth = new Auth();
class Header extends Component {
constructor(props) {
super(props);
this.state = {
authenticated: false
};
}
login() {
auth.login();
this.setState({
authenticated: auth.isAuthenticated()
});
}
logout() {
auth.logout();
this.setState({
authenticated: auth.isAuthenticated()
});
}
componentDidMount() {
// this.setState({
// authenticated: auth.isAuthenticated()
// });
}
render() {
return (
<div
style={{
background: '#006400',
marginBottom: '0.45rem'
}}
>
<div
style={{
color: 'white',
textDecoration: 'none'
margin: '0 auto',
maxWidth: 960
}}
to='/'
>
Gatsby
</Link>
</h1>
</div>
</div>
);
<h1 style={{ margin: 0 }}>
<Link
style={{
color: 'white',
textDecoration: 'none'
}}
to='/'
>
freeCodeCamp
</Link>
</h1>
{this.state.authenticated ? (
<span>
<a
href='#'
onClick={this.logout.bind(this)}
style={{
boxShadow: 'none',
lineHeight: '37px',
color: '#fff'
}}
>
Log Out
{auth.getUserName() && <span> ({auth.getUserName()})</span>}
</a>
</span>
) : (
<span>
<a
href='#'
onClick={this.login.bind(this)}
style={{
boxShadow: 'none',
lineHeight: '37px',
color: '#fff'
}}
>
Log In
</a>
</span>
)}
</div>
</div>
);
}
}
export default Header;

View File

@ -0,0 +1,12 @@
import React from 'react';
import Auth from '../auth';
function AuthCallBack() {
const auth = new Auth();
auth.handleAuthentication();
return <h2>One moment please...</h2>;
}
AuthCallBack.displayName = 'AuthCallBack';
export default AuthCallBack;

View File

@ -0,0 +1,28 @@
import { createAction, handleActions } from 'redux-actions';
import { createTypes } from '../../../utils/stateManagment';
const ns = 'app';
export const types = createTypes(
['fetchUser', 'fetchUserComplete', 'fetchUserError'],
ns
);
const initialState = {
user: {}
};
export const fetchUser = createAction(types.fetchUser);
export const fetchUserComplete = createAction(types.fetchUserComplete);
export const fecthUserError = createAction(types.fetchUserError);
export const reducer = handleActions(
{
[types.fetchUserComplete]: (state, { payload }) => ({
...state,
user: payload
})
},
initialState
);

View File

@ -6,16 +6,19 @@ import {
import { combineEpics, createEpicMiddleware } from 'redux-observable';
import { routerReducer as router, routerMiddleware } from 'react-router-redux';
import { reducer as app } from './app';
import { reducer as challenge, epics } from '../templates/Challenges/redux';
import { reducer as map } from '../components/Map/redux';
const rootReducer = combineReducers({
app,
challenge,
map,
router
});
const rootEpic = combineEpics(...epics);
const epicMiddleware = createEpicMiddleware(rootEpic, {
dependencies: {
window: typeof window !== 'undefined' ? window : {},

View File

@ -519,6 +519,17 @@ atob@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc"
auth0-js@^9.4.2:
version "9.4.2"
resolved "https://registry.yarnpkg.com/auth0-js/-/auth0-js-9.4.2.tgz#44363933266781fb9447ce09503c6f783b86a474"
dependencies:
base64-js "^1.2.0"
idtoken-verifier "^1.2.0"
qs "^6.4.0"
superagent "^3.8.2"
url-join "^1.1.0"
winchan "^0.2.0"
autoprefixer@^6.0.2, autoprefixer@^6.3.1:
version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@ -1436,7 +1447,7 @@ base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
base64-js@^1.0.2:
base64-js@^1.0.2, base64-js@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801"
@ -2211,7 +2222,7 @@ component-emitter@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe"
component-emitter@1.2.1, component-emitter@^1.2.1:
component-emitter@1.2.1, component-emitter@^1.2.0, component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
@ -2307,6 +2318,10 @@ cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
cookiejar@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@ -2459,6 +2474,10 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
crypto-js@^3.1.9-1:
version "3.1.9-1"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8"
crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
@ -3822,6 +3841,14 @@ forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@^2.3.1, form-data@~2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"
form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
@ -3830,13 +3857,9 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
form-data@~2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"
formidable@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659"
forwarded@~0.1.2:
version "0.1.2"
@ -4748,6 +4771,16 @@ icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
idtoken-verifier@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/idtoken-verifier/-/idtoken-verifier-1.2.0.tgz#4654f1f07ab7a803fc9b1b8b36057e2a87ad8b09"
dependencies:
base64-js "^1.2.0"
crypto-js "^3.1.9-1"
jsbn "^0.1.0"
superagent "^3.8.2"
url-join "^1.1.0"
ieee754@^1.1.4:
version "1.1.11"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455"
@ -5626,7 +5659,7 @@ jsan@^3.1.5, jsan@^3.1.9:
version "3.1.9"
resolved "https://registry.yarnpkg.com/jsan/-/jsan-3.1.9.tgz#2705676c1058f0a7d9ac266ad036a5769cfa7c96"
jsbn@~0.1.0:
jsbn@^0.1.0, jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@ -6203,7 +6236,7 @@ merge@^1.1.3, merge@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
methods@~1.1.2:
methods@^1.1.1, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@ -6283,7 +6316,7 @@ mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
mime@^1.3.6, mime@^1.5.0:
mime@^1.3.6, mime@^1.4.1, mime@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@ -7879,7 +7912,7 @@ q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
qs@6.5.1, qs@~6.5.1:
qs@6.5.1, qs@^6.4.0, qs@^6.5.1, qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
@ -9534,6 +9567,21 @@ style-loader@^0.13.0:
dependencies:
loader-utils "^1.0.2"
superagent@^3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403"
dependencies:
component-emitter "^1.2.0"
cookiejar "^2.1.0"
debug "^3.1.0"
extend "^3.0.0"
form-data "^2.3.1"
formidable "^1.1.1"
methods "^1.1.1"
mime "^1.4.1"
qs "^6.5.1"
readable-stream "^2.0.5"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@ -10026,6 +10074,10 @@ urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
url-join@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78"
url-loader@^0.5.7:
version "0.5.9"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295"
@ -10389,6 +10441,10 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
winchan@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/winchan/-/winchan-0.2.0.tgz#3863028e7f974b0da1412f28417ba424972abd94"
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"