zurik 1.0.0

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/.gitencrypt ADDED
File without changes
package/bin/zurik.js ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ import encryptFiles from "../lib/encrypt.js";
4
+ import decryptFiles from "../lib/decrypt.js";
5
+
6
+ const args = process.argv.slice(2);
7
+
8
+ function extractPassword() {
9
+ const pIndex = args.indexOf("-p");
10
+ if (pIndex !== -1 && args[pIndex + 1]) {
11
+ return args[pIndex + 1];
12
+ }
13
+ return process.env.ZURIK_PASSWORD || null;
14
+ }
15
+
16
+
17
+ async function run() {
18
+ const password = extractPassword();
19
+ if (!password) {
20
+ console.error("Missing password. Use -p <password> or set ZURIK_PASSWORD environment variable.");
21
+ process.exit(1);
22
+ }
23
+
24
+ if (args.includes("-e")) {
25
+ await encryptFiles(password);
26
+ return;
27
+ }
28
+
29
+ if (args.includes("-d")) {
30
+ await decryptFiles(password);
31
+ return;
32
+ }
33
+
34
+ console.log("Usage:");
35
+ console.log(" npx zurik -e [-p password] Encrypt");
36
+ console.log(" npx zurik -d [-p password] Decrypt");
37
+ }
38
+
39
+ run().catch(err => {
40
+ console.error(err.message);
41
+ process.exit(1);
42
+ });
package/lib/crypto.js ADDED
@@ -0,0 +1,41 @@
1
+ import crypto from "crypto";
2
+
3
+ const ALGO = "aes-256-gcm";
4
+ const IV_LENGTH = 16;
5
+
6
+ function deriveKey(password) {
7
+ return new Promise((resolve, reject) => {
8
+ crypto.scrypt(password, "zurik_fixed_salt", 32, (err, key) => {
9
+ if (err) reject(err);
10
+ else resolve(key);
11
+ });
12
+ });
13
+ }
14
+
15
+ export async function encryptData(data, password) {
16
+ const key = await deriveKey(password);
17
+ const iv = crypto.randomBytes(IV_LENGTH);
18
+ const cipher = crypto.createCipheriv(ALGO, key, iv);
19
+
20
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
21
+ const tag = cipher.getAuthTag();
22
+
23
+ return Buffer.concat([iv, tag, encrypted]).toString("base64");
24
+ }
25
+
26
+ export async function decryptData(base64, password) {
27
+ const buffer = Buffer.from(base64, "base64");
28
+
29
+ const iv = buffer.subarray(0, 16);
30
+ const tag = buffer.subarray(16, 32);
31
+ const ciphertext = buffer.subarray(32);
32
+
33
+ const key = await deriveKey(password);
34
+ const decipher = crypto.createDecipheriv(ALGO, key, iv);
35
+ decipher.setAuthTag(tag);
36
+
37
+ return Buffer.concat([
38
+ decipher.update(ciphertext),
39
+ decipher.final()
40
+ ]);
41
+ }
package/lib/decrypt.js ADDED
@@ -0,0 +1,19 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { decryptData } from "./crypto.js";
4
+
5
+ export default async function decryptFiles(password) {
6
+ if (!fs.existsSync(".zurik")) {
7
+ throw new Error(".zurik not found");
8
+ }
9
+
10
+ const blob = fs.readFileSync(".zurik", "utf8");
11
+ const jsonStr = await decryptData(blob, password);
12
+ const data = JSON.parse(jsonStr);
13
+
14
+ for (const [filePath, base64] of Object.entries(data.files)) {
15
+ const buffer = Buffer.from(base64, "base64");
16
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
17
+ fs.writeFileSync(filePath, buffer);
18
+ }
19
+ }
package/lib/encrypt.js ADDED
@@ -0,0 +1,47 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { encryptData } from "./crypto.js";
4
+
5
+ export default async function encryptFiles(password) {
6
+ const listFile = ".gitencrypt";
7
+
8
+ if (!fs.existsSync(listFile)) {
9
+ throw new Error(".gitencrypt not found");
10
+ }
11
+
12
+ const fileList = fs
13
+ .readFileSync(listFile, "utf8")
14
+ .split("\n")
15
+ .map(x => x.trim())
16
+ .filter(Boolean);
17
+
18
+ const bundle = { version: 1, files: {} };
19
+
20
+ for (const filePath of fileList) {
21
+ if (!fs.existsSync(filePath)) {
22
+ console.warn(`Skipping missing file: ${filePath}`);
23
+ continue;
24
+ }
25
+
26
+ const content = fs.readFileSync(filePath);
27
+ bundle.files[filePath] = content.toString("base64");
28
+ }
29
+
30
+ const encrypted = await encryptData(JSON.stringify(bundle), password);
31
+ fs.writeFileSync(".zurik", encrypted);
32
+
33
+ updateGitignore(fileList);
34
+ }
35
+
36
+ function updateGitignore(fileList) {
37
+ const gi = ".gitignore";
38
+ let text = fs.existsSync(gi) ? fs.readFileSync(gi, "utf8") : "";
39
+
40
+ for (const file of fileList) {
41
+ if (!text.includes(file)) {
42
+ text += `\n${file}`;
43
+ }
44
+ }
45
+
46
+ fs.writeFileSync(gi, text.trim() + "\n");
47
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "zurik",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for encrypting and decrypting sensitive project files into a single .zurik bundle.",
5
+ "type": "module",
6
+ "bin": {
7
+ "zurik": "./bin/zurik.js"
8
+ },
9
+ "keywords": [
10
+ "encryption",
11
+ "cli",
12
+ "security",
13
+ "aes",
14
+ "gcm",
15
+ "git",
16
+ "files"
17
+ ],
18
+ "author": "",
19
+ "license": "MIT",
20
+ "dependencies": {}
21
+ }
package/readme.md ADDED
@@ -0,0 +1,25 @@
1
+ # zurik
2
+
3
+ A Node.js CLI tool for encrypting and decrypting sensitive project files.
4
+ It collects file paths from `.gitencrypt`, bundles them into a single `.zurik` file, and decrypts them when needed.
5
+
6
+ ## Features
7
+
8
+ - Encrypt multiple files into a **single** `.zurik` bundle
9
+ - AES-256-GCM authenticated encryption
10
+ - Automatically append sensitive files to `.gitignore` when encrypting.
11
+
12
+ ## Installation
13
+
14
+ You can run it directly using `npx`:
15
+
16
+ ```sh
17
+ export ZURIK_PASSWORD="your-secret"
18
+ npx zurik -e
19
+
20
+ # or install it globally
21
+ npm install -g zurik
22
+
23
+ # also you can pass the password as an argument
24
+ npx zurik -e -p "your-password"
25
+ ```
Binary file