You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@djangocfg/crypto

Package Overview
Dependencies
Maintainers
1
Versions
120
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@djangocfg/crypto - npm Package Compare versions

Comparing version
2.1.235
to
2.1.236
+2
-2
package.json
{
"name": "@djangocfg/crypto",
"version": "2.1.235",
"version": "2.1.236",
"description": "Client-side AES-256-GCM decryption for Django-CFG encrypted API responses using Web Crypto API",

@@ -69,3 +69,3 @@ "keywords": [

"devDependencies": {
"@djangocfg/typescript-config": "^2.1.235",
"@djangocfg/typescript-config": "^2.1.236",
"@types/node": "^24.7.2",

@@ -72,0 +72,0 @@ "@types/react": "^19.1.0",

"use client";
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/react/index.ts
var react_exports = {};
__export(react_exports, {
useDecrypt: () => useDecrypt,
useDecryptionClient: () => useDecryptionClient,
useIsEncrypted: () => useIsEncrypted,
useLazyDecrypt: () => useLazyDecrypt
});
module.exports = __toCommonJS(react_exports);
// src/react/hooks.ts
var import_react = require("react");
// src/key-derivation.ts
async function deriveKey(password, salt, iterations = 1e5, keyLength = 32) {
const encoder = new TextEncoder();
const passwordBuffer = encoder.encode(password);
const keyMaterial = await crypto.subtle.importKey(
"raw",
passwordBuffer,
"PBKDF2",
false,
["deriveBits", "deriveKey"]
);
return crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt.buffer,
iterations,
hash: "SHA-256"
},
keyMaterial,
{ name: "AES-GCM", length: keyLength * 8 },
false,
["decrypt"]
);
}
__name(deriveKey, "deriveKey");
async function buildSalt(keyPrefix = "djangocfg_encryption", userId, sessionId) {
const parts = [keyPrefix];
if (sessionId) {
parts.push(`session:${sessionId}`);
} else if (userId !== void 0) {
parts.push(`user:${userId}`);
} else {
parts.push("global");
}
const saltInput = parts.join(":");
const encoder = new TextEncoder();
const inputBuffer = encoder.encode(saltInput);
const hashBuffer = await crypto.subtle.digest("SHA-256", inputBuffer);
return new Uint8Array(hashBuffer).slice(0, 16);
}
__name(buildSalt, "buildSalt");
async function deriveKeyFromConfig(config) {
const {
secretKey,
userId,
sessionId,
iterations = 1e5,
keyPrefix = "djangocfg_encryption"
} = config;
const salt = await buildSalt(keyPrefix, userId, sessionId);
return deriveKey(secretKey, salt, iterations);
}
__name(deriveKeyFromConfig, "deriveKeyFromConfig");
// src/types.ts
function isEncryptedField(value) {
if (typeof value !== "object" || value === null) return false;
const obj = value;
return obj.encrypted === true && typeof obj.algorithm === "string" && typeof obj.iv === "string" && typeof obj.data === "string" && typeof obj.auth_tag === "string";
}
__name(isEncryptedField, "isEncryptedField");
function isEncryptedResponse(value) {
if (typeof value !== "object" || value === null) return false;
const obj = value;
return obj.encrypted === true && typeof obj.algorithm === "string" && typeof obj.salt === "string" && typeof obj.iv === "string" && typeof obj.data === "string" && typeof obj.auth_tag === "string";
}
__name(isEncryptedResponse, "isEncryptedResponse");
// src/decryption.ts
function base64ToBytes(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
__name(base64ToBytes, "base64ToBytes");
async function decryptAES256GCM(ciphertext, key, iv, authTag) {
const combined = new Uint8Array(ciphertext.length + authTag.length);
combined.set(ciphertext);
combined.set(authTag, ciphertext.length);
const decrypted = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv.buffer,
tagLength: 128
// 16 bytes = 128 bits
},
key,
combined
);
return new Uint8Array(decrypted);
}
__name(decryptAES256GCM, "decryptAES256GCM");
async function decryptField(field, key) {
if (field.algorithm !== "AES-256-GCM") {
throw new Error(`Unsupported algorithm: ${field.algorithm}`);
}
const iv = base64ToBytes(field.iv);
const ciphertext = base64ToBytes(field.data);
const authTag = base64ToBytes(field.auth_tag);
const decrypted = await decryptAES256GCM(ciphertext, key, iv, authTag);
const text = new TextDecoder().decode(decrypted);
return JSON.parse(text);
}
__name(decryptField, "decryptField");
async function decryptObject(data, key) {
if (data === null || data === void 0) {
return data;
}
if (isEncryptedField(data)) {
return decryptField(data, key);
}
if (Array.isArray(data)) {
const decrypted = await Promise.all(
data.map((item) => decryptObject(item, key))
);
return decrypted;
}
if (typeof data === "object") {
const result = {};
const entries = Object.entries(data);
for (const [objKey, value] of entries) {
result[objKey] = await decryptObject(value, key);
}
return result;
}
return data;
}
__name(decryptObject, "decryptObject");
async function createDecryptionClient(config) {
const key = await deriveKeyFromConfig(config);
return {
/**
* Decrypt a single encrypted field.
*/
decryptField: /* @__PURE__ */ __name((field) => decryptField(field, key), "decryptField"),
/**
* Recursively decrypt all encrypted fields in an object.
*/
decryptObject: /* @__PURE__ */ __name((data) => decryptObject(data, key), "decryptObject"),
/**
* Check if a value is an encrypted field.
*/
isEncryptedField,
/**
* Check if a value is an encrypted response.
*/
isEncryptedResponse
};
}
__name(createDecryptionClient, "createDecryptionClient");
// src/react/hooks.ts
function useDecrypt(encryptedData, config) {
const [state, setState] = (0, import_react.useState)({
data: void 0,
isLoading: true,
error: void 0,
isDecrypted: false
});
const keyRef = (0, import_react.useRef)(null);
const configRef = (0, import_react.useRef)(config);
const configChanged = configRef.current.secretKey !== config.secretKey || configRef.current.userId !== config.userId || configRef.current.sessionId !== config.sessionId;
if (configChanged) {
configRef.current = config;
keyRef.current = null;
}
(0, import_react.useEffect)(() => {
let cancelled = false;
async function decrypt() {
try {
setState((s) => ({ ...s, isLoading: true, error: void 0 }));
if (!keyRef.current) {
keyRef.current = await deriveKeyFromConfig(config);
}
const decrypted = await decryptObject(encryptedData, keyRef.current);
if (!cancelled) {
setState({
data: decrypted,
isLoading: false,
error: void 0,
isDecrypted: true
});
}
} catch (err) {
if (!cancelled) {
setState({
data: void 0,
isLoading: false,
error: err instanceof Error ? err : new Error("Decryption failed"),
isDecrypted: false
});
}
}
}
__name(decrypt, "decrypt");
decrypt();
return () => {
cancelled = true;
};
}, [encryptedData, config.secretKey, config.userId, config.sessionId]);
return state;
}
__name(useDecrypt, "useDecrypt");
function useDecryptionClient(config) {
const [client, setClient] = (0, import_react.useState)(null);
(0, import_react.useEffect)(() => {
createDecryptionClient(config).then(setClient);
}, [config.secretKey, config.userId, config.sessionId]);
return client;
}
__name(useDecryptionClient, "useDecryptionClient");
function useLazyDecrypt(config) {
const [state, setState] = (0, import_react.useState)({
data: void 0,
isLoading: false,
error: void 0,
isDecrypted: false
});
const keyRef = (0, import_react.useRef)(null);
const decrypt = (0, import_react.useCallback)(
async (encryptedData) => {
try {
setState((s) => ({ ...s, isLoading: true, error: void 0 }));
if (!keyRef.current) {
keyRef.current = await deriveKeyFromConfig(config);
}
const decrypted = await decryptObject(encryptedData, keyRef.current);
setState({
data: decrypted,
isLoading: false,
error: void 0,
isDecrypted: true
});
return decrypted;
} catch (err) {
const error = err instanceof Error ? err : new Error("Decryption failed");
setState({
data: void 0,
isLoading: false,
error,
isDecrypted: false
});
return void 0;
}
},
[config.secretKey, config.userId, config.sessionId]
);
const reset = (0, import_react.useCallback)(() => {
setState({
data: void 0,
isLoading: false,
error: void 0,
isDecrypted: false
});
}, []);
return { ...state, decrypt, reset };
}
__name(useLazyDecrypt, "useLazyDecrypt");
function useIsEncrypted(value) {
return (0, import_react.useMemo)(() => isEncryptedField(value), [value]);
}
__name(useIsEncrypted, "useIsEncrypted");
//# sourceMappingURL=react.cjs.map
"use client";
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/react/hooks.ts
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
// src/key-derivation.ts
async function deriveKey(password, salt, iterations = 1e5, keyLength = 32) {
const encoder = new TextEncoder();
const passwordBuffer = encoder.encode(password);
const keyMaterial = await crypto.subtle.importKey(
"raw",
passwordBuffer,
"PBKDF2",
false,
["deriveBits", "deriveKey"]
);
return crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt.buffer,
iterations,
hash: "SHA-256"
},
keyMaterial,
{ name: "AES-GCM", length: keyLength * 8 },
false,
["decrypt"]
);
}
__name(deriveKey, "deriveKey");
async function buildSalt(keyPrefix = "djangocfg_encryption", userId, sessionId) {
const parts = [keyPrefix];
if (sessionId) {
parts.push(`session:${sessionId}`);
} else if (userId !== void 0) {
parts.push(`user:${userId}`);
} else {
parts.push("global");
}
const saltInput = parts.join(":");
const encoder = new TextEncoder();
const inputBuffer = encoder.encode(saltInput);
const hashBuffer = await crypto.subtle.digest("SHA-256", inputBuffer);
return new Uint8Array(hashBuffer).slice(0, 16);
}
__name(buildSalt, "buildSalt");
async function deriveKeyFromConfig(config) {
const {
secretKey,
userId,
sessionId,
iterations = 1e5,
keyPrefix = "djangocfg_encryption"
} = config;
const salt = await buildSalt(keyPrefix, userId, sessionId);
return deriveKey(secretKey, salt, iterations);
}
__name(deriveKeyFromConfig, "deriveKeyFromConfig");
// src/types.ts
function isEncryptedField(value) {
if (typeof value !== "object" || value === null) return false;
const obj = value;
return obj.encrypted === true && typeof obj.algorithm === "string" && typeof obj.iv === "string" && typeof obj.data === "string" && typeof obj.auth_tag === "string";
}
__name(isEncryptedField, "isEncryptedField");
function isEncryptedResponse(value) {
if (typeof value !== "object" || value === null) return false;
const obj = value;
return obj.encrypted === true && typeof obj.algorithm === "string" && typeof obj.salt === "string" && typeof obj.iv === "string" && typeof obj.data === "string" && typeof obj.auth_tag === "string";
}
__name(isEncryptedResponse, "isEncryptedResponse");
// src/decryption.ts
function base64ToBytes(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
__name(base64ToBytes, "base64ToBytes");
async function decryptAES256GCM(ciphertext, key, iv, authTag) {
const combined = new Uint8Array(ciphertext.length + authTag.length);
combined.set(ciphertext);
combined.set(authTag, ciphertext.length);
const decrypted = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv.buffer,
tagLength: 128
// 16 bytes = 128 bits
},
key,
combined
);
return new Uint8Array(decrypted);
}
__name(decryptAES256GCM, "decryptAES256GCM");
async function decryptField(field, key) {
if (field.algorithm !== "AES-256-GCM") {
throw new Error(`Unsupported algorithm: ${field.algorithm}`);
}
const iv = base64ToBytes(field.iv);
const ciphertext = base64ToBytes(field.data);
const authTag = base64ToBytes(field.auth_tag);
const decrypted = await decryptAES256GCM(ciphertext, key, iv, authTag);
const text = new TextDecoder().decode(decrypted);
return JSON.parse(text);
}
__name(decryptField, "decryptField");
async function decryptObject(data, key) {
if (data === null || data === void 0) {
return data;
}
if (isEncryptedField(data)) {
return decryptField(data, key);
}
if (Array.isArray(data)) {
const decrypted = await Promise.all(
data.map((item) => decryptObject(item, key))
);
return decrypted;
}
if (typeof data === "object") {
const result = {};
const entries = Object.entries(data);
for (const [objKey, value] of entries) {
result[objKey] = await decryptObject(value, key);
}
return result;
}
return data;
}
__name(decryptObject, "decryptObject");
async function createDecryptionClient(config) {
const key = await deriveKeyFromConfig(config);
return {
/**
* Decrypt a single encrypted field.
*/
decryptField: /* @__PURE__ */ __name((field) => decryptField(field, key), "decryptField"),
/**
* Recursively decrypt all encrypted fields in an object.
*/
decryptObject: /* @__PURE__ */ __name((data) => decryptObject(data, key), "decryptObject"),
/**
* Check if a value is an encrypted field.
*/
isEncryptedField,
/**
* Check if a value is an encrypted response.
*/
isEncryptedResponse
};
}
__name(createDecryptionClient, "createDecryptionClient");
// src/react/hooks.ts
function useDecrypt(encryptedData, config) {
const [state, setState] = useState({
data: void 0,
isLoading: true,
error: void 0,
isDecrypted: false
});
const keyRef = useRef(null);
const configRef = useRef(config);
const configChanged = configRef.current.secretKey !== config.secretKey || configRef.current.userId !== config.userId || configRef.current.sessionId !== config.sessionId;
if (configChanged) {
configRef.current = config;
keyRef.current = null;
}
useEffect(() => {
let cancelled = false;
async function decrypt() {
try {
setState((s) => ({ ...s, isLoading: true, error: void 0 }));
if (!keyRef.current) {
keyRef.current = await deriveKeyFromConfig(config);
}
const decrypted = await decryptObject(encryptedData, keyRef.current);
if (!cancelled) {
setState({
data: decrypted,
isLoading: false,
error: void 0,
isDecrypted: true
});
}
} catch (err) {
if (!cancelled) {
setState({
data: void 0,
isLoading: false,
error: err instanceof Error ? err : new Error("Decryption failed"),
isDecrypted: false
});
}
}
}
__name(decrypt, "decrypt");
decrypt();
return () => {
cancelled = true;
};
}, [encryptedData, config.secretKey, config.userId, config.sessionId]);
return state;
}
__name(useDecrypt, "useDecrypt");
function useDecryptionClient(config) {
const [client, setClient] = useState(null);
useEffect(() => {
createDecryptionClient(config).then(setClient);
}, [config.secretKey, config.userId, config.sessionId]);
return client;
}
__name(useDecryptionClient, "useDecryptionClient");
function useLazyDecrypt(config) {
const [state, setState] = useState({
data: void 0,
isLoading: false,
error: void 0,
isDecrypted: false
});
const keyRef = useRef(null);
const decrypt = useCallback(
async (encryptedData) => {
try {
setState((s) => ({ ...s, isLoading: true, error: void 0 }));
if (!keyRef.current) {
keyRef.current = await deriveKeyFromConfig(config);
}
const decrypted = await decryptObject(encryptedData, keyRef.current);
setState({
data: decrypted,
isLoading: false,
error: void 0,
isDecrypted: true
});
return decrypted;
} catch (err) {
const error = err instanceof Error ? err : new Error("Decryption failed");
setState({
data: void 0,
isLoading: false,
error,
isDecrypted: false
});
return void 0;
}
},
[config.secretKey, config.userId, config.sessionId]
);
const reset = useCallback(() => {
setState({
data: void 0,
isLoading: false,
error: void 0,
isDecrypted: false
});
}, []);
return { ...state, decrypt, reset };
}
__name(useLazyDecrypt, "useLazyDecrypt");
function useIsEncrypted(value) {
return useMemo(() => isEncryptedField(value), [value]);
}
__name(useIsEncrypted, "useIsEncrypted");
export {
useDecrypt,
useDecryptionClient,
useIsEncrypted,
useLazyDecrypt
};
//# sourceMappingURL=react.mjs.map