securequ 1.1.1 → 1.1.3
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/client/Base.d.ts +17 -17
- package/client/Base.js.map +1 -1
- package/client/Base.mjs.map +1 -1
- package/client/index.d.ts +7 -7
- package/client/index.js.map +1 -1
- package/client/index.mjs.map +1 -1
- package/client/types.d.ts +36 -36
- package/include/File.js.map +1 -1
- package/include/File.mjs.map +1 -1
- package/include/FileScaner.js.map +1 -1
- package/include/FileScaner.mjs.map +1 -1
- package/include/compress.d.ts +12 -0
- package/include/compress.js +1 -1
- package/include/compress.js.map +1 -1
- package/include/compress.mjs +1 -1
- package/include/compress.mjs.map +1 -1
- package/include/crypto.d.ts +19 -0
- package/include/crypto.js +1 -1
- package/include/crypto.js.map +1 -1
- package/include/crypto.mjs +1 -1
- package/include/crypto.mjs.map +1 -1
- package/index.d.ts +4 -0
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
- package/readme.md +314 -54
- package/server/Base.d.ts +19 -19
- package/server/Base.js.map +1 -1
- package/server/Base.mjs.map +1 -1
- package/server/Router.d.ts +9 -8
- package/server/Router.js.map +1 -1
- package/server/Router.mjs.map +1 -1
- package/server/index.d.ts +4 -4
- package/server/index.js.map +1 -1
- package/server/index.mjs.map +1 -1
- package/server/types.d.ts +73 -64
package/include/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sources":["../../src/include/crypto.ts"],"sourcesContent":["import sodium from \"libsodium-wrappers\";\nimport
|
|
1
|
+
{"version":3,"file":"crypto.js","sources":["../../src/include/crypto.ts"],"sourcesContent":["import sodium from \"libsodium-wrappers\";\r\nimport compresor from \"./compress\";\r\n\r\nexport type EncryptInput = string | object | any[];\r\n\r\n/** --- Key/Nonce Derivation --- */\r\nfunction deriveKey(secret: string): Uint8Array {\r\n return sodium.crypto_generichash(\r\n sodium.crypto_secretbox_KEYBYTES,\r\n sodium.from_string(secret)\r\n );\r\n}\r\n\r\nfunction deriveNonce(secret: string): Uint8Array {\r\n return sodium.crypto_generichash(\r\n sodium.crypto_secretbox_NONCEBYTES,\r\n sodium.from_string(secret)\r\n );\r\n}\r\n\r\n/** --- STRING --- */\r\nexport async function encrypt(input: EncryptInput, secret: string): Promise<string> {\r\n const encrypted = await encryptBuffer(input, secret);\r\n return sodium.to_base64(encrypted);\r\n}\r\n\r\nexport async function decrypt(base64: string, secret: string): Promise<any | null> {\r\n const cipher = sodium.from_base64(base64);\r\n return await decryptBuffer(cipher, secret);\r\n}\r\n\r\n/** --- BUFFER --- */\r\n// Encrypt\r\nexport async function encryptBuffer(input: any, secret: string): Promise<Uint8Array> {\r\n await sodium.ready;\r\n const key = deriveKey(secret);\r\n const nonce = deriveNonce(secret);\r\n const compressed = await compresor.compressBuffer(input);\r\n return sodium.crypto_secretbox_easy(compressed, nonce, key);\r\n}\r\n\r\n// Decrypt\r\nexport async function decryptBuffer(box: Uint8Array, secret: string): Promise<any | null> {\r\n await sodium.ready;\r\n const key = deriveKey(secret);\r\n const nonce = deriveNonce(secret);\r\n try {\r\n const opened = sodium.crypto_secretbox_open_easy(box, nonce, key);\r\n if (!opened) return null;\r\n return await compresor.decompressBuffer(opened);\r\n } catch (error) {\r\n return null;\r\n }\r\n}\r\n\r\n/** --- HASH --- */\r\nexport async function hash(str: string): Promise<string> {\r\n await sodium.ready;\r\n const digest = sodium.crypto_generichash(32, sodium.from_string(str));\r\n return sodium\r\n .to_base64(digest)\r\n .replace(/[^a-zA-Z0-9]/g, \"\")\r\n}\r\n\r\nconst crypto = {\r\n encrypt,\r\n decrypt,\r\n encryptBuffer,\r\n decryptBuffer,\r\n hash,\r\n};\r\n\r\nexport default crypto;\r\n"],"names":["Object","defineProperty","exports","value","sodium","require","compress","deriveKey","secret","crypto_generichash","crypto_secretbox_KEYBYTES","from_string","deriveNonce","crypto_secretbox_NONCEBYTES","async","encrypt","input","encrypted","encryptBuffer","to_base64","decrypt","base64","cipher","from_base64","decryptBuffer","ready","key","nonce","compressed","compresor","compressBuffer","crypto_secretbox_easy","box","opened","crypto_secretbox_open_easy","decompressBuffer","error","hash","str","digest","replace","crypto"],"mappings":"AAKA,aAAAA,OAAAC,eAAAC,QAAA,aAAA,CAAAC,OAAA,IAAA,IAAAC,EAAAC,QAAA,sBAAAC,EAAAD,QAAA,iBACA,SAASE,EAAUC,GAChB,OAAOJ,EAAOK,mBACXL,EAAOM,0BACPN,EAAOO,YAAYH,GAEzB,CAEA,SAASI,EAAYJ,GAClB,OAAOJ,EAAOK,mBACXL,EAAOS,4BACPT,EAAOO,YAAYH,GAEzB,CAGOM,eAAeC,EAAQC,EAAqBR,GAChD,MAAMS,QAAkBC,EAAcF,EAAOR,GAC7C,OAAOJ,EAAOe,UAAUF,EAC3B,CAEOH,eAAeM,EAAQC,EAAgBb,GAC3C,MAAMc,EAASlB,EAAOmB,YAAYF,GAClC,aAAaG,EAAcF,EAAQd,EACtC,CAIOM,eAAeI,EAAcF,EAAYR,SACvCJ,EAAOqB,MACb,MAAMC,EAAMnB,EAAUC,GAChBmB,EAAQf,EAAYJ,GACpBoB,QAAmBC,EAAAA,QAAUC,eAAed,GAClD,OAAOZ,EAAO2B,sBAAsBH,EAAYD,EAAOD,EAC1D,CAGOZ,eAAeU,EAAcQ,EAAiBxB,SAC5CJ,EAAOqB,MACb,MAAMC,EAAMnB,EAAUC,GAChBmB,EAAQf,EAAYJ,GAC1B,IACG,MAAMyB,EAAS7B,EAAO8B,2BAA2BF,EAAKL,EAAOD,GAC7D,OAAKO,QACQJ,EAAAA,QAAUM,iBAAiBF,GADpB,IAEtB,CAAC,MAAOG,GACN,OAAO,IACT,CACJ,CAGOtB,eAAeuB,EAAKC,SAClBlC,EAAOqB,MACb,MAAMc,EAASnC,EAAOK,mBAAmB,GAAIL,EAAOO,YAAY2B,IAChE,OAAOlC,EACHe,UAAUoB,GACVC,QAAQ,gBAAiB,GAChC,CAEA,MAAMC,EAAS,CACZ1B,UACAK,UACAF,gBACAM,gBACAa"}
|
package/include/crypto.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import r from"libsodium-wrappers";import
|
|
1
|
+
import r from"libsodium-wrappers";import t from"./compress.mjs";function e(t){return r.crypto_generichash(r.crypto_secretbox_KEYBYTES,r.from_string(t))}function n(t){return r.crypto_generichash(r.crypto_secretbox_NONCEBYTES,r.from_string(t))}async function c(t,e){const n=await s(t,e);return r.to_base64(n)}async function o(t,e){const n=r.from_base64(t);return await a(n,e)}async function s(c,o){await r.ready;const s=e(o),a=n(o),i=await t.compressBuffer(c);return r.crypto_secretbox_easy(i,a,s)}async function a(c,o){await r.ready;const s=e(o),a=n(o);try{const e=r.crypto_secretbox_open_easy(c,a,s);return e?await t.decompressBuffer(e):null}catch(r){return null}}async function i(t){await r.ready;const e=r.crypto_generichash(32,r.from_string(t));return r.to_base64(e).replace(/[^a-zA-Z0-9]/g,"")}const u={encrypt:c,decrypt:o,encryptBuffer:s,decryptBuffer:a,hash:i};export{o as decrypt,a as decryptBuffer,u as default,c as encrypt,s as encryptBuffer,i as hash};//# sourceMappingURL=crypto.mjs.map
|
package/include/crypto.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.mjs","sources":["../../src/include/crypto.ts"],"sourcesContent":["import sodium from \"libsodium-wrappers\";\nimport
|
|
1
|
+
{"version":3,"file":"crypto.mjs","sources":["../../src/include/crypto.ts"],"sourcesContent":["import sodium from \"libsodium-wrappers\";\r\nimport compresor from \"./compress\";\r\n\r\nexport type EncryptInput = string | object | any[];\r\n\r\n/** --- Key/Nonce Derivation --- */\r\nfunction deriveKey(secret: string): Uint8Array {\r\n return sodium.crypto_generichash(\r\n sodium.crypto_secretbox_KEYBYTES,\r\n sodium.from_string(secret)\r\n );\r\n}\r\n\r\nfunction deriveNonce(secret: string): Uint8Array {\r\n return sodium.crypto_generichash(\r\n sodium.crypto_secretbox_NONCEBYTES,\r\n sodium.from_string(secret)\r\n );\r\n}\r\n\r\n/** --- STRING --- */\r\nexport async function encrypt(input: EncryptInput, secret: string): Promise<string> {\r\n const encrypted = await encryptBuffer(input, secret);\r\n return sodium.to_base64(encrypted);\r\n}\r\n\r\nexport async function decrypt(base64: string, secret: string): Promise<any | null> {\r\n const cipher = sodium.from_base64(base64);\r\n return await decryptBuffer(cipher, secret);\r\n}\r\n\r\n/** --- BUFFER --- */\r\n// Encrypt\r\nexport async function encryptBuffer(input: any, secret: string): Promise<Uint8Array> {\r\n await sodium.ready;\r\n const key = deriveKey(secret);\r\n const nonce = deriveNonce(secret);\r\n const compressed = await compresor.compressBuffer(input);\r\n return sodium.crypto_secretbox_easy(compressed, nonce, key);\r\n}\r\n\r\n// Decrypt\r\nexport async function decryptBuffer(box: Uint8Array, secret: string): Promise<any | null> {\r\n await sodium.ready;\r\n const key = deriveKey(secret);\r\n const nonce = deriveNonce(secret);\r\n try {\r\n const opened = sodium.crypto_secretbox_open_easy(box, nonce, key);\r\n if (!opened) return null;\r\n return await compresor.decompressBuffer(opened);\r\n } catch (error) {\r\n return null;\r\n }\r\n}\r\n\r\n/** --- HASH --- */\r\nexport async function hash(str: string): Promise<string> {\r\n await sodium.ready;\r\n const digest = sodium.crypto_generichash(32, sodium.from_string(str));\r\n return sodium\r\n .to_base64(digest)\r\n .replace(/[^a-zA-Z0-9]/g, \"\")\r\n}\r\n\r\nconst crypto = {\r\n encrypt,\r\n decrypt,\r\n encryptBuffer,\r\n decryptBuffer,\r\n hash,\r\n};\r\n\r\nexport default crypto;\r\n"],"names":["sodium","compresor","deriveKey","secret","crypto_generichash","crypto_secretbox_KEYBYTES","from_string","deriveNonce","crypto_secretbox_NONCEBYTES","async","encrypt","input","encrypted","encryptBuffer","to_base64","decrypt","base64","cipher","from_base64","decryptBuffer","ready","key","nonce","compressed","compressBuffer","crypto_secretbox_easy","box","opened","crypto_secretbox_open_easy","decompressBuffer","error","hash","str","digest","replace","crypto"],"mappings":"OAKAA,MAAA,4BAAAC,MAAA,iBACA,SAASC,EAAUC,GAChB,OAAOH,EAAOI,mBACXJ,EAAOK,0BACPL,EAAOM,YAAYH,GAEzB,CAEA,SAASI,EAAYJ,GAClB,OAAOH,EAAOI,mBACXJ,EAAOQ,4BACPR,EAAOM,YAAYH,GAEzB,CAGOM,eAAeC,EAAQC,EAAqBR,GAChD,MAAMS,QAAkBC,EAAcF,EAAOR,GAC7C,OAAOH,EAAOc,UAAUF,EAC3B,CAEOH,eAAeM,EAAQC,EAAgBb,GAC3C,MAAMc,EAASjB,EAAOkB,YAAYF,GAClC,aAAaG,EAAcF,EAAQd,EACtC,CAIOM,eAAeI,EAAcF,EAAYR,SACvCH,EAAOoB,MACb,MAAMC,EAAMnB,EAAUC,GAChBmB,EAAQf,EAAYJ,GACpBoB,QAAmBtB,EAAUuB,eAAeb,GAClD,OAAOX,EAAOyB,sBAAsBF,EAAYD,EAAOD,EAC1D,CAGOZ,eAAeU,EAAcO,EAAiBvB,SAC5CH,EAAOoB,MACb,MAAMC,EAAMnB,EAAUC,GAChBmB,EAAQf,EAAYJ,GAC1B,IACG,MAAMwB,EAAS3B,EAAO4B,2BAA2BF,EAAKJ,EAAOD,GAC7D,OAAKM,QACQ1B,EAAU4B,iBAAiBF,GADpB,IAEtB,CAAC,MAAOG,GACN,OAAO,IACT,CACJ,CAGOrB,eAAesB,EAAKC,SAClBhC,EAAOoB,MACb,MAAMa,EAASjC,EAAOI,mBAAmB,GAAIJ,EAAOM,YAAY0B,IAChE,OAAOhC,EACHc,UAAUmB,GACVC,QAAQ,gBAAiB,GAChC,CAEA,MAAMC,EAAS,CACZzB,UACAK,UACAF,gBACAM,gBACAY"}
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export { default as SecurequServer } from './server/index.js';
|
|
2
2
|
export { default as SecurequClient } from './client/index.js';
|
|
3
|
+
export { default as crypto } from './include/crypto.js';
|
|
4
|
+
export { default as compresor } from './include/compress.js';
|
|
5
|
+
export { ArgsInfo, HandlerFunction, HandlerInfo, ListenerInfo, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath } from './server/types.js';
|
|
6
|
+
export { HTTPMethods, HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from './client/types.js';
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./server/index.js"),r=require("./client/index.js");exports.SecurequServer=e.default,exports.SecurequClient=r.default;//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./server/index.js"),r=require("./client/index.js"),t=require("./include/crypto.js"),u=require("./include/compress.js");exports.SecurequServer=e.default,exports.SecurequClient=r.default,exports.crypto=t.default,exports.compresor=u.default;//# sourceMappingURL=index.js.map
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{default as SecurequServer}from"./server/index.mjs";export{default as SecurequClient}from"./client/index.mjs";//# sourceMappingURL=index.mjs.map
|
|
1
|
+
export{default as SecurequServer}from"./server/index.mjs";export{default as SecurequClient}from"./client/index.mjs";export{default as crypto}from"./include/crypto.mjs";export{default as compresor}from"./include/compress.mjs";//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,54 +1,314 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
npm
|
|
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
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# securequ
|
|
4
|
+
|
|
5
|
+
High‑level encrypted & compressed HTTP request + chunked upload toolkit for browser ↔ server applications.
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
> Provides an additional application‑layer privacy/integrity envelope. Always deploy behind HTTPS.
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/securequ"><img src="https://img.shields.io/npm/v/securequ.svg" alt="npm version" /></a>
|
|
13
|
+
<a href="#"><img src="https://img.shields.io/badge/status-active-green" alt="status" /></a>
|
|
14
|
+
<a href="#security"><img src="https://img.shields.io/badge/focus-security-blue" alt="focus" /></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
## Table of Contents
|
|
18
|
+
|
|
19
|
+
- [securequ](#securequ)
|
|
20
|
+
- [Table of Contents](#table-of-contents)
|
|
21
|
+
- [Overview](#overview)
|
|
22
|
+
- [Why securequ?](#why-securequ)
|
|
23
|
+
- [Core Concepts (Abstracted)](#core-concepts-abstracted)
|
|
24
|
+
- [Security (Summary)](#security-summary)
|
|
25
|
+
- [Performance Snapshot](#performance-snapshot)
|
|
26
|
+
- [Install](#install)
|
|
27
|
+
- [Minimal Server (Express)](#minimal-server-express)
|
|
28
|
+
- [Minimal Client](#minimal-client)
|
|
29
|
+
- [Client Hooks (Selected)](#client-hooks-selected)
|
|
30
|
+
- [API Surface (High Level)](#api-surface-high-level)
|
|
31
|
+
- [Server Response Model](#server-response-model)
|
|
32
|
+
- [File Upload Overview](#file-upload-overview)
|
|
33
|
+
- [Configuration (Essentials)](#configuration-essentials)
|
|
34
|
+
- [Error Semantics](#error-semantics)
|
|
35
|
+
- [Performance Guidance](#performance-guidance)
|
|
36
|
+
- [Troubleshooting](#troubleshooting)
|
|
37
|
+
- [FAQ](#faq)
|
|
38
|
+
- [Versioning \& Stability](#versioning--stability)
|
|
39
|
+
- [Contributing](#contributing)
|
|
40
|
+
- [Security Reporting](#security-reporting)
|
|
41
|
+
- [Disclaimer](#disclaimer)
|
|
42
|
+
- [License](#license)
|
|
43
|
+
|
|
44
|
+
## Overview
|
|
45
|
+
|
|
46
|
+
securequ places a compact, binary, encrypted envelope around HTTP request/response bodies and coordinates secure, chunked file uploads. A lightweight, ephemeral token (internally named `signeture`) is established via a handshake per client origin and renewed automatically when necessary. Development mode keeps the ergonomics of plain JSON while production mode obfuscates both payload bodies and (optionally) query parameters.
|
|
47
|
+
|
|
48
|
+
Key capabilities:
|
|
49
|
+
- Application‑layer confidentiality & integrity (in addition to transport‑layer TLS)
|
|
50
|
+
- Binary serialization + compression for efficient payload transfer
|
|
51
|
+
- Short‑lived opaque token automatically refreshed
|
|
52
|
+
- File uploads with controlled chunk sizing, size limits, optional first‑chunk file‑type validation, and progress events
|
|
53
|
+
- Minimal routing utilities and lifecycle hooks—framework agnostic
|
|
54
|
+
- Consistent TypeScript surface
|
|
55
|
+
|
|
56
|
+
## Why securequ?
|
|
57
|
+
|
|
58
|
+
| Need | Plain fetch + JSON | securequ |
|
|
59
|
+
| --------------------------------------------- | -------------------- | ---------------------- |
|
|
60
|
+
| Hide request structure from casual inspection | ✗ | ✓ (encrypted envelope) |
|
|
61
|
+
| Automatic compression + binary serialization | Partial (manual) | ✓ built‑in |
|
|
62
|
+
| Short‑lived opaque request token | Custom work | ✓ baked in |
|
|
63
|
+
| Client lifecycle hooks | Manual wiring | ✓ hooks API |
|
|
64
|
+
| Validated chunked uploads + progress | Manual / library mix | ✓ integrated |
|
|
65
|
+
|
|
66
|
+
Use it when you want an extra (opaque) layer plus structured uploads without re‑inventing crypto + binary packing. If HTTPS + standard auth covers all your needs and you prefer transparency, you may not need this.
|
|
67
|
+
|
|
68
|
+
## Core Concepts (Abstracted)
|
|
69
|
+
|
|
70
|
+
| Concept | Summary |
|
|
71
|
+
| ------------------ | --------------------------------------------------------------------------------------- |
|
|
72
|
+
| Pre‑shared secret | Static value per allowed origin (server‑side registration) |
|
|
73
|
+
| Handshake | Lightweight exchange producing a short‑lived opaque token (auto refreshed) |
|
|
74
|
+
| Encrypted envelope | Bodies (and in production, query params) serialized → compressed → encrypted |
|
|
75
|
+
| Development mode | Skips encryption for non‑handshake application requests to aid debugging |
|
|
76
|
+
| Hooks | Extensibility points for request & upload lifecycle events |
|
|
77
|
+
| Chunked upload | Deterministic splitting + metadata negotiation + ordered transfer + completion callback |
|
|
78
|
+
|
|
79
|
+
## Security (Summary)
|
|
80
|
+
|
|
81
|
+
Implemented (High Level):
|
|
82
|
+
- Symmetric encryption with authenticated integrity (AEAD style)
|
|
83
|
+
- Short token lifetime, minimizing replay viability
|
|
84
|
+
- Payload and (production) query obfuscation
|
|
85
|
+
- Optional file‑type validation via first‑chunk signature scanning
|
|
86
|
+
|
|
87
|
+
Operator Responsibilities:
|
|
88
|
+
- Enforce HTTPS and standard secure headers
|
|
89
|
+
- Generate long, random client secrets and rotate periodically
|
|
90
|
+
- Layer proper authentication/authorization (sessions, tokens, etc.)
|
|
91
|
+
- Validate and sanitize business data in handlers
|
|
92
|
+
|
|
93
|
+
Out of Scope:
|
|
94
|
+
- Forward secrecy / per‑message key rotation
|
|
95
|
+
- Fine‑grained end‑user authentication
|
|
96
|
+
- True streaming (payloads are presently buffered)
|
|
97
|
+
- Built‑in rate limiting / abuse controls
|
|
98
|
+
|
|
99
|
+
## Performance Snapshot
|
|
100
|
+
|
|
101
|
+
- Compression + binary encoding reduce large structured bodies vs raw JSON
|
|
102
|
+
- Overhead is minimal for medium/large payloads; for tiny payloads (< 200B) you may prefer plain requests
|
|
103
|
+
- Chunk size is adaptive (you can override) to balance memory and progress smoothness
|
|
104
|
+
- File type detection (if enabled) inspects only the first chunk
|
|
105
|
+
|
|
106
|
+
## Install
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install securequ
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Peer/runtime deps are installed automatically (libsodium, fflate, msgpackr, path-to-regexp, xanfetch).
|
|
113
|
+
|
|
114
|
+
## Minimal Server (Express)
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import express from 'express';
|
|
118
|
+
import { SecurequServer } from 'securequ';
|
|
119
|
+
|
|
120
|
+
const api = new SecurequServer({
|
|
121
|
+
mode: 'production',
|
|
122
|
+
basepath: '/api',
|
|
123
|
+
clients: [{ origin: 'https://app.example.com', secret: process.env.APP_CLIENT_SECRET! }],
|
|
124
|
+
upload: {
|
|
125
|
+
chunk: async (chunk, meta) => { /* store chunk */ return true; },
|
|
126
|
+
complete: async (meta) => { /* stitch & persist */ return `/files/${meta.fileid}`; }
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
api.post('/echo', ({ body }) => { throw { ok: true, body }; });
|
|
131
|
+
|
|
132
|
+
const app = express();
|
|
133
|
+
app.use('/api/*', express.raw({ type: 'application/octet-stream', limit: '20mb' }), async (req, res) => {
|
|
134
|
+
const r = await api.listen({
|
|
135
|
+
signeture: req.headers['x-signeture'] as string,
|
|
136
|
+
path: req.originalUrl,
|
|
137
|
+
body: req.body,
|
|
138
|
+
method: req.method as any,
|
|
139
|
+
origin: req.headers['x-origin'] as string,
|
|
140
|
+
}, req);
|
|
141
|
+
res.status(r.status).end(r.content);
|
|
142
|
+
});
|
|
143
|
+
app.listen(4000);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Minimal Client
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { SecurequClient } from 'securequ';
|
|
150
|
+
|
|
151
|
+
const client = new SecurequClient({
|
|
152
|
+
url: 'https://api.example.com/api',
|
|
153
|
+
secret: '<client-secret>'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Simple request
|
|
157
|
+
const res = await client.post('echo', { body: { hello: 'world' } });
|
|
158
|
+
console.log(res);
|
|
159
|
+
|
|
160
|
+
// File upload with progress
|
|
161
|
+
async function uploadFile(file: File) {
|
|
162
|
+
const result = await client.upload(file, p => console.log('progress %', p));
|
|
163
|
+
console.log(result);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Client Hooks (Selected)
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
hooks: {
|
|
171
|
+
beforeRequest: (path, init) => init,
|
|
172
|
+
afterResponse: (resp) => {},
|
|
173
|
+
beforeUpload: (file, fileId) => file,
|
|
174
|
+
afterUpload: (response, file) => {},
|
|
175
|
+
beforeUploadChunk: (chunk, idx, total) => {},
|
|
176
|
+
afterUploadChunk: (resp, idx, total) => {},
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## API Surface (High Level)
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// Client
|
|
184
|
+
client.get(path, init?)
|
|
185
|
+
client.post(path, init?)
|
|
186
|
+
client.put(path, init?)
|
|
187
|
+
client.delete(path, init?)
|
|
188
|
+
client.upload(file, onProgress?)
|
|
189
|
+
|
|
190
|
+
// Server
|
|
191
|
+
server.get(path, handler)
|
|
192
|
+
server.post(path, handler)
|
|
193
|
+
server.put(path, handler)
|
|
194
|
+
server.delete(path, handler)
|
|
195
|
+
server.listen(listenerInfo, optionalArgs)
|
|
196
|
+
|
|
197
|
+
// Utilities (optional direct use)
|
|
198
|
+
import { crypto, compresor } from 'securequ';
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Server Response Model
|
|
202
|
+
|
|
203
|
+
Handlers conclude by `throw`ing:
|
|
204
|
+
- Plain object / primitive → serialized (dev) or encrypted (prod) with 200 status
|
|
205
|
+
- `Response` instance → its status/body is used (still wrapped if necessary)
|
|
206
|
+
- `Error` → message returned with a not‑found style status (configurable via customization if you wrap upstream)
|
|
207
|
+
|
|
208
|
+
This pattern deliberately short‑circuits route evaluation and keeps handler code linear.
|
|
209
|
+
|
|
210
|
+
## File Upload Overview
|
|
211
|
+
|
|
212
|
+
- Client sends metadata first
|
|
213
|
+
- Server accepts and tracks state
|
|
214
|
+
- Client streams fixed‑size chunks sequentially
|
|
215
|
+
- Final chunk triggers assembly + returned path / identifier
|
|
216
|
+
- A failure notification allows cleanup
|
|
217
|
+
|
|
218
|
+
## Configuration (Essentials)
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
// Server
|
|
222
|
+
new SecurequServer({
|
|
223
|
+
mode: 'production' | 'development',
|
|
224
|
+
basepath: '/api',
|
|
225
|
+
clients: [{ origin, secret }],
|
|
226
|
+
upload?: { maxFilesize?, checkFileType?, chunk(), complete(), failed? },
|
|
227
|
+
accept?: (info) => boolean | Promise<boolean>
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Client
|
|
231
|
+
new SecurequClient({
|
|
232
|
+
url: 'https://host/api',
|
|
233
|
+
secret: '<pre-shared>',
|
|
234
|
+
chunkSize?: number,
|
|
235
|
+
hooks?: { ... }
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Error Semantics
|
|
240
|
+
|
|
241
|
+
- Success: `success: true`, `data` contains decrypted payload
|
|
242
|
+
- Expired token is auto‑recovered (one retry) by re-handshaking
|
|
243
|
+
- Server thrown `Error` surfaces message (wrapped) to client
|
|
244
|
+
|
|
245
|
+
## Performance Guidance
|
|
246
|
+
|
|
247
|
+
- Use production mode for real benchmarking (encryption path active)
|
|
248
|
+
- Keep secrets long & random (>= 32 chars)
|
|
249
|
+
- Tune `chunkSize` only if you need very granular progress events
|
|
250
|
+
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
| Symptom | Possible Cause | Suggested Fix |
|
|
254
|
+
| -------------------------------- | ------------------------------------ | ----------------------------------------------------------------- |
|
|
255
|
+
| `Signeture expired` loops | Clock skew or token window too short | Ensure system clocks are synced; minimize artificial delays |
|
|
256
|
+
| Always 404 / Not found | Route not registered before `listen` | Register handlers before attaching middleware |
|
|
257
|
+
| Plain text visible in production | App running in development mode | Set `mode: 'production'` in server config |
|
|
258
|
+
| Upload stops mid‑way | Page navigation / tab close | Use `beforeunload` UI warning or resume strategy (future roadmap) |
|
|
259
|
+
| File type rejected | Magic bytes not recognized | Disable `checkFileType` or extend scanner if needed |
|
|
260
|
+
| High CPU for tiny payloads | Compression/encryption overhead | Bypass securequ for very small trivial requests |
|
|
261
|
+
|
|
262
|
+
If an issue isn’t listed: enable development mode locally to inspect raw (unencrypted) bodies for debugging, then switch back.
|
|
263
|
+
|
|
264
|
+
## FAQ
|
|
265
|
+
|
|
266
|
+
**Does this replace TLS?**
|
|
267
|
+
No. It layers *on top* of TLS.
|
|
268
|
+
|
|
269
|
+
**Can I plug into another HTTP framework?**
|
|
270
|
+
Yes—adapt the raw body + headers and call `server.listen()`.
|
|
271
|
+
|
|
272
|
+
**How do I add auth?**
|
|
273
|
+
Put your auth tokens/data *inside* the encrypted body or add middleware before calling `listen`.
|
|
274
|
+
|
|
275
|
+
**TypeScript support?**
|
|
276
|
+
Fully typed. Route handlers get a typed `info` object; client responses are typed with a generic shape (`SecurequClientResponse`).
|
|
277
|
+
|
|
278
|
+
**Can I inspect payloads in production?**
|
|
279
|
+
Not without decrypting. Use development mode locally when introspection is needed.
|
|
280
|
+
|
|
281
|
+
**Is there resume upload support?**
|
|
282
|
+
Not yet; planned. You can implement partial detection using hooks + server state.
|
|
283
|
+
|
|
284
|
+
**How big can files be?**
|
|
285
|
+
Limited by your configured `maxFilesize` (KB) and infrastructure memory / timeout constraints.
|
|
286
|
+
|
|
287
|
+
## Versioning & Stability
|
|
288
|
+
|
|
289
|
+
The project follows semantic versioning principles as features mature. Prior to a formal `1.x` stability declaration, minor releases may introduce carefully documented adjustments. Pin exact versions in sensitive production environments.
|
|
290
|
+
|
|
291
|
+
## Contributing
|
|
292
|
+
|
|
293
|
+
1. Fork & create a feature branch
|
|
294
|
+
2. Add or adjust tests where behavior changes
|
|
295
|
+
3. Ensure TypeScript builds without errors
|
|
296
|
+
4. Open a PR with a concise rationale
|
|
297
|
+
|
|
298
|
+
Please avoid including sensitive implementation details in public issue titles (describe at a high level instead).
|
|
299
|
+
|
|
300
|
+
## Security Reporting
|
|
301
|
+
|
|
302
|
+
If you believe you have discovered a vulnerability, please refrain from opening a public issue. Instead contact the maintainer privately (add a SECURITY.md for formal process if publishing broadly). Provide a minimal, reproducible scenario.
|
|
303
|
+
|
|
304
|
+
## Disclaimer
|
|
305
|
+
|
|
306
|
+
securequ provides an additional obfuscation + encryption layer. It is not a substitute for robust authentication, authorization, or transport security practices. Combine with TLS, secret rotation, and standard security controls.
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
No license file included. Add one (e.g., MIT) before publishing publicly.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
Issues & contributions welcome.
|
|
314
|
+
|
package/server/Base.d.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import Router from './Router.js';
|
|
2
2
|
import { SecurequServerConfig, UploadFileMeta, HandlerInfo, ArgsInfo } from './types.js';
|
|
3
3
|
|
|
4
|
-
declare class SecurequServerBase extends Router {
|
|
5
|
-
protected config: SecurequServerConfig;
|
|
6
|
-
protected secret: string | null;
|
|
7
|
-
protected clients: Map<string, string>;
|
|
8
|
-
protected uploadMeta: Map<string, UploadFileMeta & {
|
|
9
|
-
expire: number;
|
|
10
|
-
}>;
|
|
11
|
-
constructor(config: SecurequServerConfig);
|
|
12
|
-
protected getSecret(): Promise<string>;
|
|
13
|
-
protected clientInfo(path: string, origin: string): Promise<{
|
|
14
|
-
path: string;
|
|
15
|
-
secret: string;
|
|
16
|
-
hash: string;
|
|
17
|
-
searchParams: {
|
|
18
|
-
[key: string]: any;
|
|
19
|
-
};
|
|
20
|
-
}>;
|
|
21
|
-
protected isValidSigneture(signeture: string | undefined, hash: string): Promise<void>;
|
|
22
|
-
handleRequest(info: HandlerInfo, args?: ArgsInfo): Promise<void>;
|
|
4
|
+
declare class SecurequServerBase extends Router {
|
|
5
|
+
protected config: SecurequServerConfig;
|
|
6
|
+
protected secret: string | null;
|
|
7
|
+
protected clients: Map<string, string>;
|
|
8
|
+
protected uploadMeta: Map<string, UploadFileMeta & {
|
|
9
|
+
expire: number;
|
|
10
|
+
}>;
|
|
11
|
+
constructor(config: SecurequServerConfig);
|
|
12
|
+
protected getSecret(): Promise<string>;
|
|
13
|
+
protected clientInfo(path: string, origin: string): Promise<{
|
|
14
|
+
path: string;
|
|
15
|
+
secret: string;
|
|
16
|
+
hash: string;
|
|
17
|
+
searchParams: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
protected isValidSigneture(signeture: string | undefined, hash: string): Promise<void>;
|
|
22
|
+
handleRequest(info: HandlerInfo, args?: ArgsInfo): Promise<void>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export { SecurequServerBase as default };
|
package/server/Base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\n let client = this.clients.get(origin as string) as string;\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\n if (this.config.accept) {\n const is = await this.config.accept(info, args)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, args)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params","exports","default"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\r\n\r\nclass SecurequServerBase extends Router {\r\n protected config: SecurequServerConfig;\r\n protected secret: string | null = null\r\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\r\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\r\n\r\n constructor(config: SecurequServerConfig) {\r\n super()\r\n if (!config.basepath) throw new Error(\"Basepath is required\");\r\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\r\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\r\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\r\n if (config.upload) {\r\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\r\n config.upload.checkFileType = config.upload.checkFileType || true\r\n }\r\n this.config = config\r\n for (let client of this.config.clients) {\r\n this.clients.set(client.origin, client.secret)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n if (!this.secret) {\r\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\r\n }\r\n return this.secret\r\n }\r\n\r\n protected async clientInfo(path: string, origin: string) {\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n let splitUrl = path.split(\"?\")\r\n path = splitUrl[0]\r\n path = path.replace(this.config.basepath + \"/\", \"\")\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n\r\n const split = path.split(\"/\")\r\n const hash = split.shift()\r\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\r\n let client = this.clients.get(origin as string) as string;\r\n let secret = client.substring(0, hash.length as number);\r\n let searchParams: { [key: string]: any } = {}\r\n if (splitUrl.length > 1) {\r\n if (isDev) {\r\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\r\n } else {\r\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\r\n }\r\n }\r\n return {\r\n path: \"/\" + split.join('/'),\r\n secret,\r\n hash,\r\n searchParams\r\n }\r\n }\r\n\r\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\r\n const serverSecret = await this.getSecret()\r\n if (this.secret && signeture) {\r\n let info: any = await crypto.decrypt(signeture, serverSecret)\r\n let isHashValid = info.hash === hash\r\n let isNotExpired = info.expire > Date.now()\r\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\r\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\r\n }\r\n }\r\n\r\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\r\n if (this.config.accept) {\r\n const is = await this.config.accept(info, args)\r\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\r\n }\r\n\r\n const { path, method } = info;\r\n let values: any = Object.values(this.routes[method]);\r\n for (let { test, handler } of values) {\r\n const match = test(path)\r\n if (match) {\r\n await handler({ ...info, params: match.params }, args)\r\n }\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params","exports","default"],"mappings":"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"}
|
package/server/Base.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\n let client = this.clients.get(origin as string) as string;\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\n if (this.config.accept) {\n const is = await this.config.accept(info, args)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, args)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\r\nimport Router from \"./Router\";\r\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\r\n\r\nclass SecurequServerBase extends Router {\r\n protected config: SecurequServerConfig;\r\n protected secret: string | null = null\r\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\r\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\r\n\r\n constructor(config: SecurequServerConfig) {\r\n super()\r\n if (!config.basepath) throw new Error(\"Basepath is required\");\r\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\r\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\r\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\r\n if (config.upload) {\r\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\r\n config.upload.checkFileType = config.upload.checkFileType || true\r\n }\r\n this.config = config\r\n for (let client of this.config.clients) {\r\n this.clients.set(client.origin, client.secret)\r\n }\r\n }\r\n\r\n protected async getSecret() {\r\n if (!this.secret) {\r\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\r\n }\r\n return this.secret\r\n }\r\n\r\n protected async clientInfo(path: string, origin: string) {\r\n const isDev = path !== '/' && this.config.mode === 'development'\r\n let splitUrl = path.split(\"?\")\r\n path = splitUrl[0]\r\n path = path.replace(this.config.basepath + \"/\", \"\")\r\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\r\n path = path.startsWith('/') ? path.substring(1) : path\r\n\r\n const split = path.split(\"/\")\r\n const hash = split.shift()\r\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\r\n let client = this.clients.get(origin as string) as string;\r\n let secret = client.substring(0, hash.length as number);\r\n let searchParams: { [key: string]: any } = {}\r\n if (splitUrl.length > 1) {\r\n if (isDev) {\r\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\r\n } else {\r\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\r\n }\r\n }\r\n return {\r\n path: \"/\" + split.join('/'),\r\n secret,\r\n hash,\r\n searchParams\r\n }\r\n }\r\n\r\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\r\n const serverSecret = await this.getSecret()\r\n if (this.secret && signeture) {\r\n let info: any = await crypto.decrypt(signeture, serverSecret)\r\n let isHashValid = info.hash === hash\r\n let isNotExpired = info.expire > Date.now()\r\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\r\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\r\n }\r\n }\r\n\r\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\r\n if (this.config.accept) {\r\n const is = await this.config.accept(info, args)\r\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\r\n }\r\n\r\n const { path, method } = info;\r\n let values: any = Object.values(this.routes[method]);\r\n for (let { test, handler } of values) {\r\n const match = test(path)\r\n if (match) {\r\n await handler({ ...info, params: match.params }, args)\r\n }\r\n }\r\n }\r\n\r\n}\r\n\r\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params"],"mappings":"iEAIA,MAAMA,UAA2BC,EAM9B,WAAAC,CAAYC,GAET,GADAC,QALOC,KAAAC,OAAwB,KACxBD,KAAAE,QAAU,IAAIC,IACdH,KAAAI,WAAa,IAAID,KAInBL,EAAOO,SAAU,MAAM,IAAIC,MAAM,wBACtC,IAAKR,EAAOI,SAAkD,IAAvCK,OAAOC,KAAKV,EAAOI,SAASO,OAAc,MAAM,IAAIH,MAAM,kCAC5ER,EAAOO,SAASK,WAAW,OAAMZ,EAAOO,SAAW,IAAIP,EAAOO,YAC/DP,EAAOO,SAASM,SAAS,OAAMb,EAAOO,SAAWP,EAAOO,SAASO,UAAU,EAAGd,EAAOO,SAASI,OAAS,IACvGX,EAAOe,SACRf,EAAOe,OAAOC,YAAchB,EAAOe,OAAOC,aAAe,MACzDhB,EAAOe,OAAOE,cAAgBjB,EAAOe,OAAOE,gBAAiB,GAEhEf,KAAKF,OAASA,EACd,IAAK,IAAIkB,KAAUhB,KAAKF,OAAOI,QAC5BF,KAAKE,QAAQe,IAAID,EAAOE,OAAQF,EAAOf,OAE7C,CAEU,eAAMkB,GAIb,OAHKnB,KAAKC,SACPD,KAAKC,aAAemB,EAAOC,KAAKC,KAAKC,SAASC,SAAS,IAAIZ,UAAU,EAAG,IAAMU,KAAKC,SAASC,SAAS,IAAIZ,UAAU,EAAG,MAElHZ,KAAKC,MACf,CAEU,gBAAMwB,CAAWC,EAAcR,GACtC,MAAMS,EAAiB,MAATD,GAAqC,gBAArB1B,KAAKF,OAAO8B,KAC1C,IAAIC,EAAWH,EAAKI,MAAM,KAM1B,MAAMA,GAFNJ,GADAA,GADAA,GADAA,EAAOG,EAAS,IACJE,QAAQ/B,KAAKF,OAAOO,SAAW,IAAK,KACpCM,SAAS,KAAOe,EAAKd,UAAU,EAAGc,EAAKjB,OAAS,GAAKiB,GACrDhB,WAAW,KAAOgB,EAAKd,UAAU,GAAKc,GAE/BI,MAAM,KACnBT,EAAOS,EAAME,QACnB,KAAKX,aAAI,EAAJA,EAAMZ,UAAWT,KAAKE,QAAQ+B,IAAIf,GAAS,MAAM,IAAIgB,SAAS,qBAAsB,CAAEC,OAAQ,MACnG,IACIlC,EADSD,KAAKE,QAAQkC,IAAIlB,GACVN,UAAU,EAAGS,EAAKZ,QAClC4B,EAAuC,CAAA,EAQ3C,OAPIR,EAASpB,OAAS,IAEhB4B,EADCV,EACcpB,OAAO+B,YAAY,IAAIC,gBAAgBC,mBAAmBX,EAAS,YAE7DT,EAAOqB,QAAQD,mBAAmBX,EAAS,IAAK5B,IAGpE,CACJyB,KAAM,IAAMI,EAAMY,KAAK,KACvBzC,SACAoB,OACAgB,eAEN,CAEU,sBAAMM,CAAiBC,EAA+BvB,GAC7D,MAAMwB,QAAqB7C,KAAKmB,YAChC,GAAInB,KAAKC,QAAU2C,EAAW,CAC3B,IAAIE,QAAkB1B,EAAOqB,QAAQG,EAAWC,GAC5CE,EAAcD,EAAKzB,OAASA,EAC5B2B,EAAeF,EAAKG,OAASC,KAAKC,MACtC,IAAKJ,EAAa,MAAM,IAAIb,SAAS,oBAAqB,CAAEC,OAAQ,MACpE,IAAKa,EAAc,MAAM,IAAId,SAAS,oBAAqB,CAAEC,OAAQ,KACvE,CACJ,CAEA,mBAAMiB,CAAcN,EAAmBO,GACpC,GAAIrD,KAAKF,OAAOwD,OAAQ,CAErB,UADiBtD,KAAKF,OAAOwD,OAAOR,EAAMO,GACjC,MAAM,IAAInB,SAAS,uBAAwB,CAAEC,OAAQ,KAChE,CAED,MAAMT,KAAEA,EAAI6B,OAAEA,GAAWT,EACzB,IAAIU,EAAcjD,OAAOiD,OAAOxD,KAAKyD,OAAOF,IAC5C,IAAK,IAAIG,KAAEA,EAAIC,QAAEA,KAAaH,EAAQ,CACnC,MAAMI,EAAQF,EAAKhC,GACfkC,SACKD,EAAOpD,OAAAsD,OAAAtD,OAAAsD,OAAA,CAAA,EAAMf,GAAI,CAAEgB,OAAQF,EAAME,SAAUT,EAEtD,CACJ,SAEF1D"}
|
package/server/Router.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HTTPMethods } from '../client/types.js';
|
|
2
|
+
import { RouteFactory, HandlerFunction } from './types.js';
|
|
2
3
|
|
|
3
|
-
declare class Router {
|
|
4
|
-
protected routes: RouteFactory;
|
|
5
|
-
addRoute(path: string, method: HTTPMethods, handler: HandlerFunction): Promise<void>;
|
|
6
|
-
get(path: string, handler: HandlerFunction): Promise<void>;
|
|
7
|
-
post(path: string, handler: HandlerFunction): Promise<void>;
|
|
8
|
-
put(path: string, handler: HandlerFunction): Promise<void>;
|
|
9
|
-
delete(path: string, handler: HandlerFunction): Promise<void>;
|
|
4
|
+
declare class Router {
|
|
5
|
+
protected routes: RouteFactory;
|
|
6
|
+
addRoute(path: string, method: HTTPMethods, handler: HandlerFunction): Promise<void>;
|
|
7
|
+
get(path: string, handler: HandlerFunction): Promise<void>;
|
|
8
|
+
post(path: string, handler: HandlerFunction): Promise<void>;
|
|
9
|
+
put(path: string, handler: HandlerFunction): Promise<void>;
|
|
10
|
+
delete(path: string, handler: HandlerFunction): Promise<void>;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export { Router as default };
|
package/server/Router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.js","sources":["../../src/server/Router.ts"],"sourcesContent":["import { HandlerFunction,
|
|
1
|
+
{"version":3,"file":"Router.js","sources":["../../src/server/Router.ts"],"sourcesContent":["import { HTTPMethods } from \"../client/types\";\r\nimport { HandlerFunction, RouteFactory } from \"./types\"\r\nimport { match } from \"path-to-regexp\";\r\n\r\nclass Router {\r\n protected routes: RouteFactory = {\r\n GET: {},\r\n POST: {},\r\n PUT: {},\r\n DELETE: {}\r\n };\r\n\r\n async addRoute(path: string, method: HTTPMethods, handler: HandlerFunction) {\r\n if (this.routes[method][path]) return\r\n this.routes[method][path] = {\r\n handler,\r\n test: match(path)\r\n }\r\n }\r\n\r\n async get(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'GET', handler)\r\n }\r\n\r\n async post(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'POST', handler)\r\n }\r\n\r\n async put(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'PUT', handler)\r\n }\r\n\r\n async delete(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'DELETE', handler)\r\n }\r\n}\r\n\r\nexport default Router;"],"names":["Object","defineProperty","exports","value","pathToRegexp","require","default","constructor","this","routes","GET","POST","PUT","DELETE","addRoute","path","method","handler","test","match","get","post","put"],"mappings":"AAIA,aAAAA,OAAAC,eAAAC,QAAA,aAAA,CAAAC,OAAA,IAAA,IAAAC,EAAAC,QAAA,kBA+BCH,QAAAI,QA/BD,MAAA,WAAAC,GACaC,KAAAC,OAAuB,CAC9BC,IAAK,CAAA,EACLC,KAAM,CAAA,EACNC,IAAK,CAAA,EACLC,OAAQ,CAAA,EA0Bd,CAvBG,cAAMC,CAASC,EAAcC,EAAqBC,GAC3CT,KAAKC,OAAOO,GAAQD,KACxBP,KAAKC,OAAOO,GAAQD,GAAQ,CACzBE,UACAC,KAAMC,EAAAA,MAAMJ,IAElB,CAEA,SAAMK,CAAIL,EAAcE,GACrBT,KAAKM,SAASC,EAAM,MAAOE,EAC9B,CAEA,UAAMI,CAAKN,EAAcE,GACtBT,KAAKM,SAASC,EAAM,OAAQE,EAC/B,CAEA,SAAMK,CAAIP,EAAcE,GACrBT,KAAKM,SAASC,EAAM,MAAOE,EAC9B,CAEA,YAAM,CAAOF,EAAcE,GACxBT,KAAKM,SAASC,EAAM,SAAUE,EACjC"}
|
package/server/Router.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.mjs","sources":["../../src/server/Router.ts"],"sourcesContent":["import { HandlerFunction,
|
|
1
|
+
{"version":3,"file":"Router.mjs","sources":["../../src/server/Router.ts"],"sourcesContent":["import { HTTPMethods } from \"../client/types\";\r\nimport { HandlerFunction, RouteFactory } from \"./types\"\r\nimport { match } from \"path-to-regexp\";\r\n\r\nclass Router {\r\n protected routes: RouteFactory = {\r\n GET: {},\r\n POST: {},\r\n PUT: {},\r\n DELETE: {}\r\n };\r\n\r\n async addRoute(path: string, method: HTTPMethods, handler: HandlerFunction) {\r\n if (this.routes[method][path]) return\r\n this.routes[method][path] = {\r\n handler,\r\n test: match(path)\r\n }\r\n }\r\n\r\n async get(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'GET', handler)\r\n }\r\n\r\n async post(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'POST', handler)\r\n }\r\n\r\n async put(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'PUT', handler)\r\n }\r\n\r\n async delete(path: string, handler: HandlerFunction) {\r\n this.addRoute(path, 'DELETE', handler)\r\n }\r\n}\r\n\r\nexport default Router;"],"names":["match","Router","constructor","this","routes","GET","POST","PUT","DELETE","addRoute","path","method","handler","test","get","post","put"],"mappings":"gBAIAA,MAAA,iBAAA,MAAMC,EAAN,WAAAC,GACaC,KAAAC,OAAuB,CAC9BC,IAAK,CAAA,EACLC,KAAM,CAAA,EACNC,IAAK,CAAA,EACLC,OAAQ,CAAA,EA0Bd,CAvBG,cAAMC,CAASC,EAAcC,EAAqBC,GAC3CT,KAAKC,OAAOO,GAAQD,KACxBP,KAAKC,OAAOO,GAAQD,GAAQ,CACzBE,UACAC,KAAMb,EAAMU,IAElB,CAEA,SAAMI,CAAIJ,EAAcE,GACrBT,KAAKM,SAASC,EAAM,MAAOE,EAC9B,CAEA,UAAMG,CAAKL,EAAcE,GACtBT,KAAKM,SAASC,EAAM,OAAQE,EAC/B,CAEA,SAAMI,CAAIN,EAAcE,GACrBT,KAAKM,SAASC,EAAM,MAAOE,EAC9B,CAEA,YAAM,CAAOF,EAAcE,GACxBT,KAAKM,SAASC,EAAM,SAAUE,EACjC,SACFX"}
|