Skip to content

Commit afc5fa1

Browse files
authored
Merge pull request #47 from cipherstash/docs/readme-improvements
2 parents c3da3d7 + 24bbfe1 commit afc5fa1

1 file changed

Lines changed: 89 additions & 72 deletions

File tree

README.md

Lines changed: 89 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
[![Package Tests](https://github.com/cipherstash/jseql/actions/workflows/tests.yaml/badge.svg)](https://github.com/cipherstash/jseql/actions/workflows/tests.yaml)
44
[![Built by CipherStash](https://raw.githubusercontent.com/cipherstash/meta/refs/heads/main/csbadge.svg)](https://cipherstash.com)
55

6-
`jseql` is a JavaScript/TypeScript package designed to facilitate interaction with [Encrypt Query Language (EQL)](https://github.com/cipherstash/encrypt-query-language). It provides classes and methods to encrypt and decrypt data.
6+
`jseql` is a JavaScript/TypeScript package for encrypting and decrypting data in PostgreSQL databases.
7+
Encryption operations happen directly in your app, and the ciphertext is stored in your PostgreSQL database.
8+
9+
Every value you encrypt with `jseql` has a unique key, made possible by CipherStash [ZeroKMS](https://cipherstash.com/products/zerokms)'s blazing fast bulk key operations.
10+
Under the hood `jseql` uses CipherStash [Encrypt Query Language (EQL)](https://github.com/cipherstash/encrypt-query-language), and all ZeroKMS data keys are backed by a root key in [AWS KMS](https://docs.aws.amazon.com/kms/latest/developerguide/overview.html).
711

812
## Table of Contents
913

@@ -21,20 +25,16 @@
2125
`jseql` leverages [Encrypt Query Language (EQL)](https://github.com/cipherstash/encrypt-query-language) and [CipherStash](https://cipherstash.com) to encrypt data in a PostgreSQL database.
2226

2327
**Features:**
24-
- **Data encryption**: Easily encrypt data with industry standard encryption algorithms, like AES-256.
25-
CipherStash also uses a unique encryption key for every record in the database, this is also know as **field level encryption.**
26-
- **Data decryption**: Decrypt encrypted data easily directly in your application.
27-
- **Lock context**: "Lock" the encryption and decryption operations based on user identity.
28-
This allows you to ensure that only the intended users can access sensitive data.
29-
- **Bulk encryption and decryption**: Encrypt and decrypt multiple records at once using a unique data key per record.
30-
Compared to something like AWS KMS, this is much more efficient, secure, and scalable.
28+
- **Bulk encryption and decryption**: `jseql` uses [ZeroKMS](https://cipherstash.com/products/zerokms) for encrypting and decrypting thousands of records at once, while using a unique key for every value.
29+
- **Single item encryption and decryption**: Just looking for a way to encrypt and decrypt single values? `jseql` has you covered.
30+
- **Really fast:** ZeroKMS's performance makes using millions of unique keys feasible and performant for real-world applications built with `jseql`.
31+
- **Identity-aware encryption**: Lock down access to sensitive data by requiring a valid JWT to perform a decryption.
3132
- **TypeScript support**: Strongly typed with TypeScript interfaces and types.
3233

3334
**Use cases:**
34-
- Meet compliance requirements for data encryption in your application.
35-
- Ensure only the intended users can access sensitive data.
36-
- Exceed customer expectations for data security.
37-
- Improve your overall security posture and reduce the risk of data breaches.
35+
- **Trusted data access**: make sure only your end-users can access their sensitive data stored in your product.
36+
- **Meet compliance requirements faster:** achieve and exceed the data encryption requirements of SOC2 and ISO27001.
37+
- **Reduce the blast radius of data breaches:** limit the impact of exploited vulnerabilities to only the data your end-users can decrypt.
3838

3939
## Installation
4040

@@ -58,14 +58,16 @@ pnpm add @cipherstash/jseql
5858

5959
### Node.js
6060

61-
Jseql actively supports all current and [maintenance releases of Node](https://github.com/nodejs/LTS#release-schedule). If you're
62-
using a different version of Node and believe it should be supported, let us know.
61+
`jseql` actively supports all current and [maintenance releases of Node](https://github.com/nodejs/LTS#release-schedule).
62+
If you're using a different version of Node and believe it should be supported, let us know.
6363

64-
Older Node version support (minimum v10) may require lower Node-API versions. See the Node [version support matrix](https://nodejs.org/api/n-api.html#node-api-version-matrix) for more details.
64+
Older Node version support (minimum v10) may require lower Node-API versions.
65+
See the Node [version support matrix](https://nodejs.org/api/n-api.html#node-api-version-matrix) for more details.
6566

6667
### Bun (experimental)
6768

68-
[Bun](https://bun.sh/) is an alternate JavaScript runtime that targets Node compatibility. At the time of this writing, some Node-API functions are [not implemented](https://github.com/oven-sh/bun/issues/158) so Jseql may not work with Bun.
69+
[Bun](https://bun.sh/) is an alternate JavaScript runtime that targets Node compatibility.
70+
At the time of this writing, some Node-API functions are [not implemented](https://github.com/oven-sh/bun/issues/158) so `jseql` may not work with Bun.
6971

7072
## Usage
7173

@@ -117,7 +119,8 @@ const eqlClient = await eql()
117119

118120
### Encrypting data
119121

120-
To encrypt data, use the `encrypt` function. This function takes a plaintext string and an object with the table and column name as parameters.
122+
To encrypt data, use the `encrypt` function.
123+
This function takes a plaintext string and an object with the table and column name as parameters.
121124

122125
```typescript
123126
const ciphertext = await eqlClient.encrypt('plaintext', {
@@ -136,7 +139,8 @@ The `encrypt` function returns an object with a `c` key, and the value is the en
136139

137140
### Decrypting data
138141

139-
To decrypt data, use the `decrypt` function. This function takes an encrypted data object and an object with the lock context as parameters.
142+
To decrypt data, use the `decrypt` function.
143+
This function takes an encrypted data object and an object with the lock context as parameters.
140144

141145
```typescript
142146
const plaintext = await eqlClient.decrypt(ciphertext)
@@ -174,6 +178,16 @@ The `jwt_token_from_identiti_provider` is the JWT token from your identity provi
174178

175179
If you're using [Clerk](https://clerk.com/) as your identity provider, you can use the `jseqlClerkMiddleware` function to automatically set the CTS token for every user session.
176180

181+
Install the `@cipherstash/nextjs` package:
182+
183+
```bash
184+
npm install @cipherstash/nextjs
185+
# or
186+
yarn add @cipherstash/nextjs
187+
# or
188+
pnpm add @cipherstash/nextjs
189+
```
190+
177191
In your `middleware.ts` file, add the following code:
178192

179193
```typescript
@@ -247,7 +261,7 @@ const plaintext = await eqlClient.decrypt(ciphertext, {
247261

248262
### Storing encrypted data in a database
249263

250-
To store the encrypted data in PostgreSQL, you will need to specify the column type as `jsonb`. At the time of this writing.
264+
To store the encrypted data in PostgreSQL, you will need to specify the column type as `jsonb`.
251265

252266
```sql
253267
CREATE TABLE users (
@@ -257,10 +271,10 @@ CREATE TABLE users (
257271
);
258272
```
259273

260-
### Buld Encryption/Decryption
274+
### Bulk Encryption/Decryption
261275

262276
If you have a large list of items to encrypt or decrypt, you can use the **`bulkEncrypt`** and **`bulkDecrypt`** methods to batch encryption/decryption.
263-
These methods are more efficient and perform better than the single-item encryption/decryption methods.
277+
`bulkEncrypt` and `bulkDecrypt` give your app significantly better throughput than the single-item `encrypt` / `decrypt` methods.
264278

265279
#### bulkEncrypt
266280

@@ -274,34 +288,34 @@ const encryptedResults = await eqlClient.bulkEncrypt(plaintextsToEncrypt, {
274288

275289
**Parameters**
276290

277-
1. **`plaintexts`**
278-
- **Type**: `{ plaintext: string; id: string }[]`
279-
- **Description**:
280-
An array of objects containing the **plaintext** and an **id**.
281-
- **plaintext**: The string you want encrypted.
291+
1. **`plaintexts`**
292+
- **Type**: `{ plaintext: string; id: string }[]`
293+
- **Description**:
294+
An array of objects containing the **plaintext** and an **id**.
295+
- **plaintext**: The string you want encrypted.
282296
- **id**: A unique identifier you can use to map the returned ciphertext back to its source. For example, if you have a `User` with `id: 1`, you might pass `id: '1'`.
283297

284-
2. **`column`**
285-
- **Type**: `string`
286-
- **Description**:
298+
2. **`column`**
299+
- **Type**: `string`
300+
- **Description**:
287301
The name of the column you’re encrypting (e.g., "email"). This is typically used in logging or contextual purposes when constructing the payload for the encryption engine.
288302

289-
3. **`table`**
290-
- **Type**: `string`
291-
- **Description**:
303+
3. **`table`**
304+
- **Type**: `string`
305+
- **Description**:
292306
The name of the table you’re encrypting data in (e.g., "Users").
293307

294-
4. **`lockContext`** (optional)
295-
- **Type**: `LockContext`
296-
- **Description**:
308+
4. **`lockContext`** (optional)
309+
- **Type**: `LockContext`
310+
- **Description**:
297311
Additional metadata and tokens for secure encryption/decryption. If not provided, encryption proceeds without a lock context.
298312

299313
### Return Value
300314

301-
- **Type**: `Promise<Array<{ c: string; id: string }> | null>`
302-
- Returns an array of objects, where:
303-
- **`c`** is the ciphertext.
304-
- **`id`** is the same **id** you passed in, so you can correlate which ciphertext matches which original plaintext.
315+
- **Type**: `Promise<Array<{ c: string; id: string }> | null>`
316+
- Returns an array of objects, where:
317+
- **`c`** is the ciphertext.
318+
- **`id`** is the same **id** you passed in, so you can correlate which ciphertext matches which original plaintext.
305319
- If `plaintexts` is an empty array, it returns `null`.
306320

307321
### Example Usage
@@ -354,22 +368,22 @@ const decryptedResults = await eqlClient.bulkDecrypt(encryptedPayloads, {
354368

355369
**Parameters**
356370

357-
1. **`encryptedPayloads`**
358-
- **Type**: `Array<{ c: string; id: string }> | null`
359-
- **Description**:
371+
1. **`encryptedPayloads`**
372+
- **Type**: `Array<{ c: string; id: string }> | null`
373+
- **Description**:
360374
An array of objects containing the **ciphertext** (`c`) and the **id**. If this array is empty or `null`, the function returns `null`.
361375

362-
2. **`lockContext`** (optional)
363-
- **Type**: `LockContext`
364-
- **Description**:
376+
2. **`lockContext`** (optional)
377+
- **Type**: `LockContext`
378+
- **Description**:
365379
Additional metadata used to securely unlock ciphertext. If not provided, decryption proceeds without it.
366380

367381
### Return Value
368382

369-
- **Type**: `Promise<Array<{ plaintext: string; id: string }> | null>`
370-
- Returns an array of objects, where:
371-
- **`plaintext`** is the decrypted value.
372-
- **`id`** is the same **id** you passed in, so you can correlate which plaintext matches which original ciphertext.
383+
- **Type**: `Promise<Array<{ plaintext: string; id: string }> | null>`
384+
- Returns an array of objects, where:
385+
- **`plaintext`** is the decrypted value.
386+
- **`id`** is the same **id** you passed in, so you can correlate which plaintext matches which original ciphertext.
373387
- Returns `null` if the provided `encryptedPayloads` is empty or `null`.
374388

375389
### Example Usage
@@ -409,17 +423,20 @@ if (decryptedResults) {
409423
}
410424
```
411425

412-
## Searchable encrypted data
426+
## Searchable encryption
413427

414428
`jseql` does not currently support searching encrypted data.
415-
We are hard at work on this feature and will update this section when it is available.
416-
You can read more about this feature and implementation [here](https://github.com/cipherstash/encrypt-query-language).
429+
Searchable encryption is an extremely well supported capability in other CipherStash products, and will be coming to `jseql`.
430+
Until searchable encryption support is released in `jseql`, you can:
431+
432+
- Read [about how searchable encryption works in EQL](https://github.com/cipherstash/encrypt-query-language)
433+
- Vote for this feature by adding a :+1: on this [GitHub Issue](https://github.com/cipherstash/jseql/issues/46).
417434

418435
## Logging
419436

420437
> [!IMPORTANT]
421-
> `jseql` will NEVER log plaintext data.
422-
> This is by design to prevent sensitive data from being logged.
438+
> `jseql` will NEVER log plaintext data.
439+
> This is by design to prevent sensitive data from leaking into logs.
423440
424441
`@cipherstash/jseql` and `@cipherstash/nextjs` will log to the console with a log level of `info` by default.
425442
You can enable the logger by configuring the following environment variable:
@@ -436,35 +453,35 @@ JSEQL_LOG_LEVEL=error # Enable error logging
436453
- [Drizzle example](/apps/drizzle)
437454
- [Next.js, Drizzle, and Clerk example](https://github.com/cipherstash/jseql-next-drizzle)
438455

439-
`jseql` can be used with most ORMs that support PostgreSQL. If you're interested in using `jseql` with a specific ORM, please [create an issue](https://github.com/cipherstash/jseql/issues/new).
456+
`jseql` can be used with most ORMs that support PostgreSQL.
457+
If you're interested in using `jseql` with a specific ORM, please [create an issue](https://github.com/cipherstash/jseql/issues/new).
440458

441459
## CipherStash Client
442460

443461
`@cipherstash/jseql` is built on top of the CipherStash Client Rust SDK which is integrated with the `@cipherstash/jseql-ffi` package.
444-
At the time of this writing, the `@cipherstash/jseql-ffi` package is public, but the source code is not yet available.
462+
The `@cipherstash/jseql-ffi` package is [public on NPM](https://www.npmjs.com/package/@cipherstash/jseql-ffi), and the source code will be released on GitHub.
445463

446-
The Cipherstash Client is configured by environment variables, which are used to initialize the client when the `eql` function is called.
447-
Below are the available environment variables:
464+
The Cipherstash Client is configured by environment variables, which are used to initialize the client when the `eql` function is called:
448465

449-
| Variable Name | Description | Required | Default |
450-
| --- | --- | --- | --- |
451-
| CS_CLIENT_ID | The client ID for your CipherStash account. | Yes | |
452-
| CS_CLIENT_KEY | The client key for your CipherStash account. | Yes | |
453-
| CS_WORKSPACE_ID | The workspace ID for your CipherStash account. | Yes | |
454-
| CS_CLIENT_ACCESS_KEY | The access key for your CipherStash account. | Yes | |
455-
| CS_ZEROKMS_HOST | The host for the ZeroKMS server. | No | https://ap-southeast-2.aws.viturhosted.net |
456-
| CS_CONFIG_PATH | A temporary path to store the CipherStash client configuration. | No | /home/{username}/.cipherstash |
466+
| Variable Name | Description | Required | Default |
467+
|:----------------------:|:---------------------------------------------------------------:|:--------:|:--------------------------------------------:|
468+
| `CS_CLIENT_ID` | The client ID for your CipherStash account. | Yes | |
469+
| `CS_CLIENT_KEY` | The client key for your CipherStash account. | Yes | |
470+
| `CS_WORKSPACE_ID` | The workspace ID for your CipherStash account. | Yes | |
471+
| `CS_CLIENT_ACCESS_KEY` | The access key for your CipherStash account. | Yes | |
472+
| `CS_ZEROKMS_HOST` | The host for the ZeroKMS server. | No | `https://ap-southeast-2.aws.viturhosted.net` |
473+
| `CS_CONFIG_PATH` | A temporary path to store the CipherStash client configuration. | No | `/home/{username}/.cipherstash` |
457474

458-
Important notes:
475+
> [!TIP]
476+
> There are some configuration details you should take note of when deploying `jseql` in your production apps.
459477
460-
- If you've created a Workspace in a region other than `ap-southeast-2`, you will need to set the `CS_ZEROKMS_HOST` environment variable to the appropriate region. E.g. `https://<region>.aws.viturhosted.net`
461-
- In most hosting environments, the `CS_CONFIG_PATH` environment variable will need to be set to a path that is accessible by the user running the application.
462-
`/tmp/.cipherstash` will work in most cases, and has been tested on [Vercel](https://vercel.com/), [AWS Lambda](https://aws.amazon.com/lambda/), and other hosting environments.
478+
- If you've created a Workspace in a region other than `ap-southeast-2`, you will need to set the `CS_ZEROKMS_HOST` environment variable to the appropriate region. For example, if you are using ZeroKMS in the `eu-central-1` region, you need to set the `CS_ZEROKMS_HOST` variable to `https://eu-central-1.aws.viturhosted.net`. This is a known usability issue that will be addressed.
479+
- In most hosting environments, the `CS_CONFIG_PATH` environment variable will need to be set to a path that the user running the application has permission to write to. Setting `CS_CONFIG_PATH` to `/tmp/.cipherstash` will work in most cases, and has been tested on [Vercel](https://vercel.com/), [AWS Lambda](https://aws.amazon.com/lambda/), and other hosting environments.
463480

464481
## Contributing
465482

466-
Please see the [CONTRIBUTE.md](CONTRIBUTE.md) file for more information.
483+
Please read the [contribution guide](CONTRIBUTE.md).
467484

468485
## License
469486

470-
Please see the [LICENSE](LICENSE.md) file for more information.
487+
`jseql` is [MIT licensed](./LICENSE.md).

0 commit comments

Comments
 (0)