@apocaliss92/nodelink-js 0.1.9 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +257 -9
- package/dist/{DiagnosticsTools-EC7DADEQ.js → DiagnosticsTools-6WEMO4L4.js} +2 -2
- package/dist/{chunk-YUBYINJF.js → chunk-ULSFEQSE.js} +1764 -375
- package/dist/chunk-ULSFEQSE.js.map +1 -0
- package/dist/{chunk-TZFZ5WJX.js → chunk-ZE7D7LI4.js} +40 -9
- package/dist/chunk-ZE7D7LI4.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +1781 -367
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +1940 -369
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +312 -50
- package/dist/index.d.ts +314 -49
- package/dist/index.js +158 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-TZFZ5WJX.js.map +0 -1
- package/dist/chunk-YUBYINJF.js.map +0 -1
- /package/dist/{DiagnosticsTools-EC7DADEQ.js.map → DiagnosticsTools-6WEMO4L4.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<h1
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
</
|
|
1
|
+
<table>
|
|
2
|
+
<tr>
|
|
3
|
+
<td><img src="app/client/public/icon-512x512.png" alt="nodelink.js" width="256" height="256"></td>
|
|
4
|
+
<td>
|
|
5
|
+
<h1>nodelink.js</h1>
|
|
6
|
+
<p>A TypeScript library for interacting with Reolink IP cameras and NVRs using the proprietary Baichuan protocol and CGI API.</p>
|
|
7
|
+
</td>
|
|
8
|
+
</tr>
|
|
9
|
+
</table>
|
|
10
10
|
|
|
11
11
|
## Credits
|
|
12
12
|
|
|
@@ -30,6 +30,254 @@ This library is inspired by and based on the reverse engineering work done by:
|
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
|
+
## 🖥️ Manager UI (Web Dashboard)
|
|
34
|
+
|
|
35
|
+
The library includes a **complete web-based management interface** for easy camera configuration and streaming control without writing code.
|
|
36
|
+
|
|
37
|
+
<p align="center">
|
|
38
|
+
<b>Features:</b>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
- 🎛️ **Camera Management** - Add, configure, and monitor multiple cameras
|
|
42
|
+
- 📹 **Live Streaming** - Preview streams via MJPEG, WebRTC, or RTSP
|
|
43
|
+
- 📊 **Real-time Logs** - Monitor camera events and system logs
|
|
44
|
+
- ⚙️ **Settings** - Configure RTSP proxy, ports, and auto-start options
|
|
45
|
+
- 📱 **PWA Support** - Install as a Progressive Web App on mobile devices
|
|
46
|
+
- 🌐 **Responsive Design** - Works on desktop, tablet, and mobile
|
|
47
|
+
|
|
48
|
+
### External Requirements
|
|
49
|
+
|
|
50
|
+
To run the Manager UI outside Docker, you need:
|
|
51
|
+
|
|
52
|
+
Some features also rely on external binaries that must be available on the host when running outside Docker:
|
|
53
|
+
|
|
54
|
+
Install examples:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# macOS
|
|
58
|
+
brew install ffmpeg
|
|
59
|
+
|
|
60
|
+
# Debian/Ubuntu
|
|
61
|
+
sudo apt-get update && sudo apt-get install -y ffmpeg
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If you use the Docker image, FFmpeg is already included (see Docker Deployment below).
|
|
65
|
+
|
|
66
|
+
### Quick Start (Development)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd app
|
|
70
|
+
npm install
|
|
71
|
+
npm run dev
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Trusted Proxy Authentication (NGINX + Authentik)
|
|
75
|
+
|
|
76
|
+
If you want to hide the UI behind SSO (e.g. Authentik), you can delegate authentication to a reverse proxy and let this app **trust** specific headers **only** when requests come from an allowlisted proxy IP.
|
|
77
|
+
|
|
78
|
+
### Server configuration
|
|
79
|
+
|
|
80
|
+
Set these env vars for the app:
|
|
81
|
+
|
|
82
|
+
- `AUTH_ENABLED=1`
|
|
83
|
+
- `TRUST_PROXY_AUTH=1`
|
|
84
|
+
- `TRUST_PROXY_IPS=127.0.0.1,::1` (comma-separated allowlist; use the _real_ proxy/container IPs)
|
|
85
|
+
- `TRUST_PROXY_USERNAME_HEADER=x-authentik-username`
|
|
86
|
+
- `TRUST_PROXY_GROUPS_HEADER=x-authentik-groups`
|
|
87
|
+
- `TRUST_PROXY_ADMIN_GROUP=admin` (if present in groups header → user becomes `admin`)
|
|
88
|
+
|
|
89
|
+
Security notes:
|
|
90
|
+
|
|
91
|
+
- **Never expose the app directly to the Internet** when `TRUST_PROXY_AUTH=1`.
|
|
92
|
+
- Always put it behind your reverse proxy and restrict inbound traffic to the proxy only.
|
|
93
|
+
- The app will ignore trusted headers unless the TCP peer IP matches `TRUST_PROXY_IPS`.
|
|
94
|
+
|
|
95
|
+
### NGINX example (Authentik outpost)
|
|
96
|
+
|
|
97
|
+
This example assumes:
|
|
98
|
+
|
|
99
|
+
- Authentik outpost is available at `http://authentik-outpost:9000`.
|
|
100
|
+
- The app is at `http://nodelink-manager:3000`.
|
|
101
|
+
|
|
102
|
+
```nginx
|
|
103
|
+
# Authentik integration (auth_request)
|
|
104
|
+
location = /outpost.goauthentik.io/auth/nginx {
|
|
105
|
+
internal;
|
|
106
|
+
proxy_pass http://authentik-outpost:9000/outpost.goauthentik.io/auth/nginx;
|
|
107
|
+
proxy_pass_request_body off;
|
|
108
|
+
proxy_set_header Content-Length "";
|
|
109
|
+
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
|
110
|
+
proxy_set_header X-Original-Method $request_method;
|
|
111
|
+
proxy_set_header X-Original-Host $http_host;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
location / {
|
|
115
|
+
auth_request /outpost.goauthentik.io/auth/nginx;
|
|
116
|
+
error_page 401 = @ak_unauthorized;
|
|
117
|
+
|
|
118
|
+
# Pull identity from Authentik response
|
|
119
|
+
auth_request_set $ak_username $upstream_http_x_authentik_username;
|
|
120
|
+
auth_request_set $ak_groups $upstream_http_x_authentik_groups;
|
|
121
|
+
|
|
122
|
+
proxy_pass http://nodelink-manager:3000;
|
|
123
|
+
|
|
124
|
+
# Forward identity headers to the app
|
|
125
|
+
proxy_set_header X-Authentik-Username $ak_username;
|
|
126
|
+
proxy_set_header X-Authentik-Groups $ak_groups;
|
|
127
|
+
|
|
128
|
+
# Good hygiene
|
|
129
|
+
proxy_set_header Host $host;
|
|
130
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
131
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
132
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
location @ak_unauthorized {
|
|
136
|
+
return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If you run NGINX and the app on the same Docker network, set `TRUST_PROXY_IPS` to the **NGINX container IP** (or keep it `127.0.0.1,::1` only if NGINX is on the same host network namespace).
|
|
141
|
+
|
|
142
|
+
### Production Build
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cd app
|
|
146
|
+
npm run build
|
|
147
|
+
npm start
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Open http://localhost:3000 in your browser.
|
|
151
|
+
|
|
152
|
+
### Docker Deployment (Recommended)
|
|
153
|
+
|
|
154
|
+
The easiest way to run the Manager UI is with Docker:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Using pre-built image
|
|
158
|
+
docker pull ghcr.io/apocaliss92/nodelink-js-manager:latest
|
|
159
|
+
|
|
160
|
+
docker run -d \
|
|
161
|
+
--name nodelink-manager \
|
|
162
|
+
--network host \
|
|
163
|
+
-v nodelink-data:/data \
|
|
164
|
+
ghcr.io/apocaliss92/nodelink-js-manager:latest
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Or with Docker Compose:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
docker-compose up -d
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Environment Variables:**
|
|
174
|
+
|
|
175
|
+
| Variable | Default | Description |
|
|
176
|
+
| ----------- | ------- | ------------------------------------ |
|
|
177
|
+
| `PORT` | `3000` | HTTP server port |
|
|
178
|
+
| `RTSP_PORT` | `8554` | RTSP proxy port |
|
|
179
|
+
| `DATA_PATH` | `/data` | Directory for settings.json and logs |
|
|
180
|
+
|
|
181
|
+
**Dashboard authentication (optional):**
|
|
182
|
+
|
|
183
|
+
| Variable | Default | Description |
|
|
184
|
+
| ---------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
185
|
+
| `AUTH_ENABLED` | (unset) | Enable auth when set to `1/true` (or disable with `0/false`). If unset, auth auto-enables when `ADMIN_PASSWORD` is set. |
|
|
186
|
+
| `ADMIN_PASSWORD` | (unset) | Sets the `admin` password. This credential works for both the web login form and HTTP Basic auth. |
|
|
187
|
+
|
|
188
|
+
### Streaming Authentication (RTSP / MJPEG / HLS / WebRTC)
|
|
189
|
+
|
|
190
|
+
When authentication is enabled (see `AUTH_ENABLED` / `ADMIN_PASSWORD`), **all streaming endpoints are protected**.
|
|
191
|
+
|
|
192
|
+
#### Step-by-step
|
|
193
|
+
|
|
194
|
+
1. **Login to the Manager UI** (or use the API login) to obtain an auth token.
|
|
195
|
+
2. (Recommended) **Generate a long-lived personal token** from **Settings → Personal token**.
|
|
196
|
+
3. Use the correct auth mechanism depending on the streaming protocol:
|
|
197
|
+
|
|
198
|
+
- RTSP: **Digest** with username/password
|
|
199
|
+
- MJPEG/HLS: token in query string `?token=...`
|
|
200
|
+
- WebRTC signaling + status endpoints: `Authorization: Bearer ...`
|
|
201
|
+
- WebSocket logs: `?token=...` in the WS URL
|
|
202
|
+
|
|
203
|
+
There are two auth mechanisms depending on the protocol:
|
|
204
|
+
|
|
205
|
+
1. **RTSP (RTSP proxy): Digest auth with username/password**
|
|
206
|
+
|
|
207
|
+
- URL format: `rtsp://<host>:<RTSP_PORT>/<camera>/<main|sub|ext>`
|
|
208
|
+
- Credentials: the same **Users** list used by the dashboard.
|
|
209
|
+
- Digest realm: `RTSP Proxy`
|
|
210
|
+
- You can toggle whether auth is required via the Manager UI setting **“Require auth for RTSP connections”**.
|
|
211
|
+
|
|
212
|
+
Examples:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# ffmpeg (Digest)
|
|
216
|
+
ffmpeg -rtsp_transport tcp -i "rtsp://USERNAME:PASSWORD@HOST:8554/camera/main" -f null -
|
|
217
|
+
|
|
218
|
+
# VLC (it will prompt for credentials, or use URL user:pass)
|
|
219
|
+
vlc "rtsp://USERNAME:PASSWORD@HOST:8554/camera/main"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
2. **HTTP-based streaming (MJPEG / HLS): token in query string**
|
|
223
|
+
|
|
224
|
+
Browsers cannot reliably attach custom headers (like `Authorization`) to media tags (`<img>`, `<video>`), so MJPEG/HLS streams must be accessed with the auth token in the URL query string:
|
|
225
|
+
|
|
226
|
+
- MJPEG: `/api/mpeg/<camera>/<profile>?token=...`
|
|
227
|
+
- HLS playlist: `/api/hls/<camera>/<profile>/playlist.m3u8?token=...` (and segment requests will inherit the query param)
|
|
228
|
+
|
|
229
|
+
Examples:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
MJPEG:
|
|
233
|
+
http://HOST:3000/api/mpeg/camera/main?token=YOUR_TOKEN
|
|
234
|
+
|
|
235
|
+
HLS:
|
|
236
|
+
http://HOST:3000/api/hls/camera/main/playlist.m3u8?token=YOUR_TOKEN
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Security note: query tokens may end up in logs/history. Treat them like passwords.
|
|
240
|
+
|
|
241
|
+
3. **WebRTC control endpoints: Bearer token in Authorization header**
|
|
242
|
+
|
|
243
|
+
WebRTC signaling uses JSON endpoints (create session, send ICE candidates, send answer) and supports standard Bearer auth:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# 1) Login to obtain a token
|
|
247
|
+
curl -sS -X POST http://HOST:3000/api/auth/login \
|
|
248
|
+
-H 'content-type: application/json' \
|
|
249
|
+
-d '{"username":"admin","password":"YOUR_PASSWORD"}'
|
|
250
|
+
|
|
251
|
+
# 2) Use the returned token for WebRTC signaling
|
|
252
|
+
curl -sS http://HOST:3000/api/webrtc/status \
|
|
253
|
+
-H "Authorization: Bearer YOUR_TOKEN"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
You can also generate a personal token via API (requires an existing valid token):
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
curl -sS -X POST http://HOST:3000/api/auth/personal-token \
|
|
260
|
+
-H "Authorization: Bearer YOUR_TOKEN" \
|
|
261
|
+
-H 'content-type: application/json' \
|
|
262
|
+
-d '{}'
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
4. **WebSocket logs: token in query string**
|
|
266
|
+
|
|
267
|
+
The browser WebSocket handshake cannot reliably attach custom headers, so use:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
ws://HOST:3000/ws/logs?token=YOUR_TOKEN
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
If authentication is disabled, these endpoints work without credentials.
|
|
274
|
+
|
|
275
|
+
Tip: a personal token is ideal for integrations (Home Assistant, scripts, etc.) because it does not expire.
|
|
276
|
+
|
|
277
|
+
📖 **[Full Docker documentation →](./DOCKER.md)**
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
33
281
|
## 📚 Full API Documentation
|
|
34
282
|
|
|
35
283
|
For detailed method-by-method documentation, see the [documentation](./documentation/) folder:
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
runMultifocalDiagnosticsConsecutively,
|
|
10
10
|
sampleStreams,
|
|
11
11
|
testChannelStreams
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZE7D7LI4.js";
|
|
13
13
|
export {
|
|
14
14
|
collectCgiDiagnostics,
|
|
15
15
|
collectMultifocalDiagnostics,
|
|
@@ -22,4 +22,4 @@ export {
|
|
|
22
22
|
sampleStreams,
|
|
23
23
|
testChannelStreams
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=DiagnosticsTools-
|
|
25
|
+
//# sourceMappingURL=DiagnosticsTools-6WEMO4L4.js.map
|