Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions cipherstash/dataset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,24 @@ tables:
kind: ore
- version: 1
kind: unique
- path: User
fields:
- name: email_encrypted
in_place: false
mode: plaintext-duplicate
cast_type: utf8-str
indexes:
- version: 1
kind: match
tokenizer:
kind: ngram
token_length: 3
token_filters:
- kind: downcase
k: 6
m: 2048
include_original: true
- version: 1
kind: ore
- version: 1
kind: unique
2 changes: 1 addition & 1 deletion cipherstash/start.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash

docker run -p 6432:6432 -e CS_STATEMENT_HANDLER=mylittleproxy -v $(pwd)/cipherstash-proxy.toml:/etc/cipherstash-proxy/cipherstash-proxy.toml cipherstash/cipherstash-proxy:cipherstash-proxy-v0.0.25
docker run -p 6432:6432 -e CS_STATEMENT_HANDLER=mylittleproxy -e LOG_LEVEL=debug -v $(pwd)/cipherstash-proxy.toml:/etc/cipherstash-proxy/cipherstash-proxy.toml cipherstash/cipherstash-proxy:cipherstash-proxy-v0.0.25
40 changes: 20 additions & 20 deletions javascript/apps/drizzle/src/insert.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { getEmailArg } from '@cipherstash/utils'
import { eqlPayload } from '@cipherstash/eql'
import { db } from './db'
import { users } from './schema'
import { getEmailArg } from "@cipherstash/utils";
import { eqlPayload } from "@cipherstash/eql";
import { db } from "./db";
import { users } from "./schema";

const email = getEmailArg({
required: true,
})
required: true,
});

const sql = db.insert(users).values({
email: email,
email_encrypted: eqlPayload({
plaintext: email,
table: 'users',
column: 'email_encrypted',
}),
})
email: email,
email_encrypted: eqlPayload({
plaintext: email,
table: "users",
column: "email_encrypted",
}),
});

const sqlResult = sql.toSQL()
console.log('[INFO] SQL statement:', sqlResult)
const sqlResult = sql.toSQL();
console.log("[INFO] SQL statement:", sqlResult);

await sql.execute()
await sql.execute();
console.log(
"[INFO] You've inserted a new user with an encrypted email from the plaintext",
email,
)
"[INFO] You've inserted a new user with an encrypted email from the plaintext",
email,
);

process.exit(0)
process.exit(0);
30 changes: 15 additions & 15 deletions javascript/apps/drizzle/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { CsEncryptedV1Schema } from '@cipherstash/eql'
import { customType, pgTable, serial, varchar } from 'drizzle-orm/pg-core'
import type { CsEncryptedV1Schema } from "@cipherstash/eql";
import { customType, pgTable, serial, varchar } from "drizzle-orm/pg-core";

const cs_encrypted_v1 = <TData>(name: string) =>
customType<{ data: TData; driverData: string }>({
dataType() {
return 'cs_encrypted_v1'
},
toDriver(value: TData): string {
return JSON.stringify(value)
},
})(name)
customType<{ data: TData; driverData: string }>({
dataType() {
return "cs_encrypted_v1";
},
toDriver(value: TData): string {
return JSON.stringify(value);
},
})(name);

export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: varchar('email').unique(),
email_encrypted: cs_encrypted_v1<CsEncryptedV1Schema>('email_encrypted'),
})
export const users = pgTable("users", {
id: serial("id").primaryKey(),
email: varchar("email").unique(),
email_encrypted: cs_encrypted_v1<CsEncryptedV1Schema>("email_encrypted"),
});
48 changes: 24 additions & 24 deletions javascript/apps/drizzle/src/select.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { getEmailArg } from '@cipherstash/utils'
import { cs_match_v1 } from '@cipherstash/eql/drizzle'
import { db } from './db'
import { users } from './schema'
import { getEmailArg } from "@cipherstash/utils";
import { cs_match_v1 } from "@cipherstash/eql/drizzle";
import { getPlaintext } from "@cipherstash/eql";
import { db } from "./db";
import { users } from "./schema";

const email = getEmailArg({
required: false,
})
required: false,
});

const sql = db
.select({
email: users.email_encrypted,
})
.from(users)
.select({
email: users.email_encrypted,
})
.from(users);

if (email) {
sql.where(cs_match_v1(users, users.email_encrypted, email))
sql.where(cs_match_v1(users, users.email_encrypted, email));
}

const sqlResult = sql.toSQL()
console.log('[INFO] SQL statement:', sqlResult)
const sqlResult = sql.toSQL();
console.log("[INFO] SQL statement:", sqlResult);

const data = await sql.execute()
console.log('[INFO] All emails have been decrypted by CipherStash Proxy')
const data = await sql.execute();
console.log("[INFO] All emails have been decrypted by CipherStash Proxy");
console.log(
'Emails:',
JSON.stringify(
// data.map((row) => getPlaintext(row.email_encrypted)),
data,
null,
2,
),
)
"Emails:",
JSON.stringify(
data.map((row) => getPlaintext(row.email)),
null,
2,
),
);

process.exit(0)
process.exit(0);
38 changes: 36 additions & 2 deletions javascript/apps/prisma/src/db.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,36 @@
import { PrismaClient } from '@prisma/client'
export const prisma = new PrismaClient()
import { eqlPayload } from "@cipherstash/eql";
import { PrismaClient, Prisma } from "@prisma/client";

// TODO: Fix dynamic type of the whereEncrypted method
export const prisma = new PrismaClient().$extends({
model: {
$allModels: {
async whereEncrypted<T>(
this: T,
column: string,
plaintext: string,
): Promise<T[]> {
const context = Prisma.getExtensionContext(this);
const tableName = context.$name ?? "";

const result = (await prisma.$queryRaw`SELECT current_schema()`) as [
{ current_schema: string },
];
const schema = result[0].current_schema;

const payload = JSON.stringify(
eqlPayload({
plaintext,
table: tableName,
column,
}),
);

// TODO: Fix Prisma.raw to prevent SQL injection
return prisma.$queryRaw<
T[]
>`SELECT * FROM "${Prisma.raw(schema)}"."${Prisma.raw(tableName)}" WHERE cs_match_v1(${Prisma.raw(column)}) @> cs_match_v1('${Prisma.raw(payload)}')`;
},
},
},
});
38 changes: 19 additions & 19 deletions javascript/apps/prisma/src/insert.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { getEmailArg } from '@cipherstash/utils'
import { eqlPayload } from '@cipherstash/eql'
import { prisma } from './db'
import { getEmailArg } from "@cipherstash/utils";
import { eqlPayload } from "@cipherstash/eql";
import { prisma } from "./db";

const email = getEmailArg({
required: true,
})
required: true,
});

await prisma.user.create({
data: {
email: email ?? 'test@test.com',
email_encrypted: eqlPayload({
plaintext: email,
table: 'users',
column: 'email_encrypted',
}),
},
})
data: {
email: email ?? "test@test.com",
email_encrypted: eqlPayload({
plaintext: email,
table: "users",
column: "email_encrypted",
}),
},
});

console.log(
"[INFO] You've inserted a new user with an encrypted email from the plaintext",
email,
)
"[INFO] You've inserted a new user with an encrypted email from the plaintext",
email,
);

await prisma.$disconnect()
process.exit(0)
await prisma.$disconnect();
process.exit(0);
41 changes: 29 additions & 12 deletions javascript/apps/prisma/src/select.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import { prisma } from './db'
import { getPlaintext } from "@cipherstash/eql";
import { prisma } from "./db";
import { getEmailArg } from "@cipherstash/utils";
import type { User } from "@prisma/client";

const allUsers = await prisma.user.findMany()
const email = getEmailArg({
required: false,
});

console.log('[INFO] All emails have been decrypted by CipherStash Proxy')
let users: User[];

if (email) {
// TODO: Fix dynamic type of the whereEncrypted method
users = (await prisma.user.whereEncrypted(
"email_encrypted",
email,
)) as unknown as User[];
} else {
users = await prisma.user.findMany();
}

console.log("[INFO] All emails have been decrypted by CipherStash Proxy");
console.log(
'Emails:',
JSON.stringify(
allUsers.map((row) => row.email_encrypted?.p),
null,
2,
),
)
"Emails:",
JSON.stringify(
users.map((row) => getPlaintext(row.email_encrypted)),
null,
2,
),
);

await prisma.$disconnect()
process.exit(0)
await prisma.$disconnect();
process.exit(0);
8 changes: 4 additions & 4 deletions javascript/apps/prisma/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { CsEncryptedV1Schema } from '@cipherstash/eql'
import type { CsEncryptedV1Schema } from "@cipherstash/eql";

declare global {
namespace PrismaJson {
type CsEncryptedType = CsEncryptedV1Schema
}
namespace PrismaJson {
type CsEncryptedType = CsEncryptedV1Schema;
}
}
40 changes: 20 additions & 20 deletions javascript/packages/eql/src/drizzle/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { sql } from 'drizzle-orm'
import { sql } from "drizzle-orm";
import {
type PgTable,
getTableConfig,
type PgColumn,
} from 'drizzle-orm/pg-core'
import { eqlPayload } from '../'
type PgTable,
getTableConfig,
type PgColumn,
} from "drizzle-orm/pg-core";
import { eqlPayload } from "../";

export const cs_match_v1 = (
table: PgTable,
column: PgColumn,
plaintext: string,
table: PgTable,
column: PgColumn,
plaintext: string,
) => {
const tableName = getTableConfig(table)?.name
const columnName = column.name
const tableName = getTableConfig(table)?.name;
const columnName = column.name;

const payload = JSON.stringify(
eqlPayload({
plaintext,
table: tableName,
column: columnName,
}),
)
const payload = JSON.stringify(
eqlPayload({
plaintext,
table: tableName,
column: columnName,
}),
);

return sql`cs_match_v1(${column}) @> cs_match_v1(${payload})`
}
return sql`cs_match_v1(${column}) @> cs_match_v1(${payload})`;
};