@arikajs/encryption 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ArikaJs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ ## Arika Encryption
2
+
3
+ `@arikajs/encryption` provides secure, application-level encryption for the ArikaJS framework.
4
+
5
+ It is responsible for encrypting and decrypting sensitive data such as sessions, cookies, signed payloads, and internal framework values β€” similar in spirit to Laravel’s `Illuminate\Encryption`.
6
+
7
+ This package is framework-agnostic at runtime, but designed to integrate seamlessly with `@arikajs/foundation` via service providers.
8
+
9
+ ---
10
+
11
+ ## ✨ Features
12
+
13
+ - πŸ” **AES-256-GCM encryption** (modern & secure)
14
+ - πŸ”‘ **Single application key** (`APP_KEY`)
15
+ - 🧾 **Authenticated encryption** (tamper detection)
16
+ - πŸ”„ **Encrypt / decrypt strings & JSON**
17
+ - 🧠 **Stateless design** (safe for queues & workers)
18
+ - 🧩 **Framework service friendly**
19
+ - 🟦 **TypeScript-first**
20
+
21
+ ---
22
+
23
+ ## πŸ“¦ Installation
24
+
25
+ ```bash
26
+ npm install @arikajs/encryption
27
+ # or
28
+ yarn add @arikajs/encryption
29
+ # or
30
+ pnpm add @arikajs/encryption
31
+ ```
32
+
33
+ ---
34
+
35
+ ## πŸ”‘ Application Key (Required)
36
+
37
+ This package requires an application key, usually provided via:
38
+
39
+ ```ini
40
+ APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
41
+ ```
42
+
43
+ > **Note:** The key must be 32 bytes, Base64-encoded.
44
+ > You can generate one using:
45
+ > `arika key:generate`
46
+
47
+ ---
48
+
49
+ ## πŸš€ Basic Usage (Standalone)
50
+
51
+ ```ts
52
+ import { Encrypter } from '@arikajs/encryption';
53
+
54
+ const encrypter = new Encrypter('base64:your-app-key');
55
+
56
+ const encrypted = encrypter.encrypt('secret data');
57
+ const decrypted = encrypter.decrypt(encrypted);
58
+
59
+ console.log(decrypted); // "secret data"
60
+ ```
61
+
62
+ ### πŸ“¦ Encrypting Objects / JSON
63
+
64
+ ```ts
65
+ const payload = {
66
+ userId: 1,
67
+ role: 'admin',
68
+ };
69
+
70
+ const token = encrypter.encrypt(payload);
71
+
72
+ const data = encrypter.decrypt(token);
73
+ // { userId: 1, role: 'admin' }
74
+ ```
75
+
76
+ Internally, objects are JSON-serialized automatically.
77
+
78
+ ---
79
+
80
+ ## 🧠 Integration with ArikaJS
81
+
82
+ ### Register as a service (via Foundation)
83
+
84
+ ```ts
85
+ import { Encrypter } from '@arikajs/encryption';
86
+
87
+ this.app.singleton('encrypter', () => {
88
+ const key = config('app.key');
89
+
90
+ if (!key) {
91
+ throw new Error('APP_KEY is not defined.');
92
+ }
93
+
94
+ return new Encrypter(key);
95
+ });
96
+ ```
97
+
98
+ ### Usage anywhere in the app
99
+
100
+ ```ts
101
+ const encrypter = app.make<Encrypter>('encrypter');
102
+
103
+ const value = encrypter.encrypt('hello');
104
+ ```
105
+
106
+ ---
107
+
108
+ ## πŸ”’ Security Guarantees
109
+
110
+ - Uses **AES-256-GCM**
111
+ - Every payload includes:
112
+ - Random IV (Initialization Vector)
113
+ - Authentication tag
114
+ - Any tampering β†’ automatic decryption failure
115
+ - No weak or legacy algorithms
116
+ - If data is modified, `decrypt()` will throw.
117
+
118
+ ---
119
+
120
+ ## 🧩 Intended Consumers
121
+
122
+ This package is a core dependency for:
123
+
124
+ | Package | Usage |
125
+ | :--- | :--- |
126
+ | `@arikajs/session` | Encrypted sessions |
127
+ | `@arikajs/http` | Encrypted cookies |
128
+ | `@arikajs/queue` | Secure job payloads |
129
+ | `@arikajs/auth` | Token encryption |
130
+ | `@arikajs/mail` | Signed mail data |
131
+
132
+ ---
133
+
134
+ ## 🧠 API Reference
135
+
136
+ ### `new Encrypter(key: string)`
137
+ Creates a new encrypter instance.
138
+
139
+ ### `encrypt(value: string | object): string`
140
+ Encrypts a value and returns a string payload.
141
+
142
+ ### `decrypt(payload: string): any`
143
+ Decrypts a payload and returns the original value.
144
+
145
+ Throws if:
146
+ - Payload is invalid
147
+ - Payload is tampered
148
+ - Key is incorrect
149
+
150
+ ---
151
+
152
+ ## πŸ— Architecture
153
+
154
+ ```
155
+ encryption/
156
+ β”œβ”€β”€ src/
157
+ β”‚ β”œβ”€β”€ Encrypter.ts
158
+ β”‚ β”œβ”€β”€ Contracts/
159
+ β”‚ β”‚ └── Encrypter.ts
160
+ β”‚ β”œβ”€β”€ Exceptions/
161
+ β”‚ β”‚ └── DecryptionException.ts
162
+ β”‚ └── index.ts
163
+ β”œβ”€β”€ tests/
164
+ β”œβ”€β”€ package.json
165
+ β”œβ”€β”€ tsconfig.json
166
+ β”œβ”€β”€ README.md
167
+ └── LICENSE
168
+ ```
169
+
170
+ ---
171
+
172
+ ## 🚧 Planned (v1.x+)
173
+
174
+ - πŸ”„ Key rotation support
175
+ - πŸ§ͺ Encrypted payload versioning
176
+ - πŸ”‘ Multiple key support (fallback decryption)
177
+ - 🧷 Signed-only (non-encrypted) payloads
178
+
179
+ ---
180
+
181
+ ## 🧭 Philosophy
182
+
183
+ > "Encryption should be invisible, mandatory, and impossible to misuse."
184
+
185
+ This package:
186
+ - Enforces strong defaults
187
+ - Centralizes cryptography
188
+ - Avoids configuration sprawl
189
+ - Keeps security boring and safe
190
+
191
+ ---
192
+
193
+ ## πŸ“„ License
194
+
195
+ `@arikajs/encryption` is open-source software licensed under the **MIT License**.
@@ -0,0 +1,10 @@
1
+ export interface Encrypter {
2
+ /**
3
+ * Encrypt the given value.
4
+ */
5
+ encrypt(value: any): string;
6
+ /**
7
+ * Decrypt the given value.
8
+ */
9
+ decrypt(payload: string): any;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,26 @@
1
+ import { Encrypter as EncrypterContract } from './Contracts/Encrypter';
2
+ export declare class Encrypter implements EncrypterContract {
3
+ private readonly key;
4
+ private readonly cipher;
5
+ constructor(key: string);
6
+ /**
7
+ * Parse the encryption key.
8
+ */
9
+ protected parseKey(key: string): Buffer;
10
+ /**
11
+ * Encrypt the given value.
12
+ */
13
+ encrypt(value: any): string;
14
+ /**
15
+ * Decrypt the given value.
16
+ */
17
+ decrypt(payload: string): any;
18
+ /**
19
+ * Get the JSON payload from the given string.
20
+ */
21
+ protected getJsonPayload(payload: string): any;
22
+ /**
23
+ * Verify that the encryption payload is valid.
24
+ */
25
+ protected validPayload(payload: any): boolean;
26
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Encrypter = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const DecryptionException_1 = require("./Exceptions/DecryptionException");
6
+ class Encrypter {
7
+ key;
8
+ cipher = 'aes-256-gcm';
9
+ constructor(key) {
10
+ this.key = this.parseKey(key);
11
+ if (this.key.length !== 32) {
12
+ throw new Error('The encryption key must be 32 bytes.');
13
+ }
14
+ }
15
+ /**
16
+ * Parse the encryption key.
17
+ */
18
+ parseKey(key) {
19
+ if (key.startsWith('base64:')) {
20
+ return Buffer.from(key.substring(7), 'base64');
21
+ }
22
+ return Buffer.from(key);
23
+ }
24
+ /**
25
+ * Encrypt the given value.
26
+ */
27
+ encrypt(value) {
28
+ const iv = (0, crypto_1.randomBytes)(16);
29
+ const cipher = (0, crypto_1.createCipheriv)(this.cipher, this.key, iv);
30
+ const jsonValue = JSON.stringify(value);
31
+ let encrypted = cipher.update(jsonValue, 'utf8', 'base64');
32
+ encrypted += cipher.final('base64');
33
+ const tag = cipher.getAuthTag();
34
+ const payload = {
35
+ iv: iv.toString('base64'),
36
+ value: encrypted,
37
+ tag: tag.toString('base64'),
38
+ };
39
+ return Buffer.from(JSON.stringify(payload)).toString('base64');
40
+ }
41
+ /**
42
+ * Decrypt the given value.
43
+ */
44
+ decrypt(payload) {
45
+ const jsonPayload = this.getJsonPayload(payload);
46
+ const iv = Buffer.from(jsonPayload.iv, 'base64');
47
+ const tag = Buffer.from(jsonPayload.tag, 'base64');
48
+ const value = jsonPayload.value;
49
+ try {
50
+ const decipher = (0, crypto_1.createDecipheriv)(this.cipher, this.key, iv);
51
+ decipher.setAuthTag(tag);
52
+ let decrypted = decipher.update(value, 'base64', 'utf8');
53
+ decrypted += decipher.final('utf8');
54
+ return JSON.parse(decrypted);
55
+ }
56
+ catch (error) {
57
+ throw new DecryptionException_1.DecryptionException();
58
+ }
59
+ }
60
+ /**
61
+ * Get the JSON payload from the given string.
62
+ */
63
+ getJsonPayload(payload) {
64
+ try {
65
+ const decoded = Buffer.from(payload, 'base64').toString('utf8');
66
+ const data = JSON.parse(decoded);
67
+ if (!this.validPayload(data)) {
68
+ throw new DecryptionException_1.DecryptionException();
69
+ }
70
+ return data;
71
+ }
72
+ catch (error) {
73
+ throw new DecryptionException_1.DecryptionException();
74
+ }
75
+ }
76
+ /**
77
+ * Verify that the encryption payload is valid.
78
+ */
79
+ validPayload(payload) {
80
+ return typeof payload === 'object' &&
81
+ payload !== null &&
82
+ payload.iv &&
83
+ payload.value &&
84
+ payload.tag;
85
+ }
86
+ }
87
+ exports.Encrypter = Encrypter;
@@ -0,0 +1,3 @@
1
+ export declare class DecryptionException extends Error {
2
+ constructor(message?: string);
3
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DecryptionException = void 0;
4
+ class DecryptionException extends Error {
5
+ constructor(message = 'The payload is invalid or has been tampered with.') {
6
+ super(message);
7
+ this.name = 'DecryptionException';
8
+ }
9
+ }
10
+ exports.DecryptionException = DecryptionException;
@@ -0,0 +1,3 @@
1
+ export { Encrypter } from './Encrypter';
2
+ export { Encrypter as EncrypterContract } from './Contracts/Encrypter';
3
+ export * from './Exceptions/DecryptionException';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.Encrypter = void 0;
18
+ var Encrypter_1 = require("./Encrypter");
19
+ Object.defineProperty(exports, "Encrypter", { enumerable: true, get: function () { return Encrypter_1.Encrypter; } });
20
+ __exportStar(require("./Exceptions/DecryptionException"), exports);
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@arikajs/encryption",
3
+ "version": "0.0.1",
4
+ "description": "Secure, application-level encryption for the ArikaJS framework.",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc -p tsconfig.json",
10
+ "clean": "rm -rf dist",
11
+ "prepare": "echo skip"
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20.0.0"
18
+ },
19
+ "dependencies": {},
20
+ "devDependencies": {
21
+ "@types/node": "^20.11.24",
22
+ "typescript": "^5.3.3"
23
+ },
24
+ "author": "Prakash Tank"
25
+ }