|
|
@ -48,31 +48,33 @@ export class WebSocketClient { |
|
|
|
this.api.removeClient(this); |
|
|
|
this.api.removeClient(this); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private checkAuthorization() { |
|
|
|
|
|
|
|
if (!this.userId) { |
|
|
|
|
|
|
|
throw new ws.RpcError("this WebSocket session has not been authenticated", |
|
|
|
|
|
|
|
ErrorCode.Unauthorized); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private requestHandlers: ws.ClientRequestHandlers = { |
|
|
|
private requestHandlers: ws.ClientRequestHandlers = { |
|
|
|
authenticate: async (data: ws.IAuthenticateRequest) => { |
|
|
|
authenticate: async (data: ws.IAuthenticateRequest) => { |
|
|
|
if (!data.accessToken) { |
|
|
|
if (!data.accessToken) { |
|
|
|
return { |
|
|
|
throw new ws.RpcError("no token specified", ErrorCode.BadRequest); |
|
|
|
result: "error", error: { |
|
|
|
|
|
|
|
code: ErrorCode.BadRequest, message: "no token specified", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
let decoded: TokenClaims; |
|
|
|
let decoded: TokenClaims; |
|
|
|
try { |
|
|
|
try { |
|
|
|
decoded = await verifyToken(data.accessToken); |
|
|
|
decoded = await verifyToken(data.accessToken); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
return { |
|
|
|
throw new ws.RpcError("invalid token", ErrorCode.BadToken, e); |
|
|
|
result: "error", |
|
|
|
|
|
|
|
error: { code: ErrorCode.BadToken, message: "invalid token", data: e }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
this.userId = decoded.aud; |
|
|
|
this.userId = decoded.aud; |
|
|
|
|
|
|
|
log.info({ userId: decoded.aud, name: decoded.name }, "authenticated websocket client"); |
|
|
|
return { |
|
|
|
return { |
|
|
|
result: "success", |
|
|
|
result: "success", |
|
|
|
data: { authenticated: true, message: "authenticated" }, |
|
|
|
data: { authenticated: true, message: "authenticated" }, |
|
|
|
}; |
|
|
|
}; |
|
|
|
}, |
|
|
|
}, |
|
|
|
deviceSubscribe: async (data: ws.IDeviceSubscribeRequest) => { |
|
|
|
deviceSubscribe: async (data: ws.IDeviceSubscribeRequest) => { |
|
|
|
|
|
|
|
this.checkAuthorization(); |
|
|
|
const deviceId = data.deviceId; |
|
|
|
const deviceId = data.deviceId; |
|
|
|
if (deviceId !== "grinklers") { // TODO: somehow validate this device id?
|
|
|
|
if (deviceId !== "grinklers") { // TODO: somehow validate this device id?
|
|
|
|
return { |
|
|
|
return { |
|
|
@ -100,6 +102,7 @@ export class WebSocketClient { |
|
|
|
return { result: "success", data: response }; |
|
|
|
return { result: "success", data: response }; |
|
|
|
}, |
|
|
|
}, |
|
|
|
deviceCall: async (data: ws.IDeviceCallRequest) => { |
|
|
|
deviceCall: async (data: ws.IDeviceCallRequest) => { |
|
|
|
|
|
|
|
this.checkAuthorization(); |
|
|
|
try { |
|
|
|
try { |
|
|
|
const response = await this.doDeviceCallRequest(data); |
|
|
|
const response = await this.doDeviceCallRequest(data); |
|
|
|
const resData: ws.IDeviceCallResponse = { |
|
|
|
const resData: ws.IDeviceCallResponse = { |
|
|
@ -108,13 +111,7 @@ export class WebSocketClient { |
|
|
|
return { result: "success", data: resData }; |
|
|
|
return { result: "success", data: resData }; |
|
|
|
} catch (err) { |
|
|
|
} catch (err) { |
|
|
|
const e: deviceRequests.ErrorResponseData = err; |
|
|
|
const e: deviceRequests.ErrorResponseData = err; |
|
|
|
return { |
|
|
|
throw new ws.RpcError(e.message, e.code, e); |
|
|
|
result: "error", error: { |
|
|
|
|
|
|
|
code: e.code, |
|
|
|
|
|
|
|
message: e.message, |
|
|
|
|
|
|
|
data: e, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |
|
|
@ -155,7 +152,6 @@ export class WebSocketClient { |
|
|
|
return this.onError({ socketData, err }, "received invalid websocket message from client", |
|
|
|
return this.onError({ socketData, err }, "received invalid websocket message from client", |
|
|
|
ErrorCode.Parse); |
|
|
|
ErrorCode.Parse); |
|
|
|
} |
|
|
|
} |
|
|
|
log.debug({ data }, "client message"); |
|
|
|
|
|
|
|
switch (data.type) { |
|
|
|
switch (data.type) { |
|
|
|
case "request": |
|
|
|
case "request": |
|
|
|
await this.handleRequest(data); |
|
|
|
await this.handleRequest(data); |
|
|
@ -168,21 +164,21 @@ export class WebSocketClient { |
|
|
|
|
|
|
|
|
|
|
|
private async handleRequest(request: ws.ClientRequest) { |
|
|
|
private async handleRequest(request: ws.ClientRequest) { |
|
|
|
let response: ws.ServerResponseData; |
|
|
|
let response: ws.ServerResponseData; |
|
|
|
if (!this.requestHandlers[request.method]) { |
|
|
|
try { |
|
|
|
log.warn({ method: request.method }, "received invalid client request method"); |
|
|
|
if (!this.requestHandlers[request.method]) { |
|
|
|
response = { |
|
|
|
// noinspection ExceptionCaughtLocallyJS
|
|
|
|
result: "error", error: { |
|
|
|
throw new ws.RpcError("received invalid client request method"); |
|
|
|
code: ErrorCode.BadRequest, message: "received invalid client request method", |
|
|
|
} |
|
|
|
}, |
|
|
|
response = await rpc.handleRequest(this.requestHandlers, request); |
|
|
|
}; |
|
|
|
} catch (err) { |
|
|
|
} else { |
|
|
|
if (err instanceof ws.RpcError) { |
|
|
|
try { |
|
|
|
log.debug({ err }, "rpc error"); |
|
|
|
response = await rpc.handleRequest(this.requestHandlers, request); |
|
|
|
response = { result: "error", error: err.toJSON() }; |
|
|
|
} catch (err) { |
|
|
|
} else { |
|
|
|
log.error({ method: request.method, err }, "error during processing of client request"); |
|
|
|
log.error({ method: request.method, err }, "unhandled error during processing of client request"); |
|
|
|
response = { |
|
|
|
response = { |
|
|
|
result: "error", error: { |
|
|
|
result: "error", error: { |
|
|
|
code: ErrorCode.Internal, message: "error during processing of client request", |
|
|
|
code: ErrorCode.Internal, message: "unhandled error during processing of client request", |
|
|
|
data: err.toString(), |
|
|
|
data: err.toString(), |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |
|
|
@ -193,7 +189,7 @@ export class WebSocketClient { |
|
|
|
|
|
|
|
|
|
|
|
private onError(data: any, message: string, code: number = ErrorCode.Internal) { |
|
|
|
private onError(data: any, message: string, code: number = ErrorCode.Internal) { |
|
|
|
log.error(data, message); |
|
|
|
log.error(data, message); |
|
|
|
const errorData: ws.Error = { code, message, data }; |
|
|
|
const errorData: ws.IError = { code, message, data }; |
|
|
|
this.sendNotification("error", errorData); |
|
|
|
this.sendNotification("error", errorData); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|