first commit

This commit is contained in:
2026-08-14 11:44:00 +02:00
commit 4fa600a3a3
990 changed files with 153262 additions and 0 deletions
+331
View File
@@ -0,0 +1,331 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const { once } = require("events");
const sharp = require("sharp");
const app = require("../src/server");
async function createTestImage() {
const width = 200;
const height = 200;
const pixels = Buffer.alloc(
width * height * 4
);
for (
let i = 0;
i < pixels.length;
i += 4
) {
pixels[i] = 128;
pixels[i + 1] = 128;
pixels[i + 2] = 128;
pixels[i + 3] = 255;
}
return sharp(pixels, {
raw: {
width,
height,
channels: 4
}
})
.png()
.toBuffer();
}
async function createServer() {
const server = app.listen(0);
await once(server, "listening");
const address = server.address();
return {
server,
baseUrl: `http://127.0.0.1:${address.port}`
};
}
test("GET /api/health", async () => {
const {
server,
baseUrl
} = await createServer();
try {
const response = await fetch(
`${baseUrl}/api/health`
);
assert.equal(
response.status,
200
);
const body = await response.json();
assert.deepEqual(body, {
status: "ok"
});
} finally {
server.close();
}
});
test(
"encode and decode a message through the API",
async () => {
const {
server,
baseUrl
} = await createServer();
try {
const image =
await createTestImage();
const encodeForm =
new FormData();
encodeForm.append(
"image",
new Blob(
[image],
{
type: "image/png"
}
),
"test.png"
);
encodeForm.append(
"message",
"Hello from the integration test!"
);
encodeForm.append(
"password",
"test-password"
);
const encodedResponse =
await fetch(
`${baseUrl}/api/encode`,
{
method: "POST",
body: encodeForm
}
);
assert.equal(
encodedResponse.status,
200
);
assert.equal(
encodedResponse.headers.get(
"content-type"
),
"image/png"
);
const encodedImage =
Buffer.from(
await encodedResponse.arrayBuffer()
);
assert.ok(
encodedImage.length > 0
);
const decodeForm =
new FormData();
decodeForm.append(
"image",
new Blob(
[encodedImage],
{
type: "image/png"
}
),
"encoded.png"
);
decodeForm.append(
"password",
"test-password"
);
const decodedResponse =
await fetch(
`${baseUrl}/api/decode`,
{
method: "POST",
body: decodeForm
}
);
assert.equal(
decodedResponse.status,
200
);
const result =
await decodedResponse.json();
assert.deepEqual(
result,
{
type: "message",
message:
"Hello from the integration test!"
}
);
} finally {
server.close();
}
}
);
test(
"encode and decode a file through the API",
async () => {
const {
server,
baseUrl
} = await createServer();
try {
const image =
await createTestImage();
const originalFile =
Buffer.from(
"This is a secret file.\n"
);
const encodeForm =
new FormData();
encodeForm.append(
"image",
new Blob(
[image],
{
type: "image/png"
}
),
"test.png"
);
encodeForm.append(
"file",
new Blob(
[originalFile],
{
type: "text/plain"
}
),
"secret.txt"
);
encodeForm.append(
"password",
"test-password"
);
const encodedResponse =
await fetch(
`${baseUrl}/api/encode`,
{
method: "POST",
body: encodeForm
}
);
assert.equal(
encodedResponse.status,
200
);
assert.equal(
encodedResponse.headers.get(
"content-type"
),
"image/png"
);
const encodedImage =
Buffer.from(
await encodedResponse.arrayBuffer()
);
assert.ok(
encodedImage.length > 0
);
const decodeForm =
new FormData();
decodeForm.append(
"image",
new Blob(
[encodedImage],
{
type: "image/png"
}
),
"encoded.png"
);
decodeForm.append(
"password",
"test-password"
);
const decodedResponse =
await fetch(
`${baseUrl}/api/decode`,
{
method: "POST",
body: decodeForm
}
);
assert.equal(
decodedResponse.status,
200
);
const decodedFile =
Buffer.from(
await decodedResponse.arrayBuffer()
);
assert.deepEqual(
decodedFile,
originalFile
);
assert.equal(
decodedResponse.headers.get(
"content-type"
),
"text/plain"
);
assert.match(
decodedResponse.headers.get(
"content-disposition"
),
/secret\.txt/
);
} finally {
server.close();
}
}
);
+514
View File
@@ -0,0 +1,514 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const stego = require("../src/stego/engine");
function createPixels(width, height) {
const pixels =
Buffer.alloc(
width * height * 4
);
// Give the test image valid RGBA values.
for (
let i = 0;
i < pixels.length;
i += 4
) {
pixels[i] = 128;
pixels[i + 1] = 128;
pixels[i + 2] = 128;
pixels[i + 3] = 255;
}
return pixels;
}
test(
"encodes and decodes a text message",
async () => {
const width = 100;
const height = 100;
const pixels =
createPixels(
width,
height
);
const originalMessage =
"kokiiii is the best :3";
const password =
"kokithebestie";
const encoded =
await stego.encode({
pixels,
width,
height,
message:
originalMessage,
password
});
const decoded =
await stego.decode({
pixels:
encoded.pixels,
password
});
assert.equal(
decoded.type,
"message"
);
assert.equal(
decoded.message,
originalMessage
);
}
);
test(
"encodes and decodes a file",
async () => {
const width = 200;
const height = 200;
const pixels =
createPixels(
width,
height
);
const originalFile =
Buffer.from(
"This is a secret file.\n"
);
const encoded =
await stego.encode({
pixels,
width,
height,
password:
"test-password",
file: {
originalname:
"secret.txt",
mimetype:
"text/plain",
buffer:
originalFile
}
});
const decoded =
await stego.decode({
pixels:
encoded.pixels,
password:
"test-password"
});
assert.equal(
decoded.type,
"file"
);
assert.equal(
decoded.filename,
"secret.txt"
);
assert.equal(
decoded.mimetype,
"text/plain"
);
assert.deepEqual(
decoded.file,
originalFile
);
}
);
test(
"rejects an incorrect password",
async () => {
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"secret message",
password:
"correct-password"
});
await assert.rejects(
() =>
stego.decode({
pixels:
encoded.pixels,
password:
"wrong-password"
}),
{
message:
"Invalid password or corrupted payload"
}
);
}
);
test(
"requires a password for encrypted payloads",
async () => {
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"encrypted secret",
password:
"secret-password"
});
await assert.rejects(
() =>
stego.decode({
pixels:
encoded.pixels
}),
{
message:
"Password is required for this payload"
}
);
}
);
test(
"rejects a missing password during encrypted encoding",
async () => {
/*
* This test intentionally verifies that
* passwordless encoding is now allowed.
*
* It should NOT reject.
*/
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"no password"
});
assert.ok(
encoded.pixels
);
}
);
test(
"encodes and decodes a message without a password",
async () => {
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"passwordless secret"
});
const decoded =
await stego.decode({
pixels:
encoded.pixels
});
assert.equal(
decoded.type,
"message"
);
assert.equal(
decoded.message,
"passwordless secret"
);
}
);
test(
"encodes and decodes a file without a password",
async () => {
const pixels =
createPixels(
200,
200
);
const originalFile =
Buffer.from(
"passwordless file"
);
const encoded =
await stego.encode({
pixels,
width: 200,
height: 200,
file: {
originalname:
"secret.txt",
mimetype:
"text/plain",
buffer:
originalFile
}
});
const decoded =
await stego.decode({
pixels:
encoded.pixels
});
assert.equal(
decoded.type,
"file"
);
assert.equal(
decoded.filename,
"secret.txt"
);
assert.equal(
decoded.mimetype,
"text/plain"
);
assert.deepEqual(
decoded.file,
originalFile
);
}
);
test(
"rejects when neither message nor file is supplied",
async () => {
const pixels =
createPixels(
100,
100
);
await assert.rejects(
() =>
stego.encode({
pixels,
width: 100,
height: 100,
password:
"password"
}),
{
message:
"Message or file is required"
}
);
}
);
test(
"rejects a payload that is too large",
async () => {
const pixels =
createPixels(
10,
10
);
const hugeMessage =
"A".repeat(10000);
await assert.rejects(
() =>
stego.encode({
pixels,
width: 10,
height: 10,
message:
hugeMessage,
password:
"password"
}),
{
message:
/Payload too large/
}
);
}
);
test(
"reports image capacity",
() => {
const capacity =
stego.getCapacity(
100,
100
);
assert.equal(
capacity,
3740
);
}
);
test(
"rejects a tampered image",
async () => {
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"secret message",
password:
"test-password"
});
const tampered =
Buffer.from(
encoded.pixels
);
/*
* Flip a bit inside the embedded
* payload.
*/
tampered[100] ^= 1;
await assert.rejects(
() =>
stego.decode({
pixels:
tampered,
password:
"test-password"
}),
{
message:
"Invalid password or corrupted payload"
}
);
}
);
test(
"rejects a corrupted payload",
async () => {
const pixels =
createPixels(
100,
100
);
const encoded =
await stego.encode({
pixels,
width: 100,
height: 100,
message:
"secret message",
password:
"test-password"
});
const corrupted =
Buffer.from(
encoded.pixels
);
/*
* Corrupt several embedded bits
* in the payload area.
*/
for (
let i = 100;
i < 110;
i++
) {
corrupted[i] ^= 1;
}
await assert.rejects(
() =>
stego.decode({
pixels:
corrupted,
password:
"test-password"
}),
{
message:
"Invalid password or corrupted payload"
}
);
}
);