Browse Source

cleaned stuffs up

update-deps
Alex Mikhalev 7 years ago
parent
commit
a259f419fe
  1. 52
      app/components/DeviceView.tsx
  2. 33
      app/components/ProgramTable.tsx
  3. 62
      server/express/authentication.ts

52
app/components/DeviceView.tsx

@ -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));

33
app/components/ProgramTable.tsx

@ -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>
);
} }
} }

62
server/express/authentication.ts

@ -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…
Cancel
Save