mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2026-09-26 20:41:45 +00:00
v3
This commit is contained in:
@@ -3,7 +3,7 @@ import { access, constants, writeFile } from 'node:fs/promises'
|
||||
import { basename, resolve } from 'node:path'
|
||||
import { decode } from '@msgpack/msgpack'
|
||||
import pretty from 'pretty-bytes'
|
||||
import { decrypt, deriveKey, setServer, getServer, info, get } from '@cryptgeon/shared'
|
||||
import { decrypt, deriveKey, setServer, getServer, info, get, decompress } from '@cryptgeon/shared'
|
||||
|
||||
export async function download(url: URL, all: boolean, suggestedPassword?: string) {
|
||||
setServer(url.origin)
|
||||
@@ -32,7 +32,7 @@ export async function download(url: URL, all: boolean, suggestedPassword?: strin
|
||||
if (!note) throw new Error('Could not load note')
|
||||
|
||||
const decrypted = decrypt(note.data, key)
|
||||
const content = decode(decrypted) as any
|
||||
const content = decode(decompress(decrypted)) as any
|
||||
|
||||
switch (content.type) {
|
||||
case 'files':
|
||||
|
||||
@@ -3,7 +3,7 @@ import { basename } from 'node:path'
|
||||
|
||||
import { encode } from '@msgpack/msgpack'
|
||||
import mime from 'mime'
|
||||
import { encrypt, generateKey, deriveKey, randomBytes, setServer, getServer, create, utf8ToBytes } from '@cryptgeon/shared'
|
||||
import { encrypt, generateKey, deriveKey, randomBytes, setServer, getServer, create, utf8ToBytes, compress } from '@cryptgeon/shared'
|
||||
|
||||
export type UploadOptions = { views?: number; expiration?: number; password?: string }
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function upload(input: string | string[], options: UploadOptions):
|
||||
inner = encode({ type: 'files', data: files })
|
||||
}
|
||||
|
||||
const data = encrypt(inner, key)
|
||||
const data = encrypt(compress(inner), key)
|
||||
const result = await create({ meta: { ...noteOptions, extra }, data })
|
||||
let url = `${getServer()}/note/${result.id}`
|
||||
if (!password) url += `#${Buffer.from(key).toString('hex')}`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
deriveKey, generateKey, encrypt, randomBytes,
|
||||
bytesToHex, encode,
|
||||
bytesToHex, encode, compress,
|
||||
create as apiCreate,
|
||||
type FileDTO, type ServerNote
|
||||
} from '@cryptgeon/shared'
|
||||
@@ -131,7 +131,12 @@
|
||||
inner = encode({ type: 'text', data: textContent })
|
||||
}
|
||||
|
||||
const data = encrypt(inner, key)
|
||||
const originalSize =inner.byteLength
|
||||
const compressed = compress(inner)
|
||||
const compresseedSize= compressed.byteLength
|
||||
console.debug({originalSize, compresseedSize, ratio: originalSize/compresseedSize})
|
||||
|
||||
const data = encrypt(compress(inner), key)
|
||||
const extra = customPassword
|
||||
? encode({ salt: salt!, N: 32768, r: 8, p: 1 })
|
||||
: new Uint8Array()
|
||||
@@ -281,4 +286,4 @@
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { deriveKey, hexToBytes, decrypt, decode, info, get as apiGet, type FileDTO } from '@cryptgeon/shared'
|
||||
import { deriveKey, hexToBytes, decrypt, decode, decompress, info, get as apiGet, type FileDTO } from '@cryptgeon/shared'
|
||||
import { onMount } from 'svelte'
|
||||
import { t } from 'svelte-intl-precompile'
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
key = hexToBytes(password!)
|
||||
}
|
||||
|
||||
const decrypted = decrypt(serverNote.data, key)
|
||||
const content = decode(decrypted) as any
|
||||
const decrypted = decrypt(serverNote.data, key)
|
||||
const content = decode(decompress(decrypted)) as any
|
||||
|
||||
switch (content.type) {
|
||||
case 'text':
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.1.3",
|
||||
"@noble/ciphers": "^2.2.0",
|
||||
"@noble/hashes": "^2.2.0"
|
||||
"@noble/hashes": "^2.2.0",
|
||||
"lz4js": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lz4js": "^0.2.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.7"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { compress, decompress, utf8ToBytes } from "./index";
|
||||
|
||||
describe("compression", () => {
|
||||
it("round-trips small text", () => {
|
||||
const data = utf8ToBytes("hello world");
|
||||
const compressed = compress(data);
|
||||
const decompressed = decompress(compressed);
|
||||
expect(decompressed).toEqual(data);
|
||||
});
|
||||
|
||||
it("round-trips highly compressible data", () => {
|
||||
const data = utf8ToBytes("a".repeat(10_000));
|
||||
const compressed = compress(data);
|
||||
expect(compressed.length).toBeLessThan(data.length);
|
||||
const decompressed = decompress(compressed);
|
||||
expect(decompressed).toEqual(data);
|
||||
});
|
||||
|
||||
it("round-trips arbitrary bytes", () => {
|
||||
const data = new Uint8Array([0, 128, 255, 1, 2, 3, 200, 100]);
|
||||
const compressed = compress(data);
|
||||
const decompressed = decompress(compressed);
|
||||
expect(decompressed).toEqual(data);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import LZ4 from "lz4js";
|
||||
|
||||
export function compress(data: Uint8Array): Uint8Array {
|
||||
return LZ4.compress(data);
|
||||
}
|
||||
|
||||
export function decompress(data: Uint8Array): Uint8Array {
|
||||
return LZ4.decompress(data);
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
||||
import { managedNonce, randomBytes, utf8ToBytes } from "@noble/ciphers/utils.js";
|
||||
import { managedNonce, randomBytes } from "@noble/ciphers/utils.js";
|
||||
import { scrypt } from "@noble/hashes/scrypt.js";
|
||||
|
||||
export { bytesToUtf8, utf8ToBytes } from "@noble/ciphers/utils.js";
|
||||
export { randomBytes } from "@noble/ciphers/utils.js";
|
||||
export {
|
||||
bytesToUtf8,
|
||||
utf8ToBytes,
|
||||
hexToBytes,
|
||||
bytesToHex,
|
||||
randomBytes,
|
||||
} from "@noble/ciphers/utils.js";
|
||||
|
||||
const N = 2 ** 15;
|
||||
const KEY_SIZE = 32;
|
||||
@@ -25,17 +30,3 @@ export function decrypt(data: Uint8Array, key: Uint8Array): Uint8Array {
|
||||
const chacha = managedNonce(xchacha20poly1305)(key);
|
||||
return chacha.decrypt(data);
|
||||
}
|
||||
|
||||
export function bytesToHex(bytes: Uint8Array): string {
|
||||
return Array.from(bytes)
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
export function hexToBytes(hex: string): Uint8Array {
|
||||
const bytes = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./crypto.js";
|
||||
export * from "./types.js";
|
||||
export * from "./api.js";
|
||||
export { encode, decode } from "@msgpack/msgpack";
|
||||
export * from "./compression.js";
|
||||
export { encode, decode } from "@msgpack/msgpack";
|
||||
|
||||
Reference in New Issue
Block a user