mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Replace material-UI by material-components-web.
This commit is contained in:
parent
7c6023fee4
commit
317611b099
2
client/.env.development
Normal file
2
client/.env.development
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
REACT_APP_CSP_CONTENT="default-src 'unsafe-inline'; script-src * 'unsafe-inline'; img-src * data:; style-src 'unsafe-inline'; connect-src * 'unsafe-inline' extensions:"
|
2
client/.env.production
Normal file
2
client/.env.production
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
REACT_APP_CSP_CONTENT="default-src 'self'; style-src 'self'; script-src 'self';"
|
|
@ -8,6 +8,7 @@ services:
|
|||
- ./client/tsconfig.json:/usr/app/client/tsconfig.json
|
||||
- ./client/public:/usr/app/client/public
|
||||
- ./client/src:/usr/app/client/src
|
||||
- ./client/.env.development:/usr/app/client/.env.development
|
||||
networks:
|
||||
example-network:
|
||||
aliases:
|
||||
|
|
216
client/package-lock.json
generated
216
client/package-lock.json
generated
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "client-react",
|
||||
"name": "authelia-portal",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
|
@ -890,6 +890,215 @@
|
|||
"react-is": "^16.6.3"
|
||||
}
|
||||
},
|
||||
"@material/animation": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz",
|
||||
"integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA=="
|
||||
},
|
||||
"@material/base": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz",
|
||||
"integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ=="
|
||||
},
|
||||
"@material/button": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/button/-/button-0.41.0.tgz",
|
||||
"integrity": "sha512-9mA/7P8yD3YPJ8ijwu0oOiT65OCa8Km3M9OF6VAsBE+XJS9Wo5hWDMgkv16raeOFeXj+1ALsjvuTz31JdcSkgQ==",
|
||||
"requires": {
|
||||
"@material/elevation": "^0.41.0",
|
||||
"@material/ripple": "^0.41.0",
|
||||
"@material/rtl": "^0.40.1",
|
||||
"@material/shape": "^0.41.0",
|
||||
"@material/theme": "^0.41.0",
|
||||
"@material/typography": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/checkbox": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.41.0.tgz",
|
||||
"integrity": "sha512-Zz6e5WRpziO7Z+4rbEs8GHNNBf1UuttniLp6/RvwPSQRaD8G04sdg4HcP/aDCY1KGMwivkuDPc2Bsgs6j+rD7Q==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/ripple": "^0.41.0",
|
||||
"@material/rtl": "^0.40.1",
|
||||
"@material/selection-control": "^0.41.0",
|
||||
"@material/theme": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/elevation": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz",
|
||||
"integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/theme": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/floating-label": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz",
|
||||
"integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/rtl": "^0.40.1",
|
||||
"@material/theme": "^0.41.0",
|
||||
"@material/typography": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/line-ripple": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz",
|
||||
"integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/theme": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/notched-outline": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz",
|
||||
"integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/rtl": "^0.40.1",
|
||||
"@material/shape": "^0.41.0",
|
||||
"@material/theme": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/react-button": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-button/-/react-button-0.8.0.tgz",
|
||||
"integrity": "sha512-j/wk/HK2A3/mb+yFdYCbkWFi6hYvvq4fc4t1M3aRLgdeddMNn/+FHOu014dyKeFW93RrBn1WAdQTwCc31KivuQ==",
|
||||
"requires": {
|
||||
"@material/button": "^0.41.0",
|
||||
"@material/react-ripple": "^0.8.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/react-checkbox": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-checkbox/-/react-checkbox-0.8.0.tgz",
|
||||
"integrity": "sha512-/7wQcFovUa04/T0MnJOnrbGn21CgxSSWjqkbMPFh/RjET8vya/kqAjhkLw51Mk4q6si+nfHljM6YSFvvXbUBBw==",
|
||||
"requires": {
|
||||
"@material/checkbox": "^0.41.0",
|
||||
"@material/react-ripple": "^0.8.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.3.2"
|
||||
}
|
||||
},
|
||||
"@material/react-floating-label": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-floating-label/-/react-floating-label-0.8.0.tgz",
|
||||
"integrity": "sha512-Bfa+/4nLFu6YE0pAB1wG+vxwYiFvHcOKIq7uAB/IY0/N/ONKM2Jh74/KKqLvNJI608YpZqLAqmZu87R3K15rNQ==",
|
||||
"requires": {
|
||||
"@material/floating-label": "^0.41.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/react-line-ripple": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-line-ripple/-/react-line-ripple-0.8.0.tgz",
|
||||
"integrity": "sha512-s921awUm8taB/kbETGN/vEEZV1WUwtTcsNkQ//HsK2fJW7lKuyVWrObc8ZhMFWljVEUj54ANmRvCke7M4/LSmA==",
|
||||
"requires": {
|
||||
"@material/line-ripple": "^0.41.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/react-notched-outline": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-notched-outline/-/react-notched-outline-0.8.0.tgz",
|
||||
"integrity": "sha512-fQ8hHGOQ3dpk9AuuQqXbCAN2UTuRr5LCztkDxdCwvaPC+oR5meTd8RW7RkJgx/MeiSLe/1/2EMz+9lP+V0rx2w==",
|
||||
"requires": {
|
||||
"@material/notched-outline": "^0.41.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/react-ripple": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-ripple/-/react-ripple-0.8.0.tgz",
|
||||
"integrity": "sha512-ThH9Px42poicRXgFBTfLjbAsVIUi6wmX4RszDPwiSTVMQYc785n240VAD8MfVCR27ykIxCrys/YibqxvREvjUQ==",
|
||||
"requires": {
|
||||
"@material/ripple": "^0.41.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/react-text-field": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/react-text-field/-/react-text-field-0.8.0.tgz",
|
||||
"integrity": "sha512-eISr4YIBmsIarQQU/LhAPfB9M8srY8Tzagqw6E2z5JyHux8eHlsMWSuYD6eh4FiQekdZoIgoJjlFIGhOvNV59Q==",
|
||||
"requires": {
|
||||
"@material/react-floating-label": "^0.8.0",
|
||||
"@material/react-line-ripple": "^0.8.0",
|
||||
"@material/react-notched-outline": "^0.8.0",
|
||||
"@material/textfield": "^0.41.0",
|
||||
"classnames": "^2.2.5",
|
||||
"react": "^16.4.2"
|
||||
}
|
||||
},
|
||||
"@material/ripple": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz",
|
||||
"integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/theme": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/rtl": {
|
||||
"version": "0.40.1",
|
||||
"resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz",
|
||||
"integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A=="
|
||||
},
|
||||
"@material/selection-control": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz",
|
||||
"integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==",
|
||||
"requires": {
|
||||
"@material/ripple": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/shape": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz",
|
||||
"integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ=="
|
||||
},
|
||||
"@material/textfield": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-0.41.0.tgz",
|
||||
"integrity": "sha512-kJ52W2gxOS2xfpreVhvHQ1u3UkiDl58duw9HkhEkK5Oi1bSDOtbnlWy0pGTOiAma5ZQgetPNgoa+T0zMBptfnw==",
|
||||
"requires": {
|
||||
"@material/animation": "^0.41.0",
|
||||
"@material/base": "^0.41.0",
|
||||
"@material/floating-label": "^0.41.0",
|
||||
"@material/line-ripple": "^0.41.0",
|
||||
"@material/notched-outline": "^0.41.0",
|
||||
"@material/ripple": "^0.41.0",
|
||||
"@material/rtl": "^0.40.1",
|
||||
"@material/shape": "^0.41.0",
|
||||
"@material/theme": "^0.41.0",
|
||||
"@material/typography": "^0.41.0"
|
||||
}
|
||||
},
|
||||
"@material/theme": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz",
|
||||
"integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg=="
|
||||
},
|
||||
"@material/typography": {
|
||||
"version": "0.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz",
|
||||
"integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A=="
|
||||
},
|
||||
"@mrmlnc/readdir-enhanced": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
|
@ -16990,6 +17199,11 @@
|
|||
"resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
|
||||
"integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw="
|
||||
},
|
||||
"utility-types": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.4.1.tgz",
|
||||
"integrity": "sha512-GyH068kJf7c4vhfqj4aCM5X+TeV8jG2iPFLimpGpnQ7dvKfogZOHfiYxMww/nGEfMm/bEmnVbeZGO1see1OVKg=="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "client-react",
|
||||
"name": "authelia-portal",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@material-ui/core": "3.7.1",
|
||||
"@material-ui/icons": "^3.0.1",
|
||||
"@material/react-button": "^0.8.0",
|
||||
"@material/react-checkbox": "^0.8.0",
|
||||
"@material/react-text-field": "^0.8.0",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/jss": "^9.5.7",
|
||||
"@types/node": "^10.12.2",
|
||||
|
@ -31,11 +32,12 @@
|
|||
"redux-thunk": "^2.3.0",
|
||||
"typesafe-actions": "^3.0.0",
|
||||
"typescript": "^3.1.6",
|
||||
"u2f-api": "^1.0.10"
|
||||
"u2f-api": "^1.0.10",
|
||||
"utility-types": "^3.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"start": "SASS_PATH=./node_modules react-scripts start",
|
||||
"build": "SASS_PATH=./node_modules react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="robots" content="noindex, nofollow, nosnippet, noarchive">
|
||||
<meta name="theme-color" content="#000000">
|
||||
|
||||
<meta http-equiv="Content-Security-Policy" content="%REACT_APP_CSP_CONTENT%">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
|
|
|
@ -9,7 +9,5 @@
|
|||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
"display": "standalone"
|
||||
}
|
||||
|
|
0
client/src/App.css → client/src/.env.development
Normal file → Executable file
0
client/src/App.css → client/src/.env.development
Normal file → Executable file
3
client/src/App.scss
Normal file
3
client/src/App.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
@import "@material/react-button/index.scss";
|
||||
@import "@material/react-checkbox/index.scss";
|
||||
@import "@material/react-text-field/index.scss";
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import './App.css';
|
||||
import './App.scss';
|
||||
|
||||
import { Router, Route, Switch } from "react-router-dom";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { routes } from './routes/index';
|
||||
import { createBrowserHistory } from 'history';
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
container: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
messageContainer: {
|
||||
fontSize: theme.typography.fontSize,
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
marginBottom: theme.spacing.unit * 2,
|
||||
color: 'green',
|
||||
display: 'inline-block',
|
||||
marginLeft: theme.spacing.unit * 2,
|
||||
textAlign: 'left',
|
||||
|
||||
},
|
||||
successContainer: {
|
||||
verticalAlign: 'middle',
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
paddingBottom: theme.spacing.unit * 2,
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
marginBottom: theme.spacing.unit * 3,
|
||||
border: '1px solid #8ae48a',
|
||||
borderRadius: '100px',
|
||||
},
|
||||
successLogoContainer: {
|
||||
display: 'inline-block',
|
||||
},
|
||||
logoutButtonContainer: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,36 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
fields: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
},
|
||||
field: {
|
||||
paddingBottom: theme.spacing.unit * 2,
|
||||
},
|
||||
input: {
|
||||
width: '100%',
|
||||
},
|
||||
buttons: {
|
||||
'& button': {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
controls: {
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
rememberMe: {
|
||||
float: 'left',
|
||||
fontSize: theme.typography.fontSize * 0.8,
|
||||
},
|
||||
resetPassword: {
|
||||
padding: '12px 0px',
|
||||
float: 'right',
|
||||
'& a': {
|
||||
color: 'black',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,20 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
messageOuter: {
|
||||
position: 'relative',
|
||||
},
|
||||
messageInner: {
|
||||
width: '100%',
|
||||
},
|
||||
messageContainer: {
|
||||
color: 'white',
|
||||
fontSize: theme.typography.fontSize,
|
||||
padding: theme.spacing.unit * 2,
|
||||
border: '1px solid red',
|
||||
borderRadius: '5px',
|
||||
backgroundColor: '#ff8d8d',
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,69 +0,0 @@
|
|||
|
||||
import { createStyles, Theme } from "@material-ui/core";
|
||||
import { isAbsolute } from "path";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
container: {
|
||||
position: 'relative',
|
||||
},
|
||||
hello: {},
|
||||
logout: {},
|
||||
header: {
|
||||
fontSize: theme.typography.fontSize * 1.5,
|
||||
marginBottom: theme.spacing.unit,
|
||||
position: 'relative',
|
||||
'& $hello': {
|
||||
display: 'inline-block',
|
||||
},
|
||||
'& $logout': {
|
||||
position: 'absolute',
|
||||
bottom: '0px',
|
||||
right: '0px',
|
||||
fontSize: theme.typography.fontSize * 0.9,
|
||||
},
|
||||
},
|
||||
body: {
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
paddingBottom: theme.spacing.unit * 2,
|
||||
paddingLeft: theme.spacing.unit * 2,
|
||||
paddingRight: theme.spacing.unit * 2,
|
||||
border: '1px solid #e0e0e0',
|
||||
borderRadius: '2px',
|
||||
},
|
||||
methodName: {
|
||||
fontSize: theme.typography.fontSize * 1.2,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: theme.spacing.unit,
|
||||
},
|
||||
methodU2f: {
|
||||
borderBottom: '1px solid #e0e0e0',
|
||||
padding: theme.spacing.unit,
|
||||
},
|
||||
methodTotp: {
|
||||
padding: theme.spacing.unit,
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
},
|
||||
image: {
|
||||
width: '120px',
|
||||
},
|
||||
imageContainer: {
|
||||
textAlign: 'center',
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
marginBottom: theme.spacing.unit * 2,
|
||||
},
|
||||
registerDeviceContainer: {
|
||||
textAlign: 'right',
|
||||
fontSize: theme.typography.fontSize * 0.8,
|
||||
},
|
||||
registerDevice: {},
|
||||
totpField: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
width: '100%',
|
||||
},
|
||||
totpButton: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
width: '100%',
|
||||
}
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,41 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
mainContent: {
|
||||
width: '440px',
|
||||
margin: '0 auto',
|
||||
padding: '50px 0px',
|
||||
},
|
||||
frame: {
|
||||
boxShadow: 'rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '5px',
|
||||
padding: '30px 40px',
|
||||
},
|
||||
innerFrame: {
|
||||
width: '100%',
|
||||
},
|
||||
title: {
|
||||
fontSize: '1.4em',
|
||||
fontWeight: 'bold',
|
||||
borderBottom: '5px solid ' + theme.palette.primary.main,
|
||||
display: 'inline-block',
|
||||
paddingRight: '10px',
|
||||
paddingBottom: '5px',
|
||||
},
|
||||
content: {
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
paddingBottom: theme.spacing.unit,
|
||||
},
|
||||
footer: {
|
||||
marginTop: '10px',
|
||||
textAlign: 'center',
|
||||
fontSize: '0.65em',
|
||||
color: 'grey',
|
||||
'& a': {
|
||||
color: 'grey',
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,33 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
form: {
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
},
|
||||
field: {
|
||||
width: '100%',
|
||||
},
|
||||
buttonsContainer: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
width: '100%',
|
||||
},
|
||||
buttonContainer: {
|
||||
width: '50%',
|
||||
display: 'inline-block',
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
buttonConfirmContainer: {
|
||||
paddingRight: theme.spacing.unit / 2,
|
||||
},
|
||||
buttonConfirm: {
|
||||
width: '100%',
|
||||
},
|
||||
buttonCancelContainer: {
|
||||
paddingLeft: theme.spacing.unit / 2,
|
||||
},
|
||||
buttonCancel: {
|
||||
width: '100%',
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,55 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const borderColor = '#e0e0e0';
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
secretContainer: {
|
||||
width: '100%',
|
||||
border: '1px solid ' + borderColor,
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
marginBottom: theme.spacing.unit * 2,
|
||||
},
|
||||
qrcodeContainer: {
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing.unit * 2,
|
||||
},
|
||||
base32Container: {
|
||||
textAlign: 'center',
|
||||
borderTop: '1px solid ' + borderColor,
|
||||
padding: theme.spacing.unit,
|
||||
wordWrap: 'break-word',
|
||||
},
|
||||
text: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
needGoogleAuthenticator: {
|
||||
textAlign: 'center',
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
},
|
||||
needGoogleAuthenticatorText: {
|
||||
fontSize: theme.typography.fontSize * 0.8,
|
||||
},
|
||||
store: {
|
||||
width: '100px',
|
||||
marginTop: theme.spacing.unit * 0.5,
|
||||
marginLeft: theme.spacing.unit * 0.5,
|
||||
marginRight: theme.spacing.unit * 0.5,
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: 'center',
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
},
|
||||
progressContainer: {
|
||||
textAlign: 'center',
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
},
|
||||
button: {
|
||||
marginLeft: theme.spacing.unit,
|
||||
marginRight: theme.spacing.unit,
|
||||
},
|
||||
loginButtonContainer: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,30 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
form: {
|
||||
marginTop: theme.spacing.unit * 2,
|
||||
},
|
||||
field: {
|
||||
width: '100%',
|
||||
marginBottom: theme.spacing.unit * 2,
|
||||
},
|
||||
buttonsContainer: {
|
||||
width: '100%',
|
||||
},
|
||||
buttonContainer: {
|
||||
width: '50%',
|
||||
boxSizing: 'border-box',
|
||||
display: 'inline-block',
|
||||
},
|
||||
buttonResetContainer: {
|
||||
paddingRight: theme.spacing.unit / 2,
|
||||
},
|
||||
buttonCancelContainer: {
|
||||
paddingLeft: theme.spacing.unit / 2,
|
||||
},
|
||||
button: {
|
||||
width: '100%',
|
||||
}
|
||||
}));
|
||||
|
||||
export default styles;
|
|
@ -1,19 +0,0 @@
|
|||
import { createStyles, Theme } from "@material-ui/core";
|
||||
|
||||
const styles = createStyles((theme: Theme) => ({
|
||||
infoContainer: {
|
||||
marginBottom: theme.spacing.unit * 2,
|
||||
},
|
||||
imageContainer: {
|
||||
textAlign: 'center',
|
||||
'& img': {
|
||||
width: '120px',
|
||||
},
|
||||
},
|
||||
retryButtonContainer: {
|
||||
textAlign: 'center',
|
||||
paddingTop: theme.spacing.unit * 2,
|
||||
},
|
||||
}));
|
||||
|
||||
export default styles;
|
2
client/src/assets/scss/_variables.scss
Normal file
2
client/src/assets/scss/_variables.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
$theme-spacing: 10px;
|
|
@ -0,0 +1,24 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messageContainer {
|
||||
color: green;
|
||||
|
||||
.username {
|
||||
display: block;
|
||||
font-size: 1.6em;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.statusIcon {
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.logoutButtonContainer {
|
||||
margin-top: ($theme-spacing) * 2,
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.notification {
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.field {
|
||||
padding-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttons button{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.rememberMe {
|
||||
float: left;
|
||||
font-size: 0.8em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: -11px;
|
||||
}
|
||||
|
||||
.resetPassword {
|
||||
height: 40px;
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.resetPassword a {
|
||||
color: black;
|
||||
font-size: 0.8em;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.container {
|
||||
color: white;
|
||||
font-size: 0.8em;
|
||||
padding: ($theme-spacing) * 2;
|
||||
border: 1px solid red;
|
||||
border-radius: 5px;
|
||||
background-color: #ff8d8d;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.container {
|
||||
position: relative,
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: ($theme-spacing);
|
||||
position: relative;
|
||||
|
||||
.hello {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logout {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
font-size: 0.6em,
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding-top: ($theme-spacing) * 2;
|
||||
padding-bottom: ($theme-spacing) * 2;
|
||||
padding-left: ($theme-spacing) * 2;
|
||||
padding-right: ($theme-spacing) * 2;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.methodName {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
margin-bottom: ($theme-spacing);
|
||||
}
|
||||
|
||||
.methodU2f {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: ($theme-spacing);
|
||||
}
|
||||
|
||||
.methodTotp {
|
||||
padding: ($theme-spacing);
|
||||
padding-top: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: '120px';
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
text-align: center;
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.registerDeviceContainer {
|
||||
text-align: right;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.totpField {
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.totpButton {
|
||||
margin-top: ($theme-spacing);
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
@import '../../variables.scss';
|
||||
@import "@material/theme/mdc-theme";
|
||||
|
||||
.mainContent {
|
||||
width: 440px;
|
||||
margin: auto;
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
padding-bottom: ($theme-spacing);
|
||||
}
|
||||
|
||||
.frame {
|
||||
box-shadow:
|
||||
rgba(0,0,0,0.14902) 0px 1px 1px 0px,
|
||||
rgba(0,0,0,0.09804) 0px 1px 2px 0px;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 40px;
|
||||
border-top: 6px solid ($mdc-theme-primary);
|
||||
}
|
||||
|
||||
.innerFrame {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
font-size: 0.65em;
|
||||
color: grey;
|
||||
|
||||
a:visited {
|
||||
color: grey;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.form {
|
||||
padding-top: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonsContainer {
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.buttonConfirmContainer {
|
||||
padding-right: ($theme-spacing) / 2;
|
||||
}
|
||||
|
||||
.buttonConfirm {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonCancelContainer {
|
||||
padding-left: ($theme-spacing) / 2;
|
||||
}
|
||||
|
||||
.buttonCancel {
|
||||
width: 100%;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.secretContainer {
|
||||
width: 100%;
|
||||
border: 1px solid #dcdcdc;
|
||||
border-radius: 10px;
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.qrcodeContainer {
|
||||
text-align: center;
|
||||
padding: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.base32Container {
|
||||
text-align: center;
|
||||
border-top: 1px solid #dcdcdc;
|
||||
padding: ($theme-spacing);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.needGoogleAuthenticator {
|
||||
text-align: center;
|
||||
margin-top: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.needGoogleAuthenticatorText {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.store {
|
||||
width: 100px;
|
||||
margin-top: ($theme-spacing) * 0.5;
|
||||
margin-left: ($theme-spacing) * 0.5;
|
||||
margin-right: ($theme-spacing) * 0.5;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
text-align: center;
|
||||
padding-top: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.progressContainer {
|
||||
text-align: center;
|
||||
padding-top: ($theme-spacing) * 2,
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-left: ($theme-spacing);
|
||||
margin-right: ($theme-spacing);
|
||||
}
|
||||
|
||||
.loginButtonContainer {
|
||||
text-align: center;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.form {
|
||||
margin-top: ($theme-spacing) * 2,
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.buttonsContainer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
width: 50%;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.buttonResetContainer {
|
||||
padding-right: ($theme-spacing) / 2;
|
||||
}
|
||||
|
||||
.buttonCancelContainer {
|
||||
padding-left: ($theme-spacing) / 2;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
@import '../../variables.scss';
|
||||
|
||||
.infoContainer {
|
||||
margin-bottom: ($theme-spacing) * 2;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.retryButtonContainer {
|
||||
text-align: center;
|
||||
padding-top: ($theme-spacing) * 2;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import styles from '../../assets/jss/components/AlreadyAuthenticated/AlreadyAuthenticated';
|
||||
import { WithStyles, withStyles, Button } from "@material-ui/core";
|
||||
import styles from '../../assets/scss/components/AlreadyAuthenticated/AlreadyAuthenticated.module.scss';
|
||||
import Button from "@material/react-button";
|
||||
import CircleLoader, { Status } from "../CircleLoader/CircleLoader";
|
||||
|
||||
export interface OwnProps {
|
||||
|
@ -12,26 +12,23 @@ export interface DispatchProps {
|
|||
onLogoutClicked: () => void;
|
||||
}
|
||||
|
||||
export type Props = OwnProps & DispatchProps & WithStyles;
|
||||
export type Props = OwnProps & DispatchProps;
|
||||
|
||||
class AlreadyAuthenticated extends Component<Props> {
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div className={classes.successContainer}>
|
||||
<CircleLoader status={Status.SUCCESSFUL} />
|
||||
<span className={classes.messageContainer}>
|
||||
<b>{this.props.username}</b><br/>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.successContainer}>
|
||||
<div className={styles.messageContainer}>
|
||||
<span className={styles.username}>{this.props.username}</span>
|
||||
you are authenticated
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.statusIcon}><CircleLoader status={Status.SUCCESSFUL} /></div>
|
||||
</div>
|
||||
<div>Close this tab or logout</div>
|
||||
<div className={classes.logoutButtonContainer}>
|
||||
<div className={styles.logoutButtonContainer}>
|
||||
<Button
|
||||
onClick={this.props.onLogoutClicked}
|
||||
variant="contained"
|
||||
color="primary">
|
||||
color="red">
|
||||
Logout
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -40,4 +37,4 @@ class AlreadyAuthenticated extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(AlreadyAuthenticated);
|
||||
export default AlreadyAuthenticated;
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from "react";
|
||||
import classnames from 'classnames';
|
||||
|
||||
import styles from './CircleLoader.module.scss';
|
||||
import styles from '../../assets/scss/components/CircleLoader/CircleLoader.module.scss';
|
||||
|
||||
export enum Status {
|
||||
LOADING,
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import React, { Component, KeyboardEvent, ChangeEvent } from "react";
|
||||
import React, { Component, KeyboardEvent, FormEvent } from "react";
|
||||
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import TextField, {Input} from '@material/react-text-field';
|
||||
import Button from '@material/react-button';
|
||||
import Checkbox from '@material/react-checkbox';
|
||||
|
||||
import { Link } from "react-router-dom";
|
||||
import { WithStyles, withStyles } from "@material-ui/core";
|
||||
|
||||
import styles from '../../assets/jss/components/FirstFactorForm/FirstFactorForm';
|
||||
import FormNotification from "../../components/FormNotification/FormNotification";
|
||||
import Notification from "../../components/Notification/Notification";
|
||||
|
||||
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'
|
||||
import CheckBoxIcon from '@material-ui/icons/CheckBox';
|
||||
import styles from '../../assets/scss/components/FirstFactorForm/FirstFactorForm.module.scss';
|
||||
|
||||
export interface StateProps {
|
||||
formDisabled: boolean;
|
||||
|
@ -24,7 +19,7 @@ export interface DispatchProps {
|
|||
onAuthenticationRequested(username: string, password: string): void;
|
||||
}
|
||||
|
||||
export type Props = StateProps & DispatchProps & WithStyles;
|
||||
export type Props = StateProps & DispatchProps;
|
||||
|
||||
interface State {
|
||||
username: string;
|
||||
|
@ -48,12 +43,14 @@ class FirstFactorForm extends Component<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
onUsernameChanged = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({username: e.target.value});
|
||||
onUsernameChanged = (e: FormEvent<HTMLElement>) => {
|
||||
const val = (e.target as HTMLInputElement).value;
|
||||
this.setState({username: val});
|
||||
}
|
||||
|
||||
onPasswordChanged = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({password: e.target.value});
|
||||
onPasswordChanged = (e: FormEvent<HTMLElement>) => {
|
||||
const val = (e.target as HTMLInputElement).value;
|
||||
this.setState({password: val});
|
||||
}
|
||||
|
||||
onLoginClicked = () => {
|
||||
|
@ -67,63 +64,61 @@ class FirstFactorForm extends Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<FormNotification
|
||||
show={this.props.error != null}>
|
||||
<Notification
|
||||
show={this.props.error != null}
|
||||
className={styles.notification}>
|
||||
{this.props.error || ''}
|
||||
</FormNotification>
|
||||
<div className={classes.fields}>
|
||||
<div className={classes.field}>
|
||||
</Notification>
|
||||
<div className={styles.fields}>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={classes.input}
|
||||
variant="outlined"
|
||||
id="username"
|
||||
className={styles.input}
|
||||
label="Username"
|
||||
disabled={this.props.formDisabled}
|
||||
onChange={this.onUsernameChanged}>
|
||||
outlined={true}>
|
||||
<Input
|
||||
id="username"
|
||||
onChange={this.onUsernameChanged}
|
||||
disabled={this.props.formDisabled}
|
||||
value={this.state.username}/>
|
||||
</TextField>
|
||||
</div>
|
||||
<div className={classes.field}>
|
||||
<div className={styles.field}>
|
||||
<TextField
|
||||
className={classes.input}
|
||||
id="password"
|
||||
variant="outlined"
|
||||
className={styles.input}
|
||||
label="Password"
|
||||
type="password"
|
||||
disabled={this.props.formDisabled}
|
||||
onChange={this.onPasswordChanged}
|
||||
onKeyPress={this.onPasswordKeyPressed}>
|
||||
outlined={true}>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
disabled={this.props.formDisabled}
|
||||
onChange={this.onPasswordChanged}
|
||||
onKeyPress={this.onPasswordKeyPressed}
|
||||
value={this.state.password} />
|
||||
</TextField>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={classes.buttons}>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
onClick={this.onLoginClicked}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
raised={true}
|
||||
disabled={this.props.formDisabled}>
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classes.controls}>
|
||||
<div className={classes.rememberMe}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
|
||||
checkedIcon={<CheckBoxIcon fontSize="small" />}
|
||||
checked={this.state.rememberMe}
|
||||
onChange={this.toggleRememberMe}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Remember me"
|
||||
<div className={styles.controls}>
|
||||
<div className={styles.rememberMe}>
|
||||
<Checkbox
|
||||
nativeControlId='remember-checkbox'
|
||||
checked={this.state.rememberMe}
|
||||
onChange={this.toggleRememberMe}
|
||||
/>
|
||||
<label htmlFor='remember-checkbox'>Remember me</label>
|
||||
</div>
|
||||
<div className={classes.resetPassword}>
|
||||
<div className={styles.resetPassword}>
|
||||
<Link to="/forgot-password">Forgot password?</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -139,4 +134,4 @@ class FirstFactorForm extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(FirstFactorForm);
|
||||
export default FirstFactorForm;
|
|
@ -1,27 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import { withStyles, WithStyles, Collapse } from "@material-ui/core";
|
||||
|
||||
import styles from '../../assets/jss/components/FormNotification/FormNotification';
|
||||
|
||||
interface Props extends WithStyles {
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
class FormNotification extends Component<Props> {
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<Collapse in={this.props.show}>
|
||||
<div className={classes.messageOuter}>
|
||||
<div className={classes.messageInner}>
|
||||
<div className={classes.messageContainer}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Collapse>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(FormNotification);
|
21
client/src/components/Notification/Notification.tsx
Normal file
21
client/src/components/Notification/Notification.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React, { Component } from "react";
|
||||
import classnames from 'classnames';
|
||||
|
||||
import styles from '../../assets/scss/components/Notification/Notification.module.scss';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
class Notification extends Component<Props> {
|
||||
render() {
|
||||
return (this.props.show)
|
||||
? (<div className={classnames(styles.container, this.props.className)}>
|
||||
{this.props.children}
|
||||
</div>)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
export default Notification;
|
|
@ -1,10 +1,11 @@
|
|||
import React, { Component, KeyboardEvent, ChangeEvent } from 'react';
|
||||
import React, { Component, KeyboardEvent, ChangeEvent, FormEvent } from 'react';
|
||||
|
||||
import { WithStyles, withStyles, Button, TextField } from '@material-ui/core';
|
||||
import TextField, { Input } from '@material/react-text-field';
|
||||
import Button from '@material/react-button';
|
||||
|
||||
import styles from '../../assets/jss/components/SecondFactorForm/SecondFactorForm';
|
||||
import styles from '../../assets/scss/components/SecondFactorForm/SecondFactorForm.module.scss';
|
||||
import CircleLoader, { Status } from '../../components/CircleLoader/CircleLoader';
|
||||
import FormNotification from '../FormNotification/FormNotification';
|
||||
import Notification from '../Notification/Notification';
|
||||
|
||||
export interface OwnProps {
|
||||
username: string;
|
||||
|
@ -29,7 +30,7 @@ export interface DispatchProps {
|
|||
onOneTimePasswordValidationRequested: (token: string) => void;
|
||||
}
|
||||
|
||||
export type Props = OwnProps & StateProps & DispatchProps & WithStyles;
|
||||
export type Props = OwnProps & StateProps & DispatchProps;
|
||||
|
||||
interface State {
|
||||
oneTimePassword: string;
|
||||
|
@ -48,7 +49,6 @@ class SecondFactorView extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private renderU2f(n: number) {
|
||||
const { classes } = this.props;
|
||||
let u2fStatus = Status.LOADING;
|
||||
if (this.props.securityKeyVerified) {
|
||||
u2fStatus = Status.SUCCESSFUL;
|
||||
|
@ -56,14 +56,14 @@ class SecondFactorView extends Component<Props, State> {
|
|||
u2fStatus = Status.FAILURE;
|
||||
}
|
||||
return (
|
||||
<div className={classes.methodU2f} key='u2f-method'>
|
||||
<div className={classes.methodName}>Option {n} - Security Key</div>
|
||||
<div className={styles.methodU2f} key='u2f-method'>
|
||||
<div className={styles.methodName}>Option {n} - Security Key</div>
|
||||
<div>Insert your security key into a USB port and touch the gold disk.</div>
|
||||
<div className={classes.imageContainer}>
|
||||
<div className={styles.imageContainer}>
|
||||
<CircleLoader status={u2fStatus}></CircleLoader>
|
||||
</div>
|
||||
<div className={classes.registerDeviceContainer}>
|
||||
<a className={classes.registerDevice} href="#"
|
||||
<div className={styles.registerDeviceContainer}>
|
||||
<a className={styles.registerDevice} href="#"
|
||||
onClick={this.props.onRegisterSecurityKeyClicked}>
|
||||
Register device
|
||||
</a>
|
||||
|
@ -72,8 +72,8 @@ class SecondFactorView extends Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private onOneTimePasswordChanged = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({oneTimePassword: e.target.value});
|
||||
private onOneTimePasswordChanged = (e: FormEvent<HTMLElement>) => {
|
||||
this.setState({oneTimePassword: (e.target as HTMLInputElement).value});
|
||||
}
|
||||
|
||||
private onTotpKeyPressed = (e: KeyboardEvent) => {
|
||||
|
@ -88,42 +88,43 @@ class SecondFactorView extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private renderTotp(n: number) {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.methodTotp} key='totp-method'>
|
||||
<div className={classes.methodName}>Option {n} - One-Time Password</div>
|
||||
<FormNotification show={this.props.oneTimePasswordVerificationError !== null}>
|
||||
<div className={styles.methodTotp} key='totp-method'>
|
||||
<div className={styles.methodName}>Option {n} - One-Time Password</div>
|
||||
<Notification show={this.props.oneTimePasswordVerificationError !== null}>
|
||||
{this.props.oneTimePasswordVerificationError}
|
||||
</FormNotification>
|
||||
</Notification>
|
||||
<TextField
|
||||
className={classes.totpField}
|
||||
name="totp-token"
|
||||
id="totp-token"
|
||||
variant="outlined"
|
||||
className={styles.totpField}
|
||||
label="One-Time Password"
|
||||
onChange={this.onOneTimePasswordChanged}
|
||||
onKeyPress={this.onTotpKeyPressed}>
|
||||
outlined={true}>
|
||||
<Input
|
||||
name="totp-token"
|
||||
id="totp-token"
|
||||
onChange={this.onOneTimePasswordChanged as any}
|
||||
onKeyPress={this.onTotpKeyPressed}
|
||||
value={this.state.oneTimePassword} />
|
||||
</TextField>
|
||||
<div className={classes.registerDeviceContainer}>
|
||||
<a className={classes.registerDevice} href="#"
|
||||
<div className={styles.registerDeviceContainer}>
|
||||
<a className={styles.registerDevice} href="#"
|
||||
onClick={this.props.onRegisterOneTimePasswordClicked}>
|
||||
Register device
|
||||
</a>
|
||||
</div>
|
||||
<Button
|
||||
className={classes.totpButton}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={this.onOneTimePasswordValidationRequested}
|
||||
disabled={this.props.oneTimePasswordVerificationInProgress}>
|
||||
OK
|
||||
</Button>
|
||||
<div className={styles.totpButton}>
|
||||
<Button
|
||||
color="primary"
|
||||
raised={true}
|
||||
onClick={this.onOneTimePasswordValidationRequested}
|
||||
disabled={this.props.oneTimePasswordVerificationInProgress}>
|
||||
OK
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private renderMode() {
|
||||
const { classes } = this.props;
|
||||
const methods = [];
|
||||
let n = 1;
|
||||
if (this.props.securityKeySupported) {
|
||||
|
@ -133,23 +134,22 @@ class SecondFactorView extends Component<Props, State> {
|
|||
methods.push(this.renderTotp(n));
|
||||
|
||||
return (
|
||||
<div className={classes.methodsContainer}>
|
||||
<div className={styles.methodsContainer}>
|
||||
{methods}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.hello}>Hello <b>{this.props.username}</b></div>
|
||||
<div className={classes.logout}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.hello}>Hello <b>{this.props.username}</b></div>
|
||||
<div className={styles.logout}>
|
||||
<a onClick={this.props.onLogoutClicked} href="#">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.body}>
|
||||
<div className={styles.body}>
|
||||
{this.renderMode()}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -157,4 +157,4 @@ class SecondFactorView extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(SecondFactorView);
|
||||
export default SecondFactorView;
|
|
@ -32,11 +32,14 @@ function onAuthenticationRequested(dispatch: Dispatch) {
|
|||
return;
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
if ('error' in json) {
|
||||
await dispatch(authenticateFailure(json['error']));
|
||||
return;
|
||||
if (res.status !== 204) {
|
||||
const json = await res.json();
|
||||
if ('error' in json) {
|
||||
await dispatch(authenticateFailure(json['error']));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(authenticateSuccess());
|
||||
|
||||
// fetch state
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,10 @@ import { Route, Switch, Redirect, RouterProps, RouteProps } from "react-router";
|
|||
|
||||
import { routes } from '../../routes/routes';
|
||||
import { AUTHELIA_GITHUB_URL } from "../../constants";
|
||||
import { WithStyles, withStyles } from "@material-ui/core";
|
||||
|
||||
import styles from '../../assets/jss/layouts/PortalLayout/PortalLayout';
|
||||
import styles from '../../assets/scss/layouts/PortalLayout/PortalLayout.module.scss';
|
||||
|
||||
interface Props extends RouterProps, RouteProps, WithStyles {}
|
||||
interface Props extends RouterProps, RouteProps {}
|
||||
|
||||
class PortalLayout extends Component<Props> {
|
||||
private renderTitle() {
|
||||
|
@ -25,15 +24,14 @@ class PortalLayout extends Component<Props> {
|
|||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.mainContent}>
|
||||
<div className={classes.frame}>
|
||||
<div className={classes.innerFrame}>
|
||||
<div className={classes.title}>
|
||||
{this.renderTitle()}
|
||||
</div>
|
||||
<div className={classes.content}>
|
||||
<div className={styles.main}>
|
||||
<div className={styles.mainContent}>
|
||||
<div className={styles.title}>
|
||||
{this.renderTitle()}
|
||||
</div>
|
||||
<div className={styles.frame}>
|
||||
<div className={styles.innerFrame}>
|
||||
<Switch>
|
||||
{routes.map((r, key) => {
|
||||
return <Route path={r.path} component={r.component} exact={true} key={key} />
|
||||
|
@ -42,13 +40,13 @@ class PortalLayout extends Component<Props> {
|
|||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.footer}>
|
||||
<div>Powered by <a href={AUTHELIA_GITHUB_URL}>Authelia</a></div>
|
||||
<div className={styles.footer}>
|
||||
<div><a href={AUTHELIA_GITHUB_URL}>Powered by Authelia</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(PortalLayout);
|
||||
export default PortalLayout;
|
|
@ -7,7 +7,7 @@ import AuthenticationView from "../containers/views/AuthenticationView/Authentic
|
|||
|
||||
export const routes = [{
|
||||
path: '/',
|
||||
title: 'Login',
|
||||
title: 'Sign in',
|
||||
component: AuthenticationView,
|
||||
}, {
|
||||
path: '/confirmation-sent',
|
||||
|
@ -15,11 +15,11 @@ export const routes = [{
|
|||
component: ConfirmationSentView
|
||||
}, {
|
||||
path: '/one-time-password-registration',
|
||||
title: 'One-time password registration',
|
||||
title: 'One-time password',
|
||||
component: OneTimePasswordRegistrationView,
|
||||
}, {
|
||||
path: '/security-key-registration',
|
||||
title: 'Security key registration',
|
||||
title: 'Security key',
|
||||
component: SecurityKeyRegistrationView,
|
||||
}, {
|
||||
path: '/forgot-password',
|
||||
|
|
|
@ -3,7 +3,7 @@ import AlreadyAuthenticated from "../../containers/components/AlreadyAuthenticat
|
|||
import FirstFactorForm from "../../containers/components/FirstFactorForm/FirstFactorForm";
|
||||
import SecondFactorForm from "../../containers/components/SecondFactorForm/SecondFactorForm";
|
||||
import RemoteState from "./RemoteState";
|
||||
import { RouterProps, Redirect } from "react-router";
|
||||
import { RouterProps } from "react-router";
|
||||
import queryString from 'query-string';
|
||||
|
||||
export enum Stage {
|
||||
|
|
|
@ -3,8 +3,8 @@ import classnames from 'classnames';
|
|||
|
||||
import mail from '../../assets/images/mail.png';
|
||||
|
||||
import styles from './ConfirmationSentView.module.css';
|
||||
import { Button } from "@material-ui/core";
|
||||
import styles from '../../assets/scss/views/ConfirmationSentView/ConfirmationSentView.module.scss';
|
||||
import Button from "@material/react-button";
|
||||
import { RouterProps } from "react-router";
|
||||
|
||||
interface Props extends RouterProps {}
|
||||
|
@ -22,7 +22,7 @@ class ConfirmationSentView extends Component<Props> {
|
|||
<Button
|
||||
onClick={() => this.props.history.goBack()}
|
||||
className={styles.button}
|
||||
variant="contained"
|
||||
raised={true}
|
||||
color="primary">
|
||||
Back
|
||||
</Button>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React, { Component, ChangeEvent, KeyboardEvent } from "react";
|
||||
import { TextField, WithStyles, withStyles, Button } from "@material-ui/core";
|
||||
import React, { Component, KeyboardEvent, FormEvent } from "react";
|
||||
import classnames from 'classnames';
|
||||
import Button from "@material/react-button";
|
||||
import TextField, { Input } from "@material/react-text-field";
|
||||
|
||||
import styles from '../../assets/jss/views/ForgotPasswordView/ForgotPasswordView';
|
||||
import styles from '../../assets/scss/views/ForgotPasswordView/ForgotPasswordView.module.scss';
|
||||
|
||||
export interface StateProps {
|
||||
disabled: boolean;
|
||||
|
@ -13,7 +14,7 @@ export interface DispatchProps {
|
|||
onCancelClicked: () => void;
|
||||
}
|
||||
|
||||
export type Props = StateProps & DispatchProps & WithStyles;
|
||||
export type Props = StateProps & DispatchProps;
|
||||
|
||||
interface State {
|
||||
username: string;
|
||||
|
@ -27,8 +28,8 @@ class ForgotPasswordView extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
private onUsernameChanged = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({username: e.target.value});
|
||||
private onUsernameChanged = (e: FormEvent<HTMLElement>) => {
|
||||
this.setState({username: (e.target as HTMLInputElement).value});
|
||||
}
|
||||
|
||||
private onKeyPressed = (e: KeyboardEvent) => {
|
||||
|
@ -43,38 +44,38 @@ class ForgotPasswordView extends Component<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<div>What's your username?</div>
|
||||
<div className={classes.form}>
|
||||
<div className={styles.form}>
|
||||
<TextField
|
||||
className={classes.field}
|
||||
variant="outlined"
|
||||
className={styles.field}
|
||||
outlined={true}
|
||||
id="username"
|
||||
label="Username"
|
||||
onChange={this.onUsernameChanged}
|
||||
onKeyPress={this.onKeyPressed}
|
||||
value={this.state.username}
|
||||
disabled={this.props.disabled}>
|
||||
label="Username">
|
||||
<Input
|
||||
onChange={this.onUsernameChanged}
|
||||
onKeyPress={this.onKeyPressed}
|
||||
value={this.state.username}
|
||||
disabled={this.props.disabled} />
|
||||
</TextField>
|
||||
<div className={classes.buttonsContainer}>
|
||||
<div className={classnames(classes.buttonContainer, classes.buttonConfirmContainer)}>
|
||||
<div className={styles.buttonsContainer}>
|
||||
<div className={classnames(styles.buttonContainer, styles.buttonConfirmContainer)}>
|
||||
<Button
|
||||
onClick={this.onPasswordResetRequested}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.buttonConfirm}
|
||||
raised={true}
|
||||
className={styles.buttonConfirm}
|
||||
disabled={this.props.disabled}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classnames(classes.buttonContainer, classes.buttonCancelContainer)}>
|
||||
<div className={classnames(styles.buttonContainer, styles.buttonCancelContainer)}>
|
||||
<Button
|
||||
onClick={this.props.onCancelClicked}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.buttonCancel}>
|
||||
raised={true}
|
||||
className={styles.buttonCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -85,4 +86,4 @@ class ForgotPasswordView extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ForgotPasswordView);
|
||||
export default ForgotPasswordView;
|
|
@ -1,19 +1,20 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import { WithStyles, withStyles, CircularProgress, Button } from "@material-ui/core";
|
||||
import Button from "@material/react-button";
|
||||
|
||||
import styles from '../../assets/jss/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView';
|
||||
import styles from '../../assets/scss/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.module.scss';
|
||||
import { RouteProps, RouterProps } from "react-router";
|
||||
import QueryString from 'query-string';
|
||||
|
||||
import QRCode from 'qrcode.react';
|
||||
import FormNotification from "../../components/FormNotification/FormNotification";
|
||||
import Notification from "../../components/Notification/Notification";
|
||||
|
||||
import googleStoreImage from '../../assets/images/googleplay-badge.svg';
|
||||
import appleStoreImage from '../../assets/images/applestore-badge.svg';
|
||||
import { Secret } from "./Secret";
|
||||
import CircleLoader, { Status } from "../../components/CircleLoader/CircleLoader";
|
||||
|
||||
export interface Props extends WithStyles, RouteProps, RouterProps {
|
||||
export interface Props extends RouteProps, RouterProps {
|
||||
secret: Secret | null;
|
||||
error: string | null;
|
||||
onInit: (token: string) => void;
|
||||
|
@ -47,54 +48,52 @@ class OneTimePasswordRegistrationView extends Component<Props> {
|
|||
}
|
||||
|
||||
private renderWithSecret(secret: Secret) {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.text}>
|
||||
<div className={styles.text}>
|
||||
Register your device by scanning the barcode or adding the key.
|
||||
</div>
|
||||
<div className={classes.secretContainer}>
|
||||
<div className={classes.qrcodeContainer}>
|
||||
<div className={styles.secretContainer}>
|
||||
<div className={styles.qrcodeContainer}>
|
||||
<QRCode value={secret.otpauth_url} size={180} level="Q"></QRCode>
|
||||
</div>
|
||||
<div className={classes.base32Container}>{secret.base32_secret}</div>
|
||||
<div className={styles.base32Container}>{secret.base32_secret}</div>
|
||||
</div>
|
||||
<div className={classes.loginButtonContainer}>
|
||||
<div className={styles.loginButtonContainer}>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="contained"
|
||||
raised={true}
|
||||
onClick={this.props.onLoginClicked}>
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classes.needGoogleAuthenticator}>
|
||||
<div className={classes.needGoogleAuthenticatorText}>Need Google Authenticator?</div>
|
||||
<img src={appleStoreImage} className={classes.store} alt='Google Authenticator on Apple Store'/>
|
||||
<img src={googleStoreImage} className={classes.store} alt='Google Authenticator on Google Store'/>
|
||||
<div className={styles.needGoogleAuthenticator}>
|
||||
<div className={styles.needGoogleAuthenticatorText}>Need Google Authenticator?</div>
|
||||
<img src={appleStoreImage} className={styles.store} alt='Google Authenticator on Apple Store'/>
|
||||
<img src={googleStoreImage} className={styles.store} alt='Google Authenticator on Google Store'/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private renderError() {
|
||||
const {classes} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<FormNotification show={true}>
|
||||
<Notification show={true}>
|
||||
<div>{this.props.error}</div>
|
||||
</FormNotification>
|
||||
<div className={classes.buttonContainer}>
|
||||
</Notification>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
raised={true}
|
||||
className={styles.button}
|
||||
onClick={this.props.onRetryClicked}>
|
||||
Retry
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
raised={true}
|
||||
className={styles.button}
|
||||
onClick={this.props.onCancelClicked}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
@ -110,11 +109,10 @@ class OneTimePasswordRegistrationView extends Component<Props> {
|
|||
}
|
||||
|
||||
private renderLoading() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<div>One-Time password secret is being generated...</div>
|
||||
<div className={classes.progressContainer}><CircularProgress /></div>
|
||||
<div className={styles.progressContainer}><CircleLoader status={Status.LOADING} /></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -126,4 +124,4 @@ class OneTimePasswordRegistrationView extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(OneTimePasswordRegistrationView);
|
||||
export default OneTimePasswordRegistrationView;
|
|
@ -1,11 +1,13 @@
|
|||
import React, { Component, KeyboardEvent, ChangeEvent } from "react";
|
||||
import { TextField, Button, WithStyles, withStyles } from "@material-ui/core";
|
||||
import React, { Component, KeyboardEvent, FormEvent } from "react";
|
||||
import { RouterProps } from "react-router";
|
||||
import classnames from 'classnames';
|
||||
import QueryString from 'query-string';
|
||||
|
||||
import styles from '../../assets/jss/views/ResetPasswordView/ResetPasswordView';
|
||||
import FormNotification from "../../components/FormNotification/FormNotification";
|
||||
import Button from "@material/react-button";
|
||||
import TextField, { Input } from "@material/react-text-field";
|
||||
|
||||
import styles from '../../assets/scss/views/ResetPasswordView/ResetPasswordView.module.scss';
|
||||
import Notification from "../../components/Notification/Notification";
|
||||
|
||||
export interface StateProps {
|
||||
disabled: boolean;
|
||||
|
@ -17,7 +19,7 @@ export interface DispatchProps {
|
|||
onCancelClicked: () => void;
|
||||
}
|
||||
|
||||
export type Props = StateProps & DispatchProps & RouterProps & WithStyles;
|
||||
export type Props = StateProps & DispatchProps & RouterProps;
|
||||
|
||||
interface State {
|
||||
password1: string;
|
||||
|
@ -66,61 +68,64 @@ class ResetPasswordView extends Component<Props, State> {
|
|||
this.onPasswordResetRequested();
|
||||
}
|
||||
|
||||
private onPassword1Changed = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({password1: e.target.value});
|
||||
private onPassword1Changed = (e: FormEvent<HTMLElement>) => {
|
||||
this.setState({password1: (e.target as HTMLInputElement).value});
|
||||
}
|
||||
|
||||
private onPassword2Changed = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({password2: e.target.value});
|
||||
private onPassword2Changed = (e: FormEvent<HTMLElement>) => {
|
||||
this.setState({password2: (e.target as HTMLInputElement).value});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<FormNotification show={this.state.error !== null}>
|
||||
<Notification show={this.state.error !== null}>
|
||||
{this.state.error}
|
||||
</FormNotification>
|
||||
</Notification>
|
||||
<div>Enter your new password</div>
|
||||
<div className={classes.form}>
|
||||
<div className={styles.form}>
|
||||
<TextField
|
||||
className={classes.field}
|
||||
variant="outlined"
|
||||
type="password"
|
||||
className={styles.field}
|
||||
outlined={true}
|
||||
id="password1"
|
||||
value={this.state.password1}
|
||||
onChange={this.onPassword1Changed}
|
||||
disabled={this.props.disabled}
|
||||
label="New password">
|
||||
<Input
|
||||
type="password"
|
||||
key="password1"
|
||||
value={this.state.password1}
|
||||
onChange={this.onPassword1Changed}
|
||||
disabled={this.props.disabled}/>
|
||||
</TextField>
|
||||
<TextField
|
||||
className={classes.field}
|
||||
variant="outlined"
|
||||
type="password"
|
||||
className={styles.field}
|
||||
outlined={true}
|
||||
id="password2"
|
||||
value={this.state.password2}
|
||||
onKeyPress={this.onKeyPressed}
|
||||
onChange={this.onPassword2Changed}
|
||||
disabled={this.props.disabled}
|
||||
label="Confirm password">
|
||||
<Input
|
||||
type="password"
|
||||
key="password2"
|
||||
value={this.state.password2}
|
||||
onKeyPress={this.onKeyPressed}
|
||||
onChange={this.onPassword2Changed}
|
||||
disabled={this.props.disabled} />
|
||||
</TextField>
|
||||
<div className={classes.buttonsContainer}>
|
||||
<div className={classnames(classes.buttonContainer, classes.buttonResetContainer)}>
|
||||
<div className={styles.buttonsContainer}>
|
||||
<div className={classnames(styles.buttonContainer, styles.buttonResetContainer)}>
|
||||
<Button
|
||||
onClick={this.onResetClicked}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
raised={true}
|
||||
disabled={this.props.disabled}
|
||||
className={classnames(classes.button, classes.buttonReset)}>
|
||||
className={classnames(styles.button, styles.buttonReset)}>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classnames(classes.buttonContainer, classes.buttonCancelContainer)}>
|
||||
<div className={classnames(styles.buttonContainer, styles.buttonCancelContainer)}>
|
||||
<Button
|
||||
onClick={this.props.onCancelClicked}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classnames(classes.button, classes.buttonCancel)}>
|
||||
raised={true}
|
||||
className={classnames(styles.button, styles.buttonCancel)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -131,4 +136,4 @@ class ResetPasswordView extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ResetPasswordView);
|
||||
export default ResetPasswordView;
|
|
@ -1,14 +1,14 @@
|
|||
import React, { Component } from "react";
|
||||
|
||||
import { WithStyles, withStyles, Button } from "@material-ui/core";
|
||||
import Button from "@material/react-button";
|
||||
|
||||
import styles from '../../assets/jss/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView';
|
||||
import styles from '../../assets/scss/views/SecurityKeyRegistrationView/SecurityKeyRegistrationView.module.scss';
|
||||
import { RouteProps, RouterProps } from "react-router";
|
||||
import QueryString from 'query-string';
|
||||
import FormNotification from "../../components/FormNotification/FormNotification";
|
||||
import Notification from "../../components/Notification/Notification";
|
||||
import CircleLoader, { Status } from "../../components/CircleLoader/CircleLoader";
|
||||
|
||||
export interface Props extends WithStyles, RouteProps, RouterProps {
|
||||
export interface Props extends RouteProps, RouterProps {
|
||||
deviceRegistered: boolean | null;
|
||||
error: string | null;
|
||||
onInit: (token: string) => void;
|
||||
|
@ -32,16 +32,15 @@ class SecurityKeyRegistrationView extends Component<Props> {
|
|||
}
|
||||
|
||||
private renderError() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<FormNotification show={true}>
|
||||
<Notification show={true}>
|
||||
{this.props.error}
|
||||
</FormNotification>
|
||||
<div className={classes.retryButtonContainer}>
|
||||
</Notification>
|
||||
<div className={styles.retryButtonContainer}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
raised={true}
|
||||
onClick={this.props.onBackClicked}>
|
||||
Back
|
||||
</Button>
|
||||
|
@ -51,7 +50,6 @@ class SecurityKeyRegistrationView extends Component<Props> {
|
|||
}
|
||||
|
||||
private renderRegistering() {
|
||||
const { classes } = this.props;
|
||||
let status = Status.LOADING;
|
||||
if (this.props.deviceRegistered === true) {
|
||||
status = Status.SUCCESSFUL;
|
||||
|
@ -60,8 +58,8 @@ class SecurityKeyRegistrationView extends Component<Props> {
|
|||
}
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.infoContainer}>Press the gold disk to register your security key</div>
|
||||
<div className={classes.imageContainer}>
|
||||
<div className={styles.infoContainer}>Press the gold disk to register your security key</div>
|
||||
<div className={styles.imageContainer}>
|
||||
<CircleLoader status={status}></CircleLoader>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -77,4 +75,4 @@ class SecurityKeyRegistrationView extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(SecurityKeyRegistrationView);
|
||||
export default SecurityKeyRegistrationView;
|
68
package-lock.json
generated
68
package-lock.json
generated
|
@ -285,7 +285,7 @@
|
|||
},
|
||||
"@types/events": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
||||
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -312,7 +312,7 @@
|
|||
},
|
||||
"@types/express-session": {
|
||||
"version": "1.15.8",
|
||||
"resolved": "http://registry.npmjs.org/@types/express-session/-/express-session-1.15.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.15.8.tgz",
|
||||
"integrity": "sha512-Be5N9zul4C/IH1UjRDaVJ46wkG1jsBgJlihBdWlqJWfCaiqvaVmxcyqcLey7omSFGCTIUDgdHqf0vwNjEZOSVA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -358,7 +358,7 @@
|
|||
},
|
||||
"@types/ldapjs": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "http://registry.npmjs.org/@types/ldapjs/-/ldapjs-1.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-1.0.3.tgz",
|
||||
"integrity": "sha512-FSj24s1WsFEfOy8taIKp2DokSZfFkjWYZb88AS5eDj3WTocZ+4DnHjhzrXEs048WQ5mfOLJXMOAnc0kSnHh5Lw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -380,7 +380,7 @@
|
|||
},
|
||||
"@types/mockdate": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "http://registry.npmjs.org/@types/mockdate/-/mockdate-2.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/mockdate/-/mockdate-2.0.0.tgz",
|
||||
"integrity": "sha1-qvOIoerTsPXtbcFhGVbqe0ClfTw=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -598,7 +598,7 @@
|
|||
},
|
||||
"@types/yamljs": {
|
||||
"version": "0.2.30",
|
||||
"resolved": "http://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.30.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/yamljs/-/yamljs-0.2.30.tgz",
|
||||
"integrity": "sha1-0DTh0ynkbo0Pc3yajbl/aPgbU4I=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -844,7 +844,7 @@
|
|||
},
|
||||
"array-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
|
||||
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -1058,7 +1058,7 @@
|
|||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -1536,7 +1536,7 @@
|
|||
},
|
||||
"browserify-aes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -1621,7 +1621,7 @@
|
|||
},
|
||||
"browserify-rsa": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -1660,7 +1660,7 @@
|
|||
},
|
||||
"buffer": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -1753,7 +1753,7 @@
|
|||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2158,7 +2158,7 @@
|
|||
},
|
||||
"create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2171,7 +2171,7 @@
|
|||
},
|
||||
"create-hmac": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2564,7 +2564,7 @@
|
|||
},
|
||||
"diffie-hellman": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2628,7 +2628,7 @@
|
|||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -2892,7 +2892,7 @@
|
|||
},
|
||||
"events": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -3178,7 +3178,7 @@
|
|||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
|
||||
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
|
@ -3866,7 +3866,7 @@
|
|||
},
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -4744,7 +4744,7 @@
|
|||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
|
@ -4936,7 +4936,7 @@
|
|||
},
|
||||
"is-builtin-module": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
|
||||
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5740,7 +5740,7 @@
|
|||
},
|
||||
"load-json-file": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5986,7 +5986,7 @@
|
|||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"mem": {
|
||||
|
@ -6000,7 +6000,7 @@
|
|||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -6137,7 +6137,7 @@
|
|||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
|
@ -6339,7 +6339,7 @@
|
|||
},
|
||||
"ncp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "http://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
|
||||
"optional": true
|
||||
},
|
||||
|
@ -8222,7 +8222,7 @@
|
|||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -8309,7 +8309,7 @@
|
|||
},
|
||||
"parse-asn1": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
|
||||
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -8384,7 +8384,7 @@
|
|||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"path-is-inside": {
|
||||
|
@ -9062,7 +9062,7 @@
|
|||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -9581,7 +9581,7 @@
|
|||
},
|
||||
"sha.js": {
|
||||
"version": "2.4.11",
|
||||
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -10160,7 +10160,7 @@
|
|||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -10252,7 +10252,7 @@
|
|||
},
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -11312,7 +11312,7 @@
|
|||
"dependencies": {
|
||||
"async": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
|
||||
"integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
|
||||
}
|
||||
}
|
||||
|
@ -11333,7 +11333,7 @@
|
|||
},
|
||||
"wrap-ansi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
|
||||
export const PRE_VALIDATION_TEMPLATE = "need-identity-validation";
|
|
@ -1,3 +1,3 @@
|
|||
import { default as Level } from '../../../../shared/AuthenticationLevel';
|
||||
import { default as Level } from "../../../../shared/AuthenticationLevel";
|
||||
|
||||
export {Level};
|
||||
export { Level };
|
||||
|
|
|
@ -8,7 +8,7 @@ import UserMessages = require("../../../../../shared/UserMessages");
|
|||
import { ServerVariables } from "../../ServerVariables";
|
||||
import { AuthenticationSession } from "../../../../types/AuthenticationSession";
|
||||
import { GroupsAndEmails } from "../../authentication/backends/GroupsAndEmails";
|
||||
import {Level} from "../../authentication/Level";
|
||||
import { Level } from "../../authentication/Level";
|
||||
|
||||
export default function (vars: ServerVariables) {
|
||||
return function (req: express.Request, res: express.Response)
|
||||
|
@ -65,4 +65,4 @@ export default function (vars: ServerVariables) {
|
|||
})
|
||||
.catch(ErrorReplies.replyWithError200(req, res, vars.logger, UserMessages.AUTHENTICATION_FAILED));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ import objectPath = require("object-path");
|
|||
import exceptions = require("../../../Exceptions");
|
||||
import { Identity } from "../../../../../types/Identity";
|
||||
import { IdentityValidable } from "../../../IdentityValidable";
|
||||
import { PRE_VALIDATION_TEMPLATE } from "../../../IdentityCheckPreValidationTemplate";
|
||||
import Constants = require("../constants");
|
||||
import { IRequestLogger } from "../../../logging/IRequestLogger";
|
||||
import { IUsersDatabase } from "../../../authentication/backends/IUsersDatabase";
|
||||
|
||||
export const TEMPLATE_NAME = "password-reset-form";
|
||||
|
||||
export default class PasswordResetHandler implements IdentityValidable {
|
||||
private logger: IRequestLogger;
|
||||
private usersDatabase: IUsersDatabase;
|
||||
|
@ -52,7 +49,8 @@ export default class PasswordResetHandler implements IdentityValidable {
|
|||
}
|
||||
|
||||
preValidationResponse(req: express.Request, res: express.Response) {
|
||||
res.render(PRE_VALIDATION_TEMPLATE);
|
||||
res.status(204);
|
||||
res.send();
|
||||
}
|
||||
|
||||
postValidationInit(req: express.Request) {
|
||||
|
@ -60,7 +58,8 @@ export default class PasswordResetHandler implements IdentityValidable {
|
|||
}
|
||||
|
||||
postValidationResponse(req: express.Request, res: express.Response) {
|
||||
res.render(TEMPLATE_NAME);
|
||||
res.status(204);
|
||||
res.send();
|
||||
}
|
||||
|
||||
mailSubject(): string {
|
||||
|
|
|
@ -4,7 +4,6 @@ import BluebirdPromise = require("bluebird");
|
|||
|
||||
import { Identity } from "../../../../../../types/Identity";
|
||||
import { IdentityValidable } from "../../../../IdentityValidable";
|
||||
import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate";
|
||||
import Constants = require("../constants");
|
||||
import ErrorReplies = require("../../../../ErrorReplies");
|
||||
import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler";
|
||||
|
@ -64,7 +63,8 @@ export default class RegistrationHandler implements IdentityValidable {
|
|||
}
|
||||
|
||||
preValidationResponse(req: express.Request, res: express.Response) {
|
||||
res.render(PRE_VALIDATION_TEMPLATE);
|
||||
res.status(204);
|
||||
res.send();
|
||||
}
|
||||
|
||||
postValidationInit(req: express.Request) {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import express = require("express");
|
||||
import objectPath = require("object-path");
|
||||
|
||||
import { IdentityValidable } from "../../../../IdentityValidable";
|
||||
import { Identity } from "../../../../../../types/Identity";
|
||||
import { PRE_VALIDATION_TEMPLATE } from "../../../../IdentityCheckPreValidationTemplate";
|
||||
import FirstFactorValidator = require("../../../../FirstFactorValidator");
|
||||
import { AuthenticationSessionHandler } from "../../../../AuthenticationSessionHandler";
|
||||
import { IRequestLogger } from "../../../../logging/IRequestLogger";
|
||||
|
@ -13,8 +11,6 @@ import { IRequestLogger } from "../../../../logging/IRequestLogger";
|
|||
const CHALLENGE = "u2f-register";
|
||||
const MAIL_SUBJECT = "Register your security key with Authelia";
|
||||
|
||||
const POST_VALIDATION_TEMPLATE_NAME = "u2f-register";
|
||||
|
||||
|
||||
export default class RegistrationHandler implements IdentityValidable {
|
||||
private logger: IRequestLogger;
|
||||
|
@ -55,7 +51,8 @@ export default class RegistrationHandler implements IdentityValidable {
|
|||
}
|
||||
|
||||
preValidationResponse(req: express.Request, res: express.Response) {
|
||||
res.render(PRE_VALIDATION_TEMPLATE);
|
||||
res.status(204);
|
||||
res.send();
|
||||
}
|
||||
|
||||
postValidationInit(req: express.Request) {
|
||||
|
@ -63,7 +60,8 @@ export default class RegistrationHandler implements IdentityValidable {
|
|||
}
|
||||
|
||||
postValidationResponse(req: express.Request, res: express.Response) {
|
||||
res.render(POST_VALIDATION_TEMPLATE_NAME);
|
||||
res.status(204);
|
||||
res.send();
|
||||
}
|
||||
|
||||
mailSubject(): string {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as Express from 'express';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import * as Express from "express";
|
||||
import * as Bluebird from "bluebird";
|
||||
import { ServerVariables } from "../../ServerVariables";
|
||||
import { AuthenticationSessionHandler } from '../../AuthenticationSessionHandler';
|
||||
import { AuthenticationSessionHandler } from "../../AuthenticationSessionHandler";
|
||||
|
||||
export default function (vars: ServerVariables) {
|
||||
return function (req: Express.Request, res: Express.Response): Bluebird<void> {
|
||||
|
@ -10,7 +10,7 @@ export default function (vars: ServerVariables) {
|
|||
res.json({
|
||||
username: authSession.userid,
|
||||
authentication_level: authSession.authentication_level
|
||||
})
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import request = require("request");
|
||||
import assert = require("assert");
|
||||
import Endpoints = require("../../shared/api");
|
||||
|
||||
declare module "request" {
|
||||
export interface RequestAPI<TRequest extends Request,
|
||||
TOptions extends CoreOptions,
|
||||
TUriUrlOptions> {
|
||||
getAsync(uri: string, options?: RequiredUriUrl): BluebirdPromise<RequestResponse>;
|
||||
getAsync(uri: string): BluebirdPromise<RequestResponse>;
|
||||
getAsync(options: RequiredUriUrl & CoreOptions): BluebirdPromise<RequestResponse>;
|
||||
|
||||
postAsync(uri: string, options?: CoreOptions): BluebirdPromise<RequestResponse>;
|
||||
postAsync(uri: string): BluebirdPromise<RequestResponse>;
|
||||
postAsync(options: RequiredUriUrl & CoreOptions): BluebirdPromise<RequestResponse>;
|
||||
}
|
||||
}
|
||||
|
||||
const requestAsync: typeof request = BluebirdPromise.promisifyAll(request) as typeof request;
|
||||
|
||||
export = function (port: number) {
|
||||
const PORT = port;
|
||||
const BASE_URL = "http://localhost:" + PORT;
|
||||
|
||||
function execute_totp(jar: request.CookieJar, token: string) {
|
||||
return requestAsync.postAsync({
|
||||
url: BASE_URL + Endpoints.SECOND_FACTOR_TOTP_POST,
|
||||
jar: jar,
|
||||
form: {
|
||||
token: token
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function execute_u2f_authentication(jar: request.CookieJar) {
|
||||
return requestAsync.getAsync({
|
||||
url: BASE_URL + Endpoints.SECOND_FACTOR_U2F_SIGN_REQUEST_GET,
|
||||
jar: jar
|
||||
})
|
||||
.then(function (res: request.RequestResponse) {
|
||||
assert.equal(res.statusCode, 200);
|
||||
return requestAsync.postAsync({
|
||||
url: BASE_URL + Endpoints.SECOND_FACTOR_U2F_SIGN_POST,
|
||||
jar: jar,
|
||||
form: {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function execute_verification(jar: request.CookieJar) {
|
||||
return requestAsync.getAsync({ url: BASE_URL + Endpoints.VERIFY_GET, jar: jar });
|
||||
}
|
||||
|
||||
function execute_login(jar: request.CookieJar) {
|
||||
return requestAsync.getAsync({ url: BASE_URL + Endpoints.FIRST_FACTOR_GET, jar: jar });
|
||||
}
|
||||
|
||||
function execute_first_factor(jar: request.CookieJar) {
|
||||
return requestAsync.postAsync({
|
||||
url: BASE_URL + Endpoints.FIRST_FACTOR_POST,
|
||||
jar: jar,
|
||||
form: {
|
||||
username: "test_ok",
|
||||
password: "password"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function execute_failing_first_factor(jar: request.CookieJar) {
|
||||
return requestAsync.postAsync({
|
||||
url: BASE_URL + Endpoints.FIRST_FACTOR_POST,
|
||||
jar: jar,
|
||||
form: {
|
||||
username: "test_nok",
|
||||
password: "password"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
login: execute_login,
|
||||
verify: execute_verification,
|
||||
u2f_authentication: execute_u2f_authentication,
|
||||
first_factor: execute_first_factor,
|
||||
failing_first_factor: execute_failing_first_factor,
|
||||
totp: execute_totp,
|
||||
};
|
||||
};
|
||||
|
|
@ -2,6 +2,6 @@ enum Level {
|
|||
NOT_AUTHENTICATED = 0,
|
||||
ONE_FACTOR = 1,
|
||||
TWO_FACTOR = 2
|
||||
};
|
||||
}
|
||||
|
||||
export default Level;
|
||||
export default Level;
|
||||
|
|
|
@ -244,10 +244,10 @@ export const FIRST_FACTOR_POST = "/api/firstfactor";
|
|||
* @apiName State
|
||||
* @apiGroup Authentication
|
||||
* @apiVersion 1.0.0
|
||||
*
|
||||
*
|
||||
* @apiSuccess (Success 200) A dict containing the username and the authentication
|
||||
* level
|
||||
*
|
||||
*
|
||||
* @apiDescription Get the authentication state of the user based on the cookie.
|
||||
*/
|
||||
export const STATE_GET = "/api/state";
|
||||
|
|
Loading…
Reference in New Issue
Block a user