Skip to content

Commit 3b79c24

Browse files
authored
Merge pull request #108 from cipherstash/docs/restructure-for-better-first-nav
docs: make getting started easier to follow
2 parents 9a4ccea + 649e503 commit 3b79c24

3 files changed

Lines changed: 318 additions & 44 deletions

File tree

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
The documentation for Protect.js is organized into the following sections:
44

5-
- [Getting started](../README.md)
5+
- [Getting started](./getting-started.md)
66

77
## Concepts
88

docs/getting-started.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
## Getting started
2+
3+
This getting started guide steps you through:
4+
5+
- Installing and configuring Protect.js in a standalone project
6+
- Encrypting, searching, and decrypting data in a PostgreSQL database
7+
8+
> [!IMPORTANT]
9+
> **Prerequisites:** Before you start you need to have this software installed:
10+
> - [Node.js](https://nodejs.org/)
11+
> - [TypeScript](https://www.typescriptlang.org/)
12+
> - [PostgreSQL](https://www.postgresql.org/) — see PostgreSQL's [documentation for installing](https://www.postgresql.org/download/)
13+
14+
### Step 0: Basic file structure
15+
16+
This is the basic file structure of the standalone project for this getting started guide.
17+
In the `src/protect/` directory, we have table definition in `schema.ts` and the Protect.js client in `index.ts`.
18+
19+
```
20+
📦 <project root>
21+
├ 📂 src
22+
│ ├ 📂 protect
23+
│ │ ├ 📜 index.ts
24+
│ │ └ 📜 schema.ts
25+
│ └ 📜 index.ts
26+
├ 📜 .env
27+
├ 📜 cipherstash.toml
28+
├ 📜 cipherstash.secret.toml
29+
├ 📜 package.json
30+
└ 📜 tsconfig.json
31+
```
32+
33+
If you are following this getting started guide with an existing app, you can skip to [the next step](#step-1-install-protectjs).
34+
35+
If you are following this getting started guide with a clean slate, create a basic structure by running:
36+
37+
```bash
38+
mkdir -p protect-example/src/protect
39+
cd protect-example
40+
git init
41+
npm init -y
42+
```
43+
44+
## Step 1: Install Protect.js
45+
46+
Install the [`@cipherstash/protect` package](https://www.npmjs.com/package/@cipherstash/protect) with your package manager of choice:
47+
48+
```bash
49+
npm install @cipherstash/protect
50+
# or
51+
yarn add @cipherstash/protect
52+
# or
53+
pnpm add @cipherstash/protect
54+
```
55+
56+
> [!TIP]
57+
> [Bun](https://bun.sh/) is not currently supported due to a lack of [Node-API compatibility](https://github.com/oven-sh/bun/issues/158). Under the hood, Protect.js uses [CipherStash Client](#cipherstash-client) which is written in Rust and embedded using [Neon](https://github.com/neon-bindings/neon).
58+
59+
Lastly, install the CipherStash CLI:
60+
61+
- On macOS:
62+
63+
```bash
64+
brew install cipherstash/tap/stash
65+
```
66+
67+
- On Linux, download the binary for your platform, and put it on your `PATH`:
68+
- [Linux ARM64](https://github.com/cipherstash/cli-releases/releases/latest/download/stash-aarch64-unknown-linux-gnu)
69+
- [Linux x86_64](https://github.com/cipherstash/cli-releases/releases/latest/download/stash-x86_64-unknown-linux-gnu)
70+
71+
> [!NOTE]
72+
> **You need to opt-out of bundling when using Protect.js.**
73+
>
74+
> Protect.js uses Node.js specific features and requires the use of the [native Node.js `require`](https://nodejs.org/api/modules.html#requireid).
75+
>
76+
> You need to opt-out of bundling for tools like [Webpack](https://webpack.js.org/configuration/externals/), [esbuild](https://webpack.js.org/configuration/externals/), or [Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/serverExternalPackages).
77+
>
78+
> Read more about [building and bundling with Protect.js](#builds-and-bundling).
79+
80+
### Step 2: Setup credentials
81+
82+
> [!IMPORTANT]
83+
> Make sure you have [installed the CipherStash CLI](#step-1-install-protectjs) before following these steps.
84+
85+
To set up all the configuration and credentials required for Protect.js:
86+
87+
```bash
88+
stash setup
89+
```
90+
91+
If you haven't already signed up for a CipherStash account, this will prompt you to do so along the way.
92+
93+
At the end of `stash setup`, you will have two files in your project:
94+
95+
- `cipherstash.toml` which contains the configuration for Protect.js
96+
- `cipherstash.secret.toml`: which contains the credentials for Protect.js
97+
98+
> [!WARNING]
99+
> Don't commit `cipherstash.secret.toml` to git; it contains sensitive credentials.
100+
> The `stash setup` command will append to your `.gitignore` file with the `cipherstash.secret.toml` file.
101+
102+
Read more about [configuration via TOML file or environment variables](./docs/reference/configuration.md).
103+
104+
### Step 3: Define your schema
105+
106+
Protect.js uses a schema to define the tables and columns that you want to encrypt and decrypt.
107+
108+
Define your tables and columns by adding this to `src/protect/schema.ts`:
109+
110+
```ts
111+
import { csTable, csColumn } from '@cipherstash/protect'
112+
113+
export const users = csTable('users', {
114+
email: csColumn('email'),
115+
})
116+
117+
export const orders = csTable('orders', {
118+
address: csColumn('address'),
119+
})
120+
```
121+
122+
**Searchable encryption:**
123+
124+
If you want to search encrypted data in your PostgreSQL database, you must declare the indexes in schema in `src/protect/schema.ts`:
125+
126+
```ts
127+
import { csTable, csColumn } from '@cipherstash/protect'
128+
129+
export const users = csTable('users', {
130+
email: csColumn('email').freeTextSearch().equality().orderAndRange(),
131+
})
132+
133+
export const orders = csTable('orders', {
134+
address: csColumn('address'),
135+
})
136+
```
137+
138+
Read more about [defining your schema](./docs/reference/schema.md).
139+
140+
### Step 4: Initialize the Protect client
141+
142+
Import the `protect` function and initialize a client with your defined schema, by adding this to `src/protect/index.ts`:
143+
144+
```ts
145+
import { protect } from '@cipherstash/protect'
146+
import { users } from './schema'
147+
148+
// Pass all your tables to the protect function to initialize the client
149+
export const protectClient = await protect(users, orders)
150+
```
151+
152+
The `protect` function requires at least one `csTable` be provided.
153+
154+
### Step 5: Encrypt data
155+
156+
Protect.js provides the `encrypt` function on `protectClient` to encrypt data.
157+
`encrypt` takes a plaintext string, and an object with the table and column as parameters.
158+
159+
Start encrypting data by adding this to `src/index.ts`:
160+
161+
```typescript
162+
import { users } from './protect/schema'
163+
import { protectClient } from './protect'
164+
165+
const encryptResult = await protectClient.encrypt('secret@squirrel.example', {
166+
column: users.email,
167+
table: users,
168+
})
169+
170+
if (encryptResult.failure) {
171+
// Handle the failure
172+
console.log("error when encrypting:", encryptResult.failure.type, encryptResult.failure.message)
173+
}
174+
175+
const ciphertext = encryptResult.data
176+
console.log("ciphertext:", ciphertext)
177+
```
178+
179+
Run this with:
180+
181+
```bash
182+
npx tsx src/index.ts
183+
```
184+
185+
The `encrypt` function will return a `Result` object with either a `data` key, or a `failure` key.
186+
The `encryptResult` will return one of the following:
187+
188+
```typescript
189+
// Success
190+
{
191+
data: {
192+
c: '\\\\\\\\\\\\\\\\x61202020202020472aaf602219d48c4a...'
193+
}
194+
}
195+
196+
// Failure
197+
{
198+
failure: {
199+
type: 'EncryptionError',
200+
message: 'A message about the error'
201+
}
202+
}
203+
```
204+
205+
> [!TIP]
206+
> Get significantly better encryption performance by using the [`bulkEncrypt` function](#bulk-encrypting-data) for large payloads.
207+
208+
### Step 6: Decrypt data
209+
210+
Use the `decrypt` function to decrypt data.
211+
`decrypt` takes an encrypted data object as a parameter.
212+
213+
```typescript
214+
import { protectClient } from './protect'
215+
216+
const decryptResult = await protectClient.decrypt(ciphertext)
217+
218+
if (decryptResult.failure) {
219+
// Handle the failure
220+
}
221+
222+
const plaintext = decryptResult.data
223+
```
224+
225+
The `decrypt` function returns a `Result` object with either a `data` key, or a `failure` key.
226+
The `decryptResult` will return one of the following:
227+
228+
```typescript
229+
// Success
230+
{
231+
data: 'secret@squirrel.example'
232+
}
233+
234+
// Failure
235+
{
236+
failure: {
237+
type: 'DecryptionError',
238+
message: 'A message about the error'
239+
}
240+
}
241+
```
242+
243+
> [!TIP]
244+
> Get significantly better decryption performance by using the [`bulkDecrypt` function](#bulk-decrypting-data) for large payloads.
245+
246+
### Step 7: Store encrypted data in a database
247+
248+
Encrypted data can be stored in any database that supports JSONB.
249+
250+
To store the encrypted data, you will need to specify the column type as `jsonb`:
251+
252+
```sql
253+
CREATE TABLE users (
254+
id SERIAL PRIMARY KEY,
255+
email jsonb NOT NULL,
256+
);
257+
```

0 commit comments

Comments
 (0)