-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.js
122 lines (95 loc) · 3.34 KB
/
lib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { fromStreamReader } from "https://deno.land/std@0.74.0/io/mod.ts";
export const commands = {
_: Deno.core.encode('\n'),
ping: Deno.core.encode('nPING'),
scan: Deno.core.encode('nSCAN '),
stats: Deno.core.encode('nSTATS'),
reload: Deno.core.encode('nRELOAD'),
version: Deno.core.encode('nVERSION'),
shutdown: Deno.core.encode('nSHUTDOWN'),
contscan: Deno.core.encode('nCONTSCAN '),
instream: Deno.core.encode('nINSTREAM\n'),
multiscan: Deno.core.encode('nMULTISCAN '),
allmatchscan: Deno.core.encode('nALLMATCHSCAN '),
}
export default class ClamAV {
constructor({ port, host }) {
this.port = port;
this.host = host;
}
async ping() {
return Deno.core.decode(await this.request(commands.ping));
}
async stats() {
return Deno.core.decode(await this.request(commands.stats));
}
async reload() {
return Deno.core.decode(await this.request(commands.reload));
}
async version() {
return Deno.core.decode(await this.request(commands.version));
}
async contscan(path) {
return Deno.core.decode(await this.request(commands.contscan, Deno.core.encode(path)));
}
async multiscan(path) {
return Deno.core.decode(await this.request(commands.multiscan, Deno.core.encode(path)));
}
async allmatchscan(path) {
return Deno.core.decode(await this.request(commands.allmatchscan, Deno.core.encode(path)));
}
async shutdown() {
const res = await this.request(commands.shutdown);
if (0 === res.length) return !!1;
else throw Deno.core.decode(res);
}
async scan(body) {
if ('string' === typeof body) {
return Deno.core.decode(await this.request(commands.scan, Deno.core.encode(body)));
}
else if (ArrayBuffer.isView(body) & !(body instanceof Uint8Array)) body = new Uint8Array(body.buffer);
else if (body instanceof ArrayBuffer || body instanceof SharedArrayBuffer) body = new Uint8Array(body);
const { readable, writable } = new ChunksStream();
const res = this.request(commands.instream, readable);
if (body instanceof ReadableStream) await body.pipeTo(writable);
else {
const w = writable.getWriter();
if (body instanceof Uint8Array) await w.write(body);
else for await (const chunk of Deno.iter(body)) await w.write(chunk);
await w.close();
}
return Deno.core.decode(await res);
}
async request(cmd, body) {
const con = await Deno.connect({
port: this.port,
transport: 'tcp',
hostname: this.host,
}).catch(() => Promise.reject(new Error(`clamd is not running on ${this.host}:${this.port}`)));
await con.write(cmd);
if (body) {
if (body instanceof Uint8Array) await Deno.writeAll(con, body);
else await Deno.copy(body instanceof ReadableStream ? fromStreamReader(body.getReader()) : body, con);
}
con.write(commands._);
return (await Deno.readAll(con)).subarray(0, -1);
}
}
class ChunksStream extends TransformStream {
static transformer = {
flush: ChunksStream.flush,
transform: ChunksStream.transform,
};
constructor() {
super(ChunksStream.transformer);
}
static flush(controller) {
controller.enqueue(new Uint8Array(4));
}
static transform(chunk, controller) {
const size = new Uint8Array(4);
new DataView(size.buffer).setUint32(0, chunk.length, false);
controller.enqueue(size);
controller.enqueue(chunk);
}
}