This commit is contained in:
Alexander Bell 2018-09-29 22:57:57 +02:00
parent 7d736b4356
commit 6c4e135e59
4 changed files with 283 additions and 17 deletions

View File

@ -0,0 +1,227 @@
import React, {Component} from 'react';
import { observer, inject } from 'mobx-react';
import jss from 'jss';
import preset from 'jss-preset-default';
import { Segment, Container, Form, Input, Button, Icon } from 'semantic-ui-react';
import alertify from 'alertify.js';
/*
* Functions import
*/
import { encrypt, decrypt } from '../../stores/functions/encryption';
/*
* Component imports
*/
jss.setup(preset());
//Firebase
var firebase = require('../../stores/fb').fb;
// Initialize Cloud Firestore through Firebase
var db = firebase.firestore();
/*
###############################
Components -- START
###############################
*/
/*
###############################
Components -- END
###############################
*/
const Edit = inject("rootStore") ( observer(
class Edit extends Component {
constructor(props){
super(props);
//Update an existing document
/*
* Expected props
* - open: bool
* display component or not
* - toggleEditWindow: function
* toggles window: open and close
* - encryptionkey: String
* encryption key of the password
*/
//Stored information
this.stores = this.props.rootStore.stores;
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
url: '',
login: '',
password: '',
loading: false
}
//Styles
this.styles = this.getStyles();
this.sheet = jss.createStyleSheet(this.styles);
const {classes} = this.sheet.attach();
this.classes = classes;
//Styles
}
componentWillReceiveProps(nextProps) {
if(nextProps.open !== this.props.open) {
var url;
var login;
var password;
if(nextProps.open) {
url = nextProps.data[nextProps.editIndex].url;
login = decrypt(nextProps.data[nextProps.editIndex].login, nextProps.encryptionkey);
password = decrypt(nextProps.data[nextProps.editIndex].password, nextProps.encryptionkey);
} else {
url = null;
login = null;
password = null;
}
//Empty input fields
this.setState({
url: url,
login: login,
password: password
});
}
}
componentDidUpdate() {
}
componentWillUnmount() {
this.sheet.detach()
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit() {
const url = this.state.url;
const login = encrypt(this.state.login, this.props.encryptionkey);
const password = encrypt(this.state.password, this.props.encryptionkey);
const uid = this.stores.authStore.userData.uid;
const id = this.props.data[this.props.editIndex].id;
const editIndex = this.props.editIndex;
//Update a doc locally with the new values
const data = {
url: url,
login: login,
password: password,
time: new Date()
}
db.collection("passwords/"+uid+"/passwords").doc(id).set(data)
.then(() => {
console.log("Document updated");
alertify.success("Document successfully updated!");
//Update a doc locally with the new values
this.props.updateDoc(Object.assign(data, {id:id}), editIndex);
this.props.toggleEditWindow();
this.setState({
loading: false
});
})
.catch(function(error) {
console.error("Error updating the document: ", error);
alertify.error("Something went wrong! Please check your internet connection");
this.setState({
loading: false
});
});
this.setState({
loading: true
});
}
render() {
if(this.props.open) {
const url = this.state.url;
const login = this.state.login;
const password = this.state.password;
return(
<div className={this.classes.box}>
<Container text>
<Segment padded="very">
<Form onSubmit={this.handleSubmit}>
<Form.Field>
<label>Application / URL:</label>
<Input iconPosition='left' placeholder='http://exmple.com'>
<input value={url} type="text" name="url" id="url" onChange={this.handleChange} autoComplete="off" required />
</Input>
</Form.Field>
<Form.Field>
<label>Username / email adress:</label>
<Input iconPosition='left' placeholder='example@example.com'>
<input value={login} type="text" name="login" onChange={this.handleChange} autoComplete="off" required />
</Input>
</Form.Field>
<Form.Field>
<label>Password:</label>
<Input iconPosition='left' placeholder='********'>
<input value={password} type="text" name="password" onChange={this.handleChange} autoComplete="off" required />
</Input>
</Form.Field>
<p>Login and password are going to be encrypted with the key you have set.</p>
<Button loading={this.state.loading} type='submit' primary>Update</Button>
<Button loading={this.state.loading} onClick={this.props.toggleEditWindow}><Icon name="x" />Cancel</Button>
</Form>
</Segment>
</Container>
</div>
);
} else {
return null;
}
}
getStyles() {
return {
box: {
width: '100vw',
height: '100vh',
position: 'fixed',
zIndex: 1000,
top: 0,
left: 0,
backgroundColor: 'rgba(255,255,255,0.9)',
paddingTop: '5%'
}
}
}
}
));
export default Edit;

View File

@ -128,22 +128,23 @@ const New = inject("rootStore") ( observer(
const password = encrypt(this.state.password, this.props.encryptionkey);
const uid = this.stores.authStore.userData.uid;
//Update a doc locally with the new values
const data = {
uid: uid,
url: url,
login: login,
password: password,
time: new Date()
}
//Add a new doc locally so no new data transfer from firestore
//is needed
this.props.addDoc(data);
db.collection("passwords/"+uid+"/passwords").add(data)
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
alertify.success("Document successfully added!");
//Add a new doc locally so no new data transfer from firestore
//is needed
this.props.addDoc(Object.assign(data, {id:docRef.id}));
this.props.toggleNewWindow();
this.setState({
loading: false

View File

@ -73,7 +73,7 @@ class Main extends Component {
<Router history={history}>
<Menu handleItemClick={this.handleItemClick}>
<Container className={this.classes.mainContainer}>
<Segment className={this.classes.mainSegment} padded="very">
<Segment className={this.classes.mainSegment}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/p" component={PasswordManager} />
@ -99,7 +99,7 @@ class Main extends Component {
ninja: {
width: '100px',
marginBottom: '-47px',
marginBottom: '-20px',
marginTop: '30px',
marginLeft: '20px'
}

View File

@ -15,6 +15,7 @@ import { decrypt } from '../../stores/functions/encryption';
* Component imports
*/
import New from '../../components/PasswordManager/New';
import Edit from '../../components/PasswordManager/Edit';
import Headline from '../../components/Headline';
jss.setup(preset());
@ -54,11 +55,15 @@ const PasswordManager = inject("rootStore") ( observer(
this.stores = this.props.rootStore.stores;
this.toggleNewWindow = this.toggleNewWindow.bind(this);
this.toggleEditWindow = this.toggleEditWindow.bind(this);
this.onChangeInput = this.onChangeInput.bind(this);
this.addDoc = this.addDoc.bind(this);
this.updateDoc = this.updateDoc.bind(this);
this.state = {
newWindowOpen: false,
editWindowOpen: false,
editIndex: null,
key: '',
search: '',
data: [],
@ -76,9 +81,6 @@ const PasswordManager = inject("rootStore") ( observer(
componentDidMount() {
this.fetchData();
//Focus on search input
document.getElementById('search').focus();
}
@ -99,6 +101,16 @@ const PasswordManager = inject("rootStore") ( observer(
}
updateDoc(data, editIndex) {
//Update a doc locally with the new values
var newArr = this.state.data;
newArr[editIndex] = data;
this.setState({
data: newArr
});
}
onChangeInput(e) {
//Encryption key and search input
@ -122,17 +134,32 @@ const PasswordManager = inject("rootStore") ( observer(
}
toggleEditWindow(index) {
//Open window to add a new password doc
if(this.state.key !== '')
{
this.setState({
editWindowOpen: !this.state.editWindowOpen,
editIndex: index
});
} else {
alertify.error("Please set an encryption key!");
}
}
fetchData() {
//Gets password list from firestore and
//Writes in this.state
const uid = this.stores.authStore.userData.uid;
db.collection("passwords/"+uid+"/passwords").where("uid", "==", uid).orderBy("time", "desc").get().then((querySnapshot) => {
db.collection("passwords/"+uid+"/passwords").orderBy("time", "desc").get().then((querySnapshot) => {
var arr = [];
querySnapshot.forEach((doc) => {
const data = doc.data();
arr.push(data);
arr.push(Object.assign(data, {id:doc.id}));
});
this.setState({
data: arr,
@ -194,6 +221,9 @@ const PasswordManager = inject("rootStore") ( observer(
const copyPassword = () => {
copyToClipboard(decrypt(element.password, this.state.key));
}
const toggleEditWindow = () => {
this.toggleEditWindow(index);
}
const url = transformUrl(element.url);
const password = decrypt(element.password, this.state.key);
@ -201,17 +231,22 @@ const PasswordManager = inject("rootStore") ( observer(
components.push(
<Table.Row key={index}>
<Table.Cell>
<Button icon onClick={toggleEditWindow}>
<Icon name='edit' />
</Button>
</Table.Cell>
<Table.Cell>{url}</Table.Cell>
<Table.Cell>{login}</Table.Cell>
<Table.Cell>
<Button icon>
<Icon onClick={copyLogin} name='copy' />
<Button icon onClick={copyLogin}>
<Icon name='copy' />
</Button>
</Table.Cell>
<Table.Cell>{password}</Table.Cell>
<Table.Cell>
<Button icon>
<Icon onClick={copyPassword} name='copy' />
<Button icon onClick={copyPassword}>
<Icon name='copy' />
</Button>
</Table.Cell>
</Table.Row>
@ -230,6 +265,8 @@ const PasswordManager = inject("rootStore") ( observer(
<div>
<New addDoc={this.addDoc} encryptionkey={this.state.key} open={this.state.newWindowOpen} toggleNewWindow={this.toggleNewWindow} />
<Edit updateDoc={this.updateDoc} data={this.state.data} editIndex={this.state.editIndex} encryptionkey={this.state.key} open={this.state.editWindowOpen} toggleEditWindow={this.toggleEditWindow} />
<Headline black="Password " red="manager" />
<Input icon placeholder='Search...'>
@ -261,10 +298,11 @@ const PasswordManager = inject("rootStore") ( observer(
<Table celled striped>
<Table.Header>
<Table.Row>
<Table.HeaderCell width={1}></Table.HeaderCell>
<Table.HeaderCell width={4}>Application / URL</Table.HeaderCell>
<Table.HeaderCell width={5}>Username / Email adress</Table.HeaderCell>
<Table.HeaderCell width={1}></Table.HeaderCell>
<Table.HeaderCell width={5}>Password</Table.HeaderCell>
<Table.HeaderCell width={4}>Password</Table.HeaderCell>
<Table.HeaderCell width={1}></Table.HeaderCell>
</Table.Row>
</Table.Header>