Skip to content
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

File-system backend fixes and support JWT #1029

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/backends/file-system/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { APIError } from "../../valueObjects/errors";
export default class API {
constructor(config) {
this.api_root = config.api_root || "/api";
this.token = config.token;
}

user() {
Expand All @@ -17,6 +18,9 @@ export default class API {
"Content-Type": "application/json",
...headers,
};
if (this.token) {
baseHeader.Authorization = `Bearer ${ this.token }`;
}

return baseHeader;
}
Expand Down
49 changes: 32 additions & 17 deletions src/backends/file-system/AuthenticationPage.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
.fs-auth-page-root {
.nc-filesystemAuthenticationPage-root {
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
height: 100vh;
}

.fs-auth-page-card {
.nc-filesystemAuthenticationPage-form {
width: 350px;
padding: 10px;
}
margin-top: -80px;
z-index: 1;
& input {
background-color: #fff;
border-radius: var(--borderRadius);

.fs-auth-page-card img {
display: block;
margin: auto;
padding: 20px;
}
font-size: 14px;
padding: 10px 10px;
margin-bottom: 15px;
margin-top: 6px;
width: 100%;
position: relative;
z-index: 1;

.fs-auth-page-errorMsg {
color: #dd0000;
&:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--colorBlue);
}
}
}

.fs-auth-page-message {
font-size: 1.1em;
margin: 20px 10px;
.nc-filesystemAuthenticationPage-button {
@apply(--button);
@apply(--dropShadowDeep);
@apply(--buttonDefault);
@apply(--buttonGray);

padding: 0 30px;
display: block;
margin-top: 20px;
margin: auto;
}

.fs-auth-page-button {
padding: .25em 1em;
height: auto;
.nc-filesystemAuthenticationPage-errorMsg {
color: var(--colorErrorText);
}
108 changes: 88 additions & 20 deletions src/backends/file-system/AuthenticationPage.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,108 @@
import PropTypes from 'prop-types';
import React from 'react';
import { partial } from 'lodash';
import { Icon } from "UI";
import logo from "./netlify_logo.svg";
import styles from "./AuthenticationPage.css";

let component = null;

const localHosts = {
localhost: true,
"127.0.0.1": true,
"0.0.0.0": true
};

export default class AuthenticationPage extends React.Component {
constructor(props) {
super(props);
component = this;
}

componentDidMount() {
}

componentWillUnmount() {
component = null;
}

static propTypes = {
onLogin: PropTypes.func.isRequired,
inProgress: PropTypes.bool,
};

state = { email: '' };
state = { email: "", password: "", errors: {} };

handleChange = (name, e) => {
this.setState({ ...this.state, [name]: e.target.value });
};

handleLogin = (e) => {
e.preventDefault();
this.props.onLogin(this.state);
};

handleEmailChange = (value) => {
this.setState({ email: value });
const { email, password } = this.state;
const errors = {};

if (localHosts[document.location.host.split(":").shift()]) {
this.props.onLogin(this.state);
} else {
if (!email) {
errors.email = 'Make sure to enter your email.';
}
if (!password) {
errors.password = 'Please enter your password.';
}
if (Object.keys(errors).length > 0) {
this.setState({ errors });
return;
}
AuthenticationPage.authClient.login(this.state.email, this.state.password, true)
.then((user) => {
this.props.onLogin(user);
})
.catch((error) => {
this.setState({ errors: { server: error.description || error.msg || error }, loggingIn: false });
});
}
};

render() {
const { inProgress } = this.props;

return (<section className="fs-auth-page-root">
<section className="fs-auth-page-card">
<Icon className="nc-githubAuthenticationPage-logo" size="500px" type="netlify-cms"/>
<button
className="nc-githubAuthenticationPage-button"
disabled={inProgress}
onClick={this.handleLogin}
>
{inProgress ? "Logging in..." : "Login Local"}
</button>
const { errors } = this.state;
const { error, inProgress } = this.props;

return (
<section className="nc-filesystemAuthenticationPage-root">
<Icon className="nc-filesystemAuthenticationPage-logo" size="500px" type="netlify-cms"/>
<form className="nc-filesystemAuthenticationPage-form" onSubmit={this.handleLogin}>
{!error && <p>
<span className="nc-filesystemAuthenticationPage-errorMsg">{error}</span>
</p>}
{!errors.server && <p>
<span className="nc-filesystemAuthenticationPage-errorMsg">{errors.server}</span>
</p>}
<div className="nc-filesystemAuthenticationPage-errorMsg">{ errors.email || null }</div>
<input
type="text"
name="email"
placeholder="Email"
value={this.state.email}
onChange={partial(this.handleChange, 'email')}
/>
<div className="nc-filesystemAuthenticationPage-errorMsg">{ errors.password || null }</div>
<input
type="password"
name="password"
placeholder="Password"
value={this.state.password}
onChange={partial(this.handleChange, 'password')}
/>
<button
className="nc-filesystemAuthenticationPage-button"
disabled={inProgress}
onClick={this.handleLogin}
>
{inProgress ? "Logging in..." : "Login"}
</button>
</form>
</section>
</section>);
);
}
}
65 changes: 59 additions & 6 deletions src/backends/file-system/implementation.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import GoTrue from "gotrue-js";
import jwtDecode from 'jwt-decode';
import {List} from 'immutable';
import trimStart from 'lodash/trimStart';
import AuthenticationPage from './AuthenticationPage';
import API from "./API";
Expand All @@ -23,32 +26,82 @@ function nameFromEmail(email) {
.join(' ');
}

const localHosts = {
localhost: true,
"127.0.0.1": true,
"0.0.0.0": true
};

export default class fs {
constructor(config) {
this.config = config;

this.api_root = config.getIn(["backend", "api_root"], "http://localhost:8080/api");
this.api_root = config.getIn(["backend", "api_root"], "/api");

const APIUrl = config.getIn(["backend", "identity_url"], "/.netlify/identity");
this.authClient = window.netlifyIdentity ? window.netlifyIdentity.gotrue : new GoTrue({APIUrl});

AuthenticationPage.authClient = this.authClient;
}

authComponent() {
return AuthenticationPage;
}

restoreUser(user) {
if (!localHosts[document.location.host.split(":").shift()]) {
user = this.authClient && this.authClient.currentUser();
if (!user) return Promise.reject();
}
return this.authenticate(user);
}

authenticate(state) {
this.api = new API({ api_root: this.api_root });
return Promise.resolve({ email: state.email, name: nameFromEmail(state.email) });
authenticate(user) {
if (localHosts[document.location.host.split(":").shift()]) {
const userData = { name: '', email: '' };
if (user.email) {
userData.name = nameFromEmail(user.email);
userData.email = user.email;
}
this.api = new API({
api_root: this.api_root,
token: null,
});
return Promise.resolve(userData);
} else {
this.tokenPromise = user.jwt.bind(user);
return this.tokenPromise()
.then((token) => {
const userData = {
name: user.user_metadata.name || nameFromEmail(user.email),
email: user.email,
avatar_url: user.user_metadata.avatar_url,
metadata: user.user_metadata,
};
this.api = new API({
api_root: this.api_root,
token: token,
});
return userData;
});
}
}

logout() {
return null;
if (localHosts[document.location.host.split(":").shift()]) {
return null;
} else {
const user = this.authClient.currentUser();
return user && user.logout();
}
}

getToken() {
return Promise.resolve('');
if (localHosts[document.location.host.split(":").shift()]) {
return Promise.resolve('');
} else {
return this.tokenPromise();
}
}

entriesByFolder(collection, extension) {
Expand Down
23 changes: 0 additions & 23 deletions src/backends/file-system/netlify_logo.svg

This file was deleted.

1 change: 1 addition & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
*/
@import "./backends/git-gateway/AuthenticationPage.css";
@import "./backends/github/AuthenticationPage.css";
@import "./backends/file-system/AuthenticationPage.css";