@scrypted/amcrest
Advanced tools
Comparing version 0.0.26 to 0.0.27
{ | ||
"name": "@scrypted/amcrest", | ||
"version": "0.0.26", | ||
"version": "0.0.27", | ||
"description": "Amcrest Plugin for Scrypted", | ||
@@ -5,0 +5,0 @@ "author": "Scrypted", |
@@ -13,18 +13,2 @@ import AxiosDigestAuth from '@mhoc/axios-digest-auth'; | ||
async function readEvent(readable: Readable): Promise<AmcrestEvent | void> { | ||
const pt = new PassThrough(); | ||
readable.pipe(pt); | ||
const buffers: Buffer[] = []; | ||
for await (const buffer of pt) { | ||
buffers.push(buffer); | ||
const data = Buffer.concat(buffers).toString(); | ||
for (const event of Object.values(AmcrestEvent)) { | ||
if (data.indexOf(event) !== -1) { | ||
return event; | ||
} | ||
} | ||
} | ||
console.log('unhandled', Buffer.concat(buffers).toString()); | ||
} | ||
export class AmcrestCameraClient { | ||
@@ -51,3 +35,3 @@ digestAuth: AxiosDigestAuth; | ||
async* listenEvents(): AsyncGenerator<AmcrestEvent> { | ||
async listenEvents() { | ||
const response = await this.digestAuth.request({ | ||
@@ -58,22 +42,15 @@ method: "GET", | ||
}); | ||
const stream = response.data as Readable; | ||
const stream = response.data; | ||
stream.on('data', (buffer: Buffer) => { | ||
const data = buffer.toString(); | ||
for (const event of Object.values(AmcrestEvent)) { | ||
if (data.indexOf(event) !== -1) { | ||
stream.emit('event', event); | ||
} | ||
} | ||
}); | ||
const form = new Form(); | ||
try { | ||
// massage this so the parser doesn't fail on a bad content type | ||
stream.headers['content-type'] = stream.headers['content-type'].replace('multipart/x-mixed-replace', 'multipart/form-data'); | ||
form.parse(stream); | ||
while (true) { | ||
const [part] = await once(form, 'part'); | ||
const event = await readEvent(part); | ||
if (event) | ||
yield event; | ||
} | ||
} | ||
finally { | ||
stream.destroy(); | ||
} | ||
return stream; | ||
} | ||
} |
import sdk, { MediaObject, Camera, ScryptedInterface } from "@scrypted/sdk"; | ||
import { Stream } from "stream"; | ||
import { AmcrestCameraClient, AmcrestEvent } from "./amcrest-api"; | ||
import { RtspSmartCamera, RtspProvider } from "../../rtsp/src/rtsp"; | ||
import { RtspSmartCamera, RtspProvider, Destroyable } from "../../rtsp/src/rtsp"; | ||
import { EventEmitter } from "stream"; | ||
const { mediaManager } = sdk; | ||
class AmcrestCamera extends RtspSmartCamera implements Camera { | ||
eventStream: Stream; | ||
constructor(nativeId: string) { | ||
super(nativeId); | ||
this.createMotionStream(); | ||
} | ||
async createMotionStream() { | ||
while (true) { | ||
listenEvents() { | ||
const ret = new EventEmitter() as (EventEmitter & Destroyable); | ||
ret.destroy = () => { | ||
}; | ||
(async () => { | ||
const api = this.createClient(); | ||
try { | ||
this.motionDetected = false; | ||
this.audioDetected = false; | ||
const events = await api.listenEvents(); | ||
ret.destroy = () => { | ||
events.removeAllListeners(); | ||
events.destroy(); | ||
}; | ||
const api = this.createClient(); | ||
for await (const event of api.listenEvents()) { | ||
if (event === AmcrestEvent.MotionStart) | ||
events.on('close', () => ret.emit('error', new Error('close'))); | ||
events.on('error', e => ret.emit('error', e)); | ||
events.on('event', (event: AmcrestEvent) => { | ||
if (event === AmcrestEvent.MotionStart) { | ||
this.motionDetected = true; | ||
else if (event === AmcrestEvent.MotionStop) | ||
} | ||
else if (event === AmcrestEvent.MotionStop) { | ||
this.motionDetected = false; | ||
else if (event === AmcrestEvent.AudioStart) | ||
} | ||
else if (event === AmcrestEvent.AudioStart) { | ||
this.audioDetected = true; | ||
else if (event === AmcrestEvent.AudioStop) | ||
} | ||
else if (event === AmcrestEvent.AudioStop) { | ||
this.audioDetected = false; | ||
} | ||
} | ||
}) | ||
} | ||
catch (e) { | ||
console.error('event listener failure', e); | ||
await new Promise(resolve => setTimeout(resolve, 10000)); | ||
ret.emit('error', e); | ||
} | ||
} | ||
})(); | ||
return ret; | ||
} | ||
createClient() { | ||
@@ -43,0 +51,0 @@ return new AmcrestCameraClient(this.storage.getItem('ip'), this.getUsername(), this.getPassword()); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
6
66071
154