test(ipsec): покрыть декодер содержимого файла RouterOS
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-test (push) Successful in 1m53s
Docker images / frontend-image (push) Successful in 3m14s
Docker images / updater-image (push) Successful in 49s
Docker images / backend-image (push) Successful in 3m19s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-test (push) Successful in 1m53s
Docker images / frontend-image (push) Successful in 3m14s
Docker images / updater-image (push) Successful in 49s
Docker images / backend-image (push) Successful in 3m19s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -20,9 +20,10 @@
|
||||
"test:users": "tsx src/modules/users/iface-type.test.ts && tsx src/modules/users/bindings.test.ts",
|
||||
"test:pg": "tsx src/db/sql-bind.test.ts && tsx src/db/sqlite-json.test.ts && tsx src/db/traffic-flags.test.ts && tsx src/db/pg-schema.test.ts && tsx src/services/config-revisions.test.ts",
|
||||
"test:config-sync": "tsx src/services/config-apply-plan.test.ts && tsx src/services/entity-snapshots.test.ts",
|
||||
"test:ros-file": "tsx src/services/ros-file-contents.test.ts",
|
||||
"test:backups": "tsx src/services/s3-backup-client.test.ts",
|
||||
"test:live-maps": "tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/services/containers-live.test.ts",
|
||||
"test": "npm run test:alert-engine && npm run test:auth && npm run test:wireguard && npm run test:traffic-rate && npm run test:traffic-flow && npm run test:users && npm run test:pg && npm run test:backups && npm run test:live-maps && npm run test:config-sync",
|
||||
"test": "npm run test:alert-engine && npm run test:auth && npm run test:wireguard && npm run test:traffic-rate && npm run test:traffic-flow && npm run test:users && npm run test:pg && npm run test:backups && npm run test:live-maps && npm run test:config-sync && npm run test:ros-file",
|
||||
"test:geoip": "tsx src/services/traffic-flow-geoip.test.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { extractRosContentsField } from "./mikrotik.js"
|
||||
|
||||
/**
|
||||
* Собирает ответ RouterOS на `/file/get` (.proplist=contents) в том виде, в каком его
|
||||
* отдаёт устройство: single-byte строка, экранируются только кавычка и обратный слэш.
|
||||
*/
|
||||
function rosFileGetResponse(contents: Buffer): Buffer {
|
||||
const escaped: number[] = []
|
||||
for (const byte of contents) {
|
||||
if (byte === 0x22 || byte === 0x5c) escaped.push(0x5c, byte)
|
||||
else escaped.push(byte)
|
||||
}
|
||||
return Buffer.concat([
|
||||
Buffer.from('[{".id":"*A","contents":"', "latin1"),
|
||||
Buffer.from(escaped),
|
||||
Buffer.from('"}]', "latin1"),
|
||||
])
|
||||
}
|
||||
|
||||
{
|
||||
// ASCII-содержимое
|
||||
const content = Buffer.from("hello p12", "latin1")
|
||||
assert.deepEqual(extractRosContentsField(rosFileGetResponse(content)), content)
|
||||
}
|
||||
|
||||
{
|
||||
// Экранированные кавычки и обратный слэш
|
||||
const content = Buffer.from('a"b\\c"d', "latin1")
|
||||
assert.deepEqual(extractRosContentsField(rosFileGetResponse(content)), content)
|
||||
}
|
||||
|
||||
{
|
||||
// Пустой файл
|
||||
assert.equal(extractRosContentsField(rosFileGetResponse(Buffer.alloc(0))).length, 0)
|
||||
}
|
||||
|
||||
{
|
||||
// Управляющие escape-последовательности
|
||||
const raw = Buffer.from('{"contents":"a\\nb\\tc\\u0041"}', "latin1")
|
||||
assert.deepEqual(extractRosContentsField(raw), Buffer.from("a\nb\tcA", "latin1"))
|
||||
}
|
||||
|
||||
{
|
||||
// contents не первый ключ в объекте
|
||||
const raw = Buffer.from('{".id":"*B","name":"x.p12","contents":"DATA"}', "latin1")
|
||||
assert.deepEqual(extractRosContentsField(raw), Buffer.from("DATA", "latin1"))
|
||||
}
|
||||
|
||||
{
|
||||
// Все 256 байт: single-byte кодировка не должна терять значения 0x80–0xFF и NUL
|
||||
const content = Buffer.from(Array.from({ length: 256 }, (_, i) => i))
|
||||
const decoded = extractRosContentsField(rosFileGetResponse(content))
|
||||
assert.equal(decoded.length, 256)
|
||||
assert.deepEqual(decoded, content)
|
||||
}
|
||||
|
||||
{
|
||||
// Нет поля contents — понятная ошибка
|
||||
assert.throws(
|
||||
() => extractRosContentsField(Buffer.from('{".id":"*A"}', "latin1")),
|
||||
/не содержит поле contents/,
|
||||
)
|
||||
}
|
||||
|
||||
console.log("ros-file-contents.test.ts: ok")
|
||||
Reference in New Issue
Block a user