Compare commits
1 Commits
master
...
update-dep
Author | SHA1 | Date |
---|---|---|
Alex Mikhalev | c12f242cfa | 6 years ago |
54 changed files with 2427 additions and 3588 deletions
@ -0,0 +1,3 @@ |
|||||||
|
cmdline: /usr/lib/wireshark/extcap/sshdump --capture --extcap-interface sshdump --fifo /tmp/wireshark_extcap_sshdump_20180903010220_5gyEKt --remote-host RouterMain --remote-port 22 --remote-username root --sshkey /home/alex/.ssh/id_rsa --remote-interface eth0 --remote-capture-command --remote-sudo false --remote-filter not ((host fe80::9880:27ff:fec4:20a8 or host fe80::42:cff:fecd:a672 or host fe80::42:ff:fecd:47fc or host fe80::42:f7ff:fee1:ae70 or host fe80::ea43:5b74:219d:c5b7 or host 2001:470:b:a14:5751:93a2:2f5f:b9a0 or host fd7d:e461:6dfd:0:d0a6:7939:471:f8ff or host fd7d:e461:6dfd::c22 or host 2001:470:b:a14::c22 or host 172.19.0.1 or host 172.18.0.1 or host 172.17.0.1 or host 192.168.8.10) and port 22) --remote-count 0 --debug false --debug-file |
||||||
|
Remote capture command has disabled other options |
||||||
|
Running: |
@ -1,21 +0,0 @@ |
|||||||
import Command from "@oclif/command"; |
|
||||||
|
|
||||||
import { Database, ServerState } from "."; |
|
||||||
|
|
||||||
export default abstract class ManageCommand extends Command { |
|
||||||
state!: ServerState; |
|
||||||
database!: Database; |
|
||||||
|
|
||||||
async connect() { |
|
||||||
this.state = new ServerState(); |
|
||||||
await this.state.startDatabase(); |
|
||||||
this.database = this.state.database; |
|
||||||
} |
|
||||||
|
|
||||||
async finally(e: Error | undefined) { |
|
||||||
if (this.state) { |
|
||||||
await this.state.stopDatabase(); |
|
||||||
} |
|
||||||
await super.finally(e); |
|
||||||
} |
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
import { QueryFailedError } from "typeorm"; |
|
||||||
|
|
||||||
import ApiError from "@common/ApiError"; |
|
||||||
import { ErrorCode } from "@common/ErrorCode"; |
|
||||||
|
|
||||||
export default class UniqueConstraintError extends ApiError { |
|
||||||
static is(err: any): err is QueryFailedError { |
|
||||||
return err && err.name === "QueryFailedError" && (err as any).code === 23505; // unique constraint error
|
|
||||||
} |
|
||||||
|
|
||||||
constructor(err: QueryFailedError) { |
|
||||||
super(`Unsatisfied unique constraint: ${(err as any).detail}`, ErrorCode.NotUnique, err); |
|
||||||
} |
|
||||||
} |
|
@ -1,161 +0,0 @@ |
|||||||
import { flags } from "@oclif/command"; |
|
||||||
import { ux } from "cli-ux"; |
|
||||||
import { capitalize } from "lodash"; |
|
||||||
import { FindConditions } from "typeorm"; |
|
||||||
|
|
||||||
import ManageCommand from "../ManageCommand"; |
|
||||||
|
|
||||||
import { Input } from "@oclif/parser/lib/flags"; |
|
||||||
import { SprinklersDevice, User } from "@server/entities"; |
|
||||||
|
|
||||||
type DeviceFlags = (typeof DeviceCommand)["flags"] extends Input<infer F> |
|
||||||
? F |
|
||||||
: never; |
|
||||||
|
|
||||||
type Action = "show" | "delete" | "add-user" | "remove-user"; |
|
||||||
|
|
||||||
const VALID_ACTIONS: Action[] = [ "show", "delete", "add-user", "remove-user" ]; |
|
||||||
|
|
||||||
// tslint:disable:no-shadowed-variable
|
|
||||||
|
|
||||||
export default class DeviceCommand extends ManageCommand { |
|
||||||
static description = "Manage devices"; |
|
||||||
|
|
||||||
static flags = { |
|
||||||
show: flags.boolean({ |
|
||||||
char: "s", |
|
||||||
exclusive: ["add-user", "delete"], |
|
||||||
description: "Show devices(s)", |
|
||||||
}), |
|
||||||
"add-user": flags.boolean({ |
|
||||||
char: "a", |
|
||||||
exclusive: ["show", "delete"], |
|
||||||
description: "Add a user as owning this device (specify --username)" |
|
||||||
}), |
|
||||||
"remove-user": flags.boolean({ |
|
||||||
char: "r", |
|
||||||
exclusive: ["add-user", "show", "delete"], |
|
||||||
description: "Remove a user as owning this device (specify --username)" |
|
||||||
}), |
|
||||||
delete: flags.boolean({ |
|
||||||
char: "d", |
|
||||||
exclusive: ["show", "add-user"], |
|
||||||
description: "Delete a user (by --id or --username)" |
|
||||||
}), |
|
||||||
id: flags.integer({ |
|
||||||
description: "The id of the device to update or delete", |
|
||||||
}), |
|
||||||
name: flags.string({ |
|
||||||
description: "The name of the device, when creating or updating" |
|
||||||
}), |
|
||||||
deviceId: flags.string({ |
|
||||||
description: "The deviceId of the device, when creating or updating" |
|
||||||
}), |
|
||||||
username: flags.string({ |
|
||||||
description: "Specify a username for --show or --add-user" |
|
||||||
}), |
|
||||||
}; |
|
||||||
|
|
||||||
getAction(flags: DeviceFlags): Action { |
|
||||||
for (const action of VALID_ACTIONS) { |
|
||||||
if (flags[action]) { |
|
||||||
return action; |
|
||||||
} |
|
||||||
} |
|
||||||
const actionFlags = VALID_ACTIONS.map(action => `--${action}`); |
|
||||||
this.error(`Must specify an action (${actionFlags.join(', ')})`, { |
|
||||||
exit: false, |
|
||||||
}); |
|
||||||
return this._help(); |
|
||||||
} |
|
||||||
|
|
||||||
getFindConditions(flags: DeviceFlags, action: Action): FindConditions<SprinklersDevice> { |
|
||||||
const whereClause: FindConditions<SprinklersDevice> = {}; |
|
||||||
if (flags.id) { |
|
||||||
whereClause.id = flags.id; |
|
||||||
} |
|
||||||
if (flags.name) { |
|
||||||
whereClause.name = flags.name; |
|
||||||
} |
|
||||||
if (flags.deviceId) { |
|
||||||
whereClause.deviceId = flags.deviceId; |
|
||||||
} |
|
||||||
if (false) { |
|
||||||
this.error(`Must specify --id to ${action}`, { |
|
||||||
exit: false |
|
||||||
}); |
|
||||||
return this._help(); |
|
||||||
} |
|
||||||
return whereClause; |
|
||||||
} |
|
||||||
|
|
||||||
async getOrDeleteDevice(flags: DeviceFlags, action: Action): Promise<SprinklersDevice | never> { |
|
||||||
const findConditions = this.getFindConditions(flags, action); |
|
||||||
if (action === "delete") { |
|
||||||
const result = await this.database.sprinklersDevices.delete(findConditions); |
|
||||||
if (result.raw[1] > 0) { |
|
||||||
this.log(`Deleted device`); |
|
||||||
} else { |
|
||||||
this.error("Did not find device to delete"); |
|
||||||
} |
|
||||||
return this.exit(); |
|
||||||
} else { |
|
||||||
const device = await this.database.sprinklersDevices.findOne(findConditions); |
|
||||||
if (!device) { |
|
||||||
return this.error(`The specified device does not exist`); |
|
||||||
} |
|
||||||
return device; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
async run() { |
|
||||||
const parseResult = this.parse(DeviceCommand); |
|
||||||
|
|
||||||
const flags = parseResult.flags; |
|
||||||
const action = this.getAction(flags); |
|
||||||
|
|
||||||
await this.connect(); |
|
||||||
|
|
||||||
if (flags.show) { |
|
||||||
const findConditions = this.getFindConditions(flags, action); |
|
||||||
let query = this.database.sprinklersDevices.createQueryBuilder("device") |
|
||||||
.leftJoinAndSelect("device.users", "user") |
|
||||||
.where(findConditions); |
|
||||||
if (flags.username) { |
|
||||||
query = query.where("user.username = :username", { username: flags.username }); |
|
||||||
} |
|
||||||
const devices = await query.getMany(); |
|
||||||
if (devices.length === 0) { |
|
||||||
this.log("No sprinklers devices found"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
this.log("Devices: ") |
|
||||||
for (const device of devices) { |
|
||||||
this.log(JSON.stringify(device, null, " ")); |
|
||||||
} |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
const device = await this.getOrDeleteDevice(flags, action); |
|
||||||
|
|
||||||
if (flags["add-user"] || flags["remove-user"]) { |
|
||||||
if (!flags.username) { |
|
||||||
return this.error("Must specify --username for --add-user") |
|
||||||
} |
|
||||||
const user = await this.database.users.findByUsername(flags.username); |
|
||||||
if (!user) { |
|
||||||
return this.error(`Could not find user with username '${flags.username}'`); |
|
||||||
} |
|
||||||
const query = this.database.sprinklersDevices.createQueryBuilder() |
|
||||||
.relation("users") |
|
||||||
.of(device); |
|
||||||
if (flags["add-user"]) { |
|
||||||
await query.add(user); |
|
||||||
this.log(`Added user '${user.username}' to device '${device.name}`); |
|
||||||
} else { |
|
||||||
await query.remove(user); |
|
||||||
this.log(`Removed user '${user.username}' from device '${device.name}`); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,11 @@ |
|||||||
|
import Command from "@oclif/command"; |
||||||
|
|
||||||
|
import { createApp, ServerState, WebSocketApi } from "../"; |
||||||
|
|
||||||
|
import log from "@common/logger"; |
||||||
|
|
||||||
|
export default class ManageCommand extends Command { |
||||||
|
run(): Promise<any> { |
||||||
|
throw new Error("Method not implemented."); |
||||||
|
} |
||||||
|
} |
@ -1,32 +0,0 @@ |
|||||||
import { flags } from "@oclif/command"; |
|
||||||
import * as auth from "@server/authentication" |
|
||||||
|
|
||||||
import ManageCommand from "@server/ManageCommand"; |
|
||||||
|
|
||||||
// tslint:disable:no-shadowed-variable
|
|
||||||
|
|
||||||
export default class TokenCommand extends ManageCommand { |
|
||||||
static description = "Manage tokens"; |
|
||||||
|
|
||||||
static flags = { |
|
||||||
"gen-device-reg": flags.boolean({ |
|
||||||
char: "d", |
|
||||||
description: "Generate a device registration token", |
|
||||||
}), |
|
||||||
}; |
|
||||||
|
|
||||||
async run() { |
|
||||||
const parseResult = this.parse(TokenCommand); |
|
||||||
|
|
||||||
const flags = parseResult.flags; |
|
||||||
|
|
||||||
if (flags["gen-device-reg"]) { |
|
||||||
const token = await auth.generateDeviceRegistrationToken(); |
|
||||||
this.log(`Device registration token: "${token}"`) |
|
||||||
} else { |
|
||||||
this.error("Must specify a command to run"); |
|
||||||
this._help(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
@ -1,154 +0,0 @@ |
|||||||
import { flags } from "@oclif/command"; |
|
||||||
import { ux } from "cli-ux"; |
|
||||||
import { capitalize } from "lodash"; |
|
||||||
import { FindConditions } from "typeorm"; |
|
||||||
|
|
||||||
import ManageCommand from "../ManageCommand"; |
|
||||||
|
|
||||||
import { Input } from "@oclif/parser/lib/flags"; |
|
||||||
import { User } from "@server/entities"; |
|
||||||
|
|
||||||
type UserFlags = (typeof UserCommand)["flags"] extends Input<infer F> |
|
||||||
? F |
|
||||||
: never; |
|
||||||
|
|
||||||
type Action = "show" | "create" | "update" | "delete"; |
|
||||||
|
|
||||||
// tslint:disable:no-shadowed-variable
|
|
||||||
|
|
||||||
export default class UserCommand extends ManageCommand { |
|
||||||
static description = "Manage users"; |
|
||||||
|
|
||||||
static flags = { |
|
||||||
show: flags.boolean({ |
|
||||||
char: "s", |
|
||||||
exclusive: ["create", "update", "delete"], |
|
||||||
description: "Show user(s)", |
|
||||||
}), |
|
||||||
create: flags.boolean({ |
|
||||||
char: "c", |
|
||||||
exclusive: ["update", "delete", "id"], |
|
||||||
dependsOn: ["username"], |
|
||||||
description: "Create a new user" |
|
||||||
}), |
|
||||||
update: flags.boolean({ |
|
||||||
char: "u", |
|
||||||
exclusive: ["create", "delete"], |
|
||||||
description: "Update an existing user (by --id or --username)" |
|
||||||
}), |
|
||||||
delete: flags.boolean({ |
|
||||||
char: "d", |
|
||||||
exclusive: ["create", "update"], |
|
||||||
description: "Delete a user (by --id or --username)" |
|
||||||
}), |
|
||||||
id: flags.integer({ |
|
||||||
description: "The id of the user to update or delete", |
|
||||||
}), |
|
||||||
username: flags.string({ |
|
||||||
description: "The username of the user to create or update" |
|
||||||
}), |
|
||||||
name: flags.string({ |
|
||||||
description: "The name of the user, when creating or updating" |
|
||||||
}), |
|
||||||
passwordPrompt: flags.boolean({ |
|
||||||
char: "p", |
|
||||||
description: |
|
||||||
"Prompts for the password of the user when creating or updating" |
|
||||||
}) |
|
||||||
}; |
|
||||||
|
|
||||||
getAction(flags: UserFlags): Action { |
|
||||||
if (flags.show) return "show"; |
|
||||||
else if (flags.create) return "create"; |
|
||||||
else if (flags.update) return "update"; |
|
||||||
else if (flags.delete) return "delete"; |
|
||||||
else { |
|
||||||
this.error("Must specify an action (--show, --create, --update, --delete)", { |
|
||||||
exit: false |
|
||||||
}); |
|
||||||
return this._help(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
getFindConditions(flags: UserFlags, action: Action): FindConditions<User> { |
|
||||||
if (flags.id != null) { |
|
||||||
return { id: flags.id }; |
|
||||||
} else if (flags.username) { |
|
||||||
return { username: flags.username }; |
|
||||||
} else { |
|
||||||
this.error(`Must specify either --id or --username to ${action}`, { |
|
||||||
exit: false |
|
||||||
}); |
|
||||||
return this._help(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
async getOrDeleteUser(flags: UserFlags, action: Action): Promise<User | never> { |
|
||||||
if (action === "create") { |
|
||||||
return this.database.users.create(); |
|
||||||
} else { |
|
||||||
const findConditions = this.getFindConditions(flags, action); |
|
||||||
if (action === "delete") { |
|
||||||
const result = await this.database.users.delete(findConditions); |
|
||||||
this.log(`Deleted user: `, result); |
|
||||||
return this.exit(); |
|
||||||
} else { |
|
||||||
const user = await this.database.users.findOneUser(findConditions); |
|
||||||
if (!user) { |
|
||||||
return this.error(`The specified user does not exist`); |
|
||||||
} |
|
||||||
return user; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
async run() { |
|
||||||
const parseResult = this.parse(UserCommand); |
|
||||||
|
|
||||||
const flags = parseResult.flags; |
|
||||||
const action = this.getAction(flags); |
|
||||||
|
|
||||||
await this.connect(); |
|
||||||
|
|
||||||
if (flags.show) { |
|
||||||
let whereClause: FindConditions<User> = {}; |
|
||||||
if (flags.id) { |
|
||||||
whereClause.id = flags.id; |
|
||||||
} |
|
||||||
if (flags.username) { |
|
||||||
whereClause.username = flags.username; |
|
||||||
} |
|
||||||
const users = await this.database.users.find({ where: whereClause }); |
|
||||||
if (users.length == 0) { |
|
||||||
this.error("No users found"); |
|
||||||
} |
|
||||||
this.log("Users: ") |
|
||||||
for (const user of users) { |
|
||||||
this.log(JSON.stringify(user.toJSON())); |
|
||||||
} |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
const user = await this.getOrDeleteUser(flags, action); |
|
||||||
|
|
||||||
if (flags.username && (flags.create || flags.id)) { |
|
||||||
user.username = flags.username; |
|
||||||
} |
|
||||||
if (flags.name) { |
|
||||||
user.name = flags.name; |
|
||||||
} |
|
||||||
if (flags.passwordPrompt || flags.create) { |
|
||||||
const password = await ux.prompt("Enter a password to assign the user", { |
|
||||||
type: "hide" |
|
||||||
}); |
|
||||||
await user.setPassword(password); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
await this.database.users.save(user); |
|
||||||
this.log(`${capitalize(action)}d user id ${user.id} (${user.username})`); |
|
||||||
} catch (e) { |
|
||||||
throw e; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,7 +1,8 @@ |
|||||||
import log from "@common/logger"; |
import log from "@common/logger"; |
||||||
import pinoHttp = require("pino-http"); |
import expressPinoLogger = require("express-pino-logger"); |
||||||
|
import * as pino from "pino"; |
||||||
|
|
||||||
export default pinoHttp({ |
const l = pino(); |
||||||
logger: log, |
pino(l); |
||||||
useLevel: "debug", |
|
||||||
} as pinoHttp.Options); |
export default expressPinoLogger(log); |
||||||
|
@ -1,49 +1,33 @@ |
|||||||
import { EntityRepository, FindConditions, FindOneOptions, Repository } from "typeorm"; |
import { EntityRepository, FindOneOptions, Repository } from "typeorm"; |
||||||
|
|
||||||
import { User } from "@server/entities"; |
import { User } from "@server/entities"; |
||||||
|
|
||||||
export interface FindUserOptions extends FindOneOptions<User> { |
export interface FindUserOptions { |
||||||
devices: boolean; |
devices: boolean; |
||||||
} |
} |
||||||
|
|
||||||
function computeOptions( |
function applyDefaultOptions( |
||||||
options?: Partial<FindUserOptions> |
options?: Partial<FindUserOptions> |
||||||
): FindOneOptions<User> { |
): FindOneOptions<User> { |
||||||
const opts: FindUserOptions = { devices: false, ...options }; |
const opts: FindUserOptions = { devices: false, ...options }; |
||||||
const { devices, ...rest } = opts; |
const relations = [opts.devices && "devices"].filter(Boolean) as string[]; |
||||||
const relations = [devices && "devices"].filter(Boolean) as string[]; |
return { relations }; |
||||||
return { relations, ...rest }; |
|
||||||
} |
} |
||||||
|
|
||||||
@EntityRepository(User) |
@EntityRepository(User) |
||||||
export class UserRepository extends Repository<User> { |
export class UserRepository extends Repository<User> { |
||||||
findAll(options?: Partial<FindUserOptions>) { |
findAll(options?: Partial<FindUserOptions>) { |
||||||
const opts = computeOptions(options); |
const opts = applyDefaultOptions(options); |
||||||
return super.find(opts); |
return super.find(opts); |
||||||
} |
} |
||||||
|
|
||||||
findOneUser(conditions: FindConditions<User>, options?: Partial<FindUserOptions>) { |
|
||||||
const opts = computeOptions(options); |
|
||||||
return super.findOne(conditions, opts); |
|
||||||
} |
|
||||||
|
|
||||||
findById(id: number, options?: Partial<FindUserOptions>) { |
findById(id: number, options?: Partial<FindUserOptions>) { |
||||||
return this.findOneUser({ id }, options); |
const opts = applyDefaultOptions(options); |
||||||
|
return super.findOne(id, opts); |
||||||
} |
} |
||||||
|
|
||||||
findByUsername(username: string, options?: Partial<FindUserOptions>) { |
findByUsername(username: string, options?: Partial<FindUserOptions>) { |
||||||
return this.findOneUser({ username }, options); |
const opts = applyDefaultOptions(options); |
||||||
|
return this.findOne({ username }, opts); |
||||||
} |
} |
||||||
|
|
||||||
// async checkAndSave(entity: User): Promise<User> {
|
|
||||||
// return this.manager.transaction(manager => {
|
|
||||||
// let query = manager.createQueryBuilder<User>(User, "user", manager.queryRunner!);
|
|
||||||
// if (entity.id != null) {
|
|
||||||
// query = query.where("user.id <> :id", { id: entity.id })
|
|
||||||
// }
|
|
||||||
// query
|
|
||||||
|
|
||||||
// return manager.save(entity);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
} |
} |
||||||
|
@ -0,0 +1,7 @@ |
|||||||
|
declare module "express-pino-logger" { |
||||||
|
import { Logger } from "pino"; |
||||||
|
import { ErrorRequestHandler } from "express"; |
||||||
|
|
||||||
|
function makeLogger(logger: Logger): ErrorRequestHandler; |
||||||
|
export = makeLogger; |
||||||
|
} |
Loading…
Reference in new issue