cleaned stuffs up
This commit is contained in:
parent
63689e14ff
commit
a259f419fe
@ -49,19 +49,24 @@ interface DeviceViewProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DeviceView extends React.Component<DeviceViewProps> {
|
class DeviceView extends React.Component<DeviceViewProps> {
|
||||||
device!: SprinklersDevice;
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.updateDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUpdate() {
|
|
||||||
this.updateDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { id, connectionState, sections, programs, sectionRunner } = this.device;
|
const { uiStore, sprinklersApi } = this.props.state;
|
||||||
const { uiStore } = this.props.state;
|
const device = sprinklersApi.getDevice(this.props.deviceId);
|
||||||
|
const { id, connectionState, sections, programs, sectionRunner } = device;
|
||||||
|
const deviceBody = connectionState.isAvailable && (
|
||||||
|
<React.Fragment>
|
||||||
|
<SectionRunnerView sectionRunner={sectionRunner} sections={sections}/>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Column mobile="16" tablet="16" computer="8">
|
||||||
|
<SectionTable sections={sections}/>
|
||||||
|
</Grid.Column>
|
||||||
|
<Grid.Column mobile="16" tablet="16" computer="8">
|
||||||
|
<RunSectionForm device={device} uiStore={uiStore}/>
|
||||||
|
</Grid.Column>
|
||||||
|
</Grid>
|
||||||
|
<ProgramTable programs={programs} sections={sections}/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Item>
|
<Item>
|
||||||
<Item.Image src={require("@app/images/raspberry_pi.png")}/>
|
<Item.Image src={require("@app/images/raspberry_pi.png")}/>
|
||||||
@ -73,32 +78,11 @@ class DeviceView extends React.Component<DeviceViewProps> {
|
|||||||
<Item.Meta>
|
<Item.Meta>
|
||||||
Raspberry Pi Grinklers Device
|
Raspberry Pi Grinklers Device
|
||||||
</Item.Meta>
|
</Item.Meta>
|
||||||
{connectionState.isAvailable &&
|
{deviceBody}
|
||||||
<SectionRunnerView sectionRunner={sectionRunner} sections={sections}/>}
|
|
||||||
{connectionState.isAvailable &&
|
|
||||||
<Grid>
|
|
||||||
<Grid.Column mobile="16" tablet="16" computer="8">
|
|
||||||
<SectionTable sections={sections}/>
|
|
||||||
</Grid.Column>
|
|
||||||
<Grid.Column mobile="16" tablet="16" computer="8">
|
|
||||||
<RunSectionForm device={this.device} uiStore={uiStore}/>
|
|
||||||
</Grid.Column>
|
|
||||||
</Grid>
|
|
||||||
}
|
|
||||||
{connectionState.isAvailable &&
|
|
||||||
<ProgramTable programs={programs} sections={sections}/>
|
|
||||||
}
|
|
||||||
</Item.Content>
|
</Item.Content>
|
||||||
</Item>
|
</Item>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateDevice() {
|
|
||||||
const { state, deviceId } = this.props;
|
|
||||||
if (!this.device || this.device.id !== deviceId) {
|
|
||||||
this.device = state.sprinklersApi.getDevice(deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectState(observer(DeviceView));
|
export default injectState(observer(DeviceView));
|
||||||
|
@ -74,7 +74,7 @@ export default class ProgramTable extends React.Component<{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderRows = (program: Program, i: number): JSX.Element[] | null => {
|
private renderRows = (program: Program, i: number): JSX.Element | null => {
|
||||||
if (!program) {
|
if (!program) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -87,8 +87,8 @@ export default class ProgramTable extends React.Component<{
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
const cancelOrRun = () => running ? program.cancel() : program.run();
|
const cancelOrRun = () => running ? program.cancel() : program.run();
|
||||||
const rows = [(
|
const mainRow = (
|
||||||
<Table.Row key={i}>
|
<Table.Row>
|
||||||
<Table.Cell className="program--number">{"" + (i + 1)}</Table.Cell>
|
<Table.Cell className="program--number">{"" + (i + 1)}</Table.Cell>
|
||||||
<Table.Cell className="program--name">{name}</Table.Cell>
|
<Table.Cell className="program--name">{name}</Table.Cell>
|
||||||
<Table.Cell className="program--enabled">{enabled ? "Enabled" : "Not enabled"}</Table.Cell>
|
<Table.Cell className="program--enabled">{enabled ? "Enabled" : "Not enabled"}</Table.Cell>
|
||||||
@ -100,17 +100,20 @@ export default class ProgramTable extends React.Component<{
|
|||||||
</Button>
|
</Button>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
)];
|
);
|
||||||
if (false) {
|
const detailRow = false && (
|
||||||
rows.push(
|
<Table.Row>
|
||||||
<Table.Row key={i + .5}>
|
<Table.Cell className="program--sequence" colSpan="4">
|
||||||
<Table.Cell className="program--sequence" colSpan="4">
|
<h4>Sequence: </h4> {sequenceItems}
|
||||||
<h4>Sequence: </h4> {sequenceItems}
|
<h4>Schedule: </h4> <ScheduleView schedule={schedule}/>
|
||||||
<h4>Schedule: </h4> <ScheduleView schedule={schedule}/>
|
</Table.Cell>
|
||||||
</Table.Cell>
|
</Table.Row>
|
||||||
</Table.Row>,
|
);
|
||||||
);
|
return (
|
||||||
}
|
<React.Fragment key={i}>
|
||||||
return rows;
|
{mainRow}
|
||||||
|
{detailRow}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,19 @@ import { User } from "../models/User";
|
|||||||
import { ServerState } from "../state";
|
import { ServerState } from "../state";
|
||||||
import { ApiError } from "./errors";
|
import { ApiError } from "./errors";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace Express {
|
||||||
|
interface Request {
|
||||||
|
token?: TokenClaims;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const JWT_SECRET = process.env.JWT_SECRET!;
|
||||||
|
if (!JWT_SECRET) {
|
||||||
|
throw new Error("Must specify JWT_SECRET environment variable");
|
||||||
|
}
|
||||||
|
|
||||||
const ACCESS_TOKEN_LIFETIME = (30 * 60); // 30 minutes
|
const ACCESS_TOKEN_LIFETIME = (30 * 60); // 30 minutes
|
||||||
const REFRESH_TOKEN_LIFETIME = (24 * 60 * 60); // 24 hours
|
const REFRESH_TOKEN_LIFETIME = (24 * 60 * 60); // 24 hours
|
||||||
|
|
||||||
@ -24,9 +37,9 @@ interface TokenClaims {
|
|||||||
exp: number;
|
exp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function signToken(claims: TokenClaims, secret: string): Promise<string> {
|
function signToken(claims: TokenClaims): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
jwt.sign(claims, secret, (err: Error, encoded: string) => {
|
jwt.sign(claims, JWT_SECRET, (err: Error, encoded: string) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
@ -36,9 +49,9 @@ function signToken(claims: TokenClaims, secret: string): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyToken(token: string, secret: string): Promise<TokenClaims> {
|
function verifyToken(token: string): Promise<TokenClaims> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
jwt.verify(token, secret, (err, decoded) => {
|
jwt.verify(token, JWT_SECRET, (err, decoded) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.name === "TokenExpiredError") {
|
if (err.name === "TokenExpiredError") {
|
||||||
reject(new ApiError(401, "The specified token is expired", err));
|
reject(new ApiError(401, "The specified token is expired", err));
|
||||||
@ -63,7 +76,7 @@ function generateAccessToken(user: User, secret: string): Promise<string> {
|
|||||||
exp: getExpTime(ACCESS_TOKEN_LIFETIME),
|
exp: getExpTime(ACCESS_TOKEN_LIFETIME),
|
||||||
};
|
};
|
||||||
|
|
||||||
return signToken(access_token_claims, secret);
|
return signToken(access_token_claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateRefreshToken(user: User, secret: string): Promise<string> {
|
function generateRefreshToken(user: User, secret: string): Promise<string> {
|
||||||
@ -75,14 +88,10 @@ function generateRefreshToken(user: User, secret: string): Promise<string> {
|
|||||||
exp: getExpTime(REFRESH_TOKEN_LIFETIME),
|
exp: getExpTime(REFRESH_TOKEN_LIFETIME),
|
||||||
};
|
};
|
||||||
|
|
||||||
return signToken(refresh_token_claims, secret);
|
return signToken(refresh_token_claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function authentication(state: ServerState) {
|
export function authentication(state: ServerState) {
|
||||||
const JWT_SECRET = process.env.JWT_SECRET!;
|
|
||||||
if (!JWT_SECRET) {
|
|
||||||
throw new Error("Must specify JWT_SECRET environment variable");
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@ -118,7 +127,7 @@ export function authentication(state: ServerState) {
|
|||||||
if (!body || !refresh_token) {
|
if (!body || !refresh_token) {
|
||||||
throw new ApiError(400, "Must specify a refresh_token");
|
throw new ApiError(400, "Must specify a refresh_token");
|
||||||
}
|
}
|
||||||
const claims = await verifyToken(refresh_token, JWT_SECRET);
|
const claims = await verifyToken(refresh_token);
|
||||||
if (claims.type !== "refresh") {
|
if (claims.type !== "refresh") {
|
||||||
throw new ApiError(400, "Not a refresh token");
|
throw new ApiError(400, "Not a refresh token");
|
||||||
}
|
}
|
||||||
@ -146,25 +155,26 @@ export function authentication(state: ServerState) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/token/verify", async (req, res) => {
|
router.post("/token/verify", authorizeAccess, async (req, res) => {
|
||||||
const bearer = req.headers.authorization;
|
|
||||||
if (!bearer) {
|
|
||||||
throw new ApiError(401, "No bearer token specified");
|
|
||||||
}
|
|
||||||
const matches = /^Bearer (.*)$/.exec(bearer);
|
|
||||||
if (!matches || !matches[1]) {
|
|
||||||
throw new ApiError(400, "Invalid bearer token specified");
|
|
||||||
}
|
|
||||||
const token = matches[1];
|
|
||||||
|
|
||||||
log.info({ token });
|
|
||||||
|
|
||||||
const decoded = await verifyToken(token, JWT_SECRET);
|
|
||||||
res.json({
|
res.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
decoded,
|
token: req.token,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function authorizeAccess(req: Express.Request, res: Express.Response) {
|
||||||
|
const bearer = req.headers.authorization;
|
||||||
|
if (!bearer) {
|
||||||
|
throw new ApiError(401, "No bearer token specified");
|
||||||
|
}
|
||||||
|
const matches = /^Bearer (.*)$/.exec(bearer);
|
||||||
|
if (!matches || !matches[1]) {
|
||||||
|
throw new ApiError(400, "Invalid bearer token specified");
|
||||||
|
}
|
||||||
|
const token = matches[1];
|
||||||
|
|
||||||
|
req.token = await verifyToken(token);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user