mirror of
https://github.com/koush/scrypted.git
synced 2026-02-03 14:13:28 +00:00
webhook: prevent enable on internal types, fixup code to not require mixin existence
This commit is contained in:
2
plugins/webhook/.vscode/settings.json
vendored
2
plugins/webhook/.vscode/settings.json
vendored
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"scrypted.debugHost": "127.0.0.1",
|
"scrypted.debugHost": "scrypted-nvr",
|
||||||
}
|
}
|
||||||
4
plugins/webhook/package-lock.json
generated
4
plugins/webhook/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@scrypted/webhook",
|
"name": "@scrypted/webhook",
|
||||||
"version": "0.0.26",
|
"version": "0.0.27",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@scrypted/webhook",
|
"name": "@scrypted/webhook",
|
||||||
"version": "0.0.26",
|
"version": "0.0.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^16.6.1"
|
"@types/node": "^16.6.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,5 +35,5 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scrypted/sdk": "file:../../sdk"
|
"@scrypted/sdk": "file:../../sdk"
|
||||||
},
|
},
|
||||||
"version": "0.0.26"
|
"version": "0.0.27"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { HttpRequest, HttpRequestHandler, HttpResponse, MixinProvider, PushHandler, ScryptedDevice, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedInterfaceDescriptors, Setting, Settings, SettingValue, WritableDeviceState } from '@scrypted/sdk';
|
import sdk, { HttpRequest, HttpRequestHandler, HttpResponse, MixinProvider, PushHandler, ScryptedDevice, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedInterfaceDescriptors, Setting, Settings, SettingValue, WritableDeviceState } from '@scrypted/sdk';
|
||||||
import sdk from '@scrypted/sdk';
|
import { StorageSettings, StorageSettingsDevice } from '@scrypted/sdk/storage-settings';
|
||||||
import { SettingsMixinDeviceBase } from "../../../common/src/settings-mixin";
|
|
||||||
import { randomBytes } from 'crypto';
|
import { randomBytes } from 'crypto';
|
||||||
|
import { SettingsMixinDeviceBase } from "../../../common/src/settings-mixin";
|
||||||
|
|
||||||
const allInterfaceMethods: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.methods));
|
const allInterfaceMethods: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.methods));
|
||||||
const allInterfaceProperties: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.properties));
|
const allInterfaceProperties: string[] = [].concat(...Object.values(ScryptedInterfaceDescriptors).map((type: any) => type.properties));
|
||||||
|
|
||||||
import { isPublishable} from '../../mqtt/src/publishable-types';
|
import { isPublishable } from '../../mqtt/src/publishable-types';
|
||||||
|
|
||||||
const { systemManager, endpointManager, mediaManager } = sdk;
|
const { systemManager, endpointManager, mediaManager } = sdk;
|
||||||
|
|
||||||
@@ -15,7 +15,19 @@ const mediaObjectMethods = [
|
|||||||
'getVideoStream',
|
'getVideoStream',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function getMixinStorageSettings(device: StorageSettingsDevice) {
|
||||||
|
return new StorageSettings(device, {
|
||||||
|
token: {
|
||||||
|
hide: true,
|
||||||
|
persistedDefaultValue: randomBytes(8).toString('hex'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
||||||
|
storageSettings = getMixinStorageSettings(this);
|
||||||
|
|
||||||
async getMixinSettings(): Promise<Setting[]> {
|
async getMixinSettings(): Promise<Setting[]> {
|
||||||
const realDevice = systemManager.getDeviceById(this.id);
|
const realDevice = systemManager.getDeviceById(this.id);
|
||||||
return [
|
return [
|
||||||
@@ -24,6 +36,8 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
key: 'create',
|
key: 'create',
|
||||||
description: 'Create a Webhook for a device interface. E.g., OnOff to turn a light on or off, or Camera to retrieve an image. The created webhook will be viewable in the Console.',
|
description: 'Create a Webhook for a device interface. E.g., OnOff to turn a light on or off, or Camera to retrieve an image. The created webhook will be viewable in the Console.',
|
||||||
choices: realDevice.interfaces,
|
choices: realDevice.interfaces,
|
||||||
|
immediate: true,
|
||||||
|
console: true,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -31,11 +45,7 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
async putMixinSetting(key: string, value: string | number | boolean): Promise<void> {
|
async putMixinSetting(key: string, value: string | number | boolean): Promise<void> {
|
||||||
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
|
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
|
||||||
|
|
||||||
let token = this.storage.getItem('token');
|
const { token } = this.storageSettings.values;
|
||||||
if (!token) {
|
|
||||||
token = randomBytes(8).toString('hex');
|
|
||||||
this.storage.setItem('token', token);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.console.log();
|
this.console.log();
|
||||||
this.console.log();
|
this.console.log();
|
||||||
@@ -79,7 +89,11 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
this.console.log("##################################################")
|
this.console.log("##################################################")
|
||||||
}
|
}
|
||||||
|
|
||||||
async maybeSendMediaObject(response: HttpResponse, value: any, method: string) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebhookPlugin extends ScryptedDeviceBase implements Settings, MixinProvider, HttpRequestHandler, PushHandler {
|
||||||
|
static async maybeSendMediaObject(response: HttpResponse, value: any, method: string) {
|
||||||
if (!mediaObjectMethods.includes(method)) {
|
if (!mediaObjectMethods.includes(method)) {
|
||||||
response?.send(value?.toString());
|
response?.send(value?.toString());
|
||||||
return;
|
return;
|
||||||
@@ -93,9 +107,16 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async handle(request: HttpRequest, response: HttpResponse, device: ScryptedDevice, pathSegments: string[]) {
|
static async handleMixin(request: HttpRequest, response: HttpResponse, device: ScryptedDevice, pathSegments: string[]) {
|
||||||
const token = pathSegments[2];
|
const token = pathSegments[2];
|
||||||
if (token !== this.storage.getItem('token')) {
|
const mixinStorage = sdk.deviceManager.getMixinStorage(device.id);
|
||||||
|
const console = sdk.deviceManager.getMixinConsole(device.id);
|
||||||
|
const storageSettings = getMixinStorageSettings({
|
||||||
|
async onDeviceEvent() { },
|
||||||
|
storage: mixinStorage,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (token !== storageSettings.values.token) {
|
||||||
response?.send('Invalid Token', {
|
response?.send('Invalid Token', {
|
||||||
code: 401,
|
code: 401,
|
||||||
});
|
});
|
||||||
@@ -124,7 +145,7 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.console.error('webhook action error', e);
|
console.error('webhook action error', e);
|
||||||
response.send('Internal Error', {
|
response.send('Internal Error', {
|
||||||
code: 500,
|
code: 500,
|
||||||
});
|
});
|
||||||
@@ -144,16 +165,12 @@ class WebhookMixin extends SettingsMixinDeviceBase<Settings> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.console.error('Unknown method or property', methodOrProperty);
|
console.error('Unknown method or property', methodOrProperty);
|
||||||
response.send('Not Found', {
|
response.send('Not Found', {
|
||||||
code: 404,
|
code: 404,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class WebhookPlugin extends ScryptedDeviceBase implements Settings, MixinProvider, HttpRequestHandler, PushHandler {
|
|
||||||
createdMixins = new Map<string, WebhookMixin>();
|
|
||||||
|
|
||||||
async handle(request: HttpRequest, response?: HttpResponse) {
|
async handle(request: HttpRequest, response?: HttpResponse) {
|
||||||
this.console.log('received webhook', request);
|
this.console.log('received webhook', request);
|
||||||
@@ -180,17 +197,14 @@ class WebhookPlugin extends ScryptedDeviceBase implements Settings, MixinProvide
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.createdMixins.has(id)) {
|
if (!device.mixins?.includes(this.id)) {
|
||||||
await device.getSettings();
|
|
||||||
}
|
|
||||||
const mixin = this.createdMixins.get(id);
|
|
||||||
if (!mixin) {
|
|
||||||
response.send('Not Found', {
|
response.send('Not Found', {
|
||||||
code: 404,
|
code: 404,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await mixin.handle(request, response, device, pathSegments);
|
|
||||||
|
await WebhookPlugin.handleMixin(request, response, device, pathSegments);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
|
onRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
|
||||||
@@ -228,15 +242,11 @@ class WebhookPlugin extends ScryptedDeviceBase implements Settings, MixinProvide
|
|||||||
groupKey: "webhook",
|
groupKey: "webhook",
|
||||||
});
|
});
|
||||||
|
|
||||||
this.createdMixins.set(ret.id, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async releaseMixin(id: string, mixinDevice: any): Promise<void> {
|
async releaseMixin(id: string, mixinDevice: any): Promise<void> {
|
||||||
if (this.createdMixins.get(id) === mixinDevice) {
|
|
||||||
this.createdMixins.delete(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new WebhookPlugin();
|
export default WebhookPlugin;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "Node16",
|
||||||
"target": "ES2021",
|
"target": "ES2021",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"moduleResolution": "Node16",
|
"moduleResolution": "Node16",
|
||||||
|
|||||||
Reference in New Issue
Block a user