additions

This commit is contained in:
Evert Prants 2021-10-18 17:47:40 +03:00
parent dbb03e6325
commit 4a1b8348b0
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
3 changed files with 77 additions and 46 deletions

View File

@ -1,5 +1,5 @@
{
"name": "webface",
"name": "webface-server",
"version": "1.0.0",
"description": "",
"main": "index.js",

View File

@ -1,5 +1,5 @@
{
"name": "webface",
"name": "webface-server",
"plugins": [
{
"name": "webface",

View File

@ -45,13 +45,11 @@ class WebSocketServer extends EventEmitter {
constructor(
public port: number,
public host: string,
trustProxy = false,
private authorizedURL: string,
private trustProxy = false,
) {
super();
this.app.disable('x-powered-by');
if (trustProxy) {
this.app.set('trust proxy', 1);
}
this.setupApp();
}
public init(): void {
@ -66,6 +64,21 @@ class WebSocketServer extends EventEmitter {
this.wss.close();
this.server.close();
}
private setupApp(): void {
this.app.disable('x-powered-by');
if (this.trustProxy) {
this.app.set('trust proxy', 1);
}
this.app.use(express.json() as RequestHandler);
this.app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', this.authorizedURL);
res.header('Access-Control-Allow-Methods', 'POST, GET, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
}
}
class WebfaceServer extends WebSocketServer {
@ -74,13 +87,13 @@ class WebfaceServer extends WebSocketServer {
private issuedTokens = new Map<string, string>();
constructor(
public port: number,
public host: string,
public authorizedURL: string,
private users: RegisteredUser[],
port: number,
host: string,
authorizedURL: string,
trustProxy = false,
private users: RegisteredUser[],
) {
super(port, host, trustProxy);
super(port, host, authorizedURL, trustProxy);
this.initializeWebSocket();
this.initializeAPI();
}
@ -196,10 +209,11 @@ class WebfaceServer extends WebSocketServer {
* @param ws WebSocket client
* @param username Client's username
*/
private sendStatus(ws: WebSocket, username: string): void {
private sendStatus(ws: WebSocket, username: string, state?: string): void {
ws.send(JSON.stringify({
status: this.controlPlugin ? 'OK' : 'MISSING_CONTROL',
commands: this.controlPlugin?.listControlCommands() || [],
state,
user: {
username,
}
@ -230,7 +244,7 @@ class WebfaceServer extends WebSocketServer {
status: 'ERROR',
message: 'Unknown or missing command',
command: '',
state: jCmd.state,
state,
}));
return;
}
@ -241,7 +255,7 @@ class WebfaceServer extends WebSocketServer {
}
if (command === 'help' || command === 'status') {
this.sendStatus(ws, user);
this.sendStatus(ws, user, state);
return;
}
@ -312,37 +326,10 @@ class WebfaceServer extends WebSocketServer {
* Set up the HTTP API
*/
private initializeAPI(): void {
this.app.use(express.json() as RequestHandler);
this.app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', this.authorizedURL);
res.header('Access-Control-Allow-Methods', 'POST, GET, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
const router = express.Router();
const authMiddleware = this.tokenOwnerMiddleware();
router.get('/', (req, res) => {
res.json({
status: 'OK',
uptime: process.uptime(),
connections: this.connections.size,
});
});
router.get('/squeebot', authMiddleware, (req, res) => {
res.json({
status: this.controlPlugin ? 'OK' : 'MISSING_CONTROL',
uptime: process.uptime(),
connections: this.connections.size,
user: {
username: res.locals.user,
},
commands: this.controlPlugin?.listControlCommands() || [],
});
});
router.get('/', (req, res) => res.json({ status: 'OK'}));
router.post('/authorize', (req, res) => {
const { body: { username, password } } = req;
@ -372,8 +359,39 @@ class WebfaceServer extends WebSocketServer {
});
});
router.post('/introspect', authMiddleware, (req, res) => {
res.json({ status: 'OK', message: 'Token valid', user: { username: res.locals.user } });
router.get('/squeebot', authMiddleware, (req, res) => {
res.json({
status: this.controlPlugin ? 'OK' : 'MISSING_CONTROL',
uptime: process.uptime(),
connections: this.connections.size,
user: {
username: res.locals.user,
},
commands: this.controlPlugin?.listControlCommands() || [],
});
});
router.post('/verify', authMiddleware,
(req, res) => res.json({
status: 'OK',
message: 'Token valid',
user: {
username: res.locals.user
}
}));
router.post('/password', authMiddleware, (req, res) => {
const { password } = req.body;
if (!password || password.length < 8) {
return res.status(400).json({
error: 'invalid_password',
error_message: 'Password must be at least 8 characters long.',
});
}
this.emit('chpwd', { password, user: res.locals.user });
res.json({
status: 'OK'
});
});
router.delete('/token', authMiddleware, (req, res) => {
@ -521,10 +539,23 @@ class WebfacePlugin extends Plugin {
this.config.get('port') as number,
this.config.get('host'),
this.config.get('trustedRemote', '*') as string,
users,
this.config.get('trustProxy', false),
users,
);
this.srv.on('chpwd', ({ user, password }) => {
const currentUsers = this.config.get('users');
const currentUser = currentUsers.find(({ username }: RegisteredUser) => username === user);
if (currentUsers) {
bcrypt.hash(password, 10).then((hashed) => {
currentUser.password = hashed;
logger.warn('[webface] User %s password changed.', user);
this.config.set('users', currentUsers);
this.config.save().catch((e) => logger.error('[webface] Failed to save users:', e.message));
});
}
});
this.srv.init();
}
}