adding and fetching docs
This commit is contained in:
parent
d9aa8deb16
commit
8d93af6552
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.1 KiB |
@ -10,9 +10,12 @@
|
||||
<title>Ninja</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Alexander Bell, all rights reserved -->
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<!-- Alexander Bell, all rights reserved -->
|
||||
<div id="root"></div>
|
||||
<!-- Alexander Bell, all rights reserved -->
|
||||
</body>
|
||||
</html>
|
||||
|
@ -42,7 +42,7 @@ const App = inject("rootStore") ( observer(
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
body.style.margin = '0';
|
||||
body.style.padding = '0';
|
||||
body.style.overflow = 'hidden';
|
||||
body.style.overflow = 'auto';
|
||||
|
||||
//Load app
|
||||
this.stores.rootStore.loadApp();
|
||||
|
17
src/components/Headline.js
Normal file
17
src/components/Headline.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function(props) {
|
||||
/*
|
||||
* Expected props
|
||||
* - black: String
|
||||
* the text in black
|
||||
* - red: String
|
||||
* the text in red
|
||||
*/
|
||||
|
||||
return(
|
||||
<h2 style={{padding: '20px'}}>
|
||||
{props.black}<span style={{color: '#DA3821'}}>{props.red}</span>
|
||||
</h2>
|
||||
)
|
||||
}
|
@ -113,17 +113,14 @@ const Main = inject("rootStore") ( observer(
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
<div style={{minHeight: '100vh'}}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
||||
//Mobile sidebar
|
||||
|
||||
return(
|
||||
<div>
|
||||
<Sidebar.Pushable>
|
||||
<Sidebar
|
||||
as={Menu}
|
||||
@ -137,11 +134,11 @@ const Main = inject("rootStore") ( observer(
|
||||
<img alt="" src={require('../../files/images/logo.svg')} style={{display: 'block', width: '60px', height: '45px'}} />
|
||||
</Menu.Item>
|
||||
|
||||
<Menu.Item name="Home" active={activeItem === 'Home'} onClick={this.handleItemClick} as='a'>
|
||||
<Menu.Item name="/" active={activeItem === '/'} onClick={this.handleItemClick} as='a'>
|
||||
Home
|
||||
</Menu.Item>
|
||||
|
||||
<Menu.Item name="Password manager" active={activeItem === 'Password manager'} onClick={this.handleItemClick} as='a'>
|
||||
<Menu.Item name="/passwords" active={activeItem === '/passwords'} onClick={this.handleItemClick} as='a'>
|
||||
Password manager
|
||||
</Menu.Item>
|
||||
</Sidebar>
|
||||
@ -151,7 +148,6 @@ const Main = inject("rootStore") ( observer(
|
||||
{this.props.children}
|
||||
</Sidebar.Pusher>
|
||||
</Sidebar.Pushable>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
1
src/files/images/ninja.svg
Normal file
1
src/files/images/ninja.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 13 KiB |
@ -78,6 +78,7 @@ class Main extends Component {
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route path="/passwords" component={PasswordManager} />
|
||||
</Switch>
|
||||
<img alt="" style={{width: '100px', marginBottom: '-20px', marginTop: '30px', marginLeft: '20px'}} src={require('../files/images/ninja.svg')} />
|
||||
</Segment>
|
||||
</Container>
|
||||
</Menu>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, {Component} from 'react';
|
||||
import jss from 'jss';
|
||||
import preset from 'jss-preset-default';
|
||||
import { Container } from 'semantic-ui-react';
|
||||
|
||||
/*
|
||||
* Functions import
|
||||
@ -9,6 +10,7 @@ import preset from 'jss-preset-default';
|
||||
/*
|
||||
* Component imports
|
||||
*/
|
||||
import Headline from '../../components/Headline';
|
||||
|
||||
jss.setup(preset());
|
||||
|
||||
@ -53,9 +55,16 @@ class Home extends Component {
|
||||
|
||||
render() {
|
||||
return(
|
||||
<div>
|
||||
Home
|
||||
</div>
|
||||
<Container text>
|
||||
<Headline black="alexbell." red="ninja" />
|
||||
|
||||
<p>
|
||||
You are signed in on alexbell.ninja. <b>What can you do here?</b><br />
|
||||
Well, I like developing software in my freetime, mainly applications
|
||||
for my personal use. They might also be of advantage for you, so feel free
|
||||
to browse around a little and try some of what you can find here :)
|
||||
</p>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
import React, {Component} from 'react';
|
||||
import { observer, inject } from 'mobx-react';
|
||||
import jss from 'jss';
|
||||
import preset from 'jss-preset-default';
|
||||
import { Segment, Container, Header, Form, Input, Button, Icon } from 'semantic-ui-react';
|
||||
import alertify from 'alertify.js';
|
||||
|
||||
/*
|
||||
* Functions import
|
||||
*/
|
||||
import { encrypt } from '../../stores/functions/encryption';
|
||||
|
||||
/*
|
||||
* Component imports
|
||||
@ -13,6 +16,11 @@ import { Segment, Container, Header, Form, Input, Button, Icon } from 'semantic-
|
||||
|
||||
jss.setup(preset());
|
||||
|
||||
//Firebase
|
||||
var firebase = require('../../stores/fb').fb;
|
||||
// Initialize Cloud Firestore through Firebase
|
||||
var db = firebase.firestore();
|
||||
|
||||
|
||||
/*
|
||||
###############################
|
||||
@ -28,7 +36,8 @@ Components -- END
|
||||
|
||||
|
||||
|
||||
class New extends Component {
|
||||
const New = inject("rootStore") ( observer(
|
||||
class New extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
//Add a new password window
|
||||
@ -43,6 +52,12 @@ class New extends Component {
|
||||
* 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: '',
|
||||
@ -92,9 +107,41 @@ class New extends Component {
|
||||
}
|
||||
|
||||
|
||||
handleChange(e, {name}) {
|
||||
handleChange(e) {
|
||||
this.setState({
|
||||
[name]: e.target.value
|
||||
[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;
|
||||
|
||||
db.collection("passwords").add({
|
||||
uid: uid,
|
||||
url: url,
|
||||
login: login,
|
||||
password: password,
|
||||
time: new Date()
|
||||
})
|
||||
.then((docRef) => {
|
||||
console.log("Document written with ID: ", docRef.id);
|
||||
alertify.success("Document successfully added!");
|
||||
this.props.toggleNewWindow();
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error("Error adding document: ", error);
|
||||
alertify.error("Something went wrong! Please check your internet connection");
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
}
|
||||
|
||||
@ -161,6 +208,7 @@ class New extends Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
export default New;
|
||||
|
@ -1,20 +1,28 @@
|
||||
import React, {Component} from 'react';
|
||||
import { observer, inject } from 'mobx-react';
|
||||
import jss from 'jss';
|
||||
import preset from 'jss-preset-default';
|
||||
import { Menu, Segment, Dropdown, Table, Button, Icon, Header } from 'semantic-ui-react';
|
||||
import { Menu, Segment, Dropdown, Table, Button, Loader, Icon, Header, Input } from 'semantic-ui-react';
|
||||
import alertify from 'alertify.js';
|
||||
|
||||
/*
|
||||
* Functions import
|
||||
*/
|
||||
import { decrypt } from '../../stores/functions/encryption';
|
||||
|
||||
/*
|
||||
* Component imports
|
||||
*/
|
||||
import New from './New';
|
||||
import Headline from '../../components/Headline';
|
||||
|
||||
jss.setup(preset());
|
||||
|
||||
//Firebase
|
||||
var firebase = require('../../stores/fb').fb;
|
||||
// Initialize Cloud Firestore through Firebase
|
||||
var db = firebase.firestore();
|
||||
|
||||
|
||||
/*
|
||||
###############################
|
||||
@ -30,7 +38,8 @@ Components -- END
|
||||
|
||||
|
||||
|
||||
class PasswordManager extends Component {
|
||||
const PasswordManager = inject("rootStore") ( observer(
|
||||
class PasswordManager extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
//Password Manager page
|
||||
@ -40,13 +49,18 @@ class PasswordManager extends Component {
|
||||
* - /
|
||||
*/
|
||||
|
||||
//Stored information
|
||||
this.stores = this.props.rootStore.stores;
|
||||
|
||||
this.toggleNewWindow = this.toggleNewWindow.bind(this);
|
||||
this.onChangeInput = this.onChangeInput.bind(this);
|
||||
|
||||
this.state = {
|
||||
newWindowOpen: false,
|
||||
key: '',
|
||||
search: ''
|
||||
search: '',
|
||||
data: [],
|
||||
loading: true
|
||||
}
|
||||
|
||||
//Styles
|
||||
@ -58,6 +72,11 @@ class PasswordManager extends Component {
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
|
||||
componentWillUnmount() {
|
||||
this.sheet.detach()
|
||||
}
|
||||
@ -73,11 +92,10 @@ class PasswordManager extends Component {
|
||||
|
||||
|
||||
toggleNewWindow() {
|
||||
//Add new password window
|
||||
//Open window to add a new password doc
|
||||
|
||||
if(this.state.key !== '')
|
||||
{
|
||||
alertify.log("Encryption key: '" + this.state.key + "'");
|
||||
this.setState({
|
||||
newWindowOpen: !this.state.newWindowOpen
|
||||
});
|
||||
@ -87,10 +105,68 @@ class PasswordManager extends Component {
|
||||
}
|
||||
|
||||
|
||||
fetchData() {
|
||||
//Gets password list from firestore and
|
||||
//Writes in this.state
|
||||
|
||||
const uid = this.stores.authStore.userData.uid;
|
||||
|
||||
db.collection("passwords").where("uid", "==", uid).orderBy("time", "desc").get().then((querySnapshot) => {
|
||||
var arr = [];
|
||||
querySnapshot.forEach((doc) => {
|
||||
const data = doc.data();
|
||||
arr.push(data);
|
||||
});
|
||||
this.setState({
|
||||
data: arr,
|
||||
loading: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
displayData(dataList) {
|
||||
//Returns array with all table row components
|
||||
var components = [];
|
||||
|
||||
dataList.forEach((element, index) => {
|
||||
components.push(
|
||||
<Table.Row key={index}>
|
||||
<Table.Cell>{element.url}</Table.Cell>
|
||||
<Table.Cell>{decrypt(element.login, this.state.key)}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button icon>
|
||||
<Icon name='copy' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
<Table.Cell>{decrypt(element.password, this.state.key)}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button icon>
|
||||
<Icon name='copy' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
});
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const tableRows = this.displayData(this.state.data)
|
||||
|
||||
return(
|
||||
<div>
|
||||
<New encryptionkey={this.state.key} open={this.state.newWindowOpen} toggleNewWindow={this.toggleNewWindow} />
|
||||
|
||||
<Headline black="Password " red="manager" />
|
||||
|
||||
<Input icon placeholder='Search...'>
|
||||
<input type='text' placeholder='Search...' name="search" onChange={this.onChangeInput} autoComplete="off" />
|
||||
<Icon name='search' />
|
||||
</Input>
|
||||
|
||||
<Menu attached='top'>
|
||||
<Dropdown item icon='wrench' simple>
|
||||
<Dropdown.Menu>
|
||||
@ -107,16 +183,10 @@ class PasswordManager extends Component {
|
||||
<i className='key icon' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='ui right aligned category search item'>
|
||||
<div className='ui transparent icon input'>
|
||||
<input className='prompt' type='text' placeholder='Search...' name="search" onChange={this.onChangeInput} autoComplete="off" />
|
||||
<i className='search icon' />
|
||||
</div>
|
||||
</div>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
|
||||
|
||||
<Segment attached='bottom'>
|
||||
<Table celled striped>
|
||||
<Table.Header>
|
||||
@ -130,27 +200,14 @@ class PasswordManager extends Component {
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>cell</Table.Cell>
|
||||
<Table.Cell>cell</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button icon>
|
||||
<Icon name='copy' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
<Table.Cell>cell</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button icon>
|
||||
<Icon name='copy' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{tableRows}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<Loader active={this.state.loading} />
|
||||
</Segment>
|
||||
|
||||
<Header as="h3">
|
||||
How does it work?
|
||||
How does it work? Is it safe?
|
||||
</Header>
|
||||
<p>
|
||||
I ask you to give an encryption key. Once you set that key you can create a new password which is then encrypted with that key.
|
||||
@ -163,7 +220,7 @@ class PasswordManager extends Component {
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
I advise you to choose one encryption key and use it for all your passwords in your list. Why? Using the same key makes decrypting easier for you because <b>all</b> entries are being decrypted correctly at the same time by using one single key.
|
||||
<b>I advise you to choose one encryption key and use it for all your passwords in your list.</b> Why? Using the same key makes decrypting easier for you because <b>all</b> entries are being decrypted correctly at the same time by using one single key.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@ -175,6 +232,7 @@ class PasswordManager extends Component {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
export default PasswordManager;
|
||||
|
13
src/stores/functions/encryption.js
Normal file
13
src/stores/functions/encryption.js
Normal file
@ -0,0 +1,13 @@
|
||||
function norm_to_ascii(string){return unescape(encodeURIComponent(string))};
|
||||
function norm_to_unicode(string){return decodeURIComponent(escape(string))};
|
||||
function crypt_sym(string,k){return String.fromCharCode.apply(undefined,string.split("").map(function(c){return c.charCodeAt(0)^(k||13)}))};
|
||||
|
||||
export function encrypt(string, key) {
|
||||
//Encrypt a string
|
||||
return btoa(crypt_sym(norm_to_ascii(string), key));
|
||||
}
|
||||
|
||||
export function decrypt(string, key) {
|
||||
//Decrypt a string
|
||||
return crypt_sym(norm_to_unicode(atob(string)), key);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user