-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
examples: add encryption example. (#2117)
- Loading branch information
Showing
22 changed files
with
675 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
module.exports = { | ||
env: { | ||
browser: true, | ||
es2021: true, | ||
node: true, | ||
}, | ||
extends: [ | ||
`eslint:recommended`, | ||
`plugin:@typescript-eslint/recommended`, | ||
`plugin:prettier/recommended`, | ||
], | ||
parserOptions: { | ||
ecmaVersion: 2022, | ||
requireConfigFile: false, | ||
sourceType: `module`, | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
}, | ||
parser: `@typescript-eslint/parser`, | ||
plugins: [`prettier`], | ||
rules: { | ||
quotes: [`error`, `single`], | ||
"no-unused-vars": `off`, | ||
"@typescript-eslint/no-unused-vars": [ | ||
`error`, | ||
{ | ||
argsIgnorePattern: `^_`, | ||
varsIgnorePattern: `^_`, | ||
caughtErrorsIgnorePattern: `^_`, | ||
}, | ||
], | ||
}, | ||
ignorePatterns: [ | ||
`**/node_modules/**`, | ||
`**/dist/**`, | ||
`tsup.config.ts`, | ||
`vitest.config.ts`, | ||
`.eslintrc.js`, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist | ||
.env.local |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"semi": false, | ||
"singleQuote": true, | ||
"tabWidth": 2, | ||
"trailingComma": "es5" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
|
||
# Encryption example | ||
|
||
This is an example of encryption with Electric. It's a React app with a very simple Express API server. | ||
|
||
The Electric-specific code is in [`./src/Example.tsx`](./src/Example.tsx). It demonstrates: | ||
|
||
- encrypting data before sending to the API server | ||
- decrypting data after it syncs in through Electric | ||
|
||
## Setup | ||
|
||
This example is part of the [ElectricSQL monorepo](../..) and is designed to be built and run as part of the [pnpm workspace](https://pnpm.io/workspaces) defined in [`../../pnpm-workspace.yaml`](../../pnpm-workspace.yaml). | ||
|
||
Navigate to the root directory of the monorepo, e.g.: | ||
|
||
```shell | ||
cd ../../ | ||
``` | ||
|
||
Install and build all of the workspace packages and examples: | ||
|
||
```shell | ||
pnpm install | ||
pnpm run -r build | ||
``` | ||
|
||
Navigate back to this directory: | ||
|
||
```shell | ||
cd examples/basic-example | ||
``` | ||
|
||
Start the example backend services using [Docker Compose](https://docs.docker.com/compose/): | ||
|
||
```shell | ||
pnpm backend:up | ||
``` | ||
|
||
Now start the dev server: | ||
|
||
```shell | ||
pnpm dev | ||
``` | ||
|
||
Open [localhost:5173]http://localhost:5173] in your web browser. When you add items, the plaintext is encrypted before it leaves the app. You can see the ciphertext in Postgres, e.g.: | ||
|
||
```console | ||
$ psql "postgresql://postgres:password@localhost:54321/electric" | ||
psql (16.4) | ||
Type "help" for help. | ||
|
||
electric=# select * from items; | ||
id | ciphertext | iv | ||
--------------------------------------+------------------------------+------------------ | ||
491b2654-5714-48bb-a206-59f87a2dc33c | vDwv3IX5AGXJVi2jNJJDPE25MwiS | 0gwdqHvqiJ8lJqaS | ||
(1 row) | ||
``` | ||
|
||
When you're done, stop the backend services using: | ||
|
||
```shell | ||
pnpm backend:down | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import bodyParser from 'body-parser' | ||
import cors from 'cors' | ||
import express from 'express' | ||
import pg from 'pg' | ||
|
||
import { z } from 'zod' | ||
|
||
// Connect to Postgres. | ||
const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://postgres:password@localhost:54321/electric' | ||
const DATABASE_USE_SSL = process.env.DATABASE_USE_SSL === 'true' || false | ||
const pool = new pg.Pool({connectionString: DATABASE_URL, ssl: DATABASE_USE_SSL}) | ||
const db = await pool.connect() | ||
|
||
// Expose an HTTP server. | ||
const PORT = parseInt(process.env.PORT || '3001') | ||
const app = express() | ||
app.use(bodyParser.json()) | ||
app.use(cors()) | ||
|
||
// Validate user input | ||
const createSchema = z.object({ | ||
id: z.string().uuid(), | ||
ciphertext: z.string(), | ||
iv: z.string() | ||
}) | ||
|
||
// Expose `POST {data} /items`. | ||
app.post(`/items`, async (req, res) => { | ||
let data | ||
try { | ||
data = createSchema.parse(req.body) | ||
} | ||
catch (err) { | ||
return res.status(400).json({ errors: err.errors }) | ||
} | ||
|
||
// Insert the item into the database. | ||
const sql = ` | ||
INSERT INTO items ( | ||
id, | ||
ciphertext, | ||
iv | ||
) | ||
VALUES ( | ||
$1, | ||
$2, | ||
$3 | ||
) | ||
` | ||
|
||
const params = [ | ||
data.id, | ||
data.ciphertext, | ||
data.iv | ||
] | ||
|
||
try { | ||
await db.query(sql, params) | ||
} | ||
catch (err) { | ||
return res.status(500).json({ errors: err }) | ||
} | ||
|
||
return res.status(200).json({ status: 'OK' }) | ||
}) | ||
|
||
// Start the server | ||
app.listen(PORT, () => { | ||
console.log(`Server listening at http://localhost:${PORT}`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
CREATE TABLE IF NOT EXISTS items ( | ||
id UUID PRIMARY KEY NOT NULL, | ||
ciphertext TEXT NOT NULL, | ||
iv TEXT NOT NULL | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Web Example - ElectricSQL</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "@electric-examples/encryption", | ||
"private": true, | ||
"version": "0.0.1", | ||
"author": "ElectricSQL", | ||
"license": "Apache-2.0", | ||
"type": "module", | ||
"scripts": { | ||
"backend:up": "PROJECT_NAME=basic-example pnpm -C ../../ run example-backend:up && pnpm db:migrate", | ||
"backend:down": "PROJECT_NAME=basic-example pnpm -C ../../ run example-backend:down", | ||
"db:migrate": "dotenv -e ../../.env.dev -- pnpm exec pg-migrations apply --directory ./db/migrations", | ||
"dev": "concurrently \"vite\" \"node backend/api.js\"", | ||
"build": "vite build", | ||
"format": "eslint . --ext ts,tsx --fix", | ||
"stylecheck": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview", | ||
"typecheck": "tsc --noEmit" | ||
}, | ||
"dependencies": { | ||
"@electric-sql/react": "workspace:*", | ||
"base64-js": "^1.5.1", | ||
"body-parser": "^1.20.2", | ||
"cors": "^2.8.5", | ||
"express": "^4.19.2", | ||
"pg": "^8.12.0", | ||
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"uuid": "^10.0.0", | ||
"zod": "^3.23.8" | ||
}, | ||
"devDependencies": { | ||
"@databases/pg-migrations": "^5.0.3", | ||
"@types/react": "^18.3.3", | ||
"@types/react-dom": "^18.3.0", | ||
"@types/uuid": "^10.0.0", | ||
"@vitejs/plugin-react": "^4.3.1", | ||
"concurrently": "^8.2.2", | ||
"dotenv": "^16.4.5", | ||
"eslint": "^8.57.0", | ||
"typescript": "^5.5.3", | ||
"vite": "^5.3.4" | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# https://www.robotstxt.org/robotstxt.html | ||
User-agent: * | ||
Disallow: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
.App { | ||
text-align: center; | ||
} | ||
|
||
.App-logo { | ||
height: 64px; | ||
pointer-events: none; | ||
margin-top: min(40px, 5vmin); | ||
margin-bottom: min(20px, 4vmin); | ||
} | ||
|
||
.App-header { | ||
background-color: #1c1e20; | ||
min-height: 100vh; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: top; | ||
justify-content: top; | ||
font-size: calc(10px + 2vmin); | ||
color: white; | ||
} | ||
|
||
.App-link { | ||
color: #61dafb; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import logo from './assets/logo.svg' | ||
import './App.css' | ||
import './style.css' | ||
|
||
import { Example } from './Example' | ||
|
||
export default function App() { | ||
return ( | ||
<div className="App"> | ||
<header className="App-header"> | ||
<img src={logo} className="App-logo" alt="logo" /> | ||
<Example /> | ||
</header> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
.controls { | ||
margin-bottom: 1.5rem; | ||
} | ||
|
||
.button { | ||
display: inline-block; | ||
line-height: 1.3; | ||
text-align: center; | ||
text-decoration: none; | ||
vertical-align: middle; | ||
cursor: pointer; | ||
user-select: none; | ||
width: calc(15vw + 100px); | ||
margin-right: 0.5rem !important; | ||
margin-left: 0.5rem !important; | ||
border-radius: 32px; | ||
text-shadow: 2px 6px 20px rgba(0, 0, 0, 0.4); | ||
box-shadow: rgba(0, 0, 0, 0.5) 1px 2px 8px 0px; | ||
background: #1e2123; | ||
border: 2px solid #229089; | ||
color: #f9fdff; | ||
font-size: 16px; | ||
font-weight: 500; | ||
padding: 10px 18px; | ||
} | ||
|
||
.item { | ||
display: block; | ||
line-height: 1.3; | ||
text-align: center; | ||
vertical-align: middle; | ||
width: calc(30vw - 1.5rem + 200px); | ||
margin-right: auto; | ||
margin-left: auto; | ||
border-radius: 9px; | ||
border: 1px solid #D0BCFF; | ||
background: #1e2123; | ||
color: #D0BCFF; | ||
font-size: 13px; | ||
padding: 10px 18px; | ||
} | ||
|
||
form { | ||
border-top: 0.5px solid rgba(227, 227, 239, 0.32); | ||
width: calc(30vw - 1.5rem + 200px); | ||
margin: 20px auto; | ||
padding: 20px 0; | ||
} | ||
|
||
form input[type=text] { | ||
padding: 12px 18px; | ||
margin-bottom: 18px; | ||
background: #1e2123; | ||
border: 1px solid rgba(227, 227, 239, 0.92); | ||
border-radius: 9px; | ||
color: #f5f5f5; | ||
outline: none; | ||
font-size: 14px; | ||
display: block; | ||
text-align: center; | ||
width: calc(30vw - 1.5rem + 160px); | ||
margin-right: auto; | ||
margin-left: auto; | ||
} | ||
|
||
form input[type=text]::placeholder { | ||
color: rgba(227, 227, 239, 0.62); | ||
} | ||
|
||
form button[type=submit] { | ||
background: #D0BCFF; | ||
border: none; | ||
padding: 8px 20px; | ||
border-radius: 9px; | ||
color: #1e2123; | ||
font-size: 15px; | ||
font-weight: 500; | ||
cursor: pointer; | ||
} |
Oops, something went wrong.